diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-06-22 00:47:18 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-06-22 00:47:18 +0200 |
| commit | fbb12ddc6a53ad97ff6bcc7ed9b253c09001ad2f (patch) | |
| tree | 94c82f9eac30c86a1ec4f4d06f6c17b72b47cf3e | |
| parent | b6bca7703bbe6aacec0bda964c82fad389a02b69 (diff) | |
| download | busybox-w32-1_14_2.tar.gz busybox-w32-1_14_2.tar.bz2 busybox-w32-1_14_2.zip | |
post 1.14.1 fixes; bump version to 1.14.21_14_2
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | coreutils/readlink.c | 33 | ||||
| -rw-r--r-- | include/libbb.h | 2 | ||||
| -rw-r--r-- | include/usage.h | 7 | ||||
| -rw-r--r-- | libbb/simplify_path.c | 32 | ||||
| -rw-r--r-- | modutils/modprobe-small.c | 2 | ||||
| -rw-r--r-- | modutils/modprobe.c | 39 | ||||
| -rw-r--r-- | modutils/modutils.c | 2 | ||||
| -rw-r--r-- | networking/ftpd.c | 5 | ||||
| -rw-r--r-- | networking/httpd.c | 380 | ||||
| -rw-r--r-- | networking/telnetd.c | 42 | ||||
| -rw-r--r-- | shell/ash.c | 3 |
12 files changed, 321 insertions, 228 deletions
| @@ -1,6 +1,6 @@ | |||
| 1 | VERSION = 1 | 1 | VERSION = 1 |
| 2 | PATCHLEVEL = 14 | 2 | PATCHLEVEL = 14 |
| 3 | SUBLEVEL = 1 | 3 | SUBLEVEL = 2 |
| 4 | EXTRAVERSION = | 4 | EXTRAVERSION = |
| 5 | NAME = Unnamed | 5 | NAME = Unnamed |
| 6 | 6 | ||
diff --git a/coreutils/readlink.c b/coreutils/readlink.c index 721fd8597..bcf352e74 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c | |||
| @@ -6,9 +6,31 @@ | |||
| 6 | * | 6 | * |
| 7 | * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. |
| 8 | */ | 8 | */ |
| 9 | |||
| 10 | #include "libbb.h" | 9 | #include "libbb.h" |
| 11 | 10 | ||
| 11 | /* | ||
| 12 | * # readlink --version | ||
| 13 | * readlink (GNU coreutils) 6.10 | ||
| 14 | * # readlink --help | ||
| 15 | * -f, --canonicalize | ||
| 16 | * canonicalize by following every symlink in | ||
| 17 | * every component of the given name recursively; | ||
| 18 | * all but the last component must exist | ||
| 19 | * -e, --canonicalize-existing | ||
| 20 | * canonicalize by following every symlink in | ||
| 21 | * every component of the given name recursively, | ||
| 22 | * all components must exist | ||
| 23 | * -m, --canonicalize-missing | ||
| 24 | * canonicalize by following every symlink in | ||
| 25 | * every component of the given name recursively, | ||
| 26 | * without requirements on components existence | ||
| 27 | * -n, --no-newline do not output the trailing newline | ||
| 28 | * -q, --quiet, -s, --silent suppress most error messages | ||
| 29 | * -v, --verbose report error messages | ||
| 30 | * | ||
| 31 | * bbox supports: -f -n -v (fully), -q -s (accepts but ignores) | ||
| 32 | */ | ||
| 33 | |||
| 12 | int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 34 | int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 13 | int readlink_main(int argc UNUSED_PARAM, char **argv) | 35 | int readlink_main(int argc UNUSED_PARAM, char **argv) |
| 14 | { | 36 | { |
| @@ -20,7 +42,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
| 20 | unsigned opt; | 42 | unsigned opt; |
| 21 | /* We need exactly one non-option argument. */ | 43 | /* We need exactly one non-option argument. */ |
| 22 | opt_complementary = "=1"; | 44 | opt_complementary = "=1"; |
| 23 | opt = getopt32(argv, "f"); | 45 | opt = getopt32(argv, "fnvsq"); |
| 24 | fname = argv[optind]; | 46 | fname = argv[optind]; |
| 25 | ) | 47 | ) |
| 26 | SKIP_FEATURE_READLINK_FOLLOW( | 48 | SKIP_FEATURE_READLINK_FOLLOW( |
| @@ -30,9 +52,10 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
| 30 | ) | 52 | ) |
| 31 | 53 | ||
| 32 | /* compat: coreutils readlink reports errors silently via exit code */ | 54 | /* compat: coreutils readlink reports errors silently via exit code */ |
| 33 | logmode = LOGMODE_NONE; | 55 | if (!(opt & 4)) /* not -v */ |
| 56 | logmode = LOGMODE_NONE; | ||
| 34 | 57 | ||
| 35 | if (opt) { | 58 | if (opt & 1) { /* -f */ |
| 36 | buf = realpath(fname, pathbuf); | 59 | buf = realpath(fname, pathbuf); |
| 37 | } else { | 60 | } else { |
| 38 | buf = xmalloc_readlink_or_warn(fname); | 61 | buf = xmalloc_readlink_or_warn(fname); |
| @@ -40,7 +63,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) | |||
| 40 | 63 | ||
| 41 | if (!buf) | 64 | if (!buf) |
| 42 | return EXIT_FAILURE; | 65 | return EXIT_FAILURE; |
| 43 | puts(buf); | 66 | printf((opt & 2) ? "%s" : "%s\n", buf); |
| 44 | 67 | ||
| 45 | if (ENABLE_FEATURE_CLEAN_UP && !opt) | 68 | if (ENABLE_FEATURE_CLEAN_UP && !opt) |
| 46 | free(buf); | 69 | free(buf); |
diff --git a/include/libbb.h b/include/libbb.h index 2868eba03..bedf659b7 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -1099,6 +1099,8 @@ const char *get_signame(int number) FAST_FUNC; | |||
| 1099 | void print_signames(void) FAST_FUNC; | 1099 | void print_signames(void) FAST_FUNC; |
| 1100 | 1100 | ||
| 1101 | char *bb_simplify_path(const char *path) FAST_FUNC; | 1101 | char *bb_simplify_path(const char *path) FAST_FUNC; |
| 1102 | /* Returns ptr to NUL */ | ||
| 1103 | char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; | ||
| 1102 | 1104 | ||
| 1103 | #define FAIL_DELAY 3 | 1105 | #define FAIL_DELAY 3 |
| 1104 | extern void bb_do_delay(int seconds) FAST_FUNC; | 1106 | extern void bb_do_delay(int seconds) FAST_FUNC; |
diff --git a/include/usage.h b/include/usage.h index d3bf7849e..bfacc5611 100644 --- a/include/usage.h +++ b/include/usage.h | |||
| @@ -3404,12 +3404,15 @@ | |||
| 3404 | "files do not block on disk I/O" | 3404 | "files do not block on disk I/O" |
| 3405 | 3405 | ||
| 3406 | #define readlink_trivial_usage \ | 3406 | #define readlink_trivial_usage \ |
| 3407 | USE_FEATURE_READLINK_FOLLOW("[-f] ") "FILE" | 3407 | USE_FEATURE_READLINK_FOLLOW("[-fnv] ") "FILE" |
| 3408 | #define readlink_full_usage "\n\n" \ | 3408 | #define readlink_full_usage "\n\n" \ |
| 3409 | "Display the value of a symlink" \ | 3409 | "Display the value of a symlink" \ |
| 3410 | USE_FEATURE_READLINK_FOLLOW( "\n" \ | 3410 | USE_FEATURE_READLINK_FOLLOW( "\n" \ |
| 3411 | "\nOptions:" \ | 3411 | "\nOptions:" \ |
| 3412 | "\n -f Canonicalize by following all symlinks") \ | 3412 | "\n -f Canonicalize by following all symlinks" \ |
| 3413 | "\n -n Don't add newline" \ | ||
| 3414 | "\n -v Verbose" \ | ||
| 3415 | ) \ | ||
| 3413 | 3416 | ||
| 3414 | #define readprofile_trivial_usage \ | 3417 | #define readprofile_trivial_usage \ |
| 3415 | "[OPTIONS]..." | 3418 | "[OPTIONS]..." |
diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c index 367f1f04d..f80e3e8a5 100644 --- a/libbb/simplify_path.c +++ b/libbb/simplify_path.c | |||
| @@ -6,22 +6,13 @@ | |||
| 6 | * | 6 | * |
| 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| 8 | */ | 8 | */ |
| 9 | |||
| 10 | #include "libbb.h" | 9 | #include "libbb.h" |
| 11 | 10 | ||
| 12 | char* FAST_FUNC bb_simplify_path(const char *path) | 11 | char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) |
| 13 | { | 12 | { |
| 14 | char *s, *start, *p; | 13 | char *s, *p; |
| 15 | 14 | ||
| 16 | if (path[0] == '/') | ||
| 17 | start = xstrdup(path); | ||
| 18 | else { | ||
| 19 | s = xrealloc_getcwd_or_warn(NULL); | ||
| 20 | start = concat_path_file(s, path); | ||
| 21 | free(s); | ||
| 22 | } | ||
| 23 | p = s = start; | 15 | p = s = start; |
| 24 | |||
| 25 | do { | 16 | do { |
| 26 | if (*p == '/') { | 17 | if (*p == '/') { |
| 27 | if (*s == '/') { /* skip duplicate (or initial) slash */ | 18 | if (*s == '/') { /* skip duplicate (or initial) slash */ |
| @@ -47,7 +38,22 @@ char* FAST_FUNC bb_simplify_path(const char *path) | |||
| 47 | if ((p == start) || (*p != '/')) { /* not a trailing slash */ | 38 | if ((p == start) || (*p != '/')) { /* not a trailing slash */ |
| 48 | ++p; /* so keep last character */ | 39 | ++p; /* so keep last character */ |
| 49 | } | 40 | } |
| 50 | *p = 0; | 41 | *p = '\0'; |
| 42 | return p; | ||
| 43 | } | ||
| 44 | |||
| 45 | char* FAST_FUNC bb_simplify_path(const char *path) | ||
| 46 | { | ||
| 47 | char *s, *p; | ||
| 48 | |||
| 49 | if (path[0] == '/') | ||
| 50 | s = xstrdup(path); | ||
| 51 | else { | ||
| 52 | p = xrealloc_getcwd_or_warn(NULL); | ||
| 53 | s = concat_path_file(p, path); | ||
| 54 | free(p); | ||
| 55 | } | ||
| 51 | 56 | ||
| 52 | return start; | 57 | bb_simplify_abs_path_inplace(s); |
| 58 | return s; | ||
| 53 | } | 59 | } |
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 6eb950f32..6ee0164c2 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c | |||
| @@ -656,7 +656,7 @@ depmod -[aA] [-n -e -v -q -V -r -u] | |||
| 656 | [-b basedirectory] [forced_version] | 656 | [-b basedirectory] [forced_version] |
| 657 | depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ... | 657 | depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ... |
| 658 | If no arguments (except options) are given, "depmod -a" is assumed. | 658 | If no arguments (except options) are given, "depmod -a" is assumed. |
| 659 | depmod will output a dependancy list suitable for the modprobe utility. | 659 | depmod will output a dependency list suitable for the modprobe utility. |
| 660 | Options: | 660 | Options: |
| 661 | -a, --all Probe all modules | 661 | -a, --all Probe all modules |
| 662 | -A, --quick Only does the work if there's a new module | 662 | -A, --quick Only does the work if there's a new module |
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 0339ebb40..310eebc5f 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
| @@ -8,12 +8,17 @@ | |||
| 8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), | ||
| 12 | * we expect the full dependency list to be specified in modules.dep. Older | ||
| 13 | * versions would only export the direct dependency list. | ||
| 14 | */ | ||
| 15 | |||
| 11 | #include "libbb.h" | 16 | #include "libbb.h" |
| 12 | #include "modutils.h" | 17 | #include "modutils.h" |
| 13 | #include <sys/utsname.h> | 18 | #include <sys/utsname.h> |
| 14 | #include <fnmatch.h> | 19 | #include <fnmatch.h> |
| 15 | 20 | ||
| 16 | //#define DBG(...) bb_error_msg(__VA_ARGS__) | 21 | //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) |
| 17 | #define DBG(...) ((void)0) | 22 | #define DBG(...) ((void)0) |
| 18 | 23 | ||
| 19 | #define MODULE_FLAG_LOADED 0x0001 | 24 | #define MODULE_FLAG_LOADED 0x0001 |
| @@ -116,6 +121,7 @@ static void add_probe(const char *name) | |||
| 116 | return; | 121 | return; |
| 117 | } | 122 | } |
| 118 | 123 | ||
| 124 | DBG("queuing %s", name); | ||
| 119 | m->probed_name = name; | 125 | m->probed_name = name; |
| 120 | m->flags |= MODULE_FLAG_NEED_DEPS; | 126 | m->flags |= MODULE_FLAG_NEED_DEPS; |
| 121 | llist_add_to_end(&G.probes, m); | 127 | llist_add_to_end(&G.probes, m); |
| @@ -205,9 +211,10 @@ static int read_config(const char *path) | |||
| 205 | 211 | ||
| 206 | static int do_modprobe(struct module_entry *m) | 212 | static int do_modprobe(struct module_entry *m) |
| 207 | { | 213 | { |
| 208 | struct module_entry *m2; | 214 | struct module_entry *m2 = m2; /* for compiler */ |
| 209 | char *fn, *options; | 215 | char *fn, *options; |
| 210 | int rc = -1; | 216 | int rc, first; |
| 217 | llist_t *l; | ||
| 211 | 218 | ||
| 212 | if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { | 219 | if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { |
| 213 | DBG("skipping %s, not found in modules.dep", m->modname); | 220 | DBG("skipping %s, not found in modules.dep", m->modname); |
| @@ -218,13 +225,25 @@ static int do_modprobe(struct module_entry *m) | |||
| 218 | if (!(option_mask32 & MODPROBE_OPT_REMOVE)) | 225 | if (!(option_mask32 & MODPROBE_OPT_REMOVE)) |
| 219 | m->deps = llist_rev(m->deps); | 226 | m->deps = llist_rev(m->deps); |
| 220 | 227 | ||
| 228 | for (l = m->deps; l != NULL; l = l->link) | ||
| 229 | DBG("dep: %s", l->data); | ||
| 230 | |||
| 231 | first = 1; | ||
| 221 | rc = 0; | 232 | rc = 0; |
| 222 | while (m->deps && rc == 0) { | 233 | while (m->deps && rc == 0) { |
| 223 | fn = llist_pop(&m->deps); | 234 | fn = llist_pop(&m->deps); |
| 224 | m2 = get_or_add_modentry(fn); | 235 | m2 = get_or_add_modentry(fn); |
| 225 | if (option_mask32 & MODPROBE_OPT_REMOVE) { | 236 | if (option_mask32 & MODPROBE_OPT_REMOVE) { |
| 226 | if (bb_delete_module(m->modname, O_EXCL) != 0) | 237 | if (m2->flags & MODULE_FLAG_LOADED) { |
| 227 | rc = errno; | 238 | if (bb_delete_module(m2->modname, O_EXCL) != 0) { |
| 239 | if (first) | ||
| 240 | rc = errno; | ||
| 241 | } else { | ||
| 242 | m2->flags &= ~MODULE_FLAG_LOADED; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | /* do not error out if *deps* fail to unload */ | ||
| 246 | first = 0; | ||
| 228 | } else if (!(m2->flags & MODULE_FLAG_LOADED)) { | 247 | } else if (!(m2->flags & MODULE_FLAG_LOADED)) { |
| 229 | options = m2->options; | 248 | options = m2->options; |
| 230 | m2->options = NULL; | 249 | m2->options = NULL; |
| @@ -242,11 +261,10 @@ static int do_modprobe(struct module_entry *m) | |||
| 242 | free(fn); | 261 | free(fn); |
| 243 | } | 262 | } |
| 244 | 263 | ||
| 245 | //FIXME: what if rc < 0? | 264 | if (rc && !(option_mask32 & INSMOD_OPT_SILENT)) { |
| 246 | if (rc > 0 && !(option_mask32 & INSMOD_OPT_SILENT)) { | ||
| 247 | bb_error_msg("failed to %sload module %s: %s", | 265 | bb_error_msg("failed to %sload module %s: %s", |
| 248 | (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", | 266 | (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", |
| 249 | m->probed_name ? m->probed_name : m->modname, | 267 | m2->probed_name ? m2->probed_name : m2->modname, |
| 250 | moderror(rc) | 268 | moderror(rc) |
| 251 | ); | 269 | ); |
| 252 | } | 270 | } |
| @@ -294,7 +312,8 @@ static void load_modules_dep(void) | |||
| 294 | llist_add_to(&m->deps, xstrdup(tokens[0])); | 312 | llist_add_to(&m->deps, xstrdup(tokens[0])); |
| 295 | if (tokens[1]) | 313 | if (tokens[1]) |
| 296 | string_to_llist(tokens[1], &m->deps, " "); | 314 | string_to_llist(tokens[1], &m->deps, " "); |
| 297 | } | 315 | } else |
| 316 | DBG("skipping dep line"); | ||
| 298 | } | 317 | } |
| 299 | config_close(p); | 318 | config_close(p); |
| 300 | } | 319 | } |
| @@ -344,10 +363,12 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
| 344 | if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { | 363 | if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { |
| 345 | /* Each argument is a module name */ | 364 | /* Each argument is a module name */ |
| 346 | do { | 365 | do { |
| 366 | DBG("adding module %s", *argv); | ||
| 347 | add_probe(*argv++); | 367 | add_probe(*argv++); |
| 348 | } while (*argv); | 368 | } while (*argv); |
| 349 | } else { | 369 | } else { |
| 350 | /* First argument is module name, rest are parameters */ | 370 | /* First argument is module name, rest are parameters */ |
| 371 | DBG("probing just module %s", *argv); | ||
| 351 | add_probe(argv[0]); | 372 | add_probe(argv[0]); |
| 352 | G.cmdline_mopts = parse_cmdline_module_options(argv); | 373 | G.cmdline_mopts = parse_cmdline_module_options(argv); |
| 353 | } | 374 | } |
diff --git a/modutils/modutils.c b/modutils/modutils.c index 0f6cb0f2d..f437a9829 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c | |||
| @@ -57,7 +57,7 @@ char * FAST_FUNC filename2modname(const char *filename, char *modname) | |||
| 57 | from = bb_get_last_path_component_nostrip(filename); | 57 | from = bb_get_last_path_component_nostrip(filename); |
| 58 | for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) | 58 | for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) |
| 59 | modname[i] = (from[i] == '-') ? '_' : from[i]; | 59 | modname[i] = (from[i] == '-') ? '_' : from[i]; |
| 60 | modname[i] = 0; | 60 | modname[i] = '\0'; |
| 61 | 61 | ||
| 62 | return modname; | 62 | return modname; |
| 63 | } | 63 | } |
diff --git a/networking/ftpd.c b/networking/ftpd.c index ac6896117..e85e4f8ea 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
| @@ -1320,6 +1320,8 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 1320 | handle_appe(); | 1320 | handle_appe(); |
| 1321 | else if (cmdval == const_STOU) /* "store unique" */ | 1321 | else if (cmdval == const_STOU) /* "store unique" */ |
| 1322 | handle_stou(); | 1322 | handle_stou(); |
| 1323 | else | ||
| 1324 | goto bad_cmd; | ||
| 1323 | } | 1325 | } |
| 1324 | #endif | 1326 | #endif |
| 1325 | #if 0 | 1327 | #if 0 |
| @@ -1340,6 +1342,9 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 1340 | * (doesn't necessarily mean "we must support them") | 1342 | * (doesn't necessarily mean "we must support them") |
| 1341 | * foo 1.2.3: XXXX - comment | 1343 | * foo 1.2.3: XXXX - comment |
| 1342 | */ | 1344 | */ |
| 1345 | #if ENABLE_FEATURE_FTP_WRITE | ||
| 1346 | bad_cmd: | ||
| 1347 | #endif | ||
| 1343 | cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n"); | 1348 | cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n"); |
| 1344 | } | 1349 | } |
| 1345 | } | 1350 | } |
diff --git a/networking/httpd.c b/networking/httpd.c index 6bf103c56..de4fb9b39 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" | 32 | * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" |
| 33 | * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" | 33 | * bar=`httpd -e "<Hello World>"` # encode as "<Hello World>" |
| 34 | * Note that url encoding for arguments is not the same as html encoding for | 34 | * Note that url encoding for arguments is not the same as html encoding for |
| 35 | * presentation. -d decodes a url-encoded argument while -e encodes in html | 35 | * presentation. -d decodes an url-encoded argument while -e encodes in html |
| 36 | * for page display. | 36 | * for page display. |
| 37 | * | 37 | * |
| 38 | * httpd.conf has the following format: | 38 | * httpd.conf has the following format: |
| @@ -54,7 +54,7 @@ | |||
| 54 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ | 54 | * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ |
| 55 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ | 55 | * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ |
| 56 | * .au:audio/basic # additional mime type for audio.au files | 56 | * .au:audio/basic # additional mime type for audio.au files |
| 57 | * *.php:/path/php # running cgi.php scripts through an interpreter | 57 | * *.php:/path/php # run xxx.php through an interpreter |
| 58 | * | 58 | * |
| 59 | * A/D may be as a/d or allow/deny - only first char matters. | 59 | * A/D may be as a/d or allow/deny - only first char matters. |
| 60 | * Deny/Allow IP logic: | 60 | * Deny/Allow IP logic: |
| @@ -94,13 +94,13 @@ | |||
| 94 | * server exits with an error. | 94 | * server exits with an error. |
| 95 | * | 95 | * |
| 96 | */ | 96 | */ |
| 97 | /* TODO: use TCP_CORK, parse_config() */ | ||
| 97 | 98 | ||
| 98 | #include "libbb.h" | 99 | #include "libbb.h" |
| 99 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE | 100 | #if ENABLE_FEATURE_HTTPD_USE_SENDFILE |
| 100 | # include <sys/sendfile.h> | 101 | # include <sys/sendfile.h> |
| 101 | #endif | 102 | #endif |
| 102 | 103 | ||
| 103 | //#define DEBUG 1 | ||
| 104 | #define DEBUG 0 | 104 | #define DEBUG 0 |
| 105 | 105 | ||
| 106 | #define IOBUF_SIZE 8192 /* IO buffer */ | 106 | #define IOBUF_SIZE 8192 /* IO buffer */ |
| @@ -115,8 +115,8 @@ | |||
| 115 | 115 | ||
| 116 | #define HEADER_READ_TIMEOUT 60 | 116 | #define HEADER_READ_TIMEOUT 60 |
| 117 | 117 | ||
| 118 | static const char default_path_httpd_conf[] ALIGN1 = "/etc"; | 118 | static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; |
| 119 | static const char httpd_conf[] ALIGN1 = "httpd.conf"; | 119 | static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; |
| 120 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; | 120 | static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; |
| 121 | 121 | ||
| 122 | typedef struct has_next_ptr { | 122 | typedef struct has_next_ptr { |
| @@ -242,7 +242,7 @@ struct globals { | |||
| 242 | const char *bind_addr_or_port; | 242 | const char *bind_addr_or_port; |
| 243 | 243 | ||
| 244 | const char *g_query; | 244 | const char *g_query; |
| 245 | const char *configFile; | 245 | const char *opt_c_configFile; |
| 246 | const char *home_httpd; | 246 | const char *home_httpd; |
| 247 | const char *index_page; | 247 | const char *index_page; |
| 248 | 248 | ||
| @@ -289,7 +289,7 @@ struct globals { | |||
| 289 | #define rmt_ip (G.rmt_ip ) | 289 | #define rmt_ip (G.rmt_ip ) |
| 290 | #define bind_addr_or_port (G.bind_addr_or_port) | 290 | #define bind_addr_or_port (G.bind_addr_or_port) |
| 291 | #define g_query (G.g_query ) | 291 | #define g_query (G.g_query ) |
| 292 | #define configFile (G.configFile ) | 292 | #define opt_c_configFile (G.opt_c_configFile ) |
| 293 | #define home_httpd (G.home_httpd ) | 293 | #define home_httpd (G.home_httpd ) |
| 294 | #define index_page (G.index_page ) | 294 | #define index_page (G.index_page ) |
| 295 | #define found_mime_type (G.found_mime_type ) | 295 | #define found_mime_type (G.found_mime_type ) |
| @@ -452,14 +452,6 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) | |||
| 452 | /* | 452 | /* |
| 453 | * Parse configuration file into in-memory linked list. | 453 | * Parse configuration file into in-memory linked list. |
| 454 | * | 454 | * |
| 455 | * The first non-white character is examined to determine if the config line | ||
| 456 | * is one of the following: | ||
| 457 | * .ext:mime/type # new mime type not compiled into httpd | ||
| 458 | * [adAD]:from # ip address allow/deny, * for wildcard | ||
| 459 | * /path:user:pass # username/password | ||
| 460 | * Ennn:error.html # error page for status nnn | ||
| 461 | * P:/url:[http://]hostname[:port]/new/path # reverse proxy | ||
| 462 | * | ||
| 463 | * Any previous IP rules are discarded. | 455 | * Any previous IP rules are discarded. |
| 464 | * If the flag argument is not SUBDIR_PARSE then all /path and mime rules | 456 | * If the flag argument is not SUBDIR_PARSE then all /path and mime rules |
| 465 | * are also discarded. That is, previous settings are retained if flag is | 457 | * are also discarded. That is, previous settings are retained if flag is |
| @@ -469,99 +461,150 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp) | |||
| 469 | * path Path where to look for httpd.conf (without filename). | 461 | * path Path where to look for httpd.conf (without filename). |
| 470 | * flag Type of the parse request. | 462 | * flag Type of the parse request. |
| 471 | */ | 463 | */ |
| 472 | /* flag */ | 464 | /* flag param: */ |
| 473 | #define FIRST_PARSE 0 | 465 | enum { |
| 474 | #define SUBDIR_PARSE 1 | 466 | FIRST_PARSE = 0, /* path will be "/etc" */ |
| 475 | #define SIGNALED_PARSE 2 | 467 | SIGNALED_PARSE = 1, /* path will be "/etc" */ |
| 476 | #define FIND_FROM_HTTPD_ROOT 3 | 468 | SUBDIR_PARSE = 2, /* path will be derived from URL */ |
| 469 | }; | ||
| 477 | static void parse_conf(const char *path, int flag) | 470 | static void parse_conf(const char *path, int flag) |
| 478 | { | 471 | { |
| 472 | /* internally used extra flag state */ | ||
| 473 | enum { TRY_CURDIR_PARSE = 3 }; | ||
| 474 | |||
| 479 | FILE *f; | 475 | FILE *f; |
| 480 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 476 | const char *filename; |
| 481 | Htaccess *prev; | ||
| 482 | #endif | ||
| 483 | Htaccess *cur; | ||
| 484 | const char *filename = configFile; | ||
| 485 | char buf[160]; | 477 | char buf[160]; |
| 486 | char *p, *p0; | ||
| 487 | char *after_colon; | ||
| 488 | Htaccess_IP *pip; | ||
| 489 | 478 | ||
| 490 | /* discard old rules */ | 479 | /* discard old rules */ |
| 491 | free_Htaccess_IP_list(&ip_a_d); | 480 | free_Htaccess_IP_list(&ip_a_d); |
| 492 | flg_deny_all = 0; | 481 | flg_deny_all = 0; |
| 493 | /* retain previous auth and mime config only for subdir parse */ | 482 | /* retain previous auth and mime config only for subdir parse */ |
| 494 | if (flag != SUBDIR_PARSE) { | 483 | if (flag != SUBDIR_PARSE) { |
| 484 | free_Htaccess_list(&mime_a); | ||
| 495 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 485 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
| 496 | free_Htaccess_list(&g_auth); | 486 | free_Htaccess_list(&g_auth); |
| 497 | #endif | 487 | #endif |
| 498 | free_Htaccess_list(&mime_a); | ||
| 499 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | 488 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
| 500 | free_Htaccess_list(&script_i); | 489 | free_Htaccess_list(&script_i); |
| 501 | #endif | 490 | #endif |
| 502 | } | 491 | } |
| 503 | 492 | ||
| 493 | filename = opt_c_configFile; | ||
| 504 | if (flag == SUBDIR_PARSE || filename == NULL) { | 494 | if (flag == SUBDIR_PARSE || filename == NULL) { |
| 505 | filename = alloca(strlen(path) + sizeof(httpd_conf) + 2); | 495 | filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2); |
| 506 | sprintf((char *)filename, "%s/%s", path, httpd_conf); | 496 | sprintf((char *)filename, "%s/%s", path, HTTPD_CONF); |
| 507 | } | 497 | } |
| 508 | 498 | ||
| 509 | while ((f = fopen_for_read(filename)) == NULL) { | 499 | while ((f = fopen_for_read(filename)) == NULL) { |
| 510 | if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) { | 500 | if (flag >= SUBDIR_PARSE) { /* SUBDIR or TRY_CURDIR */ |
| 511 | /* config file not found, no changes to config */ | 501 | /* config file not found, no changes to config */ |
| 512 | return; | 502 | return; |
| 513 | } | 503 | } |
| 514 | if (configFile && flag == FIRST_PARSE) /* if -c option given */ | 504 | if (flag == FIRST_PARSE) { |
| 515 | bb_simple_perror_msg_and_die(filename); | 505 | /* -c CONFFILE given, but CONFFILE doesn't exist? */ |
| 516 | flag = FIND_FROM_HTTPD_ROOT; | 506 | if (opt_c_configFile) |
| 517 | filename = httpd_conf; | 507 | bb_simple_perror_msg_and_die(opt_c_configFile); |
| 508 | /* else: no -c, thus we looked at /etc/httpd.conf, | ||
| 509 | * and it's not there. try ./httpd.conf: */ | ||
| 510 | } | ||
| 511 | flag = TRY_CURDIR_PARSE; | ||
| 512 | filename = HTTPD_CONF; | ||
| 518 | } | 513 | } |
| 519 | 514 | ||
| 520 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 515 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
| 521 | prev = g_auth; | 516 | /* in "/file:user:pass" lines, we prepend path in subdirs */ |
| 522 | #endif | 517 | if (flag != SUBDIR_PARSE) |
| 523 | /* This could stand some work */ | 518 | path = ""; |
| 524 | while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) { | 519 | #endif |
| 525 | after_colon = NULL; | 520 | /* The lines can be: |
| 526 | for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) { | 521 | * |
| 527 | if (!isspace(*p0)) { | 522 | * I:default_index_file |
| 528 | *p++ = *p0; | 523 | * H:http_home |
| 529 | if (*p0 == ':' && after_colon == NULL) | 524 | * [AD]:IP[/mask] # allow/deny, * for wildcard |
| 530 | after_colon = p; | 525 | * Ennn:error.html # error page for status nnn |
| 526 | * P:/url:[http://]hostname[:port]/new/path # reverse proxy | ||
| 527 | * .ext:mime/type # mime type | ||
| 528 | * *.php:/path/php # run xxx.php through an interpreter | ||
| 529 | * /file:user:pass # username and password | ||
| 530 | */ | ||
| 531 | while (fgets(buf, sizeof(buf), f) != NULL) { | ||
| 532 | unsigned strlen_buf; | ||
| 533 | unsigned char ch; | ||
| 534 | char *after_colon; | ||
| 535 | |||
| 536 | { /* remove all whitespace, and # comments */ | ||
| 537 | char *p, *p0; | ||
| 538 | |||
| 539 | p0 = buf; | ||
| 540 | /* skip non-whitespace beginning. Often the whole line | ||
| 541 | * is non-whitespace. We want this case to work fast, | ||
| 542 | * without needless copying, therefore we don't merge | ||
| 543 | * this operation into next while loop. */ | ||
| 544 | while ((ch = *p0) != '\0' && ch != '\n' && ch != '#' | ||
| 545 | && ch != ' ' && ch != '\t' | ||
| 546 | ) { | ||
| 547 | p0++; | ||
| 548 | } | ||
| 549 | p = p0; | ||
| 550 | /* if we enter this loop, we have some whitespace. | ||
| 551 | * discard it */ | ||
| 552 | while (ch != '\0' && ch != '\n' && ch != '#') { | ||
| 553 | if (ch != ' ' && ch != '\t') { | ||
| 554 | *p++ = ch; | ||
| 555 | } | ||
| 556 | ch = *++p0; | ||
| 531 | } | 557 | } |
| 558 | *p = '\0'; | ||
| 559 | strlen_buf = p - buf; | ||
| 560 | if (strlen_buf == 0) | ||
| 561 | continue; /* empty line */ | ||
| 532 | } | 562 | } |
| 533 | *p = '\0'; | ||
| 534 | 563 | ||
| 535 | /* test for empty or strange line */ | 564 | after_colon = strchr(buf, ':'); |
| 536 | if (after_colon == NULL || *after_colon == '\0') | 565 | /* strange line? */ |
| 566 | if (after_colon == NULL || *++after_colon == '\0') | ||
| 567 | goto config_error; | ||
| 568 | |||
| 569 | ch = (buf[0] & ~0x20); /* toupper if it's a letter */ | ||
| 570 | |||
| 571 | if (ch == 'I') { | ||
| 572 | index_page = xstrdup(after_colon); | ||
| 537 | continue; | 573 | continue; |
| 538 | p0 = buf; | 574 | } |
| 539 | if (*p0 == 'd' || *p0 == 'a') | 575 | |
| 540 | *p0 -= 0x20; /* a/d -> A/D */ | 576 | /* do not allow jumping around using H in subdir's configs */ |
| 541 | if (*after_colon == '*') { | 577 | if (flag == FIRST_PARSE && ch == 'H') { |
| 542 | if (*p0 == 'D') { | 578 | home_httpd = xstrdup(after_colon); |
| 543 | /* memorize "deny all" */ | 579 | xchdir(home_httpd); |
| 544 | flg_deny_all = 1; | ||
| 545 | } | ||
| 546 | /* skip assumed "A:*", it is a default anyway */ | ||
| 547 | continue; | 580 | continue; |
| 548 | } | 581 | } |
| 549 | 582 | ||
| 550 | if (*p0 == 'A' || *p0 == 'D') { | 583 | if (ch == 'A' || ch == 'D') { |
| 551 | /* storing current config IP line */ | 584 | Htaccess_IP *pip; |
| 552 | pip = xzalloc(sizeof(Htaccess_IP)); | 585 | |
| 553 | if (scan_ip_mask(after_colon, &(pip->ip), &(pip->mask))) { | 586 | if (*after_colon == '*') { |
| 587 | if (ch == 'D') { | ||
| 588 | /* memorize "deny all" */ | ||
| 589 | flg_deny_all = 1; | ||
| 590 | } | ||
| 591 | /* skip assumed "A:*", it is a default anyway */ | ||
| 592 | continue; | ||
| 593 | } | ||
| 594 | /* store "allow/deny IP/mask" line */ | ||
| 595 | pip = xzalloc(sizeof(*pip)); | ||
| 596 | if (scan_ip_mask(after_colon, &pip->ip, &pip->mask)) { | ||
| 554 | /* IP{/mask} syntax error detected, protect all */ | 597 | /* IP{/mask} syntax error detected, protect all */ |
| 555 | *p0 = 'D'; | 598 | ch = 'D'; |
| 556 | pip->mask = 0; | 599 | pip->mask = 0; |
| 557 | } | 600 | } |
| 558 | pip->allow_deny = *p0; | 601 | pip->allow_deny = ch; |
| 559 | if (*p0 == 'D') { | 602 | if (ch == 'D') { |
| 560 | /* Deny:from_IP - prepend */ | 603 | /* Deny:from_IP - prepend */ |
| 561 | pip->next = ip_a_d; | 604 | pip->next = ip_a_d; |
| 562 | ip_a_d = pip; | 605 | ip_a_d = pip; |
| 563 | } else { | 606 | } else { |
| 564 | /* A:from_IP - append (thus D precedes A) */ | 607 | /* A:from_IP - append (thus all D's precedes A's) */ |
| 565 | Htaccess_IP *prev_IP = ip_a_d; | 608 | Htaccess_IP *prev_IP = ip_a_d; |
| 566 | if (prev_IP == NULL) { | 609 | if (prev_IP == NULL) { |
| 567 | ip_a_d = pip; | 610 | ip_a_d = pip; |
| @@ -575,12 +618,12 @@ static void parse_conf(const char *path, int flag) | |||
| 575 | } | 618 | } |
| 576 | 619 | ||
| 577 | #if ENABLE_FEATURE_HTTPD_ERROR_PAGES | 620 | #if ENABLE_FEATURE_HTTPD_ERROR_PAGES |
| 578 | if (flag == FIRST_PARSE && *p0 == 'E') { | 621 | if (flag == FIRST_PARSE && ch == 'E') { |
| 579 | unsigned i; | 622 | unsigned i; |
| 580 | int status = atoi(++p0); /* error status code */ | 623 | int status = atoi(buf + 1); /* error status code */ |
| 624 | |||
| 581 | if (status < HTTP_CONTINUE) { | 625 | if (status < HTTP_CONTINUE) { |
| 582 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 626 | goto config_error; |
| 583 | continue; | ||
| 584 | } | 627 | } |
| 585 | /* then error page; find matching status */ | 628 | /* then error page; find matching status */ |
| 586 | for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { | 629 | for (i = 0; i < ARRAY_SIZE(http_response_type); i++) { |
| @@ -597,7 +640,7 @@ static void parse_conf(const char *path, int flag) | |||
| 597 | #endif | 640 | #endif |
| 598 | 641 | ||
| 599 | #if ENABLE_FEATURE_HTTPD_PROXY | 642 | #if ENABLE_FEATURE_HTTPD_PROXY |
| 600 | if (flag == FIRST_PARSE && *p0 == 'P') { | 643 | if (flag == FIRST_PARSE && ch == 'P') { |
| 601 | /* P:/url:[http://]hostname[:port]/new/path */ | 644 | /* P:/url:[http://]hostname[:port]/new/path */ |
| 602 | char *url_from, *host_port, *url_to; | 645 | char *url_from, *host_port, *url_to; |
| 603 | Htaccess_Proxy *proxy_entry; | 646 | Htaccess_Proxy *proxy_entry; |
| @@ -605,23 +648,20 @@ static void parse_conf(const char *path, int flag) | |||
| 605 | url_from = after_colon; | 648 | url_from = after_colon; |
| 606 | host_port = strchr(after_colon, ':'); | 649 | host_port = strchr(after_colon, ':'); |
| 607 | if (host_port == NULL) { | 650 | if (host_port == NULL) { |
| 608 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 651 | goto config_error; |
| 609 | continue; | ||
| 610 | } | 652 | } |
| 611 | *host_port++ = '\0'; | 653 | *host_port++ = '\0'; |
| 612 | if (strncmp(host_port, "http://", 7) == 0) | 654 | if (strncmp(host_port, "http://", 7) == 0) |
| 613 | host_port += 7; | 655 | host_port += 7; |
| 614 | if (*host_port == '\0') { | 656 | if (*host_port == '\0') { |
| 615 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 657 | goto config_error; |
| 616 | continue; | ||
| 617 | } | 658 | } |
| 618 | url_to = strchr(host_port, '/'); | 659 | url_to = strchr(host_port, '/'); |
| 619 | if (url_to == NULL) { | 660 | if (url_to == NULL) { |
| 620 | bb_error_msg("config error '%s' in '%s'", buf, filename); | 661 | goto config_error; |
| 621 | continue; | ||
| 622 | } | 662 | } |
| 623 | *url_to = '\0'; | 663 | *url_to = '\0'; |
| 624 | proxy_entry = xzalloc(sizeof(Htaccess_Proxy)); | 664 | proxy_entry = xzalloc(sizeof(*proxy_entry)); |
| 625 | proxy_entry->url_from = xstrdup(url_from); | 665 | proxy_entry->url_from = xstrdup(url_from); |
| 626 | proxy_entry->host_port = xstrdup(host_port); | 666 | proxy_entry->host_port = xstrdup(host_port); |
| 627 | *url_to = '/'; | 667 | *url_to = '/'; |
| @@ -631,115 +671,87 @@ static void parse_conf(const char *path, int flag) | |||
| 631 | continue; | 671 | continue; |
| 632 | } | 672 | } |
| 633 | #endif | 673 | #endif |
| 674 | /* the rest of directives are non-alphabetic, | ||
| 675 | * must avoid using "toupper'ed" ch */ | ||
| 676 | ch = buf[0]; | ||
| 634 | 677 | ||
| 635 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 678 | if (ch == '.' /* ".ext:mime/type" */ |
| 636 | if (*p0 == '/') { | 679 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR |
| 637 | /* make full path from httpd root / current_path / config_line_path */ | 680 | || (ch == '*' && buf[1] == '.') /* "*.php:/path/php" */ |
| 638 | const char *tp = (flag == SUBDIR_PARSE ? path : ""); | 681 | #endif |
| 639 | p0 = xmalloc(strlen(tp) + (after_colon - buf) + 2 + strlen(after_colon)); | 682 | ) { |
| 640 | after_colon[-1] = '\0'; | 683 | char *p; |
| 641 | sprintf(p0, "/%s%s", tp, buf); | 684 | Htaccess *cur; |
| 642 | |||
| 643 | /* looks like bb_simplify_path... */ | ||
| 644 | tp = p = p0; | ||
| 645 | do { | ||
| 646 | if (*p == '/') { | ||
| 647 | if (*tp == '/') { /* skip duplicate (or initial) slash */ | ||
| 648 | continue; | ||
| 649 | } | ||
| 650 | if (*tp == '.') { | ||
| 651 | if (tp[1] == '/' || tp[1] == '\0') { /* remove extra '.' */ | ||
| 652 | continue; | ||
| 653 | } | ||
| 654 | if ((tp[1] == '.') && (tp[2] == '/' || tp[2] == '\0')) { | ||
| 655 | ++tp; | ||
| 656 | if (p > p0) { | ||
| 657 | while (*--p != '/') /* omit previous dir */ | ||
| 658 | continue; | ||
| 659 | } | ||
| 660 | continue; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | } | ||
| 664 | *++p = *tp; | ||
| 665 | } while (*++tp); | ||
| 666 | 685 | ||
| 667 | if ((p == p0) || (*p != '/')) { /* not a trailing slash */ | 686 | cur = xzalloc(sizeof(*cur) /* includes space for NUL */ + strlen_buf); |
| 668 | ++p; /* so keep last character */ | 687 | strcpy(cur->before_colon, buf); |
| 688 | p = cur->before_colon + (after_colon - buf); | ||
| 689 | p[-1] = '\0'; | ||
| 690 | cur->after_colon = p; | ||
| 691 | if (ch == '.') { | ||
| 692 | /* .mime line: prepend to mime_a list */ | ||
| 693 | cur->next = mime_a; | ||
| 694 | mime_a = cur; | ||
| 695 | } | ||
| 696 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | ||
| 697 | else { | ||
| 698 | /* script interpreter line: prepend to script_i list */ | ||
| 699 | cur->next = script_i; | ||
| 700 | script_i = cur; | ||
| 669 | } | 701 | } |
| 670 | *p = ':'; | ||
| 671 | strcpy(p + 1, after_colon); | ||
| 672 | } | ||
| 673 | #endif | 702 | #endif |
| 674 | if (*p0 == 'I') { | ||
| 675 | index_page = xstrdup(after_colon); | ||
| 676 | continue; | 703 | continue; |
| 677 | } | 704 | } |
| 678 | 705 | ||
| 679 | /* Do not allow jumping around using H in subdir's configs */ | ||
| 680 | if (flag == FIRST_PARSE && *p0 == 'H') { | ||
| 681 | home_httpd = xstrdup(after_colon); | ||
| 682 | xchdir(home_httpd); | ||
| 683 | continue; | ||
| 684 | } | ||
| 685 | |||
| 686 | /* storing current config line */ | ||
| 687 | cur = xzalloc(sizeof(Htaccess) + strlen(p0)); | ||
| 688 | strcpy(cur->before_colon, p0); | ||
| 689 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | ||
| 690 | if (*p0 == '/') /* was malloced - see above */ | ||
| 691 | free(p0); | ||
| 692 | #endif | ||
| 693 | cur->after_colon = strchr(cur->before_colon, ':'); | ||
| 694 | *cur->after_colon++ = '\0'; | ||
| 695 | if (cur->before_colon[0] == '.') { | ||
| 696 | /* .mime line: prepend to mime_a list */ | ||
| 697 | cur->next = mime_a; | ||
| 698 | mime_a = cur; | ||
| 699 | continue; | ||
| 700 | } | ||
| 701 | #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR | ||
| 702 | if (cur->before_colon[0] == '*' && cur->before_colon[1] == '.') { | ||
| 703 | /* script interpreter line: prepend to script_i list */ | ||
| 704 | cur->next = script_i; | ||
| 705 | script_i = cur; | ||
| 706 | continue; | ||
| 707 | } | ||
| 708 | #endif | ||
| 709 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 706 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
| 710 | //TODO: we do not test for leading "/"?? | 707 | if (ch == '/') { /* "/file:user:pass" */ |
| 711 | //also, do we leak cur if BASIC_AUTH is off? | 708 | char *p; |
| 712 | if (prev == NULL) { | 709 | Htaccess *cur; |
| 713 | /* first line */ | 710 | unsigned file_len; |
| 714 | g_auth = prev = cur; | 711 | |
| 715 | } else { | 712 | /* note: path is "" unless we are in SUBDIR parse, |
| 716 | /* sort path, if current length eq or bigger then move up */ | 713 | * otherwise it does NOT start with "/" */ |
| 717 | Htaccess *prev_hti = g_auth; | 714 | cur = xzalloc(sizeof(*cur) /* includes space for NUL */ |
| 718 | size_t l = strlen(cur->before_colon); | 715 | + 1 + strlen(path) |
| 719 | Htaccess *hti; | 716 | + strlen_buf |
| 720 | 717 | ); | |
| 721 | for (hti = prev_hti; hti; hti = hti->next) { | 718 | /* form "/path/file" */ |
| 722 | if (l >= strlen(hti->before_colon)) { | 719 | sprintf(cur->before_colon, "/%s%.*s", |
| 723 | /* insert before hti */ | 720 | path, |
| 724 | cur->next = hti; | 721 | (int) (after_colon - buf - 1), /* includes "/", but not ":" */ |
| 725 | if (prev_hti != hti) { | 722 | buf); |
| 726 | prev_hti->next = cur; | 723 | /* canonicalize it */ |
| 727 | } else { | 724 | p = bb_simplify_abs_path_inplace(cur->before_colon); |
| 728 | /* insert as top */ | 725 | file_len = p - cur->before_colon; |
| 729 | g_auth = cur; | 726 | /* add "user:pass" after NUL */ |
| 727 | strcpy(++p, after_colon); | ||
| 728 | cur->after_colon = p; | ||
| 729 | |||
| 730 | /* insert cur into g_auth */ | ||
| 731 | /* g_auth is sorted by decreased filename length */ | ||
| 732 | { | ||
| 733 | Htaccess *auth, **authp; | ||
| 734 | |||
| 735 | authp = &g_auth; | ||
| 736 | while ((auth = *authp) != NULL) { | ||
| 737 | if (file_len >= strlen(auth->before_colon)) { | ||
| 738 | /* insert cur before auth */ | ||
| 739 | cur->next = auth; | ||
| 740 | break; | ||
| 730 | } | 741 | } |
| 731 | break; | 742 | authp = &auth->next; |
| 732 | } | 743 | } |
| 733 | if (prev_hti != hti) | 744 | *authp = cur; |
| 734 | prev_hti = prev_hti->next; | ||
| 735 | } | ||
| 736 | if (!hti) { /* not inserted, add to bottom */ | ||
| 737 | prev->next = cur; | ||
| 738 | prev = cur; | ||
| 739 | } | 745 | } |
| 746 | continue; | ||
| 740 | } | 747 | } |
| 741 | #endif /* BASIC_AUTH */ | 748 | #endif /* BASIC_AUTH */ |
| 749 | |||
| 750 | /* the line is not recognized */ | ||
| 751 | config_error: | ||
| 752 | bb_error_msg("config error '%s' in '%s'", buf, filename); | ||
| 742 | } /* while (fgets) */ | 753 | } /* while (fgets) */ |
| 754 | |||
| 743 | fclose(f); | 755 | fclose(f); |
| 744 | } | 756 | } |
| 745 | 757 | ||
| @@ -1527,11 +1539,6 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1527 | send_headers_and_exit(HTTP_NOT_FOUND); | 1539 | send_headers_and_exit(HTTP_NOT_FOUND); |
| 1528 | log_and_exit(); | 1540 | log_and_exit(); |
| 1529 | } | 1541 | } |
| 1530 | |||
| 1531 | if (DEBUG) | ||
| 1532 | bb_error_msg("sending file '%s' content-type: %s", | ||
| 1533 | url, found_mime_type); | ||
| 1534 | |||
| 1535 | /* If you want to know about EPIPE below | 1542 | /* If you want to know about EPIPE below |
| 1536 | * (happens if you abort downloads from local httpd): */ | 1543 | * (happens if you abort downloads from local httpd): */ |
| 1537 | signal(SIGPIPE, SIG_IGN); | 1544 | signal(SIGPIPE, SIG_IGN); |
| @@ -1559,6 +1566,11 @@ static NOINLINE void send_file_and_exit(const char *url, int what) | |||
| 1559 | } | 1566 | } |
| 1560 | } | 1567 | } |
| 1561 | } | 1568 | } |
| 1569 | |||
| 1570 | if (DEBUG) | ||
| 1571 | bb_error_msg("sending file '%s' content-type: %s", | ||
| 1572 | url, found_mime_type); | ||
| 1573 | |||
| 1562 | #if ENABLE_FEATURE_HTTPD_RANGES | 1574 | #if ENABLE_FEATURE_HTTPD_RANGES |
| 1563 | if (what == SEND_BODY) | 1575 | if (what == SEND_BODY) |
| 1564 | range_start = 0; /* err pages and ranges don't mix */ | 1576 | range_start = 0; /* err pages and ranges don't mix */ |
| @@ -2031,8 +2043,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
| 2031 | /* We are done reading headers, disable peer timeout */ | 2043 | /* We are done reading headers, disable peer timeout */ |
| 2032 | alarm(0); | 2044 | alarm(0); |
| 2033 | 2045 | ||
| 2034 | if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || !ip_allowed) { | 2046 | if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0 || !ip_allowed) { |
| 2035 | /* protect listing [/path]/httpd_conf or IP deny */ | 2047 | /* protect listing [/path]/httpd.conf or IP deny */ |
| 2036 | send_headers_and_exit(HTTP_FORBIDDEN); | 2048 | send_headers_and_exit(HTTP_FORBIDDEN); |
| 2037 | } | 2049 | } |
| 2038 | 2050 | ||
| @@ -2074,7 +2086,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
| 2074 | header_ptr += 2; | 2086 | header_ptr += 2; |
| 2075 | write(proxy_fd, header_buf, header_ptr - header_buf); | 2087 | write(proxy_fd, header_buf, header_ptr - header_buf); |
| 2076 | free(header_buf); /* on the order of 8k, free it */ | 2088 | free(header_buf); /* on the order of 8k, free it */ |
| 2077 | /* cgi_io_loop_and_exit needs to have two disctinct fds */ | 2089 | /* cgi_io_loop_and_exit needs to have two distinct fds */ |
| 2078 | cgi_io_loop_and_exit(proxy_fd, dup(proxy_fd), length); | 2090 | cgi_io_loop_and_exit(proxy_fd, dup(proxy_fd), length); |
| 2079 | } | 2091 | } |
| 2080 | #endif | 2092 | #endif |
| @@ -2245,7 +2257,7 @@ static void mini_httpd_inetd(void) | |||
| 2245 | 2257 | ||
| 2246 | static void sighup_handler(int sig UNUSED_PARAM) | 2258 | static void sighup_handler(int sig UNUSED_PARAM) |
| 2247 | { | 2259 | { |
| 2248 | parse_conf(default_path_httpd_conf, SIGNALED_PARSE); | 2260 | parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE); |
| 2249 | } | 2261 | } |
| 2250 | 2262 | ||
| 2251 | enum { | 2263 | enum { |
| @@ -2304,7 +2316,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 2304 | USE_FEATURE_HTTPD_AUTH_MD5("m:") | 2316 | USE_FEATURE_HTTPD_AUTH_MD5("m:") |
| 2305 | USE_FEATURE_HTTPD_SETUID("u:") | 2317 | USE_FEATURE_HTTPD_SETUID("u:") |
| 2306 | "p:ifv", | 2318 | "p:ifv", |
| 2307 | &configFile, &url_for_decode, &home_httpd | 2319 | &opt_c_configFile, &url_for_decode, &home_httpd |
| 2308 | USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) | 2320 | USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode) |
| 2309 | USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) | 2321 | USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm) |
| 2310 | USE_FEATURE_HTTPD_AUTH_MD5(, &pass) | 2322 | USE_FEATURE_HTTPD_AUTH_MD5(, &pass) |
| @@ -2375,7 +2387,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
| 2375 | } | 2387 | } |
| 2376 | #endif | 2388 | #endif |
| 2377 | 2389 | ||
| 2378 | parse_conf(default_path_httpd_conf, FIRST_PARSE); | 2390 | parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE); |
| 2379 | if (!(opt & OPT_INETD)) | 2391 | if (!(opt & OPT_INETD)) |
| 2380 | signal(SIGHUP, sighup_handler); | 2392 | signal(SIGHUP, sighup_handler); |
| 2381 | 2393 | ||
diff --git a/networking/telnetd.c b/networking/telnetd.c index ccf328925..4c5ea3ab3 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
| @@ -199,9 +199,17 @@ static size_t iac_safe_write(int fd, const char *buf, size_t count) | |||
| 199 | return total + rc; | 199 | return total + rc; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /* Must match getopt32 string */ | ||
| 203 | enum { | ||
| 204 | OPT_WATCHCHILD = (1 << 2), /* -K */ | ||
| 205 | OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */ | ||
| 206 | OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */ | ||
| 207 | OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */ | ||
| 208 | }; | ||
| 209 | |||
| 202 | static struct tsession * | 210 | static struct tsession * |
| 203 | make_new_session( | 211 | make_new_session( |
| 204 | USE_FEATURE_TELNETD_STANDALONE(int sock) | 212 | USE_FEATURE_TELNETD_STANDALONE(int master_fd, int sock) |
| 205 | SKIP_FEATURE_TELNETD_STANDALONE(void) | 213 | SKIP_FEATURE_TELNETD_STANDALONE(void) |
| 206 | ) { | 214 | ) { |
| 207 | const char *login_argv[2]; | 215 | const char *login_argv[2]; |
| @@ -288,9 +296,29 @@ make_new_session( | |||
| 288 | /* Restore default signal handling ASAP */ | 296 | /* Restore default signal handling ASAP */ |
| 289 | bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); | 297 | bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); |
| 290 | 298 | ||
| 299 | #if ENABLE_FEATURE_TELNETD_STANDALONE | ||
| 300 | if (!(option_mask32 & OPT_INETD)) { | ||
| 301 | struct tsession *tp = sessions; | ||
| 302 | while (tp) { | ||
| 303 | close(tp->ptyfd); | ||
| 304 | close(tp->sockfd_read); | ||
| 305 | /* sockfd_write == sockfd_read for standalone telnetd */ | ||
| 306 | /*close(tp->sockfd_write);*/ | ||
| 307 | tp = tp->next; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | #endif | ||
| 311 | |||
| 291 | /* Make new session and process group */ | 312 | /* Make new session and process group */ |
| 292 | setsid(); | 313 | setsid(); |
| 293 | 314 | ||
| 315 | close(fd); | ||
| 316 | #if ENABLE_FEATURE_TELNETD_STANDALONE | ||
| 317 | close(sock); | ||
| 318 | if (master_fd >= 0) | ||
| 319 | close(master_fd); | ||
| 320 | #endif | ||
| 321 | |||
| 294 | /* Open the child's side of the tty. */ | 322 | /* Open the child's side of the tty. */ |
| 295 | /* NB: setsid() disconnects from any previous ctty's. Therefore | 323 | /* NB: setsid() disconnects from any previous ctty's. Therefore |
| 296 | * we must open child's side of the tty AFTER setsid! */ | 324 | * we must open child's side of the tty AFTER setsid! */ |
| @@ -329,14 +357,6 @@ make_new_session( | |||
| 329 | _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", loginpath);*/ | 357 | _exit(EXIT_FAILURE); /*bb_perror_msg_and_die("execv %s", loginpath);*/ |
| 330 | } | 358 | } |
| 331 | 359 | ||
| 332 | /* Must match getopt32 string */ | ||
| 333 | enum { | ||
| 334 | OPT_WATCHCHILD = (1 << 2), /* -K */ | ||
| 335 | OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */ | ||
| 336 | OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */ | ||
| 337 | OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */ | ||
| 338 | }; | ||
| 339 | |||
| 340 | #if ENABLE_FEATURE_TELNETD_STANDALONE | 360 | #if ENABLE_FEATURE_TELNETD_STANDALONE |
| 341 | 361 | ||
| 342 | static void | 362 | static void |
| @@ -465,7 +485,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
| 465 | 485 | ||
| 466 | #if ENABLE_FEATURE_TELNETD_STANDALONE | 486 | #if ENABLE_FEATURE_TELNETD_STANDALONE |
| 467 | if (IS_INETD) { | 487 | if (IS_INETD) { |
| 468 | sessions = make_new_session(0); | 488 | sessions = make_new_session(-1, 0); |
| 469 | if (!sessions) /* pty opening or vfork problem, exit */ | 489 | if (!sessions) /* pty opening or vfork problem, exit */ |
| 470 | return 1; /* make_new_session prints error message */ | 490 | return 1; /* make_new_session prints error message */ |
| 471 | } else { | 491 | } else { |
| @@ -553,7 +573,7 @@ int telnetd_main(int argc UNUSED_PARAM, char **argv) | |||
| 553 | if (fd < 0) | 573 | if (fd < 0) |
| 554 | goto again; | 574 | goto again; |
| 555 | /* Create a new session and link it into our active list */ | 575 | /* Create a new session and link it into our active list */ |
| 556 | new_ts = make_new_session(fd); | 576 | new_ts = make_new_session(master_fd, fd); |
| 557 | if (new_ts) { | 577 | if (new_ts) { |
| 558 | new_ts->next = sessions; | 578 | new_ts->next = sessions; |
| 559 | sessions = new_ts; | 579 | sessions = new_ts; |
diff --git a/shell/ash.c b/shell/ash.c index 4acc30110..4981f4ce0 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
| @@ -11909,7 +11909,8 @@ find_dot_file(char *name) | |||
| 11909 | */ | 11909 | */ |
| 11910 | return fullname; | 11910 | return fullname; |
| 11911 | } | 11911 | } |
| 11912 | stunalloc(fullname); | 11912 | if (fullname != name) |
| 11913 | stunalloc(fullname); | ||
| 11913 | } | 11914 | } |
| 11914 | 11915 | ||
| 11915 | /* not found in the PATH */ | 11916 | /* not found in the PATH */ |
