diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -57,6 +57,7 @@ #include +#include #include #include #include @@ -245,7 +246,7 @@ static int makemask(struct sockaddr_storage *ssp, int bitlen); static void mntsrv(struct svc_req *, SVCXPRT *); static void nextfield(char **, char **); -static void out_of_mem(void); +static void out_of_mem(void) __dead2; static void parsecred(char *, struct expcred *); static int parsesec(char *, struct exportlist *); static int put_exlist(struct dirlist *, XDR *, struct dirlist *, @@ -302,6 +303,11 @@ static int has_set_publicfh = 0; static struct pidfh *pfh = NULL; + +/* Temporary storage for credentials' groups. */ +static long tngroups_max; +static gid_t *tmp_groups = NULL; + /* Bits for opt_flags above */ #define OP_MAPROOT 0x01 #define OP_MAPALL 0x02 @@ -434,6 +440,18 @@ warn("cannot open or create pidfile"); } + openlog("mountd", LOG_PID, LOG_DAEMON); + + /* How many groups do we support? */ + tngroups_max = sysconf(_SC_NGROUPS_MAX); + if (tngroups_max == -1) + tngroups_max = NGROUPS_MAX; + /* Add space for the effective GID. */ + ++tngroups_max; + tmp_groups = malloc(tngroups_max); + if (tmp_groups == NULL) + out_of_mem(); + s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) have_v6 = 0; @@ -539,7 +557,6 @@ exnames = argv; else exnames = exnames_default; - openlog("mountd", LOG_PID, LOG_DAEMON); if (debug) warnx("getting export list"); get_exportlist(0); @@ -1571,9 +1588,9 @@ int unvis_len; v4root_phase = 0; - anon.cr_groups = NULL; dirhead = (struct dirlist *)NULL; unvis_dir[0] = '\0'; + while (get_line()) { if (debug) warnx("got line %s", line); @@ -1586,9 +1603,9 @@ * Set defaults. */ has_host = FALSE; - anon.cr_groups = anon.cr_smallgrps; anon.cr_uid = UID_NOBODY; anon.cr_ngroups = 1; + anon.cr_groups = tmp_groups; anon.cr_groups[0] = nogroup(); exflags = MNT_EXPORTED; got_nondir = 0; @@ -1918,10 +1935,6 @@ free_dir(dirhead); dirhead = (struct dirlist *)NULL; } - if (anon.cr_groups != anon.cr_smallgrps) { - free(anon.cr_groups); - anon.cr_groups = NULL; - } } } @@ -3187,11 +3200,11 @@ eap->ex_flags = exflags; eap->ex_uid = anoncrp->cr_uid; eap->ex_ngroups = anoncrp->cr_ngroups; - if (eap->ex_ngroups > 0) { - eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t)); - memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups * - sizeof(gid_t)); - } + /* + * Use the memory pointed to by 'anoncrp', as it outlives 'eap' which is + * local to this function. + */ + eap->ex_groups = anoncrp->cr_groups; LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags); eap->ex_indexfile = ep->ex_indexfile; if (grp->gr_type == GT_HOST) @@ -3381,7 +3394,6 @@ if (cp) *cp = savedc; error_exit: - free(eap->ex_groups); /* free strings allocated by strdup() in getmntopts.c */ if (iov != NULL) { free(iov[0].iov_base); /* fstype */ @@ -3609,21 +3621,19 @@ * Parse a description of a credential. */ static void -parsecred(char *namelist, struct expcred *cr) +parsecred(char *names, struct expcred *cr) { char *name; - char *names; struct passwd *pw; - gid_t groups[NGROUPS_MAX + 1]; - int ngroups; unsigned long name_ul; char *end = NULL; + assert(cr->cr_groups == tmp_groups); + /* * Parse the user and if possible get its password table entry. * 'cr_uid' is filled when exiting this block. */ - names = namelist; name = strsep_quote(&names, ":"); name_ul = strtoul(name, &end, 10); if (*end != '\0' || end == name) @@ -3650,17 +3660,13 @@ "can't determine groups", name); goto nogroup; } - cr->cr_uid = pw->pw_uid; - ngroups = NGROUPS_MAX + 1; - if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { + + cr->cr_ngroups = tngroups_max; + if (getgrouplist(pw->pw_name, pw->pw_gid, + cr->cr_groups, &cr->cr_ngroups) != 0) { syslog(LOG_ERR, "too many groups"); - ngroups = NGROUPS_MAX + 1; + cr->cr_ngroups = tngroups_max; } - - if (ngroups > SMALLNGROUPS) - cr->cr_groups = malloc(ngroups * sizeof(gid_t)); - cr->cr_ngroups = ngroups; - memcpy(cr->cr_groups, groups, ngroups * sizeof(gid_t)); return; } @@ -3684,17 +3690,14 @@ } else { group = name_ul; } - if (cr->cr_ngroups == NGROUPS_MAX + 1) { + if (cr->cr_ngroups == tngroups_max) { syslog(LOG_ERR, "too many groups"); break; } - groups[cr->cr_ngroups++] = group; + cr->cr_groups[cr->cr_ngroups++] = group; } if (cr->cr_ngroups == 0) goto nogroup; - if (cr->cr_ngroups > SMALLNGROUPS) - cr->cr_groups = malloc(cr->cr_ngroups * sizeof(gid_t)); - memcpy(cr->cr_groups, groups, cr->cr_ngroups * sizeof(gid_t)); return; nogroup: @@ -4063,6 +4066,7 @@ static void terminate(int sig __unused) { + free(tmp_groups); pidfile_remove(pfh); rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);