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