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