diff options
Diffstat (limited to 'release/src/router/httpd')
31 files changed, 4926 insertions, 1821 deletions
diff --git a/release/src/router/httpd/Makefile b/release/src/router/httpd/Makefile index 9e77c950..24e479f1 100644 --- a/release/src/router/httpd/Makefile +++ b/release/src/router/httpd/Makefile @@ -1,76 +1,42 @@ -# -# milli_httpd Makefile -# -# Copyright 2005, Broadcom Corporation -# All Rights Reserved. -# -# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY -# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM -# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -# -# $Id: Makefile,v 1.40.18.1.2.2 2006/02/07 10:56:31 honor Exp $ -# -include $(TOP)/.config +include ../common.mak -ifneq ($(wildcard $(SRCBASE)/cy_conf.mak),) - include $(SRCBASE)/cy_conf.mak -endif +CFLAGS = -O2 -Wall +CFLAGS += -I$(SRCBASE) -I$(SRCBASE)/include -I. -I$(TOP)/shared -CFLAGS += -I. -I$(TOP)/shared -I$(SRCBASE)/include -Wall -I$(SRCBASE)/ +OBJS = httpd.o cgi.o tomato.o version.o +OBJS += misc.o dhcp.o upgrade.o traceping.o parser.o upnp.o ctnf.o +OBJS += nvram.o log.o webio.o wl.o devlist.o ddns.o config.o bwm.o +OBJS += blackhole.o -#CFLAGS += -g -DDEBUG -CFLAGS += -s -O2 -LDFLAGS += -L$(TOP)/nvram -L$(INSTALLDIR)/nvram/usr/lib -lnvram -L$(TOP)/shared -L$(INSTALLDIR)/shared/usr/lib -lshared +LIBS = -L../nvram -lnvram -L../shared -lshared +LIBS += -L../mssl -lmssl +all: httpd -CFLAGS += -I$(TOP)/openssl/include -I$(TOP)/openssl/include/openssl -LDFLAGS += -L$(TOP)/openssl -L../openssl -lcrypto -lssl -OBJS += $(SRCBASE)/../tools/src/code_header.o backup_restore.o -OBJS += setup_wizard.o -OBJS += qos.o +httpd: $(OBJS) + @echo " [httpd] CC $@" + @$(CC) -o $@ $(OBJS) $(LIBS) + $(SIZECHECK) + $(CPTMP) -vpath %.c $(TOP)/shared -vpath %.o $(SRCBASE)/router/httpd/prebuilt - -all:clean httpd - -clean: - rm -f *.o *~ httpd - rm -f $(SRCBASE)/../tools/src/code_header.o - install: - install -D httpd $(INSTALLDIR)/usr/sbin/httpd - $(STRIP) $(INSTALLDIR)/usr/sbin/httpd - install -d $(INSTALLDIR)/etc - #install *.pem $(INSTALLDIR)/etc - install openssl.cnf $(INSTALLDIR)/etc - install -m 755 gencert.sh $(INSTALLDIR)/usr/sbin - -cert: - # create the key and certificate request - openssl req -new -out cert.csr -config openssl.cnf -keyout privkey.pem -days 3650 -newkey rsa:512 - # remove the passphrase from the key: - openssl rsa -in privkey.pem -out key.pem - # convert the certificate request into a signed certificate - openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem - rm -f cert.csr privkey.pem - # Show human-readable format - openssl x509 -in cert.pem -text -noout + @echo " [httpd] Installing to $(INSTALLDIR)" + @install -m 0500 -D httpd $(INSTALLDIR)/usr/sbin/httpd + @$(STRIP) $(INSTALLDIR)/usr/sbin/httpd -#qos_1.o:qos.o interface.o +clean: + rm -f httpd *.o .*.depend -httpd: cgi.o ej.o httpd.o broadcom.o \ - index.o status.o dhcp.o log.o upgrade.o filters.o forward.o dynamic_route.o static_route.o wireless.o ddns.o \ - find_pattern.o lib.o diag.o sysinfo.o wepkey.o md5c.o wl_test.o getservice.o $(OBJS) - $(CC) -o $@ $^ $(LDFLAGS) +size: httpd + mipsel-uclibc-nm --print-size --size-sort httpd -build_date.o: build_date.c -build_date: - echo "#define BUILD_DATE \"`date \"+%b %d %Y\"`\"" > build_date.c - echo "#define BUILD_TIME \"`date \"+%H:%M:%S\"`\"" >> build_date.c +%.o: %.c .%.depend + @echo " [httpd] CC $@" + @$(CC) $(CFLAGS) -o $@ -c $< +.%.depend: %.c + @$(CC) $(CFLAGS) -M $< > $@ -*.o: $(CY_DEPS) +-include $(OBJS:%.o=.%.depend) diff --git a/release/src/router/httpd/basic.c b/release/src/router/httpd/basic.c deleted file mode 100644 index 2eb88879..00000000 --- a/release/src/router/httpd/basic.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Basic skin (shtml) - * - * Copyright 2005, Broadcom Corporation - * All Rights Reserved. - * - * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY - * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM - * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * - * $Id: basic.c,v 1.1.1.7 2005/03/07 07:31:13 kanki Exp $ - */ - -#include <stdio.h> -#include <httpd.h> - -struct mime_handler mime_handlers[] = { - { "**.htm", "text/html", NULL, NULL, do_file, NULL }, - { "**.html", "text/html", NULL, NULL, do_file, NULL }, - { "**.gif", "image/gif", NULL, NULL, do_file, NULL }, - { "**.jpg", "image/jpeg", NULL, NULL, do_file, NULL }, - { "**.jpeg", "image/gif", NULL, NULL, do_file, NULL }, - { "**.png", "image/png", NULL, NULL, do_file, NULL }, - { "**.css", "text/css", NULL, NULL, do_file, NULL }, - { "**.au", "audio/basic", NULL, NULL, do_file, NULL }, - { "**.wav", "audio/wav", NULL, NULL, do_file, NULL }, - { "**.avi", "video/x-msvideo", NULL, NULL, do_file, NULL }, - { "**.mov", "video/quicktime", NULL, NULL, do_file, NULL }, - { "**.mpeg", "video/mpeg", NULL, NULL, do_file, NULL }, - { "**.vrml", "model/vrml", NULL, NULL, do_file, NULL }, - { "**.midi", "audio/midi", NULL, NULL, do_file, NULL }, - { "**.mp3", "audio/mpeg", NULL, NULL, do_file, NULL }, - { "**.pac", "application/x-ns-proxy-autoconfig", NULL, NULL, do_file, NULL }, - { NULL, NULL, NULL, NULL, NULL, NULL } -}; - -struct ej_handler ej_handlers[] = { - { NULL, NULL } -}; diff --git a/release/src/router/httpd/blackhole.c b/release/src/router/httpd/blackhole.c new file mode 100644 index 00000000..ab7df705 --- /dev/null +++ b/release/src/router/httpd/blackhole.c @@ -0,0 +1,183 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <time.h> + + +#ifdef BLACKHOLE +void wi_blackhole(char *url, int len, char *boundary) +{ + char buf[2048]; + int size; + int n; + time_t tick; + int foo; + const char *error; + int blen; + FILE *f; + + if (!post) { + send_header(200, NULL, mime_html, 0); + web_printf( + "<h1>Upload Test</h1>" + "<form method='post' action='blackhole.cgi?_http_id=%s' encType='multipart/form-data'>" + "<input type='file' name='file'><input type='submit'>" + "</form>", + nvram_safe_get("http_id")); + return; + } + + check_id(); + + cprintf("\nblackhole\n"); + cprintf("%s<\n", boundary); + + if ((blen = strlen(boundary)) == 0) { + error = "no boundary"; +ERROR: + cprintf("ERROR: %s\n", error); + + web_eat(len); + + send_header(200, NULL, mime_html, 0); + web_printf("ERROR: %s", error); + return; + } + + if (blen > (sizeof(buf) - 32)) { + error = "boundary is too big"; + goto ERROR; + } + + // --b\r\n + // <data>\r\n + // --b--\r\n + if (len < ((blen * 2) + 12)) { + error = "not enough data"; + goto ERROR; + } + + foo = 1; + while (len > 0) { + if (!web_getline(buf, MIN(len, sizeof(buf)))) { + break; + } + n = strlen(buf); + len -= n; + + if (n < 2) { + error = "n < 2"; + goto ERROR; + } + if (buf[--n] != '\n') { + error = "\\n not found"; + goto ERROR; + } + if (buf[--n] != '\r') { + error = "\\n without \\r"; + goto ERROR; + } + if (n == 0) break; + buf[n] = 0; + + cprintf("%s<\n", buf); + + if (foo) { + if ((buf[0] != '-') || (buf[1] != '-') || (strcmp(buf + 2, boundary) != 0)) { + error = "boundary not found on first line"; + goto ERROR; + } + foo = 0; + } + } + + if (foo != 0) { + error = "boundary not found before reaching end of header"; + goto ERROR; + } + + blen += 6; + len -= (blen + 2); + if (len < 0) { + error = "not enough data for end boundary"; + goto ERROR; + } + + unlink("/tmp/blackhole"); +/* if (len < (1*1024*1024)) f = fopen("/tmp/blackhole", "w"); + else*/ f = NULL; + +#if 0 + // read half, trigger tcp reset + len >>= 1; +#endif + + size = len; + tick = time(0); + while (len > 0) { + if ((n = web_read(buf, MIN(len, sizeof(buf)))) <= 0) { + break; + } + if (f) fwrite(buf, n, 1, f); + len -= n; + } + tick = time(0) - tick; + if (f) fclose(f); + + if (len > 0) { + error = "not all data was read"; + goto ERROR; + } + + if (web_read(buf, blen) != blen) { + error = "error while reading end boundary"; + goto ERROR; + } + buf[blen] = 0; + cprintf(">>%s<<\n", buf); + if ((strncmp(buf, "\r\n--", 4) != 0) || + (buf[blen - 1] != '-') || (buf[blen - 2] != '-') + || (strncmp(buf + 4, boundary, blen - 6) != 0)) { + error = "end boundary not found"; + goto ERROR; + } + + len += 2; + if (len > 0) { + if ((n = web_read(buf, MIN(len, sizeof(buf) - 1))) > 0) { + len -= n; + buf[n] = 0; + cprintf("last >>%s<<\n", buf); + } + } + + web_eat(len); + cprintf("len=%d\n", len); + + if (tick > 0) n = size / tick; + else n = 0; + + send_header(200, NULL, mime_html, 0); + web_printf( + "<pre>" + "Size .......: %d bytes\n" + "Time .......: %d seconds\n" + "Speed ......: %.2f kb/s | %.2f mb/s | %.2f KB/s | %.2f MB/s\n", + size, + tick, + n / 128.0, n / 131072.0, + n / 1024.0, n / 1048576.0); + if (f) { + web_pipecmd("md5sum /tmp/blackhole", WOF_NONE); + } + web_puts("</pre>"); + + cprintf("done...\n"); +} +#endif diff --git a/release/src/router/httpd/bwm.c b/release/src/router/httpd/bwm.c new file mode 100644 index 00000000..b7e1732c --- /dev/null +++ b/release/src/router/httpd/bwm.c @@ -0,0 +1,161 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <sys/stat.h> + +/* +#include <fcntl.h> +#include <errno.h> +#include <sys/wait.h> +#include <typedefs.h> +*/ + +static const char *hfn = "/var/lib/misc/rstats-history.gz"; + +void wo_bwmbackup(char *url) +{ + struct stat st; + time_t t; + int i; + + if (stat(hfn, &st) == 0) { + t = st.st_mtime; + sleep(1); + } + else { + t = 0; + } + killall("rstats", SIGHUP); + for (i = 10; i > 0; --i) { + if ((stat(hfn, &st) == 0) && (st.st_mtime != t)) break; + sleep(1); + } + if (i == 0) { + send_error(500, NULL, NULL); + return; + } + send_header(200, NULL, mime_binary, 0); + do_file((char *)hfn); +} + +void wi_bwmrestore(char *url, int len, char *boundary) +{ + char *buf; + const char *error; + int ok; + int n; + char tmp[64]; + + check_id(url); + + tmp[0] = 0; + buf = NULL; + error = "Error reading file"; + ok = 0; + + if (!skip_header(&len)) { + goto ERROR; + } + + if ((len < 64) || (len > 10240)) { + goto ERROR; + } + + if ((buf = malloc(len)) == NULL) { + error = "Not enough memory"; + goto ERROR; + } + + n = web_read(buf, len); + len -= n; + + sprintf(tmp, "%s.new", hfn); + if (f_write(tmp, buf, n, 0, 0600) != n) { + unlink(tmp); + error = "Error writing temporary file"; + goto ERROR; + } + f_write("/var/tmp/rstats-load", NULL, 0, 0, 0600); + killall("rstats", SIGHUP); + sleep(1); + + error = NULL; + rboot = 1; // used as "ok" + +ERROR: + free(buf); + web_eat(len); + if (error != NULL) resmsg_set(error); +} + +void wo_bwmrestore(char *url) +{ + if (rboot) { + redirect("/bwm-daily.asp"); + } + else { + parse_asp("error.asp"); + } +} + +void asp_netdev(int argc, char **argv) +{ + FILE *f; + char buf[256]; + unsigned long rx, tx; + char *p; + char *ifname; + char comma; + char *exclude; + + exclude = nvram_safe_get("rstats_exclude"); + web_puts("\n\nnetdev={"); + if ((f = fopen("/proc/net/dev", "r")) != NULL) { + fgets(buf, sizeof(buf), f); // header + fgets(buf, sizeof(buf), f); // " + comma = ' '; + while (fgets(buf, sizeof(buf), f)) { + if ((p = strchr(buf, ':')) == NULL) continue; + *p = 0; + if ((ifname = strrchr(buf, ' ')) == NULL) ifname = buf; + else ++ifname; +// if (strncmp(ifname, "ppp", 3) == 0) ifname = "ppp"; + if ((strcmp(ifname, "lo") == 0) || (find_word(exclude, ifname))) continue; + + // <rx bytes, packets, errors, dropped, fifo errors, frame errors, compressed, multicast><tx ...> + if (sscanf(p + 1, "%lu%*u%*u%*u%*u%*u%*u%*u%lu", &rx, &tx) != 2) continue; + web_printf("%c'%s':{rx:0x%lx,tx:0x%lx}", comma, ifname, rx, tx); + comma = ','; + } + fclose(f); + } + web_puts("};\n"); +} + +void asp_bandwidth(int argc, char **argv) +{ + char *name; + int sig; + + if ((nvram_get_int("rstats_enable") == 1) && (argc == 1)) { + if (strcmp(argv[0], "speed") == 0) { + sig = SIGUSR1; + name = "/var/spool/rstats-speed.js"; + } + else { + sig = SIGUSR2; + name = "/var/spool/rstats-history.js"; + } + unlink(name); + killall("rstats", sig); + f_wait_exists(name, 5); + do_file(name); + unlink(name); + } +} diff --git a/release/src/router/httpd/cert.pem b/release/src/router/httpd/cert.pem deleted file mode 100644 index 4fc12f2e..00000000 --- a/release/src/router/httpd/cert.pem +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICHDCCAcYCAQAwDQYJKoZIhvcNAQEEBQAwgZgxCzAJBgNVBAYTAlVTMRMwEQYD -VQQIEwpDYWxpZm9ybmlhMQ8wDQYDVQQHEwZJcnZpbmUxGjAYBgNVBAoTEUNpc2Nv -LUxpbmtzeXMsTENDMREwDwYDVQQLEwhEaXZpc2lvbjEQMA4GA1UEAxMHTGlua3N5 -czEiMCAGCSqGSIb3DQEJARYTc3VwcG9ydEBsaW5rc3lzLmNvbTAeFw0wNDA1MjAw -NTI1MTBaFw0wNDA2MTkwNTI1MTBaMIGYMQswCQYDVQQGEwJVUzETMBEGA1UECBMK -Q2FsaWZvcm5pYTEPMA0GA1UEBxMGSXJ2aW5lMRowGAYDVQQKExFDaXNjby1MaW5r -c3lzLExDQzERMA8GA1UECxMIRGl2aXNpb24xEDAOBgNVBAMTB0xpbmtzeXMxIjAg -BgkqhkiG9w0BCQEWE3N1cHBvcnRAbGlua3N5cy5jb20wXDANBgkqhkiG9w0BAQEF -AANLADBIAkEAvLeJgG1SIF0lP0caiBuK/2NEhX2oPJJX9VESl0eOkVn4KUkA2Vld -qNBT14X02nfdfEz7D1BLE0y/CRFI5JX0iQIDAQABMA0GCSqGSIb3DQEBBAUAA0EA -EEZKiLh5Xz7j64UBMIDXoxkNcgBFqO/+J2Sxv4seibnBFUam7z4peeq+6jJybaZF -fZk8bkGdhtAUiAY6U8kv/Q== ------END CERTIFICATE----- diff --git a/release/src/router/httpd/cgi.c b/release/src/router/httpd/cgi.c index 6cc6293b..11176540 100644 --- a/release/src/router/httpd/cgi.c +++ b/release/src/router/httpd/cgi.c @@ -3,7 +3,7 @@ * * Copyright 2005, Broadcom Corporation * All Rights Reserved. - * + * * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS @@ -12,123 +12,88 @@ * $Id: cgi.c,v 1.10 2005/03/07 08:35:32 kanki Exp $ */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> -#include <shutils.h> //Added by Dainel(2004-07-26) -#define assert(a) +#include "tomato.h" -#if defined(linux) -/* Use SVID search */ #define __USE_GNU #include <search.h> -#endif + /* CGI hash table */ -static struct hsearch_data htab; -static int htab_count; +static struct hsearch_data htab = { .table = NULL }; -static void -unescape(char *s) +static void unescape(char *s) { unsigned int c; while ((s = strpbrk(s, "%+"))) { - /* Parse %xx */ if (*s == '%') { sscanf(s + 1, "%02x", &c); *s++ = (char) c; - strncpy(s, s + 2, strlen(s) + 1); + strcpy(s, s + 2); } - /* Space is special */ - else if (*s == '+') + else if (*s == '+') { *s++ = ' '; + } } } -char * -get_cgi(char *name) +char *webcgi_get(const char *name) { ENTRY e, *ep; - if (!htab.table) - return NULL; + if (!htab.table) return NULL; - e.key = name; + e.key = (char *)name; hsearch_r(e, FIND, &ep, &htab); +// cprintf("%s=%s\n", name, ep ? ep->data : "(null)"); + return ep ? ep->data : NULL; } -void -set_cgi(char *name, char *value) +void webcgi_set(char *name, char *value) { ENTRY e, *ep; - //cprintf("\nIn set_cgi(), name = %s, value = %s\n", name, value); - - if (!htab.table) - return; + if (!htab.table) { + hcreate_r(16, &htab); + } e.key = name; hsearch_r(e, FIND, &ep, &htab); - if (ep){ - //cprintf("\nIn set_cgi(), ep = %s\n", ep); + if (ep) { ep->data = value; - } + } else { - //cprintf("\nIn set_cgi(), ep = %s(NULL)\n", ep); e.data = value; hsearch_r(e, ENTER, &ep, &htab); - htab_count++; } - assert(ep); } -void -init_cgi(char *query) +void webcgi_init(char *query) { - int len, nel; - char *q, *name, *value; + int nel; + char *q, *end, *name, *value; - htab_count = 0; + if (htab.table) hdestroy_r(&htab); + if (query == NULL) return; - //cprintf("\nIn init_cgi(), query = %s\n", query); - - /* Clear variables */ - if (!query) { - hdestroy_r(&htab); - return; - } - - /* Parse into individual assignments */ +// cprintf("query = %s\n", query); + + end = query + strlen(query); q = query; - len = strlen(query); nel = 1; - while (strsep(&q, "&;")) + while (strsep(&q, "&;")) { nel++; + } hcreate_r(nel, &htab); - //cprintf("\nIn init_cgi(), nel = %d\n", nel); - for (q = query; q < (query + len);) { - /* Unescape each assignment */ - unescape(name = value = q); + for (q = query; q < end; ) { + value = q; + q += strlen(q) + 1; - /* Skip to next assignment */ - for (q += strlen(q); q < (query + len) && !*q; q++); - - /* Assign variable */ + unescape(value); name = strsep(&value, "="); - if (value) - set_cgi(name, value); + if (value) webcgi_set(name, value); } - //cprintf("\nIn init_cgi(), AFTER PROCESS query = %s\n", query); -} - -int -count_cgi() -{ - return htab_count; } diff --git a/release/src/router/httpd/config.c b/release/src/router/httpd/config.c new file mode 100644 index 00000000..52e4f5c5 --- /dev/null +++ b/release/src/router/httpd/config.c @@ -0,0 +1,180 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <typedefs.h> +#include <sys/reboot.h> + +// #define DEBUG + +#ifdef DEBUG +#define NVRAMCMD "/tmp/nvram" +#else +#define NVRAMCMD "nvram" +#endif + +void wo_defaults(char *url) +{ + const char *v; + int mode; + + if ((v = webcgi_get("mode")) != NULL) { + mode = atoi(v); + if ((mode == 1) || (mode == 2)) { + prepare_upgrade(); + + parse_asp("reboot-default.asp"); + web_close(); + + killall("pppoecd", SIGTERM); + + led(LED_DIAG, 1); + sleep(2); + + if (mode == 1) { + // eval(NVRAMCMD, "defaults", "--yes"); + nvram_set("restore_defaults", "1"); + nvram_commit(); + } + else { + eval("mtd-erase", "-d", "nvram"); + } + + set_action(ACT_REBOOT); + // kill(1, SIGTERM); + reboot(RB_AUTOBOOT); + exit(0); + } + } + + redirect("/admin-config.asp"); +} + +void wo_backup(char *url) +{ + char tmp[64]; + char msg[64]; + static char *args[] = { + NVRAMCMD, "backup", NULL, NULL + }; + + strcpy(tmp, "/tmp/backupXXXXXX"); + mktemp(tmp); + args[2] = tmp; + + sprintf(msg, ">%s.msg", tmp); + + if (_eval(args, msg, 0, NULL) == 0) { + send_header(200, NULL, mime_binary, 0); + do_file(tmp); + unlink(tmp); + } + else { + resmsg_fread(msg + 1); + send_header(200, NULL, mime_html, 0); + parse_asp("error.asp"); + } + + unlink(msg + 1); +} + +void wi_restore(char *url, int len, char *boundary) +{ + char *buf; + const char *error; + int ok; + int n; + char tmp[64]; + + check_id(url); + + tmp[0] = 0; + buf = NULL; + error = "Error reading file"; + ok = 0; + + if (!skip_header(&len)) { + goto ERROR; + } + + if ((len < 64) || (len > (NVRAM_SPACE * 2))) { + error = "Invalid file"; + goto ERROR; + } + + if ((buf = malloc(len)) == NULL) { + error = "Not enough memory"; + goto ERROR; + } + + n = web_read(buf, len); + len -= n; + + strcpy(tmp, "/tmp/restoreXXXXXX"); + mktemp(tmp); + if (f_write(tmp, buf, n, 0, 0600) != n) { + error = "Error writing temporary file"; + goto ERROR; + } + + rboot = 1; + prepare_upgrade(); + + char msg[64]; + static char *args[] = { + NVRAMCMD, "restore", NULL, NULL + }; + + args[2] = tmp; + + sprintf(msg, ">%s.msg", tmp); + + if (_eval(args, msg, 0, NULL) != 0) { + resmsg_fread(msg + 1); + } +#ifndef DEBUG + unlink(msg + 1); +#endif + error = NULL; + +ERROR: + free(buf); + if (error != NULL) resmsg_set(error); + web_eat(len); +#ifndef DEBUG + if (tmp[0]) unlink(tmp); +#endif +} + + +void wo_restore(char *url) +{ + if (rboot) { + parse_asp("reboot.asp"); + web_close(); + + killall("pppoecd", SIGTERM); + sleep(2); + +#ifdef DEBUG + cprintf("---reboot=%d\n", rboot); +#else + set_action(ACT_REBOOT); + // kill(1, SIGTERM); + sync(); + reboot(RB_AUTOBOOT); +#endif + exit(0); + } + + parse_asp("error.asp"); +} diff --git a/release/src/router/httpd/ctnf.c b/release/src/router/httpd/ctnf.c new file mode 100644 index 00000000..f65aa35c --- /dev/null +++ b/release/src/router/httpd/ctnf.c @@ -0,0 +1,302 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> +#include <sys/sysinfo.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <time.h> +#include <dirent.h> + + +static void ctvbuf(FILE *f) +{ + int n; + struct sysinfo si; +// meminfo_t mem; + +#if 1 + const char *p; + + if ((p = nvram_get("ct_max")) != NULL) { + n = atoi(p); + if (n == 0) n = 2048; + else if (n < 1024) n = 1024; + else if (n > 10240) n = 10240; + } + else { + n = 2048; + } +#else + char s[64]; + + if (f_read_string("/proc/sys/net/ipv4/ip_conntrack_max", s, sizeof(s)) > 0) n = atoi(s); + else n = 1024; + if (n < 1024) n = 1024; + else if (n > 10240) n = 10240; +#endif + + n *= 170; // avg tested + +// get_memory(&mem); +// if (mem.maxfreeram < (n + (64 * 1024))) n = mem.maxfreeram - (64 * 1024); + + sysinfo(&si); + if (si.freeram < (n + (64 * 1024))) n = si.freeram - (64 * 1024); + +// cprintf("free: %dK, buffer: %dK\n", si.freeram / 1024, n / 1024); + + if (n > 4096) { +// n = + setvbuf(f, NULL, _IOFBF, n); +// cprintf("setvbuf = %d\n", n); + } +} + +void asp_ctcount(int argc, char **argv) +{ + static const char *states[10] = { + "NONE", "ESTABLISHED", "SYN_SENT", "SYN_RECV", "FIN_WAIT", + "TIME_WAIT", "CLOSE", "CLOSE_WAIT", "LAST_ACK", "LISTEN" }; + int count[13]; // tcp(10) + udp(2) + total(1) = 13 / max classes = 10 + FILE *f; + char s[512]; + char *p; + int i; + int n; + int mode; + unsigned long rip; + unsigned long lan; + unsigned long mask; + + if (argc != 1) return; + mode = atoi(argv[0]); + + memset(count, 0, sizeof(count)); + + if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) { + ctvbuf(f); // if possible, read in one go + + if (nvram_match("t_hidelr", "1")) { + mask = inet_addr(nvram_safe_get("lan_netmask")); + rip = inet_addr(nvram_safe_get("lan_ipaddr")); + lan = rip & mask; + } + else { + rip = lan = mask = 0; + } + + while (fgets(s, sizeof(s), f)) { + if (rip != 0) { + // src=x.x.x.x dst=x.x.x.x // DIR_ORIGINAL + if ((p = strstr(s + 14, "src=")) == NULL) continue; + if ((inet_addr(p + 4) & mask) == lan) { + if ((p = strstr(p + 13, "dst=")) == NULL) continue; + if (inet_addr(p + 4) == rip) continue; + } + } + + if (mode == 0) { + // count connections per state + if (strncmp(s, "tcp", 3) == 0) { + for (i = 9; i >= 0; --i) { + if (strstr(s, states[i]) != NULL) { + count[i]++; + break; + } + } + } + else if (strncmp(s, "udp", 3) == 0) { + if (strstr(s, "[UNREPLIED]") != NULL) { + count[10]++; + } + else if (strstr(s, "[ASSURED]") != NULL) { + count[11]++; + } + } + count[12]++; + } + else { + // count connections per mark + if ((p = strstr(s, " mark=")) != NULL) { + n = atoi(p + 6) & 0xFF; + if (n <= 10) count[n]++; + } + } + } + + fclose(f); + } + + if (mode == 0) { + p = s; + for (i = 0; i < 12; ++i) { + p += sprintf(p, ",%d", count[i]); + } + web_printf("\nconntrack = [%d%s];\n", count[12], s); + } + else { + p = s; + for (i = 1; i < 11; ++i) { + p += sprintf(p, ",%d", count[i]); + } + web_printf("\nnfmarks = [%d%s];\n", count[0], s); + } +} + +void asp_ctdump(int argc, char **argv) +{ + FILE *f; + char s[512]; + char *p, *q; + int mark; + int findmark; + unsigned int proto; + unsigned int time; + char src[16]; + char dst[16]; + char sport[16]; + char dport[16]; + unsigned long rip; + unsigned long lan; + unsigned long mask; + char comma; + + if (argc != 1) return; + + findmark = atoi(argv[0]); + + mask = inet_addr(nvram_safe_get("lan_netmask")); + rip = inet_addr(nvram_safe_get("lan_ipaddr")); + lan = rip & mask; + if (nvram_match("t_hidelr", "0")) rip = 0; // hide lan -> router? + + web_puts("\nctdump = ["); + comma = ' '; + if ((f = fopen("/proc/net/ip_conntrack", "r")) != NULL) { + ctvbuf(f); + while (fgets(s, sizeof(s), f)) { + if ((p = strstr(s, " mark=")) == NULL) continue; + if ((mark = (atoi(p + 6) & 0xFF)) > 10) mark = 0; + if ((findmark != -1) && (mark != findmark)) continue; + + if (sscanf(s, "%*s %u %u", &proto, &time) != 2) continue; + + if ((p = strstr(s + 14, "src=")) == NULL) continue; // DIR_ORIGINAL + if ((inet_addr(p + 4) & mask) != lan) { + // make sure we're seeing int---ext if possible + if ((p = strstr(p + 41, "src=")) == NULL) continue; // DIR_REPLY + } + else if (rip != 0) { + if ((q = strstr(p + 13, "dst=")) == NULL) continue; +// cprintf("%lx=%lx\n", inet_addr(q + 4), rip); + if (inet_addr(q + 4) == rip) continue; + } + + if ((proto == 6) || (proto == 17)) { + if (sscanf(p + 4, "%s dst=%s sport=%s dport=%s", src, dst, sport, dport) != 4) continue; + } + else { + if (sscanf(p + 4, "%s dst=%s", src, dst) != 2) continue; + sport[0] = 0; + dport[0] = 0; + } + + web_printf("%c[%u,%u,'%s','%s','%s','%s',%d]", comma, proto, time, src, dst, sport, dport, mark); + comma = ','; + } + } + web_puts("];\n"); +} + +void asp_qrate(int argc, char **argv) +{ + FILE *f; + char s[256]; + unsigned long rates[10]; + unsigned long u; + char *e; + int n; + char comma; + char *a[1]; + + a[0] = "1"; + asp_ctcount(1, a); + + memset(rates, 0, sizeof(rates)); + sprintf(s, "tc -s class ls dev %s", nvram_safe_get("wan_iface")); + if ((f = popen(s, "r")) != NULL) { + n = 1; + while (fgets(s, sizeof(s), f)) { + if (strncmp(s, "class htb 1:", 12) == 0) { + n = atoi(s + 12); + } + else if (strncmp(s, " rate ", 6) == 0) { + if ((n % 10) == 0) { + n /= 10; + if ((n >= 1) && (n <= 10)) { + u = strtoul(s + 6, &e, 10); + if (*e == 'K') u *= 1000; + else if (*e == 'M') u *= 1000 * 1000; + rates[n - 1] = u; + n = 1; + } + } + } + } + pclose(f); + } + + comma = ' '; + web_puts("\nqrates = [0,"); + for (n = 0; n < 10; ++n) { + web_printf("%c%lu", comma, rates[n]); + comma = ','; + } + web_puts("];"); +} + +static void layer7_list(const char *path, int *first) +{ + DIR *dir; + struct dirent *de; + char *p; + char name[NAME_MAX]; + + if ((dir = opendir(path)) != NULL) { + while ((de = readdir(dir)) != NULL) { + strlcpy(name, de->d_name, sizeof(name)); + if ((p = strstr(name, ".pat")) == NULL) continue; + *p = 0; + web_printf("%s'%s'", *first ? "" : ",", name); + *first = 0; + } + closedir(dir); + } +} + +void asp_layer7(int argc, char **argv) +{ + int first = 1; + web_puts("\nlayer7 = ["); + layer7_list("/etc/l7-extra", &first); + layer7_list("/etc/l7-protocols", &first); + web_puts("];\n"); +} + +void wo_expct(char *url) +{ + f_write_string("/proc/net/expire_early", "15", 0, 0); +} diff --git a/release/src/router/httpd/ddns.c b/release/src/router/httpd/ddns.c new file mode 100644 index 00000000..2863cf72 --- /dev/null +++ b/release/src/router/httpd/ddns.c @@ -0,0 +1,90 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <time.h> +#include <sys/stat.h> + + +void asp_ddnsx(int argc, char **argv) +{ + char *p, *q; + int i; + char s[256]; + char m[256]; + char name[64]; + time_t tt; + struct stat st; + + switch (get_wan_proto()) { + case WP_PPTP: + p = "pptp_get_ip"; + break; + case WP_L2TP: + p = "l2tp_get_ip"; + break; + default: + p = "wan_ipaddr"; + break; + } + + web_printf( + "\nddnsx_ip = '%s';\n" + "ddnsx_msg = [", + nvram_safe_get(p)); + + for (i = 0; i < 2; ++i) { + web_puts(i ? "','" : "'"); + sprintf(name, "/var/lib/mdu/ddnsx%d.msg", i); + f_read_string(name, m, sizeof(m)); // null term'd even on error + if (m[0] != 0) { + if ((stat(name, &st) == 0) && (st.st_mtime > Y2K)) { + strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z: ", localtime(&st.st_mtime)); + web_puts(s); + } + web_putj(m); + } + } + + web_puts("'];\nddnsx_last = ["); + + for (i = 0; i < 2; ++i) { + web_puts(i ? "','" : "'"); + sprintf(name, "ddnsx%d", i); + if (!nvram_match(name, "")) { + sprintf(name, "ddnsx%d_cache", i); + if ((p = nvram_get(name)) == NULL) continue; + tt = strtoul(p, &q, 10); + if (*q++ != ',') continue; + if (tt > Y2K) { + strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z: ", localtime(&tt)); + web_puts(s); + } + web_putj(q); + } + } + web_puts("'];\n"); +} + +void asp_ddnsx_ip(int argc, char **argv) +{ + const char *p; + + switch (get_wan_proto()) { + case WP_PPTP: + p = "pptp_get_ip"; + break; + case WP_L2TP: + p = "l2tp_get_ip"; + break; + default: + p = "wan_ipaddr"; + break; + } + web_puts(nvram_safe_get(p)); +} diff --git a/release/src/router/httpd/devlist.c b/release/src/router/httpd/devlist.c new file mode 100644 index 00000000..b72fd58b --- /dev/null +++ b/release/src/router/httpd/devlist.c @@ -0,0 +1,229 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <wlutils.h> + + +void asp_arplist(int argc, char **argv) +{ + FILE *f; + char s[512]; + char ip[16]; + char mac[18]; + char dev[17]; + char comma; + unsigned int flags; + + /* + cat /proc/net/arp + IP address HW type Flags HW address Mask Device + 192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1 + */ + + web_puts("\narplist = ["); + comma = ' '; + if ((f = fopen("/proc/net/arp", "r")) != NULL) { + while (fgets(s, sizeof(s), f)) { + if (sscanf(s, "%15s %*s 0x%X %17s %*s %16s", ip, &flags, mac, dev) != 4) continue; + if ((strlen(mac) != 17) || (strcmp(mac, "00:00:00:00:00:00") == 0)) continue; + if (flags == 0) continue; +// if ((nvram_match("wan_ifname", dev)) && (!nvram_match("wan_ipaddr", ip))) continue; // half + web_printf("%c['%s','%s','%s']", comma, ip, mac, dev); + comma = ','; + } + fclose(f); + } + web_puts("];\n"); +} + +// checkme: any easier way to do this? zzz +static int get_wds_ifname(const struct ether_addr *ea, char *ifname) +{ + struct ifreq ifr; + int sd; + int i; + struct ether_addr e; + + if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) >= 0) { + // wds doesn't show up under SIOCGIFCONF; seems to start at 17 (?) + for (i = 1; i < 32; ++i) { + ifr.ifr_ifindex = i; + if ((ioctl(sd, SIOCGIFNAME, &ifr) == 0) && + (strncmp(ifr.ifr_name, "wds", 3) == 0) && + (wl_ioctl(ifr.ifr_name, WLC_WDS_GET_REMOTE_HWADDR, &e.octet, sizeof(e.octet)) == 0)) { + if (memcmp(ea->octet, e.octet, sizeof(e.octet)) == 0) { + close(sd); + strlcpy(ifname, ifr.ifr_name, 16); + return 1; + } + } + } + close(sd); + } + return 0; +} + +void asp_devlist(int argc, char **argv) +{ + char *p; + FILE *f; + char buf[1024]; + int i; + char comma; + + // must be here for easier call via update.cgi. arg is ignored + asp_arplist(0, NULL); + asp_wlnoise(0, NULL); + + // + + p = js_string(nvram_safe_get("dhcpd_static")); + web_printf("dhcpd_static = '%s'.split('>');\n", p ? p : ""); + free(p); + + // + +#if 1 + char *wlif; + scb_val_t rssi; + sta_info_t sti; + int cmd; + struct maclist *mlist; + int mlsize; + char ifname[16]; + + web_puts("wldev = ["); + comma = ' '; + mlsize = sizeof(struct maclist) + (255 * sizeof(struct ether_addr)); + if ((mlist = malloc(mlsize)) != NULL) { + wlif = nvram_safe_get("wl0_ifname"); + cmd = WLC_GET_ASSOCLIST; + while (1) { + mlist->count = 255; + if (wl_ioctl(wlif, cmd, mlist, mlsize) == 0) { + for (i = 0; i < mlist->count; ++i) { + rssi.ea = mlist->ea[i]; + rssi.val = 0; + if (wl_ioctl(wlif, WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0) continue; + + // sta_info0<mac> + memset(&sti, 0, sizeof(sti)); + strcpy((char *)&sti, "sta_info"); + memcpy((char *)&sti + 9, rssi.ea.octet, 6); + if (wl_ioctl(wlif, WLC_GET_VAR, &sti, sizeof(sti)) != 0) continue; + + p = wlif; + if (sti.flags & WL_STA_WDS) { + if (cmd != WLC_GET_WDSLIST) continue; + if ((sti.flags & WL_WDS_LINKUP) == 0) continue; + if (get_wds_ifname(&rssi.ea, ifname)) p = ifname; + } + + web_printf("%c['%s','%s',%d]", + comma, + p, + ether_etoa(rssi.ea.octet, buf), + rssi.val); + comma = ','; + } + } + if (cmd == WLC_GET_WDSLIST) break; + cmd = WLC_GET_WDSLIST; + } + free(mlist); + } +#else + char *wlif; + scb_val_t rssi; + sta_info_t sti; + int j; + struct maclist *mlist; + int mlsize; + char ifname[16]; + + web_puts("wldev = ["); + comma = ' '; + mlsize = sizeof(struct maclist) + (127 * sizeof(struct ether_addr)); + if ((mlist = malloc(mlsize)) != NULL) { + for (j = 0; j < 2; ++j) { + wlif = nvram_safe_get("wl0_ifname"); + strcpy((char *)mlist, j ? "autho_sta_list" : "authe_sta_list"); + if (wl_ioctl(wlif, WLC_GET_VAR, mlist, mlsize) == 0) { + for (i = 0; i < mlist->count; ++i) { + rssi.ea = mlist->ea[i]; + rssi.val = 0; + if (wl_ioctl(wlif, WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0) continue; + + // sta_info0<mac> + memset(&sti, 0, sizeof(sti)); + strcpy((char *)&sti, "sta_info"); + memcpy((char *)&sti + 9, rssi.ea.octet, 6); + if (wl_ioctl(wlif, WLC_GET_VAR, &sti, sizeof(sti)) != 0) continue; + + p = wlif; + if (sti.flags & WL_STA_WDS) { + if ((sti.flags & WL_WDS_LINKUP) == 0) continue; + if (get_wds_ifname(&rssi.ea, ifname)) p = ifname; + } + + web_printf("%c['%s','%s',%d]", + comma, + p, + ether_etoa(rssi.ea.octet, buf), + rssi.val); + comma = ','; + } + } + } + free(mlist); + } +#endif + + web_puts("];\n"); + + // + + unsigned long expires; + char mac[32]; + char ip[32]; + char hostname[256]; + char *host; + + web_puts("dhcpd_lease = ["); + if (nvram_match("lan_proto", "dhcp")) { + f_write("/var/tmp/dhcp/leases.!", NULL, 0, 0, 0666); + + // dump the leases to a file + if (killall("dnsmasq", SIGUSR2) == 0) { + // helper in dnsmasq will remove this when it's done + f_wait_notexists("/var/tmp/dhcp/leases.!", 5); + } + + if ((f = fopen("/var/tmp/dhcp/leases", "r")) != NULL) { + comma = ' '; + while (fgets(buf, sizeof(buf), f)) { + if (sscanf(buf, "%lu %17s %15s %255s", &expires, mac, ip, hostname) != 4) continue; + host = js_string((hostname[0] == '*') ? "" : hostname); + web_printf("%c['%s','%s','%s','%s']", comma, + (host ? host : ""), ip, mac, ((expires == 0) ? "non-expiring" : reltime(buf, expires))); + free(host); + comma = ','; + } + fclose(f); + } + unlink("/var/tmp/dhcp/leases"); + } + web_puts("];"); +} diff --git a/release/src/router/httpd/dhcp.c b/release/src/router/httpd/dhcp.c new file mode 100644 index 00000000..aef5bcd3 --- /dev/null +++ b/release/src/router/httpd/dhcp.c @@ -0,0 +1,62 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <sys/sysinfo.h> +#include <sys/stat.h> +#include <sys/types.h> + + +void asp_dhcpc_time(int argc, char **argv) +{ + long exp; + struct sysinfo si; + long n; + int r; + char buf[32]; + + if (using_dhcpc()) { + exp = 0; + r = f_read_string("/var/lib/misc/dhcpc.expires", buf, sizeof(buf)); + if (r > 0) { + n = atol(buf); + if (n > 0) { + sysinfo(&si); + exp = n - si.uptime; + } + } + web_puts(reltime(buf, exp)); + } +} + +void wo_dhcpc(char *url) +{ + char *p; + + if ((p = webcgi_get("exec")) != NULL) { + if (strcmp(p, "release") == 0) eval("dhcpc-release"); + else if (strcmp(p, "renew") == 0) eval("dhcpc-renew"); + } + common_redirect(); +} + + +// ----------------------------------------------------------------------------- + + +void wo_dhcpd(char *url) +{ + char *p; + + if ((p = webcgi_get("remove")) != NULL) { + f_write_string("/var/tmp/dhcp/delete", p, FW_CREATE|FW_NEWLINE, 0666); + killall("dnsmasq", SIGUSR2); + f_wait_notexists("/var/tmp/dhcp/delete", 5); + } + web_puts("{}"); +} diff --git a/release/src/router/httpd/ej.c b/release/src/router/httpd/ej.c deleted file mode 100644 index d94aa601..00000000 --- a/release/src/router/httpd/ej.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Tiny Embedded JavaScript parser - * - * Copyright 2005, Broadcom Corporation - * All Rights Reserved. - * - * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY - * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM - * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * - * $Id: ej.c,v 1.9 2005/03/07 08:35:32 kanki Exp $ - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> - -#include "httpd.h" - -static char * get_arg(char *args, char **next); -//static void call(char *func, FILE *stream); -static void call(char *func, webs_t stream); - -/* Look for unquoted character within a string */ -static char * -unqstrstr(char *haystack, char *needle) -{ - char *cur; - int q; - - for (cur = haystack, q = 0; - cur < &haystack[strlen(haystack)] && !(!q && !strncmp(needle, cur, strlen(needle))); - cur++) { - if (*cur == '"') - q ? q-- : q++; - } - return (cur < &haystack[strlen(haystack)]) ? cur : NULL; -} - -static char * -get_arg(char *args, char **next) -{ - char *arg, *end; - - /* Parse out arg, ... */ - if (!(end = unqstrstr(args, ","))) { - end = args + strlen(args); - *next = NULL; - } else - *next = end + 1; - - /* Skip whitespace and quotation marks on either end of arg */ - for (arg = args; isspace((int)*arg) || *arg == '"'; arg++); - for (*end-- = '\0'; isspace((int)*end) || *end == '"'; end--) - *end = '\0'; - - return arg; -} - -static void -//call(char *func, FILE *stream) -call(char *func, webs_t stream) //jimmy, https, 8/4/2003 -{ - char *args, *end, *next; - int argc; - char * argv[16]; - struct ej_handler *handler; - - /* Parse out ( args ) */ - if (!(args = strchr(func, '('))) - return; - if (!(end = unqstrstr(func, ")"))) - return; - *args++ = *end = '\0'; - - /* Set up argv list */ - for (argc = 0; argc < 16 && args; argc++, args = next) { - if (!(argv[argc] = get_arg(args, &next))) - break; - } - - /* Call handler */ - for (handler = &ej_handlers[0]; handler->pattern; handler++) { - //if (strncmp(handler->pattern, func, strlen(handler->pattern)) == 0) - if (strcmp(handler->pattern, func) == 0) - handler->output(0, stream, argc, argv); - } -} - -void -//do_ej(char *path, FILE *stream) -do_ej(char *path, webs_t stream) // jimmy, https, 8/4/2003 -{ - FILE *fp; - int c; - char pattern[1000], *asp = NULL, *func = NULL, *end = NULL; - int len = 0; - - if (!(fp = fopen(path, "r"))) - return; - - while ((c = getc(fp)) != EOF) { - - /* Add to pattern space */ - pattern[len++] = c; - pattern[len] = '\0'; - if (len == (sizeof(pattern) - 1)) - goto release; - - - /* Look for <% ... */ - if (!asp && !strncmp(pattern, "<%", len)) { - if (len == 2) - asp = pattern + 2; - continue; - } - - /* Look for ... %> */ - if (asp) { - if (unqstrstr(asp, "%>")) { - for (func = asp; func < &pattern[len]; func = end) { - /* Skip initial whitespace */ - for (; isspace((int)*func); func++); - if (!(end = unqstrstr(func, ";"))) - break; - *end++ = '\0'; - - /* Call function */ - call(func, stream); - } - asp = NULL; - len = 0; - } - continue; - } - - release: - /* Release pattern space */ - //fputs(pattern, stream); - if(wfputs(pattern, stream) == EOF) break; //jimmy, https, 8/4/2003 - len = 0; - } - - fclose(fp); -} - -int -ejArgs(int argc, char **argv, char *fmt, ...) -{ - va_list ap; - int arg; - char *c; - - if (!argv) - return 0; - - va_start(ap, fmt); - for (arg = 0, c = fmt; c && *c && arg < argc;) { - if (*c++ != '%') - continue; - switch (*c) { - case 'd': - *(va_arg(ap, int *)) = atoi(argv[arg]); - break; - case 's': - *(va_arg(ap, char **)) = argv[arg]; - break; - } - arg++; - } - va_end(ap); - - return arg; -} diff --git a/release/src/router/httpd/gencert.sh b/release/src/router/httpd/gencert.sh index 52e64d96..8a1f837e 100755 --- a/release/src/router/httpd/gencert.sh +++ b/release/src/router/httpd/gencert.sh @@ -1,18 +1,29 @@ #!/bin/sh +SECS=1167609600 -SECS=$1 +cd /etc + +NVCN=`nvram get https_crt_cn` +if [ "$NVCN" == "" ]; then + NVCN=`nvram get lan_ipaddr` +fi + +cp -L openssl.cnf openssl.config + +I=0 +for CN in $NVCN; do + echo "$I.commonName=CN" >> openssl.config + echo "$I.commonName_value=$CN" >> openssl.config + I=$(($I + 1)) +done # create the key and certificate request -openssl req -new -out /tmp/cert.csr -config /etc/openssl.cnf -keyout /tmp/privkey.pem -newkey rsa:512 -passout pass:password +openssl req -new -out /tmp/cert.csr -config openssl.config -keyout /tmp/privkey.pem -newkey rsa:512 -passout pass:password # remove the passphrase from the key -openssl rsa -in /tmp/privkey.pem -out /tmp/key.pem -passin pass:password +openssl rsa -in /tmp/privkey.pem -out key.pem -passin pass:password # convert the certificate request into a signed certificate -if test "$SECS" -eq "" ; then - openssl x509 -in /tmp/cert.csr -out /tmp/cert.pem -req -signkey /tmp/key.pem -days 3650 -else - openssl x509 -in /tmp/cert.csr -out /tmp/cert.pem -req -signkey /tmp/key.pem -days 3650 -setstartsecs $SECS -fi -# Show human-readable format -openssl x509 -in /tmp/cert.pem -text -noout -# Remove unused files -rm -f /tmp/cert.csr /tmp/privkey.pem +openssl x509 -in /tmp/cert.csr -out cert.pem -req -signkey key.pem -setstartsecs $SECS -days 3653 -set_serial $1 + +# openssl x509 -in /etc/cert.pem -text -noout + +rm -f /tmp/cert.csr /tmp/privkey.pem openssl.config diff --git a/release/src/router/httpd/httpd.c b/release/src/router/httpd/httpd.c index 4a3288e3..034b7468 100644 --- a/release/src/router/httpd/httpd.c +++ b/release/src/router/httpd/httpd.c @@ -1,1202 +1,847 @@ +/* + + micro_httpd/mini_httpd + + Copyright © 1999,2000 by Jef Poskanzer <jef@acme.com>. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ /* - ********************************************************* - * Copyright 2003, CyberTAN Inc. All Rights Reserved * - ********************************************************* - This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc. - the contents of this file may not be disclosed to third parties, - copied or duplicated in any form without the prior written - permission of CyberTAN Inc. + Copyright 2003, CyberTAN Inc. All Rights Reserved + + This is UNPUBLISHED PROPRIETARY SOURCE CODE of CyberTAN Inc. + the contents of this file may not be disclosed to third parties, + copied or duplicated in any form without the prior written + permission of CyberTAN Inc. - This software should be used as a reference only, and it not - intended for production use! + This software should be used as a reference only, and it not + intended for production use! + THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY + KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN + SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE - THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY - KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN - SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE */ +/* + + Modified for Tomato Firmware + Portions, Copyright (C) 2006-2009 Jonathan Zarate -/* milli_httpd - pretty small HTTP server -** A combination of -** micro_httpd - really small HTTP server -** and -** mini_httpd - small HTTP server -** -** Copyright © 1999,2000 by Jef Poskanzer <jef@acme.com>. -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -** SUCH DAMAGE. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "tomato.h" #include <errno.h> #include <fcntl.h> #include <time.h> -#include <unistd.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <getopt.h> #include <stdarg.h> -#include <syslog.h> - -#include <cy_conf.h> -#include "httpd.h" -#include <bcmnvram.h> -#include <code_pattern.h> -#include <utils.h> -#include <shutils.h> -#if defined(HTTPS_SUPPORT) -#include <openssl/ssl.h> -#include <openssl/err.h> -#endif -#ifdef HSIAB_SUPPORT -#include <hsiabutils.h> -#define MAX_BUF_LEN 254 -#endif - +#include <sys/wait.h> #include <error.h> #include <sys/signal.h> +#include <netinet/tcp.h> +#include <sys/stat.h> + +#include <wlutils.h> + + +#include "../mssl/mssl.h" +int do_ssl; -#define SERVER_NAME "httpd" -//#define SERVER_PORT 80 -#define PROTOCOL "HTTP/1.0" -#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT" -#define TIMEOUT 1 - -/* A multi-family sockaddr. */ -typedef union { - struct sockaddr sa; - struct sockaddr_in sa_in; - } usockaddr; - -/* Globals. */ -#if defined(HTTPS_SUPPORT) // jimmy, https, 8/4/2003 - static SSL * ssl; -#define DEFAULT_HTTPS_PORT 443 -#define CERT_FILE "/tmp/cert.pem" -#define KEY_FILE "/tmp/key.pem" -//#define DEBUG_CIPHER -#endif -#ifdef DEBUG_CIPHER -char *set_ciphers = NULL; -int get_ciphers = 0; -#endif -#define DEFAULT_HTTP_PORT 80 -extern int do_ssl; -int server_port; -char pid_file[80]; -#ifdef SAMBA_SUPPORT -extern int smb_getlock; -extern int httpd_fork; -void smb_handler() -{ - printf("============child exit=====waitting ...====\n"); - smb_getlock=0; - wait(NULL); - printf("wait finish \n"); -} -#endif -//static FILE *conn_fp; -static webs_t conn_fp; // jimmy, https, 8/4/2003 -static char auth_userid[AUTH_MAX]; -static char auth_passwd[AUTH_MAX]; -static char auth_realm[AUTH_MAX]; -#ifdef MULTIPLE_LOGIN_SUPPORT -static char auth_id_pw[AUTH_MAX]; -static char auth_mod[AUTH_MAX]; -#endif -#ifdef GET_POST_SUPPORT int post; -#endif -int auth_fail = 0; -int httpd_level; - -char http_client_ip[20]; -extern char *get_mac_from_ip(char *ip); - -/* Forwards. */ -static int initialize_listen_socket( usockaddr* usaP ); -static int auth_check( char* dirname, char* authorization ); -static void send_authenticate( char* realm ); -static void send_error( int status, char* title, char* extra_header, char* text ); -static void send_headers( int status, char* title, char* extra_header, char* mime_type ); -static int b64_decode( const char* str, unsigned char* space, int size ); -static int match( const char* pattern, const char* string ); -static int match_one( const char* pattern, int patternlen, const char* string ); +int listenfd; +int connfd = -1; +FILE *connfp = NULL; +struct sockaddr_in clientsai; +int header_sent; +char *user_agent; +// int hidok = 0; + +const char mime_html[] = "text/html; charset=utf-8"; +const char mime_plain[] = "text/plain"; +const char mime_javascript[] = "text/javascript"; +const char mime_binary[] = "application/tomato-binary-file"; // instead of "application/octet-stream" to make browser just "save as" and prevent automatic detection weirdness -- zzz +const char mime_octetstream[] = "application/octet-stream"; + +static int match(const char* pattern, const char* string); +static int match_one(const char* pattern, int patternlen, const char* string); static void handle_request(void); -static int -initialize_listen_socket( usockaddr* usaP ) - { - int listen_fd; - int i; - - memset( usaP, 0, sizeof(usockaddr) ); - usaP->sa.sa_family = AF_INET; - usaP->sa_in.sin_addr.s_addr = htonl( INADDR_ANY ); - usaP->sa_in.sin_port = htons( server_port ); - - listen_fd = socket( usaP->sa.sa_family, SOCK_STREAM, 0 ); - if ( listen_fd < 0 ) - { - perror( "socket" ); - return -1; - } - (void) fcntl( listen_fd, F_SETFD, 1 ); - i = 1; - if ( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &i, sizeof(i) ) < 0 ) - { - perror( "setsockopt" ); - return -1; + +// -------------------------------------------------------------------------------------------------------------------- + + +static const char *http_status_desc(int status) +{ + switch (status) { + case 200: + return "OK"; + case 302: + return "Found"; + case 400: + return "Invalid Request"; + case 401: + return "Unauthorized"; + case 404: + return "Not Found"; + case 501: + return "Not Implemented"; } - if ( bind( listen_fd, &usaP->sa, sizeof(struct sockaddr_in) ) < 0 ) - { - perror( "bind" ); - return -1; + return "Unknown"; +} + +void send_header(int status, const char* header, const char* mime, int cache) +{ + time_t now; + char tms[128]; + + now = time(NULL); + if (now < Y2K) now += Y2K; + strftime(tms, sizeof(tms), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&now)); // RFC 1123 + web_printf("HTTP/1.0 %d %s\r\n" + "Date: %s\r\n", + status, http_status_desc(status), + tms); + + if (mime) web_printf("Content-Type: %s\r\n", mime); + if (cache > 0) { + web_printf("Cache-Control: max-age=%d\r\n", cache * 60); } - if ( listen( listen_fd, 1024 ) < 0 ) - { - perror( "listen" ); - return -1; + else { + web_puts("Cache-Control: no-cache, no-store, must-revalidate, private\r\n" + "Expires: Thu, 31 Dec 1970 00:00:00 GMT\r\n" + "Pragma: no-cache\r\n"); } - return listen_fd; - } - - -static int -auth_check( char* dirname, char* authorization ) - { - char authinfo[500]; - char* authpass; - int l; -#ifdef MULTIPLE_LOGIN_SUPPORT - int count; - char word[1024], *next,*accounts; - char delim[] = "< >"; -#endif - /* Is this directory unprotected? */ - if ( !strlen(auth_passwd) ) - /* Yes, let the request go through. */ - return 1; + if (header) web_printf("%s\r\n", header); + web_puts("Connection: close\r\n\r\n"); - /* Basic authorization info? */ - if ( !authorization || strncmp( authorization, "Basic ", 6 ) != 0 ) { - //send_authenticate( dirname ); - ct_syslog(LOG_INFO, httpd_level, "Authentication fail"); - return 0; - } - - /* Decode it. */ - l = b64_decode( &(authorization[6]), authinfo, sizeof(authinfo) ); - authinfo[l] = '\0'; - /* Split into user and password. */ - authpass = strchr( authinfo, ':' ); - if ( authpass == (char*) 0 ) { - /* No colon? Bogus auth info. */ - //send_authenticate( dirname ); - return 0; - } - *authpass++ = '\0'; - - /* Is this the right user and password? */ -#ifdef DDM_SUPPORT - #ifdef MULTIPLE_LOGIN_SUPPORT - count =0; - accounts = nvram_safe_get("http_login"); - split(word, accounts, next, delim) { - int len = 0; - char *name,*psw,*mod; - - memset(auth_passwd,0,sizeof(auth_passwd)); - memset(auth_mod,0,sizeof(auth_mod)); - memset(auth_userid,0,sizeof(auth_userid)); - - if ((name=strstr(word, "$NAME:")) == NULL || - (psw=strstr(word, "$PSW:")) == NULL || - (mod=strstr(word, "$MOD:")) == NULL) - continue; - - /* $NAME */ - if (sscanf(name, "$NAME:%3d:", &len) != 1) - continue; - strncpy(auth_userid, name + sizeof("$NAME:nnn:") - 1, len); - name[len] = '\0'; - - /* $PSW */ - if (sscanf(psw, "$PSW:%3d:", &len) != 1) - continue; - strncpy(auth_passwd, psw + sizeof("$PSW:nnn:") - 1, len); - psw[len] = '\0'; - - /* $MOD */ - if (sscanf(mod, "$MOD:%3d:", &len) != 1) - continue; - strncpy(auth_mod, mod + sizeof("$MOD:nnn:") - 1, len); - mod[len] = '\0'; - -// printf("accounts[%d]= name:%s, psw:%s, mod:%s system= id:%s, psw:%s\n", count, auth_userid, auth_passwd, auth_mod, authinfo, authpass); - count++; - - if (strcmp( auth_userid, authinfo ) == 0 && strcmp( auth_passwd, authpass ) == 0 ) - { - nvram_set("current_login_name",auth_userid); + header_sent = 1; +} + +void send_error(int status, const char *header, const char *text) +{ + const char *s = http_status_desc(status); + send_header(status, header, mime_html, 0); + web_printf( + "<html>" + "<head><title>Error</title></head>" + "<body>" + "<h2>%d %s</h2> %s" + "</body></html>", + status, s, text ? text : s); +} + +void redirect(const char *path) +{ + char s[512]; + + snprintf(s, sizeof(s), "Location: %s", path); + send_header(302, s, mime_html, 0); + web_puts(s); + + _dprintf("Redirect: %s\n", path); +} + +int skip_header(int *len) +{ + char buf[2048]; + + while (*len > 0) { + if (!web_getline(buf, MIN(*len, sizeof(buf)))) { + break; + } + *len -= strlen(buf); + if ((strcmp(buf, "\n") == 0) || (strcmp(buf, "\r\n") == 0)) { return 1; } } - #else - if ( strcmp( auth_userid, authinfo ) == 0 && strcmp( auth_passwd, authpass ) == 0 ) - { - return 1; - } - #endif -#else - if (strcmp( auth_passwd, authpass ) == 0 ) - return 1; -#endif - //send_authenticate( dirname ); - return 0; - } - - -static void -send_authenticate( char* realm ) - { - char header[10000]; - - (void) snprintf( - header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm ); - send_error( 401, "Unauthorized", header, "Authorization required." ); - } - - -static void -send_error( int status, char* title, char* extra_header, char* text ) - { - - // jimmy, https, 8/4/2003, fprintf -> wfprintf, fflush -> wfflush - send_headers( status, title, extra_header, "text/html" ); - (void) wfprintf( conn_fp, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, title ); - (void) wfprintf( conn_fp, "%s\n", text ); - (void) wfprintf( conn_fp, "</BODY></HTML>\n" ); - (void) wfflush( conn_fp ); - } - -static void -send_headers( int status, char* title, char* extra_header, char* mime_type ) - { - time_t now; - char timebuf[100]; - - // jimmy, https, 8/4/2003, fprintf -> wfprintf - wfprintf( conn_fp, "%s %d %s\r\n", PROTOCOL, status, title ); - wfprintf( conn_fp, "Server: %s\r\n", SERVER_NAME ); - now = time( (time_t*) 0 ); - strftime( timebuf, sizeof(timebuf), RFC1123FMT, gmtime( &now ) ); - wfprintf( conn_fp, "Date: %s\r\n", timebuf ); - if ( extra_header != (char*) 0 && *extra_header) - wfprintf( conn_fp, "%s\r\n", extra_header ); - if ( mime_type != (char*) 0 ) - wfprintf( conn_fp, "Content-Type: %s\r\n", mime_type ); - wfprintf( conn_fp, "Connection: close\r\n" ); - wfprintf( conn_fp, "\r\n" ); - } - - -/* Base-64 decoding. This represents binary data as printable ASCII -** characters. Three 8-bit binary bytes are turned into four 6-bit -** values, like so: -** -** [11111111] [22222222] [33333333] -** -** [111111] [112222] [222233] [333333] -** -** Then the 6-bit values are represented using the characters "A-Za-z0-9+/". -*/ + return 0; +} -static int b64_decode_table[256] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ - 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ - 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ - -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ - 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ - }; - -/* Do base-64 decoding on a string. Ignore any non-base64 bytes. -** Return the actual number of bytes generated. The decoded size will -** be at most 3/4 the size of the encoded, and may be smaller if there -** are padding characters (blanks, newlines). -*/ -static int -b64_decode( const char* str, unsigned char* space, int size ) - { - const char* cp; - int space_idx, phase; - int d, prev_d=0; - unsigned char c; - - space_idx = 0; - phase = 0; - for ( cp = str; *cp != '\0'; ++cp ) - { - d = b64_decode_table[(int)*cp]; - if ( d != -1 ) - { - switch ( phase ) - { - case 0: - ++phase; - break; - case 1: - c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) ); - if ( space_idx < size ) - space[space_idx++] = c; - ++phase; - break; - case 2: - c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) ); - if ( space_idx < size ) - space[space_idx++] = c; - ++phase; - break; - case 3: - c = ( ( ( prev_d & 0x03 ) << 6 ) | d ); - if ( space_idx < size ) - space[space_idx++] = c; - phase = 0; - break; - } - prev_d = d; - } - } - return space_idx; - } +// ----------------------------------------------------------------------------- -/* Simple shell-style filename matcher. Only does ? * and **, and multiple -** patterns separated by |. Returns 1 or 0. -*/ -int -match( const char* pattern, const char* string ) - { - const char* or; - - //Added by Daniel(2004-07-29) for DEBUG - //cprintf("\nIn match(), pattern = %s, file = %s\n",pattern, string); - - for (;;) - { - or = strchr( pattern, '|' ); - if ( or == (char*) 0 ) - return match_one( pattern, strlen( pattern ), string ); - if ( match_one( pattern, or - pattern, string ) ) - return 1; - pattern = or + 1; - } - } - - -static int -match_one( const char* pattern, int patternlen, const char* string ) - { - const char* p; - - for ( p = pattern; p - pattern < patternlen; ++p, ++string ) - { - if ( *p == '?' && *string != '\0' ) - continue; - if ( *p == '*' ) - { - int i, pl; - ++p; - if ( *p == '*' ) - { - /* Double-wildcard matches anything. */ - ++p; - i = strlen( string ); +static void eat_garbage(void) +{ + int i; + int flags; + + // eat garbage \r\n (IE6, ...) or browser ends up with a tcp reset error message + if ((!do_ssl) && (post)) { + if (((flags = fcntl(connfd, F_GETFL)) != -1) && (fcntl(connfd, F_SETFL, flags | O_NONBLOCK) != -1)) { +// if (fgetc(connfp) != EOF) fgetc(connfp); + for (i = 0; i < 1024; ++i) { + if (fgetc(connfp) == EOF) break; + } + fcntl(connfd, F_SETFL, flags); } - else - /* Single-wildcard matches anything but slash. */ - i = strcspn( string, "/" ); - pl = patternlen - ( p - pattern ); - for ( ; i >= 0; --i ) - if ( match_one( p, pl, &(string[i]) ) ) - return 1; - return 0; - } - if ( *p != *string ) - return 0; } - if ( *string == '\0' ) - return 1; - return 0; - } +} +// ----------------------------------------------------------------------------- -void -//do_file(char *path, FILE *stream) -do_file(char *path, webs_t stream) //jimmy, https, 8/4/2003 +static void send_authenticate(void) { - FILE *fp; - int c; - - if (!(fp = fopen(path, "r"))) - return; - while ((c = getc(fp)) != EOF) - //fputc(c, stream); - wfputc(c, stream); // jimmy, https, 8/4/2003 - fclose(fp); + char header[128]; + const char *realm; + + realm = nvram_get("router_name"); + if ((realm == NULL) || (*realm == 0) || (strlen(realm) > 64)) realm = "unknown"; + + sprintf(header, "WWW-Authenticate: Basic realm=\"%s\"", realm); + send_error(401, header, NULL); } -#ifdef HSIAB_SUPPORT -static char * // add by jimmy 2003-5-13 -get_aaa_url(int inout_mode, char *client_ip) +typedef enum { AUTH_NONE, AUTH_OK, AUTH_BAD } auth_t; + +static auth_t auth_check(const char *authorization) { - static char line[MAX_BUF_LEN]; - char cmd[MAX_BUF_LEN]; - - strcpy(line,""); - if (inout_mode == 0) - snprintf(cmd, sizeof(cmd),"GET aaa_login_url %s", client_ip); - else - snprintf(cmd, sizeof(cmd),"GET aaa_logout_url %s", client_ip); - - send_command(cmd, line); - - return line; + char buf[512]; + const char *p; + char* pass; + int len; + + if ((authorization != NULL) && (strncasecmp(authorization, "Basic ", 6) == 0)) { + if (base64_decoded_len(strlen(authorization + 6)) <= sizeof(buf)) { + len = base64_decode(authorization + 6, buf, strlen(authorization) - 6); + buf[len] = 0; + if ((pass = strchr(buf, ':')) != NULL) { + *pass++ = 0; + if ((strcmp(buf, "admin") == 0) || (strcmp(buf, "root") == 0)) { + p = nvram_get("http_passwd"); + if (strcmp(pass, ((p == NULL) || (*p == 0)) ? "admin" : p) == 0) { + return AUTH_OK; + } + } + } + } + return AUTH_BAD; + } + + return AUTH_NONE; } -char * // add by honor 2003-04-16, modify by jimmy 2003-05-13 -get_client_ip(int conn_fp) +static void auth_fail(int clen) { - struct sockaddr_in sa; - int len = sizeof(struct sockaddr_in); - static char ip[20]; - - getpeername(conn_fp, (struct sockaddr *)&sa, &len); - strcpy(ip,inet_ntoa(sa.sin_addr)); - return(ip); + if (post) web_eat(clen); + eat_garbage(); + send_authenticate(); } -#endif -static int -check_connect_type(void) +int check_wlaccess(void) { - struct wl_assoc_mac *wlmac = NULL; - int count_wl = 0; - int i; + char mac[32]; + char ifname[32]; + sta_info_t sti; + + if (nvram_match("web_wl_filter", "1")) { + if (get_client_info(mac, ifname)) { + memset(&sti, 0, sizeof(sti)); + strcpy((char *)&sti, "sta_info"); // sta_info0<mac> + ether_atoe(mac, (char *)&sti + 9); + if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_VAR, &sti, sizeof(sti)) == 0) { + if (nvram_match("debug_logwlac", "1")) { + syslog(LOG_WARNING, "Wireless access from %s blocked.", mac); + } + return 0; + } + } + } + return 1; +} - if(nvram_invmatch("web_wl_filter", "1")) - return 0; +// ----------------------------------------------------------------------------- - wlmac = get_wl_assoc_mac(&count_wl); - - for(i=0 ; i<count_wl ; i++) { - if(!strcmp(wlmac[i].mac, nvram_safe_get("http_client_mac"))) { - cprintf("Cann't accept wireless access\n"); - return -1; +static int match_one(const char* pattern, int patternlen, const char* string) +{ + const char* p; + + for (p = pattern; p - pattern < patternlen; ++p, ++string) { + if (*p == '?' && *string != '\0') + continue; + if (*p == '*') { + int i, pl; + ++p; + if (*p == '*') { + /* Double-wildcard matches anything. */ + ++p; + i = strlen(string); + } else + /* Single-wildcard matches anything but slash. */ + i = strcspn(string, "/"); + pl = patternlen - (p - pattern); + for (; i >= 0; --i) + if (match_one(p, pl, &(string[i]))) + return 1; + return 0; } + if (*p != *string) + return 0; } - + if (*string == '\0') + return 1; return 0; } - -#ifdef GOOGLE_SUPPORT -static void -add_google_pass_mac(void) +// Simple shell-style filename matcher. Only does ? * and **, and multiple +// patterns separated by |. Returns 1 or 0. +static int match(const char* pattern, const char* string) { - char *google_mac = nvram_safe_get("google_pass_mac"); - char *mac = nvram_safe_get("http_client_mac"); - char buf[1024]; + const char* p; - if(!strstr(google_mac, mac)) { - snprintf(buf, sizeof(buf), "%s %s", google_mac, mac); - nvram_set("google_pass_mac", buf); - - nvram_commit(); + for (;;) { + p = strchr(pattern, '|'); + if (p == NULL) return match_one(pattern, strlen(pattern), string); + if (match_one(pattern, p - pattern, string)) return 1; + pattern = p + 1; } - - snprintf(buf, sizeof(buf), "iptables -I google -i %s -p tcp -m mac --mac-source %s -j ACCEPT", - nvram_safe_get("lan_ifname"), nvram_safe_get("http_client_mac")); - cprintf("buf[%s]\n", buf); - system(buf); - snprintf(buf, sizeof(buf), "iptables -t nat -I google -i %s -p tcp -m mac --mac-source %s -j ACCEPT", - nvram_safe_get("lan_ifname"), nvram_safe_get("http_client_mac")); - cprintf("buf[%s]\n", buf); - system(buf); } -#endif -static void -handle_request(void) + +void do_file(char *path) { - char line[10000], *cur; - char *method, *path, *protocol, *authorization, *boundary; - char *cp; - char *file; -#ifdef MULTIPLE_LOGIN_SUPPORT - char *file_ext; -#endif - int len; - struct mime_handler *handler; - int cl = 0, flags; - int auth_no = 0; - char *http_host = NULL; - /* Initialize the request variables. */ - authorization = boundary = NULL; - bzero( line, sizeof line ); - - /* Parse the first line of the request. */ - if ( wfgets( line, sizeof(line), conn_fp ) == (char *)0 ) { //jimmy,https,8/4/2003 - send_error( 400, "Bad Request", (char*) 0, "No request found." ); - return; - } - - /* To prevent http receive https packets, cause http crash (by honor 2003/09/02) */ - if ( strncasecmp(line, "GET", 3) && strncasecmp(line, "POST", 4)) { - fprintf(stderr, "Bad Request!\n"); - return; - } - - method = path = line; - strsep(&path, " "); - if (!path) { // Avoid http server crash, added by honor 2003-12-08 - send_error( 400, "Bad Request", (char*) 0, "Can't parse request." ); - return; - } - while (*path == ' ') path++; - protocol = path; - strsep(&protocol, " "); - if (!protocol) { // Avoid http server crash, added by honor 2003-12-08 - send_error( 400, "Bad Request", (char*) 0, "Can't parse request." ); - return; - } - while (*protocol == ' ') protocol++; - cp = protocol; - strsep(&cp, " "); - cur = protocol + strlen(protocol) + 1; - - /* Parse the rest of the request headers. */ - //while ( fgets( cur, line + sizeof(line) - cur, conn_fp ) != (char*) 0 ) - while ( wfgets( cur, line + sizeof(line) - cur, conn_fp ) != 0 ) //jimmy,https,8/4/2003 - { - - if ( strcmp( cur, "\n" ) == 0 || strcmp( cur, "\r\n" ) == 0 ){ - break; - } - else if ( strncasecmp( cur, "Authorization:", 14 ) == 0 ) - { - cp = &cur[14]; - cp += strspn( cp, " \t" ); - authorization = cp; - cur = cp + strlen(cp) + 1; - } - else if (strncasecmp( cur, "Content-Length:", 15 ) == 0) { - cp = &cur[15]; - cp += strspn( cp, " \t" ); - cl = strtoul( cp, NULL, 0 ); + FILE *f; + char buf[1024]; + int nr; + if ((f = fopen(path, "r")) != NULL) { + while ((nr = fread(buf, 1, sizeof(buf), f)) > 0) + web_write(buf, nr); + fclose(f); } - else if ((cp = strstr( cur, "boundary=" ))) { - boundary = &cp[9]; - for( cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++ ); - *cp = '\0'; - cur = ++cp; +} + +static void handle_request(void) +{ + char line[10000], *cur; + char *method, *path, *protocol, *authorization, *boundary; + char *cp; + char *file; + const struct mime_handler *handler; + int cl = 0; + auth_t auth; + + user_agent = ""; + header_sent = 0; + authorization = boundary = NULL; + bzero(line, sizeof(line)); + + // Parse the first line of the request. + if (!web_getline(line, sizeof(line))) { + send_error(400, NULL, NULL); + return; } - else if (strncasecmp(cur, "Host:" , 5 ) == 0) { - cp = &cur[5 + 1]; - cp += strspn( cp, " \t" ); - http_host = cp; - cur = cp + strlen(cp) + 1; - chomp(http_host); - } + _dprintf("%s\n", line); + + method = path = line; + strsep(&path, " "); + if (!path) { // Avoid http server crash, added by honor 2003-12-08 + send_error(400, NULL, NULL); + return; } - -#ifdef HSIAB_SUPPORT - if(strstr(path,"/logout/")){ - char *logout_url; - char buf[MAX_BUF_LEN]; - char value[MAX_BUF_LEN]; - - snprintf(value, sizeof(value), "LOG aaa_redirect logout %s %s", nvram_safe_get("http_client_ip"), nvram_safe_get("http_client_mac")); - send_command(value, NULL); - - logout_url = get_aaa_url(1, nvram_safe_get("http_client_ip")); - if(!strcmp(logout_url, "fail")){ - printf("Get logout URL fail!\n"); + while (*path == ' ') path++; + + if ((strcasecmp(method, "GET") != 0) && (strcasecmp(method, "POST") != 0)) { + send_error(501, NULL, NULL); return; } - fprintf(stderr, "User will redirect to this URL...[%s]\n", logout_url); - sprintf(buf,"Location: %s",logout_url); - (void) send_headers(302,"Redirect",(char *)buf,"text/plain"); - return; - - } -#endif - if ( strcasecmp( method, "get" ) != 0 && strcasecmp(method, "post") != 0 ) { - send_error( 501, "Not Implemented", (char*) 0, "That method is not implemented." ); - return; - } - if ( path[0] != '/' ) { - send_error( 400, "Bad Request", (char*) 0, "Bad filename." ); - return; - } - file = &(path[1]); - len = strlen( file ); - //Added by Daniel(2004-07-29) for DEBUG in EZC - //cprintf("\nIn handle_request() file: [%s] \n", file); - if ( file[0] == '/' || strcmp( file, ".." ) == 0 || strncmp( file, "../", 3 ) == 0 || strstr( file, "/../" ) != (char*) 0 || strcmp( &(file[len-3]), "/.." ) == 0 ) { - send_error( 400, "Bad Request", (char*) 0, "Illegal filename." ); - return; - } - if ( strcmp( &(file[len-1]), "/" ) == 0 && len > 0) //Amin 931231 deny request "http://ip/*/" return index.asp - { - send_error( 400, "Bad Request", (char*) 0, "Illegal filename." ); - return; - } - -#ifdef MULTIPLE_LOGIN_SUPPORT - if ( file[0] == '\0' || file[len-1] == '/' ) - { - file = "index.asp"; - } -#else - if ( file[0] == '\0' || file[len-1] == '/' ) - { - #ifdef MUST_CHANGE_PWD_SUPPORT - if(!nvram_match("is_not_first_access","1")) - file = "First_Management.asp"; - else - #endif - file = "index.asp"; - } -#endif -#ifdef GOOGLE_SUPPORT - if (http_host && - strncasecmp( http_host, nvram_safe_get("lan_ipaddr"), strlen(nvram_safe_get("lan_ipaddr"))) && - strncasecmp( http_host, nvram_safe_get("wan_ipaddr"), strlen(nvram_safe_get("wan_ipaddr")))) { - /* Redirect packet for first time */ - file = "google_redirect1.asp"; - auth_no = 1; + protocol = path; + strsep(&protocol, " "); + if (!protocol) { // Avoid http server crash, added by honor 2003-12-08 + send_error(400, NULL, NULL); + return; } - else if (http_host && - !strncasecmp( http_host, nvram_safe_get("lan_ipaddr"), strlen(nvram_safe_get("lan_ipaddr"))) && - strstr(path, "accept_terms=I+Accept")) { - /* Redirect packet for accepting terms */ - file = "google_redirect2.asp"; - auth_no = 1; - add_google_pass_mac(); + while (*protocol == ' ') protocol++; + + if (path[0] != '/') { + send_error(400, NULL, NULL); + return; } -#endif + file = path + 1; - for (handler = &mime_handlers[0]; handler->pattern; handler++) { - if (match(handler->pattern, file)) { - if (!auth_no && handler->auth) { -#ifdef MULTIPLE_LOGIN_SUPPORT - handler->auth(auth_id_pw, auth_passwd, auth_realm); -#else - handler->auth(auth_userid, auth_passwd, auth_realm); //r -#endif - auth_fail = 0; - if (!auth_check(auth_realm, authorization)) { - send_authenticate(auth_realm); - return; - //auth_fail = 1; - } - - } -#ifdef MULTIPLE_LOGIN_SUPPORT - file_ext = strstr(file , "."); -// printf("The request file name is : [%s], extern name is : [%s]\n",file,file_ext); - if(!strcmp(file_ext,".asp") && strcmp(file, "Status_Lan2.asp") && strcmp(file, "Status_Wireless2.asp") && strcmp(file, "Status_Router2.asp") && strcmp(file, "DHCPTable2.asp") && strcmp(file, "Management_account.asp")) - { - if(strcmp(auth_mod, "admin")) - { - if(!strcmp(file, "Management.asp")) - auth_fail = 1; - else - { -// printf("change web url to Status_Router page\n"); - file = "Status_Router2.asp"; - } - } -// else -// printf("Not change web url to Status_Router page\n"); - } -#endif -#ifdef GET_POST_SUPPORT - post=0; - if (strcasecmp(method, "post") == 0 ) { - post=1; - } -#else - if (strcasecmp(method, "post") == 0 && !handler->input) { - send_error(501, "Not Implemented", NULL, "That method is not implemented."); - return; - } +#if 0 + const char *hid; + int n; + + hid = nvram_safe_get("http_id"); + n = strlen(hid); + cprintf("file=%s hid=%s n=%d +n=%s\n", file, hid, n, path + n + 1); + if ((strncmp(file, hid, n) == 0) && (path[n + 1] == '/')) { + path += n + 1; + file = path + 1; + hidok = 1; + + cprintf("OK path=%s file=%s\n", path, file); + } #endif - if (handler->input) { - //cprintf("\nIn Handle Request(INPUT)!!!\n"); - handler->input(file, conn_fp, cl, boundary); -#if defined(linux) - if ((flags = fcntl(fileno(conn_fp), F_GETFL)) != -1 && - fcntl(fileno(conn_fp), F_SETFL, flags | O_NONBLOCK) != -1) { - /* Read up to two more characters */ - if (fgetc(conn_fp) != EOF) - (void) fgetc(conn_fp); - fcntl(fileno(conn_fp), F_SETFL, flags); - } -#endif - } - - if(check_connect_type() <0 ){ - send_error(401, "Bad Request", (char*) 0, "Cann't use wireless interface to access web."); - return; - } - - if(auth_fail == 1){ - send_authenticate(auth_realm); - return; - } - else - send_headers( 200, "Ok", handler->extra_header, handler->mime_type ); - - if (handler->output) - { - //cprintf("\nIn Handle Request(OUTPUT)!!!\n"); - handler->output(file, conn_fp); - } - break; - } - } - - if (!handler->pattern) - send_error( 404, "Not Found", (char*) 0, "File not found." ); -} -void // add by honor 2003-04-16 -get_client_ip_mac(int conn_fp) -{ - struct sockaddr_in sa; - int len = sizeof(struct sockaddr_in); - char *m; - - getpeername(conn_fp, (struct sockaddr *)&sa, &len); - nvram_safe_set("http_client_ip", inet_ntoa(sa.sin_addr)); - m = get_mac_from_ip(inet_ntoa(sa.sin_addr)); - nvram_safe_set("http_client_mac", m); -} + if ((cp = strchr(file, '?')) != NULL) { + *cp = 0; + webcgi_init(cp + 1); + } -static void -handle_server_sig_int(int sig) -{ - ct_syslog(LOG_INFO, httpd_level, "httpd server %sshutdown", do_ssl ? "(ssl support) " : ""); - exit(0); -} + if ((file[0] == '/') || (strncmp(file, "..", 2) == 0) || (strstr(file, "/../") != NULL) || + (strcmp(file + (strlen(file) - 3), "/..") == 0)) { + send_error(400, NULL, NULL); + return; + } -void settimeouts(int sock, int secs) -{ - struct timeval tv; + if ((file[0] == 0) || (strcmp(file, "index.asp") == 0)) { + file = "status-overview.asp"; + } + else if ((strcmp(file, "ext/") == 0) || (strcmp(file, "ext") == 0)) { + file = "ext/index.asp"; + } - tv.tv_sec = secs; - tv.tv_usec = 0; - if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) - perror("setsockopt(SO_SNDTIMEO)"); - if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) - perror("setsockopt(SO_RCVTIMEO)"); -} + cp = protocol; + strsep(&cp, " "); + cur = protocol + strlen(protocol) + 1; -int main(int argc, char **argv) -{ - usockaddr usa; - int listen_fd; - int conn_fd; - socklen_t sz = sizeof(usa); - int c; - int timeout = TIMEOUT; - int n = 0; -#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003 - BIO *sbio; - SSL_CTX *ctx = NULL; - int r; - BIO *ssl_bio; -#endif - strcpy(pid_file, "/var/run/httpd.pid"); - server_port = DEFAULT_HTTP_PORT; - - while ((c = getopt(argc, argv, "Sp:t:s:gh")) != -1) - switch (c) { -#if defined(HTTPS_SUPPORT) //honor, https, 8/14/2003 - case 'S': - do_ssl = 1; - server_port = DEFAULT_HTTPS_PORT; - strcpy(pid_file, "/var/run/httpsd.pid"); - break; -#endif - case 'p': - server_port = atoi(optarg); - break; - case 't': - timeout = atoi(optarg); - break; -#ifdef DEBUG_CIPHER - case 's': - set_ciphers = optarg; - break; - case 'g': - get_ciphers = 1; - break; -#endif - case 'h': - fprintf(stderr, "Usage: %s [-S] [-p port]\n" - " -S : Support https (port 443)\n" - " -p port : Which port to listen?\n" - " -t secs : How many seconds to wait before timing out?\n" - " -s ciphers: set cipher lists\n" - " -g: get cipher lists\n" - , argv[0]); - exit(0); - break; - default: - break; + while (web_getline(cur, line + sizeof(line) - cur)) { + if ((strcmp(cur, "\n") == 0) || (strcmp(cur, "\r\n") == 0)) { + break; } - - - httpd_level = ct_openlog("httpd", LOG_PID | LOG_NDELAY, LOG_DAEMON, "LOG_HTTPD"); - - ct_syslog(LOG_INFO, httpd_level, "httpd server %sstarted at port %d\n", do_ssl ? "(ssl support) " : "", server_port); - - /* Ignore broken pipes */ - signal(SIGPIPE, SIG_IGN); -#ifdef SAMBA_SUPPORT - /* handle child exit */ - signal(SIGCHLD, smb_handler); -#endif - signal(SIGTERM, handle_server_sig_int); // kill - - -#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003 - /* Build our SSL context */ - if(do_ssl){ - SSLeay_add_ssl_algorithms(); - SSL_load_error_strings(); - ctx = SSL_CTX_new( SSLv23_server_method() ); - if ( SSL_CTX_use_certificate_file( ctx, CERT_FILE, SSL_FILETYPE_PEM ) == 0 ) { - cprintf("Cann't read %s\n", CERT_FILE); - ERR_print_errors_fp( stderr ); - exit( 1 ); + if (strncasecmp(cur, "Authorization:", 14) == 0) { + cp = &cur[14]; + cp += strspn(cp, " \t"); + authorization = cp; + cur = cp + strlen(cp) + 1; } - if(SSL_CTX_use_PrivateKey_file( ctx, KEY_FILE, SSL_FILETYPE_PEM ) == 0 ) { - cprintf("Cann't read %s\n", KEY_FILE); - ERR_print_errors_fp( stderr ); - exit( 1 ); - + else if (strncasecmp(cur, "Content-Length:", 15) == 0) { + cp = &cur[15]; + cp += strspn(cp, " \t"); + cl = strtoul(cp, NULL, 0); + if ((cl < 0) || (cl >= INT_MAX)) { + send_error(400, NULL, NULL); + return; + } } - if(SSL_CTX_check_private_key( ctx ) == 0 ) { - cprintf("Check private key fail\n"); - ERR_print_errors_fp( stderr ); - exit( 1 ); + else if ((strncasecmp(cur, "Content-Type:", 13) == 0) && ((cp = strstr(cur, "boundary=")))) { + boundary = &cp[9]; + for (cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++); + *cp = '\0'; + cur = ++cp; } - } -#endif - /* Initialize listen socket */ -retry: - if ((listen_fd = initialize_listen_socket(&usa)) < 0) { - ct_syslog(LOG_ERR, httpd_level, "Cann't bind to any address"); - close(listen_fd); - - sleep(2); - if(n++ <= 5) { - cprintf("Something error occur, retry %d\n", n); - goto retry; + else if (strncasecmp(cur, "User-Agent:", 11) == 0) { + user_agent = cur + 11; + user_agent += strspn(user_agent, " \t"); + cur = user_agent + strlen(user_agent); + *cur++ = 0; } - - exit(errno); - } - -#if !defined(DEBUG) - { - FILE *pid_fp; - /* Daemonize and log PID */ - if (daemon(1, 1) == -1) { - perror("daemon"); - exit(errno); } - if (!(pid_fp = fopen(pid_file, "w"))) { - perror(pid_file); - return errno; - } - fprintf(pid_fp, "%d", getpid()); - fclose(pid_fp); + + post = (strcasecmp(method, "post") == 0); + + auth = auth_check(authorization); + +#if 0 + cprintf("UserAgent: %s\n", user_agent); + switch (auth) { + case AUTH_NONE: + cprintf("AUTH_NONE\n"); + break; + case AUTH_OK: + cprintf("AUTH_OK\n"); + break; + case AUTH_BAD: + cprintf("AUTH_BAD\n"); + break; + default: + cprintf("AUTH_?\n"); + break; } #endif - /* Loop forever handling requests */ - for (;;) { - if ((conn_fd = accept(listen_fd, &usa.sa, &sz)) < 0) { - perror("accept"); - return errno; - } + /* + + Chrome 1.0.154: + - User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 + - It *always* sends an 'AUTH_NONE request' first. This results in a + send_authenticate, then finally sends an 'AUTH_OK request'. + - It does not clear the authentication even if AUTH_NONE request succeeds. + - If user doesn't enter anything (blank) for credential, it sends the + previous credential. + + */ - /* Make sure we don't linger a long time if the other end disappears */ - settimeouts(conn_fd, timeout); + if (strcmp(file, "logout") == 0) { // special case + wi_generic(file, cl, boundary); + eat_garbage(); - if(check_action() == ACT_TFTP_UPGRADE || // We don't want user to use web during tftp upgrade. - check_action() == ACT_SW_RESTORE || - check_action() == ACT_HW_RESTORE){ - fprintf(stderr, "http(s)d: nothing to do...\n"); - return -1; + if (strstr(user_agent, "Chrome/") != NULL) { + if (auth != AUTH_BAD) { + send_authenticate(); + return; + } } - -#if defined(HTTPS_SUPPORT) //jimmy, https, 8/4/2003 - if(do_ssl){ - if(check_action() == ACT_WEB_UPGRADE){ // We don't want user to use web (https) during web (http) upgrade. - fprintf(stderr, "httpsd: nothing to do...\n"); - return -1; + else { + if (auth == AUTH_OK) { + send_authenticate(); + return; + } } + send_error(404, NULL, "Goodbye"); + return; + } - sbio=BIO_new_socket(conn_fd,BIO_NOCLOSE); - ssl=SSL_new(ctx); - -#ifdef DEBUG_CIPHER - check_cipher(); -#endif - - SSL_set_bio(ssl,sbio,sbio); + if (auth == AUTH_BAD) { + auth_fail(cl); + return; + } - if((r=SSL_accept(ssl)<=0)){ - //berr_exit("SSL accept error"); - ct_syslog(LOG_ERR, httpd_level, "SSL accept error"); - close(conn_fd); - continue; + for (handler = &mime_handlers[0]; handler->pattern; handler++) { + if (match(handler->pattern, file)) { + if ((handler->auth) && (auth != AUTH_OK)) { + auth_fail(cl); + return; + } + + if (handler->input) handler->input(file, cl, boundary); + eat_garbage(); + if (handler->mime_type != NULL) send_header(200, NULL, handler->mime_type, handler->cache); + if (handler->output) handler->output(file); + return; } + } - conn_fp=(webs_t)BIO_new(BIO_f_buffer()); - ssl_bio=BIO_new(BIO_f_ssl()); - BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE); - BIO_push((BIO *)conn_fp,ssl_bio); - }else -#endif - { - if(check_action() == ACT_WEBS_UPGRADE){ // We don't want user to use web (http) during web (https) upgrade. - fprintf(stderr, "httpd: nothing to do...\n"); - return -1; - } - - if (!(conn_fp = fdopen(conn_fd, "r+"))) { - perror("fdopen"); - return errno; - } - } - get_client_ip_mac(conn_fd); - - handle_request(); -#ifdef SAMBA_SUPPORT - if (httpd_fork==1) { - httpd_fork=0; - close(conn_fd); - continue; - } -#endif - - wfflush(conn_fp); // jimmy, https, 8/4/2003 - wfclose(conn_fp); // jimmy, https, 8/4/2003 - close(conn_fd); + if (auth != AUTH_OK) { + auth_fail(cl); + return; } - shutdown(listen_fd, 2); - close(listen_fd); +/* + if ((!post) && (strchr(file, '.') == NULL)) { + cl = strlen(file); + if ((cl > 1) && (cl < 64)) { + char alt[128]; - return 0; + path = alt + 1; + strcpy(path, file); + + cp = path + cl - 1; + if (*cp == '/') *cp = 0; + + if ((cp = strrchr(path, '/')) != NULL) *cp = '-'; + + strcat(path, ".asp"); + if (f_exists(path)) { + alt[0] = '/'; + redirect(alt); + return; + } + } + } +*/ + + send_error(404, NULL, NULL); } -char * -wfgets(char *buf, int len, FILE *fp) +#ifdef TCONFIG_HTTPS +static void save_cert(void) { -#ifdef HTTPS_SUPPORT - if(do_ssl) - return (char *)BIO_gets((BIO *)fp, buf, len); - else -#endif - return fgets(buf, len, fp); + if (eval("tar", "-C", "/", "-czf", "/tmp/cert.tgz", "etc/cert.pem", "etc/key.pem") == 0) { + if (nvram_set_file("https_crt_file", "/tmp/cert.tgz", 8192)) { + nvram_commit_x(); + } + } + unlink("/tmp/cert.tgz"); } -int -wfputc(char c, FILE *fp) +static void erase_cert(void) { -#ifdef HTTPS_SUPPORT - if(do_ssl) - return BIO_printf((BIO *)fp, "%c", c); - else -#endif - return fputc(c, fp); + unlink("/etc/cert.pem"); + unlink("/etc/key.pem"); + nvram_unset("https_crt_file"); + nvram_unset("https_crt_gen"); } -int -wfputs(char *buf, FILE *fp) +static void start_ssl(void) { -#ifdef HTTPS_SUPPORT - if(do_ssl) - return BIO_puts((BIO *)fp, buf); - else -#endif - return fputs(buf, fp); + int ok; + int save; + int retry; + unsigned long long sn; + char t[32]; + + if (nvram_match("https_crt_gen", "1")) { + erase_cert(); + } + + retry = 1; + while (1) { + save = nvram_match("https_crt_save", "1"); + + if ((!f_exists("/etc/cert.pem")) || (!f_exists("/etc/key.pem"))) { + ok = 0; + if (save) { + if (nvram_get_file("https_crt_file", "/tmp/cert.tgz", 8192)) { + if (eval("tar", "-xzf", "/tmp/cert.tgz", "-C", "/", "etc/cert.pem", "etc/key.pem") == 0) + ok = 1; + unlink("/tmp/cert.tgz"); + } + } + if (!ok) { + erase_cert(); + syslog(LOG_INFO, "Generating SSL certificate..."); + + // browsers seems to like this when the ip address moves... -- zzz + f_read("/dev/urandom", &sn, sizeof(sn)); + + sprintf(t, "%llu", sn & 0x7FFFFFFFFFFFFFFFUL); + eval("gencert.sh", t); + } + } + + if ((save) && (*nvram_safe_get("https_crt_file")) == 0) { + save_cert(); + } + + if (ssl_init("/etc/cert.pem", "/etc/key.pem")) return; + + erase_cert(); + + syslog(retry ? LOG_WARNING : LOG_ERR, "Unable to start SSL"); + if (!retry) exit(1); + retry = 0; + } } +#endif -int -wfprintf(FILE *fp, char *fmt,...) +static void init_id(void) { - va_list args; - char buf[1024]; - int ret; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); -#ifdef HTTPS_SUPPORT - if(do_ssl) - ret = BIO_printf((BIO *)fp, "%s", buf); - else -#endif - ret = fprintf(fp, "%s", buf); - va_end(args); - return ret; + char s[128]; + unsigned long long n; + + if (strncmp(nvram_safe_get("http_id"), "TID", 3) != 0) { + f_read("/dev/urandom", &n, sizeof(n)); + sprintf(s, "TID%llx", n); + nvram_set("http_id", s); + } + + nvram_unset("http_id_warn"); } -size_t -wfwrite(char *buf, int size, int n, FILE *fp) +void check_id(const char *url) { -#ifdef HTTPS_SUPPORT - if(do_ssl) - return BIO_write((BIO *)fp, buf , n * size); - else + if (!nvram_match("http_id", webcgi_safeget("_http_id", ""))) { +#if 0 + const char *hid = nvram_safe_get("http_id"); + if (url) { + const char *a; + int n; + + // http://xxx/yyy/TID/zzz + if (((a = strrchr(url, '/')) != NULL) && (a != url)) { + n = strlen(hid); + a -= n; + if ((a > url) && (*(a - 1) == '/')) { + if (strncmp(a, hid, n) == 0) return; + } + } + } + #endif - return fwrite(buf,size,n,fp); + + char s[48]; + char *i; + char *u; + const char *a; + + a = inet_ntoa(clientsai.sin_addr); + sprintf(s, "%s,%ld", a, time(NULL) & 0xFFC0); + if (!nvram_match("http_id_warn", s)) { + nvram_set("http_id_warn", s); + + strlcpy(s, webcgi_safeget("_http_id", ""), sizeof(s)); + i = js_string(s); // quicky scrub + + strlcpy(s, url, sizeof(s)); + u = js_string(s); + + if ((i != NULL) && (u != NULL)) { + syslog(LOG_WARNING, "Invalid ID '%s' from %s for /%s", i, a, u); + } + + // free(u); + // free(i); + } + + exit(1); + } } -size_t -wfread(char *buf, int size, int n, FILE *fp) +int main(int argc, char **argv) { -#ifdef HTTPS_SUPPORT - if(do_ssl) - return BIO_read((BIO *)fp, buf , n * size); - else + int c; + int debug = 0; + int server_port = 0; + + while ((c = getopt(argc, argv, "hdp:s")) != -1) { + switch (c) { + case 'h': + printf( + "Usage: %s [options]\n" + " -d Debug mode / do not demonize\n" + " -p <port> Port to listen on\n" +#ifdef TCONFIG_HTTPS + " -s Use HTTPS\n" +#endif + , argv[0]); + return 1; + case 'd': + debug = 1; + break; + case 'p': + server_port = atoi(optarg); + break; +#ifdef TCONFIG_HTTPS + case 's': + do_ssl = 1; + break; #endif - return fread(buf,size,n,fp); -} + } + } -int -wfflush(FILE *fp) -{ -#ifdef HTTPS_SUPPORT - if(do_ssl){ - BIO_flush((BIO *)fp); - return 1; + if (server_port == 0) { +#ifdef TCONFIG_HTTPS + if (do_ssl) { + server_port = nvram_get_int("https_lanport"); + if (server_port <= 0) server_port = 443; + } + else { + server_port = nvram_get_int("http_lanport"); + if (server_port <= 0) server_port = 80; + } +#else + server_port = nvram_get_int("http_lanport"); + if (server_port <= 0) server_port = 80; +#endif + } + + openlog("httpd", LOG_PID, LOG_DAEMON); + + if (!debug) { + if (daemon(1, 1) == -1) { + syslog(LOG_ERR, "daemon: %m"); + return 0; + } + + + char s[16]; + sprintf(s, "%d", getpid()); + f_write_string(do_ssl ? "/var/run/httpsd.pid" : "/var/run/httpd.pid", s, 0, 0644); } - else + else { + printf("DEBUG mode, not daemonizing\n"); + } + + signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + +#ifdef TCONFIG_HTTPS + if (do_ssl) start_ssl(); #endif - return fflush(fp); -} -int -wfclose(FILE *fp) -{ -#ifdef HTTPS_SUPPORT - if(do_ssl){ - BIO_free_all((BIO *)fp); + struct timeval tv; + int n; + + if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + syslog(LOG_ERR, "create listening socket: %m"); + return 1; + } + fcntl(listenfd, F_SETFD, FD_CLOEXEC); + n = 1; + setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof(n)); + + struct sockaddr_in sai; + sai.sin_family = AF_INET; + sai.sin_port = htons(server_port); + sai.sin_addr.s_addr = INADDR_ANY; + if (bind(listenfd, (struct sockaddr *)&sai, sizeof(sai)) < 0) { + syslog(LOG_ERR, "bind: %m"); return 1; } - else -#endif - return fclose(fp); -} -#ifdef DEBUG_CIPHER -void check_cipher(void) -{ - STACK_OF(SSL_CIPHER) *sk; - char buf[512]; - BIO *STDout = NULL; - int i; - static BIO *bio_stdout=NULL; - X509 *peer; - static BIO *bio_s_out=NULL; - SSL_CIPHER *ciph; - - if(set_ciphers) { - /* Set supported cipher lists */ - SSL_set_cipher_list(ssl, set_ciphers); + if (listen(listenfd, 64) < 0) { + syslog(LOG_ERR, "listen: %m"); + return 1; } - if(get_ciphers) { - /* Show supported cipher lists */ - sk=SSL_get_ciphers(ssl); - for (i=0; i<sk_SSL_CIPHER_num(sk); i++) { - BIO_puts(STDout,SSL_CIPHER_description( sk_SSL_CIPHER_value(sk,i), buf, 512)); - printf("%d: %s", i, buf); + init_id(); + + for (;;) { + webcgi_init(NULL); + if (connfd >= 0) close(connfd); + + n = sizeof(clientsai); + if ((connfd = accept(listenfd, (struct sockaddr *)&clientsai, &n)) < 0) { +// if ((errno != EINTR) && (errno != EAGAIN)) { +// syslog(LOG_ERR, "accept: %m"); +// return 1; +// } + sleep(1); + continue; + } + + if (!wait_action_idle(10)) { +// syslog(LOG_WARNING, "router is busy"); + continue; + } + + if (!check_wlaccess()) { + continue; + } + + if (fork() == 0) { + close(listenfd); + + tv.tv_sec = 60; + tv.tv_usec = 0; + setsockopt(connfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + + n = 1; + setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, (char *)&n, sizeof(n)); + + fcntl(connfd, F_SETFD, FD_CLOEXEC); + + if (web_open()) handle_request(); + web_close(); + exit(0); } - if (STDout != NULL) BIO_free_all(STDout); - } - peer=SSL_get_peer_certificate(ssl); - if (peer != NULL) - { - BIO_printf(bio_s_out,"Client certificate\n"); - PEM_write_bio_X509(bio_s_out,peer); - X509_NAME_oneline(X509_get_subject_name(peer),buf,sizeof buf); - BIO_printf(bio_s_out,"subject=%s\n",buf); - X509_NAME_oneline(X509_get_issuer_name(peer),buf,sizeof buf); - BIO_printf(bio_s_out,"issuer=%s\n",buf); - X509_free(peer); } - if (SSL_get_shared_ciphers(ssl,buf,sizeof buf) != NULL) - BIO_printf(bio_s_out,"Shared ciphers:%s\n",buf); - - bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE); - ciph=SSL_get_current_cipher(ssl); - BIO_printf(bio_stdout,"%s%s, cipher %s %s\n", - "", - SSL_get_version(ssl), - SSL_CIPHER_get_version(ciph), - SSL_CIPHER_get_name(ciph)); + close(listenfd); + return 0; } -#endif diff --git a/release/src/router/httpd/httpd.h b/release/src/router/httpd/httpd.h index 15c6da96..a9a3a962 100644 --- a/release/src/router/httpd/httpd.h +++ b/release/src/router/httpd/httpd.h @@ -1,111 +1,93 @@ -/* - * milli_httpd - pretty small HTTP server - * - * Copyright 2005, Broadcom Corporation - * All Rights Reserved. - * - * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY - * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM - * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * - * $Id: httpd.h,v 1.13 2005/03/07 08:35:32 kanki Exp $ - */ - -#include <cy_conf.h> -#ifndef _httpd_h_ -#define _httpd_h_ - -#if defined(DEBUG) && defined(DMALLOC) -#include <dmalloc.h> -#endif +#ifndef __HTTPD_H__ +#define __HTTPD_H__ + +extern struct sockaddr_in clientsai; +extern int post; +extern char *user_agent; -#include <openssl/ssl.h> -extern BIO *bio_err; - -// typedef BIO * webs_t; -// #define wfgets(buf,len,fp) BIO_gets(fp,buf,len) -// #define wfputc(c,fp) BIO_printf(fp,"%c",c) -// #define wfputs(buf,fp) BIO_puts(fp,buf) -// #define wfprintf(fp, args...) BIO_printf(fp, ## args) -// #define wfwrite(buf,size,n,fp) BIO_write(fp,buf,n * size) -// #define wfread(buf,size,n,fp) BIO_read(fp,buf,n * size) -// #define wfflush(fp) BIO_flush(fp) -// #define wfclose(fp) BIO_free_all(fp) -//#else -// typedef FILE * webs_t; -// #define wfgets(buf,len,fp) fgets(buf,len,fp) -// #define wfputc(c,fp) fputc(c,fp) -// #define wfputs(buf,fp) fputs(buf,fp) -// #define wfprintf(fp, args...) fprintf(fp, ## args) -// #define wfwrite(buf,size,n,fp) fwrite(buf,size,n,fp) -// #define wfread(buf,size,n,fp) fread(buf,size,n,fp) -// #define wfflush(fp) fflush(fp) -// #define wfclose(fp) fclose(fp) -//#endif -typedef FILE * webs_t; -extern char * wfgets(char *buf, int len, FILE *fp); -extern int wfputc(char c, FILE *fp); -extern int wfputs(char *buf, FILE *fp); -extern int wfprintf(FILE *fp, char *fmt,...); -extern size_t wfwrite(char *buf, int size, int n, FILE *fp); -extern size_t wfread(char *buf, int size, int n, FILE *fp); -extern int wfflush(FILE *fp); -extern int wfclose(FILE *fp); - -int do_ssl; -/* Basic authorization userid and passwd limit */ -#define AUTH_MAX 64 - -/* Generic MIME type handler */ struct mime_handler { - char *pattern; - char *mime_type; - char *extra_header; - void (*input)(char *path, FILE *stream, int len, char *boundary); - void (*output)(char *path, FILE *stream); - void (*auth)(char *userid, char *passwd, char *realm); + const char *pattern; + const char *mime_type; + int cache; + void (*input)(char *path, int len, char *boundary); + void (*output)(char *path); + int auth; }; -extern struct mime_handler mime_handlers[]; - -/* CGI helper functions */ -extern void init_cgi(char *query); -extern char * get_cgi(char *name); -extern void set_cgi(char *name, char *value); -extern int count_cgi(); - -/* Regular file handler */ -extern void do_file(char *path, webs_t stream); - -/* GoAhead 2.1 compatibility */ -//typedef FILE * webs_t; -typedef char char_t; -#define T(s) (s) -#define __TMPVAR(x) tmpvar ## x -#define _TMPVAR(x) __TMPVAR(x) -#define TMPVAR _TMPVAR(__LINE__) -#define websWrite(wp, fmt, args...) ({ int TMPVAR = wfprintf(wp, fmt, ## args); wfflush(wp); TMPVAR; }) -#define websDebugWrite(wp, fmt, args...) ({ error_value = 1; wfputs("<!--", wp); int TMPVAR = wfprintf(wp, fmt, ## args); wfputs("-->", wp); wfflush(wp); TMPVAR; }) -#define websError(wp, code, msg, args...) wfprintf(wp, msg, ## args) -#define websHeader(wp) wfputs("<html lang=\"en\">", wp) -#define websFooter(wp) wfputs("</html>", wp) -#define websDone(wp, code) wfflush(wp) -#define websGetVar(wp, var, default) (get_cgi(var) ? : default) -#define websSetVar(wp, var, value) set_cgi(var, value) -#define websDefaultHandler(wp, urlPrefix, webDir, arg, url, path, query) ({ do_ej(path, wp); fflush(wp); 1; }) -#define websWriteData(wp, buf, nChars) ({ int TMPVAR = wfwrite(buf, 1, nChars, wp); wfflush(wp); TMPVAR; }) -#define websWriteDataNonBlock websWriteData -#define a_assert(a) - -extern int ejArgs(int argc, char_t **argv, char_t *fmt, ...); - -/* GoAhead 2.1 Embedded JavaScript compatibility */ -extern void do_ej(char *path, webs_t stream); -struct ej_handler { - char *pattern; - int (*output)(int eid, webs_t wp, int argc, char_t **argv); -}; -extern struct ej_handler ej_handlers[]; +extern const struct mime_handler mime_handlers[]; + + +// + +extern void do_file(char *path); + + +// basic http i/o + +typedef enum { + WOF_NONE, + WOF_JAVASCRIPT, + WOF_HTML +} wofilter_t; + +extern int web_getline(char *buffer, int max); +extern int web_putc(char c); +extern void web_puts(const char *buffer); +extern void web_putj(const char *buffer); +extern void web_puth(const char *buffer); +extern int web_write(const char *buffer, int len); +extern int web_read(void *buffer, int len); +extern int web_read_x(void *b, int len); +extern int web_eat(int max); +extern int web_flush(void); +extern int web_open(void); +extern int web_close(void); + +extern int web_pipecmd(const char *cmd, wofilter_t wof); +extern int web_putfile(const char *fname, wofilter_t wof); + +extern int _web_printf(wofilter_t wof, const char *format, ...); +#define web_printf(args...) _web_printf(WOF_NONE, ##args) +#define web_printfj(args...) _web_printf(WOF_JAVASCRIPT, ##args) +#define web_printfh(args...) _web_printf(WOF_HTML, ##args) + + +// http header handling +extern const char mime_html[]; +extern const char mime_plain[]; +extern const char mime_javascript[]; +extern const char mime_octetstream[]; +extern const char mime_binary[]; +extern int header_sent; -#endif /* _httpd_h_ */ +extern void send_header(int status, const char *header, const char *mime, int cache); +extern void send_error(int status, const char *header, const char *text); +extern void redirect(const char *path); +extern int skip_header(int *len); + + +// cgi handling + +extern void webcgi_init(char *query); +extern char *webcgi_get(const char *name); +extern void webcgi_set(char *name, char *value); + +#define webcgi_safeget(key, default) (webcgi_get(key) ? : (default)) + + +// asp file handing + +typedef struct { + const char *name; + void (*exec)(int argc, char **argv); +} aspapi_t; + +extern const aspapi_t aspapi[]; + +extern int parse_asp(const char *path); + + +// +extern void check_id(const char *url); + +#endif diff --git a/release/src/router/httpd/key.pem b/release/src/router/httpd/key.pem deleted file mode 100644 index 6e666d27..00000000 --- a/release/src/router/httpd/key.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBALy3iYBtUiBdJT9HGogbiv9jRIV9qDySV/VREpdHjpFZ+ClJANlZ -XajQU9eF9Np33XxM+w9QSxNMvwkRSOSV9IkCAwEAAQJAfanZreMd5N8hhllamXd9 -v0HixuE9vdfVKk2qC4JitPYHReAgpR4gGWiE917PLWoL1701rXbqlEkGcplePHm9 -YQIhAN153pKg1TM6nIm4dNym4SI4ViAfyanbn3ESedgUNlIPAiEA2iJldvc+ofZj -SqlkfyPQNnHa5oLzgXlzbK5GP3T0h+cCIQC5vgKHMHF9dFNiQRtpDl/TpjG84Uvs -s28lklwzdsgTywIgTVUYZ56rw7uX4+Y9zJ0jucmPc11FesdV1lfKa8DI2E0CICZZ -wecsBOdY0s2uJn+SXm14f5/Ipysx2WFbaDCqcb/D ------END RSA PRIVATE KEY----- diff --git a/release/src/router/httpd/log.c b/release/src/router/httpd/log.c new file mode 100644 index 00000000..2aca2b23 --- /dev/null +++ b/release/src/router/httpd/log.c @@ -0,0 +1,76 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> + +static int logok(void) +{ + if (nvram_match("log_file", "1")) return 1; + resmsg_set("Internal logging disabled"); + redirect("error.asp"); + return 0; +} + +void wo_viewlog(char *url) +{ + char *p; + char *c; + char s[128]; + char t[128]; + int n; + + if (!logok()) return; + + if ((p = webcgi_get("find")) != NULL) { + send_header(200, NULL, mime_plain, 0); + if (strlen(p) > 64) return; + c = t; + while (*p) { + switch (*p) { + case '<': + case '>': + case '|': + case '"': + case '\\': + *c++ = '\\'; + *c++ = *p; + break; + default: + if (isprint(*p)) *c++ = *p; + break; + } + ++p; + } + *c = 0; + sprintf(s, "cat %s %s | grep -i \"%s\"", "/var/log/messages.0", "/var/log/messages", t); + web_pipecmd(s, WOF_NONE); + return; + } + + if ((p = webcgi_get("which")) == NULL) return; + if (strcmp(p, "all") == 0) { + send_header(200, NULL, mime_plain, 0); + do_file("/var/log/messages.0"); + do_file("/var/log/messages"); + return; + } + if ((n = atoi(p)) > 0) { + send_header(200, NULL, mime_plain, 0); + sprintf(s, "cat %s %s | tail -n %d", "/var/log/messages.0", "/var/log/messages", n); + web_pipecmd(s, WOF_NONE); + } +} + +void wo_syslog(char *url) +{ + if (!logok()) return; + send_header(200, NULL, mime_binary, 0); + do_file("/var/log/messages.0"); + do_file("/var/log/messages"); +} diff --git a/release/src/router/httpd/misc.c b/release/src/router/httpd/misc.c new file mode 100644 index 00000000..8bc05772 --- /dev/null +++ b/release/src/router/httpd/misc.c @@ -0,0 +1,502 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> +#include <sys/sysinfo.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <dirent.h> +#include <time.h> +#include <sys/statfs.h> +#include <netdb.h> +#include <net/route.h> + +#include <wlioctl.h> +#include <wlutils.h> + +// to javascript-safe string +char *js_string(const char *s) +{ + unsigned char c; + char *buffer; + char *b; + + if ((buffer = malloc((strlen(s) * 4) + 1)) != NULL) { + b = buffer; + while ((c = *s++) != 0) { + if ((c == '"') || (c == '\'') || (c == '\\') || (!isprint(c))) { + b += sprintf(b, "\\x%02x", c); + } + else { + *b++ = c; + } + } + *b = 0; + } + return buffer; +} + +// to html-safe string +char *html_string(const char *s) +{ + unsigned char c; + char *buffer; + char *b; + + if ((buffer = malloc((strlen(s) * 6) + 1)) != NULL) { + b = buffer; + while ((c = *s++) != 0) { + if ((c == '&') || (c == '<') || (c == '>') || (c == '"') || (c == '\'') || (!isprint(c))) { + b += sprintf(b, "&#%d;", c); + } + else { + *b++ = c; + } + } + *b = 0; + } + return buffer; +} + +// removes \r +char *unix_string(const char *s) +{ + char *buffer; + char *b; + char c; + + if ((buffer = malloc(strlen(s) + 1)) != NULL) { + b = buffer; + while ((c = *s++) != 0) + if (c != '\r') *b++ = c; + *b = 0; + } + return buffer; +} + +// # days, ##:##:## +char *reltime(char *buf, time_t t) +{ + int days; + int m; + + if (t < 0) t = 0; + days = t / 86400; + m = t / 60; + sprintf(buf, "%d day%s, %02d:%02d:%02d", days, ((days==1) ? "" : "s"), ((m / 60) % 24), (m % 60), (int)(t % 60)); + return buf; +} + +int get_client_info(char *mac, char *ifname) +{ + FILE *f; + char s[256]; + char ips[16]; + +/* +# cat /proc/net/arp +IP address HW type Flags HW address Mask Device +192.168.0.1 0x1 0x2 00:01:02:03:04:05 * vlan1 +192.168.1.5 0x1 0x2 00:05:06:07:08:09 * br0 +*/ + + if ((f = fopen("/proc/net/arp", "r")) != NULL) { + while (fgets(s, sizeof(s), f)) { + if (sscanf(s, "%15s %*s %*s %17s %*s %16s", ips, mac, ifname) == 3) { + if (inet_addr(ips) == clientsai.sin_addr.s_addr) { + fclose(f); + return 1; + } + } + } + fclose(f); + } + return 0; +} + + + + + +// <% lanip(mode); %> +// <mode> +// 1 return first 3 octets (192.168.1) +// 2 return last octet (1) +// else return full (192.168.1.1) + +void asp_lanip(int argc, char **argv) +{ + char *nv, *p; + char s[64]; + char mode; + + mode = argc ? *argv[0] : 0; + + if ((nv = nvram_get("lan_ipaddr")) != NULL) { + strcpy(s, nv); + if ((p = strrchr(s, '.')) != NULL) { + *p = 0; + web_puts((mode == '1') ? s : (mode == '2') ? (p + 1) : nv); + } + } +} + +void asp_lipp(int argc, char **argv) +{ + char *one = "1"; + asp_lanip(1, &one); +} + +// <% psup(process); %> +// returns 1 if process is running + +void asp_psup(int argc, char **argv) +{ + if (argc == 1) web_printf("%d", pidof(argv[0]) > 0); +} + +/* +# cat /proc/meminfo + total: used: free: shared: buffers: cached: +Mem: 14872576 12877824 1994752 0 1236992 4837376 +Swap: 0 0 0 +MemTotal: 14524 kB +MemFree: 1948 kB +MemShared: 0 kB +Buffers: 1208 kB +Cached: 4724 kB +SwapCached: 0 kB +Active: 4364 kB +Inactive: 2952 kB +HighTotal: 0 kB +HighFree: 0 kB +LowTotal: 14524 kB +LowFree: 1948 kB +SwapTotal: 0 kB +SwapFree: 0 kB + +*/ + +typedef struct { + unsigned long total; + unsigned long free; + unsigned long shared; + unsigned long buffers; + unsigned long cached; + unsigned long swaptotal; + unsigned long swapfree; + unsigned long maxfreeram; +} meminfo_t; + +static int get_memory(meminfo_t *m) +{ + FILE *f; + char s[128]; + int ok = 0; + + if ((f = fopen("/proc/meminfo", "r")) != NULL) { + while (fgets(s, sizeof(s), f)) { + if (strncmp(s, "Mem:", 4) == 0) { + if (sscanf(s + 6, "%ld %*d %ld %ld %ld %ld", &m->total, &m->free, &m->shared, &m->buffers, &m->cached) == 5) + ++ok; + } + else if (strncmp(s, "SwapTotal:", 10) == 0) { + m->swaptotal = strtoul(s + 12, NULL, 10) * 1024; + ++ok; + } + else if (strncmp(s, "SwapFree:", 9) == 0) { + m->swapfree = strtoul(s + 11, NULL, 10) * 1024; + ++ok; + break; + } + } + fclose(f); + } + if (ok != 3) { + memset(m, 0, sizeof(*m)); + return 0; + } + m->maxfreeram = m->free; + if (nvram_match("t_cafree", "1")) m->maxfreeram += m->cached; + return 1; +} + +void asp_sysinfo(int argc, char **argv) +{ + struct sysinfo si; + char s[64]; + meminfo_t mem; + + web_puts("\nsysinfo = {\n"); + sysinfo(&si); + get_memory(&mem); + web_printf( + "\tuptime: %ld,\n" + "\tuptime_s: '%s',\n" + "\tloads: [%ld, %ld, %ld],\n" + "\ttotalram: %ld,\n" + "\tfreeram: %ld,\n" + "\tshareram: %ld,\n" + "\tbufferram: %ld,\n" + "\tcached: %ld,\n" + "\ttotalswap: %ld,\n" + "\tfreeswap: %ld,\n" + "\ttotalfreeram: %ld,\n" + "\tprocs: %d\n", + si.uptime, + reltime(s, si.uptime), + si.loads[0], si.loads[1], si.loads[2], + mem.total, mem.free, + mem.shared, mem.buffers, mem.cached, + mem.swaptotal, mem.swapfree, + mem.maxfreeram, + si.procs); + web_puts("};\n"); +} + +void asp_activeroutes(int argc, char **argv) +{ + FILE *f; + char s[512]; + char dev[17]; + unsigned long dest; + unsigned long gateway; + unsigned long flags; + unsigned long mask; + unsigned metric; + struct in_addr ia; + char s_dest[16]; + char s_gateway[16]; + char s_mask[16]; + int n; + + web_puts("\nactiveroutes = ["); + n = 0; + if ((f = fopen("/proc/net/route", "r")) != NULL) { + while (fgets(s, sizeof(s), f)) { + if (sscanf(s, "%16s%lx%lx%lx%*s%*s%u%lx", dev, &dest, &gateway, &flags, &metric, &mask) != 6) continue; + if ((flags & RTF_UP) == 0) continue; + if (dest != 0) { + ia.s_addr = dest; + strcpy(s_dest, inet_ntoa(ia)); + } + else { + strcpy(s_dest, "default"); + } + if (gateway != 0) { + ia.s_addr = gateway; + strcpy(s_gateway, inet_ntoa(ia)); + } + else { + strcpy(s_gateway, "*"); + } + ia.s_addr = mask; + strcpy(s_mask, inet_ntoa(ia)); + web_printf("%s['%s','%s','%s','%s',%u]", n ? "," : "", dev, s_dest, s_gateway, s_mask, metric); + ++n; + } + fclose(f); + } + web_puts("];\n"); +} + +void asp_cgi_get(int argc, char **argv) +{ + const char *v; + int i; + + for (i = 0; i < argc; ++i) { + v = webcgi_get(argv[i]); + if (v) web_puts(v); + } +} + +void asp_time(int argc, char **argv) +{ + time_t t; + char s[64]; + + t = time(NULL); + if (t < Y2K) { + web_puts("Not Available"); + } + else { + strftime(s, sizeof(s), "%a, %d %b %Y %H:%M:%S %z", localtime(&t)); + web_puts(s); + } +} + +void asp_wanup(int argc, char **argv) +{ + web_puts(check_wanup() ? "1" : "0"); +} + +void asp_wanstatus(int argc, char **argv) +{ + const char *p; + + if ((using_dhcpc()) && (f_exists("/var/lib/misc/dhcpc.renewing"))) { + p = "Renewing..."; + } + else if (check_wanup()) { + p = "Connected"; + } + else if (f_exists("/var/lib/misc/wan.connecting")) { + p = "Connecting..."; + } + else { + p = "Disconnected"; + } + web_puts(p); +} + +void asp_link_uptime(int argc, char **argv) +{ + struct sysinfo si; + char buf[64]; + long uptime; + + buf[0] = '-'; + buf[1] = 0; + if (check_wanup()) { + sysinfo(&si); + if (f_read("/var/lib/misc/wantime", &uptime, sizeof(uptime)) == sizeof(uptime)) { + reltime(buf, si.uptime - uptime); + } + } + web_puts(buf); +} + +void asp_rrule(int argc, char **argv) +{ + char s[32]; + int i; + + i = nvram_get_int("rruleN"); + sprintf(s, "rrule%d", i); + web_puts("\nrrule = '"); + web_putj(nvram_safe_get(s)); + web_printf("';\nrruleN = %d;\n", i); +} + +void asp_compmac(int argc, char **argv) +{ + char mac[32]; + char ifname[32]; + + if (get_client_info(mac, ifname)) { + web_puts(mac); + } +} + +void asp_ident(int argc, char **argv) +{ + web_puth(nvram_safe_get("router_name")); +} + +void asp_statfs(int argc, char **argv) +{ + struct statfs sf; + + if (argc != 2) return; + + // used for /cifs/, /jffs/... if it returns squashfs type, assume it's not mounted + if ((statfs(argv[0], &sf) != 0) || (sf.f_type == 0x73717368)) + memset(&sf, 0, sizeof(sf)); + + web_printf( + "\n%s = {\n" + "\tsize: %llu,\n" + "\tfree: %llu\n" + "};\n", + argv[1], + ((uint64_t)sf.f_bsize * sf.f_blocks), + ((uint64_t)sf.f_bsize * sf.f_bfree)); +} + +void asp_notice(int argc, char **argv) +{ + char s[256]; + char buf[2048]; + + if (argc != 1) return; + snprintf(s, sizeof(s), "/var/notice/%s", argv[0]); + if (f_read_string(s, buf, sizeof(buf)) <= 0) return; + web_putj(buf); +} + +void wo_wakeup(char *url) +{ + char *mac; + char *p; + char *end; + + if ((mac = webcgi_get("mac")) != NULL) { + end = mac + strlen(mac); + while (mac < end) { + while ((*mac == ' ') || (*mac == '\t') || (*mac == '\r') || (*mac == '\n')) ++mac; + if (*mac == 0) break; + + p = mac; + while ((*p != 0) && (*p != ' ') && (*p != '\r') && (*p != '\n')) ++p; + *p = 0; + + eval("ether-wake", "-i", nvram_safe_get("lan_ifname"), mac); + mac = p + 1; + } + } + common_redirect(); +} + +void asp_dns(int argc, char **argv) +{ + char s[128]; + int i; + const dns_list_t *dns; + + dns = get_dns(); // static buffer + strcpy(s, "\ndns = ["); + for (i = 0 ; i < dns->count; ++i) { + sprintf(s + strlen(s), "%s'%s:%u'", i ? "," : "", inet_ntoa(dns->dns[i].addr), dns->dns[i].port); + } + strcat(s, "];\n"); + web_puts(s); +} + +void wo_resolve(char *url) +{ + char *p; + char *ip; + struct hostent *he; + struct in_addr ia; + char comma; + char *js; + + comma = ' '; + web_puts("\nresolve_data = [\n"); + if ((p = webcgi_get("ip")) != NULL) { + while ((ip = strsep(&p, ",")) != NULL) { + ia.s_addr = inet_addr(ip); + he = gethostbyaddr(&ia, sizeof(ia), AF_INET); + js = js_string(he ? he->h_name : ""); + web_printf("%c['%s','%s']", comma, inet_ntoa(ia), js); + free(js); + comma = ','; + } + } + web_puts("];\n"); +} + + diff --git a/release/src/router/httpd/nvram.c b/release/src/router/httpd/nvram.c new file mode 100644 index 00000000..beacf788 --- /dev/null +++ b/release/src/router/httpd/nvram.c @@ -0,0 +1,70 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + + +// <% nvram("x,y,z"); %> -> nvram = {'x': '1','y': '2','z': '3'}; +void asp_nvram(int argc, char **argv) +{ + char *list; + char *p, *k; + const char *v; + + if ((argc != 1) || ((list = strdup(argv[0])) == NULL)) return; + web_puts("\nnvram = {\n"); + p = list; + while ((k = strsep(&p, ",")) != NULL) { + if (*k == 0) continue; + v = nvram_get(k); + if (!v) { + v = ""; + } + web_printf("\t%s: '", k); + web_putj(v); + web_puts("',\n"); + } + free(list); + + web_puts("\thttp_id: '"); + web_putj(nvram_safe_get("http_id")); + web_puts("',\n"); + + web_puts("\tweb_mx: '"); + web_putj(nvram_safe_get("web_mx")); + web_puts("',\n"); + + web_puts("\tweb_pb: '"); + web_putj(nvram_safe_get("web_pb")); + web_puts("'};\n"); +} + +// <% nvramseq('foo', 'bar%d', 5, 8); %> -> foo = ['a','b','c']; +void asp_nvramseq(int argc, char **argv) +{ + int i, e; + char s[256]; + + if (argc != 4) return; + + web_printf("\n%s = [\n", argv[0]); + e = atoi(argv[3]); + for (i = atoi(argv[2]); i <= e; ++i) { + snprintf(s, sizeof(s), argv[1], i); + web_puts("'"); + web_putj(nvram_safe_get(s)); + web_puts((i == e) ? "'" : "',"); + } + web_puts("];\n"); +} + +void asp_nv(int argc, char **argv) +{ + if (argc == 1) { + web_puts(nvram_safe_get(argv[0])); + } +} diff --git a/release/src/router/httpd/openssl.cnf b/release/src/router/httpd/openssl.cnf deleted file mode 100644 index 12475c45..00000000 --- a/release/src/router/httpd/openssl.cnf +++ /dev/null @@ -1,263 +0,0 @@ -# -# OpenSSL example configuration file. -# This is mostly being used for generation of certificate requests. -# - -# This definition stops the following lines choking if HOME isn't -# defined. -HOME = . -RANDFILE = $ENV::HOME/.rnd - -# Extra OBJECT IDENTIFIER info: -#oid_file = $ENV::HOME/.oid -oid_section = new_oids - -# To use this configuration file with the "-extfile" option of the -# "openssl x509" utility, name here the section containing the -# X.509v3 extensions to use: -# extensions = -# (Alternatively, use a configuration file that has only -# X.509v3 extensions in its main [= default] section.) - -[ new_oids ] - -# We can add new OIDs in here for use by 'ca' and 'req'. -# Add a simple OID like this: -# testoid1=1.2.3.4 -# Or use config file substitution like this: -# testoid2=${testoid1}.5.6 - -#################################################################### -[ ca ] -default_ca = CA_default # The default ca section - -#################################################################### -[ CA_default ] - -#dir = ./demoCA # Where everything is kept -dir = /usr/share # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -new_certs_dir = $dir/newcerts # default place for new certs. - -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/cakey.pem# The private key -RANDFILE = $dir/private/.rand # private random number file - -x509_extensions = usr_cert # The extentions to add to the cert - -# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs -# so this is commented out by default to leave a V1 CRL. -# crl_extensions = crl_ext - -default_days = 3650 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = md5 # which md to use. -preserve = no # keep passed DN ordering - -# A few difference way of specifying how similar the request should look -# For type CA, the listed attributes must be the same, and the optional -# and supplied fields are just that :-) -policy = policy_match - -# For the CA policy -[ policy_match ] -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -# For the 'anything' policy -# At this point in time, you must list all acceptable 'object' -# types. -[ policy_anything ] -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -#################################################################### -[ req ] -default_bits = 2048 -default_keyfile = privkey.pem -distinguished_name = req_distinguished_name -attributes = req_attributes -x509_extensions = v3_ca # The extentions to add to the self signed cert - -# Passwords for private keys if not present they will be prompted for -#input_password = secret -#output_password = secret - -# This sets a mask for permitted string types. There are several options. -# default: PrintableString, T61String, BMPString. -# pkix : PrintableString, BMPString. -# utf8only: only UTF8Strings. -# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). -# MASK:XXXX a literal mask value. -# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings -# so use this option with caution! -string_mask = nombstr - -req_extensions = v3_req # The extensions to add to a certificate request - -[ req_distinguished_name ] -countryName = Country Name (2 letter code) -countryName_default = GB -countryName_value = US -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Berkshire -stateOrProvinceName_value = California - -localityName = Locality Name (eg, city) -localityName_default = Newbury -localityName_value = Irvine - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = My Company Ltd -0.organizationName_value = Cisco-Linksys, LLC - -# we can do this but it is not needed normally :-) -#1.organizationName = Second Organization Name (eg, company) -#1.organizationName_default = World Wide Web Pty Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -organizationalUnitName_value = Division - -commonName = Common Name (eg, your name or your server\'s hostname) -commonName_max = 64 -commonName_value = Linksys - -emailAddress = Email Address -emailAddress_max = 40 -emailAddress_value = support@linksys.com - -# SET-ex3 = SET extension number 3 - -[ req_attributes ] -challengePassword = A challenge password -challengePassword_min = 4 -challengePassword_max = 20 -challengePassword_value = - -unstructuredName = An optional company name -unstructuredName_value = - -[ usr_cert ] - -# These extensions are added when 'ca' signs a request. - -# This goes against PKIX guidelines but some CAs do it and some software -# requires this to avoid interpreting an end user certificate as a CA. - -basicConstraints=CA:FALSE - -# Here are some examples of the usage of nsCertType. If it is omitted -# the certificate can be used for anything *except* object signing. - -# This is OK for an SSL server. -# nsCertType = server - -# For an object signing certificate this would be used. -# nsCertType = objsign - -# For normal client use this is typical -# nsCertType = client, email - -# and for everything including object signing: -# nsCertType = client, email, objsign - -# This is typical in keyUsage for a client certificate. -# keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -# This will be displayed in Netscape's comment listbox. -nsComment = "OpenSSL Generated Certificate" - -# PKIX recommendations harmless if included in all certificates. -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid,issuer:always - -# This stuff is for subjectAltName and issuerAltname. -# Import the email address. -# subjectAltName=email:copy - -# Copy subject details -# issuerAltName=issuer:copy - -#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem -#nsBaseUrl -#nsRevocationUrl -#nsRenewalUrl -#nsCaPolicyUrl -#nsSslServerName - -[ v3_req ] - -# Extensions to add to a certificate request - -basicConstraints = CA:FALSE -keyUsage = nonRepudiation, digitalSignature, keyEncipherment - -[ v3_ca ] - - -# Extensions for a typical CA - - -# PKIX recommendation. - -subjectKeyIdentifier=hash - -authorityKeyIdentifier=keyid:always,issuer:always - -# This is what PKIX recommends but some broken software chokes on critical -# extensions. -#basicConstraints = critical,CA:true -# So we do this instead. -basicConstraints = CA:true - -# Key usage: this is typical for a CA certificate. However since it will -# prevent it being used as an test self-signed certificate it is best -# left out by default. -# keyUsage = cRLSign, keyCertSign - -# Some might want this also -# nsCertType = sslCA, emailCA - -# Include email address in subject alt name: another PKIX recommendation -# subjectAltName=email:copy -# Copy issuer details -# issuerAltName=issuer:copy - -# DER hex encoding of an extension: beware experts only! -# obj=DER:02:03 -# Where 'obj' is a standard or added object -# You can even override a supported extension: -# basicConstraints= critical, DER:30:03:01:01:FF - -[ crl_ext ] - -# CRL extensions. -# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. - -# issuerAltName=issuer:copy -authorityKeyIdentifier=keyid:always,issuer:always - -[ engine ] -default = openssl -# rsa = openssl -# dsa = openssl -# dh = openssl -# rand = openssl -# bn_mod_exp = openssl -# bn_mod_exp_crt = openssl diff --git a/release/src/router/httpd/parser.c b/release/src/router/httpd/parser.c new file mode 100644 index 00000000..9dc4e94d --- /dev/null +++ b/release/src/router/httpd/parser.c @@ -0,0 +1,187 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + + +#define DEBUG 1 + +/* + <% ident(arg, "arg", 'arg'); %> + + Syntax checking is very relaxed and all arguments are considered a + string. Example, the following are the same: + + <% ident(foo); %> + <% ident('foo'); %> + +*/ +int parse_asp(const char *path) +{ + char *buffer; + char *cp; + char *a, *b, *c; + char x; + int argc; + char *argv[32]; + char *ident; + const aspapi_t *api; + +#if TOMATO_N + // temp!!! + char npath[256]; + int n; + + if (!nvram_match("debug_npages", "0")) { + if (((a = strrchr(path, '.')) != NULL) && ((n = a - path) > 3) && (strncmp(a - 2, "-n", 2) != 0)) { + memcpy(npath, path, n); + memcpy(npath + n, "-n", 2); + strcpy(npath + n + 2, a); + if (f_exists(npath)) { + path = npath; + } + } + } +#endif + + if (f_read_alloc_string(path, &buffer, 128 * 1024) < 0) { + free(buffer); + if (!header_sent) send_error(500, NULL, "Read error"); + return 0; + } + + if (!header_sent) send_header(200, NULL, mime_html, 0); + + // <% id(arg, arg); %> + cp = buffer; + while (*cp) { + if ((b = strstr(cp, "%>")) == NULL) { + web_puts(cp); + break; + } + *b = 0; + + //xx <% <% %> + //xx %> + + a = cp; + while ((c = strstr(a, "<%")) != NULL) { + a = c + 2; + } + + if (a == cp) { + *b = '%'; + b += 2; + web_write(cp, b - cp); + cp = b; + continue; + } + + web_write(cp, (a - cp) - 2); + + cp = b + 2; + + while (*a == ' ') ++a; + ident = a; + while (((*a >= 'a') && (*a <= 'z')) || ((*a >= 'A') && (*a <= 'Z')) || ((*a >= '0') && (*a <= '9')) || (*a == '_')) { + ++a; + } + if (ident == a) { +#ifdef DEBUG + syslog(LOG_WARNING, "Identifier not found in %s @%u", path, a - buffer); +#endif + continue; + } + b = a; + while (*a == ' ') ++a; + if (*a++ != '(') { +#ifdef DEBUG + syslog(LOG_WARNING, "Expecting ( in %s @%u", path, a - buffer); +#endif + continue; + } + *b = 0; + + // <% foo(123, "arg"); %> + // a -----^ ^--- null + +// printf("\n[[['%s'\n", ident); + + argc = 0; + while (*a) { + while (*a == ' ') ++a; + if (*a == ')') { +FINAL: + ++a; + while ((*a == ' ') || (*a == ';')) ++a; + if (*a != 0) break; + + for (api = aspapi; api->name; ++api) { + if (strcmp(api->name, ident) == 0) { + api->exec(argc, argv); + break; + } + } + + a = NULL; +/* + int z; + for (z = 0; z < argc; ++z) { + printf(" %d '%s'\n", z, argv[z]); + } +*/ + break; + } + + if (argc >= 32) { +#ifdef DEBUG + syslog(LOG_WARNING, "Error while parsing arguments in %s @%u", path, a - buffer); +#endif + break; + } + + if ((*a == '"') || (*a == '\'')) { + x = *a; + argv[argc++] = a + 1; + while ((*++a != x) && (*a != 0)) { + if (*a == '\\') { + if (*++a == 0) break; + *(a - 1) = *a; + } + } + if (*a == 0) break; + *a++ = 0; + } + else { + argv[argc++] = a; + while ((*a != ',') && (*a != ')') && (*a != ' ') && (*a != 0)) ++a; + } + while (*a == ' ') ++a; + if (*a == ')') { + *a = 0; + goto FINAL; + } + if (*a != ',') break; + *a++ = 0; + } + +#ifdef DEBUG + if (a != NULL) syslog(LOG_WARNING, "Error while parsing arguments in %s @%u", path, a - buffer); +#endif + +// printf("argc=%d]]]\n", argc); + } + + + free(buffer); + return 1; +} + +void wo_asp(char *path) +{ + parse_asp(path); +} diff --git a/release/src/router/httpd/prebuilt/ezc.o b/release/src/router/httpd/prebuilt/ezc.o Binary files differdeleted file mode 100644 index 4e7b4659..00000000 --- a/release/src/router/httpd/prebuilt/ezc.o +++ /dev/null diff --git a/release/src/router/httpd/tomato.c b/release/src/router/httpd/tomato.c new file mode 100644 index 00000000..01b912dc --- /dev/null +++ b/release/src/router/httpd/tomato.c @@ -0,0 +1,935 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2010 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <sys/sysinfo.h> +#include <sys/stat.h> +#include <arpa/inet.h> +#include <time.h> + + +// #define DEBUG_NOEXECSERVICE +// #define DEBUG_NVRAMSET(k, v) cprintf("nvram set %s=%s\n", k, v); +#define DEBUG_NVRAMSET(k, v) do { } while(0); + + +char *post_buf = NULL; +int rboot = 0; +extern int post; + +static void asp_css(int argc, char **argv); +static void asp_resmsg(int argc, char **argv); + +// +static void wo_tomato(char *url); +static void wo_update(char *url); +static void wo_service(char *url); +static void wo_shutdown(char *url); +static void wo_nvcommit(char *url); +// static void wo_logout(char *url); + + +// ---------------------------------------------------------------------------- + + +void exec_service(const char *action) +{ + int i; + + _dprintf("exec_service: %s\n", action); + + i = 10; + while ((!nvram_match("action_service", "")) && (i-- > 0)) { + _dprintf("%s: waiting before %d\n", __FUNCTION__, i); + sleep(1); + } + + nvram_set("action_service", action); + kill(1, SIGUSR1); + + i = 3; + while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) { + _dprintf("%s: waiting after %d\n", __FUNCTION__, i); + sleep(1); + } + +/* + if (atoi(webcgi_safeget("_service_wait", ""))) { + i = 10; + while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) { + _dprintf("%s: waiting after %d\n", __FUNCTION__, i); + sleep(1); + } + } +*/ +} + +static void wi_generic_noid(char *url, int len, char *boundary) +{ + if (post == 1) { + if (len >= (32 * 1024)) { +// syslog(LOG_WARNING, "POST max"); + exit(1); + } + + if (!post_buf) free(post_buf); + if ((post_buf = malloc(len + 1)) == NULL) { +// syslog(LOG_CRIT, "Unable to allocate post buffer"); + exit(1); + } + + if (web_read_x(post_buf, len) != len) { + exit(1); + } + post_buf[len] = 0; + webcgi_init(post_buf); + } +} + +void wi_generic(char *url, int len, char *boundary) +{ + wi_generic_noid(url, len, boundary); + check_id(url); +} + +static void wo_blank(char *url) +{ + web_puts("\n\n\n\n"); +} + +static void wo_favicon(char *url) +{ + send_header(200, NULL, "image/vnd.microsoft.icon", 0); + do_file(url); +/* + if (nvram_match("web_favicon", "1")) { + send_header(200, NULL, "image/vnd.microsoft.icon", 0); + do_file(url); + } + else { + send_error(404, NULL, NULL); + } +*/ +} + +static void wo_cfe(char *url) +{ + do_file("/dev/mtd/0ro"); +} + +static void wo_nvram(char *url) +{ + web_pipecmd("nvram show", WOF_NONE); +} + +static void wo_iptables(char *url) +{ + web_pipecmd("iptables -nvL; iptables -t nat -nvL; iptables -t mangle -nvL", WOF_NONE); +} + +/* +static void wo_spin(char *url) +{ + char s[64]; + + strlcpy(s, nvram_safe_get("web_css"), sizeof(s)); + strlcat(s, "_spin.gif", sizeof(s)); + if (f_exists(s)) do_file(s); + else do_file("_spin.gif"); +} +*/ + +void common_redirect(void) +{ + if (atoi(webcgi_safeget("_ajax", ""))) { + send_header(200, NULL, mime_html, 0); + web_puts("OK"); + } + else { + redirect(webcgi_safeget("_redirect", "/")); + } +} + +// ---------------------------------------------------------------------------- + +const struct mime_handler mime_handlers[] = { + { "update.cgi", mime_javascript, 0, wi_generic, wo_update, 1 }, + { "tomato.cgi", NULL, 0, wi_generic, wo_tomato, 1 }, + + { "debug.js", mime_javascript, 5, wi_generic_noid, wo_blank, 1 }, // while debugging + { "cfe/*.bin", mime_binary, 0, wi_generic, wo_cfe, 1 }, + { "nvram/*.txt", mime_binary, 0, wi_generic, wo_nvram, 1 }, + { "ipt/*.txt", mime_binary, 0, wi_generic, wo_iptables, 1 }, + + { "cfg/*.cfg", NULL, 0, wi_generic, wo_backup, 1 }, + { "cfg/restore.cgi", mime_html, 0, wi_restore, wo_restore, 1 }, + { "cfg/defaults.cgi", NULL, 0, wi_generic, wo_defaults, 1 }, + + { "bwm/*.gz", NULL, 0, wi_generic, wo_bwmbackup, 1 }, + { "bwm/restore.cgi", NULL, 0, wi_bwmrestore, wo_bwmrestore, 1 }, + + { "logs/view.cgi", NULL, 0, wi_generic, wo_viewlog, 1 }, + { "logs/*.txt", NULL, 0, wi_generic, wo_syslog, 1 }, + + { "logout.asp", NULL, 0, wi_generic, wo_asp, 1 }, + { "clearcookies.asp", NULL, 0, wi_generic, wo_asp, 1 }, + +// { "spin.gif", NULL, 0, wi_generic_noid, wo_spin, 1 }, + + { "**.asp", NULL, 0, wi_generic_noid, wo_asp, 1 }, + { "**.css", "text/css", 2, wi_generic_noid, do_file, 1 }, + { "**.htm", mime_html, 2, wi_generic_noid, do_file, 1 }, + { "**.gif", "image/gif", 5, wi_generic_noid, do_file, 1 }, + { "**.jpg", "image/jpeg", 5, wi_generic_noid, do_file, 1 }, + { "**.png", "image/png", 5, wi_generic_noid, do_file, 1 }, + { "**.js", mime_javascript, 2, wi_generic_noid, do_file, 1 }, + { "**.jsx", mime_javascript, 0, wi_generic, wo_asp, 1 }, + { "**.svg", "image/svg+xml", 2, wi_generic_noid, do_file, 1 }, + { "**.txt", mime_plain, 2, wi_generic_noid, do_file, 1 }, + { "**.bin", mime_binary, 0, wi_generic_noid, do_file, 1 }, + { "**.bino", mime_octetstream, 0, wi_generic_noid, do_file, 1 }, + { "favicon.ico", NULL, 5, wi_generic_noid, wo_favicon, 1 }, + + + { "dhcpc.cgi", NULL, 0, wi_generic, wo_dhcpc, 1 }, + { "dhcpd.cgi", mime_javascript, 0, wi_generic, wo_dhcpd, 1 }, + { "nvcommit.cgi", NULL, 0, wi_generic, wo_nvcommit, 1 }, + { "ping.cgi", mime_javascript, 0, wi_generic, wo_ping, 1 }, + { "trace.cgi", mime_javascript, 0, wi_generic, wo_trace, 1 }, + { "upgrade.cgi", mime_html, 0, wi_upgrade, wo_flash, 1 }, + { "upnp.cgi", NULL, 0, wi_generic, wo_upnp, 1 }, + { "wakeup.cgi", NULL, 0, wi_generic, wo_wakeup, 1 }, + { "wlmnoise.cgi", mime_html, 0, wi_generic, wo_wlmnoise, 1 }, + { "wlradio.cgi", NULL, 0, wi_generic, wo_wlradio, 1 }, + { "resolve.cgi", mime_javascript, 0, wi_generic, wo_resolve, 1 }, + { "expct.cgi", mime_html, 0, wi_generic, wo_expct, 1 }, + { "service.cgi", NULL, 0, wi_generic, wo_service, 1 }, +// { "logout.cgi", NULL, 0, wi_generic, wo_logout, 0 }, // see httpd.c + { "shutdown.cgi", mime_html, 0, wi_generic, wo_shutdown, 1 }, + +#ifdef BLACKHOLE + { "blackhole.cgi", NULL, 0, wi_blackhole, NULL, 1 }, +#endif +// { "test", mime_html, 0, wi_generic, wo_test, 1 }, + { NULL, NULL, 0, NULL, NULL, 1 } +}; + +const aspapi_t aspapi[] = { + { "activeroutes", asp_activeroutes }, + { "arplist", asp_arplist }, + { "bandwidth", asp_bandwidth }, + { "build_time", asp_build_time }, + { "cgi_get", asp_cgi_get }, + { "compmac", asp_compmac }, + { "ctcount", asp_ctcount }, + { "ctdump", asp_ctdump }, + { "ddnsx", asp_ddnsx }, + { "devlist", asp_devlist }, + { "dhcpc_time", asp_dhcpc_time }, + { "dns", asp_dns }, + { "ident", asp_ident }, + { "lanip", asp_lanip }, + { "layer7", asp_layer7 }, + { "link_uptime", asp_link_uptime }, + { "lipp", asp_lipp }, + { "netdev", asp_netdev }, + { "notice", asp_notice }, + { "nv", asp_nv }, + { "nvram", asp_nvram }, + { "nvramseq", asp_nvramseq }, + { "psup", asp_psup }, + { "qrate", asp_qrate }, + { "resmsg", asp_resmsg }, + { "rrule", asp_rrule }, + { "statfs", asp_statfs }, + { "sysinfo", asp_sysinfo }, + { "time", asp_time }, + { "upnpinfo", asp_upnpinfo }, + { "version", asp_version }, + { "wanstatus", asp_wanstatus }, + { "wanup", asp_wanup }, + { "wlchannel", asp_wlchannel }, + { "wlclient", asp_wlclient }, + { "wlcrssi", asp_wlcrssi }, + { "wlnoise", asp_wlnoise }, + { "wlradio", asp_wlradio }, + { "wlscan", asp_wlscan }, + { "css", asp_css }, + { NULL, NULL } +}; + +// ----------------------------------------------------------------------------- + +static void asp_css(int argc, char **argv) +{ + const char *css = nvram_safe_get("web_css"); + + if (strcmp(css, "tomato") != 0) { + web_printf("<link rel='stylesheet' type='text/css' href='%s.css'>", css); + } +} + +// ----------------------------------------------------------------------------- + +const char *resmsg_get(void) +{ + return webcgi_safeget("resmsg", ""); +} + +void resmsg_set(const char *msg) +{ + webcgi_set("resmsg", strdup(msg)); // m ok +} + +int resmsg_fread(const char *fname) +{ + char s[256]; + char *p; + + f_read_string(fname, s, sizeof(s)); + if ((p = strchr(s, '\n')) != NULL) *p = 0; + if (s[0]) { + resmsg_set(s); + return 1; + } + return 0; +} + +static void asp_resmsg(int argc, char **argv) +{ + char *p; + + if ((p = js_string(webcgi_safeget("resmsg", (argc > 0) ? argv[0] : ""))) == NULL) return; + web_printf("\nresmsg='%s';\n", p); + free(p); +} + +// ---------------------------------------------------------------------------- + +// verification... simple sanity checks. UI should verify all fields. + +// todo: move and re-use for filtering - zzz + +typedef union { + int i; + long l; + const char *s; +} nvset_varg_t; + +typedef struct { + const char *name; + enum { + VT_NONE, // no checking + VT_LENGTH, // check length of string + VT_TEXT, // strip \r, check length of string + VT_RANGE, // expect an integer, check range + VT_IP, // expect an ip address + VT_MAC, // expect a mac address + VT_TEMP // no checks, no commit + } vtype; + nvset_varg_t va; + nvset_varg_t vb; +} nvset_t; + + +#define V_NONE VT_NONE, { }, { } +#define V_01 VT_RANGE, { .l = 0 }, { .l = 1 } +#define V_PORT VT_RANGE, { .l = 2 }, { .l = 65535 } +#define V_ONOFF VT_LENGTH, { .i = 2 }, { .i = 3 } +#define V_WORD VT_LENGTH, { .i = 1 }, { .i = 16 } +#define V_LENGTH(min, max) VT_LENGTH, { .i = min }, { .i = max } +#define V_TEXT(min, max) VT_TEXT, { .i = min }, { .i = max } +#define V_RANGE(min, max) VT_RANGE, { .l = min }, { .l = max } +#define V_IP VT_IP, { }, { } +#define V_OCTET VT_RANGE, { .l = 0 }, { .l = 255 } +#define V_NUM VT_RANGE, { .l = 0 }, { .l = 0x7FFFFFFF } +#define V_TEMP VT_TEMP, { }, { } + +static const nvset_t nvset_list[] = { + +// basic-ident + { "router_name", V_LENGTH(0, 32) }, + { "wan_hostname", V_LENGTH(0, 32) }, + { "wan_domain", V_LENGTH(0, 32) }, + +// basic-time + { "tm_tz", V_LENGTH(1, 64) }, // PST8PDT + { "tm_sel", V_LENGTH(1, 64) }, // PST8PDT + { "tm_dst", V_01 }, + { "ntp_updates", V_RANGE(-1, 24) }, + { "ntp_tdod", V_01 }, + { "ntp_server", V_LENGTH(1, 150) }, // x y z + { "ntp_kiss", V_LENGTH(0, 255) }, + +// basic-static + { "dhcpd_static", V_LENGTH(0, 106*101)}, // 106 (max chars per entry) x 100 entries + +// basic-ddns + { "ddnsx0", V_LENGTH(0, 2048) }, + { "ddnsx1", V_LENGTH(0, 2048) }, + { "ddnsx0_cache", V_LENGTH(0, 1) }, // only to clear + { "ddnsx1_cache", V_LENGTH(0, 1) }, + { "ddnsx_ip", V_LENGTH(0, 32) }, + { "ddnsx_save", V_01 }, + { "ddnsx_refresh", V_RANGE(0, 365) }, + +// basic-network + // WAN + { "wan_proto", V_LENGTH(1, 16) }, // disabled, dhcp, static, pppoe, pptp, l2tp + { "wan_ipaddr", V_IP }, + { "wan_netmask", V_IP }, + { "wan_gateway", V_IP }, + { "hb_server_ip", V_LENGTH(0, 32) }, + { "l2tp_server_ip", V_IP }, + { "pptp_server_ip", V_IP }, + { "ppp_username", V_LENGTH(0, 60) }, + { "ppp_passwd", V_LENGTH(0, 60) }, + { "ppp_service", V_LENGTH(0, 50) }, + { "ppp_demand", V_01 }, + { "ppp_idletime", V_RANGE(0, 1440) }, + { "ppp_redialperiod", V_RANGE(1, 86400) }, + { "mtu_enable", V_01 }, + { "wan_mtu", V_RANGE(576, 1500) }, + { "wan_islan", V_01 }, + + // LAN + { "lan_ipaddr", V_IP }, + { "lan_netmask", V_IP }, + { "lan_gateway", V_IP }, + { "wan_dns", V_LENGTH(0, 50) }, // ip ip ip + { "lan_proto", V_WORD }, // static, dhcp + { "dhcp_start", V_RANGE(1, 254) }, // remove ! + { "dhcp_num", V_RANGE(1, 255) }, // remove ! + { "dhcpd_startip", V_IP }, + { "dhcpd_endip", V_IP }, + { "dhcp_lease", V_RANGE(1, 10080) }, + { "wan_wins", V_IP }, + + // wireless + { "wl_radio", V_01 }, + { "wl_mode", V_LENGTH(2, 3) }, // ap, sta, wet, wds + { "wl_net_mode", V_LENGTH(5, 8) }, // disabled, mixed, b-only, g-only, bg-mixed, n-only [speedbooster] + { "wl_ssid", V_LENGTH(1, 32) }, + { "wl_closed", V_01 }, + { "wl_channel", V_RANGE(1, 14) }, +#if TOMATO_N + // ! update +#endif + + { "security_mode2", V_LENGTH(1, 32) }, // disabled, radius, wep, wpa_personal, wpa_enterprise, wpa2_personal, wpa2_enterprise + { "wl_radius_ipaddr", V_IP }, + { "wl_radius_port", V_PORT }, + { "wl_radius_key", V_LENGTH(1, 64) }, + { "wl_wep_bit", V_RANGE(64, 128) }, // 64 or 128 + { "wl_passphrase", V_LENGTH(0, 20) }, + { "wl_key", V_RANGE(1, 4) }, + { "wl_key1", V_LENGTH(0, 26) }, + { "wl_key2", V_LENGTH(0, 26) }, + { "wl_key3", V_LENGTH(0, 26) }, + { "wl_key4", V_LENGTH(0, 26) }, + { "wl_crypto", V_LENGTH(3, 8) }, // tkip, aes, tkip+aes + { "wl_wpa_psk", V_LENGTH(8, 64) }, + { "wl_wpa_gtk_rekey", V_RANGE(60, 7200) }, + + { "wl_lazywds", V_01 }, + { "wl_wds", V_LENGTH(0, 180) }, // mac mac mac (x 10) + + { "security_mode", V_LENGTH(1, 32) }, // disabled, radius, wpa, psk,wep, wpa2, psk2, wpa wpa2, psk psk2 + { "wds_enable", V_01 }, + { "wl_gmode", V_RANGE(-1, 6) }, + { "wl_wep", V_LENGTH(1, 32) }, // off, on, restricted,tkip,aes,tkip+aes + { "wl_akm", V_LENGTH(0, 32) }, // wpa, wpa2, psk, psk2, wpa wpa2, psk psk2, "" + { "wl_auth_mode", V_LENGTH(4, 6) }, // none, radius + +#if TOMATO_N + { "wl_nmode", V_NONE }, + { "wl_nreqd", V_NONE }, +#endif + +// basic-wfilter + { "wl_macmode", V_NONE }, // allow, deny, disabled + { "wl_maclist", V_LENGTH(0, 18*201) }, // 18 x 200 (11:22:33:44:55:66 ...) + { "macnames", V_LENGTH(0, 62*201) }, // 62 (12+1+48+1) x 50 (112233445566<..>) todo: re-use -- zzz + +// advanced-ctnf + { "ct_max", V_RANGE(128, 10240) }, + { "ct_tcp_timeout", V_LENGTH(20, 70) }, + { "ct_udp_timeout", V_LENGTH(5, 15) }, + { "nf_ttl", V_RANGE(-10, 10) }, + { "nf_l7in", V_01 }, + { "nf_rtsp", V_01 }, + { "nf_pptp", V_01 }, + { "nf_h323", V_01 }, + { "nf_ftp", V_01 }, + +// advanced-dhcpdns + { "dhcpd_slt", V_RANGE(-1, 43200) }, // -1=infinite, 0=follow normal lease time, >=1 custom + { "dhcpd_dmdns", V_01 }, + { "dhcpd_lmax", V_NUM }, + { "dhcpd_gwmode", V_NUM }, + { "dns_addget", V_01 }, + { "dns_intcpt", V_01 }, + { "dhcpc_minpkt", V_01 }, + { "dnsmasq_custom", V_TEXT(0, 2048) }, +// { "dnsmasq_norw", V_01 }, + +// advanced-firewall + { "block_wan", V_01 }, + { "multicast_pass", V_01 }, + { "block_loopback", V_01 }, + { "nf_loopback", V_NUM }, + { "ne_syncookies", V_01 }, + +// advanced-misc + { "wait_time", V_RANGE(3, 20) }, + { "wan_speed", V_RANGE(0, 4) }, + +// advanced-mac + { "mac_wan", V_LENGTH(0, 17) }, + { "mac_wl", V_LENGTH(0, 17) }, + +// advanced-routing + { "routes_static", V_LENGTH(0, 2048) }, + { "lan_stp", V_RANGE(0, 1) }, + { "wk_mode", V_LENGTH(1, 32) }, // gateway, router + { "dr_setting", V_RANGE(0, 3) }, + { "dr_lan_tx", V_LENGTH(0, 32) }, + { "dr_lan_rx", V_LENGTH(0, 32) }, + { "dr_wan_tx", V_LENGTH(0, 32) }, + { "dr_wan_rx", V_LENGTH(0, 32) }, + +// advanced-wireless + { "wl_afterburner", V_LENGTH(2, 4) }, // off, on, auto + { "wl_auth", V_01 }, + { "wl_rateset", V_LENGTH(2, 7) }, // all, default, 12 + { "wl_rate", V_RANGE(0, 54 * 1000 * 1000) }, + { "wl_mrate", V_RANGE(0, 54 * 1000 * 1000) }, + { "wl_gmode_protection",V_LENGTH(3, 4) }, // off, auto + { "wl_frameburst", V_ONOFF }, // off, on + { "wl_bcn", V_RANGE(1, 65535) }, + { "wl_dtim", V_RANGE(1, 255) }, + { "wl_frag", V_RANGE(256, 2346) }, + { "wl_rts", V_RANGE(0, 2347) }, + { "wl_ap_isolate", V_01 }, + { "wl_plcphdr", V_LENGTH(4, 5) }, // long, short + { "wl_antdiv", V_RANGE(0, 3) }, + { "wl_txant", V_RANGE(0, 3) }, + { "wl_txpwr", V_RANGE(0, 255) }, + { "wl_wme", V_ONOFF }, // off, on + { "wl_wme_no_ack", V_ONOFF }, // off, on + { "wl_maxassoc", V_RANGE(0, 255) }, + { "wl_distance", V_LENGTH(0, 5) }, // "", 1-99999 + { "wlx_hpamp", V_01 }, + { "wlx_hperx", V_01 }, + +#if TOMATO_N + { "wl_nmode_protection",V_WORD, }, // off, auto + { "wl_nmcsidx", V_RANGE(-2, 15), }, // -2 - 15 +#endif + +// forward-dmz + { "dmz_enable", V_01 }, + { "dmz_ipaddr", V_LENGTH(0, 15) }, + { "dmz_sip", V_LENGTH(0, 512) }, + +// forward-upnp + { "upnp_enable", V_NUM }, +#ifndef USE_MINIUPNPD + { "upnp_mnp", V_01 }, +// { "upnp_config", V_01 }, + { "upnp_ssdp_interval", V_RANGE(10, 9999) }, + { "upnp_max_age", V_RANGE(5, 9999) }, +#endif + +// forward-basic + { "portforward", V_LENGTH(0, 4096) }, + +// forward-triggered + { "trigforward", V_LENGTH(0, 4096) }, + + +// access restriction + { "rruleN", V_RANGE(0, 49) }, +// { "rrule##", V_LENGTH(0, 2048) }, // in save_variables() + +// admin-access + { "http_enable", V_01 }, + { "https_enable", V_01 }, + { "https_crt_save", V_01 }, + { "https_crt_cn", V_LENGTH(0, 64) }, + { "https_crt_gen", V_TEMP }, + { "remote_management", V_01 }, + { "remote_mgt_https", V_01 }, + { "http_lanport", V_PORT }, + { "https_lanport", V_PORT }, + { "web_wl_filter", V_01 }, + { "web_css", V_LENGTH(1, 32) }, + { "web_mx", V_LENGTH(0, 128) }, + { "http_wanport", V_PORT }, + { "telnetd_eas", V_01 }, + { "telnetd_port", V_PORT }, + { "sshd_eas", V_01 }, + { "sshd_pass", V_01 }, + { "sshd_port", V_PORT }, + { "sshd_remote", V_01 }, + { "sshd_rport", V_PORT }, + { "sshd_authkeys", V_TEXT(0, 4096) }, + { "rmgt_sip", V_LENGTH(0, 512) }, + { "ne_shlimit", V_TEXT(1, 50) }, + +// admin-bwm + { "rstats_enable", V_01 }, + { "rstats_path", V_LENGTH(0, 48) }, + { "rstats_stime", V_RANGE(1, 168) }, + { "rstats_offset", V_RANGE(1, 31) }, + { "rstats_exclude", V_LENGTH(0, 64) }, + { "rstats_sshut", V_01 }, + { "rstats_bak", V_01 }, + +// admin-buttons + { "sesx_led", V_RANGE(0, 255) }, // amber, white, aoss + { "sesx_b0", V_RANGE(0, 4) }, // 0-4: toggle wireless, reboot, shutdown, script + { "sesx_b1", V_RANGE(0, 4) }, // " + { "sesx_b2", V_RANGE(0, 4) }, // " + { "sesx_b3", V_RANGE(0, 4) }, // " + { "sesx_script", V_TEXT(0, 1024) }, // + { "script_brau", V_TEXT(0, 1024) }, // + +// admin-debug + { "debug_nocommit", V_01 }, + { "debug_cprintf", V_01 }, + { "debug_cprintf_file", V_01 }, +// { "debug_keepfiles", V_01 }, + { "debug_ddns", V_01 }, + { "debug_norestart", V_TEXT(0, 128) }, + { "console_loglevel", V_RANGE(1, 8) }, + { "t_cafree", V_01 }, + { "t_hidelr", V_01 }, + +// admin-sched + { "sch_rboot", V_TEXT(0, 64) }, + { "sch_rcon", V_TEXT(0, 64) }, + { "sch_c1", V_TEXT(0, 64) }, + { "sch_c1_cmd", V_TEXT(0, 2048) }, + { "sch_c2", V_TEXT(0, 64) }, + { "sch_c2_cmd", V_TEXT(0, 2048) }, + { "sch_c3", V_TEXT(0, 64) }, + { "sch_c3_cmd", V_TEXT(0, 2048) }, + +// admin-scripts + { "script_init", V_TEXT(0, 4096) }, + { "script_shut", V_TEXT(0, 4096) }, + { "script_fire", V_TEXT(0, 8192) }, + { "script_wanup", V_TEXT(0, 4096) }, + +// admin-log + { "log_remote", V_01 }, + { "log_remoteip", V_IP }, + { "log_remoteport", V_PORT }, + { "log_file", V_01 }, + { "log_limit", V_RANGE(0, 2400) }, + { "log_in", V_RANGE(0, 3) }, + { "log_out", V_RANGE(0, 3) }, + { "log_mark", V_RANGE(0, 1440) }, + { "log_events", V_TEXT(0, 32) }, // "acre,crond,ntp" + +// admin-cifs + { "cifs1", V_LENGTH(1, 1024) }, + { "cifs2", V_LENGTH(1, 1024) }, + +// admin-jffs2 + { "jffs2_on", V_01 }, + { "jffs2_exec", V_LENGTH(0, 64) }, + { "jffs2_format", V_01 }, + +// qos + { "qos_enable", V_01 }, + { "qos_ack", V_01 }, + { "qos_syn", V_01 }, + { "qos_fin", V_01 }, + { "qos_rst", V_01 }, + { "qos_icmp", V_01 }, + { "qos_reset", V_01 }, + { "qos_obw", V_RANGE(10, 999999) }, + { "qos_ibw", V_RANGE(10, 999999) }, + { "qos_orules", V_LENGTH(0, 4096) }, + { "qos_default", V_RANGE(0, 9) }, + { "qos_irates", V_LENGTH(0, 128) }, + { "qos_orates", V_LENGTH(0, 128) }, + + { "ne_vegas", V_01 }, + { "ne_valpha", V_NUM }, + { "ne_vbeta", V_NUM }, + { "ne_vgamma", V_NUM }, + + +/* +ppp_static 0/1 +ppp_static_ip IP +wl_enable 0/1 +wl_wds_timeout +wl_maxassoc 1-256 +wl_phytype a,b,g +wl_net_reauth +wl_preauth +wl_wme_ap_bk +wl_wme_ap_be +wl_wme_ap_vi +wl_wme_ap_vo +wl_wme_sta_bk +wl_wme_sta_be +wl_wme_sta_vi +wl_wme_sta_vo +QoS +port_priority_1 0-2 +port_flow_control_1 0,1 +port_rate_limit_1 0-8 +port_priority_2 0-2 +port_flow_control_2 0,1 +port_rate_limit_2 0-8 +port_priority_3 0-2 +port_flow_control_3 0,1 +port_rate_limit_3 0-8 +port_priority_4 0-2 +port_flow_control_4 0,1 +port_rate_limit_4 0-8 +wl_ap_ip +wl_ap_ssid +*/ + + { NULL } +}; + +static int save_variables(int write) +{ + const nvset_t *v; + char *p, *e; + int n; + long l; + unsigned u[6]; + int ok; + char s[256]; + int dirty; + static const char *msgf = "The field \"%s\" is invalid. Please report this problem."; + + dirty = 0; + for (v = nvset_list; v->name; ++v) { +// _dprintf("[%s] %p\n", v->name, webcgi_get((char*)v->name)); + if ((p = webcgi_get((char*)v->name)) == NULL) continue; + ok = 1; + switch (v->vtype) { + case VT_TEXT: + p = unix_string(p); // NOTE: p = malloc'd + // drop + case VT_LENGTH: + n = strlen(p); + if ((n < v->va.i) || (n > v->vb.i)) ok = 0; + break; + case VT_RANGE: + l = strtol(p, &e, 10); + if ((p == e) || (*e) || (l < v->va.l) || (l > v->vb.l)) ok = 0; + break; + case VT_IP: + if ((sscanf(p, "%3u.%3u.%3u.%3u", &u[0], &u[1], &u[2], &u[3]) != 4) || + (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255)) ok = 0; + break; + case VT_MAC: + if ((sscanf(p, "%2x:%2x:%2x:%2x:%2x:%2x", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]) != 6) || + (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255) || (u[4] > 255) || (u[5] > 255)) ok = 0; + break; + default: + // shutup gcc + break; + } + if (!ok) { + if (v->vtype == VT_TEXT) free(p); + + sprintf(s, msgf, v->name); + resmsg_set(s); + return 0; + } + if (write) { + if (!nvram_match((char *)v->name, p)) { + if (v->vtype != VT_TEMP) dirty = 1; + nvram_set(v->name, p); + } + } + if (v->vtype == VT_TEXT) free(p); + } + + + // special cases + + char *p1, *p2; + if (((p1 = webcgi_get("set_password_1")) != NULL) && (strcmp(p1, "**********") != 0)) { + if (((p2 = webcgi_get("set_password_2")) != NULL) && (strcmp(p1, p2) == 0)) { + if ((write) && (!nvram_match("http_passwd", p1))) { + dirty = 1; + nvram_set("http_passwd", p1); + } + } + else { + sprintf(s, msgf, "password"); + resmsg_set(s); + return 0; + } + } + + for (n = 0; n < 50; ++n) { + sprintf(s, "rrule%d", n); + if ((p = webcgi_get(s)) != NULL) { + if (strlen(p) > 2048) { + sprintf(s, msgf, s); + resmsg_set(s); + return 0; + } + if ((write) && (!nvram_match(s, p))) { + dirty = 1; + nvram_set(s, p); + } + } + } + + return (write) ? dirty : 1; +} + +static void wo_tomato(char *url) +{ + char *v; + int i; + int ajax; + int nvset; + const char *red; + int commit; + +// _dprintf("tomato.cgi\n"); + + red = webcgi_safeget("_redirect", ""); + if (!*red) send_header(200, NULL, mime_html, 0); + + commit = atoi(webcgi_safeget("_commit", "1")); + ajax = atoi(webcgi_safeget("_ajax", "0")); + + nvset = atoi(webcgi_safeget("_nvset", "1")); + if (nvset) { + if (!save_variables(0)) { + if (ajax) { + web_printf("@msg:%s", resmsg_get()); + } + else { + parse_asp("error.asp"); + } + return; + } + commit = save_variables(1) && commit; + + resmsg_set("Settings saved."); + } + + rboot = atoi(webcgi_safeget("_reboot", "0")); + if (rboot) { + parse_asp("reboot.asp"); + } + else { + if (ajax) { + web_printf("@msg:%s", resmsg_get()); + } + else if (atoi(webcgi_safeget("_moveip", "0"))) { + parse_asp("saved-moved.asp"); + } + else if (!*red) { + parse_asp("saved.asp"); + } + } + + if (commit) { + _dprintf("commit from tomato.cgi\n"); + nvram_commit_x(); + } + + if ((v = webcgi_get("_service")) != NULL) { + if (!*red) { + if (ajax) web_printf(" Some services are being restarted..."); + web_close(); + } + sleep(1); + + if (*v == '*') { + kill(1, SIGHUP); + } + else if (*v != 0) { + exec_service(v); + } + } + + for (i = atoi(webcgi_safeget("_sleep", "0")); i > 0; --i) sleep(1); + + if (*red) redirect(red); + + if (rboot) { + web_close(); + sleep(1); + kill(1, SIGTERM); + } +} + + +// ---------------------------------------------------------------------------- + + +static void wo_update(char *url) +{ + const aspapi_t *api; + const char *name; + int argc; + char *argv[16]; + char s[32]; + + if ((name = webcgi_get("exec")) != NULL) { + for (api = aspapi; api->name; ++api) { + if (strcmp(api->name, name) == 0) { + for (argc = 0; argc < 16; ++argc) { + sprintf(s, "arg%d", argc); + if ((argv[argc] = (char *)webcgi_get(s)) == NULL) break; + } + api->exec(argc, argv); + break; + } + } + } +} + +static void wo_service(char *url) +{ + int n; + + exec_service(webcgi_safeget("_service", "")); + + if ((n = atoi(webcgi_safeget("_sleep", "2"))) <= 0) n = 2; + sleep(n); + + common_redirect(); +} + +static void wo_shutdown(char *url) +{ + parse_asp("shutdown.asp"); + web_close(); + sleep(1); + + kill(1, SIGQUIT); +} + +static void wo_nvcommit(char *url) +{ + parse_asp("saved.asp"); + web_close(); + nvram_commit(); +} + + diff --git a/release/src/router/httpd/tomato.h b/release/src/router/httpd/tomato.h new file mode 100644 index 00000000..3cd6c49b --- /dev/null +++ b/release/src/router/httpd/tomato.h @@ -0,0 +1,162 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#ifndef __TOMATO_H_ +#define __TOMATO_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <typedefs.h> +#include <syslog.h> +#include <signal.h> + +#include <bcmutils.h> +#include <bcmnvram.h> +#include <utils.h> +#include <shutils.h> +#include <shared.h> + +#include <tomato_profile.h> +#include <tomato_config.h> + + +#include "httpd.h" + + +#define USE_MINIUPNPD +// #define BLACKHOLE // for testing + + +#define _dprintf(args...) do { } while(0) +// #define _dprintf cprintf + +extern int rboot; + +extern void exec_service(const char *action); +extern void wi_generic(char *url, int len, char *boundary); +extern void common_redirect(void); + +extern const char *resmsg_get(void); +extern void resmsg_set(const char *msg); +extern int resmsg_fread(const char *fname); + + + +// nvram.c +extern void asp_nvram(int argc, char **argv); +extern void asp_nvramseq(int argc, char **argv); +extern void asp_nv(int argc, char **argv); + +// misc.c +extern char *js_string(const char *s); +extern char *html_string(const char *s); +extern char *unix_string(const char *s); +extern char *reltime(char *buf, time_t t); +extern int get_client_info(char *mac, char *ifname); + +extern void asp_lipp(int argc, char **argv); +extern void asp_activeroutes(int argc, char **argv); +extern void asp_cgi_get(int argc, char **argv); +extern void asp_time(int argc, char **argv); +extern void asp_wanup(int argc, char **argv); +extern void asp_wanstatus(int argc, char **argv); +extern void asp_link_uptime(int argc, char **argv); +extern void asp_rrule(int argc, char **argv); +extern void asp_compmac(int argc, char **argv); +extern void asp_ident(int argc, char **argv); +extern void asp_lanip(int argc, char **argv); +extern void asp_psup(int argc, char **argv); +extern void asp_sysinfo(int argc, char **argv); +extern void asp_statfs(int argc, char **argv); +extern void asp_notice(int argc, char **argv); +extern void wo_wakeup(char *url); +extern void asp_dns(int argc, char **argv); +extern void wo_resolve(char *url); + +// devlist.c +extern void asp_arplist(int argc, char **argv); +extern void asp_devlist(int argc, char **argv); + +// ctnf.c +extern void asp_ctcount(int argc, char **argv); +extern void asp_ctdump(int argc, char **argv); +extern void asp_qrate(int argc, char **argv); +extern void asp_layer7(int argc, char **argv); +extern void wo_expct(char *url); + +// wl.c +extern void asp_wlscan(int argc, char **argv); +extern void asp_wlradio(int argc, char **argv); +extern void wo_wlradio(char *url); +extern void asp_wlnoise(int argc, char **argv); +extern void asp_wlcrssi(int argc, char **argv); +extern void wo_wlmnoise(char *url); +extern void asp_wlclient(int argc, char **argv); +extern void asp_wlchannel(int argc, char **argv); + +// dhcp.c +extern void asp_dhcpc_time(int argc, char **argv); +extern void wo_dhcpd(char *url); +extern void wo_dhcpc(char *url); + +// version.c +extern void asp_build_time(int argc, char **argv); +extern void asp_version(int argc, char **argv); + +// traceping.c +extern void wo_trace(char *url); +extern void wo_ping(char *url); + +// log.c +extern void wo_viewlog(char *url); +extern void wo_syslog(char *url); + +// ddns.c +extern void asp_ddnsx(int argc, char **argv); +extern void asp_ddnsx_ip(int argc, char **argv); +extern void asp_ddnsx_msg(int argc, char **argv); + +// upgrade.c +extern void prepare_upgrade(void); +extern void wi_upgrade(char *url, int len, char *boundary); +extern void wo_flash(char *url); + +// config.c +extern void wo_backup(char *url); +extern void wi_restore(char *url, int len, char *boundary); +extern void wo_restore(char *url); +extern void wo_defaults(char *url); + +// parser.c +extern void wo_asp(char *path); + +// blackhole.c +extern void wi_blackhole(char *url, int len, char *boundary); + +// upnp.c +extern void asp_upnpinfo(int argc, char **argv); +extern void wo_upnp(char *url); + +// bwm.c +extern void wo_bwmbackup(char *url); +extern void wi_bwmrestore(char *url, int len, char *boundary); +extern void wo_bwmrestore(char *url); +extern void asp_netdev(int argc, char **argv); +extern void asp_bandwidth(int argc, char **argv); + + +#if TOMATO_SL +// share.c +extern void asp_sharelist(int argc, char **argv); +extern void wo_umount(char *url); +extern void wo_usb(char *url); +#endif + + +#endif diff --git a/release/src/router/httpd/traceping.c b/release/src/router/httpd/traceping.c new file mode 100644 index 00000000..eaf7118c --- /dev/null +++ b/release/src/router/httpd/traceping.c @@ -0,0 +1,108 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> + + +static int check_addr(const char *addr, int max) +{ + const char *p; + char c; + + if ((addr == NULL) || (addr[0] == 0)) return 0; + p = addr; + while (*p) { + c = *p; + if ((!isalnum(c)) && (c != '.') && (c != '-')) return 0; + ++p; + } + return((p - addr) <= max); +} + +void wo_trace(char *url) +{ + char cmd[256]; + const char *addr; + + addr = webcgi_get("addr"); + if (!check_addr(addr, 64)) return; + + killall("traceroute", SIGTERM); + + web_puts("\ntracedata = '"); + sprintf(cmd, "traceroute -I -m %u -w %u %s", atoi(webcgi_safeget("hops", "0")), atoi(webcgi_safeget("wait", "0")), addr); + web_pipecmd(cmd, WOF_JAVASCRIPT); + web_puts("';"); +} + +void wo_ping(char *url) +{ + char cmd[256]; + const char *addr; + + addr = webcgi_get("addr"); + if (!check_addr(addr, 64)) return; + + killall("ping", SIGTERM); + + web_puts("\npingdata = '"); + sprintf(cmd, "ping -c %d -s %d %s", atoi(webcgi_safeget("count", "0")), atoi(webcgi_safeget("size", "0")), addr); + web_pipecmd(cmd, WOF_JAVASCRIPT); + web_puts("';"); +} + + +/* +#include <regex.h> + +int main(int argc, char **argv) +{ + FILE *f; + char s[1024]; + int n; + char domain[512]; + char ip[32]; + char min[32]; + regex_t re; + regmatch_t rm[10]; + int i; + + if ((f = popen("traceroute -I 192.168.0.1", "r")) == NULL) { + perror("popen"); + return 1; + } +// 2 192.168.0.1 (192.168.0.1) 1.908 ms 1.812 ms 1.688 ms + + while (fgets(s, sizeof(s), f)) { + + // + if (regcomp(&re, "^ +[0-9]+ +(.+?) +\\((.+?)\\) +(.+?) ms +(.+?) ms +(.+?) ms", REG_EXTENDED) != 0) { + printf("error: regcomp\n"); + return 1; + } + if ((regexec(&re, s, sizeof(rm) / sizeof(rm[0]), rm, 0) == 0) && (re.re_nsub == 5)) { + printf("["); + for (i = 1; i < 6; ++i) { + s[rm[i].rm_eo] = 0; + printf("'%s'%c", s + rm[i].rm_so, (i == 5) ? ' ' : ','); + } + printf("]\n"); +// printf("%d = %d = [%s]\n", i, rm[i].rm_so, s + rm[i].rm_so); + } + regfree(&re); + +// sscanf(s, "%d %s (%s) %s ms", &n, domain, ip, min); +// printf("[%s] %s %s\n", ip, domain, min); + } + pclose(f); + + return 0; +} + +*/ diff --git a/release/src/router/httpd/upgrade.c b/release/src/router/httpd/upgrade.c new file mode 100644 index 00000000..ce3e27c4 --- /dev/null +++ b/release/src/router/httpd/upgrade.c @@ -0,0 +1,153 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/wait.h> +#include <typedefs.h> +#include <sys/reboot.h> + +#if 1 +#define MTD_WRITE_CMD "mtd-write" +#else +#define DEBUG_TEST +#define MTD_WRITE_CMD "/tmp/mtd-write" +#endif + +void prepare_upgrade(void) +{ + int n; + + // stop non-essential stuff & free up some memory + exec_service("upgrade-start"); + for (n = 30; n > 0; --n) { + sleep(1); + if (nvram_match("action_service", "")) break; // this is cleared at the end + } + unlink("/var/log/messages"); + unlink("/var/log/messages.0"); + sync(); +} + +void wi_upgrade(char *url, int len, char *boundary) +{ + uint8 buf[1024]; + const char *error = "Error reading file"; + int ok = 0; + int n; + + check_id(url); + + // quickly check if JFFS2 is mounted by checking if /jffs/ is not squashfs + struct statfs sf; + if ((statfs("/jffs", &sf) != 0) || (sf.f_type != 0x73717368)) { + error = "JFFS2 is currently in use. Since an upgrade may overwrite the " + "JFFS2 partition, please backup the contents, disable JFFS2, then reboot the router"; + goto ERROR; + } + + // skip the rest of the header + if (!skip_header(&len)) goto ERROR; + + if (len < (1 * 1024 * 1024)) { + error = "Invalid file"; + goto ERROR; + } + + // -- anything after here ends in a reboot -- + + rboot = 1; + + led(LED_DIAG, 1); + + signal(SIGTERM, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + prepare_upgrade(); + system("cp reboot.asp /tmp"); // copy to memory + + char fifo[] = "/tmp/flashXXXXXX"; + int pid = -1; + FILE *f = NULL; + + if ((mktemp(fifo) == NULL) || + (mkfifo(fifo, S_IRWXU) < 0)) { + error = "Unable to create a fifo"; + goto ERROR2; + } + + char *wargv[] = { MTD_WRITE_CMD, "-w", "-i", fifo, "-d", "linux", NULL }; + if (_eval(wargv, ">/tmp/.mtd-write", 0, &pid) != 0) { + error = "Unable to start flash program"; + goto ERROR2; + } + + if ((f = fopen(fifo, "w")) == NULL) { + error = "Unable to start pipe for mtd write"; + goto ERROR2; + } + + // !!! This will actually write the boundary. But since mtd-write + // uses trx length... -- zzz + + while (len > 0) { + if ((n = web_read(buf, MIN(len, sizeof(buf)))) <= 0) { + goto ERROR2; + } + len -= n; + if (safe_fwrite(buf, 1, n, f) != n) { + error = "Error writing to pipe"; + goto ERROR2; + } + } + + error = NULL; + ok = 1; + +ERROR2: + rboot = 1; + set_action(ACT_REBOOT); + + if (f) fclose(f); + if (pid != -1) waitpid(pid, &n, 0); + + resmsg_fread("/tmp/.mtd-write"); + + web_eat(len); + return; + +ERROR: + resmsg_set(error); + web_eat(len); +} + +void wo_flash(char *url) +{ + if (rboot) { + parse_asp("/tmp/reboot.asp"); + web_close(); + +#ifdef DEBUG_TEST + printf("\n\n -- reboot -- \n\n"); + set_action(ACT_IDLE); +#else + killall("pppoecd", SIGTERM); + sleep(2); + // kill(1, SIGTERM); + reboot(RB_AUTOBOOT); +#endif + exit(0); + } + + parse_asp("error.asp"); +} diff --git a/release/src/router/httpd/upnp.c b/release/src/router/httpd/upnp.c new file mode 100644 index 00000000..8a8f8fe0 --- /dev/null +++ b/release/src/router/httpd/upnp.c @@ -0,0 +1,74 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +void asp_upnpinfo(int argc, char **argv) +{ +#ifdef USE_MINIUPNPD + if (nvram_get_int("upnp_enable")) { + f_write_string("/etc/upnp/info", "", 0, 0); + if (killall("miniupnpd", SIGUSR2) == 0) { + f_wait_notexists("/etc/upnp/info", 5); + } + + web_puts("\nmupnp_data = '"); + web_putfile("/etc/upnp/data.info", WOF_JAVASCRIPT); + web_puts("';\n"); + } +#else + unlink("/var/spool/upnp.js"); + if (nvram_get_int("upnp_enable") == 1) { + if (killall("upnp", SIGUSR2) == 0) { + f_wait_exists("/var/spool/upnp.js", 5); + } + } + + web_puts("\nupnp_data = [\n"); + do_file("/var/spool/upnp.js"); + web_puts("];\n"); + unlink("/var/spool/upnp.js"); +#endif +} + +void wo_upnp(char *url) +{ +#ifdef USE_MINIUPNPD + char s[256]; + const char *proto; + const char *eport; + + if (nvram_get_int("upnp_enable")) { + if (((proto = webcgi_get("remove_proto")) != NULL) && (*proto) && + ((eport = webcgi_get("remove_eport")) != NULL) && (*eport)) { + sprintf(s, "%3s %6s\n", proto, eport); + f_write_string("/etc/upnp/delete", s, 0, 0); + if (killall("miniupnpd", SIGUSR2) == 0) { + f_wait_notexists("/etc/upnp/delete", 5); + } + } + } + common_redirect(); +#else + char s[256]; + const char *proto; + const char *port; + + if (nvram_get_int("upnp_enable") == 1) { + if (((proto = webcgi_get("remove_proto")) != NULL) && (*proto) && + ((port = webcgi_get("remove_ext_port")) != NULL) && (*port)) { + + sprintf(s, "%s %s\n", proto, port); + f_write_string("/var/spool/upnp.delete", s, 0, 0); + if (killall("upnp", SIGUSR2) == 0) { + f_wait_notexists("/var/spool/upnp.delete", 5); + } + } + } + common_redirect(); +#endif +} diff --git a/release/src/router/httpd/version.c b/release/src/router/httpd/version.c new file mode 100644 index 00000000..bdd1a5d2 --- /dev/null +++ b/release/src/router/httpd/version.c @@ -0,0 +1,24 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +void asp_build_time(int argc, char **argv) +{ + web_puts(tomato_buildtime); +} + +void asp_version(int argc, char **argv) +{ + if (argc != 0) { + web_puts(tomato_version); + } + else { + web_write(tomato_version, strrchr(tomato_version, '.') - tomato_version); + } +} + diff --git a/release/src/router/httpd/webio.c b/release/src/router/httpd/webio.c new file mode 100644 index 00000000..11e8a67a --- /dev/null +++ b/release/src/router/httpd/webio.c @@ -0,0 +1,229 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ +#include "tomato.h" + +#include "../mssl/mssl.h" +extern int do_ssl; + +#include <errno.h> +#include <stdarg.h> + +extern FILE *connfp; +extern int connfd; + +int web_getline(char *buffer, int max) +{ + while (fgets(buffer, max, connfp) == NULL) { + if (errno != EINTR) return 0; + } +// cprintf("%s", buffer); + return 1; +} + +void web_puts(const char *buffer) +{ + web_write(buffer, strlen(buffer)); +} + +void web_putj(const char *buffer) +{ + char *p; + + p = js_string(buffer); + if (p) { + web_puts(p); + free(p); + } +} + +void web_puth(const char *buffer) +{ + char *p; + + p = html_string(buffer); + if (p) { + web_puts(p); + free(p); + } +} + +int _web_printf(wofilter_t wof, const char *format, ...) +{ + va_list args; + char *b, *p; + int size; + int n; + + size = 1024; + while (1) { + if ((b = malloc(size)) == NULL) return 0; + + va_start(args, format); + n = vsnprintf(b, size, format, args); + va_end(args); + + if (n > -1) { + if (n < size) { + switch (wof) { + case WOF_JAVASCRIPT: + p = js_string(b); + free(b); + break; + case WOF_HTML: + p = html_string(b); + free(b); + break; + default: + p = b; + break; + } + if (!p) return 0; + web_puts(p); + free(p); + return 1; + } + size = n + 1; + } + else size *= 2; + + free(b); + if (size > (10 * 1024)) return 0; + } +} + +int web_write(const char *buffer, int len) +{ + int n = len; + int r = 0; + + while (n > 0) { + r = fwrite(buffer, 1, n, connfp); + if ((r == 0) && (errno != EINTR)) return -1; + buffer += r; + n -= r; + } + return r; +} + +int web_read(void *buffer, int len) +{ + int r; + if (len <= 0) return 0; + while ((r = fread(buffer, 1, len, connfp)) == 0) { + if (errno != EINTR) return -1; + } + return r; +} + +int web_read_x(void *buffer, int len) +{ + int n; + int t = 0; + while (len > 0) { + n = web_read(buffer, len); + if (n <= 0) return len; + (unsigned char *)buffer += n; + len -= n; + t += n; + } + return t; +} + +int web_eat(int max) +{ + char buf[512]; + int n; + while (max > 0) { + if ((n = web_read(buf, (max < sizeof(buf)) ? max : sizeof(buf))) <= 0) return 0; + max -= n; + } + return 1; +} + +int web_flush(void) +{ + return (fflush(connfp) == 0); +} + +int web_open(void) +{ + if (do_ssl) { +#ifdef TCONFIG_HTTPS + if ((connfp = ssl_server_fopen(connfd)) != NULL) return 1; +#endif + } + else { + if ((connfp = fdopen(connfd, "r+")) != NULL) return 1; + } + return 0; +} + +int web_close(void) +{ + if (connfp != NULL) { + fflush(connfp); + fclose(connfp); + connfp = NULL; + } + if (connfd != -1) { +// shutdown(connfd, SHUT_RDWR); + close(connfd); + connfd = -1; + } + return 1; +} + + +// -------------------------------------------------------------------------------------------------------------------- + + +static void _web_putfile(FILE *f, wofilter_t wof) +{ + char buf[2048]; + int nr; + + while ((nr = fread(buf, 1, sizeof(buf) - 1, f)) > 0) { + buf[nr] = 0; + switch (wof) { + case WOF_JAVASCRIPT: + web_putj(buf); + break; + case WOF_HTML: + web_puth(buf); + break; + default: + web_puts(buf); + break; + } + } +} + +int web_putfile(const char *fname, wofilter_t wof) +{ + FILE *f; + + if ((f = fopen(fname, "r")) != NULL) { + _web_putfile(f, wof); + fclose(f); + return 1; + } + return 0; +} + +int web_pipecmd(const char *cmd, wofilter_t wof) +{ + FILE *f; + + if ((f = popen(cmd, "r")) != NULL) { + _web_putfile(f, wof); + pclose(f); + return 1; + } + return 0; +} + + diff --git a/release/src/router/httpd/webmsg.c b/release/src/router/httpd/webmsg.c new file mode 100644 index 00000000..50448567 --- /dev/null +++ b/release/src/router/httpd/webmsg.c @@ -0,0 +1,65 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <sys/stat.h> + + + +static const char webMsgFile[] = "/tmp/.webmsg"; + + +void setWebMsg(const char *s) +{ + FILE *f; + if (s) { + if ((f = fopen(webMsgFile, "w")) != NULL) { + fputs(s, f); + fclose(f); + } + } + else { + unlink(webMsgFile); + } +} + +void getWebMsg(char *s, int max) +{ + FILE *f; + int n; + + if ((f = fopen(webMsgFile, "r")) != NULL) { + n = fread(s, 1, max - 1, f); + s[n] = 0; + fclose(f); + unlink(webMsgFile); + } + else s[0] = 0; +} + +int webMsgExist(void) +{ + struct stat st; + return ((stat(webMsgFile, &st) == 0) && (st.st_size > 0)); +} + +void asp_webmsg(int argc, char **argv) +{ + char s[512]; + const char *msg = s; + + getWebMsg(s, sizeof(s)); + if (s[0] == 0) { + if (argc == 0) return; + msg = argv[0]; + } + if ((argc >= 2) && (argv[1][0] == '1')) web_putj(msg); + else web_puth(msg); +} + + diff --git a/release/src/router/httpd/wl.c b/release/src/router/httpd/wl.c new file mode 100644 index 00000000..5d4fc1d9 --- /dev/null +++ b/release/src/router/httpd/wl.c @@ -0,0 +1,247 @@ +/* + + Tomato Firmware + Copyright (C) 2006-2009 Jonathan Zarate + +*/ + +#include "tomato.h" + +#include <ctype.h> +#include <wlutils.h> + + +// returns: ['bssid','ssid',channel,capabilities,rssi,noise,[rates,]], or [null,'error message'] +void asp_wlscan(int argc, char **argv) +{ + // scan + + wl_scan_params_t sp; + int ap; + int radio; + char *wif; + int zero = 0; + + web_puts("\nwlscandata = ["); + + wif = nvram_safe_get("wl_ifname"); + + memset(&sp, 0xff, sizeof(sp)); // most default to -1 + sp.ssid.SSID_len = 0; + sp.bss_type = DOT11_BSSTYPE_ANY; // =2 + sp.channel_num = 0; + + if (wl_ioctl(wif, WLC_GET_AP, &ap, sizeof(ap)) < 0) { + web_puts("[null,'Unable to get AP mode.']];\n"); + return; + } + if (ap > 0) { + wl_ioctl(wif, WLC_SET_AP, &zero, sizeof(zero)); + } + + radio = get_radio(); + if (!radio) set_radio(1); + + if (wl_ioctl(wif, WLC_SCAN, &sp, WL_SCAN_PARAMS_FIXED_SIZE) < 0) { + if (ap > 0) wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap)); + if (!radio) set_radio(0); + web_puts("[null,'Unable to start scan.']];\n"); + return; + } + + sleep(2); + + + // get results + + wl_scan_results_t *results; + wl_bss_info_t *bssi; + int r; + + results = malloc(WLC_IOCTL_MAXLEN); + if (!results) { + if (ap > 0) wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap)); + if (!radio) set_radio(0); + web_puts("[null,'Not enough memory.']];"); + return; + } + results->buflen = WLC_IOCTL_MAXLEN - (sizeof(*results) - sizeof(results->bss_info)); + results->version = WL_BSS_INFO_VERSION; + r = wl_ioctl(wif, WLC_SCAN_RESULTS, results, WLC_IOCTL_MAXLEN); + + if (ap > 0) { + wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap)); +#ifndef WL_BSS_INFO_VERSION +#error WL_BSS_INFO_VERSION +#endif + +#if WL_BSS_INFO_VERSION >= 108 + // no idea why this voodoo sequence works to wake up wl -- zzz + eval("wl", "ssid", nvram_safe_get("wl_ssid")); + if (radio) set_radio(1); +#endif + } + if (!radio) set_radio(0); + + if (r < 0) { + free(results); + web_puts("[null,'Unable to obtain scan result.']];\n"); + return; + } + + + // format for javascript + + int i; + int j; + int k; + char c; + char ssid[64]; + char mac[32]; + char *ssidj; + int channel; + + bssi = &results->bss_info[0]; + for (i = 0; i < results->count; ++i) { + +#if WL_BSS_INFO_VERSION >= 108 + channel = CHSPEC_CHANNEL(bssi->chanspec); +#else + channel = bssi->channel; +#endif + + j = bssi->SSID_len; + if (j < 0) j = 0; + if (j > 32) j = 32; + if (nvram_get_int("wlx_scrubssid")) { + for (k = j - 1; k >= 0; --k) { + c = bssi->SSID[k]; + if (!isprint(c)) c = '?'; + ssid[k] = c; + } + } + else { + memcpy(ssid, bssi->SSID, j); + } + ssid[j] = 0; + ssidj = js_string(ssid); + + web_printf("%s['%s','%s',%u,%u,%d,%d,[", (i > 0) ? "," : "", + ether_etoa(bssi->BSSID.octet, mac), ssidj ? ssidj : "", + channel, + bssi->capability, bssi->RSSI, bssi->phy_noise); + free(ssidj); + + for (j = 0; j < bssi->rateset.count; ++j) { + web_printf("%s%u", j ? "," : "", bssi->rateset.rates[j]); + } + web_puts("]]"); + + bssi = (wl_bss_info_t*)((uint8*)bssi + bssi->length); + } + + web_puts("];\n"); + free(results); +} + + +void asp_wlradio(int argc, char **argv) +{ + web_printf("\nwlradio = %d;\n", get_radio()); +} + +void wo_wlradio(char *url) +{ + char *enable; + + parse_asp("saved.asp"); + if (nvram_match("wl_radio", "1")) { + if ((enable = webcgi_get("enable")) != NULL) { + web_close(); + sleep(2); + eval("radio", atoi(enable) ? "on" : "off"); + return; + } + } +} + +static int read_noise(void) +{ + int v; + + // WLC_GET_PHY_NOISE + if (wl_ioctl(nvram_safe_get("wl_ifname"), 135, &v, sizeof(v)) == 0) { + char s[32]; + sprintf(s, "%d", v); + nvram_set("t_noise", s); + return v; + } + return -99; +} + +void asp_wlcrssi(int argc, char **argv) +{ + scb_val_t rssi; + + memset(&rssi, 0, sizeof(rssi)); + if (wl_client()) { + if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0) + rssi.val = -100; + } + web_printf("\nwlcrssi = %d;\n", rssi.val); +} + +void asp_wlnoise(int argc, char **argv) +{ + int v; + + if (wl_client()) { + v = read_noise(); + } + else { + v = nvram_get_int("t_noise"); + if ((v > 0) || (v < -100)) v = -99; + } + web_printf("\nwlnoise = %d;\n", v); +} + +void wo_wlmnoise(char *url) +{ + int ap; + int i; + char *wif; + + parse_asp("mnoise.asp"); + web_close(); + sleep(3); + + wif = nvram_safe_get("wl_ifname"); + if (wl_ioctl(wif, WLC_GET_AP, &ap, sizeof(ap)) < 0) return; + + i = 0; + wl_ioctl(wif, WLC_SET_AP, &i, sizeof(i)); + + for (i = 10; i > 0; --i) { + sleep(1); + read_noise(); + } + + wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap)); +} + +void asp_wlclient(int argc, char **argv) +{ + web_puts(wl_client() ? "1" : "0"); +} + +void asp_wlchannel(int argc, char **argv) +{ + channel_info_t ch; + + if (wl_ioctl(nvram_safe_get("wl_ifname"), WLC_GET_CHANNEL, &ch, sizeof(ch)) < 0) { + web_puts(nvram_safe_get("wl_channel")); + } + else { + web_printf("%d", (ch.scan_channel > 0) ? -ch.scan_channel : ch.hw_channel); + } +} |