Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/mountd/mountd.c
Show First 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | struct dirlist { | ||||
char *dp_dirp; | char *dp_dirp; | ||||
}; | }; | ||||
/* dp_flag bits */ | /* dp_flag bits */ | ||||
#define DP_DEFSET 0x1 | #define DP_DEFSET 0x1 | ||||
#define DP_HOSTSET 0x2 | #define DP_HOSTSET 0x2 | ||||
/* | /* | ||||
* maproot/mapall credentials. | * maproot/mapall credentials. | ||||
* cr_smallgrps can be used for a group list up to SMALLNGROUPS in size. | |||||
* Larger group lists are malloc'd/free'd. | |||||
*/ | */ | ||||
#define SMALLNGROUPS 32 | |||||
struct expcred { | struct expcred { | ||||
uid_t cr_uid; | uid_t cr_uid; | ||||
int cr_ngroups; | int cr_ngroups; | ||||
gid_t cr_groups[NGROUPS_MAX + 1]; | gid_t cr_smallgrps[SMALLNGROUPS]; | ||||
gid_t *cr_groups; | |||||
}; | }; | ||||
struct exportlist { | struct exportlist { | ||||
struct dirlist *ex_dirl; | struct dirlist *ex_dirl; | ||||
struct dirlist *ex_defdir; | struct dirlist *ex_defdir; | ||||
struct grouplist *ex_grphead; | struct grouplist *ex_grphead; | ||||
int ex_flag; | int ex_flag; | ||||
fsid_t ex_fs; | fsid_t ex_fs; | ||||
▲ Show 20 Lines • Show All 1,378 Lines • ▼ Show 20 Lines | get_exportlist_one(int passno) | ||||
struct dirlist *dirhead; | struct dirlist *dirhead; | ||||
struct statfs fsb; | struct statfs fsb; | ||||
struct expcred anon; | struct expcred anon; | ||||
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; | char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; | ||||
int len, has_host, got_nondir, dirplen, netgrp; | int len, has_host, got_nondir, dirplen, netgrp; | ||||
uint64_t exflags; | uint64_t exflags; | ||||
v4root_phase = 0; | v4root_phase = 0; | ||||
anon.cr_groups = NULL; | |||||
dirhead = (struct dirlist *)NULL; | dirhead = (struct dirlist *)NULL; | ||||
while (get_line()) { | while (get_line()) { | ||||
if (debug) | if (debug) | ||||
warnx("got line %s", line); | warnx("got line %s", line); | ||||
cp = line; | cp = line; | ||||
nextfield(&cp, &endcp); | nextfield(&cp, &endcp); | ||||
if (*cp == '#') | if (*cp == '#') | ||||
goto nextline; | goto nextline; | ||||
/* | /* | ||||
* Set defaults. | * Set defaults. | ||||
*/ | */ | ||||
has_host = FALSE; | has_host = FALSE; | ||||
anon.cr_groups = anon.cr_smallgrps; | |||||
anon.cr_uid = UID_NOBODY; | anon.cr_uid = UID_NOBODY; | ||||
anon.cr_ngroups = 1; | anon.cr_ngroups = 1; | ||||
anon.cr_groups[0] = GID_NOGROUP; | anon.cr_groups[0] = GID_NOGROUP; | ||||
exflags = MNT_EXPORTED; | exflags = MNT_EXPORTED; | ||||
got_nondir = 0; | got_nondir = 0; | ||||
opt_flags = 0; | opt_flags = 0; | ||||
ep = (struct exportlist *)NULL; | ep = (struct exportlist *)NULL; | ||||
dirp = NULL; | dirp = NULL; | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | if ((ep->ex_flag & EX_LINKED) == 0) { | ||||
ep->ex_flag |= EX_LINKED; | ep->ex_flag |= EX_LINKED; | ||||
} | } | ||||
nextline: | nextline: | ||||
v4root_phase = 0; | v4root_phase = 0; | ||||
if (dirhead) { | if (dirhead) { | ||||
free_dir(dirhead); | free_dir(dirhead); | ||||
dirhead = (struct dirlist *)NULL; | dirhead = (struct dirlist *)NULL; | ||||
} | } | ||||
if (anon.cr_groups != anon.cr_smallgrps) { | |||||
kib: I find a test like anon.cr_groups != anon.cr_smallgrps more clean, instead of relying on the… | |||||
free(anon.cr_groups); | |||||
anon.cr_groups = NULL; | |||||
} | } | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Get the export list from all specified files | * Get the export list from all specified files | ||||
*/ | */ | ||||
static void | static void | ||||
get_exportlist(int passno) | get_exportlist(int passno) | ||||
{ | { | ||||
struct export_args export; | struct export_args export; | ||||
▲ Show 20 Lines • Show All 1,065 Lines • ▼ Show 20 Lines | if (ep->ex_indexfile) | ||||
free(ep->ex_indexfile); | free(ep->ex_indexfile); | ||||
free_dir(ep->ex_dirl); | free_dir(ep->ex_dirl); | ||||
grp = ep->ex_grphead; | grp = ep->ex_grphead; | ||||
while (grp) { | while (grp) { | ||||
tgrp = grp; | tgrp = grp; | ||||
grp = grp->gr_next; | grp = grp->gr_next; | ||||
free_grp(tgrp); | free_grp(tgrp); | ||||
} | } | ||||
if (ep->ex_defanon.cr_groups != ep->ex_defanon.cr_smallgrps) | |||||
free(ep->ex_defanon.cr_groups); | |||||
free((caddr_t)ep); | free((caddr_t)ep); | ||||
} | } | ||||
/* | /* | ||||
* Free up the v4root exports. | * Free up the v4root exports. | ||||
*/ | */ | ||||
static void | static void | ||||
free_v4rootexp(void) | free_v4rootexp(void) | ||||
▲ Show 20 Lines • Show All 536 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Parse a description of a credential. | * Parse a description of a credential. | ||||
*/ | */ | ||||
static void | static void | ||||
parsecred(char *namelist, struct expcred *cr) | parsecred(char *namelist, struct expcred *cr) | ||||
{ | { | ||||
char *name; | char *name; | ||||
int cnt; | int inpos; | ||||
char *names; | char *names; | ||||
struct passwd *pw; | struct passwd *pw; | ||||
struct group *gr; | struct group *gr; | ||||
gid_t groups[NGROUPS_MAX + 1]; | |||||
int ngroups; | |||||
/* | /* | ||||
* Set up the unprivileged user. | * Set up the unprivileged user. | ||||
*/ | */ | ||||
cr->cr_groups = cr->cr_smallgrps; | |||||
cr->cr_uid = UID_NOBODY; | cr->cr_uid = UID_NOBODY; | ||||
Done Inline ActionsI take it this will not be in the committed version? freqlabs: I take it this will not be in the committed version? | |||||
cr->cr_groups[0] = GID_NOGROUP; | cr->cr_groups[0] = GID_NOGROUP; | ||||
cr->cr_ngroups = 1; | cr->cr_ngroups = 1; | ||||
/* | /* | ||||
* Get the user's password table entry. | * Get the user's password table entry. | ||||
*/ | */ | ||||
names = namelist; | names = namelist; | ||||
name = strsep_quote(&names, ":"); | name = strsep_quote(&names, ":"); | ||||
/* Bug? name could be NULL here */ | /* Bug? name could be NULL here */ | ||||
if (isdigit(*name) || *name == '-') | if (isdigit(*name) || *name == '-') | ||||
pw = getpwuid(atoi(name)); | pw = getpwuid(atoi(name)); | ||||
else | else | ||||
pw = getpwnam(name); | pw = getpwnam(name); | ||||
/* | /* | ||||
* Credentials specified as those of a user. | * Credentials specified as those of a user. | ||||
*/ | */ | ||||
if (names == NULL) { | if (names == NULL) { | ||||
if (pw == NULL) { | if (pw == NULL) { | ||||
syslog(LOG_ERR, "unknown user: %s", name); | syslog(LOG_ERR, "unknown user: %s", name); | ||||
return; | return; | ||||
} | } | ||||
cr->cr_uid = pw->pw_uid; | cr->cr_uid = pw->pw_uid; | ||||
cr->cr_ngroups = NGROUPS_MAX + 1; | ngroups = NGROUPS_MAX + 1; | ||||
if (getgrouplist(pw->pw_name, pw->pw_gid, cr->cr_groups, | if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { | ||||
&cr->cr_ngroups)) { | |||||
syslog(LOG_ERR, "too many groups"); | syslog(LOG_ERR, "too many groups"); | ||||
cr->cr_ngroups = NGROUPS_MAX + 1; | ngroups = NGROUPS_MAX + 1; | ||||
} | } | ||||
/* | /* | ||||
* Compress out duplicate. | * Compress out duplicate. | ||||
*/ | */ | ||||
if (cr->cr_ngroups > 1 && cr->cr_groups[0] == | if (ngroups > 1 && groups[0] == groups[1]) { | ||||
cr->cr_groups[1]) { | ngroups--; | ||||
for (cnt = 2; cnt < cr->cr_ngroups; cnt++) | inpos = 2; | ||||
cr->cr_groups[cnt - 1] = cr->cr_groups[cnt]; | } else | ||||
cr->cr_ngroups--; | inpos = 1; | ||||
} | if (ngroups > NGROUPS_MAX) | ||||
if (cr->cr_ngroups > NGROUPS_MAX) | ngroups = NGROUPS_MAX; | ||||
cr->cr_ngroups = NGROUPS_MAX; | if (ngroups > SMALLNGROUPS) | ||||
cr->cr_groups = malloc(ngroups * sizeof(gid_t)); | |||||
cr->cr_ngroups = ngroups; | |||||
cr->cr_groups[0] = groups[0]; | |||||
memcpy(&cr->cr_groups[1], &groups[inpos], (ngroups - 1) * | |||||
Done Inline ActionsHow about using memcpy here, too? freqlabs: How about using memcpy here, too? | |||||
sizeof(gid_t)); | |||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* Explicit credential specified as a colon separated list: | * Explicit credential specified as a colon separated list: | ||||
* uid:gid:gid:... | * uid:gid:gid:... | ||||
*/ | */ | ||||
if (pw != NULL) | if (pw != NULL) | ||||
cr->cr_uid = pw->pw_uid; | cr->cr_uid = pw->pw_uid; | ||||
else if (isdigit(*name) || *name == '-') | else if (isdigit(*name) || *name == '-') | ||||
cr->cr_uid = atoi(name); | cr->cr_uid = atoi(name); | ||||
else { | else { | ||||
syslog(LOG_ERR, "unknown user: %s", name); | syslog(LOG_ERR, "unknown user: %s", name); | ||||
return; | return; | ||||
} | } | ||||
cr->cr_ngroups = 0; | cr->cr_ngroups = 0; | ||||
while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { | while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { | ||||
name = strsep_quote(&names, ":"); | name = strsep_quote(&names, ":"); | ||||
if (isdigit(*name) || *name == '-') { | if (isdigit(*name) || *name == '-') { | ||||
cr->cr_groups[cr->cr_ngroups++] = atoi(name); | groups[cr->cr_ngroups++] = atoi(name); | ||||
} else { | } else { | ||||
if ((gr = getgrnam(name)) == NULL) { | if ((gr = getgrnam(name)) == NULL) { | ||||
syslog(LOG_ERR, "unknown group: %s", name); | syslog(LOG_ERR, "unknown group: %s", name); | ||||
continue; | continue; | ||||
} | } | ||||
cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; | groups[cr->cr_ngroups++] = gr->gr_gid; | ||||
} | } | ||||
} | } | ||||
if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) | if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) | ||||
syslog(LOG_ERR, "too many groups"); | syslog(LOG_ERR, "too many groups"); | ||||
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)); | |||||
} | } | ||||
#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) | #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) | ||||
/* | /* | ||||
* Routines that maintain the remote mounttab | * Routines that maintain the remote mounttab | ||||
*/ | */ | ||||
static void | static void | ||||
get_mountlist(void) | get_mountlist(void) | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (grp->gr_type == GT_HOST) { | if (grp->gr_type == GT_HOST) { | ||||
if (grp->gr_ptr.gt_addrinfo != NULL) | if (grp->gr_ptr.gt_addrinfo != NULL) | ||||
freeaddrinfo(grp->gr_ptr.gt_addrinfo); | freeaddrinfo(grp->gr_ptr.gt_addrinfo); | ||||
} else if (grp->gr_type == GT_NET) { | } else if (grp->gr_type == GT_NET) { | ||||
if (grp->gr_ptr.gt_net.nt_name) | if (grp->gr_ptr.gt_net.nt_name) | ||||
free(grp->gr_ptr.gt_net.nt_name); | free(grp->gr_ptr.gt_net.nt_name); | ||||
} | } | ||||
if (grp->gr_anon.cr_groups != grp->gr_anon.cr_smallgrps) | |||||
free(grp->gr_anon.cr_groups); | |||||
free((caddr_t)grp); | free((caddr_t)grp); | ||||
} | } | ||||
#ifdef DEBUG | #ifdef DEBUG | ||||
static void | static void | ||||
SYSLOG(int pri, const char *fmt, ...) | SYSLOG(int pri, const char *fmt, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
cp_cred(struct expcred *outcr, struct expcred *incr) | cp_cred(struct expcred *outcr, struct expcred *incr) | ||||
{ | { | ||||
outcr->cr_uid = incr->cr_uid; | outcr->cr_uid = incr->cr_uid; | ||||
outcr->cr_ngroups = incr->cr_ngroups; | outcr->cr_ngroups = incr->cr_ngroups; | ||||
if (outcr->cr_ngroups > SMALLNGROUPS) | |||||
outcr->cr_groups = malloc(outcr->cr_ngroups * sizeof(gid_t)); | |||||
else | |||||
outcr->cr_groups = outcr->cr_smallgrps; | |||||
memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups * | memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups * | ||||
sizeof(gid_t)); | sizeof(gid_t)); | ||||
} | } |
I find a test like anon.cr_groups != anon.cr_smallgrps more clean, instead of relying on the size comparision.