source: src/router/httpd/httpd.c @ 32012

Last change on this file since 32012 was 32012, checked in by brainslayer, 3 months ago

everthing else might create a security leak

File size: 45.5 KB
Line 
1/* milli_httpd - pretty small HTTP server
2** A combination of
3** micro_httpd - really small HTTP server
4** and
5** mini_httpd - small HTTP server
6**
7** Copyright  1999,2000 by Jef Poskanzer <jef@acme.com>.
8** All rights reserved.
9**
10** Redistribution and use in source and binary forms, with or without
11** modification, are permitted provided that the following conditions
12** are met:
13** 1. Redistributions of source code must retain the above copyright
14**    notice, this list of conditions and the following disclaimer.
15** 2. Redistributions in binary form must reproduce the above copyright
16**    notice, this list of conditions and the following disclaimer in the
17**    documentation and/or other materials provided with the distribution.
18**
19** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29** SUCH DAMAGE.
30*/
31#define _GNU_SOURCE
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <time.h>
38#include <unistd.h>
39#include <netinet/in.h>
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <sys/stat.h>
43#include <arpa/inet.h>
44#include <getopt.h>
45#include <stdarg.h>
46#include <syslog.h>
47#include <cy_conf.h>
48#include "httpd.h"
49#include <bcmnvram.h>
50#include <code_pattern.h>
51#include <utils.h>
52#include <shutils.h>
53#include <sys/time.h>
54#include <signal.h>
55#include <sys/wait.h>
56
57#ifdef HAVE_OPENSSL
58#include <openssl/ssl.h>
59#endif
60
61#ifdef HAVE_MATRIXSSL
62#include <matrixSsl.h>
63#include <matrixssl_xface.h>
64#endif
65
66#ifdef HAVE_POLARSSL
67#include "polarssl/entropy.h"
68#include <polarssl/ctr_drbg.h>
69#include <polarssl/certs.h>
70#include <polarssl/x509.h>
71#include <polarssl/ssl.h>
72#include <polarssl/net.h>
73//#include <xyssl_xface.h>
74#endif
75
76#ifdef __UCLIBC__
77#include <error.h>
78#endif
79#include <sys/signal.h>
80
81#ifdef HAVE_IAS
82#include <sys/sysinfo.h>
83#endif
84
85#define SERVER_NAME "httpd"
86#define PROTOCOL "HTTP/1.0"
87#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
88#define TIMEOUT 5
89
90/* A multi-family sockaddr. */
91typedef union {
92        struct sockaddr sa;
93        struct sockaddr_in sa_in;
94} usockaddr;
95
96/* Globals. */
97#ifdef HAVE_OPENSSL
98static SSL *ssl;
99#endif
100
101#ifdef FILTER_DEBUG
102FILE *debout;
103#endif
104
105#if defined(HAVE_OPENSSL) || defined(HAVE_MATRIXSSL) || defined(HAVE_POLARSSL)
106
107#define DEFAULT_HTTPS_PORT 443
108#define CERT_FILE "/etc/cert.pem"
109#define KEY_FILE "/etc/key.pem"
110#endif
111
112#ifdef HAVE_MATRIXSSL
113extern ssl_t *ssl;
114extern sslKeys_t *keys;
115#endif
116
117#ifdef HAVE_POLARSSL
118ssl_context ssl;
119int my_ciphers[] = {
120        TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
121        TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
122        TLS_RSA_WITH_AES_256_CBC_SHA,
123        TLS_RSA_WITH_RC4_128_MD5,
124        TLS_RSA_WITH_RC4_128_SHA,
125        TLS_RSA_WITH_AES_128_CBC_SHA256,
126        TLS_RSA_WITH_AES_256_CBC_SHA256,
127        TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
128        TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
129        TLS_RSA_WITH_AES_128_GCM_SHA256,
130        TLS_RSA_WITH_AES_256_GCM_SHA384,
131        0
132};
133
134char *dhm_P =
135    "E4004C1F94182000103D883A448B3F80"
136    "2CE4B44A83301270002C20D0321CFD00"
137    "11CCEF784C26A400F43DFB901BCA7538" "F2C6B176001CF5A0FD16D2C48B1D0C1C" "F6AC8E1DA6BCC3B4E1F96B0564965300" "FFA1D0B601EB2800F489AA512C4B248C" "01F76949A60BB7F00A40B1EAB64BDD48" "E8A700D60B7F1200FA8E77B0A979DABF";
138
139char *dhm_G = "4";
140//unsigned char session_table[SSL_SESSION_TBL_LEN];
141#endif
142
143#define DEFAULT_HTTP_PORT 80
144int server_port;
145char pid_file[80];
146char *server_dir = NULL;
147
148#ifdef HAVE_HTTPS
149int do_ssl = 0;
150#endif
151
152//static FILE *conn_fp;
153static webs_t conn_fp = NULL;   // jimmy, https, 8/4/2003
154static char auth_userid[AUTH_MAX];
155static char auth_passwd[AUTH_MAX];
156char auth_realm[AUTH_MAX];
157char curr_page[32];
158
159//#ifdef GET_POST_SUPPORT
160int post;
161
162//#endif
163int auth_fail = 0;
164int httpd_level;
165
166char http_client_ip[20];
167extern char *get_mac_from_ip(char *ip);
168
169/* Forwards. */
170static int initialize_listen_socket(usockaddr * usaP);
171static int auth_check(char *user, char *pass, char *dirname, char *authorization);
172static void send_error(int status, char *title, char *extra_header, char *text);
173void send_headers(int status, char *title, char *extra_header, char *mime_type, int length, char *attach_file);
174static int b64_decode(const char *str, unsigned char *space, int size);
175static int match(const char *pattern, const char *string);
176static int match_one(const char *pattern, int patternlen, const char *string);
177static void handle_request(void);
178
179static int initialize_listen_socket(usockaddr * usaP)
180{
181        int listen_fd;
182        int i;
183
184        memset(usaP, 0, sizeof(usockaddr));
185        usaP->sa.sa_family = AF_INET;
186        usaP->sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
187        usaP->sa_in.sin_port = htons(server_port);
188
189        listen_fd = socket(usaP->sa.sa_family, SOCK_STREAM, 0);
190        if (listen_fd < 0) {
191                perror("socket");
192                return -1;
193        }
194        (void)fcntl(listen_fd, F_SETFD, 1);
195        i = 1;
196        if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)) < 0) {
197                perror("setsockopt");
198                return -1;
199        }
200        if (bind(listen_fd, &usaP->sa, sizeof(struct sockaddr_in)) < 0) {
201                perror("bind");
202                return -1;
203        }
204        if (listen(listen_fd, 1024) < 0) {
205                perror("listen");
206                return -1;
207        }
208        return listen_fd;
209}
210
211static int auth_check(char *user, char *pass, char *dirname, char *authorization)
212{
213        unsigned char authinfo[500];
214        unsigned char *authpass;
215        int l;
216
217        /* Is this directory unprotected? */
218        if (!strlen(pass))
219                /* Yes, let the request go through. */
220                return 1;
221
222        /* Basic authorization info? */
223        if (!authorization || strncmp(authorization, "Basic ", 6) != 0) {
224                //send_authenticate( dirname );
225                ct_syslog(LOG_INFO, httpd_level, "Authentication fail");
226                return 0;
227        }
228
229        /* Decode it. */
230        l = b64_decode(&(authorization[6]), authinfo, sizeof(authinfo));
231        authinfo[l] = '\0';
232        /* Split into user and password. */
233        authpass = strchr((char *)authinfo, ':');
234        if (authpass == (unsigned char *)0) {
235                /* No colon?  Bogus auth info. */
236                //send_authenticate( dirname );
237                return 0;
238        }
239        *authpass++ = '\0';
240
241        char *crypt(const char *, const char *);
242
243        char buf1[36];
244        char buf2[36];
245        char *enc1;
246        char *enc2;
247        memdebug_enter();
248        enc1 = crypt(authinfo, (unsigned char *)user);
249
250        if (strcmp(enc1, user)) {
251                return 0;
252        }
253        char dummy[128];
254        enc2 = crypt(authpass, (unsigned char *)pass);
255        if (strcmp(enc2, pass)) {
256                syslog(LOG_INFO, "httpd login failure - bad passwd !\n");
257                while (wfgets(dummy, 64, conn_fp) > 0) {
258                        //fprintf(stderr, "flushing %s\n", dummy);
259                }
260                return 0;
261        }
262        memdebug_leave();
263
264#if 0                           //ndef HAVE_IAS
265        u_int64_t auth_time = (u_int64_t)(atoll(nvram_safe_get("auth_time")));
266        u_int64_t curr_time = (u_int64_t)time(NULL);
267        char s_curr_time[24];
268        sprintf(s_curr_time, "%llu", curr_time);
269        if (nvram_get("ias_startup") && nvram_geti("ias_startup") > 0) {
270                fprintf(stderr, "IAS ignore\n");
271                return 1;
272        }
273
274        int submittedtoken = nvram_geti("token");
275        int currenttoken = nvram_geti("ptoken");
276
277        //protect config changes
278        if (!strcmp(curr_page, "apply.cgi") || !strcmp(curr_page, "nvram.cgi") || !strcmp(curr_page, "upgrade.cgi")) {
279                //if token does not match ask for auth again, every page that does submit data in POST must send correct token
280                if (currenttoken != 0)
281                        if ((submittedtoken != currenttoken)) {
282                                //empty read buffer or send_authenticate will fail
283                                while (wfgets(dummy, 64, conn_fp) > 0) {
284                                        //fprintf(stderr, "flushing %s\n", dummy);
285                                }
286                                return 0;
287                        }
288        }
289
290        if (((curr_time - auth_time) > atoll(nvram_safe_get("auth_limit")))) {
291                //empty read buffer or send_authenticate will fail
292                while (wfgets(dummy, 64, conn_fp) > 0) {
293                        //fprintf(stderr, "flushing %s\n", dummy);
294                }
295                return 0;
296        }
297
298        nvram_set("auth_time", s_curr_time);
299#endif
300
301        return 1;
302}
303
304void send_authenticate(char *realm)
305{
306        u_int64_t auth_time = (u_int64_t)(atoll(nvram_safe_get("auth_time")));
307        u_int64_t curr_time = (u_int64_t)time(NULL);
308        char s_curr_time[24];
309        sprintf(s_curr_time, "%llu", curr_time);
310
311        char header[10000];
312
313        (void)snprintf(header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm);
314        send_error(401, "Unauthorized", header,
315#if defined(HAVE_BUFFALO) && defined(HAVE_IAS)
316                   "Authorization required. please note that the default username is \"admin\" in all newer releases");
317#else
318                   "Authorization required. please note that the default username is \"root\" in all newer releases");
319#endif
320        /* init these after a successful auth */
321        nvram_set("auth_time", s_curr_time);
322}
323
324static void send_error(int status, char *title, char *extra_header, char *text)
325{
326
327        // jimmy, https, 8/4/2003, fprintf -> wfprintf, fflush -> wfflush
328        send_headers(status, title, extra_header, "text/html", -1, NULL);
329        (void)wfprintf(conn_fp, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, title);
330        (void)wfprintf(conn_fp, "%s\n", text);
331        (void)wfprintf(conn_fp, "</BODY></HTML>\n");
332        (void)wfflush(conn_fp);
333}
334
335void send_headers(int status, char *title, char *extra_header, char *mime_type, int length, char *attach_file)
336{
337        time_t now;
338        char timebuf[100];
339
340        wfprintf(conn_fp, "%s %d %s\r\n", PROTOCOL, status, title);
341        if (mime_type != (char *)0)
342                wfprintf(conn_fp, "Content-Type: %s\r\n", mime_type);
343
344        wfprintf(conn_fp, "Server: %s\r\n", SERVER_NAME);
345        now = time((time_t *) 0);
346        strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
347        wfprintf(conn_fp, "Date: %s\r\n", timebuf);
348        wfprintf(conn_fp, "Connection: close\r\n");
349        wfprintf(conn_fp, "Cache-Control: no-store, no-cache, must-revalidate\r\n");
350        wfprintf(conn_fp, "Cache-Control: post-check=0, pre-check=0\r\n");
351        wfprintf(conn_fp, "Pragma: no-cache\r\n");
352        if (attach_file)
353                wfprintf(conn_fp, "Content-Disposition: attachment; filename=%s\r\n", attach_file);
354        if (extra_header != (char *)0 && *extra_header)
355                wfprintf(conn_fp, "%s\r\n", extra_header);
356        if (length != -1)
357                wfprintf(conn_fp, "Content-Length: %ld\r\n", length);
358        wfprintf(conn_fp, "\r\n");
359}
360
361/* Base-64 decoding.  This represents binary data as printable ASCII
362** characters.  Three 8-bit binary bytes are turned into four 6-bit
363** values, like so:
364**
365**   [11111111]  [22222222]  [33333333]
366**
367**   [111111] [112222] [222233] [333333]
368**
369** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
370*/
371
372static int b64_decode_table[256] = {
373        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 00-0F */
374        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10-1F */
375        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 20-2F */
376        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 30-3F */
377        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,   /* 40-4F */
378        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 50-5F */
379        -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 60-6F */
380        41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 70-7F */
381        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80-8F */
382        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90-9F */
383        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0-AF */
384        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0-BF */
385        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0-CF */
386        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* D0-DF */
387        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* E0-EF */
388        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  /* F0-FF */
389};
390
391/* Do base-64 decoding on a string.  Ignore any non-base64 bytes.
392** Return the actual number of bytes generated.  The decoded size will
393** be at most 3/4 the size of the encoded, and may be smaller if there
394** are padding characters (blanks, newlines).
395*/
396static int b64_decode(const char *str, unsigned char *space, int size)
397{
398        const char *cp;
399        int space_idx, phase;
400        int d, prev_d = 0;
401        unsigned char c;
402
403        space_idx = 0;
404        phase = 0;
405        for (cp = str; *cp != '\0'; ++cp) {
406                d = b64_decode_table[(int)*cp];
407                if (d != -1) {
408                        switch (phase) {
409                        case 0:
410                                ++phase;
411                                break;
412                        case 1:
413                                c = ((prev_d << 2) | ((d & 0x30) >> 4));
414                                if (space_idx < size)
415                                        space[space_idx++] = c;
416                                ++phase;
417                                break;
418                        case 2:
419                                c = (((prev_d & 0xf) << 4) | ((d & 0x3c) >> 2));
420                                if (space_idx < size)
421                                        space[space_idx++] = c;
422                                ++phase;
423                                break;
424                        case 3:
425                                c = (((prev_d & 0x03) << 6) | d);
426                                if (space_idx < size)
427                                        space[space_idx++] = c;
428                                phase = 0;
429                                break;
430                        }
431                        prev_d = d;
432                }
433        }
434        return space_idx;
435}
436
437/* Simple shell-style filename matcher.  Only does ? * and **, and multiple
438** patterns separated by |.  Returns 1 or 0.
439*/
440static int match(const char *pattern, const char *string)
441{
442        const char *or;
443
444        for (;;) {
445                or = strchr(pattern, '|');
446                if (or == (char *)0)
447                        return match_one(pattern, strlen(pattern), string);
448                if (match_one(pattern, or - pattern, string))
449                        return 1;
450                pattern = or + 1;
451        }
452}
453
454static int match_one(const char *pattern, int patternlen, const char *string)
455{
456        const char *p;
457
458        for (p = pattern; p - pattern < patternlen; ++p, ++string) {
459                if (*p == '?' && *string != '\0')
460                        continue;
461                if (*p == '*') {
462                        int i, pl;
463
464                        ++p;
465                        if (*p == '*') {
466                                /* Double-wildcard matches anything. */
467                                ++p;
468                                i = strlen(string);
469                        } else
470                                /* Single-wildcard matches anything but slash. */
471                                i = strcspn(string, "/");
472                        pl = patternlen - (p - pattern);
473                        for (; i >= 0; --i)
474                                if (match_one(p, pl, &(string[i])))
475                                        return 1;
476                        return 0;
477                }
478                if (*p != *string)
479                        return 0;
480        }
481        if (*string == '\0')
482                return 1;
483        return 0;
484}
485
486static void do_file_2(struct mime_handler *handler, char *path, webs_t stream, char *query, char *attach)       //jimmy, https, 8/4/2003
487{
488
489        size_t len;
490        FILE *web = getWebsFile(path);
491
492        if (web == NULL) {
493                if (!(web = fopen(path, "rb")))
494                        return;
495                fseek(web, 0, SEEK_END);
496                len = ftell(web);
497                fseek(web, 0, SEEK_SET);
498
499        } else {
500                len = getWebsFileLen(path);
501        }
502        if (!handler->send_headers)
503                send_headers(200, "Ok", handler->extra_header, handler->mime_type, len, attach);
504        char *buffer = malloc(4096);
505        while (len) {
506                size_t ret = fread(buffer, 1, len > 4096 ? 4096 : len, web);
507                len -= ret;
508                wfwrite(buffer, ret, 1, stream);
509        }
510        free(buffer);
511        fclose(web);
512}
513
514void
515//do_file(char *path, FILE *stream)
516do_file(char *method, struct mime_handler *handler, char *path, webs_t stream, char *query)     //jimmy, https, 8/4/2003
517{
518
519        do_file_2(handler, path, stream, query, NULL);
520}
521
522void do_file_attach(struct mime_handler *handler, char *path, webs_t stream, char *query, char *attachment)     //jimmy, https, 8/4/2003
523{
524
525        do_file_2(handler, path, stream, query, attachment);
526}
527
528#ifdef HSIAB_SUPPORT
529static char *                   // add by jimmy 2003-5-13
530get_aaa_url(int inout_mode, char *client_ip)
531{
532        static char line[MAX_BUF_LEN];
533        char cmd[MAX_BUF_LEN];
534
535        strcpy(line, "");
536        if (inout_mode == 0)
537                snprintf(cmd, sizeof(cmd), "GET aaa_login_url %s", client_ip);
538        else
539                snprintf(cmd, sizeof(cmd), "GET aaa_logout_url %s", client_ip);
540
541        send_command(cmd, line);
542
543        return line;
544}
545
546char *                          // add by honor 2003-04-16, modify by jimmy 2003-05-13
547get_client_ip(int conn_fp)
548{
549        struct sockaddr_in sa;
550        int len = sizeof(struct sockaddr_in);
551        static char ip[20];
552
553        getpeername(conn_fp, (struct sockaddr *)&sa, &len);
554        char client[32];
555        char *peer = inet_ntop(AF_INET, &sa.sin_addr, client, 16);
556
557        strcpy(ip, peer);
558        return (ip);
559}
560#endif
561
562static int check_connect_type(void)
563{
564        struct wl_assoc_mac *wlmac = NULL;
565        int count_wl = 0;
566        int i, j, ret = 0;
567        char temp[32];
568        int c = get_wl_instances();
569
570        for (j = 0; j < c; j++) {
571                sprintf(temp, "wl%d_web_filter", j);
572                if (nvram_invmatchi(temp, 1))
573                        continue;
574
575                wlmac = get_wl_assoc_mac(j, &count_wl);
576
577                for (i = 0; i < count_wl; i++) {
578                        if (!strcmp(wlmac[i].mac, nvram_safe_get("http_client_mac"))) {
579                                cprintf("Can't accept wireless access\n");
580                                ret = -1;
581                        }
582                }
583                free(wlmac);
584        }
585
586        return ret;
587}
588
589static char *last_log_ip = NULL;
590static int registered = -1;
591static int registered_real = -1;
592char *request_url = NULL;
593#ifdef HAVE_IAS
594char ias_sid[20];
595char ias_http_client_mac[20];
596int ias_sid_timeout;
597void ias_sid_set();
598int ias_sid_valid();
599#endif
600
601#define LINE_LEN 10000
602static void handle_request(void)
603{
604        char *query;
605        char *cur;
606        char *method, *path, *protocol, *authorization, *boundary, *referer, *host, *useragent, *language;
607        char *cp;
608        char *file = NULL;
609        FILE *exec;
610        int len;
611        struct mime_handler *handler;
612        int cl = 0, count, flags;
613        char line[LINE_LEN + 1];
614
615        /* Initialize the request variables. */
616        authorization = referer = boundary = host = NULL;
617        bzero(line, sizeof line);
618
619        memset(line, 0, LINE_LEN);
620        /* Parse the first line of the request. */
621        if (wfgets(line, LINE_LEN, conn_fp) == (char *)0) {     //jimmy,https,8/4/2003
622                send_error(400, "Bad Request", (char *)0, "No request found.");
623                return;
624        }
625
626        /* To prevent http receive https packets, cause http crash (by honor 2003/09/02) */
627        if (strncasecmp(line, "GET", 3) && strncasecmp(line, "POST", 4) && strncasecmp(line, "OPTIONS", 7)) {
628                return;
629        }
630        method = path = line;
631        strsep(&path, " ");
632        if (!path) {            // Avoid http server crash, added by honor 2003-12-08
633                send_error(400, "Bad Request", (char *)0, "Can't parse request.");
634                return;
635        }
636        while (*path == ' ')
637                path++;
638        protocol = path;
639        strsep(&protocol, " ");
640        if (!protocol) {        // Avoid http server crash, added by honor 2003-12-08
641                send_error(400, "Bad Request", (char *)0, "Can't parse request.");
642                return;
643        }
644        while (*protocol == ' ')
645                protocol++;
646        cp = protocol;
647        strsep(&cp, " ");
648        cur = protocol + strlen(protocol) + 1;
649        /* Parse the rest of the request headers. */
650
651        while (wfgets(cur, line + LINE_LEN - cur, conn_fp) != 0)        //jimmy,https,8/4/2003
652        {
653                if (strcmp(cur, "\n") == 0 || strcmp(cur, "\r\n") == 0) {
654                        break;
655                } else if (strncasecmp(cur, "Authorization:", 14) == 0) {
656                        cp = &cur[14];
657                        cp += strspn(cp, " \t");
658                        authorization = cp;
659                        cur = cp + strlen(cp) + 1;
660                } else if (strncasecmp(cur, "Referer:", 8) == 0) {
661                        cp = &cur[8];
662                        cp += strspn(cp, " \t");
663                        referer = cp;
664                        cur = cp + strlen(cp) + 1;
665                } else if (strncasecmp(cur, "Host:", 5) == 0) {
666                        cp = &cur[5];
667                        cp += strspn(cp, " \t");
668                        host = cp;
669                        cur = cp + strlen(cp) + 1;
670                } else if (strncasecmp(cur, "Content-Length:", 15) == 0) {
671                        cp = &cur[15];
672                        cp += strspn(cp, " \t");
673                        cl = strtoul(cp, NULL, 0);
674
675                } else if ((cp = strstr(cur, "boundary="))) {
676                        boundary = &cp[9];
677                        for (cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++) ;
678                        *cp = '\0';
679                        cur = ++cp;
680                } else if (strncasecmp(cur, "User-Agent:", 11) == 0) {
681                        cp = &cur[11];
682                        cp += strspn(cp, " \t");
683                        useragent = cp;
684                        cur = cp + strlen(cp) + 1;
685                } else if (strncasecmp(cur, "Accept-Language:", 16) == 0) {
686                        cp = &cur[17];
687                        cp += strspn(cp, " \t");
688                        language = cp;
689                        cur = cp + strlen(cp) + 1;
690                }
691        }
692
693        if (strcasecmp(method, "get") != 0 && strcasecmp(method, "post") != 0 && strcasecmp(method, "options") != 0) {
694                send_error(501, "Not Implemented", (char *)0, "That method is not implemented.");
695                return;
696        }
697        if (path[0] != '/') {
698                send_error(400, "Bad Request", (char *)0, "Bad filename.");
699                return;
700        }
701        file = &(path[1]);
702        len = strlen(file);
703        if (file[0] == '/' || strcmp(file, "..") == 0 || strncmp(file, "../", 3) == 0 || strstr(file, "/../") != (char *)0 || strcmp(&(file[len - 3]), "/..") == 0) {
704                send_error(400, "Bad Request", (char *)0, "Illegal filename.");
705                return;
706        }
707        int nodetect = 0;
708        if (nvram_matchi("status_auth", 0) && endswith(file, "Info.htm"))
709                nodetect = 1;
710        if (nvram_matchi("no_crossdetect", 1))
711                nodetect = 1;
712#ifdef HAVE_IAS
713        if (nvram_matchi("ias_startup", 3) || nvram_matchi("ias_startup", 2)) {
714                nodetect = 1;
715                typedef struct {
716                        char *iso;
717                        char *mapping;
718                        char *countryext;
719                } ISOMAP;
720
721                ISOMAP isomap[] = {
722                        {
723                         "de", "german"},       //
724                        {
725                         "es", "spanish"},      //
726                        {
727                         "fr", "french"},       //
728                        {
729                         "hr", "croatian"},     //
730                        {
731                         "hu", "hungarian"},    //
732                        {
733                         "nl", "dutch"},        //
734                        {
735                         "it", "italian"},      //
736                        {
737                         "lv", "latvian"},      //
738                        {
739                         "jp", "japanese"},     //
740                        {
741                         "pl", "polish"},       //
742                        {
743                         "pt", "portuguese_braz"},      //
744                        {
745                         "ro", "romanian"},     //
746                        {
747                         "ru", "russian", "RU"},        //
748                        {
749                         "sl", "slovenian"},    //
750                        {
751                         "sr", "serbian"},      //
752                        {
753                         "sv", "swedish"},      //
754                        {
755                         "zh", "chinese_simplified"},   //
756                        {
757                         "tr", "turkish"},      //
758                        NULL
759                };
760                if (nvram_match("langprop", "") || nvram_get("langprop") == NULL) {
761                        int cnt = 0;
762                        nvram_set("langprop", "english");
763                        while (isomap[cnt].iso != NULL) {
764                                if (strncasecmp(language, isomap[cnt].iso, 2) == 0) {
765                                        nvram_set("langprop", isomap[cnt].mapping);
766                                        if (isomap[cnt].countryext)
767                                                nvram_set("country", isomap[cnt].countryext);
768                                        break;
769                                }
770                                cnt++;
771                        }
772                }
773        }
774#endif
775
776        if (!referer && strcasecmp(method, "post") == 0 && nodetect == 0) {
777                send_error(400, "Bad Request", (char *)0, "Cross Site Action detected!");
778                return;
779        }
780        if (referer && host && nodetect == 0) {
781                int i;
782                int hlen = strlen(host);
783                int rlen = strlen(referer);
784                int slashs = 0;
785
786                for (i = 0; i < rlen; i++) {
787                        if (referer[i] == '/')
788                                slashs++;
789                        if (slashs == 2) {
790                                i++;
791                                break;
792                        }
793                }
794                if (slashs == 2) {
795                        int a;
796                        int c = 0;
797
798                        for (a = 0; a < hlen; a++)
799                                if (host[a] == ' ' || host[a] == '\r' || host[a] == '\n' || host[a] == '\t')
800                                        host[a] = 0;
801                        hlen = strlen(host);
802                        for (a = i; a < rlen; a++) {
803                                if (referer[a] == '/') {
804                                        send_error(400, "Bad Request", (char *)0, "Cross Site Action detected!");
805                                        return;
806                                }
807                                if (host[c++] != referer[a]) {
808                                        send_error(400, "Bad Request", (char *)0, "Cross Site Action detected!");
809                                        return;
810                                }
811                                if (c == hlen) {
812                                        a++;
813                                        break;
814                                }
815                        }
816                        if (c != hlen || referer[a] != '/') {
817                                send_error(400, "Bad Request", (char *)0, "Cross Site Action detected!");
818                                return;
819                        }
820                }
821
822        }
823        // seg change for status site
824#ifdef HAVE_REGISTER
825        if (registered_real == -1) {
826                registered_real = isregistered_real();
827        }
828        if (!registered_real)
829                registered = isregistered();
830        else
831                registered = registered_real;
832#endif
833
834        // save the originally requested url
835        if (request_url)        // ahm, we should check for null
836                free(request_url);
837        request_url = strdup(file);
838
839#ifdef HAVE_SKYTRON
840        if (file[0] == '\0' || file[len - 1] == '/') {
841                file = "setupindex.asp";
842        }
843#else
844#ifdef HAVE_BUFFALO
845#ifdef HAVE_IAS
846        int ias_startup = nvram_geti("ias_startup");
847        int ias_detected = 0;
848        char redirect_path[48];
849
850        if (ias_startup > 1) {
851
852                if (endswith(file, "?ias_detect")) {
853                        ias_detected = 1;
854                        fprintf(stderr, "[HTTP PATH] %s detected (%d)\n", file, ias_startup);
855                }
856
857                if (!endswith(file, ".js") && !endswith(file, "detect.asp")
858                    && ias_detected == 0 && nvram_matchi("ias_startup", 3)) {
859
860                        fprintf(stderr, "[HTTP PATH] %s redirect\n", file);
861                        sprintf(redirect_path, "Location: http://%s/detect.asp", nvram_get("lan_ipaddr"));
862                        send_headers(302, "Found", redirect_path, "", -1, NULL);
863                        return;
864
865                } else if (ias_detected == 1) {
866                        fprintf(stderr, "[HTTP PATH] %s redirected\n", file);
867                        nvram_seti("ias_startup", 2);
868                }
869        }
870
871        if (!ias_sid_valid()
872            && (endswith(file, "InternetAtStart.asp") || endswith(file, "detect.asp") || endswith(file, "?ias_detect"))
873            && strstr(useragent, "Android"))
874                ias_sid_set();
875
876        char hostname[32];
877        if (strlen(host) < 32 && ias_detected == 1 && (nvram_matchi("ias_dnsresp", 1))) {
878                strncpy(hostname, host, strspn(host, "123456789.:"));
879                if (!strcmp(hostname, nvram_get("lan_ipaddr"))) {
880
881                        nvram_unset("ias_dnsresp");
882
883                        sysprintf("iptables -t nat -D PREROUTING -i br0 -p udp --dport 53 -j DNAT --to %s:55300", nvram_get("lan_ipaddr"));
884
885                        char buf[128];
886                        char call[64];
887                        int pid;
888                        FILE *fp;
889
890                        sprintf(call, "ps|grep \"dns_responder\"");
891                        fp = popen(call, "r");
892                        if (fp) {
893                                while (fgets(buf, sizeof(buf), fp)) {
894                                        if (strstr(buf, nvram_get("lan_ipaddr"))) {
895                                                if (sscanf(buf, "%d ", &pid)) {
896                                                        kill(pid, SIGTERM);
897                                                }
898                                        }
899                                }
900
901                                pclose(fp);
902                        }
903
904                }
905        }
906#endif
907#endif
908        if (file[0] == '\0' || file[len - 1] == '/') {
909
910                {
911                        if (server_dir != NULL && strcmp(server_dir, "/www"))   // to allow to use router as a WEB server
912                        {
913                                file = "index.htm";
914                        } else {
915#ifdef HAVE_IAS
916                                file = "index.asp";
917#else
918                                if (nvram_invmatchi("status_auth", 0))
919                                        file = "Info.htm";
920                                else
921                                        file = "index.asp";
922#endif
923                        }
924                }
925        } else {
926                {
927                        if (nvram_invmatchi("status_auth", 1))
928                                if (strcmp(file, "Info.htm") == 0)
929                                        file = "index.asp";
930                }
931        }
932#endif
933
934        {
935                if (strncmp(file, "bigfile.bin", 11)) {
936                        /* extract url args if present */
937                        query = strchr(file, '?');
938                        if (query) {
939                                //see token length in createpageToken
940                                char token[16] = "0";
941                                strncpy(token, &query[1], sizeof(token));
942                                nvram_set("token", token);
943                                *query++ = 0;
944                        } else {
945                                nvram_seti("token", 0);
946                        }
947                }
948                int changepassword = 0;
949
950#ifdef HAVE_REGISTER
951                if (!registered_real) {
952                        if (endswith(file, "About.htm"))
953                                file = "register.asp";
954                }
955                if (!registered) {
956                        if (endswith(file, ".asp"))
957                                file = "register.asp";
958                        else if (endswith(file, ".htm"))
959                                file = "register.asp";
960                        else if (endswith(file, ".html"))
961                                file = "register.asp";
962                } else
963#endif
964                {
965                        if (((nvram_match("http_username", DEFAULT_USER)
966                              && nvram_match("http_passwd", DEFAULT_PASS))
967                             || nvram_match("http_username", "")
968                             || nvram_match("http_passwd", "admin"))
969                            && !endswith(file, "register.asp")
970                            && !endswith(file, "vsp.html")) {
971                                changepassword = 1;
972                                if (endswith(file, ".asp"))
973                                        file = "changepass.asp";
974                                else if (endswith(file, ".htm")
975                                         && !endswith(file, "About.htm"))
976                                        file = "changepass.asp";
977                                else if (endswith(file, ".html"))
978                                        file = "changepass.asp";
979                        } else {
980                                if (endswith(file, "changepass.asp")) {
981                                        if (nvram_invmatchi("status_auth", 0))
982                                                file = "Info.htm";
983                                        else
984                                                file = "index.asp";
985                                }
986                        }
987                }
988                FILE *fp;
989                int file_found = 1;
990
991                strncpy(curr_page, file, sizeof(curr_page));
992
993                for (handler = &mime_handlers[0]; handler->pattern; handler++) {
994                        if (match(handler->pattern, file)) {
995#ifdef HAVE_REGISTER
996                                if (registered)
997#endif
998                                {
999                                        memdebug_enter();
1000                                        if (!changepassword && handler->auth && strcasecmp(method, "options") && strncmp(file, "bigfile.bin", 11)) {
1001                                                int result = handler->auth(conn_fp,
1002                                                                           auth_userid,
1003                                                                           auth_passwd,
1004                                                                           auth_realm,
1005                                                                           authorization,
1006                                                                           auth_check);
1007
1008#ifdef HAVE_IAS
1009                                                if (!result && !((!strcmp(file, "apply.cgi") || !strcmp(file, "InternetAtStart.ajax.asp"))
1010                                                                 && strstr(useragent, "Android")
1011                                                                 && ias_sid_valid())) {
1012                                                        fprintf(stderr, "[AUTH FAIL]: %s", useragent);
1013#else
1014                                                if (!result) {
1015#endif
1016                                                        auth_fail = 0;
1017                                                        send_authenticate(auth_realm);
1018                                                        return;
1019                                                }
1020                                        }
1021                                        memdebug_leave_info("auth");
1022                                }
1023                                post = 0;
1024                                if (strcasecmp(method, "post") == 0) {
1025                                        post = 1;
1026                                }
1027                                {
1028                                        memdebug_enter();
1029                                        if (handler->input)
1030                                                handler->input(file, conn_fp, cl, boundary);
1031                                        memdebug_leave_info("input");
1032                                }
1033#if defined(linux)
1034#ifdef HAVE_HTTPS
1035                                if (!do_ssl && (flags = fcntl(fileno(conn_fp->fp), F_GETFL)) != -1 && fcntl(fileno(conn_fp->fp), F_SETFL, flags | O_NONBLOCK) != -1) {
1036                                        /* Read up to two more characters */
1037                                        if (fgetc(conn_fp->fp) != EOF)
1038                                                (void)fgetc(conn_fp->fp);
1039                                        fcntl(fileno(conn_fp->fp), F_SETFL, flags);
1040                                }
1041#else
1042                                if ((flags = fcntl(fileno(conn_fp->fp), F_GETFL)) != -1 && fcntl(fileno(conn_fp->fp), F_SETFL, flags | O_NONBLOCK) != -1) {
1043                                        /* Read up to two more characters */
1044                                        if (fgetc(conn_fp->fp) != EOF)
1045                                                (void)fgetc(conn_fp->fp);
1046                                        fcntl(fileno(conn_fp->fp), F_SETFL, flags);
1047                                }
1048#endif
1049#endif
1050                                {
1051                                        memdebug_enter();
1052                                        if (check_connect_type() < 0) {
1053                                                send_error(401, "Bad Request", (char *)0, "Can't use wireless interface to access GUI.");
1054                                                return;
1055                                        }
1056                                        memdebug_leave_info("connect");
1057                                }
1058                                {
1059                                        memdebug_enter();
1060                                        if (auth_fail == 1) {
1061                                                send_authenticate(auth_realm);
1062                                                auth_fail = 0;
1063                                                return;
1064                                        } else {
1065                                                if (handler->output != do_file)
1066                                                        if (handler->send_headers)
1067                                                                send_headers(200, "Ok", handler->extra_header, handler->mime_type, -1, NULL);
1068                                        }
1069                                        memdebug_leave_info("auth_output");
1070                                }
1071
1072                                {
1073                                        memdebug_enter();
1074                                        // check for do_file handler and check if file exists
1075                                        file_found = 1;
1076                                        if (handler->output == do_file) {
1077                                                if (getWebsFileLen(file) == 0) {
1078                                                        if (!(fp = fopen(file, "rb"))) {
1079                                                                file_found = 0;
1080                                                        } else {
1081                                                                fclose(fp);
1082                                                        }
1083                                                }
1084                                        }
1085                                        if (handler->output && file_found) {
1086                                                handler->output(method, handler, file, conn_fp, query);
1087                                        } else {
1088                                                send_error(404, "Not Found", (char *)0, "File not found.");
1089                                        }
1090                                        break;
1091                                        memdebug_leave_info("output");
1092                                }
1093                        }
1094
1095                        if (!handler->pattern)
1096                                send_error(404, "Not Found", (char *)0, "File not found.");
1097                }
1098        }
1099}
1100
1101void                            // add by honor 2003-04-16
1102get_client_ip_mac(int conn_fp)
1103{
1104        struct sockaddr_in sa;
1105        unsigned int len = sizeof(struct sockaddr_in);
1106        char *m;
1107
1108        getpeername(conn_fp, (struct sockaddr *)&sa, &len);
1109        char client[32];
1110        char *peer = (char *)inet_ntop(AF_INET, &sa.sin_addr, client, 16);
1111
1112        nvram_set("http_client_ip", peer);
1113        m = get_mac_from_ip(peer);
1114        nvram_set("http_client_mac", m);
1115#ifdef HAVE_IAS
1116        sprintf(ias_http_client_mac, "%s\0", m);
1117#endif
1118}
1119
1120static void handle_server_sig_int(int sig)
1121{
1122#ifdef HAVE_HTTPS
1123        ct_syslog(LOG_INFO, httpd_level, "httpd server %sshutdown", do_ssl ? "(ssl support) " : "");
1124#else
1125        ct_syslog(LOG_INFO, httpd_level, "httpd server shutdown");
1126#endif
1127        exit(0);
1128}
1129
1130void settimeouts(int sock, int secs)
1131{
1132        struct timeval tv;
1133
1134        tv.tv_sec = secs;
1135        tv.tv_usec = 0;
1136        if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0)
1137                perror("setsockopt(SO_SNDTIMEO)");
1138        if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
1139                perror("setsockopt(SO_RCVTIMEO)");
1140}
1141
1142static void sigchld(int sig)
1143{
1144        while (waitpid(-1, NULL, WNOHANG) > 0) ;
1145}
1146
1147static void set_sigchld_handler(void)
1148{
1149        struct sigaction act;
1150
1151        memset(&act, 0, sizeof(act));
1152        act.sa_handler = sigchld;
1153        sigaction(SIGCHLD, &act, 0);
1154}
1155
1156#ifdef HAVE_OPENSSL
1157#define SSLBUFFERSIZE 16384
1158struct sslbuffer {
1159        unsigned char *sslbuffer;
1160        unsigned int count;
1161        SSL *ssl;
1162};
1163
1164static struct sslbuffer *initsslbuffer(SSL * ssl)
1165{
1166        struct sslbuffer *buffer;
1167        buffer = malloc(sizeof(struct sslbuffer));
1168        buffer->ssl = ssl;
1169        buffer->count = 0;
1170        buffer->sslbuffer = malloc(SSLBUFFERSIZE);
1171        return buffer;
1172}
1173
1174static void sslbufferflush(struct sslbuffer *buffer)
1175{
1176        SSL_write(buffer->ssl, buffer->sslbuffer, buffer->count);
1177        buffer->count = 0;
1178}
1179
1180static void sslbufferfree(struct sslbuffer *buffer)
1181{
1182        free(buffer->sslbuffer);
1183        int sockfd = SSL_get_fd(ssl);
1184        SSL_shutdown(buffer->ssl);
1185        close(sockfd);
1186        SSL_free(buffer->ssl);
1187        free(buffer);
1188}
1189
1190static int sslbufferread(struct sslbuffer *buffer, char *data, int datalen)
1191{
1192        return SSL_read(buffer->ssl, data, datalen);
1193}
1194
1195static int sslbufferpeek(struct sslbuffer *buffer, char *data, int datalen)
1196{
1197        return SSL_peek(buffer->ssl, data, datalen);
1198}
1199
1200static int sslbufferwrite(struct sslbuffer *buffer, char *data, int datalen)
1201{
1202
1203        int targetsize = SSLBUFFERSIZE - buffer->count;
1204        while (datalen >= targetsize) {
1205                memcpy(&buffer->sslbuffer[buffer->count], data, targetsize);
1206                datalen -= targetsize;
1207                data += targetsize;
1208                SSL_write(buffer->ssl, buffer->sslbuffer, SSLBUFFERSIZE);
1209                buffer->count = 0;
1210                targetsize = SSLBUFFERSIZE;
1211        }
1212        if (datalen) {
1213                memcpy(&buffer->sslbuffer[buffer->count], data, datalen);
1214                buffer->count += datalen;
1215        }
1216        return datalen;
1217}
1218
1219#endif
1220
1221int main(int argc, char **argv)
1222{
1223        usockaddr usa;
1224        int listen_fd;
1225        int conn_fd;
1226        socklen_t sz = sizeof(usa);
1227        int c;
1228        int timeout = TIMEOUT;
1229        struct stat stat_dir;
1230
1231        set_sigchld_handler();
1232        nvram_seti("gozila_action", 0);
1233
1234/* SEG addition */
1235        Initnvramtab();
1236#ifdef HAVE_OPENSSL
1237        SSL_CTX *ctx = NULL;
1238        int r;
1239#endif
1240#ifdef HAVE_POLARSSL
1241        int ret, len;
1242        x509_crt srvcert;
1243        pk_context rsa;
1244        entropy_context entropy;
1245        ctr_drbg_context ctr_drbg;
1246        const char *pers = "ssl_server";
1247#endif
1248
1249        strcpy(pid_file, "/var/run/httpd.pid");
1250        server_port = DEFAULT_HTTP_PORT;
1251
1252        while ((c = getopt(argc, argv, "Sih:p:d:t:s:g:e:")) != -1)
1253                switch (c) {
1254#ifdef HAVE_HTTPS
1255                case 'S':
1256#if defined(HAVE_OPENSSL) || defined(HAVE_MATRIXSSL) || defined(HAVE_POLARSSL)
1257                        do_ssl = 1;
1258                        server_port = DEFAULT_HTTPS_PORT;
1259                        strcpy(pid_file, "/var/run/httpsd.pid");
1260#else
1261                        fprintf(stderr, "No SSL support available\n");
1262                        exit(0);
1263#endif
1264                        break;
1265#endif
1266                case 'h':
1267                        server_dir = optarg;
1268                        break;
1269                case 'p':
1270                        server_port = atoi(optarg);
1271                        break;
1272                case 't':
1273                        timeout = atoi(optarg);
1274                        break;
1275#ifdef DEBUG_CIPHER
1276                case 's':
1277                        set_ciphers = optarg;
1278                        break;
1279                case 'g':
1280                        get_ciphers = 1;
1281                        break;
1282#endif
1283                case 'i':
1284                        fprintf(stderr, "Usage: %s [-S] [-p port]\n"
1285#ifdef HAVE_HTTPS
1286                                "       -S : Support https (port 443)\n"
1287#endif
1288                                "       -p port : Which port to listen?\n" "    -t secs : How many seconds to wait before timing out?\n"
1289#ifdef DEBUG_CIPHER
1290                                "       -s ciphers: set cipher lists\n" "       -g: get cipher lists\n"
1291#endif
1292                                "       -h: home directory: use directory\n", argv[0]);
1293                        exit(0);
1294                        break;
1295                default:
1296                        break;
1297                }
1298
1299        httpd_level = ct_openlog("httpd", LOG_PID | LOG_NDELAY, LOG_DAEMON, "LOG_HTTPD");
1300#ifdef HAVE_HTTPS
1301        ct_syslog(LOG_INFO, httpd_level, "httpd server %sstarted at port %d\n", do_ssl ? "(ssl support) " : "", server_port);
1302#else
1303        ct_syslog(LOG_INFO, httpd_level, "httpd server started at port %d\n", server_port);
1304#endif
1305        /* Ignore broken pipes */
1306        signal(SIGPIPE, SIG_IGN);
1307        signal(SIGTERM, handle_server_sig_int); // kill
1308
1309        if (server_dir && stat(server_dir, &stat_dir) == 0)
1310                chdir(server_dir);
1311
1312        /* Build our SSL context */
1313#ifdef HAVE_HTTPS
1314        if (do_ssl) {
1315#ifdef HAVE_OPENSSL
1316                SSLeay_add_ssl_algorithms();
1317                SSL_load_error_strings();
1318                ctx = SSL_CTX_new(SSLv23_server_method());
1319#ifdef HAVE_CUSTOMSSLCERT
1320                if (SSL_CTX_use_certificate_file(ctx, nvram_safe_get("https_cert_file"), SSL_FILETYPE_PEM)
1321#else
1322                if (SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM)
1323#endif
1324                    == 0) {
1325                        cprintf("Can't read %s\n", CERT_FILE);
1326                        ERR_print_errors_fp(stderr);
1327                        exit(1);
1328
1329                }
1330#ifdef HAVE_CUSTOMSSLCERT
1331                if (SSL_CTX_use_PrivateKey_file(ctx, nvram_safe_get("https_key_file"), SSL_FILETYPE_PEM)
1332#else
1333                if (SSL_CTX_use_PrivateKey_file(ctx, KEY_FILE, SSL_FILETYPE_PEM)
1334#endif
1335                    == 0) {
1336                        cprintf("Can't read %s\n", KEY_FILE);
1337                        ERR_print_errors_fp(stderr);
1338                        exit(1);
1339
1340                }
1341                if (SSL_CTX_check_private_key(ctx) == 0) {
1342                        cprintf("Check private key fail\n");
1343                        ERR_print_errors_fp(stderr);
1344                        exit(1);
1345                }
1346#endif
1347#ifdef HAVE_POLARSSL
1348                if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) {
1349                        fprintf(stderr, " failed\n  ! ctr_drbg_init returned %d\n", ret);
1350                }
1351
1352                memset(&ssl, 0, sizeof(ssl));
1353                memset(&srvcert, 0, sizeof(x509_crt));
1354                x509_crt_init(&srvcert);
1355                ret = x509_crt_parse_file(&srvcert, CERT_FILE);
1356                if (ret != 0) {
1357                        printf("x509_read_crtfile failed\n");
1358                        exit(0);
1359                }
1360                ret = pk_parse_keyfile(&rsa, KEY_FILE, NULL);
1361                if (ret != 0) {
1362                        printf("x509_read_keyfile failed\n");
1363                        exit(0);
1364                }
1365#endif
1366
1367#ifdef HAVE_MATRIXSSL
1368                matrixssl_init();
1369#ifdef HAVE_CUSTOMSSLCERT
1370                if (f_exists(nvram_safe_get("https_cert_file")) && f_exists(nvram_safe_get("https_key_file"))) {
1371                        if (0 != matrixSslReadKeys(&keys, nvram_safe_get("https_cert_file"), nvram_safe_get("https_key_file"), NULL, NULL)) {
1372                                fprintf(stderr, "Error reading or parsing %s / %s.\n", nvram_safe_get("https_cert_file"), nvram_safe_get("https_key_file"));
1373                        }
1374                } else
1375#endif
1376                {
1377                        if (0 != matrixSslReadKeys(&keys, CERT_FILE, KEY_FILE, NULL, NULL)) {
1378                                fprintf(stderr, "Error reading or parsing %s.\n", KEY_FILE);
1379                                exit(0);
1380                        }
1381                }
1382#endif
1383        }
1384#endif
1385
1386        /* Initialize listen socket */
1387        if ((listen_fd = initialize_listen_socket(&usa)) < 0) {
1388                ct_syslog(LOG_ERR, httpd_level, "Can't bind to any address");
1389                exit(errno);
1390        }
1391#if !defined(DEBUG)
1392        {
1393                FILE *pid_fp;
1394
1395                /* Daemonize and log PID */
1396                if (daemon(1, 1) == -1) {
1397                        perror("daemon");
1398                        exit(errno);
1399                }
1400                if (!(pid_fp = fopen(pid_file, "w"))) {
1401                        perror(pid_file);
1402                        return errno;
1403                }
1404                fprintf(pid_fp, "%d", getpid());
1405                fclose(pid_fp);
1406        }
1407#endif
1408
1409        /* Loop forever handling requests */
1410        for (;;) {
1411                if ((conn_fd = accept(listen_fd, &usa.sa, &sz)) < 0) {
1412                        perror("accept");
1413                        return errno;
1414                }
1415
1416                /* Make sure we don't linger a long time if the other end disappears */
1417                settimeouts(conn_fd, timeout);
1418                fcntl(conn_fd, F_SETFD, fcntl(conn_fd, F_GETFD) | FD_CLOEXEC);
1419
1420                if (check_action() == ACT_TFTP_UPGRADE ||       // We don't want user to use web during tftp upgrade.
1421                    check_action() == ACT_SW_RESTORE || check_action() == ACT_HW_RESTORE) {
1422                        fprintf(stderr, "http(s)d: nothing to do...\n");
1423                        return -1;
1424                }
1425#ifdef HAVE_HTTPS
1426                if (do_ssl) {
1427                        if (check_action() == ACT_WEB_UPGRADE) {        // We don't want user to use web (https) during web (http) upgrade.
1428                                fprintf(stderr, "httpsd: nothing to do...\n");
1429                                return -1;
1430                        }
1431#ifdef HAVE_OPENSSL
1432                        const char *allowedCiphers =
1433                            "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
1434                        ssl = SSL_new(ctx);
1435
1436#ifdef NID_X9_62_prime256v1
1437                        EC_KEY *ecdh = NULL;
1438                        if (ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) {
1439                                SSL_CTX_set_tmp_ecdh(ctx, ecdh);
1440                                EC_KEY_free(ecdh);
1441                        }
1442#endif
1443
1444                        // Setup available ciphers
1445                        SSL_CTX_set_cipher_list(ctx, allowedCiphers);
1446
1447                        // Enforce our desired cipher order, disable obsolete protocols
1448                        SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SAFARI_ECDHE_ECDSA_BUG);
1449
1450                        SSL_set_fd(ssl, conn_fd);
1451                        r = SSL_accept(ssl);
1452                        if (r <= 0) {
1453                                //berr_exit("SSL accept error");
1454//                              ERR_print_errors_fp(stderr);
1455//                              fprintf(stderr,"ssl accept return %d, ssl error %d %d\n",r,SSL_get_error(ssl,r),RAND_status());
1456                                ct_syslog(LOG_ERR, httpd_level, "SSL accept error");
1457                                close(conn_fd);
1458                                SSL_free(ssl);
1459                                continue;
1460                        }
1461
1462                        if (!conn_fp)
1463                                conn_fp = safe_malloc(sizeof(webs));
1464
1465                        conn_fp->fp = (FILE *) initsslbuffer(ssl);
1466
1467#elif defined(HAVE_MATRIXSSL)
1468                        matrixssl_new_session(conn_fd);
1469                        if (!conn_fp)
1470                                conn_fp = safe_malloc(sizeof(webs));
1471                        conn_fp->fp = (FILE *) conn_fd;
1472#endif
1473#ifdef HAVE_POLARSSL
1474                        ssl_free(&ssl);
1475                        if ((ret = ssl_init(&ssl)) != 0) {
1476                                printf("ssl_init failed\n");
1477                                close(conn_fd);
1478                                continue;
1479                        }
1480                        ssl_set_endpoint(&ssl, SSL_IS_SERVER);
1481                        ssl_set_authmode(&ssl, SSL_VERIFY_NONE);
1482                        ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
1483                        ssl_set_ca_chain(&ssl, srvcert.next, NULL, NULL);
1484
1485                        ssl_set_bio(&ssl, net_recv, &conn_fd, net_send, &conn_fd);
1486                        ssl_set_ciphersuites(&ssl, my_ciphers);
1487                        ssl_set_own_cert(&ssl, &srvcert, &rsa);
1488
1489                        //              ssl_set_sidtable(&ssl, session_table);
1490                        ssl_set_dh_param(&ssl, dhm_P, dhm_G);
1491
1492                        ret = ssl_handshake(&ssl);
1493                        if (ret != 0) {
1494                                printf("ssl_server_start failed\n");
1495                                close(conn_fd);
1496                                continue;
1497                        }
1498                        if (!conn_fp)
1499                                conn_fp = safe_malloc(sizeof(webs));
1500                        conn_fp->fp = (webs_t)(&ssl);
1501#endif
1502                } else
1503#endif
1504                {
1505#ifdef HAVE_HTTPS
1506                        if (check_action() == ACT_WEBS_UPGRADE) {       // We don't want user to use web (http) during web (https) upgrade.
1507                                fprintf(stderr, "httpd: nothing to do...\n");
1508                                return -1;
1509                        }
1510#endif
1511                        if (!conn_fp)
1512                                conn_fp = safe_malloc(sizeof(webs));
1513                        if (!(conn_fp->fp = fdopen(conn_fd, "r+"))) {
1514                                perror("fdopen");
1515                                return errno;
1516                        }
1517                }
1518                {
1519                        memdebug_enter();
1520                        get_client_ip_mac(conn_fd);
1521                        memdebug_leave_info("get_client_ip_mac");
1522                }
1523                {
1524                        memdebug_enter();
1525
1526                        handle_request();
1527
1528                        memdebug_leave_info("handle_request");
1529                }
1530                wfclose(conn_fp);       // jimmy, https, 8/4/2003
1531                free(conn_fp);
1532                conn_fp = NULL;
1533                close(conn_fd);
1534
1535                showmemdebugstat();
1536        }
1537
1538        shutdown(listen_fd, 2);
1539        close(listen_fd);
1540
1541        return 0;
1542}
1543
1544char *wfgets(char *buf, int len, webs_t wp)
1545{
1546        FILE *fp = wp->fp;
1547#ifdef HAVE_HTTPS
1548#ifdef HAVE_OPENSSL
1549        if (do_ssl) {
1550                int eof = 1;
1551                int i;
1552                char c;
1553                if (sslbufferpeek((struct sslbuffer *)fp, buf, len) <= 0)
1554                        return NULL;
1555                for (i = 0; i < len; i++) {
1556                        c = buf[i];
1557                        if (c == '\n' || c == 0) {
1558                                eof = 0;
1559                                break;
1560                        }
1561                }
1562                if (sslbufferread((struct sslbuffer *)fp, buf, i + 1) <= 0)
1563                        return NULL;
1564                if (!eof) {
1565                        buf[i + 1] = 0;
1566                        return buf;
1567                } else
1568                        return NULL;
1569
1570        } else
1571#elif defined(HAVE_MATRIXSSL)
1572        if (do_ssl)
1573                return (char *)matrixssl_gets(fp, buf, len);
1574        else
1575#elif defined(HAVE_POLARSSL)
1576
1577        fprintf(stderr, "ssl read %d\n", len);
1578        if (do_ssl) {
1579                int ret = ssl_read((ssl_context *) fp, (unsigned char *)buf, len);
1580                fprintf(stderr, "returns %d\n", ret);
1581                return (char *)buf;
1582        } else
1583#endif
1584#endif
1585                return fgets(buf, len, fp);
1586}
1587
1588int wfputs(char *buf, webs_t wp)
1589{
1590        FILE *fp = wp->fp;
1591#ifdef HAVE_HTTPS
1592        if (do_ssl)
1593#ifdef HAVE_OPENSSL
1594        {
1595
1596                return sslbufferwrite((struct sslbuffer *)fp, buf, strlen(buf));
1597        }
1598#elif defined(HAVE_MATRIXSSL)
1599                return matrixssl_puts(fp, buf);
1600#elif defined(HAVE_POLARSSL)
1601        {
1602                fprintf(stderr, "ssl write str %d\n", strlen(buf));
1603                return ssl_write((ssl_context *) fp, (unsigned char *)buf, strlen(buf));
1604        }
1605#endif
1606        else
1607#endif
1608                return fputs(buf, fp);
1609}
1610
1611int wfprintf(webs_t wp, char *fmt, ...)
1612{
1613        FILE *fp = wp->fp;
1614        va_list args;
1615        char *buf;
1616        int ret;
1617
1618        va_start(args, fmt);
1619        vasprintf(&buf, fmt, args);
1620#ifdef HAVE_HTTPS
1621        if (do_ssl)
1622#ifdef HAVE_OPENSSL
1623        {
1624                ret = sslbufferwrite((struct sslbuffer *)fp, buf, strlen(buf));
1625        }
1626#elif defined(HAVE_MATRIXSSL)
1627                ret = matrixssl_printf(fp, "%s", buf);
1628#elif defined(HAVE_POLARSSL)
1629        {
1630                fprintf(stderr, "ssl write buf %d\n", strlen(buf));
1631                ret = ssl_write((ssl_context *) fp, buf, strlen(buf));
1632        }
1633#endif
1634        else
1635#endif
1636                ret = fprintf(fp, "%s", buf);
1637        free(buf);
1638        va_end(args);
1639        return ret;
1640}
1641
1642int websWrite(webs_t wp, char *fmt, ...)
1643{
1644        va_list args;
1645        char *buf;
1646        int ret;
1647        if (!wp || !fmt)
1648                return -1;
1649        FILE *fp = wp->fp;
1650
1651        va_start(args, fmt);
1652        vasprintf(&buf, fmt, args);
1653#ifdef HAVE_HTTPS
1654        if (do_ssl)
1655#ifdef HAVE_OPENSSL
1656        {
1657                ret = sslbufferwrite((struct sslbuffer *)fp, buf, strlen(buf));
1658        }
1659#elif defined(HAVE_MATRIXSSL)
1660                ret = matrixssl_printf(fp, "%s", buf);
1661#elif defined(HAVE_POLARSSL)
1662        {
1663                fprintf(stderr, "ssl write buf %d\n", strlen(buf));
1664                ret = ssl_write((ssl_context *) fp, buf, strlen(buf));
1665        }
1666#endif
1667        else
1668#endif
1669                ret = fprintf(fp, "%s", buf);
1670        free(buf);
1671        va_end(args);
1672        return ret;
1673}
1674
1675size_t wfwrite(char *buf, int size, int n, webs_t wp)
1676{
1677        FILE *fp = wp->fp;
1678#ifdef HAVE_HTTPS
1679        if (do_ssl)
1680#ifdef HAVE_OPENSSL
1681        {
1682                return sslbufferwrite((struct sslbuffer *)fp, buf, n * size);
1683        }
1684#elif defined(HAVE_MATRIXSSL)
1685                return matrixssl_write(fp, (unsigned char *)buf, n * size);
1686#elif defined(HAVE_POLARSSL)
1687        {
1688                fprintf(stderr, "ssl write buf %d\n", n * size);
1689                return ssl_write((ssl_context *) fp, (unsigned char *)buf, n * size);
1690        }
1691#endif
1692        else
1693#endif
1694                return fwrite(buf, size, n, fp);
1695}
1696
1697size_t wfread(char *buf, int size, int n, webs_t wp)
1698{
1699        FILE *fp = wp->fp;
1700
1701#ifdef HAVE_HTTPS
1702        if (do_ssl) {
1703#ifdef HAVE_OPENSSL
1704                return sslbufferread((struct sslbuffer *)fp, buf, n * size);
1705#elif defined(HAVE_MATRIXSSL)
1706                //do it in chains
1707                int cnt = (size * n) / 0x4000;
1708                int i;
1709                int len = 0;
1710
1711                for (i = 0; i < cnt; i++) {
1712                        len += matrixssl_read(fp, buf, 0x4000);
1713                        *buf += 0x4000;
1714                }
1715                len += matrixssl_read(fp, buf, (size * n) % 0x4000);
1716
1717                return len;
1718#elif defined(HAVE_POLARSSL)
1719                int len = n * size;
1720                fprintf(stderr, "read ssl %d\n", len);
1721                return ssl_read((ssl_context *) fp, (unsigned char *)buf, &len);
1722#endif
1723        } else
1724#endif
1725                return fread(buf, size, n, fp);
1726}
1727
1728int wfflush(webs_t wp)
1729{
1730        FILE *fp = wp->fp;
1731
1732#ifdef HAVE_HTTPS
1733        if (do_ssl) {
1734#ifdef HAVE_OPENSSL
1735                /* ssl_write doesn't buffer */
1736                sslbufferflush((struct sslbuffer *)fp);
1737                return 1;
1738#elif defined(HAVE_MATRIXSSL)
1739                return matrixssl_flush(fp);
1740#elif defined(HAVE_POLARSSL)
1741                ssl_flush_output((ssl_context *) fp);
1742                return 1;
1743#endif
1744        } else
1745#endif
1746                return fflush(fp);
1747}
1748
1749int wfclose(webs_t wp)
1750{
1751        FILE *fp = wp->fp;
1752
1753#ifdef HAVE_HTTPS
1754        if (do_ssl) {
1755#ifdef HAVE_OPENSSL
1756                sslbufferflush((struct sslbuffer *)fp);
1757                sslbufferfree((struct sslbuffer *)fp);
1758                return 1;
1759#elif defined(HAVE_MATRIXSSL)
1760                return matrixssl_free_session(fp);
1761#elif defined(HAVE_POLARSSL)
1762                ssl_close_notify((ssl_context *) fp);
1763                ssl_free((ssl_context *) fp);
1764                return 1;
1765#endif
1766        } else
1767#endif
1768        {
1769                int ret = fclose(fp);
1770                wp->fp = NULL;
1771                return ret;
1772        }
1773}
1774
1775#ifdef HAVE_IAS
1776void ias_sid_set()
1777{
1778
1779        struct sysinfo sinfo;
1780
1781        sysinfo(&sinfo);
1782        if (strlen(ias_http_client_mac)) {
1783                ias_sid_timeout = sinfo.uptime + 300;
1784                sprintf(ias_sid, "%s", ias_http_client_mac);
1785                fprintf(stderr, "[IAS SID SET] %d %s\n", ias_sid_timeout, ias_sid);
1786        }
1787        return;
1788}
1789
1790int ias_sid_valid()
1791{
1792
1793        struct sysinfo sinfo;
1794        char *mac;
1795
1796        if (!ias_sid_timeout && (!ias_sid || !strcmp(ias_sid, "")))
1797                return 0;
1798
1799        sysinfo(&sinfo);
1800        mac = ias_http_client_mac;
1801        if (sinfo.uptime > ias_sid_timeout || (strcmp(mac, ias_sid) && strlen(mac))) {
1802                fprintf(stderr, "[IAS SID RESET] %d<>%d %s<>%s\n", sinfo.uptime, ias_sid_timeout, mac, ias_sid);
1803                ias_sid_timeout = 0;
1804                sprintf(ias_sid, "");
1805                return 0;
1806        } else
1807                ias_sid_timeout = sinfo.uptime + 300;
1808        return 1;
1809}
1810#endif
Note: See TracBrowser for help on using the repository browser.