Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/libbb/appletlib.c
- Timestamp:
- Jan 1, 2014, 12:47:38 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.2/mindi-busybox/libbb/appletlib.c
r2725 r3232 28 28 */ 29 29 #include "busybox.h" 30 #include <assert.h> 31 #include <malloc.h> 32 /* Try to pull in PAGE_SIZE */ 33 #ifdef __linux__ 34 # include <sys/user.h> 35 #endif 36 #ifdef __GNU__ /* Hurd */ 37 # include <mach/vm_param.h> 30 31 #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ 32 || defined(__APPLE__) \ 33 ) 34 # include <malloc.h> /* for mallopt */ 38 35 #endif 39 36 … … 43 40 #include "applets.h" 44 41 #undef PROTOTYPES 45 46 42 47 43 /* Include generated applet names, pointers to <applet>_main, etc */ … … 55 51 #endif 56 52 57 58 53 #include "usage_compressed.h" 54 59 55 60 56 #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE … … 67 63 68 64 static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 69 # include " archive.h"65 # include "bb_archive.h" 70 66 static const char *unpack_usage_messages(void) 71 67 { … … 145 141 146 142 #if NUM_APPLETS > 8 147 /* NB: any char pointer will work as well, not necessarily applet_names */ 148 static int applet_name_compare(const void *name, const void *v) 149 { 150 int i = (const char *)v - applet_names; 143 static int applet_name_compare(const void *name, const void *idx) 144 { 145 int i = (int)(ptrdiff_t)idx - 1; 151 146 return strcmp(name, APPLET_NAME(i)); 152 147 } … … 157 152 /* Do a binary search to find the applet entry given the name. */ 158 153 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; 154 p = bsearch(name, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare); 155 /* 156 * if (!p) return -1; 157 * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :) 158 */ 159 return (int)(ptrdiff_t)p - 1; 163 160 #else 164 161 /* A version which does not pull in bsearch */ … … 228 225 IF_FEATURE_SUID(static uid_t ruid;) /* real uid */ 229 226 230 #if ENABLE_FEATURE_SUID_CONFIG 231 232 /* applets[] is const, so we have to define this "override" structure */ 233 static struct BB_suid_config { 227 # if ENABLE_FEATURE_SUID_CONFIG 228 229 static struct suid_config_t { 230 /* next ptr must be first: this struct needs to be llist-compatible */ 231 struct suid_config_t *m_next; 232 struct bb_uidgid_t m_ugid; 234 233 int m_applet; 235 uid_t m_uid;236 gid_t m_gid;237 234 mode_t m_mode; 238 struct BB_suid_config *m_next;239 235 } *suid_config; 240 236 … … 245 241 { 246 242 struct group *grp = getgrgid(g); 247 248 243 if (grp) { 249 244 char **mem; 250 251 245 for (mem = grp->gr_mem; *mem; mem++) { 252 246 struct passwd *pwd = getpwnam(*mem); 253 254 247 if (pwd && (pwd->pw_uid == u)) 255 248 return 1; … … 259 252 } 260 253 261 /* This should probably be a libbb routine. In that case, 262 * I'd probably rename it to something like bb_trimmed_slice. 263 */ 254 /* libbb candidate */ 264 255 static char *get_trimmed_slice(char *s, char *e) 265 256 { … … 279 270 } 280 271 281 /* Don't depend on the tools to combine strings. */282 static const char config_file[] ALIGN1 = "/etc/busybox.conf";283 284 /* We don't supply a value for the nul, so an index adjustment is285 * necessary below. Also, we use unsigned short here to save some286 * space even though these are really mode_t values. */287 static const unsigned short mode_mask[] ALIGN2 = {288 /* SST sst xxx --- */289 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */290 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */291 0, S_IXOTH, S_IXOTH, 0 /* other */292 };293 294 #define parse_error(x) do { errmsg = x; goto pe_label; } while (0)295 296 272 static void parse_config_file(void) 297 273 { 298 struct BB_suid_config *sct_head; 299 struct BB_suid_config *sct; 274 /* Don't depend on the tools to combine strings. */ 275 static const char config_file[] ALIGN1 = "/etc/busybox.conf"; 276 277 struct suid_config_t *sct_head; 300 278 int applet_no; 301 279 FILE *f; 302 280 const char *errmsg; 303 char *s;304 char *e;305 int i;306 281 unsigned lc; 307 282 smallint section; 308 char buffer[256];309 283 struct stat st; 310 311 assert(!suid_config); /* Should be set to NULL by bss init. */312 284 313 285 ruid = getuid(); … … 319 291 || (st.st_uid != 0) /* Not owned by root? */ 320 292 || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */ 321 || !(f = fopen_for_read(config_file)) 293 || !(f = fopen_for_read(config_file)) /* Cannot open? */ 322 294 ) { 323 295 return; … … 329 301 330 302 while (1) { 331 s = buffer; 332 333 if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */ 334 // why? 335 if (ferror(f)) { /* Make sure it wasn't a read error. */ 336 parse_error("reading"); 337 } 303 char buffer[256]; 304 char *s; 305 306 if (!fgets(buffer, sizeof(buffer), f)) { /* Are we done? */ 307 // Looks like bloat 308 //if (ferror(f)) { /* Make sure it wasn't a read error. */ 309 // errmsg = "reading"; 310 // goto pe_label; 311 //} 338 312 fclose(f); 339 313 suid_config = sct_head; /* Success, so set the pointer. */ … … 341 315 } 342 316 317 s = buffer; 343 318 lc++; /* Got a (partial) line. */ 344 319 … … 352 327 * too long if it did end with a newline. */ 353 328 if (!strchr(s, '\n') && !feof(f)) { 354 parse_error("line too long"); 329 errmsg = "line too long"; 330 goto pe_label; 355 331 } 356 332 … … 368 344 * whitespace for the section name. We also require that 369 345 * there are no stray characters after the closing bracket. */ 370 e = strchr(s, ']');346 char *e = strchr(s, ']'); 371 347 if (!e /* Missing right bracket? */ 372 348 || e[1] /* Trailing characters? */ 373 349 || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */ 374 350 ) { 375 parse_error("section header"); 351 errmsg = "section header"; 352 goto pe_label; 376 353 } 377 354 /* Right now we only have one section so just check it. … … 398 375 399 376 /* First get the key (an applet name in our case). */ 400 e = strchr(s, '=');377 char *e = strchr(s, '='); 401 378 if (e) { 402 379 s = get_trimmed_slice(s, e); 403 380 } 404 381 if (!e || !*s) { /* Missing '=' or empty key. */ 405 parse_error("keyword"); 382 errmsg = "keyword"; 383 goto pe_label; 406 384 } 407 385 … … 412 390 applet_no = find_applet_by_name(s); 413 391 if (applet_no >= 0) { 392 unsigned i; 393 struct suid_config_t *sct; 394 414 395 /* Note: We currently don't check for duplicates! 415 396 * The last config line for each applet will be the 416 397 * one used since we insert at the head of the list. 417 398 * I suppose this could be considered a feature. */ 418 sct = x malloc(sizeof(struct BB_suid_config));399 sct = xzalloc(sizeof(*sct)); 419 400 sct->m_applet = applet_no; 420 sct->m_mode = 0;401 /*sct->m_mode = 0;*/ 421 402 sct->m_next = sct_head; 422 403 sct_head = sct; … … 427 408 428 409 for (i = 0; i < 3; i++) { 429 /* There are 4 chars + 1 nul for each of user/group/other. */ 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"); 410 /* There are 4 chars for each of user/group/other. 411 * "x-xx" instead of "x-" are to make 412 * "idx > 3" check catch invalid chars. 413 */ 414 static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx"; 415 static const unsigned short mode_mask[] ALIGN2 = { 416 S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* Ssx- */ 417 S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* Ssx- */ 418 S_IXOTH, 0 /* x- */ 419 }; 420 const char *q = strchrnul(mode_chars + 4*i, *e); 421 unsigned idx = q - (mode_chars + 4*i); 422 if (idx > 3) { 423 errmsg = "mode"; 424 goto pe_label; 436 425 } 437 /* Adjust by -i to account for nul. */438 sct->m_mode |= mode_mask[(q - mode_chars) - i];426 sct->m_mode |= mode_mask[q - mode_chars]; 427 e++; 439 428 } 440 429 441 /* Now get the theuser/group info. */430 /* Now get the user/group info. */ 442 431 443 432 s = skip_whitespace(e); 444 445 /* Note: we require whitespace between the mode and the 446 * user/group info. */ 447 if ((s == e) || !(e = strchr(s, '.'))) { 448 parse_error("<uid>.<gid>"); 449 } 450 *e++ = '\0'; 451 452 /* We can't use get_ug_id here since it would exit() 453 * if a uid or gid was not found. Oh well... */ 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"); 433 /* Default is 0.0, else parse USER.GROUP: */ 434 if (*s) { 435 /* We require whitespace between mode and USER.GROUP */ 436 if ((s == e) || !(e = strchr(s, '.'))) { 437 errmsg = "uid.gid"; 438 goto pe_label; 459 439 } 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"); 440 *e = ':'; /* get_uidgid needs USER:GROUP syntax */ 441 if (get_uidgid(&sct->m_ugid, s, /*allow_numeric:*/ 1) == 0) { 442 errmsg = "unknown user/group"; 443 goto pe_label; 469 444 } 470 sct->m_gid = grp->gr_gid;471 445 } 472 446 } … … 482 456 * are used in some future version of busybox. */ 483 457 if (!section) { 484 parse_error("keyword outside section"); 458 errmsg = "keyword outside section"; 459 goto pe_label; 485 460 } 486 461 … … 488 463 489 464 pe_label: 490 fprintf(stderr, "Parse error in %s, line %d: %s\n",491 config_file, lc, errmsg);492 493 465 fclose(f); 466 bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg); 467 494 468 /* Release any allocated memory before returning. */ 495 while (sct_head) { 496 sct = sct_head->m_next; 497 free(sct_head); 498 sct_head = sct; 499 } 500 } 501 #else 469 llist_free((llist_t*)sct_head, NULL); 470 } 471 # else 502 472 static inline void parse_config_file(void) 503 473 { 504 474 IF_FEATURE_SUID(ruid = getuid();) 505 475 } 506 # endif /* FEATURE_SUID_CONFIG */507 508 509 # if ENABLE_FEATURE_SUID476 # endif /* FEATURE_SUID_CONFIG */ 477 478 479 # if ENABLE_FEATURE_SUID 510 480 static void check_suid(int applet_no) 511 481 { … … 516 486 rgid = getgid(); 517 487 518 # if ENABLE_FEATURE_SUID_CONFIG488 # if ENABLE_FEATURE_SUID_CONFIG 519 489 if (suid_cfg_readable) { 520 490 uid_t uid; 521 struct BB_suid_config*sct;491 struct suid_config_t *sct; 522 492 mode_t m; 523 493 … … 528 498 goto check_need_suid; 529 499 found: 500 /* Is this user allowed to run this applet? */ 530 501 m = sct->m_mode; 531 if (sct->m_u id == ruid)502 if (sct->m_ugid.uid == ruid) 532 503 /* same uid */ 533 504 m >>= 6; 534 else if ((sct->m_ gid == rgid) || ingroup(ruid, sct->m_gid))505 else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.gid)) 535 506 /* same group / in group */ 536 507 m >>= 3; 537 538 if (!(m & S_IXOTH)) /* is x bit not set ? */ 539 bb_error_msg_and_die("you have no permission to run this applet!"); 540 541 /* _both_ sgid and group_exec have to be set for setegid */ 542 if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 543 rgid = sct->m_gid; 544 /* else (no setegid) we will set egid = rgid */ 508 if (!(m & S_IXOTH)) /* is x bit not set? */ 509 bb_error_msg_and_die("you have no permission to run this applet"); 545 510 546 511 /* We set effective AND saved ids. If saved-id is not set 547 * like we do below, seteiud(0) can still later succeed! */ 512 * like we do below, seteuid(0) can still later succeed! */ 513 514 /* Are we directed to change gid 515 * (APPLET = *s* USER.GROUP or APPLET = *S* USER.GROUP)? 516 */ 517 if (sct->m_mode & S_ISGID) 518 rgid = sct->m_ugid.gid; 519 /* else: we will set egid = rgid, thus dropping sgid effect */ 548 520 if (setresgid(-1, rgid, rgid)) 549 521 bb_perror_msg_and_die("setresgid"); 550 522 551 /* do we have to set effective uid? */ 523 /* Are we directed to change uid 524 * (APPLET = s** USER.GROUP or APPLET = S** USER.GROUP)? 525 */ 552 526 uid = ruid; 553 527 if (sct->m_mode & S_ISUID) 554 uid = sct->m_uid; 555 /* else (no seteuid) we will set euid = ruid */ 556 528 uid = sct->m_ugid.uid; 529 /* else: we will set euid = ruid, thus dropping suid effect */ 557 530 if (setresuid(-1, uid, uid)) 558 531 bb_perror_msg_and_die("setresuid"); 559 return; 560 } 561 #if !ENABLE_FEATURE_SUID_CONFIG_QUIET 532 533 goto ret; 534 } 535 # if !ENABLE_FEATURE_SUID_CONFIG_QUIET 562 536 { 563 537 static bool onetime = 0; … … 565 539 if (!onetime) { 566 540 onetime = 1; 567 fprintf(stderr, "Using fallback suid method\n");568 } 569 } 570 # endif541 bb_error_msg("using fallback suid method"); 542 } 543 } 544 # endif 571 545 check_need_suid: 572 # endif573 if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) {546 # endif 547 if (APPLET_SUID(applet_no) == BB_SUID_REQUIRE) { 574 548 /* Real uid is not 0. If euid isn't 0 too, suid bit 575 549 * is most probably not set on our executable */ 576 550 if (geteuid()) 577 551 bb_error_msg_and_die("must be suid to work properly"); 578 } else if (APPLET_SUID(applet_no) == _BB_SUID_DROP) {552 } else if (APPLET_SUID(applet_no) == BB_SUID_DROP) { 579 553 xsetgid(rgid); /* drop all privileges */ 580 554 xsetuid(ruid); 581 555 } 582 } 583 #else 584 #define check_suid(x) ((void)0) 585 #endif /* FEATURE_SUID */ 586 587 588 #if ENABLE_FEATURE_INSTALLER 556 # if ENABLE_FEATURE_SUID_CONFIG 557 ret: ; 558 llist_free((llist_t*)suid_config, NULL); 559 # endif 560 } 561 # else 562 # define check_suid(x) ((void)0) 563 # endif /* FEATURE_SUID */ 564 565 566 # if ENABLE_FEATURE_INSTALLER 589 567 static const char usr_bin [] ALIGN1 = "/usr/bin/"; 590 568 static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; … … 593 571 &usr_bin [4], /* "/bin/" */ 594 572 &usr_sbin[4] /* "/sbin/" */ 595 # if !ENABLE_INSTALL_NO_USR573 # if !ENABLE_INSTALL_NO_USR 596 574 ,usr_bin 597 575 ,usr_sbin 598 # endif576 # endif 599 577 }; 600 601 578 602 579 /* create (sym)links for each applet */ … … 629 606 } 630 607 } 631 # else632 # define install_links(x,y,z) ((void)0)633 # endif608 # else 609 # define install_links(x,y,z) ((void)0) 610 # endif 634 611 635 612 /* If we were called as "busybox..." */ … … 652 629 full_write2_str(" multi-call binary.\n"); /* reuse */ 653 630 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"631 "BusyBox is copyrighted by many authors between 1998-2012.\n" 632 "Licensed under GPLv2. See source distribution for detailed\n" 633 "copyright notices.\n" 657 634 "\n" 658 "Usage: busybox [function] [arguments]...\n" 659 " or: busybox --list[-full]\n" 635 "Usage: busybox [function [arguments]...]\n" 636 " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" 637 IF_FEATURE_INSTALLER( 638 " or: busybox --install [-s] [DIR]\n" 639 ) 660 640 " or: function [arguments]...\n" 661 641 "\n" … … 696 676 dup2(1, 2); 697 677 while (*a) { 698 # if ENABLE_FEATURE_INSTALLER699 if (argv[1][6]) /* --list- path? */678 # if ENABLE_FEATURE_INSTALLER 679 if (argv[1][6]) /* --list-full? */ 700 680 full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); 701 # endif681 # endif 702 682 full_write2_str(a); 703 683 full_write2_str("\n"); … … 711 691 int use_symbolic_links; 712 692 const char *busybox; 693 713 694 busybox = xmalloc_readlink(bb_busybox_exec_path); 714 if (!busybox) 715 busybox = bb_busybox_exec_path; 716 /* busybox --install [-s] [DIR]: */ 717 /* -s: make symlinks */ 718 /* DIR: directory to install links to */ 719 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++); 695 if (!busybox) { 696 /* bb_busybox_exec_path is usually "/proc/self/exe". 697 * In chroot, readlink("/proc/self/exe") usually fails. 698 * In such case, better use argv[0] as symlink target 699 * if it is a full path name. 700 */ 701 if (argv[0][0] != '/') 702 bb_error_msg_and_die("'%s' is not an absolute path", argv[0]); 703 busybox = argv[0]; 704 } 705 /* busybox --install [-s] [DIR]: 706 * -s: make symlinks 707 * DIR: directory to install links to 708 */ 709 use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); 720 710 install_links(busybox, use_symbolic_links, argv[2]); 721 711 return 0; … … 759 749 * should be no different from e.g. "test --foo". */ 760 750 //TODO: just compare applet_no with APPLET_NO_test 761 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) 751 if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { 752 /* If you want "foo --help" to return 0: */ 753 /*xfunc_error_retval = 0;*/ 762 754 bb_show_usage(); 755 } 763 756 } 764 757 if (ENABLE_FEATURE_SUID) … … 772 765 if (applet >= 0) 773 766 run_applet_no_and_exit(applet, argv); 774 if ( !strncmp(name, "busybox", 7))767 if (strncmp(name, "busybox", 7) == 0) 775 768 exit(busybox_main(argv)); 776 769 } … … 787 780 { 788 781 /* Tweak malloc for reduced memory consumption */ 789 #ifndef PAGE_SIZE790 # define PAGE_SIZE (4*1024) /* guess */791 #endif792 782 #ifdef M_TRIM_THRESHOLD 793 783 /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory … … 795 785 * Default is way too big: 256k 796 786 */ 797 mallopt(M_TRIM_THRESHOLD, 2 * PAGE_SIZE);787 mallopt(M_TRIM_THRESHOLD, 8 * 1024); 798 788 #endif 799 789 #ifdef M_MMAP_THRESHOLD … … 801 791 * Default is too big: 256k 802 792 */ 803 mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256); 793 mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256); 794 #endif 795 796 #if !BB_MMU 797 /* NOMMU re-exec trick sets high-order bit in first byte of name */ 798 if (argv[0][0] & 0x80) { 799 re_execed = 1; 800 argv[0][0] &= 0x7f; 801 } 804 802 #endif 805 803 806 804 #if defined(SINGLE_APPLET_MAIN) 807 /* Only one applet is selected by the user! */ 805 /* Only one applet is selected in .config */ 806 if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { 807 /* "busybox <applet> <params>" should still work as expected */ 808 argv++; 809 } 808 810 /* applet_names in this case is just "applet\0\0" */ 809 811 lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); … … 812 814 lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); 813 815 814 #if !BB_MMU815 /* NOMMU re-exec trick sets high-order bit in first byte of name */816 if (argv[0][0] & 0x80) {817 re_execed = 1;818 argv[0][0] &= 0x7f;819 }820 #endif821 816 applet_name = argv[0]; 822 817 if (applet_name[0] == '-')
Note:
See TracChangeset
for help on using the changeset viewer.