xref: /freebsd/usr.sbin/jail/jail.c (revision 7deb00ccd95a0502fae9afc177bc29e279013af2)
1ce5c1cd1SPoul-Henning Kamp /*
2ce5c1cd1SPoul-Henning Kamp  * ----------------------------------------------------------------------------
3ce5c1cd1SPoul-Henning Kamp  * "THE BEER-WARE LICENSE" (Revision 42):
4ce5c1cd1SPoul-Henning Kamp  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5ce5c1cd1SPoul-Henning Kamp  * can do whatever you want with this stuff. If we meet some day, and you think
6ce5c1cd1SPoul-Henning Kamp  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7ce5c1cd1SPoul-Henning Kamp  * ----------------------------------------------------------------------------
8ce5c1cd1SPoul-Henning Kamp  */
9ce5c1cd1SPoul-Henning Kamp 
1054ede02dSPhilippe Charnier #include <sys/cdefs.h>
1154ede02dSPhilippe Charnier __FBSDID("$FreeBSD$");
1254ede02dSPhilippe Charnier 
13d6131f4bSMaxim Konovalov #include <sys/param.h>
143876038aSDima Dorfman #include <sys/jail.h>
157deb00ccSMatteo Riondato #include <sys/sysctl.h>
163876038aSDima Dorfman 
173876038aSDima Dorfman #include <netinet/in.h>
183876038aSDima Dorfman #include <arpa/inet.h>
193876038aSDima Dorfman 
203876038aSDima Dorfman #include <err.h>
21927b4810SMaxim Konovalov #include <errno.h>
22d6131f4bSMaxim Konovalov #include <grp.h>
23d6131f4bSMaxim Konovalov #include <login_cap.h>
245b242e8cSMaxim Konovalov #include <paths.h>
25d6131f4bSMaxim Konovalov #include <pwd.h>
2675c13541SPoul-Henning Kamp #include <stdio.h>
272694efd4SDima Dorfman #include <stdlib.h>
282694efd4SDima Dorfman #include <string.h>
293876038aSDima Dorfman #include <unistd.h>
3075c13541SPoul-Henning Kamp 
31d6131f4bSMaxim Konovalov static void	usage(void);
327deb00ccSMatteo Riondato static void	setsecurelevel(int level);
335b242e8cSMaxim Konovalov extern char	**environ;
34d6131f4bSMaxim Konovalov 
35927b4810SMaxim Konovalov #define GET_USER_INFO do {						\
36927b4810SMaxim Konovalov 	pwd = getpwnam(username);					\
37927b4810SMaxim Konovalov 	if (pwd == NULL) {						\
38927b4810SMaxim Konovalov 		if (errno)						\
39927b4810SMaxim Konovalov 			err(1, "getpwnam: %s", username);		\
40927b4810SMaxim Konovalov 		else							\
41927b4810SMaxim Konovalov 			errx(1, "%s: no such user", username);		\
42927b4810SMaxim Konovalov 	}								\
43927b4810SMaxim Konovalov 	lcap = login_getpwclass(pwd);					\
44927b4810SMaxim Konovalov 	if (lcap == NULL)						\
45927b4810SMaxim Konovalov 		err(1, "getpwclass: %s", username);			\
46927b4810SMaxim Konovalov 	ngroups = NGROUPS;						\
47927b4810SMaxim Konovalov 	if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0)	\
48927b4810SMaxim Konovalov 		err(1, "getgrouplist: %s", username);			\
49927b4810SMaxim Konovalov } while (0)
50927b4810SMaxim Konovalov 
5175c13541SPoul-Henning Kamp int
5275c13541SPoul-Henning Kamp main(int argc, char **argv)
5375c13541SPoul-Henning Kamp {
54d1df3fcdSXin LI 	login_cap_t *lcap = NULL;
5575c13541SPoul-Henning Kamp 	struct jail j;
56d1df3fcdSXin LI 	struct passwd *pwd = NULL;
5775c13541SPoul-Henning Kamp 	struct in_addr in;
58950cc395SStefan Farfeleder 	gid_t groups[NGROUPS];
59cdafc851SPhilip Paeps 	int ch, i, iflag, Jflag, lflag, ngroups, uflag, Uflag;
60cdafc851SPhilip Paeps 	char path[PATH_MAX], *username, *JidFile;
615b242e8cSMaxim Konovalov 	static char *cleanenv;
6295751846SXin LI 	const char *shell, *p = NULL;
637deb00ccSMatteo Riondato 	int securelevel = -1;
64cdafc851SPhilip Paeps 	FILE *fp;
6575c13541SPoul-Henning Kamp 
66cdafc851SPhilip Paeps 	iflag = Jflag = lflag = uflag = Uflag = 0;
67cdafc851SPhilip Paeps 	username = JidFile = cleanenv = NULL;
68cdafc851SPhilip Paeps 	fp = NULL;
69d6131f4bSMaxim Konovalov 
707deb00ccSMatteo Riondato 	while ((ch = getopt(argc, argv, "ils:u:U:J:")) != -1) {
71d6131f4bSMaxim Konovalov 		switch (ch) {
72ebf5d9bcSMike Barcroft 		case 'i':
73ebf5d9bcSMike Barcroft 			iflag = 1;
74ebf5d9bcSMike Barcroft 			break;
75cdafc851SPhilip Paeps 		case 'J':
76cdafc851SPhilip Paeps 			JidFile = optarg;
77cdafc851SPhilip Paeps 			Jflag = 1;
78cdafc851SPhilip Paeps 			break;
797deb00ccSMatteo Riondato 		case 's':
807deb00ccSMatteo Riondato 			securelevel = (int) strtol(optarg, NULL, 0);
817deb00ccSMatteo Riondato 			break;
82d6131f4bSMaxim Konovalov 		case 'u':
83d6131f4bSMaxim Konovalov 			username = optarg;
84927b4810SMaxim Konovalov 			uflag = 1;
85927b4810SMaxim Konovalov 			break;
86927b4810SMaxim Konovalov 		case 'U':
87927b4810SMaxim Konovalov 			username = optarg;
88927b4810SMaxim Konovalov 			Uflag = 1;
89d6131f4bSMaxim Konovalov 			break;
905b242e8cSMaxim Konovalov 		case 'l':
915b242e8cSMaxim Konovalov 			lflag = 1;
925b242e8cSMaxim Konovalov 			break;
93d6131f4bSMaxim Konovalov 		default:
94d6131f4bSMaxim Konovalov 			usage();
95ebf5d9bcSMike Barcroft 		}
96d6131f4bSMaxim Konovalov 	}
97d6131f4bSMaxim Konovalov 	argc -= optind;
98d6131f4bSMaxim Konovalov 	argv += optind;
99d6131f4bSMaxim Konovalov 	if (argc < 4)
100d6131f4bSMaxim Konovalov 		usage();
101927b4810SMaxim Konovalov 	if (uflag && Uflag)
102927b4810SMaxim Konovalov 		usage();
1035b242e8cSMaxim Konovalov 	if (lflag && username == NULL)
1045b242e8cSMaxim Konovalov 		usage();
105927b4810SMaxim Konovalov 	if (uflag)
106927b4810SMaxim Konovalov 		GET_USER_INFO;
107232a6818SPawel Jakub Dawidek 	if (realpath(argv[0], path) == NULL)
108232a6818SPawel Jakub Dawidek 		err(1, "realpath: %s", argv[0]);
109232a6818SPawel Jakub Dawidek 	if (chdir(path) != 0)
110232a6818SPawel Jakub Dawidek 		err(1, "chdir: %s", path);
1117248ef86SPoul-Henning Kamp 	memset(&j, 0, sizeof(j));
1127248ef86SPoul-Henning Kamp 	j.version = 0;
113232a6818SPawel Jakub Dawidek 	j.path = path;
114d6131f4bSMaxim Konovalov 	j.hostname = argv[1];
115b026ec0eSMaxim Konovalov 	if (inet_aton(argv[2], &in) == 0)
116b026ec0eSMaxim Konovalov 		errx(1, "Could not make sense of ip-number: %s", argv[2]);
117ce5c1cd1SPoul-Henning Kamp 	j.ip_number = ntohl(in.s_addr);
118cdafc851SPhilip Paeps 	if (Jflag) {
119cdafc851SPhilip Paeps 		fp = fopen(JidFile, "w");
120cdafc851SPhilip Paeps 		if (fp == NULL)
121cdafc851SPhilip Paeps 			errx(1, "Could not create JidFile: %s", JidFile);
122cdafc851SPhilip Paeps 	}
123ebf5d9bcSMike Barcroft 	i = jail(&j);
124ebf5d9bcSMike Barcroft 	if (i == -1)
125b026ec0eSMaxim Konovalov 		err(1, "jail");
12625639ca7SMike Barcroft 	if (iflag) {
127ebf5d9bcSMike Barcroft 		printf("%d\n", i);
12825639ca7SMike Barcroft 		fflush(stdout);
12925639ca7SMike Barcroft 	}
130cdafc851SPhilip Paeps 	if (Jflag) {
131cdafc851SPhilip Paeps 		if (fp != NULL) {
132cdafc851SPhilip Paeps 			fprintf(fp, "%d\t%s\t%s\t%s\t%s\n",
133cdafc851SPhilip Paeps 			    i, j.path, j.hostname, argv[2], argv[3]);
134cdafc851SPhilip Paeps 			(void)fclose(fp);
135cdafc851SPhilip Paeps 		} else {
136cdafc851SPhilip Paeps 			errx(1, "Could not write JidFile: %s", JidFile);
137cdafc851SPhilip Paeps 		}
138cdafc851SPhilip Paeps 	}
1397deb00ccSMatteo Riondato 	if (securelevel > 0)
1407deb00ccSMatteo Riondato 			setsecurelevel(securelevel);
141d6131f4bSMaxim Konovalov 	if (username != NULL) {
142927b4810SMaxim Konovalov 		if (Uflag)
143927b4810SMaxim Konovalov 			GET_USER_INFO;
1445b242e8cSMaxim Konovalov 		if (lflag) {
1455b242e8cSMaxim Konovalov 			p = getenv("TERM");
1465b242e8cSMaxim Konovalov 			environ = &cleanenv;
1475b242e8cSMaxim Konovalov 		}
148b026ec0eSMaxim Konovalov 		if (setgroups(ngroups, groups) != 0)
149b026ec0eSMaxim Konovalov 			err(1, "setgroups");
150b026ec0eSMaxim Konovalov 		if (setgid(pwd->pw_gid) != 0)
151b026ec0eSMaxim Konovalov 			err(1, "setgid");
152b026ec0eSMaxim Konovalov 		if (setusercontext(lcap, pwd, pwd->pw_uid,
1532edf0a44SMaxim Konovalov 		    LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0)
154b026ec0eSMaxim Konovalov 			err(1, "setusercontext");
1550389572fSMaxim Konovalov 		login_close(lcap);
156d6131f4bSMaxim Konovalov 	}
1575b242e8cSMaxim Konovalov 	if (lflag) {
1585b242e8cSMaxim Konovalov 		if (*pwd->pw_shell)
1595b242e8cSMaxim Konovalov 			shell = pwd->pw_shell;
1605b242e8cSMaxim Konovalov 		else
1615b242e8cSMaxim Konovalov 			shell = _PATH_BSHELL;
1625b242e8cSMaxim Konovalov 		if (chdir(pwd->pw_dir) < 0)
1635b242e8cSMaxim Konovalov 			errx(1, "no home directory");
1645b242e8cSMaxim Konovalov 		setenv("HOME", pwd->pw_dir, 1);
1655b242e8cSMaxim Konovalov 		setenv("SHELL", shell, 1);
1665b242e8cSMaxim Konovalov 		setenv("USER", pwd->pw_name, 1);
1675b242e8cSMaxim Konovalov 		if (p)
1685b242e8cSMaxim Konovalov 			setenv("TERM", p, 1);
1695b242e8cSMaxim Konovalov 	}
170b026ec0eSMaxim Konovalov 	if (execv(argv[3], argv + 3) != 0)
171b026ec0eSMaxim Konovalov 		err(1, "execv: %s", argv[3]);
17275c13541SPoul-Henning Kamp 	exit(0);
17375c13541SPoul-Henning Kamp }
174d6131f4bSMaxim Konovalov 
175d6131f4bSMaxim Konovalov static void
176d6131f4bSMaxim Konovalov usage(void)
177d6131f4bSMaxim Konovalov {
178d6131f4bSMaxim Konovalov 
1797deb00ccSMatteo Riondato 	(void)fprintf(stderr, "%s%s%s\n",
1807deb00ccSMatteo Riondato 		 "usage: jail [-i] [-J jid_file] [-s securelevel] [-l -u ",
1817deb00ccSMatteo Riondato  		 "username | -U username]",
182927b4810SMaxim Konovalov 	     " path hostname ip-number command ...");
183b026ec0eSMaxim Konovalov 	exit(1);
184d6131f4bSMaxim Konovalov }
1857deb00ccSMatteo Riondato 
1867deb00ccSMatteo Riondato static void
1877deb00ccSMatteo Riondato setsecurelevel(int level) {
1887deb00ccSMatteo Riondato 		if (sysctlbyname("kern.securelevel", NULL, 0, &level, sizeof(level)))
1897deb00ccSMatteo Riondato 		   err(1, "Can not set securelevel to %d", level);
1907deb00ccSMatteo Riondato 
1917deb00ccSMatteo Riondato }
1927deb00ccSMatteo Riondato 
193