diff --git a/CHANGELOG b/CHANGELOG index b77c2cd..5bbf9a1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ - ignore "winbind" if it appears in "automount" nsswitch.conf. - fix another expire regression introduced in the "mitigate manual umount" patch. - correct check for busy offset mounts before offset umount. +- make double quote handing consistent. 4/1/2007 autofs-5.0.1 rc3 ------------------------- diff --git a/lib/parse_subs.c b/lib/parse_subs.c index d4ddbe4..81db459 100644 --- a/lib/parse_subs.c +++ b/lib/parse_subs.c @@ -89,6 +89,18 @@ int chunklen(const char *whence, int expect_colon) quote = 1; continue; } + case '"': + if (quote) + break; + while (*str) { + str++; + n++; + if (*str == '"') + break; + if (*str == ':') + expect_colon = 0; + } + break; case ':': if (expect_colon) expect_colon = 0; @@ -185,11 +197,19 @@ int span_space(const char *str, unsigned int maxlen) const char *p = str; unsigned int len = 0; - while (!isblank(*(p++)) && len++ < maxlen) { - if (*p == '\\') { + while (*p && !isblank(*p) && len < maxlen) { + if (*p == '"') { + while (*p++ && len++ < maxlen) { + if (*p == '"') + break; + } + } else if (*p == '\\') { p += 2; len += 2; + continue; } + p++; + len++; } return len; } diff --git a/modules/lookup_file.c b/modules/lookup_file.c index 051e5b5..0f4d8f1 100644 --- a/modules/lookup_file.c +++ b/modules/lookup_file.c @@ -41,7 +41,7 @@ typedef enum { } LOOKUP_STATE; typedef enum { got_nothing, got_star, got_real, got_plus } FOUND_STATE; -typedef enum { esc_none, esc_char, esc_val } ESCAPES; +typedef enum { esc_none, esc_char, esc_val, esc_all } ESCAPES; struct lookup_context { @@ -143,6 +143,8 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig ungetc(nch, f); escape = esc_char; } + if (ch == '"') + escape = esc_all; break; case esc_char: @@ -152,6 +154,11 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig case esc_val: escape = esc_none; break; + + case esc_all: + if (ch == '"') + escape = esc_none; + break; } switch (state) { @@ -171,6 +178,10 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig *(kptr++) = ch; key_len++; } + } else if (escape == esc_all) { + state = st_compare; + *(kptr++) = ch; + key_len++; } else if (escape == esc_char); else state = st_badent; @@ -181,7 +192,11 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig state = st_begin; if (gotten == got_plus) goto got_it; - if (escape != esc_val) + else if (escape == esc_all) { + warn(LOGOPT_ANY, MODPREFIX + "unmatched \" in map key %s", key); + goto next; + } else if (escape != esc_val) goto got_it; } else if (isspace(ch) && !escape) { getting = got_real; @@ -199,6 +214,10 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig "length is %d", key, KEY_MAX_LEN); } else { + if (escape == esc_val) { + *(kptr++) = '\\'; + key_len++; + } *(kptr++) = ch; key_len++; } @@ -237,9 +256,12 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig break; } p = mapent; - *(p++) = '\\'; + if (escape == esc_val) { + *(p++) = '\\'; + mapent_len++; + } *(p++) = ch; - mapent_len = 2; + mapent_len++; } else { p = mapent; *(p++) = ch; @@ -264,6 +286,12 @@ static int read_one(FILE *f, char *key, unsigned int *k_len, char *mapent, unsig } ungetc(nch, f); state = st_begin; + if (escape == esc_all) { + warn(LOGOPT_ANY, MODPREFIX + "unmatched \" in %s for key %s", + mapent, key); + goto next; + } if (gotten == got_real || gotten == getting) goto got_it; } else if (mapent_len < MAPENT_MAX_LEN) { diff --git a/modules/parse_sun.c b/modules/parse_sun.c index 6b2a640..0a3cac9 100644 --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -193,6 +193,23 @@ int expandsunent(const char *src, char *dst, const char *key, } break; + case '"': + len++; + if (dst) + *dst++ = ch; + + while (*src && *src != '"') { + len++; + if (dst) + *dst++ = *src; + src++; + } + if (*src && dst) { + len++; + *dst++ = *src++; + } + break; + case ':': if (dst) *(dst++) = @@ -573,7 +590,10 @@ static int check_is_multi(const char *mapent) MODPREFIX "unexpected NULL map entry pointer"); return 0; } - + + if (*p == '"') + p++; + /* If first character is "/" it's a multi-mount */ if (*p == '/') return 1; @@ -590,6 +610,8 @@ static int check_is_multi(const char *mapent) * entry. */ if (not_first_chunk) { + if (*p == '"') + p++; if (*p == '/' || *p == '-') { multi = 1; break; @@ -749,13 +771,6 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char * debug(logopt, MODPREFIX "gathered options: %s", myoptions); - /* Location can't begin with a '/' */ - if (*p == '/') { - warn(logopt, MODPREFIX "error location begins with \"/\""); - free(myoptions); - return 0; - } - l = chunklen(p, check_colon(p)); loc = dequote(p, l, logopt); if (!loc) { @@ -764,6 +779,13 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char * return 0; } + /* Location can't begin with a '/' */ + if (*p == '/') { + warn(logopt, MODPREFIX "error location begins with \"/\""); + free(myoptions); + return 0; + } + if (!validate_location(loc)) { warn(logopt, MODPREFIX "invalid location"); free(myoptions); @@ -776,22 +798,22 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char * p += l; p = skipspace(p); - while (*p && *p != '/') { + while (*p && ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/'))) { char *tmp, *ent; - /* Location can't begin with a '/' */ - if (*p == '/') { - warn(logopt, - MODPREFIX "error location begins with \"/\""); + l = chunklen(p, check_colon(p)); + ent = dequote(p, l, logopt); + if (!ent) { + warn(logopt, MODPREFIX "null location or out of memory"); free(myoptions); free(loc); return 0; } - l = chunklen(p, check_colon(p)); - ent = dequote(p, l, logopt); - if (!ent) { - warn(logopt, MODPREFIX "null location or out of memory"); + /* Location can't begin with a '/' */ + if (*p == '/') { + warn(logopt, + MODPREFIX "error location begins with \"/\""); free(myoptions); free(loc); return 0; @@ -1077,7 +1099,7 @@ int parse_mount(struct autofs_point *ap, const char *name, char *path, *myoptions, *loc; int status; - if (*p != '/') { + if ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/')) { l = 0; path = dequote("/", 1, ap->logopt); debug(ap->logopt, @@ -1139,7 +1161,7 @@ int parse_mount(struct autofs_point *ap, const char *name, free(loc); free(path); free(myoptions); - } while (*p == '/'); + } while (*p == '/' || (*p == '"' && *(p + 1) == '/')); /* * We've got the ordered list of multi-mount entries so go @@ -1203,14 +1225,6 @@ int parse_mount(struct autofs_point *ap, const char *name, int loclen; int l; - /* Location can't begin with a '/' */ - if (*p == '/') { - free(options); - warn(ap->logopt, - MODPREFIX "error location begins with \"/\""); - return 1; - } - l = chunklen(p, check_colon(p)); loc = dequote(p, l, ap->logopt); if (!loc) { @@ -1219,6 +1233,14 @@ int parse_mount(struct autofs_point *ap, const char *name, return 1; } + /* Location can't begin with a '/' */ + if (*p == '/') { + free(options); + warn(ap->logopt, + MODPREFIX "error location begins with \"/\""); + return 1; + } + if (!validate_location(loc)) { free(loc); free(options); diff --git a/samples/auto.smb b/samples/auto.smb index d0abcd7..56e6232 100755 --- a/samples/auto.smb +++ b/samples/auto.smb @@ -20,7 +20,16 @@ done $SMBCLIENT -gNL $key 2>/dev/null| awk -v key="$key" -v opts="$opts" -F'|' -- ' BEGIN { ORS=""; first=1 } - /Disk/ { if (first) { print opts; first=0 }; sub(/ /, "\\ ", $2); print " \\\n\t /" $2, "://" key "/" $2 } + /Disk/ { + if (first) + print opts; first=0 + dir = $2 + loc = $2 + # Enclose mount dir and location in quotes + # Double quote "$" in location as it is special + gsub(/\$$/, "\\$", loc); + print " \\\n\t \"/" dir "\"", "\"://" key "/" loc "\"" + } END { if (!first) print "\n"; else exit 1 } '