jexec.c revision 179319
1/*- 2 * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/usr.sbin/jexec/jexec.c 179319 2008-05-26 11:57:49Z mr $ 27 */ 28 29#include <sys/param.h> 30#include <sys/jail.h> 31#include <sys/sysctl.h> 32 33#include <arpa/inet.h> 34 35#include <err.h> 36#include <errno.h> 37#include <limits.h> 38#include <login_cap.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <pwd.h> 42#include <unistd.h> 43#include <string.h> 44 45static void usage(void); 46int addr2jid(const char *addr); 47 48#define GET_USER_INFO do { \ 49 pwd = getpwnam(username); \ 50 if (pwd == NULL) { \ 51 if (errno) \ 52 err(1, "getpwnam: %s", username); \ 53 else \ 54 errx(1, "%s: no such user", username); \ 55 } \ 56 lcap = login_getpwclass(pwd); \ 57 if (lcap == NULL) \ 58 err(1, "getpwclass: %s", username); \ 59 ngroups = NGROUPS; \ 60 if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \ 61 err(1, "getgrouplist: %s", username); \ 62} while (0) 63 64int 65main(int argc, char *argv[]) 66{ 67 int jid; 68 login_cap_t *lcap = NULL; 69 struct passwd *pwd = NULL; 70 gid_t groups[NGROUPS]; 71 int ch, ngroups, uflag, Uflag; 72 char *username; 73 ch = uflag = Uflag = 0; 74 username = NULL; 75 76 while ((ch = getopt(argc, argv, "u:U:")) != -1) { 77 switch (ch) { 78 case 'u': 79 username = optarg; 80 uflag = 1; 81 break; 82 case 'U': 83 username = optarg; 84 Uflag = 1; 85 break; 86 default: 87 usage(); 88 } 89 } 90 argc -= optind; 91 argv += optind; 92 if (argc < 2) 93 usage(); 94 if (uflag && Uflag) 95 usage(); 96 if (uflag) 97 GET_USER_INFO; 98 jid = (int)strtol(argv[0], NULL, 10); 99 if (jail_attach(jid) == -1) 100 if (jail_attach(addr2jid(argv[0])) == -1) 101 errx(1, "jail_attach(): Cant convert %s to jid", argv[0]); 102 if (chdir("/") == -1) 103 err(1, "chdir(): /"); 104 if (username != NULL) { 105 if (Uflag) 106 GET_USER_INFO; 107 if (setgroups(ngroups, groups) != 0) 108 err(1, "setgroups"); 109 if (setgid(pwd->pw_gid) != 0) 110 err(1, "setgid"); 111 if (setusercontext(lcap, pwd, pwd->pw_uid, 112 LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) 113 err(1, "setusercontext"); 114 login_close(lcap); 115 } 116 if (execvp(argv[1], argv + 1) == -1) 117 err(1, "execvp(): %s", argv[1]); 118 exit(0); 119} 120 121static void 122usage(void) 123{ 124 125 fprintf(stderr, "%s%s\n", 126 "usage: jexec [-u username | -U username]", 127 " [jid | hostname | ip-number] command ..."); 128 exit(1); 129} 130 131int 132addr2jid(const char *addr) 133{ 134 struct xprison *sxp, *xp; 135 struct in_addr in; 136 size_t i, len, slen; 137 138 if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) 139 err(1, "sysctlbyname(): security.jail.list"); 140 for (i = 0; i < 4; i++) { 141 if (len <= 0) 142 err(1, "sysctlbyname(): len <=0"); 143 sxp = xp = malloc(len); 144 if (sxp == NULL) 145 err(1, "malloc()"); 146 if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) { 147 if (errno == ENOMEM) { 148 free(sxp); 149 sxp = NULL; 150 continue; 151 } 152 err(1, "sysctlbyname(): security.jail.list"); 153 } 154 break; 155 } 156 if (sxp == NULL) 157 err(1, "sysctlbyname(): security.jail.list"); 158 if (len < sizeof(*xp) || len % sizeof(*xp) || 159 xp->pr_version != XPRISON_VERSION) 160 errx(1, "Kernel and userland out of sync"); 161 slen = strlen(addr); 162 for (i = 0; i < len / sizeof(*xp); i++) { 163 in.s_addr = ntohl(xp->pr_ip); 164 if ((strncmp(inet_ntoa(in), addr, slen) == 0) || 165 (strncmp(xp->pr_host, addr, slen) == 0)) { 166 free(sxp); 167 return (xp->pr_id); 168 } 169 xp++; 170 } 171 free(sxp); 172 return 0; 173} 174