- fix hosts map use after free.

- fix uri list locking (again).
- check for stale SASL credentials upon connect fail.
- add "forcestart" and "forcerestart" init script options to allow use of
    5.0.3 strartup behavior if required.
- always read entire file map into cache to speed lookups.
- make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit.
- make some easy alloca replacements.
- update to configure libtirpc if present.
- update to provide ipv6 name and address support.
- update to provide ipv6 address parsing.
This commit is contained in:
Ian Kent 2009-02-16 04:01:39 +00:00
parent ad62197f9f
commit c5187b0dbf
13 changed files with 7842 additions and 2 deletions

View File

@ -0,0 +1,226 @@
autofs-5.0.4 - always read file maps
From: Ian Kent <raven@themaw.net>
autofs tries to not load an entire map into the internal cache unless it
has to. For maps that do get loaded into the cache it relies on checks to
work out if a map is up to date in order to trigger a map read. This is
fine for maps that can do direct key lookups but file maps need to do a
linear search through the file when locating an entry for a key. For large
maps this can be a huge overhead. This patch make autofs always load file
based maps at start and makes use of the map file mtime to discover if the
cache needs to be refreshed.
---
CHANGELOG | 1 +
daemon/lookup.c | 9 +++++--
modules/lookup_file.c | 65 ++++++++++++++++---------------------------------
3 files changed, 28 insertions(+), 47 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index d4dd70b..afd1335 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@
- check for stale SASL credentials upon connect fail.
- add "forcestart" and "forcerestart" init script options to allow
use of 5.0.3 strartup behavior if required.
+- always read entire file map into cache to speed lookups.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/daemon/lookup.c b/daemon/lookup.c
index 741d846..e034348 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -283,10 +283,13 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a
* for the fail cases to function correctly and to cache the
* lookup handle.
*
- * We always need to whole map for direct mounts in order to
- * mount the triggers.
+ * We always need to read the whole map for direct mounts in
+ * order to mount the triggers. We also want to read the whole
+ * map if it's a file map to avoid potentially lengthy linear
+ * file scanning.
*/
- if (!(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
+ if (strcmp(map->type, "file") &&
+ !(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
return NSS_STATUS_SUCCESS;
if (!map->stale)
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 95b9f6f..aafeb8b 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -44,7 +44,6 @@ typedef enum { esc_none, esc_char, esc_val, esc_all } ESCAPES;
struct lookup_context {
const char *mapname;
- time_t mtime;
struct parse_mod *parse;
};
@@ -54,7 +53,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
{
struct lookup_context *ctxt;
char buf[MAX_ERR_BUF];
- struct stat st;
*context = NULL;
@@ -87,15 +85,6 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
return 1;
}
- if (stat(ctxt->mapname, &st)) {
- free(ctxt);
- logmsg(MODPREFIX "file map %s, could not stat",
- argv[0]);
- return 1;
- }
-
- ctxt->mtime = st.st_mtime;
-
if (!mapfmt)
mapfmt = MAPFMT_DEFAULT;
@@ -391,9 +380,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
int blen;
char *path;
char *ent;
- struct stat st;
FILE *f;
- int fd;
unsigned int path_len, ent_len;
int entry, cur_state;
@@ -428,8 +415,6 @@ int lookup_read_master(struct master *master, time_t age, void *context)
return NSS_STATUS_UNAVAIL;
}
- fd = fileno(f);
-
while(1) {
entry = read_one(logopt, f, path, &path_len, ent, &ent_len);
if (!entry) {
@@ -504,13 +489,6 @@ int lookup_read_master(struct master *master, time_t age, void *context)
break;
}
- if (fstat(fd, &st)) {
- crit(logopt, MODPREFIX "file map %s, could not stat",
- ctxt->mapname);
- return NSS_STATUS_UNAVAIL;
- }
- ctxt->mtime = st.st_mtime;
-
fclose(f);
return NSS_STATUS_SUCCESS;
@@ -642,9 +620,7 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
struct mapent_cache *mc;
char *key;
char *mapent;
- struct stat st;
FILE *f;
- int fd;
unsigned int k_len, m_len;
int entry;
@@ -684,8 +660,6 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
return NSS_STATUS_UNAVAIL;
}
- fd = fileno(f);
-
while(1) {
entry = read_one(ap->logopt, f, key, &k_len, mapent, &m_len);
if (!entry) {
@@ -748,13 +722,6 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
break;
}
- if (fstat(fd, &st)) {
- crit(ap->logopt,
- MODPREFIX "file map %s, could not stat",
- ctxt->mapname);
- return NSS_STATUS_UNAVAIL;
- }
- ctxt->mtime = st.st_mtime;
source->age = age;
fclose(f);
@@ -951,9 +918,6 @@ static int check_map_indirect(struct autofs_point *ap,
if (ret == CHE_FAIL)
return NSS_STATUS_NOTFOUND;
- if (ret & CHE_UPDATED)
- source->stale = 1;
-
pthread_cleanup_push(cache_lock_cleanup, mc);
cache_writelock(mc);
exists = cache_lookup_distinct(mc, key);
@@ -963,7 +927,6 @@ static int check_map_indirect(struct autofs_point *ap,
free(exists->mapent);
exists->mapent = NULL;
exists->status = 0;
- source->stale = 1;
}
}
pthread_cleanup_pop(1);
@@ -985,14 +948,8 @@ static int check_map_indirect(struct autofs_point *ap,
we = cache_lookup_distinct(mc, "*");
if (we) {
/* Wildcard entry existed and is now gone */
- if (we->source == source && (wild & CHE_MISSING)) {
+ if (we->source == source && (wild & CHE_MISSING))
cache_delete(mc, "*");
- source->stale = 1;
- }
- } else {
- /* Wildcard not in map but now is */
- if (wild & (CHE_OK | CHE_UPDATED))
- source->stale = 1;
}
pthread_cleanup_pop(1);
@@ -1062,9 +1019,28 @@ 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 != '/') {
+ struct stat st;
char *lkp_key;
+ /*
+ * We can skip the map lookup and cache update altogether
+ * if we know the map hasn't been modified since it was
+ * last read. If it has then we can mark the map stale
+ * so a re-read is triggered following the lookup.
+ */
+ if (stat(ctxt->mapname, &st)) {
+ error(ap->logopt, MODPREFIX
+ "file map %s, could not stat", ctxt->mapname);
+ return NSS_STATUS_UNAVAIL;
+ }
+
cache_readlock(mc);
+ me = cache_lookup_first(mc);
+ if (me && st.st_mtime <= me->age)
+ goto do_cache_lookup;
+ else
+ source->stale = 1;
+
me = cache_lookup_distinct(mc, key);
if (me && me->multi)
lkp_key = strdup(me->multi->key);
@@ -1088,6 +1064,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
}
cache_readlock(mc);
+do_cache_lookup:
me = cache_lookup(mc, key);
/* Stale mapent => check for entry in alternate source or wildcard */
if (me && !me->mapent) {

View File

@ -0,0 +1,552 @@
autofs-5.0.4 - code analysis corrections
From: Ian Kent <raven@themaw.net>
Several mistakes have been reported by Paul Wankadia <junyer@google.com>:
- a malloc(3) allocation return was not being checked in make_fullpath().
- a double free and a use after free was identified in lookup_prune_cache().
- off-by-one buffer overflow in lib/macros.c:macro_parse_globalvar().
- several potential buffer overflows in modules/parse_hesiod.c.
- double free in daemon/indirect.c:do_mount_autofs_indirect().
- bogus struct name used for sizeof in lib/cache.c:cache_init() and
lib/cache.c:cache_init_null_cache().
- in daemon/direct.c:handle_packet_expire_direct master_unlock_mutex() not
needed and mutexes not unlocked for file descriptor fail case.
- in modules/lookup_multi.c:lookup_init() struct module_info array not
checked before free for allocation failure case.
- in modules/lookup_program.c:lookup_mount() mapent not freed on cache update failure.
- in modules/mount_nfs.c allocation of mount location not checked.
- in modules/parse_sun.c:parse_mapent() mount location not freed on syntax error.
- in modules/parse_sun.c:parse_mount() mount location not freed on syntax error.
- in modules/parse_sun.c:parse_init() a malloc is not checked and the
handling of the fail case is poor.
- in lib/mounts.c:tree_make_mnt_tree() variable ent is not freed on ent->path
alloc fail.
- in modules/replicated.c:add_host() NULL pointer dereference.
- add missing pthread_attr_destroy() in lib/alarm.c:alarm_start_handler().
- add missing pthread_attr_destroy() in daemon/state.c:st_start_handler().
- add missing fclose() in lib/defaults.c:*defaults_get_searchdns().
- add missing close()es in modules/mount_changer.c:swapCD().
---
daemon/direct.c | 6 ++-
daemon/indirect.c | 3 +-
daemon/lookup.c | 20 +++++-------
daemon/state.c | 6 ++-
lib/alarm.c | 6 ++-
lib/cache.c | 4 +-
lib/defaults.c | 1 +
lib/macros.c | 2 +
lib/mounts.c | 5 ++-
modules/lookup_multi.c | 15 +++++----
modules/lookup_program.c | 4 ++
modules/mount_changer.c | 2 +
modules/mount_nfs.c | 5 +++
modules/parse_hesiod.c | 79 ++++++++++++++++++++++++++++++++++++++++------
modules/parse_sun.c | 18 ++++++----
modules/replicated.c | 2 +
16 files changed, 123 insertions(+), 55 deletions(-)
diff --git a/daemon/direct.c b/daemon/direct.c
index 2d979f1..fc3c969 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -1088,7 +1088,6 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
crit(ap->logopt, "can't find map entry for (%lu,%lu)",
(unsigned long) pkt->dev, (unsigned long) pkt->ino);
master_source_unlock(ap->entry);
- master_mutex_unlock();
pthread_setcancelstate(state, NULL);
return 1;
}
@@ -1098,8 +1097,9 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
int ioctlfd;
ops->open(ap->logopt, &ioctlfd, me->dev, me->key);
if (ioctlfd == -1) {
- crit(ap->logopt, "can't open ioctlfd for %s",
- me->key);
+ crit(ap->logopt, "can't open ioctlfd for %s", me->key);
+ cache_unlock(mc);
+ master_source_unlock(ap->entry);
pthread_setcancelstate(state, NULL);
return 1;
}
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 2ccbc53..f40c393 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -159,6 +159,7 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
}
free(options);
+ options = NULL;
ret = stat(root, &st);
if (ret == -1) {
@@ -167,8 +168,6 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
goto out_umount;
}
- options = NULL;
-
if (ops->open(ap->logopt, &ap->ioctlfd, st.st_dev, root)) {
crit(ap->logopt,
"failed to create ioctl fd for autofs path %s", ap->path);
diff --git a/daemon/lookup.c b/daemon/lookup.c
index e034348..fd2ce55 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -1001,12 +1001,16 @@ static char *make_fullpath(const char *root, const char *key)
if (l > KEY_MAX_LEN)
return NULL;
path = malloc(l);
+ if (!path)
+ return NULL;
strcpy(path, key);
} else {
l = strlen(key) + 1 + strlen(root) + 1;
if (l > KEY_MAX_LEN)
return NULL;
path = malloc(l);
+ if (!path)
+ return NULL;
sprintf(path, "%s/%s", root, key);
}
return path;
@@ -1076,10 +1080,6 @@ int lookup_prune_cache(struct autofs_point *ap, time_t age)
this = cache_lookup_distinct(mc, key);
if (!this) {
cache_unlock(mc);
- free(key);
- if (next_key)
- free(next_key);
- free(path);
goto next;
}
@@ -1097,18 +1097,14 @@ int lookup_prune_cache(struct autofs_point *ap, time_t age)
}
cache_unlock(mc);
- if (!next_key) {
- free(key);
- free(path);
- cache_readlock(mc);
- continue;
- }
next:
cache_readlock(mc);
- me = cache_lookup_distinct(mc, next_key);
+ if (next_key) {
+ me = cache_lookup_distinct(mc, next_key);
+ free(next_key);
+ }
free(key);
free(path);
- free(next_key);
}
pthread_cleanup_pop(1);
map->stale = 0;
diff --git a/daemon/state.c b/daemon/state.c
index cd63be1..606743b 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -1140,9 +1140,9 @@ int st_start_handler(void)
}
status = pthread_create(&thid, pattrs, st_queue_handler, NULL);
- if (status)
- return 0;
- return 1;
+ pthread_attr_destroy(pattrs);
+
+ return !status;
}
diff --git a/lib/alarm.c b/lib/alarm.c
index 1e32291..46df38a 100755
--- a/lib/alarm.c
+++ b/lib/alarm.c
@@ -238,9 +238,9 @@ int alarm_start_handler(void)
}
status = pthread_create(&thid, pattrs, alarm_handler, NULL);
- if (status)
- return 0;
- return 1;
+ pthread_attr_destroy(pattrs);
+
+ return !status;
}
diff --git a/lib/cache.c b/lib/cache.c
index edb3192..4cb4582 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -192,7 +192,7 @@ struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map)
mc->size = defaults_get_map_hash_table_size();
- mc->hash = malloc(mc->size * sizeof(struct entry *));
+ mc->hash = malloc(mc->size * sizeof(struct mapent *));
if (!mc->hash) {
free(mc);
return NULL;
@@ -243,7 +243,7 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
mc->size = NULL_MAP_HASHSIZE;
- mc->hash = malloc(mc->size * sizeof(struct entry *));
+ mc->hash = malloc(mc->size * sizeof(struct mapent *));
if (!mc->hash) {
free(mc);
return NULL;
diff --git a/lib/defaults.c b/lib/defaults.c
index 0d39716..e507a59 100644
--- a/lib/defaults.c
+++ b/lib/defaults.c
@@ -565,6 +565,7 @@ struct ldap_searchdn *defaults_get_searchdns(void)
if (!new) {
defaults_free_searchdns(sdn);
+ fclose(f);
return NULL;
}
diff --git a/lib/macros.c b/lib/macros.c
index 85f9cd3..32b70bf 100644
--- a/lib/macros.c
+++ b/lib/macros.c
@@ -165,7 +165,7 @@ int macro_parse_globalvar(const char *define)
char buf[MAX_MACRO_STRING];
char *pbuf, *value;
- if (strlen(define) > MAX_MACRO_STRING)
+ if (strlen(define) >= MAX_MACRO_STRING)
return 0;
strcpy(buf, define);
diff --git a/lib/mounts.c b/lib/mounts.c
index b98e1a4..08ca4e3 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -257,10 +257,10 @@ struct mnt_list *get_mnt_list(const char *table, const char *path, int include)
if (mptr == list)
list = ent;
+ else
+ last->next = ent;
ent->next = mptr;
- if (last)
- last->next = ent;
ent->path = malloc(len + 1);
if (!ent->path) {
@@ -705,6 +705,7 @@ struct mnt_list *tree_make_mnt_tree(const char *table, const char *path)
ent->path = malloc(len + 1);
if (!ent->path) {
endmntent(tab);
+ free(ent);
tree_free_mnt_tree(tree);
return NULL;
}
diff --git a/modules/lookup_multi.c b/modules/lookup_multi.c
index 1bf2e0a..6ec8434 100644
--- a/modules/lookup_multi.c
+++ b/modules/lookup_multi.c
@@ -212,14 +212,15 @@ nomem:
logerr(MODPREFIX "error: %s", estr);
error_out:
if (ctxt) {
- for (i = 0; i < ctxt->n; i++) {
- if (ctxt->m[i].mod)
- close_lookup(ctxt->m[i].mod);
- if (ctxt->m[i].argv)
- free_argv(ctxt->m[i].argc, ctxt->m[i].argv);
- }
- if (ctxt->m)
+ if (ctxt->m) {
+ for (i = 0; i < ctxt->n; i++) {
+ if (ctxt->m[i].mod)
+ close_lookup(ctxt->m[i].mod);
+ if (ctxt->m[i].argv)
+ free_argv(ctxt->m[i].argc, ctxt->m[i].argv);
+ }
free(ctxt->m);
+ }
if (ctxt->argl)
free(ctxt->argl);
free(ctxt);
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
index 9878936..5b295a5 100644
--- a/modules/lookup_program.c
+++ b/modules/lookup_program.c
@@ -396,8 +396,10 @@ next:
cache_writelock(mc);
ret = cache_update(mc, source, name, mapent, time(NULL));
cache_unlock(mc);
- if (ret == CHE_FAIL)
+ if (ret == CHE_FAIL) {
+ free(mapent);
return NSS_STATUS_UNAVAIL;
+ }
debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent);
diff --git a/modules/mount_changer.c b/modules/mount_changer.c
index 92bb72b..c30190d 100644
--- a/modules/mount_changer.c
+++ b/modules/mount_changer.c
@@ -162,6 +162,7 @@ int swapCD(const char *device, const char *slotName)
logerr(MODPREFIX
"Device %s is not an ATAPI compliant CD changer.",
device);
+ close(fd);
return 1;
}
@@ -169,6 +170,7 @@ int swapCD(const char *device, const char *slotName)
slot = ioctl(fd, CDROM_SELECT_DISC, slot);
if (slot < 0) {
logerr(MODPREFIX "CDROM_SELECT_DISC failed");
+ close(fd);
return 1;
}
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index 20732f8..6f54f47 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -221,6 +221,11 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
/* Not a local host - do an NFS mount */
loc = malloc(strlen(this->name) + 1 + strlen(this->path) + 1);
+ if (!loc) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt, "malloc: %s", estr);
+ return 1;
+ }
strcpy(loc, this->name);
strcat(loc, ":");
strcat(loc, this->path);
diff --git a/modules/parse_hesiod.c b/modules/parse_hesiod.c
index d5bb0f4..7a6a57d 100644
--- a/modules/parse_hesiod.c
+++ b/modules/parse_hesiod.c
@@ -46,6 +46,12 @@ static int parse_afs(struct autofs_point *ap,
/* Isolate the source for this AFS fs. */
for (i = 0; (!isspace(p[i]) && i < source_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for AFS "
+ "source: %s", p);
+ return 1;
+ }
source[i] = p[i];
}
@@ -56,8 +62,14 @@ static int parse_afs(struct autofs_point *ap,
while ((*p) && (isspace(*p)))
p++;
- /* Isolate the source for this AFS fs. */
+ /* Isolate the options for this AFS fs. */
for (i = 0; (!isspace(p[i]) && i < options_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for AFS "
+ "options: %s", p);
+ return 1;
+ }
options[i] = p[i];
}
options[i] = 0;
@@ -106,6 +118,12 @@ static int parse_nfs(struct autofs_point *ap,
/* Isolate the remote mountpoint for this NFS fs. */
for (i = 0; (!isspace(p[i]) && i < (int) sizeof(mount)); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for NFS "
+ "mountpoint: %s", p);
+ return 1;
+ }
mount[i] = p[i];
}
@@ -118,15 +136,26 @@ static int parse_nfs(struct autofs_point *ap,
/* Isolate the remote host. */
for (i = 0; (!isspace(p[i]) && i < source_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for NFS "
+ "host: %s", p);
+ return 1;
+ }
source[i] = p[i];
}
source[i] = 0;
p += i;
+ if (strlen(source) + strlen(mount) + 2 > source_len) {
+ error(ap->logopt, MODPREFIX "entry too log for mount source");
+ return 1;
+ }
+
/* Append ":mountpoint" to the source to get "host:mountpoint". */
- strncat(source, ":", source_len);
- strncat(source, mount, source_len);
+ strcat(source, ":");
+ strcat(source, mount);
/* Skip whitespace. */
while ((*p) && (isspace(*p)))
@@ -134,6 +163,12 @@ static int parse_nfs(struct autofs_point *ap,
/* Isolate the mount options. */
for (i = 0; (!isspace(p[i]) && i < options_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for NFS "
+ "mount options: %s", p);
+ return 1;
+ }
options[i] = p[i];
}
options[i] = 0;
@@ -178,6 +213,12 @@ static int parse_generic(struct autofs_point *ap,
/* Isolate the source for this fs. */
for (i = 0; (!isspace(p[i]) && i < source_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for generic "
+ "mount source: %s", p);
+ return 1;
+ }
source[i] = p[i];
}
@@ -190,6 +231,12 @@ static int parse_generic(struct autofs_point *ap,
/* Isolate the mount options. */
for (i = 0; (!isspace(p[i]) && i < options_len); i++) {
+ if (!p[i]) {
+ error(ap->logopt, MODPREFIX
+ "unexpeced end of input looking for generic "
+ "mount options: %s", p);
+ return 1;
+ }
options[i] = p[i];
}
options[i] = 0;
@@ -227,6 +274,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
char options[HESIOD_LEN + 1];
char *q;
const char *p;
+ int ret;
ap->entry->current = NULL;
master_source_current_signal(ap->entry);
@@ -250,19 +298,28 @@ int parse_mount(struct autofs_point *ap, const char *name,
return 1;
/* If it's an AFS fs... */
} else if (!strcasecmp(fstype, "afs"))
- parse_afs(ap, mapent, name, name_len,
- source, sizeof(source), options, sizeof(options));
+ ret = parse_afs(ap, mapent, name, name_len,
+ source, sizeof(source), options,
+ sizeof(options));
/* If it's NFS... */
else if (!strcasecmp(fstype, "nfs"))
- parse_nfs(ap, mapent, name, name_len,
- source, sizeof(source), options, sizeof(options));
+ ret = parse_nfs(ap, mapent, name, name_len,
+ source, sizeof(source), options,
+ sizeof(options));
/* Punt. */
else
- parse_generic(ap, mapent, name, name_len, source, sizeof(source),
- options, sizeof(options));
+ ret = parse_generic(ap, mapent, name, name_len,
+ source, sizeof(source), options,
+ sizeof(options));
- debug(ap->logopt,
- MODPREFIX "mount %s is type %s from %s", name, fstype, source);
+ if (ret) {
+ error(ap->logopt, MODPREFIX "failed to parse entry");
+ return 1;
+ } else {
+ debug(ap->logopt,
+ MODPREFIX "mount %s is type %s from %s",
+ name, fstype, source);
+ }
return do_mount(ap, ap->path, name, name_len, source, fstype, options);
}
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 72e51e2..ed73e46 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -379,15 +379,17 @@ int parse_init(int argc, const char *const *argv, void **context)
if (ctxt->optstr) {
noptstr =
(char *) realloc(ctxt->optstr, optlen + len + 2);
- if (!noptstr)
- break;
- noptstr[optlen] = ',';
- strcpy(noptstr + optlen + 1, argv[i] + offset);
- optlen += len + 1;
+ if (noptstr) {
+ noptstr[optlen] = ',';
+ strcpy(noptstr + optlen + 1, argv[i] + offset);
+ optlen += len + 1;
+ }
} else {
noptstr = (char *) malloc(len + 1);
- strcpy(noptstr, argv[i] + offset);
- optlen = len;
+ if (noptstr) {
+ strcpy(noptstr, argv[i] + offset);
+ optlen = len;
+ }
}
if (!noptstr) {
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
@@ -895,6 +897,7 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
if (*p == '/') {
warn(logopt, MODPREFIX "error location begins with \"/\"");
free(myoptions);
+ free(loc);
return 0;
}
@@ -1636,6 +1639,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
/* Location can't begin with a '/' */
if (*p == '/') {
free(options);
+ free(loc);
warn(ap->logopt,
MODPREFIX "error location begins with \"/\"");
return 1;
diff --git a/modules/replicated.c b/modules/replicated.c
index 63829a2..835af97 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -304,7 +304,7 @@ static int add_host(struct host **list, struct host *host)
{
struct host *this, *last;
- if (!list) {
+ if (!*list) {
*list = host;
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
autofs-5.0.4 - fix hosts map use after free
From: Ian Kent <raven@themaw.net>
This patch fixed use a map entry after it has been freed in the
hosts map lookup module.
---
CHANGELOG | 1 +
modules/lookup_hosts.c | 8 +++++---
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index eb4a189..3199e4d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,7 @@
Valerie Aurora Henson).
- clear the quoted flag after each character from program map input.
- use CLOEXEC flag for setmntent also.
+- fix hosts map use after free.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
index 93b975a..d3ae0e2 100644
--- a/modules/lookup_hosts.c
+++ b/modules/lookup_hosts.c
@@ -138,17 +138,19 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
/* Check if we recorded a mount fail for this key anywhere */
me = lookup_source_mapent(ap, name, LKP_DISTINCT);
if (me) {
+ struct mapent_cache *fmc = me->mc;
+
if (me->status >= time(NULL)) {
- cache_unlock(me->mc);
+ cache_unlock(fmc);
return NSS_STATUS_NOTFOUND;
}
if (!me->mapent) {
- cache_delete(me->mc, name);
+ cache_delete(fmc, name);
me = NULL;
}
- cache_unlock(me->mc);
+ cache_unlock(fmc);
}
cache_readlock(mc);

View File

@ -0,0 +1,235 @@
autofs-5.0.4 - force unlink umount at startup
From: Ian Kent <raven@themaw.net>
Version 5.0.3 autofs would unlink existing mounts at startup. This
functioned OK most of the time but caused processes whose working
directory was within unlinked automounted directories to not get a
correct pwd reported by the system.
There can be situations where the unlink umounting is desirable, such
as when the daemon is forceably killed and we want to get rid of any
existing mounts at startup. This change provides a way to force this
old behavior by passing the "--force" option to the daemon. This can
also be done by using the "forcestart" and "forcerestart" actions to
the init script.
Note that the old behavior will always be used if the kernel does not
include the iotcl re-implementation which provides the ability to
re-connect to existing mounts.
---
CHANGELOG | 2 ++
daemon/automount.c | 14 +++++++++++++-
daemon/direct.c | 2 +-
daemon/indirect.c | 2 +-
include/automount.h | 3 +++
man/automount.8 | 13 +++++++++++++
redhat/autofs.init.in | 10 +++++++++-
samples/rc.autofs.in | 10 +++++++++-
8 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 7dee674..d4dd70b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,8 @@
- fix hosts map use after free.
- fix uri list locking (again).
- check for stale SASL credentials upon connect fail.
+- add "forcestart" and "forcerestart" init script options to allow
+ use of 5.0.3 strartup behavior if required.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index f04273f..e20e7c9 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -57,6 +57,7 @@ static char *pid_file = NULL; /* File in which to keep pid */
unsigned int global_random_selection; /* use random policy when selecting
* which multi-mount host to mount */
long global_negative_timeout = -1;
+int do_force_unlink = 0; /* Forceably unlink mount tree at startup */
static int start_pipefd[2];
static int st_stat = 0;
@@ -1798,6 +1799,7 @@ int main(int argc, char *argv[])
{"version", 0, 0, 'V'},
{"set-log-priority", 1, 0, 'l'},
{"dont-check-daemon", 0, 0, 'C'},
+ {"force", 0, 0, 'F'},
{0, 0, 0, 0}
};
@@ -1819,7 +1821,7 @@ int main(int argc, char *argv[])
daemon_check = 1;
opterr = 0;
- while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:C", long_options, NULL)) != EOF) {
+ while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:CF", long_options, NULL)) != EOF) {
switch (opt) {
case 'h':
usage();
@@ -1892,6 +1894,10 @@ int main(int argc, char *argv[])
daemon_check = 0;
break;
+ case 'F':
+ do_force_unlink = 1;
+ break;
+
case '?':
case ':':
printf("%s: Ambiguous or unknown options\n", program);
@@ -2066,6 +2072,12 @@ int main(int argc, char *argv[])
exit(3);
}
+ /*
+ * Mmm ... reset force unlink umount so we don't also do this
+ * in future when we receive a HUP signal.
+ */
+ do_force_unlink = 0;
+
res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
close(start_pipefd[1]);
diff --git a/daemon/direct.c b/daemon/direct.c
index d9dda3d..2d979f1 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -335,7 +335,7 @@ int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struc
/* Calculate the timeouts */
ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
- if (ops->version) {
+ if (ops->version && !do_force_unlink) {
ap->flags |= MOUNT_FLAG_REMOUNT;
ret = try_remount(ap, me, t_direct);
ap->flags &= ~MOUNT_FLAG_REMOUNT;
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 0721707..2ccbc53 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -97,7 +97,7 @@ static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
- if (ops->version) {
+ if (ops->version && !do_force_unlink) {
ap->flags |= MOUNT_FLAG_REMOUNT;
ret = try_remount(ap, NULL, t_indirect);
ap->flags &= ~MOUNT_FLAG_REMOUNT;
diff --git a/include/automount.h b/include/automount.h
index 46cb6c6..1f14d5b 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -428,6 +428,9 @@ struct autofs_point {
struct list_head submounts; /* List of child submounts */
};
+/* Foreably unlink existing mounts at startup. */
+extern int do_force_unlink;
+
/* Standard functions used by daemon or modules */
#define MOUNT_OFFSET_OK 0
diff --git a/man/automount.8 b/man/automount.8
index d9285bf..9fcaaf4 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -84,6 +84,11 @@ path name as specified in the master map.
.TP
.I "\-C, \-\-dont-check-daemon"
Don't check if the daemon is currently running (see NOTES).
+.TP
+.I "\-F, \-\-force"
+Force an unlink umount of existing mounts under autofs managed mount points
+during startup. This can cause problems for processes with working directories
+within these mounts (see NOTES).
.SH ARGUMENTS
\fBautomount\fP takes one optional argument, the name of the master map to
use.
@@ -132,6 +137,14 @@ for certain types of automount maps. The mounts of the seperate daemons
might interfere with one another. The implications of running multiple
daemon instances needs to be checked and tested before we can say this
is supported.
+.P
+If the option to force an unlink of mounts at startup is used then processes
+whose working directory is within unlinked automounted directories will not
+get the correct pwd from the system. This is because, after the mount is
+unlinked from the mount tree, anything that needs to walk back up the mount
+tree to construct a path, such as getcwd(2) and the proc filesystem
+/proc/<pid>/cwd, cannot work because the point from which the path is
+constructed has been detached from the mount tree.
.SH "SEE ALSO"
.BR autofs (5),
.BR autofs (8),
diff --git a/redhat/autofs.init.in b/redhat/autofs.init.in
index 65c786e..471667e 100644
--- a/redhat/autofs.init.in
+++ b/redhat/autofs.init.in
@@ -137,6 +137,10 @@ case "$1" in
start)
start
;;
+ forcestart)
+ OPTIONS="$OPTIONS --force"
+ start
+ ;;
stop)
stop
;;
@@ -146,6 +150,10 @@ case "$1" in
restart)
restart
;;
+ forcerestart)
+ OPTIONS="$OPTIONS --force"
+ restart
+ ;;
reload)
reload
;;
@@ -155,7 +163,7 @@ case "$1" in
fi
;;
*)
- echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}"
+ echo $"Usage: $0 {start|forcestart|stop|status|restart|orcerestart|reload|condrestart}"
exit 1;
;;
esac
diff --git a/samples/rc.autofs.in b/samples/rc.autofs.in
index 51f5b02..2877fe2 100644
--- a/samples/rc.autofs.in
+++ b/samples/rc.autofs.in
@@ -117,17 +117,25 @@ case "$1" in
start)
start
;;
+ forcestart)
+ OPTIONS="$OPTIONS --force"
+ start
+ ;;
stop)
stop
;;
restart)
restart
;;
+ forcerestart)
+ OPTIONS="$OPTIONS --force"
+ restart
+ ;;
reload)
reload
;;
*)
- echo $"Usage: $0 {start|stop|restart|reload}"
+ echo $"Usage: $0 {start|forcestart|stop|restart|forcerestart|reload}"
exit 1;
;;
esac

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,462 @@
autofs-5.0.4 - ipv6 parse
From: Ian Kent <raven@themaw.net>
Since ipv6 addresses use a colon separator and we use the colon quite a
bit as a delimiting character we need to distinguish between when the
colon is the delimeter we are looking for and when it is part of an ipv6
address. Since there is widespread use of "[" and "]" to provide the
ability to separate a port specification from an ipv6 address this
convention has also been used in autofs.
---
CHANGELOG | 1
include/parse_subs.h | 8 +++
lib/master_tok.l | 10 ++--
lib/parse_subs.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++---
modules/lookup_file.c | 40 +++++++------------
modules/lookup_ldap.c | 21 ++++++++--
modules/mount_autofs.c | 29 +++++---------
modules/parse_sun.c | 16 ++++---
modules/replicated.c | 26 +++++++++++-
9 files changed, 187 insertions(+), 63 deletions(-)
--- autofs-5.0.4.orig/include/parse_subs.h
+++ autofs-5.0.4/include/parse_subs.h
@@ -20,6 +20,12 @@
struct mapent;
+struct map_type_info {
+ char *type;
+ char *format;
+ char *map;
+};
+
const char *skipspace(const char *);
int check_colon(const char *);
int chunklen(const char *, int);
@@ -27,5 +33,7 @@ int strmcmp(const char *, const char *,
char *dequote(const char *, int, unsigned int);
int span_space(const char *, unsigned int);
char *sanitize_path(const char *, int, unsigned int, unsigned int);
+void free_map_type_info(struct map_type_info *);
+struct map_type_info *parse_map_type_info(const char *);
#endif
--- autofs-5.0.4.orig/lib/master_tok.l
+++ autofs-5.0.4/lib/master_tok.l
@@ -96,10 +96,12 @@ SLASHIFYSTR (--(no-)?slashify-colons)
NUMBER [0-9]+
DNSERVSTR1 ([[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?:)
-DNSERVSTR2 (\/\/[[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?\/)
-DNSERVSTR3 (([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?:)
-DNSERVSTR4 (\/\/([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?\/)
-DNSERVERSTR ({DNSERVSTR1}|{DNSERVSTR2}|{DNSERVSTR3}|{DNSERVSTR4})
+DNSERVSTR2 (\[([[:xdigit:]]:.)+\](:[0-9]+)?:)
+DNSERVSTR3 (\/\/[[:alpha:]][[:alnum:]\-.]*(:[0-9]+)?\/)
+DNSERVSTR4 (\/\/\[([[:xdigit:]]:.)+\](:[0-9]+)?\/)
+DNSERVSTR5 (([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?:)
+DNSERVSTR6 (\/\/([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(:[0-9]+)?\/)
+DNSERVERSTR ({DNSERVSTR1}|{DNSERVSTR2}|{DNSERVSTR3}|{DNSERVSTR4}|{DNSERVSTR5}|{DNSERVSTR6})
AT_CN ([cC][[nN])
AT_NMN ([nN][iI][sS][Mm][aA][pP][Nn][aA][mM][eE])
--- autofs-5.0.4.orig/lib/parse_subs.c
+++ autofs-5.0.4/lib/parse_subs.c
@@ -56,14 +56,13 @@ int check_colon(const char *str)
char *ptr = (char *) str;
/* Colon escape */
- if (*ptr == ':')
+ if (!strncmp(ptr, ":/", 2))
return 1;
- while (*ptr && *ptr != ':' && *ptr != '/') {
+ while (*ptr && strncmp(ptr, ":/", 2))
ptr++;
- }
- if (!*ptr || *ptr == '/')
+ if (!*ptr)
return 0;
return 1;
@@ -93,12 +92,12 @@ int chunklen(const char *whence, int exp
n++;
if (*str == '"')
break;
- if (*str == ':')
+ if (!strncmp(str, ":/", 2))
expect_colon = 0;
}
break;
case ':':
- if (expect_colon)
+ if (expect_colon && !strncmp(str, ":/", 2))
expect_colon = 0;
continue;
case ' ':
@@ -300,3 +299,91 @@ char *sanitize_path(const char *path, in
return s_path;
}
+void free_map_type_info(struct map_type_info *info)
+{
+ if (info->type)
+ free(info->type);
+ if (info->format)
+ free(info->format);
+ if (info->map)
+ free(info->map);
+ free(info);
+ return;
+}
+
+struct map_type_info *parse_map_type_info(const char *str)
+{
+ struct map_type_info *info;
+ char *buf, *type, *fmt, *map, *tmp;
+
+ buf = strdup(str);
+ if (!buf)
+ return NULL;
+
+ info = malloc(sizeof(struct map_type_info));
+ if (!info) {
+ free(buf);
+ return NULL;
+ }
+ memset(info, 0, sizeof(struct map_type_info));
+
+ type = fmt = NULL;
+
+ /* Look for space terminator - ignore local options */
+ map = buf;
+ for (tmp = buf; *tmp; tmp++) {
+ if (*tmp == ' ') {
+ *tmp = '\0';
+ break;
+ } else if (*tmp == ',') {
+ type = buf;
+ *tmp++ = '\0';
+ fmt = tmp;
+ } else if (*tmp == ':') {
+ if (!fmt)
+ type = buf;
+ *tmp++ = '\0';
+ map = tmp;
+ } else if (*tmp == '[') {
+ /*
+ * Unescaped '[' is a syntax error here as only
+ * an ldap map with a type specified should contain
+ * them.
+ */
+ free(buf);
+ return 0;
+ }
+ if (*tmp == '\\')
+ tmp++;
+ }
+
+ if (type) {
+ info->type = strdup(type);
+ if (!info->type) {
+ free(buf);
+ free_map_type_info(info);
+ return NULL;
+ }
+ }
+
+ if (fmt) {
+ info->format = strdup(fmt);
+ if (!info->format) {
+ free(buf);
+ free_map_type_info(info);
+ return NULL;
+ }
+ }
+
+ info->map = strdup(map);
+ if (!info->map) {
+ free(buf);
+ free_map_type_info(info);
+ return NULL;
+ }
+
+ free(buf);
+
+ return info;
+}
+
--- autofs-5.0.4.orig/modules/lookup_file.c
+++ autofs-5.0.4/modules/lookup_file.c
@@ -523,10 +523,10 @@ prepare_plus_include(struct autofs_point
{
struct map_source *current;
struct map_source *source;
- char *type, *map, *fmt;
+ struct map_type_info *info;
const char *argv[2];
int argc;
- char *buf, *tmp;
+ char *buf;
current = ap->entry->current;
ap->entry->current = NULL;
@@ -548,33 +548,19 @@ prepare_plus_include(struct autofs_point
return NULL;
}
- type = fmt = NULL;
-
- /* Look for space terminator - ignore local options */
- map = buf;
- for (tmp = buf; *tmp; tmp++) {
- if (*tmp == ' ') {
- *tmp = '\0';
- break;
- } else if (*tmp == ',') {
- type = buf;
- *tmp++ = '\0';
- fmt = tmp;
- } else if (*tmp == ':') {
- if (!fmt)
- type = buf;
- *tmp++ = '\0';
- map = tmp;
- }
- if (*tmp == '\\')
- tmp++;
+ if (!(info = parse_map_type_info(buf))) {
+ error(ap->logopt, MODPREFIX "failed to parse map info");
+ free(buf);
+ return NULL;
}
argc = 1;
- argv[0] = map;
+ argv[0] = info->map;
argv[1] = NULL;
- source = master_find_source_instance(current, type, fmt, argc, argv);
+ source = master_find_source_instance(current,
+ info->type, info->format,
+ argc, argv);
if (source)
/*
* Make sure included map age is in sync with its owner
@@ -582,8 +568,11 @@ prepare_plus_include(struct autofs_point
*/
source->age = age;
else {
- source = master_add_source_instance(current, type, fmt, age, argc, argv);
+ source = master_add_source_instance(current,
+ info->type, info->format,
+ age, argc, argv);
if (!source) {
+ free_map_type_info(info);
free(buf);
error(ap->logopt, "failed to add included map instance");
return NULL;
@@ -594,6 +583,7 @@ prepare_plus_include(struct autofs_point
if (inc)
source->recurse = 1;
+ free_map_type_info(info);
free(buf);
return source;
--- autofs-5.0.4.orig/modules/lookup_ldap.c
+++ autofs-5.0.4/modules/lookup_ldap.c
@@ -1119,11 +1119,26 @@ static int parse_server_string(unsigned
memcpy(ctxt->server, s, l);
*/
}
- } else if (strchr(ptr, ':') != NULL) {
- char *q = NULL;
+ } else if (strchr(ptr, ':') != NULL || *ptr == '[') {
+ const char *q = NULL;
/* Isolate the server. Include the port spec */
- q = strchr(ptr, ':');
+ if (*ptr != '[')
+ q = strchr(ptr, ':');
+ else {
+ q = ++ptr;
+ while (*q == ':' || isxdigit(*q))
+ q++;
+ if (*q != ']') {
+ crit(logopt, MODPREFIX
+ "invalid LDAP map syntax %s", ptr);
+ return 0;
+ }
+ q++;
+ if (*q == ':')
+ q++;
+ }
+
if (isdigit(*q))
while (isdigit(*q))
q++;
--- autofs-5.0.4.orig/modules/mount_autofs.c
+++ autofs-5.0.4/modules/mount_autofs.c
@@ -50,7 +50,7 @@ int mount_mount(struct autofs_point *ap,
int argc, status, ghost = ap->flags & MOUNT_FLAG_GHOST;
time_t timeout = ap->exp_timeout;
unsigned logopt = ap->logopt;
- char *type, *format, *tmp, *tmp2;
+ struct map_type_info *info;
struct master *master;
struct master_mapent *entry;
struct map_source *source;
@@ -174,21 +174,12 @@ int mount_mount(struct autofs_point *ap,
argc = 1;
- type = NULL;
- format = NULL;
-
- tmp = strchr(what, ':');
- if (tmp) {
- *tmp++ = '\0';
- tmp2 = strchr(what, ',');
- if (tmp2) {
- *tmp2++ = '\0';
- format = tmp2;
- }
- type = (char *) what;
- argv[0] = tmp;
- } else
- argv[0] = (char *) what;
+ if (!(info = parse_map_type_info(what))) {
+ error(ap->logopt, MODPREFIX "failed to parse map info");
+ master_free_mapent(entry);
+ return 1;
+ }
+ argv[0] = info->map;
if (options) {
p = options;
@@ -202,13 +193,17 @@ int mount_mount(struct autofs_point *ap,
}
argv[argc] = NULL;
- source = master_add_map_source(entry, type, format, time(NULL), argc, argv);
+ source = master_add_map_source(entry,
+ info->type, info->format,
+ time(NULL), argc, argv);
if (!source) {
error(ap->logopt,
MODPREFIX "failed to add map source to entry");
master_free_mapent(entry);
+ free_map_type_info(info);
return 1;
}
+ free_map_type_info(info);
source->mc = cache_init(entry->ap, source);
if (!source->mc) {
--- autofs-5.0.4.orig/modules/parse_sun.c
+++ autofs-5.0.4/modules/parse_sun.c
@@ -245,7 +245,9 @@ int expandsunent(const char *src, char *
*(dst++) =
(seen_colons && slashify_colons) ? '/' : ':';
len++;
- seen_colons = 1;
+ /* Were looking for the colon preceeding a path */
+ if (*src == '/')
+ seen_colons = 1;
break;
default:
@@ -814,21 +816,23 @@ static int validate_location(char *loc)
return 1;
/*
- * If a ':' is present now it must be a host name, except
+ * If a ':/' is present now it must be a host name, except
* for those special file systems like sshfs which use "#"
- * and "@" in the host name part.
+ * and "@" in the host name part and ipv6 addresses that
+ * have ":", "[" and "]".
*/
if (check_colon(ptr)) {
- while (*ptr && *ptr != ':') {
+ while (*ptr && strncmp(ptr, ":/", 2)) {
if (!(isalnum(*ptr) ||
*ptr == '-' || *ptr == '.' || *ptr == '_' ||
*ptr == ',' || *ptr == '(' || *ptr == ')' ||
- *ptr == '#' || *ptr == '@'))
+ *ptr == '#' || *ptr == '@' || *ptr == ':' ||
+ *ptr == '[' || *ptr == ']'))
return 0;
ptr++;
}
- if (*ptr && *ptr == ':')
+ if (*ptr && !strncmp(ptr, ":/", 2))
ptr++;
}
--- autofs-5.0.4.orig/modules/replicated.c
+++ autofs-5.0.4/modules/replicated.c
@@ -1168,6 +1168,28 @@ static int add_local_path(struct host **
return 1;
}
+static char *seek_delim(const char *s)
+{
+ const char *p = s;
+ char *delim;
+
+ delim = strpbrk(p, "(, \t:");
+ if (delim && *delim != ':')
+ return delim;
+
+ while (*p) {
+ if (*p != ':') {
+ p++;
+ continue;
+ }
+ if (!strncmp(p, ":/", 2))
+ return (char *) p;
+ p++;
+ }
+
+ return NULL;
+}
+
int parse_location(unsigned logopt, struct host **hosts, const char *list)
{
char *str, *p, *delim;
@@ -1187,7 +1209,7 @@ int parse_location(unsigned logopt, stru
int weight = 0;
p += strspn(p, " \t,");
- delim = strpbrk(p, "(, \t:");
+ delim = seek_delim(p);
if (delim) {
if (*delim == '(') {
@@ -1211,7 +1233,7 @@ int parse_location(unsigned logopt, stru
/* Oh boy - might have spaces in the path */
next = path;
- while (*next && *next != ':')
+ while (*next && strncmp(next, ":/", 2))
next++;
/* No spaces in host names at least */
--- autofs-5.0.4.orig/CHANGELOG
+++ autofs-5.0.4/CHANGELOG
@@ -19,6 +19,7 @@
- make some easy alloca replacements (Valerie Aurora Henson).
- update to configure libtirpc if present.
- update to provide ipv6 name and address support.
+- update to provide ipv6 address parsing.
4/11/2008 autofs-5.0.4
-----------------------

View File

@ -0,0 +1,352 @@
autofs-5.0.4 - library reload fix update
From: Ian Kent <raven@themaw.net>
We still have a problem with libxml2 being unloaded before its thread
specific data destructor is called. This is due to the main thread
exiting (closing the handle we hold open to prevent this) before all
the mount handling threads have actually completed. This patch makes
the mount handling threads joinable (and joins with them as they exit)
to ensure that the mount handling threads have completed before allowing
the main thread to complete.
---
daemon/automount.c | 35 +++++++++++++++++++++++------------
daemon/direct.c | 7 ++++---
daemon/indirect.c | 7 ++++---
daemon/state.c | 7 ++++---
include/master.h | 3 +++
lib/master.c | 38 ++++++++++++++++++++++++++++++++++----
modules/mount_autofs.c | 4 ++--
7 files changed, 74 insertions(+), 27 deletions(-)
diff --git a/daemon/automount.c b/daemon/automount.c
index e120f50..f04273f 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -69,8 +69,9 @@ static size_t kpkt_len;
/* Does kernel know about SOCK_CLOEXEC and friends */
static int cloexec_works = 0;
-/* Attribute to create detached thread */
-pthread_attr_t thread_attr;
+/* Attributes for creating detached and joinable threads */
+pthread_attr_t th_attr;
+pthread_attr_t th_attr_detached;
struct master_readmap_cond mrc = {
PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, NULL, 0, 0, 0, 0};
@@ -1192,7 +1193,7 @@ static pthread_t do_signals(struct master *master, int sig)
if (status)
fatal(status);
- status = pthread_create(&thid, &thread_attr, do_notify_state, &r_sig);
+ status = pthread_create(&thid, &th_attr_detached, do_notify_state, &r_sig);
if (status) {
error(master->logopt,
"mount state notify thread create failed");
@@ -1281,7 +1282,7 @@ static int do_hup_signal(struct master *master, time_t age)
master->reading = 1;
- status = pthread_create(&thid, &thread_attr, do_read_master, NULL);
+ status = pthread_create(&thid, &th_attr_detached, do_read_master, NULL);
if (status) {
error(logopt,
"master read map thread create failed");
@@ -1327,7 +1328,7 @@ static void *statemachine(void *arg)
case SIGTERM:
case SIGINT:
case SIGUSR2:
- if (master_list_empty(master_list))
+ if (master_done(master_list))
return NULL;
case SIGUSR1:
do_signals(master_list, sig);
@@ -1448,8 +1449,6 @@ static void handle_mounts_cleanup(void *arg)
master_mutex_unlock();
destroy_logpri_fifo(ap);
- master_free_mapent_sources(ap->entry, 1);
- master_free_mapent(ap->entry);
if (clean) {
if (rmdir(path) == -1) {
@@ -1461,8 +1460,12 @@ static void handle_mounts_cleanup(void *arg)
info(logopt, "shut down path %s", path);
- /* If we are the last tell the state machine to shutdown */
- if (!submount && master_list_empty(master_list))
+ /*
+ * If we are not a submount send a signal to the signal handler
+ * so it can join with any completed handle_mounts() threads and
+ * perform final cleanup.
+ */
+ if (!submount)
pthread_kill(state_mach_thid, SIGTERM);
return;
@@ -1980,7 +1983,15 @@ int main(int argc, char *argv[])
exit(1);
}
- if (pthread_attr_init(&thread_attr)) {
+ if (pthread_attr_init(&th_attr)) {
+ logerr("%s: failed to init thread attribute struct!",
+ program);
+ close(start_pipefd[1]);
+ release_flag_file();
+ exit(1);
+ }
+
+ if (pthread_attr_init(&th_attr_detached)) {
logerr("%s: failed to init thread attribute struct!",
program);
close(start_pipefd[1]);
@@ -1989,7 +2000,7 @@ int main(int argc, char *argv[])
}
if (pthread_attr_setdetachstate(
- &thread_attr, PTHREAD_CREATE_DETACHED)) {
+ &th_attr_detached, PTHREAD_CREATE_DETACHED)) {
logerr("%s: failed to set detached thread attribute!",
program);
close(start_pipefd[1]);
@@ -1999,7 +2010,7 @@ int main(int argc, char *argv[])
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
if (pthread_attr_setstacksize(
- &thread_attr, PTHREAD_STACK_MIN*64)) {
+ &th_attr_detached, PTHREAD_STACK_MIN*64)) {
logerr("%s: failed to set stack size thread attribute!",
program);
close(start_pipefd[1]);
diff --git a/daemon/direct.c b/daemon/direct.c
index c0243c4..d9dda3d 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -37,7 +37,8 @@
#include "automount.h"
-extern pthread_attr_t thread_attr;
+/* Attribute to create detached thread */
+extern pthread_attr_t th_attr_detached;
struct mnt_params {
char *options;
@@ -1142,7 +1143,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
debug(ap->logopt, "token %ld, name %s",
(unsigned long) pkt->wait_queue_token, mt->name);
- status = pthread_create(&thid, &thread_attr, do_expire_direct, mt);
+ status = pthread_create(&thid, &th_attr_detached, do_expire_direct, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
ops->send_fail(ap->logopt,
@@ -1451,7 +1452,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
mt->gid = pkt->gid;
mt->wait_queue_token = pkt->wait_queue_token;
- status = pthread_create(&thid, &thread_attr, do_mount_direct, mt);
+ status = pthread_create(&thid, &th_attr_detached, do_mount_direct, mt);
if (status) {
error(ap->logopt, "missing mount thread create failed");
ops->send_fail(ap->logopt,
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 9d3745c..0721707 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -36,7 +36,8 @@
#include "automount.h"
-extern pthread_attr_t thread_attr;
+/* Attribute to create detached thread */
+extern pthread_attr_t th_attr_detached;
static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -647,7 +648,7 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
mt->len = pkt->len;
mt->wait_queue_token = pkt->wait_queue_token;
- status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt);
+ status = pthread_create(&thid, &th_attr_detached, do_expire_indirect, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
ops->send_fail(ap->logopt,
@@ -835,7 +836,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
mt->gid = pkt->gid;
mt->wait_queue_token = pkt->wait_queue_token;
- status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt);
+ status = pthread_create(&thid, &th_attr_detached, do_mount_indirect, mt);
if (status) {
error(ap->logopt, "expire thread create failed");
ops->send_fail(ap->logopt,
diff --git a/daemon/state.c b/daemon/state.c
index 87c16a6..cd63be1 100644
--- a/daemon/state.c
+++ b/daemon/state.c
@@ -16,7 +16,8 @@
#include "automount.h"
-extern pthread_attr_t thread_attr;
+/* Attribute to create detached thread */
+extern pthread_attr_t th_attr_detached;
struct state_queue {
pthread_t thid;
@@ -292,7 +293,7 @@ static enum expire expire_proc(struct autofs_point *ap, int now)
else
expire = expire_proc_direct;
- status = pthread_create(&thid, &thread_attr, expire, ea);
+ status = pthread_create(&thid, &th_attr_detached, expire, ea);
if (status) {
error(ap->logopt,
"expire thread create for %s failed", ap->path);
@@ -519,7 +520,7 @@ static unsigned int st_readmap(struct autofs_point *ap)
ra->ap = ap;
ra->now = now;
- status = pthread_create(&thid, &thread_attr, do_readmap, ra);
+ status = pthread_create(&thid, &th_attr_detached, do_readmap, ra);
if (status) {
error(ap->logopt, "read map thread create failed");
st_readmap_cleanup(ra);
diff --git a/include/master.h b/include/master.h
index 6d801a9..c519e97 100644
--- a/include/master.h
+++ b/include/master.h
@@ -48,6 +48,7 @@ struct master_mapent {
struct map_source *maps;
struct autofs_point *ap;
struct list_head list;
+ struct list_head join;
};
struct master {
@@ -61,6 +62,7 @@ struct master {
unsigned int logopt;
struct mapent_cache *nc;
struct list_head mounts;
+ struct list_head completed;
};
/* From the yacc master map parser */
@@ -109,6 +111,7 @@ void master_notify_state_change(struct master *, int);
int master_mount_mounts(struct master *, time_t, int);
extern inline unsigned int master_get_logopt(void);
int master_list_empty(struct master *);
+int master_done(struct master *);
int master_kill(struct master *);
#endif
diff --git a/lib/master.c b/lib/master.c
index e1cc062..762094f 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -32,8 +32,8 @@ struct master *master_list = NULL;
extern long global_negative_timeout;
-/* Attribute to create detached thread */
-extern pthread_attr_t thread_attr;
+/* Attribute to create a joinable thread */
+extern pthread_attr_t th_attr;
extern struct startup_cond suc;
@@ -704,11 +704,16 @@ void master_add_mapent(struct master *master, struct master_mapent *entry)
void master_remove_mapent(struct master_mapent *entry)
{
+ struct master *master = entry->master;
+
if (entry->ap->submount)
return;
- if (!list_empty(&entry->list))
+ if (!list_empty(&entry->list)) {
list_del_init(&entry->list);
+ list_add(&entry->join, &master->completed);
+ }
+
return;
}
@@ -786,6 +791,7 @@ struct master *master_new(const char *name, unsigned int timeout, unsigned int g
master->logopt = master->default_logging;
INIT_LIST_HEAD(&master->mounts);
+ INIT_LIST_HEAD(&master->completed);
return master;
}
@@ -993,7 +999,7 @@ static int master_do_mount(struct master_mapent *entry)
debug(ap->logopt, "mounting %s", entry->path);
- status = pthread_create(&thid, &thread_attr, handle_mounts, &suc);
+ status = pthread_create(&thid, &th_attr, handle_mounts, &suc);
if (status) {
crit(ap->logopt,
"failed to create mount handler thread for %s",
@@ -1170,6 +1176,30 @@ int master_list_empty(struct master *master)
return res;
}
+int master_done(struct master *master)
+{
+ struct list_head *head, *p;
+ struct master_mapent *entry;
+ int res = 0;
+
+ master_mutex_lock();
+ head = &master->completed;
+ p = head->next;
+ while (p != head) {
+ entry = list_entry(p, struct master_mapent, join);
+ p = p->next;
+ list_del(&entry->join);
+ pthread_join(entry->thid, NULL);
+ master_free_mapent_sources(entry, 1);
+ master_free_mapent(entry);
+ }
+ if (list_empty(&master->mounts))
+ res = 1;
+ master_mutex_unlock();
+
+ return res;
+}
+
inline unsigned int master_get_logopt(void)
{
return master_list ? master_list->logopt : LOGOPT_NONE;
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index 82a5ef3..44fc043 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -30,7 +30,7 @@
#define MODPREFIX "mount(autofs): "
/* Attribute to create detached thread */
-extern pthread_attr_t thread_attr;
+extern pthread_attr_t th_attr_detached;
extern struct startup_cond suc;
int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
@@ -235,7 +235,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
suc.done = 0;
suc.status = 0;
- if (pthread_create(&thid, &thread_attr, handle_mounts, &suc)) {
+ if (pthread_create(&thid, &th_attr_detached, handle_mounts, &suc)) {
crit(ap->logopt,
MODPREFIX
"failed to create mount handler thread for %s",

View File

@ -0,0 +1,222 @@
autofs-5.0.4 - make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit
From: Valerie Aurora Henson <vaurora@redhat.com>
Non-critical changes to make auditing buffer lengths easier.
* Some buffers were the wrong (too big) size, some were used twice for
different purposes.
* Use sizeof(buf) instead of repeating the *MAX* define in functions
that need to know the size of a statically allocated buffer.
* Fix a compiler warning about discarding the const on a string.
---
CHANGELOG | 1 +
modules/lookup_ldap.c | 51 ++++++++++++++++++++++---------------------------
2 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index afd1335..417a001 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@
- add "forcestart" and "forcerestart" init script options to allow
use of 5.0.3 strartup behavior if required.
- always read entire file map into cache to speed lookups.
+- make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index bee97ae..d8a60d3 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -272,7 +272,7 @@ LDAP *init_ldap_connection(unsigned logopt, const char *uri, struct lookup_conte
static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt, const char *class, const char *key)
{
- char buf[PARSE_MAX_BUF];
+ char buf[MAX_ERR_BUF];
char *query, *dn, *qdn;
LDAPMessage *result, *e;
struct ldap_searchdn *sdns = NULL;
@@ -296,7 +296,7 @@ static int get_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt
query = alloca(l);
if (query == NULL) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ char *estr = strerror_r(errno, buf, sizeof(buf));
crit(logopt, MODPREFIX "alloca: %s", estr);
return NSS_STATUS_UNAVAIL;
}
@@ -1082,7 +1082,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
}
if (!tmp) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
return 0;
}
@@ -1104,7 +1104,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
tmp = malloc(l + 1);
if (!tmp) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
crit(logopt, MODPREFIX "malloc: %s", estr);
return 0;
}
@@ -1139,7 +1139,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
/* Isolate the server's name. */
if (!tmp) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
return 0;
}
@@ -1180,7 +1180,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
ctxt->mapname = map;
else {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
if (ctxt->server)
free(ctxt->server);
@@ -1191,7 +1191,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
base = malloc(l + 1);
if (!base) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
if (ctxt->server)
free(ctxt->server);
@@ -1205,7 +1205,7 @@ static int parse_server_string(unsigned logopt, const char *url, struct lookup_c
char *map = malloc(l + 1);
if (!map) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
if (ctxt->server)
free(ctxt->server);
@@ -1318,7 +1318,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
/* If we can't build a context, bail. */
ctxt = malloc(sizeof(struct lookup_context));
if (!ctxt) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ char *estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
return 1;
}
@@ -1419,8 +1419,9 @@ int lookup_read_master(struct master *master, time_t age, void *context)
unsigned int timeout = master->default_timeout;
unsigned int logging = master->default_logging;
unsigned int logopt = master->logopt;
- int rv, l, count, blen;
- char buf[PARSE_MAX_BUF];
+ int rv, l, count;
+ char buf[MAX_ERR_BUF];
+ char parse_buf[PARSE_MAX_BUF];
char *query;
LDAPMessage *result, *e;
char *class, *info, *entry;
@@ -1442,7 +1443,7 @@ int lookup_read_master(struct master *master, time_t age, void *context)
query = alloca(l);
if (query == NULL) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ char *estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "alloca: %s", estr);
return NSS_STATUS_UNAVAIL;
}
@@ -1532,19 +1533,13 @@ int lookup_read_master(struct master *master, time_t age, void *context)
goto next;
}
- blen = strlen(*keyValue) + 1 + strlen(*values) + 2;
- if (blen > PARSE_MAX_BUF) {
+ if (snprintf(parse_buf, sizeof(parse_buf), "%s %s",
+ *keyValue, *values) >= sizeof(parse_buf)) {
error(logopt, MODPREFIX "map entry too long");
ldap_value_free(values);
goto next;
}
- memset(buf, 0, PARSE_MAX_BUF);
-
- strcpy(buf, *keyValue);
- strcat(buf, " ");
- strcat(buf, *values);
-
- master_parse_entry(buf, timeout, logging, age);
+ master_parse_entry(parse_buf, timeout, logging, age);
next:
ldap_value_free(keyValue);
e = ldap_next_entry(ldap, e);
@@ -1561,7 +1556,7 @@ static int get_percent_decoded_len(const char *name)
{
int escapes = 0;
int escaped = 0;
- char *tmp = name;
+ const char *tmp = name;
int look_for_close = 0;
while (*tmp) {
@@ -2060,7 +2055,7 @@ static int do_get_entries(struct ldap_search_params *sp, struct map_source *sour
mapent = malloc(v_len + 1);
if (!mapent) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
ldap_value_free_len(bvValues);
goto next;
@@ -2080,7 +2075,7 @@ static int do_get_entries(struct ldap_search_params *sp, struct map_source *sour
mapent_len = new_size;
} else {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "realloc: %s", estr);
}
}
@@ -2181,7 +2176,7 @@ static int read_one_map(struct autofs_point *ap,
sp.query = alloca(l);
if (sp.query == NULL) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ char *estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
return NSS_STATUS_UNAVAIL;
}
@@ -2335,7 +2330,7 @@ static int lookup_one(struct autofs_point *ap,
query = alloca(l);
if (query == NULL) {
- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ char *estr = strerror_r(errno, buf, sizeof(buf));
crit(ap->logopt, MODPREFIX "malloc: %s", estr);
if (enc_len1) {
free(enc_key1);
@@ -2507,7 +2502,7 @@ static int lookup_one(struct autofs_point *ap,
mapent = malloc(v_len + 1);
if (!mapent) {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "malloc: %s", estr);
ldap_value_free_len(bvValues);
goto next;
@@ -2527,7 +2522,7 @@ static int lookup_one(struct autofs_point *ap,
mapent_len = new_size;
} else {
char *estr;
- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ estr = strerror_r(errno, buf, sizeof(buf));
logerr(MODPREFIX "realloc: %s", estr);
}
}

View File

@ -0,0 +1,61 @@
autofs-5.0.4 - renew sasl creds upon reconnect fail
From: Ian Kent <raven@themaw.net>
If a server re-connect fails it could be due to the authentication
credentail having timed out. So we need to dispose of this and retry
the connection including refreshing re-authenticating.
---
CHANGELOG | 1 +
modules/lookup_ldap.c | 17 +++++++++++++++++
2 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index b093451..7dee674 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,6 +11,7 @@
- use CLOEXEC flag for setmntent also.
- fix hosts map use after free.
- fix uri list locking (again).
+- check for stale SASL credentials upon connect fail.
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index b6784e1..bee97ae 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -675,6 +675,13 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
if (ctxt->server || !ctxt->uris) {
ldap = do_connect(logopt, ctxt->server, ctxt);
+#ifdef WITH_SASL
+ /* Dispose of the sasl authentication connection and try again. */
+ if (!ldap) {
+ autofs_sasl_dispose(ctxt);
+ ldap = connect_to_server(logopt, ctxt->server, ctxt);
+ }
+#endif
return ldap;
}
@@ -682,6 +689,16 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
this = ctxt->uri;
uris_mutex_unlock(ctxt);
ldap = do_connect(logopt, this->uri, ctxt);
+#ifdef WITH_SASL
+ /*
+ * Dispose of the sasl authentication connection and try the
+ * current server again before trying other servers in the list.
+ */
+ if (!ldap) {
+ autofs_sasl_dispose(ctxt);
+ ldap = connect_to_server(logopt, this->uri, ctxt);
+ }
+#endif
if (ldap)
return ldap;

View File

@ -0,0 +1,224 @@
autofs-5.0.4 - uris list locking fix
From: Ian Kent <raven@themaw.net>
The ldap uris list doesn't need to change we just need to keep
track of current server uri in the list and try to connect in
a round robin order. Also it's possible multiple concurrent
connection attempts may not be able to use the full list of
servers (if one is present).
---
CHANGELOG | 1 +
include/lookup_ldap.h | 3 +-
modules/lookup_ldap.c | 68 ++++++++++++++++++++++---------------------------
3 files changed, 33 insertions(+), 39 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 3199e4d..b093451 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,7 @@
- clear the quoted flag after each character from program map input.
- use CLOEXEC flag for setmntent also.
- fix hosts map use after free.
+- fix uri list locking (again).
4/11/2008 autofs-5.0.4
-----------------------
diff --git a/include/lookup_ldap.h b/include/lookup_ldap.h
index f9ed778..b47bf5d 100644
--- a/include/lookup_ldap.h
+++ b/include/lookup_ldap.h
@@ -55,7 +55,8 @@ struct lookup_context {
* given in configuration.
*/
pthread_mutex_t uris_mutex;
- struct list_head *uri;
+ struct list_head *uris;
+ struct ldap_uri *uri;
char *cur_host;
struct ldap_searchdn *sdns;
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 6ba80eb..b6784e1 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -137,7 +137,7 @@ static void uris_mutex_unlock(struct lookup_context *ctxt)
return;
}
-int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
{
int rv;
@@ -147,16 +147,14 @@ int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt
rv = ldap_simple_bind_s(ldap, NULL, NULL);
if (rv != LDAP_SUCCESS) {
- if (!ctxt->uri) {
+ if (!ctxt->uris) {
crit(logopt, MODPREFIX
"Unable to bind to the LDAP server: "
"%s, error %s", ctxt->server ? "" : "(default)",
ldap_err2string(rv));
} else {
- struct ldap_uri *uri;
- uri = list_entry(ctxt->uri->next, struct ldap_uri, list);
info(logopt, MODPREFIX "Unable to bind to the LDAP server: "
- "%s, error %s", uri->uri, ldap_err2string(rv));
+ "%s, error %s", uri, ldap_err2string(rv));
}
return -1;
}
@@ -498,7 +496,7 @@ static int find_query_dn(unsigned logopt, LDAP *ldap, struct lookup_context *ctx
return 0;
}
-static int do_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
+static int do_bind(unsigned logopt, LDAP *ldap, const char *uri, struct lookup_context *ctxt)
{
char *host = NULL, *nhost;
int rv, need_base = 1;
@@ -511,11 +509,11 @@ static int do_bind(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt)
rv = autofs_sasl_bind(logopt, ldap, ctxt);
debug(logopt, MODPREFIX "autofs_sasl_bind returned %d", rv);
} else {
- rv = bind_ldap_anonymous(logopt, ldap, ctxt);
+ rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
}
#else
- rv = bind_ldap_anonymous(logopt, ldap, ctxt);
+ rv = bind_ldap_anonymous(logopt, ldap, uri, ctxt);
debug(logopt, MODPREFIX "ldap anonymous bind returned %d", rv);
#endif
@@ -584,7 +582,7 @@ static LDAP *do_connect(unsigned logopt, const char *uri, struct lookup_context
if (!ldap)
return NULL;
- if (!do_bind(logopt, ldap, ctxt)) {
+ if (!do_bind(logopt, ldap, uri, ctxt)) {
unbind_ldap_connection(logopt, ldap, ctxt);
return NULL;
}
@@ -612,7 +610,7 @@ static LDAP *connect_to_server(unsigned logopt, const char *uri, struct lookup_c
return NULL;
}
- if (!do_bind(logopt, ldap, ctxt)) {
+ if (!do_bind(logopt, ldap, uri, ctxt)) {
unbind_ldap_connection(logopt, ldap, ctxt);
autofs_sasl_dispose(ctxt);
error(logopt, MODPREFIX "cannot bind to server");
@@ -638,36 +636,34 @@ static LDAP *find_server(unsigned logopt, struct lookup_context *ctxt)
{
LDAP *ldap = NULL;
struct ldap_uri *this;
- struct list_head *p;
- LIST_HEAD(tmp);
+ struct list_head *p, *first;
/* Try each uri in list, add connect fails to tmp list */
uris_mutex_lock(ctxt);
- p = ctxt->uri->next;
- while(p != ctxt->uri) {
+ if (!ctxt->uri)
+ first = ctxt->uris;
+ else
+ first = &ctxt->uri->list;
+ uris_mutex_unlock(ctxt);
+ p = first->next;
+ while(p != first) {
+ /* Skip list head */
+ if (p == ctxt->uris) {
+ p = p->next;
+ continue;
+ }
this = list_entry(p, struct ldap_uri, list);
- uris_mutex_unlock(ctxt);
debug(logopt, "trying server %s", this->uri);
ldap = connect_to_server(logopt, this->uri, ctxt);
if (ldap) {
info(logopt, "connected to uri %s", this->uri);
uris_mutex_lock(ctxt);
+ ctxt->uri = this;
+ uris_mutex_unlock(ctxt);
break;
}
- uris_mutex_lock(ctxt);
p = p->next;
- list_del_init(&this->list);
- list_add_tail(&this->list, &tmp);
}
- /*
- * Successfuly connected uri (head of list) and untried uris are
- * in ctxt->uri list. Make list of remainder and failed uris with
- * failed uris at end and assign back to ctxt-uri.
- */
- list_splice(ctxt->uri, &tmp);
- INIT_LIST_HEAD(ctxt->uri);
- list_splice(&tmp, ctxt->uri);
- uris_mutex_unlock(ctxt);
return ldap;
}
@@ -677,23 +673,19 @@ static LDAP *do_reconnect(unsigned logopt, struct lookup_context *ctxt)
struct ldap_uri *this;
LDAP *ldap;
- if (ctxt->server || !ctxt->uri) {
+ if (ctxt->server || !ctxt->uris) {
ldap = do_connect(logopt, ctxt->server, ctxt);
return ldap;
}
uris_mutex_lock(ctxt);
- this = list_entry(ctxt->uri->next, struct ldap_uri, list);
+ this = ctxt->uri;
uris_mutex_unlock(ctxt);
ldap = do_connect(logopt, this->uri, ctxt);
if (ldap)
return ldap;
- /* Failed to connect, put at end of list */
- uris_mutex_lock(ctxt);
- list_del_init(&this->list);
- list_add_tail(&this->list, ctxt->uri);
- uris_mutex_unlock(ctxt);
+ /* Failed to connect, try to find a new server */
#ifdef WITH_SASL
autofs_sasl_dispose(ctxt);
@@ -1259,8 +1251,8 @@ static void free_context(struct lookup_context *ctxt)
free(ctxt->cur_host);
if (ctxt->base)
free(ctxt->base);
- if (ctxt->uri)
- defaults_free_uris(ctxt->uri);
+ if (ctxt->uris)
+ defaults_free_uris(ctxt->uris);
ret = pthread_mutex_destroy(&ctxt->uris_mutex);
if (ret)
fatal(ret);
@@ -1344,7 +1336,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
if (uris) {
validate_uris(uris);
if (!list_empty(uris))
- ctxt->uri = uris;
+ ctxt->uris = uris;
else {
error(LOGOPT_ANY,
"no valid uris found in config list"
@@ -1375,7 +1367,7 @@ int lookup_init(const char *mapfmt, int argc, const char *const *argv, void **co
}
#endif
- if (ctxt->server || !ctxt->uri) {
+ if (ctxt->server || !ctxt->uris) {
ldap = connect_to_server(LOGOPT_NONE, ctxt->server, ctxt);
if (!ldap) {
free_context(ctxt);

View File

@ -4,7 +4,7 @@
Summary: A tool for automatically mounting and unmounting filesystems
Name: autofs
Version: 5.0.4
Release: 8
Release: 9
Epoch: 1
License: GPLv2+
Group: System Environment/Daemons
@ -19,6 +19,18 @@ Patch6: autofs-5.0.4-fix-select-fd-limit.patch
Patch7: autofs-5.0.4-make-hash-table-scale-to-thousands-of-entries.patch
Patch8: autofs-5.0.4-fix-quoted-mess.patch
Patch9: autofs-5.0.4-use-CLOEXEC-flag-setmntent.patch
Patch10: autofs-5.0.4-fix-hosts-map-use-after-free.patch
Patch11: autofs-5.0.4-uris-list-locking-fix.patch
Patch12: autofs-5.0.4-renew-sasl-creds-upon-reconnect-fail.patch
Patch13: autofs-5.0.4-library-reload-fix-update.patch
Patch14: autofs-5.0.4-force-unlink-umount.patch
Patch15: autofs-5.0.4-always-read-file-maps.patch
Patch16: autofs-5.0.4-code-analysis-corrections.patch
Patch17: autofs-5.0.4-make-MAX_ERR_BUF-and-PARSE_MAX_BUF-use-easier-to-audit.patch
Patch18: autofs-5.0.4-easy-alloca-replacements.patch
Patch19: autofs-5.0.4-configure-libtirpc.patch
Patch20: autofs-5.0.4-ipv6-name-and-address-support.patch
Patch21: autofs-5.0.4-ipv6-parse.patch
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs
Requires: kernel >= 2.6.17
@ -69,10 +81,22 @@ echo %{version}-%{release} > .version
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%build
#CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir}
%configure --disable-mount-locking --enable-ignore-busy
%configure --disable-mount-locking --enable-ignore-busy --with-libtirpc
make initdir=%{_initrddir} DONTSTRIP=1
%install
@ -121,6 +145,19 @@ fi
%{_libdir}/autofs/
%changelog
* Mon Feb 16 2009 Ian Kent <ikent@redhat.com> - 5.0.4-9
- fix hosts map use after free.
- fix uri list locking (again).
- check for stale SASL credentials upon connect fail.
- add "forcestart" and "forcerestart" init script options to allow
use of 5.0.3 strartup behavior if required.
- always read entire file map into cache to speed lookups.
- make MAX_ERR_BUF and PARSE_MAX_BUF use easier to audit.
- make some easy alloca replacements.
- update to configure libtirpc if present.
- update to provide ipv6 name and address support.
- update to provide ipv6 address parsing.
* Thu Feb 5 2009 Ian Kent <ikent@redhat.com> - 5.0.4-8
- rename program map parsing bug fix patch.
- use CLOEXEC flag functionality for setmntent also, if present.