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