1*8aac90f1SBaptiste Daroussin /*- 2*8aac90f1SBaptiste Daroussin * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> 3*8aac90f1SBaptiste Daroussin * 4*8aac90f1SBaptiste Daroussin * SPDX-License-Identifier: BSD-2-Clause 5*8aac90f1SBaptiste Daroussin */ 6*8aac90f1SBaptiste Daroussin 7*8aac90f1SBaptiste Daroussin #include <sys/limits.h> 8*8aac90f1SBaptiste Daroussin 9*8aac90f1SBaptiste Daroussin #include <err.h> 10*8aac90f1SBaptiste Daroussin #include <paths.h> 11*8aac90f1SBaptiste Daroussin #include <pwd.h> 12*8aac90f1SBaptiste Daroussin #include <stdbool.h> 13*8aac90f1SBaptiste Daroussin #include <stdio.h> 14*8aac90f1SBaptiste Daroussin #include <stdlib.h> 15*8aac90f1SBaptiste Daroussin #include <string.h> 16*8aac90f1SBaptiste Daroussin #include <unistd.h> 17*8aac90f1SBaptiste Daroussin 18*8aac90f1SBaptiste Daroussin static void 19*8aac90f1SBaptiste Daroussin usage(void) 20*8aac90f1SBaptiste Daroussin { 21*8aac90f1SBaptiste Daroussin fprintf(stderr, "usage: mdo [-u username] [-i] [--] [command [args]]\n"); 22*8aac90f1SBaptiste Daroussin exit(EXIT_FAILURE); 23*8aac90f1SBaptiste Daroussin } 24*8aac90f1SBaptiste Daroussin 25*8aac90f1SBaptiste Daroussin int 26*8aac90f1SBaptiste Daroussin main(int argc, char **argv) 27*8aac90f1SBaptiste Daroussin { 28*8aac90f1SBaptiste Daroussin struct passwd *pw; 29*8aac90f1SBaptiste Daroussin const char *username = "root"; 30*8aac90f1SBaptiste Daroussin bool uidonly = false; 31*8aac90f1SBaptiste Daroussin int ch; 32*8aac90f1SBaptiste Daroussin 33*8aac90f1SBaptiste Daroussin while ((ch = getopt(argc, argv, "u:i")) != -1) { 34*8aac90f1SBaptiste Daroussin switch (ch) { 35*8aac90f1SBaptiste Daroussin case 'u': 36*8aac90f1SBaptiste Daroussin username = optarg; 37*8aac90f1SBaptiste Daroussin break; 38*8aac90f1SBaptiste Daroussin case 'i': 39*8aac90f1SBaptiste Daroussin uidonly = true; 40*8aac90f1SBaptiste Daroussin break; 41*8aac90f1SBaptiste Daroussin default: 42*8aac90f1SBaptiste Daroussin usage(); 43*8aac90f1SBaptiste Daroussin } 44*8aac90f1SBaptiste Daroussin } 45*8aac90f1SBaptiste Daroussin argc -= optind; 46*8aac90f1SBaptiste Daroussin argv += optind; 47*8aac90f1SBaptiste Daroussin 48*8aac90f1SBaptiste Daroussin if ((pw = getpwnam(username)) == NULL) { 49*8aac90f1SBaptiste Daroussin if (strspn(username, "0123456789") == strlen(username)) { 50*8aac90f1SBaptiste Daroussin const char *errp = NULL; 51*8aac90f1SBaptiste Daroussin uid_t uid = strtonum(username, 0, UID_MAX, &errp); 52*8aac90f1SBaptiste Daroussin if (errp != NULL) 53*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "%s", errp); 54*8aac90f1SBaptiste Daroussin pw = getpwuid(uid); 55*8aac90f1SBaptiste Daroussin } 56*8aac90f1SBaptiste Daroussin if (pw == NULL) 57*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "invalid username '%s'", username); 58*8aac90f1SBaptiste Daroussin } 59*8aac90f1SBaptiste Daroussin if (!uidonly) { 60*8aac90f1SBaptiste Daroussin if (initgroups(pw->pw_name, pw->pw_gid) == -1) 61*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "failed to call initgroups"); 62*8aac90f1SBaptiste Daroussin if (setgid(pw->pw_gid) == -1) 63*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "failed to call setgid"); 64*8aac90f1SBaptiste Daroussin } 65*8aac90f1SBaptiste Daroussin if (setuid(pw->pw_uid) == -1) 66*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "failed to call setuid"); 67*8aac90f1SBaptiste Daroussin if (*argv == NULL) { 68*8aac90f1SBaptiste Daroussin const char *sh = getenv("SHELL"); 69*8aac90f1SBaptiste Daroussin if (sh == NULL) 70*8aac90f1SBaptiste Daroussin sh = _PATH_BSHELL; 71*8aac90f1SBaptiste Daroussin execlp(sh, sh, "-i", NULL); 72*8aac90f1SBaptiste Daroussin } else { 73*8aac90f1SBaptiste Daroussin execvp(argv[0], argv); 74*8aac90f1SBaptiste Daroussin } 75*8aac90f1SBaptiste Daroussin err(EXIT_FAILURE, "exec failed"); 76*8aac90f1SBaptiste Daroussin } 77