1/* $NetBSD: chroot.c,v 1.18 2011/08/28 08:32:47 mbalmer Exp $ */ 2 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/cdefs.h> 33#ifndef lint 34__COPYRIGHT("@(#) Copyright (c) 1988, 1993\ 35 The Regents of the University of California. All rights reserved."); 36#endif /* not lint */ 37 38#ifndef lint 39#if 0 40static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93"; 41#else 42__RCSID("$NetBSD: chroot.c,v 1.18 2011/08/28 08:32:47 mbalmer Exp $"); 43#endif 44#endif /* not lint */ 45 46#include <sys/param.h> 47 48#include <err.h> 49#include <errno.h> 50#include <grp.h> 51#include <paths.h> 52#include <pwd.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <inttypes.h> 56#include <string.h> 57#include <unistd.h> 58 59static void usage(void) __dead; 60 61static int 62getnum(const char *str, uintmax_t *num) 63{ 64 char *ep; 65 66 errno = 0; 67 68 *num = strtoumax(str, &ep, 0); 69 if (str[0] == '\0' || *ep != '\0') { 70 errno = EINVAL; 71 return -1; 72 } 73 74 if (errno == ERANGE && *num == UINTMAX_MAX) 75 return -1; 76 77 return 0; 78} 79 80 81static gid_t 82getgroup(const char *group) 83{ 84 uintmax_t num; 85 struct group *gp; 86 87 if ((gp = getgrnam(group)) != NULL) 88 return gp->gr_gid; 89 90 if (getnum(group, &num) == -1) 91 errx(1, "no such group `%s'", group); 92 93 return (gid_t)num; 94} 95 96static uid_t 97getuser(const char *user) 98{ 99 uintmax_t num; 100 struct passwd *pw; 101 102 if ((pw = getpwnam(user)) != NULL) 103 return pw->pw_uid; 104 105 if (getnum(user, &num) == -1) 106 errx(1, "no such user `%s'", user); 107 108 return (uid_t)num; 109} 110 111int 112main(int argc, char *argv[]) 113{ 114 char *user; /* user to switch to before running program */ 115 char *group; /* group to switch to ... */ 116 char *grouplist; /* group list to switch to ... */ 117 char *p; 118 const char *shell; 119 gid_t gid, gidlist[NGROUPS_MAX]; 120 uid_t uid; 121 int ch, gids; 122 123 user = NULL; 124 group = NULL; 125 grouplist = NULL; 126 gid = 0; 127 uid = 0; 128 gids = 0; 129 while ((ch = getopt(argc, argv, "G:g:u:")) != -1) { 130 switch(ch) { 131 case 'u': 132 user = optarg; 133 if (*user == '\0') 134 usage(); 135 break; 136 case 'g': 137 group = optarg; 138 if (*group == '\0') 139 usage(); 140 break; 141 case 'G': 142 grouplist = optarg; 143 if (*grouplist == '\0') 144 usage(); 145 break; 146 case '?': 147 default: 148 usage(); 149 } 150 } 151 argc -= optind; 152 argv += optind; 153 154 if (argc < 1) 155 usage(); 156 157 if (user != NULL) 158 uid = getuser(user); 159 160 if (group != NULL) 161 gid = getgroup(group); 162 163 if (grouplist != NULL) { 164 while ((p = strsep(&grouplist, ",")) != NULL) { 165 if (*p == '\0') 166 continue; 167 168 if (gids == NGROUPS_MAX) 169 errx(1, 170 "too many supplementary groups provided"); 171 172 gidlist[gids++] = getgroup(p); 173 } 174 } 175 176 if (chdir(argv[0]) == -1 || chroot(".") == -1) 177 err(1, "%s", argv[0]); 178 179 if (gids && setgroups(gids, gidlist) == -1) 180 err(1, "setgroups"); 181 if (group && setgid(gid) == -1) 182 err(1, "setgid"); 183 if (user && setuid(uid) == -1) 184 err(1, "setuid"); 185 186 if (argv[1]) { 187 execvp(argv[1], &argv[1]); 188 err(1, "%s", argv[1]); 189 } 190 191 if ((shell = getenv("SHELL")) == NULL) 192 shell = _PATH_BSHELL; 193 execlp(shell, shell, "-i", NULL); 194 err(1, "%s", shell); 195 /* NOTREACHED */ 196} 197 198static void 199usage(void) 200{ 201 202 (void)fprintf(stderr, "Usage: %s [-G group,group,...] [-g group] " 203 "[-u user] newroot [command]\n", getprogname()); 204 exit(1); 205} 206