/* * Given an export and the clients hostname(s) * determine the security flavors that this * client is permitted to use. * * This is somewhat more complicated than the "old" * routine because the options may contain multiple * security flavors (sec=) each with its own access * lists. So a client could be granted access based * on a number of security flavors. Note that the * type of access might not always be the same, the * client may get readonly access with one flavor * and readwrite with another, however the client * is not told this detail, it gets only the list * of flavors, and only if the client is using * version 3 of the mount protocol. */ static int getclientsflavors_new(struct share *sh, struct netbuf *nb, struct nd_hostservlist *clnames, int *flavors) { char *opts, *p, *val; char *lasts; char *f; int access_ok, count, c; opts = strdup(sh->sh_opts); if (opts == NULL) { syslog(LOG_ERR, "getclientsflavors: no memory"); return (0); } p = opts; count = c = 0; /* default access is rw */ access_ok = 1; while (*p) { switch (getsubopt(&p, optlist, &val)) { case OPT_SEC: /* * Before a new sec=xxx option, check if we need * to move the c index back to the previous count. */ if (!access_ok) { c = count; } /* get all the sec=f1[:f2] flavors */ while ((f = strtok_r(val, ":", &lasts)) != NULL) { flavors[c++] = map_flavor(f); val = NULL; } /* for a new sec=xxx option, default is rw access */ access_ok = 1; break; case OPT_RO: case OPT_RW: if (in_access_list(nb, clnames, val)) { count = c; access_ok = 1; } else { access_ok = 0; } break; } } if (!access_ok) { c = count; } free(opts); return (c); }
/* * Given an export and the clients hostname(s) * determine the security flavors that this * client is permitted to use. * * This routine is called only for "old" syntax, i.e. * only one security flavor is allowed. So we need * to determine two things: the particular flavor, * and whether the client is allowed to use this * flavor, i.e. is in the access list. * * Note that if there is no access list, then the * default is that access is granted. */ static int getclientsflavors_old(struct share *sh, struct netbuf *nb, struct nd_hostservlist *clnames, int *flavors) { char *opts, *p, *val; int ok = 0; int defaultaccess = 1; opts = strdup(sh->sh_opts); if (opts == NULL) { syslog(LOG_ERR, "getclientsflavors: no memory"); return (0); } flavors[0] = AUTH_SYS; p = opts; while (*p) { switch (getsubopt(&p, optlist, &val)) { case OPT_SECURE: flavors[0] = AUTH_DES; break; case OPT_RO: case OPT_RW: defaultaccess = 0; if (in_access_list(nb, clnames, val)) ok++; break; } } free(opts); return (defaultaccess || ok); }
static int check_client_new(struct share *sh, struct netbuf *nb, struct nd_hostservlist *clnames, int flavor) { char *opts, *p, *val; char *lasts; char *f; int match = 0; /* Set when a flavor is matched */ int perm = 0; /* Set when "ro", "rw" or "root" is matched */ int list = 0; /* Set when "ro", "rw" is found */ int ro_val = 0; /* Set if ro option is 'ro=' */ int rw_val = 0; /* Set if rw option is 'rw=' */ opts = strdup(sh->sh_opts); if (opts == NULL) { syslog(LOG_ERR, "check_client: no memory"); return (0); } p = opts; while (*p) { switch (getsubopt(&p, optlist, &val)) { case OPT_SEC: if (match) goto done; while ((f = strtok_r(val, ":", &lasts)) != NULL) { if (flavor == map_flavor(f)) { match = 1; break; } val = NULL; } break; case OPT_RO: if (!match) break; list++; if (val) ro_val++; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_RO; break; case OPT_RW: if (!match) break; list++; if (val) rw_val++; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_RW; break; case OPT_ROOT: /* * Check if the client is in * the root list. Only valid * for AUTH_SYS. */ if (flavor != AUTH_SYS) break; if (!match) break; if (val == NULL || *val == '\0') break; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_ROOT; break; } } done: /* * If no match then set the perm accordingly */ if (!match) return (NFSAUTH_DENIED); if (list) { /* * If the client doesn't match an "ro" or "rw" list then * check if it may have access by using a different flavor. * If so, return NFSAUTH_WRONGSEC. * If not, return NFSAUTH_DENIED. */ if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) { if (is_wrongsec(sh, nb, clnames, flavor)) perm |= NFSAUTH_WRONGSEC; else perm |= NFSAUTH_DENIED; } } else { /* * The client matched a flavor entry that * has no explicit "rw" or "ro" determination. * Make sure it defaults to "rw". */ perm |= NFSAUTH_RW; } /* * The client may show up in both ro= and rw= * lists. If so, then turn off the RO access * bit leaving RW access. */ if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { /* * Logically cover all permutations of rw=,ro=. * In the case where, rw,ro=<host> we would like * to remove RW access for the host. In all other cases * RW wins the precedence battle. */ if (!rw_val && ro_val) { perm &= ~(NFSAUTH_RW); } else { perm &= ~(NFSAUTH_RO); } } free(opts); return (perm); }
static int check_client_old(struct share *sh, struct netbuf *nb, struct nd_hostservlist *clnames, int flavor) { char *opts, *p, *val; int match; /* Set when a flavor is matched */ int perm = 0; /* Set when "ro", "rw" or "root" is matched */ int list = 0; /* Set when "ro", "rw" is found */ int ro_val = 0; /* Set if ro option is 'ro=' */ int rw_val = 0; /* Set if rw option is 'rw=' */ opts = strdup(sh->sh_opts); if (opts == NULL) { syslog(LOG_ERR, "check_client: no memory"); return (0); } p = opts; match = AUTH_UNIX; while (*p) { switch (getsubopt(&p, optlist, &val)) { case OPT_SECURE: match = AUTH_DES; break; case OPT_RO: list++; if (val) ro_val++; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_RO; break; case OPT_RW: list++; if (val) rw_val++; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_RW; break; case OPT_ROOT: /* * Check if the client is in * the root list. Only valid * for AUTH_SYS. */ if (flavor != AUTH_SYS) break; if (val == NULL || *val == '\0') break; if (in_access_list(nb, clnames, val)) perm |= NFSAUTH_ROOT; break; } } free(opts); if (flavor != match) return (NFSAUTH_DENIED); if (list) { /* * If the client doesn't match an "ro" or "rw" * list then set no access. */ if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) perm |= NFSAUTH_DENIED; } else { /* * The client matched a flavor entry that * has no explicit "rw" or "ro" determination. * Default it to "rw". */ perm |= NFSAUTH_RW; } /* * The client may show up in both ro= and rw= * lists. If so, then turn off the RO access * bit leaving RW access. */ if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) { /* * Logically cover all permutations of rw=,ro=. * In the case where, rw,ro=<host> we would like * to remove RW access for the host. In all other cases * RW wins the precedence battle. */ if (!rw_val && ro_val) { perm &= ~(NFSAUTH_RW); } else { perm &= ~(NFSAUTH_RO); } } return (perm); }
static char * charmap_search(struct netbuf *nbuf, char *opts) { char *copts; char *next; char *name; char *result = NULL; char *netid; struct netconfig *nconf; struct nd_hostservlist *hl = NULL; struct sockaddr *sa; /* eventually charopts should be dynamically setup */ if (charopts == NULL) { free(copts); return (NULL); } sa = (struct sockaddr *)nbuf->buf; switch (sa->sa_family) { case AF_INET: nconf = getnetconfigent("tcp"); break; case AF_INET6: nconf = getnetconfigent("tcp6"); break; default: return (NULL); } if (nconf == NULL) { return (NULL); } /* * Use the this API instead of the netdir_getbyaddr() * to avoid service lookup. */ if (__netdir_getbyaddr_nosrv(nconf, &hl, nbuf)) { syslog(LOG_ERR, "netdir: %s\n", netdir_sperror()); freenetconfigent(nconf); return (NULL); } copts = strdup(opts); if (copts == NULL) { freenetconfigent(nconf); return (NULL); } next = copts; while (*next != '\0') { char *val; name = next; if (getsubopt(&next, charopts, &val) >= 0) { char *cp; /* * name will have the whole opt and val the value. Set * the '=' to '\0' and we have the charmap in name and * the access list in val. */ cp = strchr(name, '='); if (cp != NULL) *cp = '\0'; if (in_access_list(nbuf, hl, val)) { result = name; break; } } } if (result != NULL) result = strdup(result); free(copts); freenetconfigent(nconf); return (result); }