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
18static void
19usage(void)
20{
21	fprintf(stderr, "usage: mdo [-u username] [-i] [--] [command [args]]\n");
22	exit(EXIT_FAILURE);
23}
24
25int
26main(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