diff --git a/CHANGELOG b/CHANGELOG index 48d811a..93a4df5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ --------------------- - code cleanup. - fix race for current map source. +- cthon map parser corrections. 13/7/2006 autofs-5.0.1 rc1 -------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 23c123f..95eba4b 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -1368,8 +1368,8 @@ void *handle_mounts(void *arg) * So, the solution is a recipe for disaster. * Hope we don't get a really busy system! */ - /* sleep(1); */ - sched_yield(); + sleep(5); + /* sched_yield(); */ return NULL; } diff --git a/include/automount.h b/include/automount.h index 908b308..8a5b800 100644 --- a/include/automount.h +++ b/include/automount.h @@ -28,6 +28,7 @@ #include "master.h" #include "macros.h" #include "log.h" #include "rpc_subs.h" +#include "parse_subs.h" #ifdef WITH_DMALLOC #include @@ -115,6 +116,7 @@ #define CHE_UPDATED 0x0002 #define CHE_RMPATH 0x0004 #define CHE_MISSING 0x0008 #define CHE_COMPLETED 0x0010 +#define CHE_DUPLICATE 0x0020 #define HASHSIZE 77 #define NEGATIVE_TIMEOUT 10 diff --git a/lib/Makefile b/lib/Makefile index 5eddebb..5c4d022 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,12 +8,12 @@ include ../Makefile.rules SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \ master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \ - args.c alarm.c macros.c master.c defaults.c + args.c alarm.c macros.c master.c defaults.c parse_subs.c RPCS = mount.h mount_clnt.c mount_xdr.c OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \ mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \ nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \ - defaults.o + defaults.o parse_subs.o YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \ master_tok.c master_parse.tab.c master_parse.tab.h diff --git a/lib/cache.c b/lib/cache.c index 6736a88..ffc4c9b 100644 --- a/lib/cache.c +++ b/lib/cache.c @@ -446,6 +446,7 @@ static void cache_add_ordered_offset(str { struct list_head *p; struct mapent *this; + int status = CHE_OK; list_for_each(p, head) { size_t tlen; @@ -456,15 +457,15 @@ static void cache_add_ordered_offset(str eq = strncmp(this->key, me->key, tlen); if (!eq && tlen == strlen(me->key)) - goto done; + return; if (eq > 0) { list_add_tail(&me->multi_list, p); - goto done; + return; } } list_add_tail(&me->multi_list, p); -done: + return; } @@ -478,7 +479,11 @@ int cache_add_offset(struct mapent_cache if (!owner) return CHE_FAIL; - ret = cache_update(mc, owner->source, key, mapent, age); + me = cache_lookup_distinct(mc, key); + if (me && me != owner) + return CHE_DUPLICATE; + + ret = cache_add(mc, owner->source, key, mapent, age); if (ret == CHE_FAIL) { warn(LOGOPT_ANY, "failed to add key %s to cache", key); return CHE_FAIL; diff --git a/modules/lookup_file.c b/modules/lookup_file.c index 913af6a..a515d70 100644 --- a/modules/lookup_file.c +++ b/modules/lookup_file.c @@ -182,6 +182,8 @@ static int read_one(FILE *f, char *key, state = st_begin; if (gotten == got_plus) goto got_it; + if (escape != esc_val) + goto got_it; } else if (isspace(ch) && !escape) { getting = got_real; state = st_entspc; @@ -192,7 +194,7 @@ static int read_one(FILE *f, char *key, if (key_len == KEY_MAX_LEN) { state = st_badent; error(LOGOPT_ANY, - MODPREFIX "Map key \"%s...\" " + MODPREFIX "map key \"%s...\" " "is too long. The maximum key " "length is %d", key, KEY_MAX_LEN); @@ -214,8 +216,12 @@ static int read_one(FILE *f, char *key, break; case st_badent: - if (ch == '\n') + if (ch == '\n') { state = st_begin; + if (gotten == got_real || gotten == getting) + goto got_it; + goto next; + } break; case st_entspc: @@ -232,6 +238,16 @@ static int read_one(FILE *f, char *key, case st_getent: if (ch == '\n') { + nch = getc(f); + if (nch != EOF && isblank(nch)) { + state = st_badent; + ungetc(nch, f); + error(LOGOPT_ANY, MODPREFIX + "bad map entry \"%s...\" for key " + "\"%s\"", mapent, key); + break; + } + ungetc(nch, f); state = st_begin; if (gotten == got_real || gotten == getting) goto got_it; @@ -245,7 +261,7 @@ static int read_one(FILE *f, char *key, ungetc(nch, f); } else { error(LOGOPT_ANY, - MODPREFIX "Map entry \"%s...\" for key " + MODPREFIX "map entry \"%s...\" for key " "\"%s\" is too long. The maximum entry" " size is %d", mapent, key, MAPENT_MAX_LEN); @@ -640,15 +656,36 @@ int lookup_read_map(struct autofs_point master_free_mapent_sources(iap->entry, 0); master_free_mapent(iap->entry); } else { - if (ap->type == LKP_INDIRECT && *key == '/') + char *dq_key, *dq_mapent; + + dq_key = dequote(key, strlen(key), ap->logopt); + if (!dq_key) continue; - if (ap->type == LKP_DIRECT && *key != '/') + if (*dq_key == '/') { + if (ap->type == LKP_INDIRECT) { + free(dq_key); + continue; + } + } else { + if (ap->type == LKP_DIRECT) { + free(dq_key); + continue; + } + } + + dq_mapent = dequote(mapent, strlen(mapent), ap->logopt); + if (!dq_mapent) { + free(dq_key); continue; + } cache_writelock(mc); - cache_update(mc, source, key, mapent, age); + cache_update(mc, source, dq_key, dq_mapent, age); cache_unlock(mc); + + free(dq_key); + free(dq_mapent); } if (feof(f)) diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index 9a7794d..7986d3b 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -1146,6 +1146,7 @@ static int read_one_map(struct autofs_po while (e) { char *mapent = NULL; + char *dq_key, *dq_mapent; keyValue = ldap_get_values(ldap, e, entry); @@ -1227,18 +1228,37 @@ static int read_one_map(struct autofs_po } ldap_value_free(values); - if (**keyValue == '/' && strlen(*keyValue) == 1) - **keyValue = '*'; - - if (ap->type == LKP_INDIRECT && **keyValue == '/') + dq_key = dequote(*keyValue, strlen(*keyValue), ap->logopt); + if (!dq_key) goto next; - if (ap->type == LKP_DIRECT && **keyValue != '/') + if (*dq_key == '/' && strlen(dq_key) == 1) + *dq_key = '*'; + + if (*dq_key == '/') { + if (ap->type == LKP_INDIRECT) { + free(dq_key); + goto next; + } + } else { + if (ap->type == LKP_DIRECT) { + free(dq_key); + goto next; + } + } + + dq_mapent = dequote(mapent, strlen(mapent), ap->logopt); + if (!mapent) { + free(dq_key); goto next; + } cache_writelock(mc); - cache_update(mc, source, *keyValue, mapent, age); + cache_update(mc, source, dq_key, dq_mapent, age); cache_unlock(mc); + + free(dq_key); + free(dq_mapent); next: if (mapent) { free(mapent); diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c index cb5d620..4049f1b 100644 --- a/modules/lookup_nisplus.c +++ b/modules/lookup_nisplus.c @@ -202,6 +202,8 @@ int lookup_read_map(struct autofs_point result_count = NIS_RES_NUMOBJ(result); while (result_count--) { + char *dq_key, *dq_mapent; + this = &result->objects.objects_val[current++]; key = ENTRY_VAL(this, 0); /* @@ -211,16 +213,35 @@ int lookup_read_map(struct autofs_point if (*key == '+') continue; - if (ap->type == LKP_INDIRECT && *key == '/') + dq_key = dequote(key, ENTRY_LEN(this, 0), ap->logopt); + if (!dq_key) continue; - if (ap->type == LKP_DIRECT && *key != '/') - continue; + if (*dq_key == '/') { + if (ap->type == LKP_INDIRECT) { + free(dq_key); + continue; + } + } else { + if (ap->type == LKP_DIRECT) { + free(dq_key); + continue; + } + } mapent = ENTRY_VAL(this, 1); + dq_mapent = dequote(mapent, ENTRY_LEN(this, 1), ap->logopt); + if (!dq_mapent) { + free(dq_key); + continue; + } + cache_writelock(mc); - cache_update(mc, source, key, mapent, age); + cache_update(mc, source, dq_key, dq_mapent, age); cache_unlock(mc); + + free(dq_key); + free(dq_mapent); } nis_freeresult(result); diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c index 4114aaa..741e6ec 100644 --- a/modules/lookup_yp.c +++ b/modules/lookup_yp.c @@ -248,8 +248,7 @@ int yp_all_callback(int status, char *yp struct map_source *source = cbdata->source; struct mapent_cache *mc = source->mc; time_t age = cbdata->age; - char *key; - char *mapent; + char *key, *mapent; int ret; if (status != YP_TRUE) @@ -262,23 +261,35 @@ int yp_all_callback(int status, char *yp if (*ypkey == '+') return 0; - if (ap->type == LKP_INDIRECT && *ypkey == '/') - return 0; - - if (ap->type == LKP_DIRECT && *ypkey != '/') + key = dequote(ypkey, ypkeylen, ap->logopt); + if (!key) return 0; - key = alloca(ypkeylen + 1); - strncpy(key, ypkey, ypkeylen); - *(key + ypkeylen) = '\0'; + if (*key == '/') { + if (ap->type == LKP_INDIRECT) { + free(key); + return 0; + } + } else { + if (ap->type == LKP_DIRECT) { + free(key); + return 0; + } + } - mapent = alloca(vallen + 1); - strncpy(mapent, val, vallen); - *(mapent + vallen) = '\0'; + mapent = dequote(val, vallen, ap->logopt); + if (!mapent) { + free(key); + return 0; + } cache_writelock(mc); ret = cache_update(mc, source, key, mapent, age); cache_unlock(mc); + + free(key); + free(mapent); + if (ret == CHE_FAIL) return -1; diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c index 72a9c53..0ab2faf 100644 --- a/modules/mount_nfs.c +++ b/modules/mount_nfs.c @@ -227,7 +227,7 @@ int mount_mount(struct autofs_point *ap, err = spawnll(log_debug, PATH_MOUNT, PATH_MOUNT, "-t", - "nfs", SLOPPYOPT "-o", nfsoptions, + "nfs", "-o", nfsoptions, loc, fullpath, NULL); } else { debug(ap->logopt, diff --git a/modules/parse_sun.c b/modules/parse_sun.c index d415660..929698f 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -214,116 +214,6 @@ int expandsunent(const char *src, char * return len; } -/* - * Skip whitespace in a string; if we hit a #, consider the rest of the - * entry a comment. - */ -const char *skipspace(const char *whence) -{ - while (1) { - switch (*whence) { - case ' ': - case '\b': - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - whence++; - break; - case '#': /* comment: skip to end of string */ - while (*whence != '\0') - whence++; - /* FALLTHROUGH */ - - default: - return whence; - } - } -} - -/* - * Check a string to see if a colon appears before the next '/'. - */ -int check_colon(const char *str) -{ - char *ptr = (char *) str; - - while (*ptr && *ptr != ':' && *ptr != '/') { - ptr++; - } - - if (!*ptr || *ptr == '/') - return 0; - - return 1; -} - -/* Get the length of a chunk delimitered by whitespace */ -int chunklen(const char *whence, int expect_colon) -{ - int n = 0; - int quote = 0; - - for (; *whence; whence++, n++) { - switch (*whence) { - case '\\': - if( quote ) { - break; - } else { - quote = 1; - continue; - } - case ':': - if (expect_colon) - expect_colon = 0; - continue; - case ' ': - case '\t': - /* Skip space or tab if we expect a colon */ - if (expect_colon) - continue; - case '\b': - case '\n': - case '\v': - case '\f': - case '\r': - case '#': - case '\0': - if (!quote) - return n; - /* FALLTHROUGH */ - default: - break; - } - quote = 0; - } - - return n; -} - -/* - * Compare str with pat. Return 0 if compare equal or - * str is an abbreviation of pat of no less than mchr characters. - */ -int strmcmp(const char *str, const char *pat, int mchr) -{ - int nchr = 0; - - while (*str == *pat) { - if (!*str) - return 0; - str++; - pat++; - nchr++; - } - - if (!*str && nchr > mchr) - return 0; - - return *pat - *str; -} - int parse_init(int argc, const char *const *argv, void **context) { struct parse_context *ctxt; @@ -476,33 +366,6 @@ int parse_init(int argc, const char *con } } -static char *dequote(const char *str, int len, unsigned int logopt) -{ - char *ret = malloc(len + 1); - char *cp = ret; - const char *scp; - int origlen = len; - int quote = 0; - - if (ret == NULL) - return NULL; - - for (scp = str; len > 0 && *scp; scp++, len--) { - if (*scp == '\\' && !quote ) { - quote = 1; - continue; - } - quote = 0; - *cp++ = *scp; - } - *cp = '\0'; - - debug(logopt, - MODPREFIX "dequote(\"%.*s\") -> %s", origlen, str, ret); - - return ret; -} - static const char *parse_options(const char *str, char **ret, unsigned int logopt) { const char *cp = str; @@ -757,7 +620,7 @@ add_offset_entry(struct autofs_point *ap struct mapent_cache *mc; char m_key[PATH_MAX + 1]; char m_mapent[MAPENT_MAX_LEN + 1]; - int m_key_len, m_mapent_len; + int p_len, m_key_len, m_options_len, m_mapent_len; int ret; source = ap->entry->current; @@ -766,34 +629,54 @@ add_offset_entry(struct autofs_point *ap mc = source->mc; - m_key_len = m_root_len + strlen(path) + 1; - if (m_key_len > PATH_MAX) { + if (!*path || !*loc) { error(ap->logopt, - MODPREFIX "multi mount key too long - ignored"); + MODPREFIX "syntax error in offset %s -> %s", path, loc); + return CHE_FAIL; + } + + p_len = strlen(path); + /* Trailing '/' causes us pain */ + if (path[p_len - 1] == '/') + p_len--; + m_key_len = m_root_len + p_len; + if (m_key_len > PATH_MAX) { + error(ap->logopt, MODPREFIX "multi mount key too long"); return CHE_FAIL; } strcpy(m_key, m_root); - strcat(m_key, path); + strncat(m_key, path, p_len); + m_key[m_key_len] = '\0'; - m_mapent_len = strlen(myoptions) + strlen(loc) + 3; - if (m_mapent_len > MAPENT_MAX_LEN) { - error(ap->logopt, - MODPREFIX "multi mount mapent too long - ignored"); + m_options_len = 0; + if (*myoptions) + m_options_len = strlen(myoptions) + 2; + + m_mapent_len = strlen(loc); + if (m_mapent_len + m_options_len > MAPENT_MAX_LEN) { + error(ap->logopt, MODPREFIX "multi mount mapent too long"); return CHE_FAIL; } - strcpy(m_mapent, "-"); - strcat(m_mapent, myoptions); - strcat(m_mapent, " "); - strcat(m_mapent, loc); - debug(ap->logopt, - MODPREFIX - "adding multi-mount offset %s -> %s", path, m_mapent); + if (*myoptions) { + strcpy(m_mapent, "-"); + strcat(m_mapent, myoptions); + strcat(m_mapent, " "); + strcat(m_mapent, loc); + } else + strcpy(m_mapent, loc); cache_writelock(mc); ret = cache_add_offset(mc, name, m_key, m_mapent, age); cache_unlock(mc); + if (ret == CHE_OK) + debug(ap->logopt, MODPREFIX + "added multi-mount offset %s -> %s", path, m_mapent); + else + debug(ap->logopt, MODPREFIX + "syntax error in offset %s -> %s", path, loc); + return ret; } @@ -862,21 +745,164 @@ cont: return 1; } -static void parse_sun_cleanup(struct mapent_cache *mc, const char *name, - char *options, char *path, char *myoptions) +static int validate_location(char *loc) { - cache_writelock(mc); - cache_delete_offset_list(mc, name); - cache_unlock(mc); + char *ptr = loc; - if (options) - free(options); + /* We don't know much about these */ + if (*ptr == '/') + return 1; + + /* If a ':' is present now it must be a host name */ + if (check_colon(ptr)) { + if (!isalpha(*ptr++)) + return 0; - if (path) - free(path); + while (*ptr && *ptr != ':') { + if (!(isalnum(*ptr) || + *ptr == '-' || *ptr == '.' || *ptr == ',')) + return 0; + ptr++; + } + + if (*ptr && *ptr == ':') + ptr++; + } + + /* Must always be something following */ + if (!*ptr) + return 0; + + return 1; +} - if (myoptions) +static int parse_mapent(const char *ent, char *g_options, char **options, char **location, int logopt) +{ + char buf[MAX_ERR_BUF]; + const char *p; + char *myoptions, *loc; + int l; + + p = ent; + + myoptions = strdup(g_options); + if (!myoptions) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(logopt, MODPREFIX "strdup: %s", estr); + return 0; + } + + /* Local options are appended to per-map options */ + if (*p == '-') { + do { + char *tmp, *newopt = NULL; + + p = parse_options(p, &newopt, logopt); + + tmp = concat_options(myoptions, newopt); + if (!tmp) { + char *estr; + estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(logopt, MODPREFIX + "concat_options: %s", estr); + free(myoptions); + return 0; + } + myoptions = tmp; + + p = skipspace(p); + } while (*p == '-'); + } + + /* Location can't begin with a '/' */ + if (*p == '/') { + error(logopt, MODPREFIX "error location begins with \"/\""); + free(myoptions); + return 0; + } + + /* Skip ':' escape */ + if (*p == ':') + p++; + + l = chunklen(p, check_colon(p)); + loc = dequote(p, l, logopt); + if (!loc) { + error(logopt, MODPREFIX "out of memory"); free(myoptions); + return 0; + } + + if (!validate_location(loc)) { + error(logopt, MODPREFIX "invalid location"); + free(myoptions); + free(loc); + return 0; + } + + debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc); + + p += l; + p = skipspace(p); + + while (*p && *p != '/') { + char *ent; + + /* Location can't begin with a '/' */ + if (*p == '/') { + error(logopt, + MODPREFIX "error location begins with \"/\""); + free(myoptions); + free(loc); + return 0; + } + + /* Skip ':' escape */ + if (*p == ':') + p++; + + l = chunklen(p, check_colon(p)); + ent = dequote(p, l, logopt); + if (!ent) { + error(logopt, MODPREFIX "out of memory"); + free(myoptions); + free(loc); + return 0; + } + + if (!validate_location(ent)) { + error(logopt, + MODPREFIX "invalid location %s", ent); + free(ent); + free(myoptions); + free(loc); + return 0; + } + + debug(logopt, MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent); + + loc = realloc(loc, strlen(loc) + l + 2); + if (!loc) { + error(logopt, MODPREFIX "out of memory"); + free(ent); + free(myoptions); + free(loc); + return 0; + } + + strcat(loc, " "); + strcat(loc, ent); + + free(ent); + + p += l; + p = skipspace(p); + } + + *options = myoptions; + *location = loc; + + return (p - ent); } /* @@ -898,7 +924,7 @@ int parse_mount(struct autofs_point *ap, char buf[MAX_ERR_BUF]; struct map_source *source; struct mapent_cache *mc; - struct mapent *me; + struct mapent *me, *ro; char *pmapent, *options; const char *p; int mapent_len, rv = 0; @@ -977,9 +1003,6 @@ int parse_mount(struct autofs_point *ap, if (check_is_multi(p)) { char *m_root = NULL; int m_root_len; - char *root_path = NULL; - char *root_loc = NULL; - char *root_options = NULL; time_t age = time(NULL); int l; @@ -1041,8 +1064,7 @@ int parse_mount(struct autofs_point *ap, /* It's a multi-mount; deal with it */ do { - char *myoptions = strdup(options); - char *path, *loc; + char *path, *myoptions, *loc; int status; if (myoptions == NULL) { @@ -1055,86 +1077,50 @@ int parse_mount(struct autofs_point *ap, if (*p != '/') { l = 0; path = dequote("/", 1, ap->logopt); + debug(ap->logopt, + MODPREFIX "dequote(\"/\") -> %s", path); } else { l = chunklen(p, 0); path = dequote(p, l, ap->logopt); + debug(ap->logopt, MODPREFIX + "dequote(\"%.*s\") -> %s", l, p, path); } if (!path) { error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, options, NULL, myoptions); + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(options); return 1; } - p += l; - p = skipspace(p); - - /* Local options are appended to per-map options */ - if (*p == '-') { - do { - char *newopt = NULL; - - p = parse_options(p, &newopt, ap->logopt); - myoptions = concat_options(myoptions, newopt); - - if (myoptions == NULL) { - char *estr; - estr = strerror_r(errno, buf, MAX_ERR_BUF); - error(ap->logopt, MODPREFIX - "multi concat_options: %s", estr); - parse_sun_cleanup(mc, name, - options, NULL, NULL); - return 1; - } - p = skipspace(p); - } while (*p == '-'); + if (!*path) { + error(ap->logopt, MODPREFIX "invalid path"); + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(path); + free(options); + return 1; } - /* Skip over colon escape */ - if (*p == ':') - p++; + p += l; + p = skipspace(p); - l = chunklen(p, check_colon(p)); - loc = dequote(p, l, ap->logopt); - if (!loc) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, options, path, myoptions); + l = parse_mapent(p, options, &myoptions, &loc, ap->logopt); + if (!l) { + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(path); + free(options); return 1; } p += l; p = skipspace(p); - while (*p && *p != '/') { - char *ent; - - l = chunklen(p, check_colon(p)); - ent = dequote(p, l, ap->logopt); - if (!ent) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, - options, path, myoptions); - return 1; - } - - loc = realloc(loc, strlen(loc) + l + 2); - if (!loc) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, - options, path, myoptions); - free(ent); - return 1; - } - - strcat(loc, " "); - strcat(loc, ent); - - free(ent); - - p += l; - p = skipspace(p); - } - master_source_current_wait(ap->entry); ap->entry->current = source; @@ -1142,61 +1128,70 @@ int parse_mount(struct autofs_point *ap, m_root, m_root_len, path, myoptions, loc, age); - if (!strcmp(path, "/")) { - root_path = strdup(path); - if (!root_path) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, - options, path, myoptions); - return 1; - } - root_loc = strdup(loc); - if (!root_loc) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, - options, path, myoptions); - free(root_path); - return 1; - } - root_options = strdup(myoptions); - if (!root_options) { - error(ap->logopt, MODPREFIX "out of memory"); - parse_sun_cleanup(mc, name, - options, path, myoptions); - free(root_loc); - free(root_path); - return 1; - } + if (status != CHE_OK) { + error(ap->logopt, MODPREFIX "error adding multi-mount"); + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(path); + free(options); + free(myoptions); + free(loc); + return 1; } + free(loc); free(path); free(myoptions); } while (*p == '/'); - if (root_path) { - rv = sun_mount(ap, m_root, root_path, strlen(root_path), - root_loc, strlen(root_loc), root_options, ctxt); + /* Mount root offset if it exists */ + cache_readlock(mc); + ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list); + if (ro) { + char *myoptions, *loc; - free(root_path); - free(root_loc); - free(root_options); + rv = parse_mapent(ro->mapent, + options, &myoptions, &loc, ap->logopt); + if (!rv) { + cache_unlock(mc); + error(ap->logopt, + MODPREFIX "mount of root offset failed"); + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(options); + return 1; + } + + rv = sun_mount(ap, m_root, + "/", 1, loc, strlen(loc), myoptions, ctxt); + + free(myoptions); + free(loc); if (rv < 0) { + cache_unlock(mc); error(ap->logopt, MODPREFIX "mount multi-mount root %s failed", name); cache_writelock(mc); cache_delete_offset_list(mc, name); cache_unlock(mc); + free(options); return rv; } } - cache_readlock(mc); if (!mount_multi_triggers(ap, m_root, me, "/")) { + cache_unlock(mc); error(ap->logopt, MODPREFIX "failed to mount offset triggers"); - rv = 1; + cache_writelock(mc); + cache_delete_offset_list(mc, name); + cache_unlock(mc); + free(options); + return 1; } cache_unlock(mc); @@ -1209,6 +1204,14 @@ int parse_mount(struct autofs_point *ap, int loclen; int l; + /* Location can't begin with a '/' */ + if (*p == '/') { + error(ap->logopt, + MODPREFIX "error location begins with \"/\""); + free(options); + return 1; + } + if (*p == ':') p++; /* Sun escape for entries starting with / */ @@ -1220,6 +1223,23 @@ int parse_mount(struct autofs_point *ap, return 1; } + if (!*loc) { + error(ap->logopt, MODPREFIX "invalid location"); + free(loc); + free(options); + return 1; + } + + if (!validate_location(loc)) { + error(ap->logopt, MODPREFIX "invalid location"); + free(loc); + free(options); + return 1; + } + + debug(ap->logopt, + MODPREFIX "dequote(\"%.*s\") -> %s", l, p, loc); + p += l; p = skipspace(p); @@ -1230,14 +1250,27 @@ int parse_mount(struct autofs_point *ap, ent = dequote(p, l, ap->logopt); if (!ent) { error(ap->logopt, MODPREFIX "out of memory"); + free(loc); free(options); return 1; } + if (!validate_location(ent)) { + error(ap->logopt, MODPREFIX "invalid location"); + free(ent); + free(loc); + free(options); + return 1; + } + + debug(ap->logopt, + MODPREFIX "dequote(\"%.*s\") -> %s", l, p, ent); + loc = realloc(loc, strlen(loc) + l + 2); if (!loc) { error(ap->logopt, MODPREFIX "out of memory"); free(ent); + free(loc); free(options); return 1; } @@ -1269,7 +1302,7 @@ int parse_mount(struct autofs_point *ap, /* non-strict failure to normal failure for ordinary mount */ if (rv < 0) rv = -rv; - + free(loc); free(options);