Skip to content

Commit 91eb4d2

Browse files
committed
chroot: slightly cleanup
Highlights: - Pull resolve_user() and resolve_group() out to make the main flow a bit easier to read - Fix some edge-cases in user/group resolution: you can have fully numeric usernames, and they may or may not live within the valid ID range. Switch to just trying to resolve every specified group/user as a name, first, with a fallback to converting it to a numeric type and trying to resolve it as an ID. - Constify locals in main() that don't need to be mutable, re-sort Reviewed by: emaste, olce Differential Revision: https://reviews.freebsd.org/D51509
1 parent 702423e commit 91eb4d2

1 file changed

Lines changed: 51 additions & 43 deletions

File tree

usr.sbin/chroot/chroot.c

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,58 @@
4747

4848
static void usage(void) __dead2;
4949

50+
static gid_t
51+
resolve_group(const char *group)
52+
{
53+
char *endp;
54+
struct group *gp;
55+
unsigned long gid;
56+
57+
gp = getgrnam(group);
58+
if (gp != NULL)
59+
return (gp->gr_gid);
60+
61+
/*
62+
* Numeric IDs don't need a trip through the database to check them,
63+
* POSIX seems to think we should generally accept a numeric ID as long
64+
* as it's within the valid range.
65+
*/
66+
errno = 0;
67+
gid = strtoul(group, &endp, 0);
68+
if (errno == 0 && *endp == '\0' && (gid_t)gid >= 0 && gid <= GID_MAX)
69+
return (gid);
70+
71+
errx(1, "no such group '%s'", group);
72+
}
73+
74+
static uid_t
75+
resolve_user(const char *user)
76+
{
77+
char *endp;
78+
struct passwd *pw;
79+
unsigned long uid;
80+
81+
pw = getpwnam(user);
82+
if (pw != NULL)
83+
return (pw->pw_uid);
84+
85+
errno = 0;
86+
uid = strtoul(user, &endp, 0);
87+
if (errno == 0 && *endp == '\0' && (uid_t)uid >= 0 && uid <= UID_MAX)
88+
return (uid);
89+
90+
errx(1, "no such user '%s'", user);
91+
}
92+
5093
int
5194
main(int argc, char *argv[])
5295
{
53-
struct group *gp;
54-
struct passwd *pw;
55-
char *endp, *p, *user, *group, *grouplist;
56-
const char *shell;
96+
const char *group, *p, *shell, *user;
97+
char *grouplist;
98+
long ngroups_max;
5799
gid_t gid, *gidlist;
58100
uid_t uid;
59101
int arg, ch, error, gids;
60-
long ngroups_max;
61102
bool nonprivileged;
62103

63104
gid = 0;
@@ -95,19 +136,8 @@ main(int argc, char *argv[])
95136
if (argc < 1)
96137
usage();
97138

98-
if (group != NULL) {
99-
if (isdigit((unsigned char)*group)) {
100-
gid = (gid_t)strtoul(group, &endp, 0);
101-
if (*endp != '\0')
102-
goto getgroup;
103-
} else {
104-
getgroup:
105-
if ((gp = getgrnam(group)) != NULL)
106-
gid = gp->gr_gid;
107-
else
108-
errx(1, "no such group `%s'", group);
109-
}
110-
}
139+
if (group != NULL)
140+
gid = resolve_group(group);
111141

112142
ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
113143
if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
@@ -122,35 +152,13 @@ main(int argc, char *argv[])
122152
if (*p == '\0')
123153
continue;
124154

125-
if (isdigit((unsigned char)*p)) {
126-
gidlist[gids] = (gid_t)strtoul(p, &endp, 0);
127-
if (*endp != '\0')
128-
goto getglist;
129-
} else {
130-
getglist:
131-
if ((gp = getgrnam(p)) != NULL)
132-
gidlist[gids] = gp->gr_gid;
133-
else
134-
errx(1, "no such group `%s'", p);
135-
}
136-
gids++;
155+
gidlist[gids++] = resolve_group(p);
137156
}
138157
if (p != NULL && gids == ngroups_max)
139158
errx(1, "too many supplementary groups provided");
140159

141-
if (user != NULL) {
142-
if (isdigit((unsigned char)*user)) {
143-
uid = (uid_t)strtoul(user, &endp, 0);
144-
if (*endp != '\0')
145-
goto getuser;
146-
} else {
147-
getuser:
148-
if ((pw = getpwnam(user)) != NULL)
149-
uid = pw->pw_uid;
150-
else
151-
errx(1, "no such user `%s'", user);
152-
}
153-
}
160+
if (user != NULL)
161+
uid = resolve_user(user);
154162

155163
if (nonprivileged) {
156164
arg = PROC_NO_NEW_PRIVS_ENABLE;

0 commit comments

Comments
 (0)