1 /* $OpenBSD: chroot.c,v 1.7 2002/10/29 23:12:06 millert Exp $ */ 2 /* $NetBSD: chroot.c,v 1.11 2001/04/06 02:34:04 lukem Exp $ */ 3 4 /* 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 #ifndef lint 39 static const char copyright[] = 40 "@(#) Copyright (c) 1988, 1993\n\ 41 The Regents of the University of California. All rights reserved.\n"; 42 #endif /* not lint */ 43 44 #ifndef lint 45 #if 0 46 static const char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93"; 47 #else 48 static const char rcsid[] = "$OpenBSD: chroot.c,v 1.7 2002/10/29 23:12:06 millert Exp $"; 49 #endif 50 #endif /* not lint */ 51 52 #include <ctype.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <grp.h> 56 #include <limits.h> 57 #include <paths.h> 58 #include <pwd.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 int main(int, char **); 65 __dead void usage(void); 66 67 int 68 main(int argc, char **argv) 69 { 70 struct group *gp; 71 struct passwd *pw; 72 const char *shell; 73 char *fulluser, *user, *group, *grouplist, *endp, *p; 74 gid_t gid, gidlist[NGROUPS_MAX]; 75 uid_t uid; 76 int ch, gids; 77 unsigned long ul; 78 79 gid = 0; 80 uid = 0; 81 gids = 0; 82 user = fulluser = group = grouplist = NULL; 83 while ((ch = getopt(argc, argv, "G:g:U:u:")) != -1) { 84 switch(ch) { 85 case 'U': 86 fulluser = optarg; 87 if (*fulluser == '\0') 88 usage(); 89 break; 90 case 'u': 91 user = optarg; 92 if (*user == '\0') 93 usage(); 94 break; 95 case 'g': 96 group = optarg; 97 if (*group == '\0') 98 usage(); 99 break; 100 case 'G': 101 grouplist = optarg; 102 if (*grouplist == '\0') 103 usage(); 104 break; 105 case '?': 106 default: 107 usage(); 108 } 109 } 110 argc -= optind; 111 argv += optind; 112 113 if (argc < 1) 114 usage(); 115 if (fulluser && (user || group || grouplist)) 116 errx(1, 117 "the -U option may not be specified with any other option"); 118 119 if (group != NULL) { 120 if ((gp = getgrnam(group)) != NULL) 121 gid = gp->gr_gid; 122 else if (isdigit((unsigned char)*group)) { 123 errno = 0; 124 ul = strtoul(group, &endp, 10); 125 if (*endp != '\0' || 126 (ul == ULONG_MAX && errno == ERANGE)) 127 errx(1, "invalid group ID `%s'", group); 128 gid = (gid_t)ul; 129 } else 130 errx(1, "no such group `%s'", group); 131 if (grouplist != NULL) 132 gidlist[gids++] = gid; 133 if (setgid(gid) != 0) 134 err(1, "setgid"); 135 } 136 137 while ((p = strsep(&grouplist, ",")) != NULL && gids < NGROUPS_MAX) { 138 if (*p == '\0') 139 continue; 140 141 if ((gp = getgrnam(p)) != NULL) 142 gidlist[gids] = gp->gr_gid; 143 else if (isdigit((unsigned char)*p)) { 144 errno = 0; 145 ul = strtoul(p, &endp, 10); 146 if (*endp != '\0' || 147 (ul == ULONG_MAX && errno == ERANGE)) 148 errx(1, "invalid group ID `%s'", p); 149 gidlist[gids] = (gid_t)ul; 150 } else 151 errx(1, "no such group `%s'", p); 152 /* 153 * Ignore primary group if specified; we already added it above. 154 */ 155 if (group == NULL || gidlist[gids] != gid) 156 gids++; 157 } 158 if (p != NULL && gids == NGROUPS_MAX) 159 errx(1, "too many supplementary groups provided"); 160 if (gids && setgroups(gids, gidlist) != 0) 161 err(1, "setgroups"); 162 163 if (user != NULL) { 164 if ((pw = getpwnam(user)) != NULL) 165 uid = pw->pw_uid; 166 else if (isdigit((unsigned char)*user)) { 167 errno = 0; 168 ul = strtoul(user, &endp, 10); 169 if (*endp != '\0' || 170 (ul == ULONG_MAX && errno == ERANGE)) 171 errx(1, "invalid user ID `%s'", user); 172 uid = (uid_t)ul; 173 } else 174 errx(1, "no such user `%s'", user); 175 } 176 177 if (fulluser != NULL) { 178 if ((pw = getpwnam(fulluser)) == NULL) 179 errx(1, "no such user `%s'", fulluser); 180 uid = pw->pw_uid; 181 gid = pw->pw_gid; 182 if (setgid(gid) != 0) 183 err(1, "setgid"); 184 if (initgroups(fulluser, gid) == -1) 185 err(1, "initgroups"); 186 } 187 188 if (chroot(argv[0]) != 0 || chdir("/") != 0) 189 err(1, "%s", argv[0]); 190 191 if ((user || fulluser) && setuid(uid) != 0) 192 err(1, "setuid"); 193 194 if (argv[1]) { 195 execvp(argv[1], &argv[1]); 196 err(1, "%s", argv[1]); 197 } 198 199 if ((shell = getenv("SHELL")) == NULL) 200 shell = _PATH_BSHELL; 201 execlp(shell, shell, "-i", (char *)NULL); 202 err(1, "%s", shell); 203 /* NOTREACHED */ 204 } 205 206 void 207 usage(void) 208 { 209 extern char *__progname; 210 211 (void)fprintf(stderr, "usage: %s [-g group] [-G group,group,...] " 212 "[-u user] [-U user] newroot [command]\n", __progname); 213 exit(1); 214 } 215