Merge Tomato 1.25
[tomato.git] / release / src / router / httpd / tomato.c
blobaf581993c132cd7252d278f1031311605ae91411
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "tomato.h"
10 #include <sys/sysinfo.h>
11 #include <sys/stat.h>
12 #include <arpa/inet.h>
13 #include <time.h>
16 // #define DEBUG_NOEXECSERVICE
17 // #define DEBUG_NVRAMSET(k, v) cprintf("nvram set %s=%s\n", k, v);
18 #define DEBUG_NVRAMSET(k, v) do { } while(0);
21 char *post_buf = NULL;
22 int rboot = 0;
23 extern int post;
25 void asp_resmsg(int argc, char **argv);
28 static void wo_tomato(char *url);
29 static void wo_update(char *url);
30 static void wo_service(char *url);
31 static void wo_shutdown(char *url);
32 static void wo_nvcommit(char *url);
33 // static void wo_logout(char *url);
36 // ----------------------------------------------------------------------------
39 void exec_service(const char *action)
41 int i;
43 _dprintf("exec_service: %s\n", action);
45 i = 10;
46 while ((!nvram_match("action_service", "")) && (i-- > 0)) {
47 _dprintf("%s: waiting before %d\n", __FUNCTION__, i);
48 sleep(1);
51 nvram_set("action_service", action);
52 kill(1, SIGUSR1);
54 i = 3;
55 while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
56 _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
57 sleep(1);
61 if (atoi(webcgi_safeget("_service_wait", ""))) {
62 i = 10;
63 while ((nvram_match("action_service", (char *)action)) && (i-- > 0)) {
64 _dprintf("%s: waiting after %d\n", __FUNCTION__, i);
65 sleep(1);
71 static void wi_generic_noid(char *url, int len, char *boundary)
73 if (post == 1) {
74 if (len >= (32 * 1024)) {
75 // syslog(LOG_WARNING, "POST max");
76 exit(1);
79 if (!post_buf) free(post_buf);
80 if ((post_buf = malloc(len + 1)) == NULL) {
81 // syslog(LOG_CRIT, "Unable to allocate post buffer");
82 exit(1);
85 if (web_read_x(post_buf, len) != len) {
86 exit(1);
88 post_buf[len] = 0;
89 webcgi_init(post_buf);
93 void wi_generic(char *url, int len, char *boundary)
95 wi_generic_noid(url, len, boundary);
96 check_id(url);
99 static void wo_blank(char *url)
101 web_puts("\n\n\n\n");
104 static void wo_favicon(char *url)
106 send_header(200, NULL, "image/vnd.microsoft.icon", 0);
107 do_file(url);
109 if (nvram_match("web_favicon", "1")) {
110 send_header(200, NULL, "image/vnd.microsoft.icon", 0);
111 do_file(url);
113 else {
114 send_error(404, NULL, NULL);
119 static void wo_cfe(char *url)
121 do_file("/dev/mtd/0ro");
124 static void wo_nvram(char *url)
126 web_pipecmd("nvram show", WOF_NONE);
129 static void wo_iptables(char *url)
131 web_pipecmd("iptables -nvL; iptables -t nat -nvL; iptables -t mangle -nvL", WOF_NONE);
135 static void wo_spin(char *url)
137 char s[64];
139 strlcpy(s, nvram_safe_get("web_css"), sizeof(s));
140 strlcat(s, "_spin.gif", sizeof(s));
141 if (f_exists(s)) do_file(s);
142 else do_file("_spin.gif");
146 void common_redirect(void)
148 if (atoi(webcgi_safeget("_ajax", ""))) {
149 send_header(200, NULL, mime_html, 0);
150 web_puts("OK");
152 else {
153 redirect(webcgi_safeget("_redirect", "/"));
157 // ----------------------------------------------------------------------------
159 const struct mime_handler mime_handlers[] = {
160 { "update.cgi", mime_javascript, 0, wi_generic, wo_update, 1 },
161 { "tomato.cgi", NULL, 0, wi_generic, wo_tomato, 1 },
163 { "debug.js", mime_javascript, 5, wi_generic_noid, wo_blank, 1 }, // while debugging
164 { "cfe/*.bin", mime_binary, 0, wi_generic, wo_cfe, 1 },
165 { "nvram/*.txt", mime_binary, 0, wi_generic, wo_nvram, 1 },
166 { "ipt/*.txt", mime_binary, 0, wi_generic, wo_iptables, 1 },
168 { "cfg/*.cfg", NULL, 0, wi_generic, wo_backup, 1 },
169 { "cfg/restore.cgi", mime_html, 0, wi_restore, wo_restore, 1 },
170 { "cfg/defaults.cgi", NULL, 0, wi_generic, wo_defaults, 1 },
172 { "bwm/*.gz", NULL, 0, wi_generic, wo_bwmbackup, 1 },
173 { "bwm/restore.cgi", NULL, 0, wi_bwmrestore, wo_bwmrestore, 1 },
175 { "logs/view.cgi", NULL, 0, wi_generic, wo_viewlog, 1 },
176 { "logs/*.txt", NULL, 0, wi_generic, wo_syslog, 1 },
178 { "logout.asp", NULL, 0, wi_generic, wo_asp, 1 },
179 { "clearcookies.asp", NULL, 0, wi_generic, wo_asp, 1 },
181 // { "spin.gif", NULL, 0, wi_generic_noid, wo_spin, 1 },
183 { "**.asp", NULL, 0, wi_generic_noid, wo_asp, 1 },
184 { "**.css", "text/css", 2, wi_generic_noid, do_file, 1 },
185 { "**.htm", mime_html, 2, wi_generic_noid, do_file, 1 },
186 { "**.gif", "image/gif", 5, wi_generic_noid, do_file, 1 },
187 { "**.jpg", "image/jpeg", 5, wi_generic_noid, do_file, 1 },
188 { "**.png", "image/png", 5, wi_generic_noid, do_file, 1 },
189 { "**.js", mime_javascript, 2, wi_generic_noid, do_file, 1 },
190 { "**.jsx", mime_javascript, 0, wi_generic, wo_asp, 1 },
191 { "**.svg", "image/svg+xml", 2, wi_generic_noid, do_file, 1 },
192 { "**.txt", mime_plain, 2, wi_generic_noid, do_file, 1 },
193 { "**.bin", mime_binary, 0, wi_generic_noid, do_file, 1 },
194 { "**.bino", mime_octetstream, 0, wi_generic_noid, do_file, 1 },
195 { "favicon.ico", NULL, 5, wi_generic_noid, wo_favicon, 1 },
198 { "dhcpc.cgi", NULL, 0, wi_generic, wo_dhcpc, 1 },
199 { "dhcpd.cgi", mime_javascript, 0, wi_generic, wo_dhcpd, 1 },
200 { "nvcommit.cgi", NULL, 0, wi_generic, wo_nvcommit, 1 },
201 { "ping.cgi", mime_javascript, 0, wi_generic, wo_ping, 1 },
202 { "trace.cgi", mime_javascript, 0, wi_generic, wo_trace, 1 },
203 { "upgrade.cgi", mime_html, 0, wi_upgrade, wo_flash, 1 },
204 { "upnp.cgi", NULL, 0, wi_generic, wo_upnp, 1 },
205 { "wakeup.cgi", NULL, 0, wi_generic, wo_wakeup, 1 },
206 { "wlmnoise.cgi", mime_html, 0, wi_generic, wo_wlmnoise, 1 },
207 { "wlradio.cgi", NULL, 0, wi_generic, wo_wlradio, 1 },
208 { "resolve.cgi", mime_javascript, 0, wi_generic, wo_resolve, 1 },
209 { "expct.cgi", mime_html, 0, wi_generic, wo_expct, 1 },
210 { "service.cgi", NULL, 0, wi_generic, wo_service, 1 },
211 // { "logout.cgi", NULL, 0, wi_generic, wo_logout, 0 }, // see httpd.c
212 { "shutdown.cgi", mime_html, 0, wi_generic, wo_shutdown, 1 },
213 { "vpnstatus.cgi", mime_javascript, 0, wi_generic, wo_vpn_status, 1 },
215 #ifdef BLACKHOLE
216 { "blackhole.cgi", NULL, 0, wi_blackhole, NULL, 1 },
217 #endif
218 // { "test", mime_html, 0, wi_generic, wo_test, 1 },
219 { NULL, NULL, 0, NULL, NULL, 1 }
222 const aspapi_t aspapi[] = {
223 { "activeroutes", asp_activeroutes },
224 { "arplist", asp_arplist },
225 { "bandwidth", asp_bandwidth },
226 { "build_time", asp_build_time },
227 { "cgi_get", asp_cgi_get },
228 { "compmac", asp_compmac },
229 { "ctcount", asp_ctcount },
230 { "ctdump", asp_ctdump },
231 { "ddnsx", asp_ddnsx },
232 { "devlist", asp_devlist },
233 { "dhcpc_time", asp_dhcpc_time },
234 { "dns", asp_dns },
235 { "ident", asp_ident },
236 { "lanip", asp_lanip },
237 { "layer7", asp_layer7 },
238 { "link_uptime", asp_link_uptime },
239 { "lipp", asp_lipp },
240 { "netdev", asp_netdev },
241 { "notice", asp_notice },
242 { "nv", asp_nv },
243 { "nvram", asp_nvram },
244 { "nvramseq", asp_nvramseq },
245 { "psup", asp_psup },
246 { "qrate", asp_qrate },
247 { "resmsg", asp_resmsg },
248 { "rrule", asp_rrule },
249 { "statfs", asp_statfs },
250 { "sysinfo", asp_sysinfo },
251 { "time", asp_time },
252 { "upnpinfo", asp_upnpinfo },
253 { "version", asp_version },
254 { "wanstatus", asp_wanstatus },
255 { "wanup", asp_wanup },
256 { "wlchannel", asp_wlchannel },
257 { "wlclient", asp_wlclient },
258 { "wlcrssi", asp_wlcrssi },
259 { "wlnoise", asp_wlnoise },
260 { "wlradio", asp_wlradio },
261 { "wlscan", asp_wlscan },
262 #if TOMATO_SL
263 { "sharelist", asp_sharelist },
264 #endif
265 { NULL, NULL }
268 // -----------------------------------------------------------------------------
270 const char *resmsg_get(void)
272 return webcgi_safeget("resmsg", "");
275 void resmsg_set(const char *msg)
277 webcgi_set("resmsg", strdup(msg)); // m ok
280 int resmsg_fread(const char *fname)
282 char s[256];
283 char *p;
285 f_read_string(fname, s, sizeof(s));
286 if ((p = strchr(s, '\n')) != NULL) *p = 0;
287 if (s[0]) {
288 resmsg_set(s);
289 return 1;
291 return 0;
294 void asp_resmsg(int argc, char **argv)
296 char *p;
298 if ((p = js_string(webcgi_safeget("resmsg", (argc > 0) ? argv[0] : ""))) == NULL) return;
299 web_printf("\nresmsg='%s';\n", p);
300 free(p);
303 // ----------------------------------------------------------------------------
305 // verification... simple sanity checks. UI should verify all fields.
307 // todo: move and re-use for filtering - zzz
309 typedef union {
310 int i;
311 long l;
312 const char *s;
313 } nvset_varg_t;
315 typedef struct {
316 const char *name;
317 enum {
318 VT_NONE, // no checking
319 VT_LENGTH, // check length of string
320 VT_TEXT, // strip \r, check length of string
321 VT_RANGE, // expect an integer, check range
322 VT_IP, // expect an ip address
323 VT_MAC, // expect a mac address
324 VT_TEMP // no checks, no commit
325 } vtype;
326 nvset_varg_t va;
327 nvset_varg_t vb;
328 } nvset_t;
331 #define V_NONE VT_NONE, { }, { }
332 #define V_01 VT_RANGE, { .l = 0 }, { .l = 1 }
333 #define V_PORT VT_RANGE, { .l = 2 }, { .l = 65535 }
334 #define V_ONOFF VT_LENGTH, { .i = 2 }, { .i = 3 }
335 #define V_WORD VT_LENGTH, { .i = 1 }, { .i = 16 }
336 #define V_LENGTH(min, max) VT_LENGTH, { .i = min }, { .i = max }
337 #define V_TEXT(min, max) VT_TEXT, { .i = min }, { .i = max }
338 #define V_RANGE(min, max) VT_RANGE, { .l = min }, { .l = max }
339 #define V_IP VT_IP, { }, { }
340 #define V_OCTET VT_RANGE, { .l = 0 }, { .l = 255 }
341 #define V_NUM VT_RANGE, { .l = 0 }, { .l = 0x7FFFFFFF }
342 #define V_TEMP VT_TEMP, { }, { }
344 static const nvset_t nvset_list[] = {
346 // basic-ident
347 { "router_name", V_LENGTH(0, 32) },
348 { "wan_hostname", V_LENGTH(0, 32) },
349 { "wan_domain", V_LENGTH(0, 32) },
351 // basic-time
352 { "tm_tz", V_LENGTH(1, 64) }, // PST8PDT
353 { "tm_sel", V_LENGTH(1, 64) }, // PST8PDT
354 { "tm_dst", V_01 },
355 { "ntp_updates", V_RANGE(-1, 24) },
356 { "ntp_tdod", V_01 },
357 { "ntp_server", V_LENGTH(1, 150) }, // x y z
358 { "ntp_kiss", V_LENGTH(0, 255) },
360 // basic-static
361 { "dhcpd_static", V_LENGTH(0, 85*101) }, // 85 (max chars per entry) x 100 entries
363 // basic-ddns
364 { "ddnsx0", V_LENGTH(0, 2048) },
365 { "ddnsx1", V_LENGTH(0, 2048) },
366 { "ddnsx0_cache", V_LENGTH(0, 1) }, // only to clear
367 { "ddnsx1_cache", V_LENGTH(0, 1) },
368 { "ddnsx_ip", V_LENGTH(0, 32) },
369 { "ddnsx_save", V_01 },
370 { "ddnsx_refresh", V_RANGE(0, 365) },
372 // basic-network
373 // WAN
374 { "wan_proto", V_LENGTH(1, 16) }, // disabled, dhcp, static, pppoe, pptp, l2tp
375 { "wan_ipaddr", V_IP },
376 { "wan_netmask", V_IP },
377 { "wan_gateway", V_IP },
378 { "hb_server_ip", V_LENGTH(0, 32) },
379 { "l2tp_server_ip", V_IP },
380 { "pptp_server_ip", V_IP },
381 { "ppp_username", V_LENGTH(0, 50) },
382 { "ppp_passwd", V_LENGTH(0, 50) },
383 { "ppp_service", V_LENGTH(0, 50) },
384 { "ppp_demand", V_01 },
385 { "ppp_idletime", V_RANGE(0, 1440) },
386 { "ppp_redialperiod", V_RANGE(1, 86400) },
387 { "mtu_enable", V_01 },
388 { "wan_mtu", V_RANGE(576, 1500) },
389 { "wan_islan", V_01 },
391 // LAN
392 { "lan_ipaddr", V_IP },
393 { "lan_netmask", V_IP },
394 { "lan_gateway", V_IP },
395 { "wan_dns", V_LENGTH(0, 50) }, // ip ip ip
396 { "lan_proto", V_WORD }, // static, dhcp
397 { "dhcp_start", V_RANGE(1, 254) }, // remove !
398 { "dhcp_num", V_RANGE(1, 255) }, // remove !
399 { "dhcpd_startip", V_IP },
400 { "dhcpd_endip", V_IP },
401 { "dhcp_lease", V_RANGE(1, 10080) },
402 { "wan_wins", V_IP },
404 // wireless
405 { "wl_radio", V_01 },
406 { "wl_mode", V_LENGTH(2, 3) }, // ap, sta, wet, wds
407 { "wl_net_mode", V_LENGTH(5, 8) }, // disabled, mixed, b-only, g-only, bg-mixed, n-only [speedbooster]
408 { "wl_ssid", V_LENGTH(1, 32) },
409 { "wl_closed", V_01 },
410 { "wl_channel", V_RANGE(1, 14) },
411 #if TOMATO_N
412 // ! update
413 #endif
415 { "security_mode2", V_LENGTH(1, 32) }, // disabled, radius, wep, wpa_personal, wpa_enterprise, wpa2_personal, wpa2_enterprise
416 { "wl_radius_ipaddr", V_IP },
417 { "wl_radius_port", V_PORT },
418 { "wl_radius_key", V_LENGTH(1, 64) },
419 { "wl_wep_bit", V_RANGE(64, 128) }, // 64 or 128
420 { "wl_passphrase", V_LENGTH(0, 20) },
421 { "wl_key", V_RANGE(1, 4) },
422 { "wl_key1", V_LENGTH(0, 26) },
423 { "wl_key2", V_LENGTH(0, 26) },
424 { "wl_key3", V_LENGTH(0, 26) },
425 { "wl_key4", V_LENGTH(0, 26) },
426 { "wl_crypto", V_LENGTH(3, 8) }, // tkip, aes, tkip+aes
427 { "wl_wpa_psk", V_LENGTH(8, 64) },
428 { "wl_wpa_gtk_rekey", V_RANGE(60, 7200) },
430 { "wl_lazywds", V_01 },
431 { "wl_wds", V_LENGTH(0, 180) }, // mac mac mac (x 10)
433 { "security_mode", V_LENGTH(1, 32) }, // disabled, radius, wpa, psk,wep, wpa2, psk2, wpa wpa2, psk psk2
434 { "wds_enable", V_01 },
435 { "wl_gmode", V_RANGE(-1, 6) },
436 { "wl_wep", V_LENGTH(1, 32) }, // off, on, restricted,tkip,aes,tkip+aes
437 { "wl_akm", V_LENGTH(0, 32) }, // wpa, wpa2, psk, psk2, wpa wpa2, psk psk2, ""
438 { "wl_auth_mode", V_LENGTH(4, 6) }, // none, radius
440 #if TOMATO_N
441 { "wl_nmode", V_NONE },
442 { "wl_nreqd", V_NONE },
443 #endif
445 // basic-wfilter
446 { "wl_macmode", V_NONE }, // allow, deny, disabled
447 { "wl_maclist", V_LENGTH(0, 18*201) }, // 18 x 200 (11:22:33:44:55:66 ...)
448 { "macnames", V_LENGTH(0, 62*201) }, // 62 (12+1+48+1) x 50 (112233445566<..>) todo: re-use -- zzz
450 // advanced-ctnf
451 { "ct_max", V_RANGE(128, 10240) },
452 { "ct_tcp_timeout", V_LENGTH(20, 70) },
453 { "ct_udp_timeout", V_LENGTH(5, 15) },
454 { "nf_ttl", V_RANGE(-10, 10) },
455 { "nf_l7in", V_01 },
456 { "nf_rtsp", V_01 },
457 { "nf_pptp", V_01 },
458 { "nf_h323", V_01 },
459 { "nf_ftp", V_01 },
461 // advanced-dhcpdns
462 { "dhcpd_slt", V_RANGE(-1, 43200) }, // -1=infinite, 0=follow normal lease time, >=1 custom
463 { "dhcpd_dmdns", V_01 },
464 { "dhcpd_lmax", V_NUM },
465 { "dns_addget", V_01 },
466 { "dns_intcpt", V_01 },
467 { "dhcpc_minpkt", V_01 },
468 { "dnsmasq_custom", V_TEXT(0, 2048) },
469 // { "dnsmasq_norw", V_01 },
471 // advanced-firewall
472 { "block_wan", V_01 },
473 { "multicast_pass", V_01 },
474 { "block_loopback", V_01 },
475 { "nf_loopback", V_NUM },
476 { "ne_syncookies", V_01 },
478 // advanced-misc
479 { "wait_time", V_RANGE(3, 20) },
480 { "wan_speed", V_RANGE(0, 4) },
482 // advanced-mac
483 { "mac_wan", V_LENGTH(0, 17) },
484 { "mac_wl", V_LENGTH(0, 17) },
486 // advanced-routing
487 { "routes_static", V_LENGTH(0, 2048) },
488 { "lan_stp", V_RANGE(0, 1) },
489 { "wk_mode", V_LENGTH(1, 32) }, // gateway, router
490 { "dr_setting", V_RANGE(0, 3) },
491 { "dr_lan_tx", V_LENGTH(0, 32) },
492 { "dr_lan_rx", V_LENGTH(0, 32) },
493 { "dr_wan_tx", V_LENGTH(0, 32) },
494 { "dr_wan_rx", V_LENGTH(0, 32) },
496 // advanced-wireless
497 { "wl_afterburner", V_LENGTH(2, 4) }, // off, on, auto
498 { "wl_auth", V_01 },
499 { "wl_rateset", V_LENGTH(2, 7) }, // all, default, 12
500 { "wl_rate", V_RANGE(0, 54 * 1000 * 1000) },
501 { "wl_mrate", V_RANGE(0, 54 * 1000 * 1000) },
502 { "wl_gmode_protection",V_LENGTH(3, 4) }, // off, auto
503 { "wl_frameburst", V_ONOFF }, // off, on
504 { "wl_bcn", V_RANGE(1, 65535) },
505 { "wl_dtim", V_RANGE(1, 255) },
506 { "wl_frag", V_RANGE(256, 2346) },
507 { "wl_rts", V_RANGE(0, 2347) },
508 { "wl_ap_isolate", V_01 },
509 { "wl_plcphdr", V_LENGTH(4, 5) }, // long, short
510 { "wl_antdiv", V_RANGE(0, 3) },
511 { "wl_txant", V_RANGE(0, 3) },
512 { "wl_txpwr", V_RANGE(0, 255) },
513 { "wl_wme", V_ONOFF }, // off, on
514 { "wl_wme_no_ack", V_ONOFF }, // off, on
515 { "wl_maxassoc", V_RANGE(0, 255) },
516 { "wl_distance", V_LENGTH(0, 5) }, // "", 1-99999
517 { "wlx_hpamp", V_01 },
518 { "wlx_hperx", V_01 },
520 #if TOMATO_N
521 { "wl_nmode_protection",V_WORD, }, // off, auto
522 { "wl_nmcsidx", V_RANGE(-2, 15), }, // -2 - 15
523 #endif
525 // forward-dmz
526 { "dmz_enable", V_01 },
527 { "dmz_ipaddr", V_LENGTH(0, 15) },
528 { "dmz_sip", V_LENGTH(0, 512) },
530 // forward-upnp
531 { "upnp_enable", V_NUM },
532 #ifndef USE_MINIUPNPD
533 { "upnp_mnp", V_01 },
534 // { "upnp_config", V_01 },
535 { "upnp_ssdp_interval", V_RANGE(10, 9999) },
536 { "upnp_max_age", V_RANGE(5, 9999) },
537 #endif
539 // forward-basic
540 { "portforward", V_LENGTH(0, 4096) },
542 // forward-triggered
543 { "trigforward", V_LENGTH(0, 4096) },
546 // access restriction
547 { "rruleN", V_RANGE(0, 49) },
548 // { "rrule##", V_LENGTH(0, 2048) }, // in save_variables()
550 // admin-access
551 { "http_enable", V_01 },
552 { "https_enable", V_01 },
553 { "https_crt_save", V_01 },
554 { "https_crt_cn", V_LENGTH(0, 64) },
555 { "https_crt_gen", V_TEMP },
556 { "remote_management", V_01 },
557 { "remote_mgt_https", V_01 },
558 { "http_lanport", V_PORT },
559 { "https_lanport", V_PORT },
560 { "web_wl_filter", V_01 },
561 // { "web_favicon", V_01 },
562 { "web_css", V_LENGTH(1, 32) },
563 { "http_wanport", V_PORT },
564 { "telnetd_eas", V_01 },
565 { "telnetd_port", V_PORT },
566 { "sshd_eas", V_01 },
567 { "sshd_pass", V_01 },
568 { "sshd_port", V_PORT },
569 { "sshd_remote", V_01 },
570 { "sshd_rport", V_PORT },
571 { "sshd_authkeys", V_TEXT(0, 4096) },
572 { "rmgt_sip", V_LENGTH(0, 512) },
573 { "ne_shlimit", V_TEXT(1, 50) },
575 // admin-bwm
576 { "rstats_enable", V_01 },
577 { "rstats_path", V_LENGTH(0, 48) },
578 { "rstats_stime", V_RANGE(1, 168) },
579 { "rstats_offset", V_RANGE(1, 31) },
580 { "rstats_exclude", V_LENGTH(0, 64) },
581 { "rstats_sshut", V_01 },
582 { "rstats_bak", V_01 },
584 // admin-buttons
585 { "sesx_b0", V_RANGE(0, 4) }, // 0-4: toggle wireless, reboot, shutdown, script
586 { "sesx_b1", V_RANGE(0, 4) }, // "
587 { "sesx_b2", V_RANGE(0, 4) }, // "
588 { "sesx_b3", V_RANGE(0, 4) }, // "
589 { "sesx_script", V_TEXT(0, 1024) }, //
591 // admin-debug
592 { "debug_nocommit", V_01 },
593 { "debug_cprintf", V_01 },
594 { "debug_cprintf_file", V_01 },
595 // { "debug_keepfiles", V_01 },
596 { "debug_ddns", V_01 },
597 { "debug_norestart", V_TEXT(0, 128) },
598 { "console_loglevel", V_RANGE(1, 8) },
599 { "t_cafree", V_01 },
600 { "t_hidelr", V_01 },
602 // admin-sched
603 { "sch_rboot", V_TEXT(0, 64) },
604 { "sch_rcon", V_TEXT(0, 64) },
605 { "sch_c1", V_TEXT(0, 64) },
606 { "sch_c1_cmd", V_TEXT(0, 2048) },
607 { "sch_c2", V_TEXT(0, 64) },
608 { "sch_c2_cmd", V_TEXT(0, 2048) },
609 { "sch_c3", V_TEXT(0, 64) },
610 { "sch_c3_cmd", V_TEXT(0, 2048) },
612 // admin-scripts
613 { "script_init", V_TEXT(0, 4096) },
614 { "script_shut", V_TEXT(0, 4096) },
615 { "script_fire", V_TEXT(0, 8192) },
616 { "script_wanup", V_TEXT(0, 4096) },
618 // admin-log
619 { "log_remote", V_01 },
620 { "log_remoteip", V_IP },
621 { "log_remoteport", V_PORT },
622 { "log_file", V_01 },
623 { "log_limit", V_RANGE(0, 2400) },
624 { "log_in", V_RANGE(0, 3) },
625 { "log_out", V_RANGE(0, 3) },
626 { "log_mark", V_RANGE(0, 1440) },
627 { "log_events", V_TEXT(0, 32) }, // "acre,crond,ntp"
629 // admin-cifs
630 { "cifs1", V_LENGTH(1, 1024) },
631 { "cifs2", V_LENGTH(1, 1024) },
633 // admin-jffs2
634 { "jffs2_on", V_01 },
635 { "jffs2_exec", V_LENGTH(0, 64) },
636 { "jffs2_format", V_01 },
638 // qos
639 { "qos_enable", V_01 },
640 { "qos_ack", V_01 },
641 { "qos_syn", V_01 },
642 { "qos_fin", V_01 },
643 { "qos_rst", V_01 },
644 { "qos_icmp", V_01 },
645 { "qos_reset", V_01 },
646 { "qos_obw", V_RANGE(10, 999999) },
647 { "qos_ibw", V_RANGE(10, 999999) },
648 { "qos_orules", V_LENGTH(0, 4096) },
649 { "qos_default", V_RANGE(0, 9) },
650 { "qos_irates", V_LENGTH(0, 128) },
651 { "qos_orates", V_LENGTH(0, 128) },
653 { "ne_vegas", V_01 },
654 { "ne_valpha", V_NUM },
655 { "ne_vbeta", V_NUM },
656 { "ne_vgamma", V_NUM },
658 // vpn
659 { "vpn_debug", V_01 },
660 { "vpn_server_eas", V_NONE },
661 { "vpn_server_dns", V_NONE },
662 { "vpn_server1_if", V_TEXT(3, 3) }, // tap, tun
663 { "vpn_server1_proto", V_TEXT(3, 10) }, // udp, tcp-server
664 { "vpn_server1_port", V_PORT },
665 { "vpn_server1_firewall", V_TEXT(0, 8) }, // auto, external, custom
666 { "vpn_server1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
667 { "vpn_server1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
668 { "vpn_server1_cipher", V_TEXT(0, 16) },
669 { "vpn_server1_dhcp", V_01 },
670 { "vpn_server1_r1", V_IP },
671 { "vpn_server1_r2", V_IP },
672 { "vpn_server1_sn", V_IP },
673 { "vpn_server1_nm", V_IP },
674 { "vpn_server1_local", V_IP },
675 { "vpn_server1_remote", V_IP },
676 { "vpn_server1_hmac", V_RANGE(-1, 2) },
677 { "vpn_server1_ccd", V_01 },
678 { "vpn_server1_c2c", V_01 },
679 { "vpn_server1_ccd_excl", V_01 },
680 { "vpn_server1_ccd_val", V_NONE },
681 { "vpn_server1_custom", V_NONE },
682 { "vpn_server1_static", V_NONE },
683 { "vpn_server1_ca", V_NONE },
684 { "vpn_server1_crt", V_NONE },
685 { "vpn_server1_key", V_NONE },
686 { "vpn_server1_dh", V_NONE },
687 { "vpn_server2_if", V_TEXT(3, 3) }, // tap, tun
688 { "vpn_server2_proto", V_TEXT(3, 10) }, // udp, tcp-server
689 { "vpn_server2_port", V_PORT },
690 { "vpn_server2_firewall", V_TEXT(0, 8) }, // auto, external, custom
691 { "vpn_server2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
692 { "vpn_server2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
693 { "vpn_server2_cipher", V_TEXT(0, 16) },
694 { "vpn_server2_dhcp", V_01 },
695 { "vpn_server2_r1", V_IP },
696 { "vpn_server2_r2", V_IP },
697 { "vpn_server2_sn", V_IP },
698 { "vpn_server2_nm", V_IP },
699 { "vpn_server2_local", V_IP },
700 { "vpn_server2_remote", V_IP },
701 { "vpn_server2_hmac", V_RANGE(-1, 2) },
702 { "vpn_server2_custom", V_NONE },
703 { "vpn_server2_ccd", V_01 },
704 { "vpn_server2_c2c", V_01 },
705 { "vpn_server2_ccd_excl", V_01 },
706 { "vpn_server2_ccd_val", V_NONE },
707 { "vpn_server2_static", V_NONE },
708 { "vpn_server2_ca", V_NONE },
709 { "vpn_server2_crt", V_NONE },
710 { "vpn_server2_key", V_NONE },
711 { "vpn_server2_dh", V_NONE },
712 { "vpn_client_eas", V_NONE },
713 { "vpn_client1_if", V_TEXT(3, 3) }, // tap, tun
714 { "vpn_client1_bridge", V_01 },
715 { "vpn_client1_nat", V_01 },
716 { "vpn_client1_proto", V_TEXT(3, 10) }, // udp, tcp-server
717 { "vpn_client1_addr", V_NONE },
718 { "vpn_client1_port", V_PORT },
719 { "vpn_client1_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
720 { "vpn_client1_firewall", V_TEXT(0, 6) }, // auto, custom
721 { "vpn_client1_crypt", V_TEXT(0, 6) }, // tls, secret, custom
722 { "vpn_client1_comp", V_TEXT(0, 8) }, // yes, no, adaptive
723 { "vpn_client1_cipher", V_TEXT(0, 16) },
724 { "vpn_client1_local", V_IP },
725 { "vpn_client1_remote", V_IP },
726 { "vpn_client1_nm", V_IP },
727 { "vpn_client1_hmac", V_RANGE(-1, 2) },
728 { "vpn_client1_custom", V_NONE },
729 { "vpn_client1_static", V_NONE },
730 { "vpn_client1_ca", V_NONE },
731 { "vpn_client1_crt", V_NONE },
732 { "vpn_client1_key", V_NONE },
733 { "vpn_client2_if", V_TEXT(3, 3) }, // tap, tun
734 { "vpn_client2_bridge", V_01 },
735 { "vpn_client2_nat", V_01 },
736 { "vpn_client2_proto", V_TEXT(3, 10) }, // udp, tcp-server
737 { "vpn_client2_addr", V_NONE },
738 { "vpn_client2_port", V_PORT },
739 { "vpn_client2_retry", V_RANGE(-1,32767) }, // -1 infinite, 0 disabled, >= 1 custom
740 { "vpn_client2_firewall", V_TEXT(0, 6) }, // auto, custom
741 { "vpn_client2_crypt", V_TEXT(0, 6) }, // tls, secret, custom
742 { "vpn_client2_comp", V_TEXT(0, 8) }, // yes, no, adaptive
743 { "vpn_client2_cipher", V_TEXT(0, 16) },
744 { "vpn_client2_local", V_IP },
745 { "vpn_client2_remote", V_IP },
746 { "vpn_client2_nm", V_IP },
747 { "vpn_client2_hmac", V_RANGE(-1, 2) },
748 { "vpn_client2_custom", V_NONE },
749 { "vpn_client2_static", V_NONE },
750 { "vpn_client2_ca", V_NONE },
751 { "vpn_client2_crt", V_NONE },
752 { "vpn_client2_key", V_NONE },
756 ppp_static 0/1
757 ppp_static_ip IP
758 wl_enable 0/1
759 wl_wds_timeout
760 wl_maxassoc 1-256
761 wl_phytype a,b,g
762 wl_net_reauth
763 wl_preauth
764 wl_wme_ap_bk
765 wl_wme_ap_be
766 wl_wme_ap_vi
767 wl_wme_ap_vo
768 wl_wme_sta_bk
769 wl_wme_sta_be
770 wl_wme_sta_vi
771 wl_wme_sta_vo
773 port_priority_1 0-2
774 port_flow_control_1 0,1
775 port_rate_limit_1 0-8
776 port_priority_2 0-2
777 port_flow_control_2 0,1
778 port_rate_limit_2 0-8
779 port_priority_3 0-2
780 port_flow_control_3 0,1
781 port_rate_limit_3 0-8
782 port_priority_4 0-2
783 port_flow_control_4 0,1
784 port_rate_limit_4 0-8
785 wl_ap_ip
786 wl_ap_ssid
789 { NULL }
792 static int save_variables(int write)
794 const nvset_t *v;
795 char *p, *e;
796 int n;
797 long l;
798 unsigned u[6];
799 int ok;
800 char s[256];
801 int dirty;
802 static const char *msgf = "The field \"%s\" is invalid. Please report this problem.";
804 dirty = 0;
805 for (v = nvset_list; v->name; ++v) {
806 // _dprintf("[%s] %p\n", v->name, webcgi_get((char*)v->name));
807 if ((p = webcgi_get((char*)v->name)) == NULL) continue;
808 ok = 1;
809 switch (v->vtype) {
810 case VT_TEXT:
811 p = unix_string(p); // NOTE: p = malloc'd
812 // drop
813 case VT_LENGTH:
814 n = strlen(p);
815 if ((n < v->va.i) || (n > v->vb.i)) ok = 0;
816 break;
817 case VT_RANGE:
818 l = strtol(p, &e, 10);
819 if ((p == e) || (*e) || (l < v->va.l) || (l > v->vb.l)) ok = 0;
820 break;
821 case VT_IP:
822 if ((sscanf(p, "%3u.%3u.%3u.%3u", &u[0], &u[1], &u[2], &u[3]) != 4) ||
823 (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255)) ok = 0;
824 break;
825 case VT_MAC:
826 if ((sscanf(p, "%2x:%2x:%2x:%2x:%2x:%2x", &u[0], &u[1], &u[2], &u[3], &u[4], &u[5]) != 6) ||
827 (u[0] > 255) || (u[1] > 255) || (u[2] > 255) || (u[3] > 255) || (u[4] > 255) || (u[5] > 255)) ok = 0;
828 break;
829 default:
830 // shutup gcc
831 break;
833 if (!ok) {
834 if (v->vtype == VT_TEXT) free(p);
836 sprintf(s, msgf, v->name);
837 resmsg_set(s);
838 return 0;
840 if (write) {
841 if (!nvram_match((char *)v->name, p)) {
842 if (v->vtype != VT_TEMP) dirty = 1;
843 nvram_set(v->name, p);
846 if (v->vtype == VT_TEXT) free(p);
850 // special cases
852 char *p1, *p2;
853 if (((p1 = webcgi_get("set_password_1")) != NULL) && (strcmp(p1, "**********") != 0)) {
854 if (((p2 = webcgi_get("set_password_2")) != NULL) && (strcmp(p1, p2) == 0)) {
855 if ((write) && (!nvram_match("http_passwd", p1))) {
856 dirty = 1;
857 nvram_set("http_passwd", p1);
860 else {
861 sprintf(s, msgf, "password");
862 resmsg_set(s);
863 return 0;
867 for (n = 0; n < 50; ++n) {
868 sprintf(s, "rrule%d", n);
869 if ((p = webcgi_get(s)) != NULL) {
870 if (strlen(p) > 2048) {
871 sprintf(s, msgf, s);
872 resmsg_set(s);
873 return 0;
875 if ((write) && (!nvram_match(s, p))) {
876 dirty = 1;
877 nvram_set(s, p);
882 return (write) ? dirty : 1;
885 static void wo_tomato(char *url)
887 char *v;
888 int i;
889 int ajax;
890 int nvset;
891 const char *red;
892 int commit;
894 // _dprintf("tomato.cgi\n");
896 red = webcgi_safeget("_redirect", "");
897 if (!*red) send_header(200, NULL, mime_html, 0);
899 commit = atoi(webcgi_safeget("_commit", "1"));
900 ajax = atoi(webcgi_safeget("_ajax", "0"));
902 nvset = atoi(webcgi_safeget("_nvset", "1"));
903 if (nvset) {
904 if (!save_variables(0)) {
905 if (ajax) {
906 web_printf("@msg:%s", resmsg_get());
908 else {
909 parse_asp("error.asp");
911 return;
913 commit = save_variables(1) && commit;
915 resmsg_set("Settings saved.");
918 rboot = atoi(webcgi_safeget("_reboot", "0"));
919 if (rboot) {
920 parse_asp("reboot.asp");
922 else {
923 if (ajax) {
924 web_printf("@msg:%s", resmsg_get());
926 else if (atoi(webcgi_safeget("_moveip", "0"))) {
927 parse_asp("saved-moved.asp");
929 else if (!*red) {
930 parse_asp("saved.asp");
934 if (commit) {
935 _dprintf("commit from tomato.cgi\n");
936 nvram_commit_x();
939 if ((v = webcgi_get("_service")) != NULL) {
940 if (!*red) {
941 if (ajax) web_printf(" Some services are being restarted...");
942 web_close();
944 sleep(1);
946 if (*v == '*') {
947 kill(1, SIGHUP);
949 else if (*v != 0) {
950 exec_service(v);
954 for (i = atoi(webcgi_safeget("_sleep", "0")); i > 0; --i) sleep(1);
956 if (*red) redirect(red);
958 if (rboot) {
959 web_close();
960 sleep(1);
961 kill(1, SIGTERM);
966 // ----------------------------------------------------------------------------
969 static void wo_update(char *url)
971 const aspapi_t *api;
972 const char *name;
973 int argc;
974 char *argv[16];
975 char s[32];
977 if ((name = webcgi_get("exec")) != NULL) {
978 for (api = aspapi; api->name; ++api) {
979 if (strcmp(api->name, name) == 0) {
980 for (argc = 0; argc < 16; ++argc) {
981 sprintf(s, "arg%d", argc);
982 if ((argv[argc] = (char *)webcgi_get(s)) == NULL) break;
984 api->exec(argc, argv);
985 break;
991 static void wo_service(char *url)
993 int n;
995 exec_service(webcgi_safeget("_service", ""));
997 if ((n = atoi(webcgi_safeget("_sleep", "2"))) <= 0) n = 2;
998 sleep(n);
1000 common_redirect();
1004 static void wo_logout(char *url)
1006 char s[256];
1008 // doesn't work with all browsers...
1010 if (((user_agent) && (strstr(user_agent, "Opera") != NULL))) {
1011 sprintf(s, "%llx", (unsigned long long)time(NULL) * rand());
1012 send_authenticate(s);
1014 else {
1015 send_authenticate(NULL);
1020 static void wo_shutdown(char *url)
1022 parse_asp("shutdown.asp");
1023 web_close();
1024 sleep(1);
1026 kill(1, SIGQUIT);
1029 static void wo_nvcommit(char *url)
1031 parse_asp("saved.asp");
1032 web_close();
1033 nvram_commit();