diff --git a/autofs-5.0.8-amd-lookup-update-lookup-hesiod-to-handle-amd-keys.patch b/autofs-5.0.8-amd-lookup-update-lookup-hesiod-to-handle-amd-keys.patch new file mode 100644 index 0000000..aae211d --- /dev/null +++ b/autofs-5.0.8-amd-lookup-update-lookup-hesiod-to-handle-amd-keys.patch @@ -0,0 +1,423 @@ +autofs-5.0.8 - amd lookup update lookup hesiod to handle amd keys + +From: Ian Kent + +Warning, this is completely untested. + +I don't have a hesiod test environment so I can't test this at all. +If we do in fact have hesiod users then I'll need to work with them +to fix any reported problems. +--- + CHANGELOG | 3 + modules/lookup_hesiod.c | 330 ++++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 272 insertions(+), 61 deletions(-) + +diff --git a/CHANGELOG b/CHANGELOG +index 16a8ab4..f44f6f5 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -4,7 +4,8 @@ + - add amd map format parser. + - amd lookup update lookup ldap to handle amd keys + - inadvertantly drop from initial series. +- ++- amd lookup update lookup hesiod to handle amd keys ++ - inadvertantly drop from initial series. + + 28/03/2014 autofs-5.0.9 + ======================= +diff --git a/modules/lookup_hesiod.c b/modules/lookup_hesiod.c +index c4f3558..526f294 100644 +--- a/modules/lookup_hesiod.c ++++ b/modules/lookup_hesiod.c +@@ -20,12 +20,15 @@ + #include "automount.h" + #include "nsswitch.h" + +-#define MAPFMT_DEFAULT "hesiod" ++#define MAPFMT_DEFAULT "hesiod" ++#define AMD_MAP_PREFIX "hesiod." ++#define AMD_MAP_PREFIX_LEN 7 + + #define MODPREFIX "lookup(hesiod): " + #define HESIOD_LEN 512 + + struct lookup_context { ++ const char *mapname; + struct parse_mod *parser; + void *hesiod_context; + }; +@@ -50,6 +53,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + logerr(MODPREFIX "malloc: %s", estr); + return 1; + } ++ memset(ctxt, 0, sizeof(struct lookup_context)); + + /* Initialize the resolver. */ + res_init(); +@@ -66,6 +70,20 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + if (!mapfmt) + mapfmt = MAPFMT_DEFAULT; + ++ if (!strcmp(mapfmt, "amd")) { ++ /* amd formated hesiod maps have a map name */ ++ const char *mapname = argv[0]; ++ if (strncmp(mapname, AMD_MAP_PREFIX, AMD_MAP_PREFIX_LEN)) { ++ logerr(MODPREFIX ++ "incorrect prefix for hesiod map %s", mapname); ++ free(ctxt); ++ return 1; ++ } ++ ctxt->mapname = mapname; ++ argc--; ++ argv++; ++ } ++ + /* Open the parser, if we can. */ + ctxt->parser = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1); + if (!ctxt->parser) { +@@ -97,16 +115,203 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context) + * it's an ERR filesystem, it's an error message we should log. Otherwise, + * assume it's something we know how to deal with already (generic). + */ ++static int lookup_one(struct autofs_point *ap, ++ struct map_source *source, ++ const char *key, int key_len, ++ struct lookup_context *ctxt) ++{ ++ struct mapent_cache *mc; ++ char **hes_result; ++ char **record, *best_record = NULL, *p; ++ int priority, lowest_priority = INT_MAX; ++ int ret, status; ++ ++ mc = source->mc; ++ ++ status = pthread_mutex_lock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ ++ hes_result = hesiod_resolve(ctxt->hesiod_context, key, "filsys"); ++ if (!hes_result || !hes_result[0]) { ++ int err = errno; ++ error(ap->logopt, ++ MODPREFIX "key \"%s\" not found in map", key); ++ status = pthread_mutex_unlock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ if (err == HES_ER_NOTFOUND) ++ return CHE_MISSING; ++ else ++ return CHE_FAIL; ++ } ++ ++ /* autofs doesn't support falling back to alternate records, so just ++ find the record with the lowest priority and hope it works. ++ -- Aaron Ucko 2002-03-11 */ ++ for (record = hes_result; *record; ++record) { ++ p = strrchr(*record, ' '); ++ if ( p && isdigit(p[1]) ) { ++ priority = atoi(p+1); ++ } else { ++ priority = INT_MAX - 1; ++ } ++ if (priority < lowest_priority) { ++ lowest_priority = priority; ++ best_record = *record; ++ } ++ } ++ ++ cache_writelock(mc); ++ ret = cache_update(mc, source, key, best_record, time(NULL)); ++ cache_unlock(mc); ++ if (ret == CHE_FAIL) { ++ hesiod_free_list(ctxt->hesiod_context, hes_result); ++ status = pthread_mutex_unlock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ return ret; ++ } ++ ++ debug(ap->logopt, ++ MODPREFIX "lookup for \"%s\" gave \"%s\"", ++ key, best_record); ++ ++ hesiod_free_list(ctxt->hesiod_context, hes_result); ++ ++ status = pthread_mutex_unlock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ ++ return ret; ++} ++ ++static int lookup_one_amd(struct autofs_point *ap, ++ struct map_source *source, ++ const char *key, int key_len, ++ struct lookup_context *ctxt) ++{ ++ struct mapent_cache *mc; ++ char *hesiod_base; ++ char **hes_result; ++ char *lkp_key; ++ int status, ret; ++ ++ mc = source->mc; ++ ++ hesiod_base = conf_amd_get_hesiod_base(); ++ if (!hesiod_base) ++ return CHE_FAIL; ++ ++ lkp_key = malloc(key_len + strlen(ctxt->mapname) - 7 + 2); ++ if (!lkp_key) { ++ free(hesiod_base); ++ return CHE_FAIL; ++ } ++ ++ strcpy(lkp_key, key); ++ strcat(lkp_key, "."); ++ strcat(lkp_key, ctxt->mapname + AMD_MAP_PREFIX_LEN); ++ ++ status = pthread_mutex_lock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ ++ hes_result = hesiod_resolve(ctxt->hesiod_context, lkp_key, hesiod_base); ++ if (!hes_result || !hes_result[0]) { ++ int err = errno; ++ if (err == HES_ER_NOTFOUND) ++ ret = CHE_MISSING; ++ else ++ ret = CHE_FAIL; ++ goto done; ++ } ++ ++ cache_writelock(mc); ++ ret = cache_update(mc, source, lkp_key, *hes_result, time(NULL)); ++ cache_unlock(mc); ++ ++ if (hes_result) ++ hesiod_free_list(ctxt->hesiod_context, hes_result); ++done: ++ free(lkp_key); ++ ++ status = pthread_mutex_unlock(&hesiod_mutex); ++ if (status) ++ fatal(status); ++ ++ return ret; ++} ++ ++static int match_amd_key(struct autofs_point *ap, ++ struct map_source *source, ++ const char *key, int key_len, ++ struct lookup_context *ctxt) ++{ ++ char buf[MAX_ERR_BUF]; ++ char *lkp_key; ++ char *prefix; ++ int ret; ++ ++ ret = lookup_one_amd(ap, source, key, key_len, ctxt); ++ if (ret == CHE_OK || ret == CHE_UPDATED) ++ return ret; ++ ++ lkp_key = strdup(key); ++ if (!lkp_key) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "strdup: %s", estr); ++ return CHE_FAIL; ++ } ++ ++ ret = CHE_MISSING; ++ ++ /* ++ * Now strip successive directory components and try a ++ * match against map entries ending with a wildcard and ++ * finally try the wilcard entry itself. ++ */ ++ while ((prefix = strrchr(lkp_key, '/'))) { ++ char *match; ++ size_t len; ++ *prefix = '\0'; ++ len = strlen(lkp_key) + 3; ++ match = malloc(len); ++ if (!match) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "malloc: %s", estr); ++ ret = CHE_FAIL; ++ goto done; ++ } ++ len--; ++ strcpy(match, lkp_key); ++ strcat(match, "/*"); ++ ret = lookup_one_amd(ap, source, match, len, ctxt); ++ free(match); ++ if (ret == CHE_OK || ret == CHE_UPDATED) ++ goto done; ++ } ++ ++ /* Lastly try the wildcard */ ++ ret = lookup_one_amd(ap, source, "*", 1, ctxt); ++done: ++ free(lkp_key); ++ return ret; ++} ++ + int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context) + { + struct lookup_context *ctxt = (struct lookup_context *) context; +- struct map_source *source; + struct mapent_cache *mc; ++ char buf[MAX_ERR_BUF]; ++ struct map_source *source; + struct mapent *me; +- char **hes_result; +- int status, rv; +- char **record, *best_record = NULL, *p; +- int priority, lowest_priority = INT_MAX; ++ char key[KEY_MAX_LEN + 1]; ++ size_t key_len; ++ char *lkp_key; ++ size_t len; ++ char *mapent; ++ int rv; + + source = ap->entry->current; + ap->entry->current = NULL; +@@ -118,6 +323,19 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + MODPREFIX "looking up root=\"%s\", name=\"%s\"", + ap->path, name); + ++ if (!(source->flags & MAP_FLAG_FORMAT_AMD)) { ++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name); ++ if (key_len > KEY_MAX_LEN) ++ return NSS_STATUS_NOTFOUND; ++ } else { ++ key_len = expandamdent(name, NULL, NULL); ++ if (key_len > KEY_MAX_LEN) ++ return NSS_STATUS_NOTFOUND; ++ expandamdent(name, key, NULL); ++ key[key_len] = '\0'; ++ debug(ap->logopt, MODPREFIX "expanded key: \"%s\"", key); ++ } ++ + /* Check if we recorded a mount fail for this key anywhere */ + me = lookup_source_mapent(ap, name, LKP_DISTINCT); + if (me) { +@@ -144,69 +362,61 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + } + } + +- chdir("/"); /* If this is not here the filesystem stays +- busy, for some reason... */ +- +- status = pthread_mutex_lock(&hesiod_mutex); +- if (status) +- fatal(status); +- +- hes_result = hesiod_resolve(ctxt->hesiod_context, name, "filsys"); +- if (!hes_result || !hes_result[0]) { +- /* Note: it is not clear to me how to distinguish between +- * the "no search results" case and other failures. --JM */ +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", name); +- status = pthread_mutex_unlock(&hesiod_mutex); +- if (status) +- fatal(status); +- return NSS_STATUS_NOTFOUND; ++ /* If this is not here the filesystem stays busy, for some reason... */ ++ if (chdir("/")) ++ warn(ap->logopt, ++ MODPREFIX "failed to set working directory to \"/\""); ++ ++ len = key_len; ++ if (!(source->flags & MAP_FLAG_FORMAT_AMD)) ++ lkp_key = strdup(key); ++ else { ++ rv = lookup_one_amd(ap, source, "/defaults", 9, ctxt); ++ if (rv == CHE_FAIL) ++ warn(ap->logopt, ++ MODPREFIX "failed to lookup \"/defaults\" entry"); ++ ++ if (!ap->pref) ++ lkp_key = strdup(key); ++ else { ++ len += strlen(ap->pref); ++ lkp_key = malloc(len + 1); ++ if (lkp_key) { ++ strcpy(lkp_key, ap->pref); ++ strcat(lkp_key, name); ++ } ++ } + } + +- /* autofs doesn't support falling back to alternate records, so just +- find the record with the lowest priority and hope it works. +- -- Aaron Ucko 2002-03-11 */ +- for (record = hes_result; *record; ++record) { +- p = strrchr(*record, ' '); +- if ( p && isdigit(p[1]) ) { +- priority = atoi(p+1); +- } else { +- priority = INT_MAX - 1; +- } +- if (priority < lowest_priority) { +- lowest_priority = priority; +- best_record = *record; +- } ++ if (!lkp_key) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, "malloc: %s", estr); ++ return NSS_STATUS_UNKNOWN; + } + +- cache_writelock(mc); +- rv = cache_update(mc, source, name, best_record, time(NULL)); +- cache_unlock(mc); +- if (rv == CHE_FAIL) +- return NSS_STATUS_UNAVAIL; ++ if (source->flags & MAP_FLAG_FORMAT_AMD) ++ rv = match_amd_key(ap, source, lkp_key, len, ctxt); ++ else ++ rv = lookup_one(ap, source, lkp_key, len, ctxt); + +- debug(ap->logopt, +- MODPREFIX "lookup for \"%s\" gave \"%s\"", +- name, best_record); ++ if (rv == CHE_FAIL) { ++ free(lkp_key); ++ return NSS_STATUS_UNAVAIL; ++ } + +- rv = ctxt->parser->parse_mount(ap, name, name_len, best_record, +- ctxt->parser->context); ++ me = match_cached_key(ap, MODPREFIX, source, lkp_key); ++ free(lkp_key); ++ if (!me) ++ return NSS_STATUS_NOTFOUND; + +- hesiod_free_list(ctxt->hesiod_context, hes_result); ++ if (!me->mapent) ++ return NSS_STATUS_UNAVAIL; + +- status = pthread_mutex_unlock(&hesiod_mutex); +- if (status) +- fatal(status); ++ mapent = strdup(me->mapent); + +- if (rv) { +- /* Don't update negative cache when re-connecting */ +- if (ap->flags & MOUNT_FLAG_REMOUNT) +- return NSS_STATUS_TRYAGAIN; +- cache_writelock(mc); +- cache_update_negative(mc, source, name, ap->negative_timeout); +- cache_unlock(mc); +- return NSS_STATUS_TRYAGAIN; +- } ++ rv = ctxt->parser->parse_mount(ap, key, key_len, ++ mapent, ctxt->parser->context); ++ free(mapent); + + /* + * Unavailable due to error such as module load fail diff --git a/autofs-5.0.8-amd-lookup-update-lookup-ldap-to-handle-amd-keys.patch b/autofs-5.0.8-amd-lookup-update-lookup-ldap-to-handle-amd-keys.patch new file mode 100644 index 0000000..a40d4ce --- /dev/null +++ b/autofs-5.0.8-amd-lookup-update-lookup-ldap-to-handle-amd-keys.patch @@ -0,0 +1,954 @@ +autofs-5.0.8 - amd lookup update lookup ldap to handle amd keys + +From: Ian Kent + + +--- + CHANGELOG | 3 + include/lookup_ldap.h | 3 + modules/lookup_ldap.c | 707 +++++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 654 insertions(+), 59 deletions(-) + +diff --git a/CHANGELOG b/CHANGELOG +index 5cc1506..16a8ab4 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -2,6 +2,9 @@ + ======================= + - fix mistake in assignment. + - add amd map format parser. ++- amd lookup update lookup ldap to handle amd keys ++ - inadvertantly drop from initial series. ++ + + 28/03/2014 autofs-5.0.9 + ======================= +diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h +index f34c029..ba817aa 100644 +--- a/include/lookup_ldap.h ++++ b/include/lookup_ldap.h +@@ -36,6 +36,7 @@ struct ldap_searchdn { + + struct lookup_context { + char *mapname; ++ unsigned int format; + + char *server; + int port; +@@ -43,6 +44,8 @@ struct lookup_context { + char *qdn; + unsigned int timeout; + unsigned int network_timeout; ++ unsigned long timestamp; ++ unsigned int check_defaults; + + /* LDAP version 2 or 3 */ + int version; +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index c22d100..833cb86 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + + #define MODULE_LOOKUP + #include "automount.h" +@@ -52,6 +53,14 @@ static struct ldap_schema common_schema[] = { + }; + static unsigned int common_schema_count = sizeof(common_schema)/sizeof(struct ldap_schema); + ++static struct ldap_schema amd_timestamp = { ++ "madmap", "amdmapName", "amdmapTimestamp", NULL, "amdmapTimestamp" ++}; ++ ++static struct ldap_schema amd_schema = { ++ "amdmap", "amdmapName", "amdmap", "amdmapKey", "amdmapValue" ++}; ++ + /* + * Initialization and de-initialization of LDAP and OpenSSL must be + * always serialized to avoid corruption of context structures inside +@@ -62,6 +71,7 @@ pthread_mutex_t ldapinit_mutex = PTHREAD_MUTEX_INITIALIZER; + struct ldap_search_params { + struct autofs_point *ap; + LDAP *ldap; ++ char *base; + char *query, **attrs; + struct berval *cookie; + ber_int_t pageSize; +@@ -531,6 +541,16 @@ static int find_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctx + if (ctxt->schema) + return 0; + ++ if (ctxt->format & MAP_FLAG_FORMAT_AMD) { ++ schema = alloc_common_schema(&amd_schema); ++ if (!schema) { ++ error(logopt, MODPREFIX "failed to allocate schema"); ++ return 0; ++ } ++ ctxt->schema = schema; ++ return 1; ++ } ++ + for (i = 0; i < common_schema_count; i++) { + const char *class = common_schema[i].map_class; + const char *key = common_schema[i].map_attr; +@@ -587,8 +607,10 @@ static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_c + + if (!ctxt->cur_host) { + ctxt->cur_host = nhost; +- /* Check if schema defined in conf first time only */ +- ctxt->schema = defaults_get_schema(); ++ if (!(ctxt->format & MAP_FLAG_FORMAT_AMD)) { ++ /* Check if schema defined in conf first time only */ ++ ctxt->schema = defaults_get_schema(); ++ } + } else { + /* If connection host has changed update */ + if (strcmp(ctxt->cur_host, nhost)) { +@@ -614,7 +636,7 @@ static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_c + MODPREFIX "failed to find valid query dn"); + return 0; + } +- } else { ++ } else if (!(ctxt->format & MAP_FLAG_FORMAT_AMD)) { + const char *class = ctxt->schema->map_class; + const char *key = ctxt->schema->map_attr; + if (!get_query_dn(logopt, ldap, ctxt, class, key)) { +@@ -648,6 +670,126 @@ static LDAP *do_connect(unsigned logopt, const char *uri, struct lookup_context + return ldap; + } + ++static unsigned long get_amd_timestamp(struct lookup_context *ctxt) ++{ ++ LDAP *ldap; ++ LDAPMessage *result = NULL, *e; ++ char *query; ++ int scope = LDAP_SCOPE_SUBTREE; ++ char *map, *class, *value; ++ char *attrs[2]; ++ struct berval **bvValues; ++ unsigned long timestamp = 0; ++ int rv, l, ql; ++ ++ ldap = do_connect(LOGOPT_ANY, ctxt->server, ctxt); ++ if (!ldap) ++ return 0; ++ ++ map = amd_timestamp.map_attr; ++ class = amd_timestamp.entry_class; ++ value = amd_timestamp.value_attr; ++ ++ attrs[0] = value; ++ attrs[1] = NULL; ++ ++ /* Build a query string. */ ++ l = strlen(class) + ++ strlen(map) + strlen(ctxt->mapname) + 21; ++ ++ query = malloc(l); ++ if (query == NULL) { ++ char buf[MAX_ERR_BUF]; ++ char *estr = strerror_r(errno, buf, sizeof(buf)); ++ crit(LOGOPT_ANY, MODPREFIX "malloc: %s", estr); ++ return 0; ++ } ++ ++ /* ++ * Look for an entry in class under ctxt-base ++ * whose entry is equal to qKey. ++ */ ++ ql = sprintf(query, "(&(objectclass=%s)(%s=%s))", ++ class, map, ctxt->mapname); ++ if (ql >= l) { ++ error(LOGOPT_ANY, ++ MODPREFIX "error forming query string"); ++ free(query); ++ return 0; ++ } ++ ++ rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result); ++ if ((rv != LDAP_SUCCESS) || !result) { ++ crit(LOGOPT_ANY, MODPREFIX "timestamp query failed %s", query); ++ unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt); ++ if (result) ++ ldap_msgfree(result); ++ free(query); ++ return 0; ++ } ++ ++ e = ldap_first_entry(ldap, result); ++ if (!e) { ++ debug(LOGOPT_ANY, ++ MODPREFIX "got answer, but no entry for timestamp"); ++ ldap_msgfree(result); ++ unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt); ++ free(query); ++ return CHE_MISSING; ++ } ++ ++ while (e) { ++ char *v_val; ++ char *endptr; ++ ++ bvValues = ldap_get_values_len(ldap, e, value); ++ if (!bvValues || !*bvValues) { ++ debug(LOGOPT_ANY, ++ MODPREFIX "no value found in timestamp"); ++ goto next; ++ } ++ ++ /* There should be one value for a timestamp */ ++ v_val = bvValues[0]->bv_val; ++ ++ timestamp = strtol(v_val, &endptr, 0); ++ if ((errno == ERANGE && ++ (timestamp == LONG_MAX || timestamp == LONG_MIN)) || ++ (errno != 0 && timestamp == 0)) { ++ debug(LOGOPT_ANY, ++ MODPREFIX "invalid value in timestamp"); ++ free(query); ++ return 0; ++ } ++ ++ if (endptr == v_val) { ++ debug(LOGOPT_ANY, ++ MODPREFIX "no digits found in timestamp"); ++ free(query); ++ return 0; ++ } ++ ++ if (*endptr != '\0') { ++ warn(LOGOPT_ANY, MODPREFIX ++ "characters found after number: %s", endptr); ++ warn(LOGOPT_ANY, ++ MODPREFIX "timestamp may be invalid"); ++ } ++ ++ ldap_value_free_len(bvValues); ++ break; ++next: ++ ldap_value_free_len(bvValues); ++ e = ldap_next_entry(ldap, e); ++ } ++ ++ ldap_msgfree(result); ++ unbind_ldap_connection(LOGOPT_ANY, ldap, ctxt); ++ free(query); ++ ++ return timestamp; ++} ++ + static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_context *ctxt) + { + LDAP *ldap; +@@ -1215,7 +1357,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c + const char *q = NULL; + + /* Isolate the server(s). */ +- if ((q = strchr(s, '/'))) { ++ if ((q = strchr(s, '/')) || (q = strchr(s, '\0'))) { + l = q - s; + if (*proto) { + al_len = l + strlen(proto) + 2; +@@ -1318,8 +1460,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c + ptr += l + 1; + } + +- /* TODO: why did I do this - how can the map name "and" base dn be missing? */ +- if (!ptr) ++ if (!ptr || ctxt->format & MAP_FLAG_FORMAT_AMD) + goto done; + + /* +@@ -1505,36 +1646,83 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + /* If a map type isn't explicitly given, parse it like sun entries. */ + if (mapfmt == NULL) + mapfmt = MAPFMT_DEFAULT; +- +- /* +- * Parse out the server name and base dn, and fill them +- * into the proper places in the lookup context structure. +- */ +- if (!parse_server_string(LOGOPT_NONE, argv[0], ctxt)) { +- error(LOGOPT_ANY, MODPREFIX "cannot parse server string"); +- free_context(ctxt); +- return 1; ++ if (!strcmp(mapfmt, "amd")) { ++ ctxt->format = MAP_FLAG_FORMAT_AMD; ++ ctxt->check_defaults = 1; + } + +- if (!ctxt->base) +- ctxt->sdns = defaults_get_searchdns(); +- + ctxt->timeout = defaults_get_ldap_timeout(); + ctxt->network_timeout = defaults_get_ldap_network_timeout(); + +- if (!ctxt->server) { +- struct list_head *uris = defaults_get_uris(); +- if (uris) { +- validate_uris(uris); +- if (!list_empty(uris)) +- ctxt->uris = uris; +- else { +- error(LOGOPT_ANY, +- "no valid uris found in config list" +- ", using default system config"); +- free(uris); ++ if (!(ctxt->format & MAP_FLAG_FORMAT_AMD)) { ++ /* ++ * Parse out the server name and base dn, and fill them ++ * into the proper places in the lookup context structure. ++ */ ++ if (!parse_server_string(LOGOPT_NONE, argv[0], ctxt)) { ++ error(LOGOPT_ANY, MODPREFIX "cannot parse server string"); ++ free_context(ctxt); ++ return 1; ++ } ++ ++ if (!ctxt->base) ++ ctxt->sdns = defaults_get_searchdns(); ++ ++ if (!ctxt->server) { ++ struct list_head *uris = defaults_get_uris(); ++ if (uris) { ++ validate_uris(uris); ++ if (!list_empty(uris)) ++ ctxt->uris = uris; ++ else { ++ error(LOGOPT_ANY, MODPREFIX ++ "no valid uris found in config list" ++ ", using default system config"); ++ free(uris); ++ } + } + } ++ } else { ++ char *tmp = conf_amd_get_ldap_base(); ++ if (!tmp) { ++ error(LOGOPT_ANY, MODPREFIX "failed to get base dn"); ++ free_context(ctxt); ++ return 1; ++ } ++ ctxt->base = tmp; ++ ++ tmp = conf_amd_get_ldap_hostports(); ++ if (!tmp) { ++ error(LOGOPT_ANY, ++ MODPREFIX "failed to get ldap_hostports"); ++ free_context(ctxt); ++ return 1; ++ } ++ ++ /* ++ * Parse out the server name and port, and save them in ++ * the proper places in the lookup context structure. ++ */ ++ if (!parse_server_string(LOGOPT_NONE, tmp, ctxt)) { ++ error(LOGOPT_ANY, MODPREFIX "cannot parse server string"); ++ free_context(ctxt); ++ return 1; ++ } ++ free(tmp); ++ ++ if (!ctxt->server) { ++ error(LOGOPT_ANY, MODPREFIX "ldap_hostports not valid"); ++ free_context(ctxt); ++ return 1; ++ } ++ ++ tmp = strdup(argv[0]); ++ if (!tmp) { ++ error(LOGOPT_ANY, MODPREFIX "failed to set mapname"); ++ free_context(ctxt); ++ return 1; ++ } ++ ctxt->mapname = tmp; + } + + /* +@@ -1558,6 +1746,8 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co + } + #endif + ++ ctxt->timestamp = get_amd_timestamp(ctxt); ++ + /* Open the parser, if we can. */ + ctxt->parse = open_parse(mapfmt, MODPREFIX, argc - 1, argv + 1); + if (!ctxt->parse) { +@@ -2029,7 +2219,7 @@ static int do_paged_query(struct ldap_search_params *sp, struct lookup_context * + if (sp->morePages == TRUE) + goto do_paged; + +- rv = ldap_search_s(sp->ldap, ctxt->qdn, scope, sp->query, sp->attrs, 0, &sp->result); ++ rv = ldap_search_s(sp->ldap, sp->base, scope, sp->query, sp->attrs, 0, &sp->result); + if ((rv != LDAP_SUCCESS) || !sp->result) { + /* + * Check for Size Limit exceeded and force run through loop +@@ -2063,7 +2253,7 @@ do_paged: + + /* Search for entries in the directory using the parmeters. */ + rv = ldap_search_ext_s(sp->ldap, +- ctxt->qdn, scope, sp->query, sp->attrs, ++ sp->base, scope, sp->query, sp->attrs, + 0, controls, NULL, NULL, 0, &sp->result); + if ((rv != LDAP_SUCCESS) && (rv != LDAP_PARTIAL_RESULTS)) { + ldap_control_free(pageControl); +@@ -2364,6 +2554,115 @@ next: + return LDAP_SUCCESS; + } + ++static int do_get_amd_entries(struct ldap_search_params *sp, ++ struct map_source *source, ++ struct lookup_context *ctxt) ++{ ++ struct autofs_point *ap = sp->ap; ++ struct mapent_cache *mc = source->mc; ++ struct berval **bvKey; ++ struct berval **bvValues; ++ LDAPMessage *e; ++ char *entry, *value; ++ int rv, ret, count; ++ ++ entry = ctxt->schema->entry_attr; ++ value = ctxt->schema->value_attr; ++ ++ e = ldap_first_entry(sp->ldap, sp->result); ++ if (!e) { ++ debug(ap->logopt, ++ MODPREFIX "query succeeded, no matches for %s", ++ sp->query); ++ ret = ldap_parse_result(sp->ldap, sp->result, ++ &rv, NULL, NULL, NULL, NULL, 0); ++ if (ret == LDAP_SUCCESS) ++ return rv; ++ else ++ return LDAP_OPERATIONS_ERROR; ++ } else ++ debug(ap->logopt, MODPREFIX "examining entries"); ++ ++ while (e) { ++ char *k_val, *v_val; ++ ber_len_t k_len; ++ char *s_key; ++ ++ bvKey = ldap_get_values_len(sp->ldap, e, entry); ++ if (!bvKey || !*bvKey) { ++ e = ldap_next_entry(sp->ldap, e); ++ if (!e) { ++ debug(ap->logopt, MODPREFIX ++ "failed to get next entry for query %s", ++ sp->query); ++ ret = ldap_parse_result(sp->ldap, ++ sp->result, &rv, ++ NULL, NULL, NULL, NULL, 0); ++ if (ret == LDAP_SUCCESS) ++ return rv; ++ else ++ return LDAP_OPERATIONS_ERROR; ++ } ++ continue; ++ } ++ ++ /* By definition keys should be unique within each map entry */ ++ k_val = NULL; ++ k_len = 0; ++ ++ count = ldap_count_values_len(bvKey); ++ if (count > 1) ++ warn(ap->logopt, MODPREFIX ++ "more than one %s, using first", entry); ++ ++ k_val = bvKey[0]->bv_val; ++ k_len = bvKey[0]->bv_len; ++ ++ bvValues = ldap_get_values_len(sp->ldap, e, value); ++ if (!bvValues || !*bvValues) { ++ debug(ap->logopt, ++ MODPREFIX "no %s defined for %s", ++ value, sp->query); ++ goto next; ++ } ++ ++ count = ldap_count_values_len(bvValues); ++ if (count > 1) ++ warn(ap->logopt, MODPREFIX ++ "more than one %s, using first", value); ++ ++ v_val = bvValues[0]->bv_val; ++ ++ /* Don't fail on "/" in key => type == 0 */ ++ s_key = sanitize_path(k_val, k_len, 0, ap->logopt); ++ if (!s_key) ++ goto next; ++ ++ cache_writelock(mc); ++ cache_update(mc, source, s_key, v_val, sp->age); ++ cache_unlock(mc); ++ ++ free(s_key); ++next: ++ ldap_value_free_len(bvValues); ++ ldap_value_free_len(bvKey); ++ e = ldap_next_entry(sp->ldap, e); ++ if (!e) { ++ debug(ap->logopt, MODPREFIX ++ "failed to get next entry for query %s", ++ sp->query); ++ ret = ldap_parse_result(sp->ldap, ++ sp->result, &rv, ++ NULL, NULL, NULL, NULL, 0); ++ if (ret == LDAP_SUCCESS) ++ return rv; ++ else ++ return LDAP_OPERATIONS_ERROR; ++ } ++ } ++ ++ return LDAP_SUCCESS; ++} + + static int read_one_map(struct autofs_point *ap, + struct map_source *source, +@@ -2419,9 +2718,14 @@ static int read_one_map(struct autofs_point *ap, + return NSS_STATUS_UNAVAIL; + } + ++ if (ctxt->format & MAP_FLAG_FORMAT_AMD) ++ sp.base = ctxt->base; ++ else ++ sp.base = ctxt->qdn; ++ + /* Look around. */ + debug(ap->logopt, +- MODPREFIX "searching for \"%s\" under \"%s\"", sp.query, ctxt->qdn); ++ MODPREFIX "searching for \"%s\" under \"%s\"", sp.query, sp.base); + + sp.cookie = NULL; + sp.pageSize = 2000; +@@ -2465,7 +2769,10 @@ static int read_one_map(struct autofs_point *ap, + return NSS_STATUS_UNAVAIL; + } + +- rv = do_get_entries(&sp, source, ctxt); ++ if (source->flags & MAP_FLAG_FORMAT_AMD) ++ rv = do_get_amd_entries(&sp, source, ctxt); ++ else ++ rv = do_get_entries(&sp, source, ctxt); + if (rv != LDAP_SUCCESS) { + ldap_msgfree(sp.result); + unbind_ldap_connection(ap->logopt, sp.ldap, ctxt); +@@ -2874,6 +3181,219 @@ next: + return ret; + } + ++static int lookup_one_amd(struct autofs_point *ap, ++ struct map_source *source, ++ char *qKey, int qKey_len, ++ struct lookup_context *ctxt) ++{ ++ struct mapent_cache *mc = source->mc; ++ LDAP *ldap; ++ LDAPMessage *result = NULL, *e; ++ char *query; ++ int scope = LDAP_SCOPE_SUBTREE; ++ char *map, *class, *entry, *value; ++ char *attrs[3]; ++ struct berval **bvKey; ++ struct berval **bvValues; ++ char buf[MAX_ERR_BUF]; ++ time_t age = time(NULL); ++ int rv, l, ql, count; ++ int ret = CHE_MISSING; ++ ++ if (ctxt == NULL) { ++ crit(ap->logopt, MODPREFIX "context was NULL"); ++ return CHE_FAIL; ++ } ++ ++ /* Initialize the LDAP context. */ ++ ldap = do_reconnect(ap->logopt, ctxt); ++ if (!ldap) ++ return CHE_UNAVAIL; ++ ++ map = ctxt->schema->map_attr; ++ class = ctxt->schema->entry_class; ++ entry = ctxt->schema->entry_attr; ++ value = ctxt->schema->value_attr; ++ ++ attrs[0] = entry; ++ attrs[1] = value; ++ attrs[2] = NULL; ++ ++ /* Build a query string. */ ++ l = strlen(class) + ++ strlen(map) + strlen(ctxt->mapname) + ++ strlen(entry) + strlen(qKey) + 24; ++ ++ query = malloc(l); ++ if (query == NULL) { ++ char *estr = strerror_r(errno, buf, sizeof(buf)); ++ crit(ap->logopt, MODPREFIX "malloc: %s", estr); ++ return CHE_FAIL; ++ } ++ ++ /* ++ * Look for an entry in class under ctxt-base ++ * whose entry is equal to qKey. ++ */ ++ ql = sprintf(query, "(&(objectclass=%s)(%s=%s)(%s=%s))", ++ class, map, ctxt->mapname, entry, qKey); ++ if (ql >= l) { ++ error(ap->logopt, ++ MODPREFIX "error forming query string"); ++ free(query); ++ return CHE_FAIL; ++ } ++ ++ debug(ap->logopt, ++ MODPREFIX "searching for \"%s\" under \"%s\"", query, ctxt->base); ++ ++ rv = ldap_search_s(ldap, ctxt->base, scope, query, attrs, 0, &result); ++ if ((rv != LDAP_SUCCESS) || !result) { ++ crit(ap->logopt, MODPREFIX "query failed for %s", query); ++ unbind_ldap_connection(ap->logopt, ldap, ctxt); ++ if (result) ++ ldap_msgfree(result); ++ free(query); ++ return CHE_FAIL; ++ } ++ ++ debug(ap->logopt, ++ MODPREFIX "getting first entry for %s=\"%s\"", entry, qKey); ++ ++ e = ldap_first_entry(ldap, result); ++ if (!e) { ++ debug(ap->logopt, ++ MODPREFIX "got answer, but no entry for %s", query); ++ ldap_msgfree(result); ++ unbind_ldap_connection(ap->logopt, ldap, ctxt); ++ free(query); ++ return CHE_MISSING; ++ } ++ ++ while (e) { ++ char *k_val, *v_val; ++ ber_len_t k_len; ++ char *s_key; ++ ++ bvKey = ldap_get_values_len(ldap, e, entry); ++ if (!bvKey || !*bvKey) { ++ e = ldap_next_entry(ldap, e); ++ continue; ++ } ++ ++ /* By definition keys should be unique within each map entry */ ++ k_val = NULL; ++ k_len = 0; ++ ++ count = ldap_count_values_len(bvKey); ++ if (count > 1) ++ warn(ap->logopt, MODPREFIX ++ "more than one %s, using first", entry); ++ ++ k_val = bvKey[0]->bv_val; ++ k_len = bvKey[0]->bv_len; ++ ++ debug(ap->logopt, MODPREFIX "examining first entry"); ++ ++ bvValues = ldap_get_values_len(ldap, e, value); ++ if (!bvValues || !*bvValues) { ++ debug(ap->logopt, ++ MODPREFIX "no %s defined for %s", value, query); ++ goto next; ++ } ++ ++ count = ldap_count_values_len(bvValues); ++ if (count > 1) ++ warn(ap->logopt, MODPREFIX ++ "more than one %s, using first", value); ++ ++ /* There should be one value for a key, use first value */ ++ v_val = bvValues[0]->bv_val; ++ ++ /* Don't fail on "/" in key => type == 0 */ ++ s_key = sanitize_path(k_val, k_len, 0, ap->logopt); ++ if (!s_key) ++ goto next; ++ ++ cache_writelock(mc); ++ ret = cache_update(mc, source, s_key, v_val, age); ++ cache_unlock(mc); ++ ++ free(s_key); ++next: ++ ldap_value_free_len(bvValues); ++ ldap_value_free_len(bvKey); ++ e = ldap_next_entry(ldap, e); ++ } ++ ++ ldap_msgfree(result); ++ unbind_ldap_connection(ap->logopt, ldap, ctxt); ++ free(query); ++ ++ return ret; ++} ++ ++static int match_key(struct autofs_point *ap, ++ struct map_source *source, ++ char *key, int key_len, ++ struct lookup_context *ctxt) ++{ ++ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD; ++ char buf[MAX_ERR_BUF]; ++ char *lkp_key; ++ char *prefix; ++ int ret; ++ ++ if (is_amd_format) ++ ret = lookup_one_amd(ap, source, key, key_len, ctxt); ++ else ++ ret = lookup_one(ap, source, key, key_len, ctxt); ++ ++ if (ret == CHE_OK || ret == CHE_UPDATED) ++ return ret; ++ ++ if (!is_amd_format) ++ return CHE_FAIL; ++ ++ lkp_key = strdup(key); ++ if (!lkp_key) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "strdup: %s", estr); ++ return CHE_FAIL; ++ } ++ ++ ret = CHE_MISSING; ++ ++ /* ++ * Now strip successive directory components and try a ++ * match against map entries ending with a wildcard and ++ * finally try the wilcard entry itself. ++ */ ++ while ((prefix = strrchr(lkp_key, '/'))) { ++ char *match; ++ size_t len; ++ *prefix = '\0'; ++ len = strlen(lkp_key + 3); ++ match = malloc(len); ++ if (!match) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "malloc: %s", estr); ++ ret = CHE_FAIL; ++ goto done; ++ } ++ len--; ++ strcpy(match, lkp_key); ++ strcat(match, "/*"); ++ ret = lookup_one_amd(ap, source, match, len, ctxt); ++ free(match); ++ if (ret == CHE_OK || ret == CHE_UPDATED) ++ goto done; ++ } ++done: ++ free(lkp_key); ++ return ret; ++} ++ + static int check_map_indirect(struct autofs_point *ap, + struct map_source *source, + char *key, int key_len, +@@ -2888,16 +3408,43 @@ static int check_map_indirect(struct autofs_point *ap, + mc = source->mc; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- ret = lookup_one(ap, source, key, key_len, ctxt); ++ ++ pthread_mutex_lock(&ap->entry->current_mutex); ++ if (source->flags & MAP_FLAG_FORMAT_AMD) { ++ unsigned long timestamp = get_amd_timestamp(ctxt); ++ if (timestamp > ctxt->timestamp) { ++ ctxt->timestamp = timestamp; ++ source->stale = 1; ++ ctxt->check_defaults = 1; ++ } ++ ++ if (ctxt->check_defaults) { ++ /* Check for a /defaults entry */ ++ ret = lookup_one_amd(ap, source, "/defaults", 9, ctxt); ++ if (ret == CHE_FAIL) { ++ warn(ap->logopt, MODPREFIX ++ "error getting /defaults from map %s", ++ ctxt->mapname); ++ } else ++ ctxt->check_defaults = 0; ++ } ++ } ++ pthread_mutex_unlock(&ap->entry->current_mutex); ++ ++ ret = match_key(ap, source, key, key_len, ctxt); + if (ret == CHE_FAIL) { + pthread_setcancelstate(cur_state, NULL); + return NSS_STATUS_NOTFOUND; + } else if (ret == CHE_UNAVAIL) { ++ struct mapent *exists; + /* + * If the server is down and the entry exists in the cache + * and belongs to this map return success and use the entry. + */ +- struct mapent *exists = cache_lookup(mc, key); ++ if (source->flags & MAP_FLAG_FORMAT_AMD) ++ exists = match_cached_key(ap, MODPREFIX, source, key); ++ else ++ exists = cache_lookup(mc, key); + if (exists && exists->source == source) { + pthread_setcancelstate(cur_state, NULL); + return NSS_STATUS_SUCCESS; +@@ -2910,24 +3457,28 @@ static int check_map_indirect(struct autofs_point *ap, + } + pthread_setcancelstate(cur_state, NULL); + +- /* +- * Check for map change and update as needed for +- * following cache lookup. +- */ +- cache_readlock(mc); +- t_last_read = ap->exp_runfreq + 1; +- me = cache_lookup_first(mc); +- while (me) { +- if (me->source == source) { +- t_last_read = now - me->age; +- break; ++ if (!(source->flags & MAP_FLAG_FORMAT_AMD)) { ++ /* ++ * Check for map change and update as needed for ++ * following cache lookup. ++ */ ++ cache_readlock(mc); ++ t_last_read = ap->exp_runfreq + 1; ++ me = cache_lookup_first(mc); ++ while (me) { ++ if (me->source == source) { ++ t_last_read = now - me->age; ++ break; ++ } ++ me = cache_lookup_next(mc, me); + } +- me = cache_lookup_next(mc, me); +- } +- cache_unlock(mc); ++ cache_unlock(mc); + +- if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED) +- source->stale = 1; ++ pthread_mutex_lock(&ap->entry->current_mutex); ++ if (t_last_read > ap->exp_runfreq && ret & CHE_UPDATED) ++ source->stale = 1; ++ pthread_mutex_unlock(&ap->entry->current_mutex); ++ } + + cache_readlock(mc); + me = cache_lookup_distinct(mc, "*"); +@@ -2948,8 +3499,10 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + struct mapent *me; + char key[KEY_MAX_LEN + 1]; + int key_len; ++ char *lkp_key; + char *mapent = NULL; + char mapent_buf[MAPENT_MAX_LEN + 1]; ++ char buf[MAX_ERR_BUF]; + int status = 0; + int ret = 1; + +@@ -2961,9 +3514,18 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + + debug(ap->logopt, MODPREFIX "looking up %s", name); + +- key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name); +- if (key_len > KEY_MAX_LEN) +- return NSS_STATUS_NOTFOUND; ++ if (!(source->flags & MAP_FLAG_FORMAT_AMD)) { ++ key_len = snprintf(key, KEY_MAX_LEN + 1, "%s", name); ++ if (key_len > KEY_MAX_LEN) ++ return NSS_STATUS_NOTFOUND; ++ } else { ++ key_len = expandamdent(name, NULL, NULL); ++ if (key_len > KEY_MAX_LEN) ++ return NSS_STATUS_NOTFOUND; ++ expandamdent(name, key, NULL); ++ key[key_len] = '\0'; ++ debug(ap->logopt, MODPREFIX "expanded key: \"%s\"", key); ++ } + + /* Check if we recorded a mount fail for this key anywhere */ + me = lookup_source_mapent(ap, key, LKP_DISTINCT); +@@ -2997,18 +3559,26 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + * we never know about it. + */ + if (ap->type == LKP_INDIRECT && *key != '/') { +- char *lkp_key; +- + cache_readlock(mc); + me = cache_lookup_distinct(mc, key); + if (me && me->multi) + lkp_key = strdup(me->multi->key); +- else ++ else if (!ap->pref) + lkp_key = strdup(key); ++ else { ++ lkp_key = malloc(strlen(ap->pref) + strlen(key) + 1); ++ if (lkp_key) { ++ strcpy(lkp_key, ap->pref); ++ strcat(lkp_key, key); ++ } ++ } + cache_unlock(mc); + +- if (!lkp_key) ++ if (!lkp_key) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "malloc: %s", estr); + return NSS_STATUS_UNKNOWN; ++ } + + status = check_map_indirect(ap, source, + lkp_key, strlen(lkp_key), ctxt); +@@ -3029,7 +3599,25 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + cache_readlock(mc); + else + cache_writelock(mc); +- me = cache_lookup(mc, key); ++ ++ if (!ap->pref) ++ lkp_key = strdup(key); ++ else { ++ lkp_key = malloc(strlen(ap->pref) + strlen(key) + 1); ++ if (lkp_key) { ++ strcpy(lkp_key, ap->pref); ++ strcat(lkp_key, key); ++ } ++ } ++ ++ if (!lkp_key) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, MODPREFIX "malloc: %s", estr); ++ cache_unlock(mc); ++ return NSS_STATUS_UNKNOWN; ++ } ++ ++ me = match_cached_key(ap, MODPREFIX, source, lkp_key); + /* Stale mapent => check for entry in alternate source or wildcard */ + if (me && !me->mapent) { + while ((me = cache_lookup_key_next(me))) +@@ -3055,6 +3643,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void * + } + } + cache_unlock(mc); ++ free(lkp_key); + + if (!mapent) + return NSS_STATUS_TRYAGAIN; diff --git a/autofs-5.0.9-check-for-non-existent-negative-entries-in-lookup_ghost.patch b/autofs-5.0.9-check-for-non-existent-negative-entries-in-lookup_ghost.patch new file mode 100644 index 0000000..f313140 --- /dev/null +++ b/autofs-5.0.9-check-for-non-existent-negative-entries-in-lookup_ghost.patch @@ -0,0 +1,64 @@ +autofs-5.0.9 - check for non existent negative entries in lookup_ghost() + +From: Ian Kent + +Map entries that have been created in the cache due to a negative lookup +but don't exist in the map source shouldn't have directories created. + +This can be detected by checking me->status. + +For negative entries that are present in the map source me->status will +have been set to 0 in lookup_prune_one_cache() and negavive entries that +have been created in the same second as the map read will always have +me->status > 0 and so will also be skipped by lookup_ghost(). +--- + CHANGELOG | 1 + + daemon/lookup.c | 16 +++++++++++++++- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/CHANGELOG b/CHANGELOG +index 8c1da44..113dfb8 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -7,6 +7,7 @@ + - amd lookup update lookup hesiod to handle amd keys + - inadvertantly drop from initial series. + - fix wildcard key lookup. ++- check for non existent negative entries in lookup_ghost(). + + 28/03/2014 autofs-5.0.9 + ======================= +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 999be9d..b4cdcce 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -716,6 +716,17 @@ int lookup_ghost(struct autofs_point *ap, const char *root) + cache_readlock(mc); + me = cache_enumerate(mc, NULL); + while (me) { ++ /* ++ * Map entries that have been created in the cache ++ * due to a negative lookup but don't exist in the ++ * map source shouldn't have directories created. ++ * me->status of negative entries that are present ++ * in the map source will have me->status set to 0 ++ * in lookup_prune_one_cache(). ++ */ ++ if (me->status && !me->mapent) ++ goto next; ++ + if (!strcmp(me->key, "*")) + goto next; + +@@ -1339,7 +1350,10 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti + + if (valid) + cache_delete(mc, key); +- else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) { ++ else if (this->status) { ++ cache_unlock(mc); ++ goto next; ++ } else if (!is_mounted(_PROC_MOUNTS, path, MNTS_AUTOFS)) { + dev_t devid = ap->dev; + status = CHE_FAIL; + if (ap->type == LKP_DIRECT) diff --git a/autofs-5.1.0-beta1-fix-wildcard-key-lookup.patch b/autofs-5.1.0-beta1-fix-wildcard-key-lookup.patch new file mode 100644 index 0000000..3b50780 --- /dev/null +++ b/autofs-5.1.0-beta1-fix-wildcard-key-lookup.patch @@ -0,0 +1,170 @@ +autofs-5.1.0-beta1 - fix wildcard key lookup + +From: Ian Kent + +The changes to key matching caused wildcard key lookups for autofs +format maps to fail. +--- + CHANGELOG | 1 + + modules/lookup_ldap.c | 10 ++++------ + modules/lookup_nisplus.c | 11 +++++------ + modules/lookup_program.c | 4 ++-- + modules/lookup_yp.c | 6 ++---- + 5 files changed, 14 insertions(+), 18 deletions(-) + +diff --git a/CHANGELOG b/CHANGELOG +index f44f6f5..8c1da44 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -6,6 +6,7 @@ + - inadvertantly drop from initial series. + - amd lookup update lookup hesiod to handle amd keys + - inadvertantly drop from initial series. ++- fix wildcard key lookup. + + 28/03/2014 autofs-5.0.9 + ======================= +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 833cb86..dac346c 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -3349,12 +3349,9 @@ static int match_key(struct autofs_point *ap, + else + ret = lookup_one(ap, source, key, key_len, ctxt); + +- if (ret == CHE_OK || ret == CHE_UPDATED) ++ if (ret == CHE_OK || ret == CHE_UPDATED || !is_amd_format) + return ret; + +- if (!is_amd_format) +- return CHE_FAIL; +- + lkp_key = strdup(key); + if (!lkp_key) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +@@ -3399,6 +3396,7 @@ static int check_map_indirect(struct autofs_point *ap, + char *key, int key_len, + struct lookup_context *ctxt) + { ++ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD; + struct mapent_cache *mc; + struct mapent *me; + time_t now = time(NULL); +@@ -3410,7 +3408,7 @@ static int check_map_indirect(struct autofs_point *ap, + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + + pthread_mutex_lock(&ap->entry->current_mutex); +- if (source->flags & MAP_FLAG_FORMAT_AMD) { ++ if (is_amd_format) { + unsigned long timestamp = get_amd_timestamp(ctxt); + if (timestamp > ctxt->timestamp) { + ctxt->timestamp = timestamp; +@@ -3457,7 +3455,7 @@ static int check_map_indirect(struct autofs_point *ap, + } + pthread_setcancelstate(cur_state, NULL); + +- if (!(source->flags & MAP_FLAG_FORMAT_AMD)) { ++ if (!is_amd_format) { + /* + * Check for map change and update as needed for + * following cache lookup. +diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c +index e9444c9..db1b162 100644 +--- a/modules/lookup_nisplus.c ++++ b/modules/lookup_nisplus.c +@@ -339,6 +339,7 @@ static int match_key(struct autofs_point *ap, + const char *key, int key_len, + struct lookup_context *ctxt) + { ++ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD; + char buf[MAX_ERR_BUF]; + char *lkp_key; + char *prefix; +@@ -347,12 +348,9 @@ static int match_key(struct autofs_point *ap, + ret = lookup_one(ap, source, key, key_len, ctxt); + if (ret < 0) + return ret; +- if (ret == CHE_OK || ret == CHE_UPDATED) ++ if (ret == CHE_OK || ret == CHE_UPDATED || is_amd_format) + return ret; + +- if (!(source->flags & MAP_FLAG_FORMAT_AMD)) +- return CHE_FAIL; +- + lkp_key = strdup(key); + if (!lkp_key) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +@@ -504,6 +502,7 @@ static int check_map_indirect(struct autofs_point *ap, + char *key, int key_len, + struct lookup_context *ctxt) + { ++ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD; + struct mapent_cache *mc; + struct mapent *me, *exists; + time_t now = time(NULL); +@@ -512,7 +511,7 @@ static int check_map_indirect(struct autofs_point *ap, + + mc = source->mc; + +- if (source->flags & MAP_FLAG_FORMAT_AMD) { ++ if (is_amd_format) { + /* Check for a /defaults entry to update the map source */ + if (lookup_amd_defaults(ap, source, ctxt) == CHE_FAIL) { + warn(ap->logopt, MODPREFIX +@@ -559,7 +558,7 @@ static int check_map_indirect(struct autofs_point *ap, + } + me = cache_lookup_next(mc, me); + } +- if (source->flags & MAP_FLAG_FORMAT_AMD) ++ if (is_amd_format) + exists = match_cached_key(ap, MODPREFIX, source, key); + else + exists = cache_lookup_distinct(mc, key); +diff --git a/modules/lookup_program.c b/modules/lookup_program.c +index 08d14ff..aae0ec0 100644 +--- a/modules/lookup_program.c ++++ b/modules/lookup_program.c +@@ -382,7 +382,7 @@ static int match_key(struct autofs_point *ap, + char *prefix; + int ret; + +- if (source->flags & MAP_FLAG_FORMAT_AMD) { ++ if (is_amd_format) { + ret = lookup_amd_defaults(ap, source, ctxt); + if (ret != NSS_STATUS_SUCCESS) { + warn(ap->logopt, +@@ -420,7 +420,7 @@ static int match_key(struct autofs_point *ap, + ment = lookup_one(ap, lkp_key, lkp_len, ctxt); + if (ment) { + char *start = ment; +- if (source->flags & MAP_FLAG_FORMAT_AMD) { ++ if (is_amd_format) { + start = ment + lkp_len; + while (isblank(*start)) + start++; +diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c +index 146e39e..fcf470a 100644 +--- a/modules/lookup_yp.c ++++ b/modules/lookup_yp.c +@@ -457,6 +457,7 @@ static int match_key(struct autofs_point *ap, + const char *key, int key_len, + struct lookup_context *ctxt) + { ++ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD; + char buf[MAX_ERR_BUF]; + char *lkp_key; + char *prefix; +@@ -465,12 +466,9 @@ static int match_key(struct autofs_point *ap, + ret = lookup_one(ap, source, key, strlen(key), ctxt); + if (ret < 0) + return ret; +- if (ret == CHE_OK || ret == CHE_UPDATED) ++ if (ret == CHE_OK || ret == CHE_UPDATED || !is_amd_format) + return ret; + +- if (!(source->flags & MAP_FLAG_FORMAT_AMD)) +- return CHE_FAIL; +- + lkp_key = strdup(key); + if (!lkp_key) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); diff --git a/autofs.spec b/autofs.spec index 521e3cb..90cda9b 100644 --- a/autofs.spec +++ b/autofs.spec @@ -8,11 +8,15 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.1.0 -Release: 0.beta1%{?dist} +Release: 0.beta1.1%{?dist} Epoch: 1 License: GPLv2+ Group: System Environment/Daemons Source: ftp://ftp.kernel.org/pub/linux/daemons/autofs/v5/autofs-%{version}-beta1.tar.gz +Patch1: autofs-5.0.8-amd-lookup-update-lookup-ldap-to-handle-amd-keys.patch +Patch2: autofs-5.0.8-amd-lookup-update-lookup-hesiod-to-handle-amd-keys.patch +Patch3: autofs-5.1.0-beta1-fix-wildcard-key-lookup.patch +Patch4: autofs-5.0.9-check-for-non-existent-negative-entries-in-lookup_ghost.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if %{with_systemd} BuildRequires: systemd-units @@ -70,6 +74,10 @@ echo %{version}-%{release} > .version %define unitdir %{?_unitdir:/usr/lib/systemd/system} %define systemd_configure_arg --with-systemd %endif +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 %build LDFLAGS=-Wl,-z,now @@ -162,6 +170,14 @@ fi %dir /etc/auto.master.d %changelog +* Sun Apr 13 2014 Ian Kent - 1:5.1.0-0.beta1.1 +- amd lookup update lookup ldap to handle amd keys + - inadvertantly drop from initial series. +- amd lookup update lookup hesiod to handle amd keys + - inadvertantly drop from initial series. +- fix wildcard key lookup. +- check for non existent negative entries in lookup_ghost(). + * Wed Apr 2 2014 Ian Kent - 1:5.1.0-0.beta1 - Update to autofs-5.0.1-beta1.