xref: /freebsd/usr.bin/mdo/mdo.c (revision 8aac90f18aef7c9eea906c3ff9a001ca7b94f375)
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
usage(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
main(int argc,char ** argv)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