xref: /freebsd/usr.bin/mdo/mdo.c (revision 7899f917b1c0ea178f1d2be0cfb452086d079d23)
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