aboutsummaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/Makefile1
-rw-r--r--usr.bin/mdo/Makefile4
-rw-r--r--usr.bin/mdo/mdo.144
-rw-r--r--usr.bin/mdo/mdo.c76
4 files changed, 125 insertions, 0 deletions
diff --git a/usr.bin/Makefile b/usr.bin/Makefile
index 0a584a18d14a..a9d5c1563797 100644
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -87,6 +87,7 @@ SUBDIR= alias \
lzmainfo \
m4 \
mandoc \
+ mdo \
mesg \
ministat \
mkdep \
diff --git a/usr.bin/mdo/Makefile b/usr.bin/mdo/Makefile
new file mode 100644
index 000000000000..e20f2719fc82
--- /dev/null
+++ b/usr.bin/mdo/Makefile
@@ -0,0 +1,4 @@
+PROG= mdo
+SRCS= mdo.c
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/mdo/mdo.1 b/usr.bin/mdo/mdo.1
new file mode 100644
index 000000000000..115ce44f4531
--- /dev/null
+++ b/usr.bin/mdo/mdo.1
@@ -0,0 +1,44 @@
+.\"-
+.\" Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd May 22, 2024
+.Dt MDO 1
+.Os
+.Sh NAME
+.Nm mdo
+.Nd execute commands as another user
+.Sh SYNOPSIS
+.Nm
+.Op Fl u Ar username
+.Op Fl i
+.Op command Op args
+.Sh DESCRIPTION
+The
+.Nm
+utility executes the specified
+.Ar command
+as user
+.Ar username .
+.Pp
+If no
+.Ar username
+is provided it defaults to the
+.Va root
+user.
+If no
+.Ar command
+is specified, it will execute the shell specified as
+.Va SHELL
+environnement variable, falling back on
+.Pa /bin/sh .
+.Pp
+The
+.Fl i
+option can be used to only call
+.Fn setuid
+and keep the group from the calling user.
+.Sh SEE ALSO
+.Xr su 1
+.Xr mac_do 4
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");
+}