diff options
Diffstat (limited to 'applets')
-rw-r--r-- | applets/applets.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/applets/applets.c b/applets/applets.c index f3e56a9f3..2ab44059a 100644 --- a/applets/applets.c +++ b/applets/applets.c | |||
@@ -25,6 +25,7 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include <unistd.h> | ||
28 | #include <stdio.h> | 29 | #include <stdio.h> |
29 | #include <stdlib.h> | 30 | #include <stdlib.h> |
30 | #include <string.h> | 31 | #include <string.h> |
@@ -40,6 +41,42 @@ struct BB_applet *applet_using; | |||
40 | /* The -1 arises because of the {0,NULL,0,-1} entry above. */ | 41 | /* The -1 arises because of the {0,NULL,0,-1} entry above. */ |
41 | const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); | 42 | const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); |
42 | 43 | ||
44 | |||
45 | #ifdef CONFIG_FEATURE_SUID | ||
46 | |||
47 | static void check_suid ( struct BB_applet *app ); | ||
48 | |||
49 | #ifdef CONFIG_FEATURE_SUID_CONFIG | ||
50 | |||
51 | #include <sys/stat.h> | ||
52 | #include <ctype.h> | ||
53 | #include "pwd.h" | ||
54 | #include "grp.h" | ||
55 | |||
56 | static void parse_error ( int line, const char *err ); | ||
57 | static void parse_config_file ( void ); | ||
58 | |||
59 | #define CONFIG_FILE "/etc/busybox.conf" | ||
60 | |||
61 | // applets [] is const, so we have to define this "override" structure | ||
62 | struct BB_suid_config { | ||
63 | struct BB_applet *m_applet; | ||
64 | |||
65 | uid_t m_uid; | ||
66 | gid_t m_gid; | ||
67 | mode_t m_mode; | ||
68 | |||
69 | struct BB_suid_config *m_next; | ||
70 | }; | ||
71 | |||
72 | static struct BB_suid_config *suid_config; | ||
73 | |||
74 | #endif // CONFIG_FEATURE_SUID_CONFIG | ||
75 | |||
76 | #endif // CONFIG_FEATURE_SUID | ||
77 | |||
78 | |||
79 | |||
43 | extern void show_usage(void) | 80 | extern void show_usage(void) |
44 | { | 81 | { |
45 | const char *format_string; | 82 | const char *format_string; |
@@ -80,6 +117,11 @@ void run_applet_by_name(const char *name, int argc, char **argv) | |||
80 | static int recurse_level = 0; | 117 | static int recurse_level = 0; |
81 | extern int been_there_done_that; /* From busybox.c */ | 118 | extern int been_there_done_that; /* From busybox.c */ |
82 | 119 | ||
120 | #ifdef CONFIG_FEATURE_SUID_CONFIG | ||
121 | if ( recurse_level == 0 ) | ||
122 | parse_config_file ( ); | ||
123 | #endif | ||
124 | |||
83 | recurse_level++; | 125 | recurse_level++; |
84 | /* Do a binary search to find the applet entry given the name. */ | 126 | /* Do a binary search to find the applet entry given the name. */ |
85 | if ((applet_using = find_applet_by_name(name)) != NULL) { | 127 | if ((applet_using = find_applet_by_name(name)) != NULL) { |
@@ -96,6 +138,10 @@ void run_applet_by_name(const char *name, int argc, char **argv) | |||
96 | been_there_done_that=1; | 138 | been_there_done_that=1; |
97 | busybox_main(0, NULL); | 139 | busybox_main(0, NULL); |
98 | } | 140 | } |
141 | #ifdef CONFIG_FEATURE_SUID | ||
142 | check_suid ( applet_using ); | ||
143 | #endif | ||
144 | |||
99 | exit((*(applet_using->main)) (argc, argv)); | 145 | exit((*(applet_using->main)) (argc, argv)); |
100 | } | 146 | } |
101 | /* Just in case they have renamed busybox - Check argv[1] */ | 147 | /* Just in case they have renamed busybox - Check argv[1] */ |
@@ -106,6 +152,247 @@ void run_applet_by_name(const char *name, int argc, char **argv) | |||
106 | } | 152 | } |
107 | 153 | ||
108 | 154 | ||
155 | #ifdef CONFIG_FEATURE_SUID | ||
156 | |||
157 | #ifdef CONFIG_FEATURE_SUID_CONFIG | ||
158 | |||
159 | // check if u is member of group g | ||
160 | static int ingroup ( uid_t u, gid_t g ) | ||
161 | { | ||
162 | struct group *grp = getgrgid ( g ); | ||
163 | |||
164 | if ( grp ) { | ||
165 | char **mem; | ||
166 | |||
167 | for ( mem = grp-> gr_mem; *mem; mem++ ) { | ||
168 | struct passwd *pwd = getpwnam ( *mem ); | ||
169 | |||
170 | if ( pwd && ( pwd-> pw_uid == u )) | ||
171 | return 1; | ||
172 | } | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | #endif | ||
178 | |||
179 | |||
180 | void check_suid ( struct BB_applet *applet ) | ||
181 | { | ||
182 | uid_t ruid = getuid ( ); // real [ug]id | ||
183 | uid_t rgid = getgid ( ); | ||
184 | |||
185 | #ifdef CONFIG_FEATURE_SUID_CONFIG | ||
186 | struct BB_suid_config *sct; | ||
187 | |||
188 | for ( sct = suid_config; sct; sct = sct-> m_next ) { | ||
189 | if ( sct-> m_applet == applet ) | ||
190 | break; | ||
191 | } | ||
192 | if ( sct ) { | ||
193 | mode_t m = sct-> m_mode; | ||
194 | |||
195 | if ( sct-> m_uid == ruid ) // same uid | ||
196 | m >>= 6; | ||
197 | else if (( sct-> m_gid == rgid ) || ingroup ( ruid, sct-> m_gid )) // same group / in group | ||
198 | m >>= 3; | ||
199 | |||
200 | if (!( m & S_IXOTH )) // is x bit not set ? | ||
201 | error_msg_and_die ( "You have no permission to run this applet!" ); | ||
202 | |||
203 | if (( sct-> m_mode & ( S_ISGID | S_IXGRP )) == ( S_ISGID | S_IXGRP )) { // *both* have to be set for sgid | ||
204 | if ( setegid ( sct-> m_gid )) | ||
205 | error_msg_and_die ( "BusyBox binary has insufficient rights to set proper GID for applet!" ); | ||
206 | } | ||
207 | else | ||
208 | setgid ( rgid ); // no sgid -> drop | ||
209 | |||
210 | if ( sct-> m_mode & S_ISUID ) { | ||
211 | if ( seteuid ( sct-> m_uid )) | ||
212 | error_msg_and_die ( "BusyBox binary has insufficient rights to set proper UID for applet!" ); | ||
213 | } | ||
214 | else | ||
215 | setuid ( ruid ); // no suid -> drop | ||
216 | } | ||
217 | else { // default: drop all priviledges | ||
218 | setgid ( rgid ); | ||
219 | setuid ( ruid ); | ||
220 | } | ||
221 | #else | ||
222 | |||
223 | if ( applet-> need_suid == _BB_SUID_ALWAYS ) { | ||
224 | if ( geteuid ( ) != 0 ) | ||
225 | error_msg_and_die ( "This applet requires root priviledges!" ); | ||
226 | } | ||
227 | else if ( applet-> need_suid == _BB_SUID_NEVER ) { | ||
228 | setgid ( rgid ); // drop all priviledges | ||
229 | setuid ( ruid ); | ||
230 | } | ||
231 | #endif | ||
232 | } | ||
233 | |||
234 | #ifdef CONFIG_FEATURE_SUID_CONFIG | ||
235 | |||
236 | void parse_error ( int line, const char *err ) | ||
237 | { | ||
238 | char msg [512]; | ||
239 | snprintf ( msg, sizeof( msg ) - 1, "Parse error in %s, line %d: %s", CONFIG_FILE, line, err ); | ||
240 | |||
241 | error_msg_and_die ( msg ); | ||
242 | } | ||
243 | |||
244 | |||
245 | void parse_config_file ( void ) | ||
246 | { | ||
247 | struct stat st; | ||
248 | |||
249 | suid_config = 0; | ||
250 | |||
251 | // is there a config file ? | ||
252 | if ( stat ( CONFIG_FILE, &st ) == 0 ) { | ||
253 | // is it owned by root with no write perm. for group and others ? | ||
254 | if ( S_ISREG( st. st_mode ) && ( st. st_uid == 0 ) && (!( st. st_mode & ( S_IWGRP | S_IWOTH )))) { | ||
255 | // that's ok .. then try to open it | ||
256 | FILE *f = fopen ( CONFIG_FILE, "r" ); | ||
257 | |||
258 | if ( f ) { | ||
259 | char buffer [4096]; | ||
260 | int section = 0; | ||
261 | int lc = 0; | ||
262 | |||
263 | while ( fgets ( buffer, sizeof( buffer ) - 1, f )) { | ||
264 | char c = buffer [0]; | ||
265 | char *p; | ||
266 | |||
267 | lc++; | ||
268 | |||
269 | p = strchr ( buffer, '#' ); | ||
270 | if ( p ) | ||
271 | *p = 0; | ||
272 | p = buffer + xstrlen ( buffer ); | ||
273 | while (( p > buffer ) && isspace ( *--p )) | ||
274 | *p = 0; | ||
275 | |||
276 | if ( p == buffer ) | ||
277 | continue; | ||
278 | |||
279 | if ( c == '[' ) { | ||
280 | p = strchr ( buffer, ']' ); | ||
281 | |||
282 | if ( !p || ( p == ( buffer + 1 ))) // no matching ] or empty [] | ||
283 | parse_error ( lc, "malformed section header" ); | ||
284 | |||
285 | *p = 0; | ||
286 | |||
287 | if ( strcasecmp ( buffer + 1, "SUID" ) == 0 ) | ||
288 | section = 1; | ||
289 | else | ||
290 | section = -1; // unknown section - just skip | ||
291 | } | ||
292 | else if ( section ) { | ||
293 | switch ( section ) { | ||
294 | case 1: { // SUID | ||
295 | int l; | ||
296 | struct BB_applet *applet; | ||
297 | |||
298 | p = strchr ( buffer, '=' ); // <key>[::space::]*=[::space::]*<value> | ||
299 | |||
300 | if ( !p || ( p == ( buffer + 1 ))) // no = or key is empty | ||
301 | parse_error ( lc, "malformed keyword" ); | ||
302 | |||
303 | l = p - buffer; | ||
304 | while ( isspace ( buffer [--l] )) { } // skip whitespace | ||
305 | |||
306 | buffer [l+1] = 0; | ||
307 | |||
308 | if (( applet = find_applet_by_name ( buffer ))) { | ||
309 | struct BB_suid_config *sct = xmalloc ( sizeof( struct BB_suid_config )); | ||
310 | |||
311 | sct-> m_applet = applet; | ||
312 | sct-> m_next = suid_config; | ||
313 | suid_config = sct; | ||
314 | |||
315 | while ( isspace ( *++p )) { } // skip whitespace | ||
316 | |||
317 | sct-> m_mode = 0; | ||
318 | |||
319 | switch ( *p++ ) { | ||
320 | case 'S': sct-> m_mode |= S_ISUID; break; | ||
321 | case 's': sct-> m_mode |= S_ISUID; // no break | ||
322 | case 'x': sct-> m_mode |= S_IXUSR; break; | ||
323 | case '-': break; | ||
324 | default : parse_error ( lc, "invalid user mode" ); | ||
325 | } | ||
326 | |||
327 | switch ( *p++ ) { | ||
328 | case 's': sct-> m_mode |= S_ISGID; // no break | ||
329 | case 'x': sct-> m_mode |= S_IXGRP; break; | ||
330 | case 'S': break; | ||
331 | case '-': break; | ||
332 | default : parse_error ( lc, "invalid group mode" ); | ||
333 | } | ||
334 | |||
335 | switch ( *p ) { | ||
336 | case 't': | ||
337 | case 'x': sct-> m_mode |= S_IXOTH; break; | ||
338 | case 'T': | ||
339 | case '-': break; | ||
340 | default : parse_error ( lc, "invalid other mode" ); | ||
341 | } | ||
342 | |||
343 | while ( isspace ( *++p )) { } // skip whitespace | ||
344 | |||
345 | if ( isdigit ( *p )) { | ||
346 | sct-> m_uid = strtol ( p, &p, 10 ); | ||
347 | if ( *p++ != '.' ) | ||
348 | parse_error ( lc, "parsing <uid>.<gid>" ); | ||
349 | } | ||
350 | else { | ||
351 | struct passwd *pwd; | ||
352 | char *p2 = strchr ( p, '.' ); | ||
353 | |||
354 | if ( !p2 ) | ||
355 | parse_error ( lc, "parsing <uid>.<gid>" ); | ||
356 | |||
357 | *p2 = 0; | ||
358 | pwd = getpwnam ( p ); | ||
359 | |||
360 | if ( !pwd ) | ||
361 | parse_error ( lc, "invalid user name" ); | ||
362 | |||
363 | sct-> m_uid = pwd-> pw_uid; | ||
364 | p = p2 + 1; | ||
365 | } | ||
366 | if ( isdigit ( *p )) | ||
367 | sct-> m_gid = strtol ( p, &p, 10 ); | ||
368 | else { | ||
369 | struct group *grp = getgrnam ( p ); | ||
370 | |||
371 | if ( !grp ) | ||
372 | parse_error ( lc, "invalid group name" ); | ||
373 | |||
374 | sct-> m_gid = grp-> gr_gid; | ||
375 | } | ||
376 | } | ||
377 | break; | ||
378 | } | ||
379 | default: // unknown - skip | ||
380 | break; | ||
381 | } | ||
382 | } | ||
383 | else | ||
384 | parse_error ( lc, "keyword not within section" ); | ||
385 | } | ||
386 | fclose ( f ); | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | |||
392 | #endif | ||
393 | |||
394 | #endif | ||
395 | |||
109 | /* END CODE */ | 396 | /* END CODE */ |
110 | /* | 397 | /* |
111 | Local Variables: | 398 | Local Variables: |