diff options
Diffstat (limited to 'usr/src/lib/libsmbfs/smb/rcfile.c')
-rw-r--r-- | usr/src/lib/libsmbfs/smb/rcfile.c | 426 |
1 files changed, 248 insertions, 178 deletions
diff --git a/usr/src/lib/libsmbfs/smb/rcfile.c b/usr/src/lib/libsmbfs/smb/rcfile.c index 3f5a87435d..22ca0fc420 100644 --- a/usr/src/lib/libsmbfs/smb/rcfile.c +++ b/usr/src/lib/libsmbfs/smb/rcfile.c @@ -36,45 +36,61 @@ #include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> + #include <ctype.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <stdlib.h> -#include <libintl.h> -#include <pwd.h> +#include <synch.h> #include <unistd.h> -#include <sys/debug.h> +#include <pwd.h> +#include <libintl.h> #include <cflib.h> #include "rcfile_priv.h" -extern int smb_debug; -SLIST_HEAD(rcfile_head, rcfile); -static struct rcfile_head pf_head = {NULL}; +#include <assert.h> + +#if 0 /* before SMF */ +#define SMB_CFG_FILE "/etc/nsmb.conf" +#define OLD_SMB_CFG_FILE "/usr/local/etc/nsmb.conf" +#endif +#define SMBFS_SHARECTL_CMD "/usr/sbin/sharectl get smbfs" + +extern int smb_debug; static struct rcfile *rc_cachelookup(const char *filename); -struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); +static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname); static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname); -static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); -struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname); +static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp); +static struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *key); static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value); static void rc_key_free(struct rckey *p); static void rc_parse(struct rcfile *rcp); +/* lock for the variables below */ +mutex_t rcfile_mutex = DEFAULTMUTEX; + +SLIST_HEAD(rcfile_head, rcfile); +static struct rcfile_head pf_head = {NULL}; +struct rcfile *smb_rc; +int home_nsmbrc; int insecure_nsmbrc; /* * open rcfile and load its content, if already open - return previous handle */ -int +static int rc_open(const char *filename, const char *mode, struct rcfile **rcfile) { + struct stat statbuf; struct rcfile *rcp; FILE *f; - struct stat statbuf; + + assert(MUTEX_HELD(&rcfile_mutex)); rcp = rc_cachelookup(filename); if (rcp) { @@ -102,12 +118,15 @@ rc_open(const char *filename, const char *mode, struct rcfile **rcfile) return (0); } -int +static int rc_merge(const char *filename, struct rcfile **rcfile) { + struct stat statbuf; struct rcfile *rcp = *rcfile; FILE *f, *t; + assert(MUTEX_HELD(&rcfile_mutex)); + insecure_nsmbrc = 0; if (rcp == NULL) { return (rc_open(filename, "r", rcfile)); @@ -115,6 +134,10 @@ rc_merge(const char *filename, struct rcfile **rcfile) f = fopen(filename, "r"); if (f == NULL) return (errno); + insecure_nsmbrc = 0; + if (fstat(fileno(f), &statbuf) >= 0 && + (statbuf.st_mode & 077) != 0) + insecure_nsmbrc = 1; t = rcp->rf_f; rcp->rf_f = f; rc_parse(rcp); @@ -123,43 +146,45 @@ rc_merge(const char *filename, struct rcfile **rcfile) return (0); } -int -rc_merge_pipe(const char *command, struct rcfile **rcfile) +/* + * Like rc_open, but does popen of command: + * sharectl get smbfs + */ +static int +rc_popen_cmd(const char *command, struct rcfile **rcfile) { - struct rcfile *rcp = *rcfile; - FILE *f, *t; + struct rcfile *rcp; + FILE *f; + + assert(MUTEX_HELD(&rcfile_mutex)); - insecure_nsmbrc = 0; f = popen(command, "r"); if (f == NULL) return (errno); + insecure_nsmbrc = 0; + + rcp = malloc(sizeof (struct rcfile)); if (rcp == NULL) { - rcp = malloc(sizeof (struct rcfile)); - if (rcp == NULL) { - fclose(f); - return (ENOMEM); - } - *rcfile = rcp; - bzero(rcp, sizeof (struct rcfile)); - rcp->rf_name = strdup(command); - rcp->rf_f = f; - SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); - rc_parse(rcp); - } else { - t = rcp->rf_f; - rcp->rf_f = f; - rc_parse(rcp); - rcp->rf_f = t; + fclose(f); + return (ENOMEM); } - fclose(f); + bzero(rcp, sizeof (struct rcfile)); + rcp->rf_name = strdup(command); + rcp->rf_f = f; + SLIST_INSERT_HEAD(&pf_head, rcp, rf_next); + rc_parse(rcp); + *rcfile = rcp; + /* fclose(f) in rc_close */ return (0); } -int +static int rc_close(struct rcfile *rcp) { struct rcsection *p, *n; + mutex_lock(&rcfile_mutex); + fclose(rcp->rf_f); for (p = SLIST_FIRST(&rcp->rf_sect); p; ) { n = p; @@ -169,6 +194,8 @@ rc_close(struct rcfile *rcp) free(rcp->rf_name); SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next); free(rcp); + + mutex_unlock(&rcfile_mutex); return (0); } @@ -177,17 +204,21 @@ rc_cachelookup(const char *filename) { struct rcfile *p; + assert(MUTEX_HELD(&rcfile_mutex)); + SLIST_FOREACH(p, &pf_head, rf_next) if (strcmp(filename, p->rf_name) == 0) return (p); return (0); } -/* static */ struct rcsection * +static struct rcsection * rc_findsect(struct rcfile *rcp, const char *sectname) { struct rcsection *p; + assert(MUTEX_HELD(&rcfile_mutex)); + SLIST_FOREACH(p, &rcp->rf_sect, rs_next) if (strcasecmp(p->rs_name, sectname) == 0) return (p); @@ -199,6 +230,8 @@ rc_addsect(struct rcfile *rcp, const char *sectname) { struct rcsection *p; + assert(MUTEX_HELD(&rcfile_mutex)); + p = rc_findsect(rcp, sectname); if (p) return (p); @@ -216,6 +249,8 @@ rc_freesect(struct rcfile *rcp, struct rcsection *rsp) { struct rckey *p, *n; + assert(MUTEX_HELD(&rcfile_mutex)); + SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next); for (p = SLIST_FIRST(&rsp->rs_keys); p; ) { n = p; @@ -227,11 +262,13 @@ rc_freesect(struct rcfile *rcp, struct rcsection *rsp) return (0); } -/* static */ struct rckey * +static struct rckey * rc_sect_findkey(struct rcsection *rsp, const char *keyname) { struct rckey *p; + assert(MUTEX_HELD(&rcfile_mutex)); + SLIST_FOREACH(p, &rsp->rs_keys, rk_next) if (strcmp(p->rk_name, keyname) == 0) return (p); @@ -243,6 +280,8 @@ rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value) { struct rckey *p; + assert(MUTEX_HELD(&rcfile_mutex)); + p = rc_sect_findkey(rsp, name); if (!p) { p = malloc(sizeof (*p)); @@ -273,16 +312,13 @@ rc_key_free(struct rckey *p) free(p); } -enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; - -int home_nsmbrc = 0; -static char *minauth[] = { - "kerberos", - "ntlmv2", - "ntlm", - "lm", +static char *minauth_values[] = { "none", + "lm", + "ntlm", + "ntlmv2", + "kerberos", NULL }; @@ -291,43 +327,57 @@ eval_minauth(char *auth) { int i; - for (i = 0; minauth[i]; i++) - if (strcmp(auth, minauth[i]) == 0) - break; - return (i); + for (i = 0; minauth_values[i]; i++) + if (strcmp(auth, minauth_values[i]) == 0) + return (i); + return (-1); } /* - * Ensure that "minauth" is set to the highest level (lowest array offset) + * Ensure that "minauth" is set to the highest level */ +/*ARGSUSED*/ static void set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp, char *ptr) { int now, new; +#ifdef DEBUG + char *from; + + if (smb_debug) + from = (home_nsmbrc) ? + "user file" : "SMF"; +#endif if (strcmp(rkp->rk_name, "minauth") == 0) { now = eval_minauth(rkp->rk_value); new = eval_minauth(ptr); - if (new >= now) { + if (new <= now) { #ifdef DEBUG if (smb_debug) - printf( - "set_value: rejecting %s=%s from %s\n", - rkp->rk_name, ptr, home_nsmbrc ? - "user file" : "SMF"); + fprintf(stderr, + "set_value: rejecting %s=%s" + " in %s from %s\n", + rkp->rk_name, ptr, + rsp->rs_name, from); #endif return; } } #ifdef DEBUG if (smb_debug) - printf("set_value: applying %s=%s from %s\n", - rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF"); + fprintf(stderr, + "set_value: applying %s=%s in %s from %s\n", + rkp->rk_name, ptr, rsp->rs_name, from); #endif rkp->rk_value = strdup(ptr); } + +/* states in rc_parse */ +enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue}; + static void rc_parse(struct rcfile *rcp) { @@ -338,6 +388,8 @@ rc_parse(struct rcfile *rcp) char buf[2048]; char *next = buf, *last = &buf[sizeof (buf)-1]; + assert(MUTEX_HELD(&rcfile_mutex)); + while ((c = getc(f)) != EOF) { if (c == '\r') continue; @@ -393,8 +445,8 @@ rc_parse(struct rcfile *rcp) state = stSkipToEOL; continue; } - if (home_nsmbrc && - (strcmp(buf, "nbns") == 0 || + if (home_nsmbrc != 0 && ( + strcmp(buf, "nbns") == 0 || strcmp(buf, "nbns_enable") == 0 || strcmp(buf, "nbns_broadcast") == 0 || strcmp(buf, "signing") == 0)) { @@ -405,7 +457,8 @@ rc_parse(struct rcfile *rcp) state = stNewLine; continue; } - if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) { + if (insecure_nsmbrc != 0 && + strcmp(buf, "password") == 0) { fprintf(stderr, dgettext(TEXT_DOMAIN, "Warning: .nsmbrc file not secure, " "ignoring passwords\n")); @@ -445,16 +498,27 @@ rc_getstringptr(struct rcfile *rcp, const char *section, const char *key, { struct rcsection *rsp; struct rckey *rkp; + int err; + + mutex_lock(&rcfile_mutex); *dest = NULL; rsp = rc_findsect(rcp, section); - if (!rsp) - return (ENOENT); + if (!rsp) { + err = ENOENT; + goto out; + } rkp = rc_sect_findkey(rsp, key); - if (!rkp) - return (ENOENT); + if (!rkp) { + err = ENOENT; + goto out; + } *dest = rkp->rk_value; - return (0); + err = 0; + +out: + mutex_unlock(&rcfile_mutex); + return (err); } int @@ -468,7 +532,7 @@ rc_getstring(struct rcfile *rcp, const char *section, const char *key, if (error) return (error); if (strlen(value) >= maxlen) { - fprintf(stdout, dgettext(TEXT_DOMAIN, + fprintf(stderr, dgettext(TEXT_DOMAIN, "line too long for key '%s' in section '%s', max = %d\n"), key, section, maxlen); return (EINVAL); @@ -482,22 +546,31 @@ rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value) { struct rcsection *rsp; struct rckey *rkp; + int err; + + mutex_lock(&rcfile_mutex); rsp = rc_findsect(rcp, section); - if (!rsp) - return (ENOENT); + if (!rsp) { + err = ENOENT; + goto out; + } rkp = rc_sect_findkey(rsp, key); - if (!rkp) - return (ENOENT); + if (!rkp) { + err = ENOENT; + goto out; + } errno = 0; *value = strtol(rkp->rk_value, NULL, 0); - if (errno) { - fprintf(stdout, dgettext(TEXT_DOMAIN, + if ((err = errno) != 0) { + fprintf(stderr, dgettext(TEXT_DOMAIN, "invalid int value '%s' for key '%s' in section '%s'\n"), rkp->rk_value, key, section); - return (errno); } - return (0); + +out: + mutex_unlock(&rcfile_mutex); + return (err); } /* @@ -510,139 +583,136 @@ rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value) struct rcsection *rsp; struct rckey *rkp; char *p; + int err; + + mutex_lock(&rcfile_mutex); rsp = rc_findsect(rcp, section); - if (!rsp) - return (ENOENT); + if (!rsp) { + err = ENOENT; + goto out; + } rkp = rc_sect_findkey(rsp, key); - if (!rkp) - return (ENOENT); + if (!rkp) { + err = ENOENT; + goto out; + } p = rkp->rk_value; while (*p && isspace(*p)) p++; if (*p == '0' || strcasecmp(p, "no") == 0 || strcasecmp(p, "false") == 0) { *value = 0; - return (0); + err = 0; + goto out; } if (*p == '1' || strcasecmp(p, "yes") == 0 || strcasecmp(p, "true") == 0) { *value = 1; - return (0); + err = 0; + goto out; } fprintf(stderr, dgettext(TEXT_DOMAIN, "invalid boolean value '%s' for key '%s' in section '%s' \n"), p, key, section); - return (EINVAL); + err = EINVAL; + +out: + mutex_unlock(&rcfile_mutex); + return (err); +} + +#ifdef DEBUG +void +dump_props(char *where) +{ + struct rcsection *rsp = NULL; + struct rckey *rkp = NULL; + + fprintf(stderr, "Settings %s\n", where); + SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) { + fprintf(stderr, "section=%s\n", rsp->rs_name); + fflush(stderr); + + SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) { + fprintf(stderr, " key=%s, value=%s\n", + rkp->rk_name, rkp->rk_value); + fflush(stderr); + } + } } +#endif /* - * Unified command line/rc file parser + * first parse "sharectl get smbfs, then $HOME/.nsmbrc + * This is called by library consumers (commands) */ int -opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect, - opt_callback_t *callback) +smb_open_rcfile(char *home) { - int len, error; - - for (; ap->opt; ap++) { - switch (ap->type) { - case OPTARG_STR: - if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0) - break; - len = strlen(ap->str); - if (len > ap->ival) { - fprintf(stdout, dgettext(TEXT_DOMAIN, - "rc: argument for option '%c' (%s) too long\n"), - ap->opt, ap->name); - return (EINVAL); - } - callback(ap); - break; - case OPTARG_BOOL: - error = rc_getbool(rcp, sect, ap->name, &ap->ival); - if (error == ENOENT) - break; - if (error) - return (EINVAL); - callback(ap); - break; - case OPTARG_INT: - if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0) - break; - if (((ap->flag & OPTFL_HAVEMIN) && - ap->ival < ap->min) || - ((ap->flag & OPTFL_HAVEMAX) && - ap->ival > ap->max)) { - fprintf(stdout, dgettext(TEXT_DOMAIN, - "rc: argument for option '%c' (%s) " - "should be in [%d-%d] range\n"), - ap->opt, ap->name, ap->min, ap->max); - return (EINVAL); - } - callback(ap); - break; - default: - break; + char *fn; + int len, error = 0; + + mutex_lock(&rcfile_mutex); + + smb_rc = NULL; +#if 0 /* before SMF */ + fn = SMB_CFG_FILE; + error = rc_open(fn, &smb_rc); +#else + fn = SMBFS_SHARECTL_CMD; + error = rc_popen_cmd(fn, &smb_rc); +#endif + if (error != 0 && error != ENOENT) { + /* Error from fopen. strerror is OK. */ + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Can't open %s: %s\n"), fn, strerror(errno)); + } +#ifdef DEBUG + if (smb_debug) + dump_props(fn); +#endif + + if (home) { + len = strlen(home) + 20; + fn = malloc(len); + snprintf(fn, len, "%s/.nsmbrc", home); + home_nsmbrc = 1; + error = rc_merge(fn, &smb_rc); + if (error != 0 && error != ENOENT) { + fprintf(stderr, dgettext(TEXT_DOMAIN, + "Can't open %s: %s\n"), fn, strerror(errno)); } + home_nsmbrc = 0; +#ifdef DEBUG + if (smb_debug) + dump_props(fn); +#endif + free(fn); } - return (0); + + /* Mostly ignore error returns above. */ + if (smb_rc == NULL) + error = ENOENT; + else + error = 0; + + mutex_unlock(&rcfile_mutex); + + return (error); } -int -opt_args_parseopt(struct opt_args *ap, int opt, char *arg, - opt_callback_t *callback) +/* + * This is called by library consumers (commands) + */ +void +smb_close_rcfile(void) { - int len; + struct rcfile *rcp; - for (; ap->opt; ap++) { - if (ap->opt != opt) - continue; - switch (ap->type) { - case OPTARG_STR: - ap->str = arg; - if (arg) { - len = strlen(ap->str); - if (len > ap->ival) { - fprintf(stdout, dgettext(TEXT_DOMAIN, - "opt: Argument for option '%c' (%s) too long\n"), - ap->opt, ap->name); - return (EINVAL); - } - callback(ap); - } - break; - case OPTARG_BOOL: - ap->ival = 0; - callback(ap); - break; - case OPTARG_INT: - errno = 0; - ap->ival = strtol(arg, NULL, 0); - if (errno) { - fprintf(stdout, dgettext(TEXT_DOMAIN, - "opt: Invalid integer value for " - "option '%c' (%s).\n"), - ap->opt, ap->name); - return (EINVAL); - } - if (((ap->flag & OPTFL_HAVEMIN) && - (ap->ival < ap->min)) || - ((ap->flag & OPTFL_HAVEMAX) && - (ap->ival > ap->max))) { - fprintf(stdout, dgettext(TEXT_DOMAIN, - "opt: Argument for option '%c' (%s) " - "should be in [%d-%d] range\n"), - ap->opt, ap->name, ap->min, ap->max); - return (EINVAL); - } - callback(ap); - break; - default: - break; - } - break; + if ((rcp = smb_rc) != NULL) { + smb_rc = NULL; + rc_close(rcp); } - return (0); } |