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$ 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 45 static void usage(void); 46 static int 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 64 int 65 main(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, hflag; 72 char *username; 73 ch = uflag = Uflag = hflag = 0; 74 username = NULL; 75 76 while ((ch = getopt(argc, argv, "u:U:h")) != -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 case 'h': 87 hflag = 1; 88 break; 89 default: 90 usage(); 91 } 92 } 93 argc -= optind; 94 argv += optind; 95 if (argc < 2) 96 usage(); 97 if (uflag && Uflag) 98 usage(); 99 if (uflag) 100 GET_USER_INFO; 101 if (hflag) { 102 if ((jid = addr2jid(argv[0])) == 0) 103 errx(1, "jail_attach(): Cannot convert %s to jid", argv[0]); 104 } else 105 jid = (int)strtol(argv[0], NULL, 10); 106 if (jail_attach(jid) == -1) 107 err(1, "jail_attach(): %d", jid); 108 if (chdir("/") == -1) 109 err(1, "chdir(): /"); 110 if (username != NULL) { 111 if (Uflag) 112 GET_USER_INFO; 113 if (setgroups(ngroups, groups) != 0) 114 err(1, "setgroups"); 115 if (setgid(pwd->pw_gid) != 0) 116 err(1, "setgid"); 117 if (setusercontext(lcap, pwd, pwd->pw_uid, 118 LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) 119 err(1, "setusercontext"); 120 login_close(lcap); 121 } 122 if (execvp(argv[1], argv + 1) == -1) 123 err(1, "execvp(): %s", argv[1]); 124 exit(0); 125 } 126 127 static void 128 usage(void) 129 { 130 131 fprintf(stderr, "%s%s\n", 132 "usage: jexec [-u username | -U username]", 133 " [-h hostname | -h ip-number | jid] command ..."); 134 exit(1); 135 } 136 137 static int 138 addr2jid(const char *addr) 139 { 140 struct xprison *sxp, *xp; 141 struct in_addr in; 142 size_t i, len; 143 int jid, cnt; 144 jid = cnt = 0; 145 146 if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) 147 err(1, "sysctlbyname(): security.jail.list"); 148 for (i = 0; i < 4; i++) { 149 if (len <= 0) 150 err(1, "sysctlbyname(): len <=0"); 151 sxp = xp = malloc(len); 152 if (sxp == NULL) 153 err(1, "malloc()"); 154 if (sysctlbyname("security.jail.list", xp, &len, NULL, 0) == -1) { 155 if (errno == ENOMEM) { 156 free(sxp); 157 sxp = NULL; 158 continue; 159 } 160 err(1, "sysctlbyname(): security.jail.list"); 161 } 162 break; 163 } 164 if (sxp == NULL) 165 err(1, "sysctlbyname(): security.jail.list"); 166 if (len < sizeof(*xp) || len % sizeof(*xp) || 167 xp->pr_version != XPRISON_VERSION) 168 errx(1, "Kernel and userland out of sync"); 169 for (i = 0; i < len / sizeof(*xp); i++) { 170 in.s_addr = ntohl(xp->pr_ip); 171 if ((strcmp(inet_ntoa(in), addr) == 0) || 172 (strcmp(xp->pr_host, addr) == 0)) { 173 jid = xp->pr_id; 174 cnt++; 175 } 176 xp++; 177 } 178 free(sxp); 179 if (cnt == 1) 180 return (jid); 181 else 182 return(0); 183 } 184