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