aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2023-03-19 10:25:23 +0000
committerRon Yorston <rmy@pobox.com>2023-03-19 10:25:23 +0000
commitb0e7a401d51402c052563f55331c8b9001a1215c (patch)
treedaad4a5fd2ab07a4cc85b837416cd80cc0d7a1e7 /util-linux
parent6de29a7e5346bea9c1c2ad4faf4010ee78f1a97b (diff)
downloadbusybox-w32-b0e7a401d51402c052563f55331c8b9001a1215c.tar.gz
busybox-w32-b0e7a401d51402c052563f55331c8b9001a1215c.tar.bz2
busybox-w32-b0e7a401d51402c052563f55331c8b9001a1215c.zip
runuser,drop: drop runuser, tweak drop
Remove the runuser applet, leaving only drop. Move drop from util-linux to miscutils. A command of the form 'drop -c command' causes the BusyBox shell to be used, just like 'drop' without any arguments. A simple OpenSSH configuration with 'drop.exe' as DefaultShell and no DefaultShellArguments now works both for interactive login and to run a command. This is useful for older versions of OpenSSH which don't support DefaultShellArguments. Saves 208-232 bytes.
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/runuser.c164
1 files changed, 0 insertions, 164 deletions
diff --git a/util-linux/runuser.c b/util-linux/runuser.c
deleted file mode 100644
index 993a4ed68..000000000
--- a/util-linux/runuser.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * runuser - run a shell without elevated privileges.
4 * This is a much restricted, Windows-specific reimplementation of
5 * runuser from util-linux.
6 *
7 * Copyright (c) 2023 Ronald M Yorston
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
10 */
11//config:config RUNUSER
12//config: bool "runuser"
13//config: default y
14//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
15//config: help
16//config: Run a shell without elevated privileges
17//config:
18//config:config DROP
19//config: bool "drop"
20//config: default y
21//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
22//config: help
23//config: Run a command without elevated privileges
24
25//applet:IF_RUNUSER(APPLET(runuser, BB_DIR_USR_BIN, BB_SUID_DROP))
26//applet:IF_DROP(APPLET_ODDNAME(drop, runuser, BB_DIR_USR_BIN, BB_SUID_DROP, drop))
27
28//kbuild:lib-$(CONFIG_RUNUSER) += runuser.o
29//kbuild:lib-$(CONFIG_DROP) += runuser.o
30
31//usage:#define runuser_trivial_usage
32//usage: "USER [ARG...]"
33//usage:#define runuser_full_usage "\n\n"
34//usage: "Run a shell without elevated privileges. The user name\n"
35//usage: "must be that of the user who was granted those privileges.\n"
36//usage: "Any arguments are passed to the shell.\n"
37
38//usage:#define drop_trivial_usage
39//usage: "[COMMAND [ARG...]]"
40//usage:#define drop_full_usage "\n\n"
41//usage: "Run a command without elevated privileges. Run the BusyBox\n"
42//usage: "shell if no COMMAND is provided. Any arguments are passed\n"
43//usage: "to the command.\n"
44
45#include "libbb.h"
46#include <winsafer.h>
47#include <lazyload.h>
48
49int runuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
50int runuser_main(int argc, char **argv)
51{
52#if ENABLE_RUNUSER && ENABLE_DROP
53 int is_runuser = strcmp(applet_name, "runuser") == 0;
54#else
55 const int is_runuser = ENABLE_RUNUSER;
56#endif
57 const char *user, *exe;
58 SAFER_LEVEL_HANDLE safer;
59 HANDLE token;
60 STARTUPINFO si;
61 PROCESS_INFORMATION pi;
62 TOKEN_MANDATORY_LABEL TIL;
63 // Medium integrity level S-1-16-8192
64 unsigned char medium[12] = {
65 0x01, 0x01, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x10,
67 0x00, 0x20, 0x00, 0x00
68 };
69 char *cmd, *q, *newcmd, **a;
70 DWORD code;
71 // This shouldn't be necessary but without it the binary complains
72 // it can't find CreateProcessAsUserA on older versions of Windows.
73 DECLARE_PROC_ADDR(BOOL, CreateProcessAsUserA, HANDLE, LPCSTR, LPSTR,
74 LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD,
75 LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
76
77 if (!INIT_PROC_ADDR(advapi32.dll, CreateProcessAsUserA))
78 bb_simple_error_msg_and_die("not supported");
79
80 if (is_runuser) {
81 if (getuid() != 0)
82 bb_simple_error_msg_and_die("may not be used by non-root users");
83
84 if (argc < 2)
85 bb_show_usage();
86
87 user = get_user_name();
88 if (user == NULL || strcmp(argv[1], user) != 0)
89 bb_simple_error_msg_and_die("invalid user");
90 }
91
92 /*
93 * Run a shell using a token with reduced privilege. Hints from:
94 *
95 * https://stackoverflow.com/questions/17765568/
96 */
97 if (SaferCreateLevel(SAFER_SCOPEID_USER, SAFER_LEVELID_NORMALUSER,
98 SAFER_LEVEL_OPEN, &safer, NULL) &&
99 SaferComputeTokenFromLevel(safer, NULL, &token, 0, NULL)) {
100
101 // Set medium integrity
102 TIL.Label.Sid = (PSID)medium;
103 TIL.Label.Attributes = SE_GROUP_INTEGRITY;
104 if (SetTokenInformation(token, TokenIntegrityLevel, &TIL,
105 sizeof(TOKEN_MANDATORY_LABEL))) {
106
107 if (is_runuser || argc == 1) {
108 exe = bb_busybox_exec_path;
109 cmd = xstrdup("sh");
110 } else {
111 char *file;
112
113#if ENABLE_FEATURE_PREFER_APPLETS
114 if (!has_path(argv[1]) && find_applet_by_name(argv[1]) >= 0) {
115 file = xstrdup(bb_busybox_exec_path);
116 } else
117#endif
118 if (has_path(argv[1])) {
119 file = file_is_win32_exe(argv[1]);
120 } else {
121 file = find_first_executable(argv[1]);
122 }
123
124 if (file == NULL) {
125 xfunc_error_retval = 127;
126 bb_error_msg_and_die("can't find '%s'", argv[1]);
127 }
128
129 slash_to_bs(file);
130 exe = file;
131 cmd = quote_arg(argv[1]);
132 }
133
134 // Build the command line
135 for (a = argv + 1 + (argc != 1); *a; ++a) {
136 q = quote_arg(*a);
137 newcmd = xasprintf("%s %s", cmd, q);
138 free(q);
139 free(cmd);
140 cmd = newcmd;
141 }
142
143 ZeroMemory(&si, sizeof(STARTUPINFO));
144 si.cb = sizeof(STARTUPINFO);
145 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
146 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
147 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
148 si.dwFlags = STARTF_USESTDHANDLES;
149
150 if (!CreateProcessAsUserA(token, exe, cmd, NULL, NULL, TRUE,
151 0, NULL, NULL, &si, &pi)) {
152 xfunc_error_retval = 126;
153 bb_error_msg_and_die("can't execute '%s'", exe);
154 }
155
156 WaitForSingleObject(pi.hProcess, INFINITE);
157 if (GetExitCodeProcess(pi.hProcess, &code)) {
158 return (int)code;
159 }
160 }
161 }
162
163 return EXIT_FAILURE;
164}