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