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