Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/chroot/chroot.c
101477 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1988, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/types.h>
33
#include <sys/procctl.h>
34
35
#include <ctype.h>
36
#include <err.h>
37
#include <errno.h>
38
#include <grp.h>
39
#include <limits.h>
40
#include <paths.h>
41
#include <pwd.h>
42
#include <stdbool.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
48
static void usage(void) __dead2;
49
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 <= 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 <= UID_MAX)
88
return (uid);
89
90
errx(1, "no such user '%s'", user);
91
}
92
93
int
94
main(int argc, char *argv[])
95
{
96
const char *group, *p, *shell, *user;
97
char *grouplist;
98
long ngroups_max;
99
gid_t gid, *gidlist;
100
uid_t uid;
101
int arg, ch, error, gids;
102
bool nonprivileged;
103
104
gid = 0;
105
uid = 0;
106
gids = 0;
107
user = group = grouplist = NULL;
108
gidlist = NULL;
109
nonprivileged = false;
110
while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
111
switch(ch) {
112
case 'u':
113
user = optarg;
114
if (*user == '\0')
115
usage();
116
break;
117
case 'g':
118
group = optarg;
119
if (*group == '\0')
120
usage();
121
break;
122
case 'G':
123
grouplist = optarg;
124
125
/*
126
* XXX Why not allow us to drop all of our supplementary
127
* groups?
128
*/
129
if (*grouplist == '\0')
130
usage();
131
break;
132
case 'n':
133
nonprivileged = true;
134
break;
135
case '?':
136
default:
137
usage();
138
}
139
}
140
argc -= optind;
141
argv += optind;
142
143
if (argc < 1)
144
usage();
145
146
if (group != NULL)
147
gid = resolve_group(group);
148
149
if (grouplist != NULL) {
150
ngroups_max = sysconf(_SC_NGROUPS_MAX);
151
if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
152
err(1, "malloc");
153
for (gids = 0; (p = strsep(&grouplist, ",")) != NULL &&
154
gids < ngroups_max; ) {
155
if (*p == '\0')
156
continue;
157
158
gidlist[gids++] = resolve_group(p);
159
}
160
if (p != NULL && gids == ngroups_max)
161
errx(1, "too many supplementary groups provided");
162
}
163
164
if (user != NULL)
165
uid = resolve_user(user);
166
167
if (nonprivileged) {
168
arg = PROC_NO_NEW_PRIVS_ENABLE;
169
error = procctl(P_PID, getpid(), PROC_NO_NEW_PRIVS_CTL, &arg);
170
if (error != 0)
171
err(1, "procctl");
172
}
173
174
if (chdir(argv[0]) == -1)
175
err(1, "%s", argv[0]);
176
if (chroot(".") == -1) {
177
if (errno == EPERM && !nonprivileged && geteuid() != 0)
178
errx(1, "unprivileged use requires -n");
179
err(1, "%s", argv[0]);
180
}
181
182
if (gidlist != NULL && setgroups(gids, gidlist) == -1)
183
err(1, "setgroups");
184
if (group && setgid(gid) == -1)
185
err(1, "setgid");
186
if (user && setuid(uid) == -1)
187
err(1, "setuid");
188
189
if (argv[1]) {
190
execvp(argv[1], &argv[1]);
191
err(1, "%s", argv[1]);
192
}
193
194
if (!(shell = getenv("SHELL")))
195
shell = _PATH_BSHELL;
196
execlp(shell, shell, "-i", (char *)NULL);
197
err(1, "%s", shell);
198
/* NOTREACHED */
199
}
200
201
static void
202
usage(void)
203
{
204
(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
205
"[-u user] [-n] newroot [command]\n");
206
exit(1);
207
}
208
209