diff options
Diffstat (limited to 'usr.bin/mdo/mdo.c')
| -rw-r--r-- | usr.bin/mdo/mdo.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/usr.bin/mdo/mdo.c b/usr.bin/mdo/mdo.c new file mode 100644 index 000000000000..22e2838daa08 --- /dev/null +++ b/usr.bin/mdo/mdo.c @@ -0,0 +1,76 @@ +/*- + * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/limits.h> + +#include <err.h> +#include <paths.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void +usage(void) +{ + fprintf(stderr, "usage: mdo [-u username] [-i] [--] [command [args]]\n"); + exit(EXIT_FAILURE); +} + +int +main(int argc, char **argv) +{ + struct passwd *pw; + const char *username = "root"; + bool uidonly = false; + int ch; + + while ((ch = getopt(argc, argv, "u:i")) != -1) { + switch (ch) { + case 'u': + username = optarg; + break; + case 'i': + uidonly = true; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if ((pw = getpwnam(username)) == NULL) { + if (strspn(username, "0123456789") == strlen(username)) { + const char *errp = NULL; + uid_t uid = strtonum(username, 0, UID_MAX, &errp); + if (errp != NULL) + err(EXIT_FAILURE, "%s", errp); + pw = getpwuid(uid); + } + if (pw == NULL) + err(EXIT_FAILURE, "invalid username '%s'", username); + } + if (!uidonly) { + if (initgroups(pw->pw_name, pw->pw_gid) == -1) + err(EXIT_FAILURE, "failed to call initgroups"); + if (setgid(pw->pw_gid) == -1) + err(EXIT_FAILURE, "failed to call setgid"); + } + if (setuid(pw->pw_uid) == -1) + err(EXIT_FAILURE, "failed to call setuid"); + if (*argv == NULL) { + const char *sh = getenv("SHELL"); + if (sh == NULL) + sh = _PATH_BSHELL; + execlp(sh, sh, "-i", NULL); + } else { + execvp(argv[0], argv); + } + err(EXIT_FAILURE, "exec failed"); +} |
