1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include "busybox.h"
30
31#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
32 || defined(__APPLE__) \
33 )
34# include <malloc.h>
35#endif
36
37
38
39#define PROTOTYPES
40#include "applets.h"
41#undef PROTOTYPES
42
43
44#include "applet_tables.h"
45
46#ifdef SINGLE_APPLET_MAIN
47# undef ENABLE_FEATURE_INDIVIDUAL
48# define ENABLE_FEATURE_INDIVIDUAL 1
49# undef IF_FEATURE_INDIVIDUAL
50# define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
51#endif
52
53#include "usage_compressed.h"
54
55
56#if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE
57static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
58#else
59# define usage_messages 0
60#endif
61
62#if ENABLE_FEATURE_COMPRESS_USAGE
63
64static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
65# include "archive.h"
66static const char *unpack_usage_messages(void)
67{
68 char *outbuf = NULL;
69 bunzip_data *bd;
70 int i;
71
72 i = start_bunzip(&bd,
73 -1,
74 packed_usage,
75 sizeof(packed_usage));
76
77
78 if (!i) {
79
80 outbuf = malloc_or_warn(sizeof(UNPACKED_USAGE));
81 if (outbuf)
82 read_bunzip(bd, outbuf, sizeof(UNPACKED_USAGE));
83 }
84 dealloc_bunzip(bd);
85 return outbuf;
86}
87# define dealloc_usage_messages(s) free(s)
88
89#else
90
91# define unpack_usage_messages() usage_messages
92# define dealloc_usage_messages(s) ((void)(s))
93
94#endif
95
96
97void FAST_FUNC bb_show_usage(void)
98{
99 if (ENABLE_SHOW_USAGE) {
100#ifdef SINGLE_APPLET_STR
101
102 const char *usage_string = unpack_usage_messages();
103
104 if (*usage_string == '\b') {
105 full_write2_str("No help available.\n\n");
106 } else {
107 full_write2_str("Usage: "SINGLE_APPLET_STR" ");
108 full_write2_str(usage_string);
109 full_write2_str("\n\n");
110 }
111 if (ENABLE_FEATURE_CLEAN_UP)
112 dealloc_usage_messages((char*)usage_string);
113#else
114 const char *p;
115 const char *usage_string = p = unpack_usage_messages();
116 int ap = find_applet_by_name(applet_name);
117
118 if (ap < 0)
119 xfunc_die();
120 while (ap) {
121 while (*p++) continue;
122 ap--;
123 }
124 full_write2_str(bb_banner);
125 full_write2_str(" multi-call binary.\n");
126 if (*p == '\b')
127 full_write2_str("\nNo help available.\n\n");
128 else {
129 full_write2_str("\nUsage: ");
130 full_write2_str(applet_name);
131 full_write2_str(" ");
132 full_write2_str(p);
133 full_write2_str("\n\n");
134 }
135 if (ENABLE_FEATURE_CLEAN_UP)
136 dealloc_usage_messages((char*)usage_string);
137#endif
138 }
139 xfunc_die();
140}
141
142#if NUM_APPLETS > 8
143
144static int applet_name_compare(const void *name, const void *v)
145{
146 int i = (const char *)v - applet_names;
147 return strcmp(name, APPLET_NAME(i));
148}
149#endif
150int FAST_FUNC find_applet_by_name(const char *name)
151{
152#if NUM_APPLETS > 8
153
154 const char *p;
155 p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare);
156 if (!p)
157 return -1;
158 return p - applet_names;
159#else
160
161 int i = 0;
162 const char *p = applet_names;
163 while (i < NUM_APPLETS) {
164 if (strcmp(name, p) == 0)
165 return i;
166 p += strlen(p) + 1;
167 i++;
168 }
169 return -1;
170#endif
171}
172
173
174void lbb_prepare(const char *applet
175 IF_FEATURE_INDIVIDUAL(, char **argv))
176 MAIN_EXTERNALLY_VISIBLE;
177void lbb_prepare(const char *applet
178 IF_FEATURE_INDIVIDUAL(, char **argv))
179{
180#ifdef __GLIBC__
181 (*(int **)&bb_errno) = __errno_location();
182 barrier();
183#endif
184 applet_name = applet;
185
186
187 if (ENABLE_LOCALE_SUPPORT && getpid() != 1)
188 setlocale(LC_ALL, "");
189
190#if ENABLE_FEATURE_INDIVIDUAL
191
192
193 if (argv[1]
194 && !argv[2]
195 && strcmp(argv[1], "--help") == 0
196 && strncmp(applet, "busybox", 7) != 0
197 ) {
198
199
200 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
201 bb_show_usage();
202 }
203#endif
204}
205
206
207
208
209
210
211
212
213
214
215const char *applet_name;
216#if !BB_MMU
217bool re_execed;
218#endif
219
220
221
222#if !defined(SINGLE_APPLET_MAIN)
223
224IF_FEATURE_SUID(static uid_t ruid;)
225
226# if ENABLE_FEATURE_SUID_CONFIG
227
228static struct suid_config_t {
229
230 struct suid_config_t *m_next;
231 struct bb_uidgid_t m_ugid;
232 int m_applet;
233 mode_t m_mode;
234} *suid_config;
235
236static bool suid_cfg_readable;
237
238
239static int ingroup(uid_t u, gid_t g)
240{
241 struct group *grp = getgrgid(g);
242 if (grp) {
243 char **mem;
244 for (mem = grp->gr_mem; *mem; mem++) {
245 struct passwd *pwd = getpwnam(*mem);
246 if (pwd && (pwd->pw_uid == u))
247 return 1;
248 }
249 }
250 return 0;
251}
252
253
254static char *get_trimmed_slice(char *s, char *e)
255{
256
257
258
259 while (e-- > s) {
260 if (!isspace(*e)) {
261 break;
262 }
263 }
264 e[1] = '\0';
265
266
267
268 return skip_whitespace(s);
269}
270
271static void parse_config_file(void)
272{
273
274 static const char config_file[] ALIGN1 = "/etc/busybox.conf";
275
276 struct suid_config_t *sct_head;
277 int applet_no;
278 FILE *f;
279 const char *errmsg;
280 unsigned lc;
281 smallint section;
282 struct stat st;
283
284 ruid = getuid();
285 if (ruid == 0)
286 return;
287
288 if ((stat(config_file, &st) != 0)
289 || !S_ISREG(st.st_mode)
290 || (st.st_uid != 0)
291 || (st.st_mode & (S_IWGRP | S_IWOTH))
292 || !(f = fopen_for_read(config_file))
293 ) {
294 return;
295 }
296
297 suid_cfg_readable = 1;
298 sct_head = NULL;
299 section = lc = 0;
300
301 while (1) {
302 char buffer[256];
303 char *s;
304
305 if (!fgets(buffer, sizeof(buffer), f)) {
306
307
308
309
310
311 fclose(f);
312 suid_config = sct_head;
313 return;
314 }
315
316 s = buffer;
317 lc++;
318
319
320
321
322
323
324
325
326
327 if (!strchr(s, '\n') && !feof(f)) {
328 errmsg = "line too long";
329 goto pe_label;
330 }
331
332
333
334 s = get_trimmed_slice(s, strchrnul(s, '#'));
335 if (!*s) {
336 continue;
337 }
338
339
340
341 if (*s == '[') {
342
343
344
345 char *e = strchr(s, ']');
346 if (!e
347 || e[1]
348 || !*(s = get_trimmed_slice(s+1, e))
349 ) {
350 errmsg = "section header";
351 goto pe_label;
352 }
353
354
355
356
357
358
359 if (strcasecmp(s, "SUID") == 0) {
360 section = 1;
361 continue;
362 }
363 section = -1;
364 continue;
365 }
366
367
368
369 if (section == 1) {
370
371
372
373
374
375
376 char *e = strchr(s, '=');
377 if (e) {
378 s = get_trimmed_slice(s, e);
379 }
380 if (!e || !*s) {
381 errmsg = "keyword";
382 goto pe_label;
383 }
384
385
386
387
388
389 applet_no = find_applet_by_name(s);
390 if (applet_no >= 0) {
391 unsigned i;
392 struct suid_config_t *sct;
393
394
395
396
397
398 sct = xzalloc(sizeof(*sct));
399 sct->m_applet = applet_no;
400
401 sct->m_next = sct_head;
402 sct_head = sct;
403
404
405
406 e = skip_whitespace(e+1);
407
408 for (i = 0; i < 3; i++) {
409
410
411
412
413 static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx";
414 static const unsigned short mode_mask[] ALIGN2 = {
415 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0,
416 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0,
417 S_IXOTH, 0
418 };
419 const char *q = strchrnul(mode_chars + 4*i, *e);
420 unsigned idx = q - (mode_chars + 4*i);
421 if (idx > 3) {
422 errmsg = "mode";
423 goto pe_label;
424 }
425 sct->m_mode |= mode_mask[q - mode_chars];
426 e++;
427 }
428
429
430
431 s = skip_whitespace(e);
432
433 if (*s) {
434
435 if ((s == e) || !(e = strchr(s, '.'))) {
436 errmsg = "uid.gid";
437 goto pe_label;
438 }
439 *e = ':';
440 if (get_uidgid(&sct->m_ugid, s, 1) == 0) {
441 errmsg = "unknown user/group";
442 goto pe_label;
443 }
444 }
445 }
446 continue;
447 }
448
449
450
451
452
453
454
455
456 if (!section) {
457 errmsg = "keyword outside section";
458 goto pe_label;
459 }
460
461 }
462
463 pe_label:
464 fclose(f);
465 bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg);
466
467
468 llist_free((llist_t*)sct_head, NULL);
469}
470# else
471static inline void parse_config_file(void)
472{
473 IF_FEATURE_SUID(ruid = getuid();)
474}
475# endif
476
477
478# if ENABLE_FEATURE_SUID
479static void check_suid(int applet_no)
480{
481 gid_t rgid;
482
483 if (ruid == 0)
484 return;
485 rgid = getgid();
486
487# if ENABLE_FEATURE_SUID_CONFIG
488 if (suid_cfg_readable) {
489 uid_t uid;
490 struct suid_config_t *sct;
491 mode_t m;
492
493 for (sct = suid_config; sct; sct = sct->m_next) {
494 if (sct->m_applet == applet_no)
495 goto found;
496 }
497 goto check_need_suid;
498 found:
499
500 m = sct->m_mode;
501 if (sct->m_ugid.uid == ruid)
502
503 m >>= 6;
504 else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.gid))
505
506 m >>= 3;
507 if (!(m & S_IXOTH))
508 bb_error_msg_and_die("you have no permission to run this applet");
509
510
511
512
513
514
515
516 if (sct->m_mode & S_ISGID)
517 rgid = sct->m_ugid.gid;
518
519 if (setresgid(-1, rgid, rgid))
520 bb_perror_msg_and_die("setresgid");
521
522
523
524
525 uid = ruid;
526 if (sct->m_mode & S_ISUID)
527 uid = sct->m_ugid.uid;
528
529 if (setresuid(-1, uid, uid))
530 bb_perror_msg_and_die("setresuid");
531
532 goto ret;
533 }
534# if !ENABLE_FEATURE_SUID_CONFIG_QUIET
535 {
536 static bool onetime = 0;
537
538 if (!onetime) {
539 onetime = 1;
540 bb_error_msg("using fallback suid method");
541 }
542 }
543# endif
544 check_need_suid:
545# endif
546 if (APPLET_SUID(applet_no) == BB_SUID_REQUIRE) {
547
548
549 if (geteuid())
550 bb_error_msg_and_die("must be suid to work properly");
551 } else if (APPLET_SUID(applet_no) == BB_SUID_DROP) {
552 xsetgid(rgid);
553 xsetuid(ruid);
554 }
555# if ENABLE_FEATURE_SUID_CONFIG
556 ret: ;
557 llist_free((llist_t*)suid_config, NULL);
558# endif
559}
560# else
561# define check_suid(x) ((void)0)
562# endif
563
564
565# if ENABLE_FEATURE_INSTALLER
566static const char usr_bin [] ALIGN1 = "/usr/bin/";
567static const char usr_sbin[] ALIGN1 = "/usr/sbin/";
568static const char *const install_dir[] = {
569 &usr_bin [8],
570 &usr_bin [4],
571 &usr_sbin[4]
572# if !ENABLE_INSTALL_NO_USR
573 ,usr_bin
574 ,usr_sbin
575# endif
576};
577
578
579static void install_links(const char *busybox, int use_symbolic_links,
580 char *custom_install_dir)
581{
582
583
584
585 int (*lf)(const char *, const char *);
586 char *fpc;
587 unsigned i;
588 int rc;
589
590 lf = link;
591 if (use_symbolic_links)
592 lf = symlink;
593
594 for (i = 0; i < ARRAY_SIZE(applet_main); i++) {
595 fpc = concat_path_file(
596 custom_install_dir ? custom_install_dir : install_dir[APPLET_INSTALL_LOC(i)],
597 APPLET_NAME(i));
598
599
600 rc = lf(busybox, fpc);
601 if (rc != 0 && errno != EEXIST) {
602 bb_simple_perror_msg(fpc);
603 }
604 free(fpc);
605 }
606}
607# else
608# define install_links(x,y,z) ((void)0)
609# endif
610
611
612static int busybox_main(char **argv)
613{
614 if (!argv[1]) {
615
616 const char *a;
617 int col;
618 unsigned output_width;
619 help:
620 output_width = 80;
621 if (ENABLE_FEATURE_AUTOWIDTH) {
622
623 get_terminal_width_height(0, &output_width, NULL);
624 }
625
626 dup2(1, 2);
627 full_write2_str(bb_banner);
628 full_write2_str(" multi-call binary.\n");
629 full_write2_str(
630 "Copyright (C) 1998-2011 Erik Andersen, Rob Landley, Denys Vlasenko\n"
631 "and others. Licensed under GPLv2.\n"
632 "See source distribution for full notice.\n"
633 "\n"
634 "Usage: busybox [function] [arguments]...\n"
635 " or: busybox --list[-full]\n"
636 " or: function [arguments]...\n"
637 "\n"
638 "\tBusyBox is a multi-call binary that combines many common Unix\n"
639 "\tutilities into a single executable. Most people will create a\n"
640 "\tlink to busybox for each function they wish to use and BusyBox\n"
641 "\twill act like whatever it was invoked as.\n"
642 "\n"
643 "Currently defined functions:\n"
644 );
645 col = 0;
646 a = applet_names;
647
648 output_width--;
649 while (*a) {
650 int len2 = strlen(a) + 2;
651 if (col >= (int)output_width - len2) {
652 full_write2_str(",\n");
653 col = 0;
654 }
655 if (col == 0) {
656 col = 6;
657 full_write2_str("\t");
658 } else {
659 full_write2_str(", ");
660 }
661 full_write2_str(a);
662 col += len2;
663 a += len2 - 1;
664 }
665 full_write2_str("\n\n");
666 return 0;
667 }
668
669 if (strncmp(argv[1], "--list", 6) == 0) {
670 unsigned i = 0;
671 const char *a = applet_names;
672 dup2(1, 2);
673 while (*a) {
674# if ENABLE_FEATURE_INSTALLER
675 if (argv[1][6])
676 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1);
677# endif
678 full_write2_str(a);
679 full_write2_str("\n");
680 i++;
681 a += strlen(a) + 1;
682 }
683 return 0;
684 }
685
686 if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) {
687 int use_symbolic_links;
688 const char *busybox;
689
690 busybox = xmalloc_readlink(bb_busybox_exec_path);
691 if (!busybox) {
692
693
694
695
696
697 if (argv[0][0] != '/')
698 bb_error_msg_and_die("'%s' is not an absolute path", argv[0]);
699 busybox = argv[0];
700 }
701
702
703
704
705 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++);
706 install_links(busybox, use_symbolic_links, argv[2]);
707 return 0;
708 }
709
710 if (strcmp(argv[1], "--help") == 0) {
711
712 if (!argv[2])
713 goto help;
714
715 argv[0] = argv[2];
716 argv[2] = NULL;
717 } else {
718
719 argv++;
720 }
721
722
723 applet_name = bb_get_last_path_component_nostrip(argv[0]);
724 run_applet_and_exit(applet_name, argv);
725
726
727 full_write2_str(applet_name);
728 full_write2_str(": applet not found\n");
729 xfunc_die();
730}
731
732void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv)
733{
734 int argc = 1;
735
736 while (argv[argc])
737 argc++;
738
739
740 xfunc_error_retval = EXIT_FAILURE;
741
742 applet_name = APPLET_NAME(applet_no);
743 if (argc == 2 && strcmp(argv[1], "--help") == 0) {
744
745
746
747 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0)
748 bb_show_usage();
749 }
750 if (ENABLE_FEATURE_SUID)
751 check_suid(applet_no);
752 exit(applet_main[applet_no](argc, argv));
753}
754
755void FAST_FUNC run_applet_and_exit(const char *name, char **argv)
756{
757 int applet = find_applet_by_name(name);
758 if (applet >= 0)
759 run_applet_no_and_exit(applet, argv);
760 if (strncmp(name, "busybox", 7) == 0)
761 exit(busybox_main(argv));
762}
763
764#endif
765
766
767
768#if ENABLE_BUILD_LIBBUSYBOX
769int lbb_main(char **argv)
770#else
771int main(int argc UNUSED_PARAM, char **argv)
772#endif
773{
774
775#ifdef M_TRIM_THRESHOLD
776
777
778
779
780 mallopt(M_TRIM_THRESHOLD, 8 * 1024);
781#endif
782#ifdef M_MMAP_THRESHOLD
783
784
785
786 mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256);
787#endif
788
789#if !BB_MMU
790
791 if (argv[0][0] & 0x80) {
792 re_execed = 1;
793 argv[0][0] &= 0x7f;
794 }
795#endif
796
797#if defined(SINGLE_APPLET_MAIN)
798
799 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) {
800
801 argv++;
802 }
803
804 lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
805 return SINGLE_APPLET_MAIN(argc, argv);
806#else
807 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
808
809 applet_name = argv[0];
810 if (applet_name[0] == '-')
811 applet_name++;
812 applet_name = bb_basename(applet_name);
813
814 parse_config_file();
815
816 run_applet_and_exit(applet_name, argv);
817
818
819 full_write2_str(applet_name);
820 full_write2_str(": applet not found\n");
821 xfunc_die();
822#endif
823}
824