1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of
5 * the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
15 * MA 02111-1307 USA
16 */
17/* milli_httpd - pretty small HTTP server
18** A combination of
19** micro_httpd - really small HTTP server
20** and
21** mini_httpd - small HTTP server
22**
23** Copyright ?1999,2000 by Jef Poskanzer <jef@acme.com>.
24** All rights reserved.
25**
26** Redistribution and use in source and binary forms, with or without
27** modification, are permitted provided that the following conditions
28** are met:
29** 1. Redistributions of source code must retain the above copyright
30**    notice, this list of conditions and the following disclaimer.
31** 2. Redistributions in binary form must reproduce the above copyright
32**    notice, this list of conditions and the following disclaimer in the
33**    documentation and/or other materials provided with the distribution.
34**
35** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
36** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
39** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45** SUCH DAMAGE.
46*/
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <time.h>
54#include <unistd.h>
55#include <netinet/in.h>
56#include <sys/types.h>
57#include <sys/socket.h>
58#include <sys/time.h>
59//#include <sys/stat.h>
60#include <assert.h>
61#include <sys/ioctl.h>
62#include <ctype.h>
63
64typedef unsigned int __u32;   // 1225 ham
65
66#include <httpd.h>
67//2008.08 magic{
68#include <bcmnvram.h>	//2008.08 magic
69#include <arpa/inet.h>	//2008.08 magic
70
71#include <error.h>
72#include <sys/signal.h>
73#include <sys/wait.h>
74#include <shared.h>
75#include <shutils.h>
76
77#define ETCPHYRD	14
78#define SIOCGETCPHYRD   0x89FE
79//#include "etioctl.h"
80
81#ifdef RTCONFIG_HTTPS
82#include <syslog.h>
83#include <mssl.h>
84#include <shutils.h>
85#define SERVER_PORT_SSL	443
86#endif
87#include "bcmnvram_f.h"
88
89/* A multi-family sockaddr. */
90typedef union {
91    struct sockaddr sa;
92    struct sockaddr_in sa_in;
93} usockaddr;
94
95#include "queue.h"
96#define MAX_CONN_ACCEPT 64
97#define MAX_CONN_TIMEOUT 60
98
99#ifdef RTCONFIG_IFTTT
100#define IFTTTUSERAGENT	"asusrouter-Windows-IFTTT-1.0"
101#define GETIFTTTCGI	"get_IFTTTPincode.cgi"
102#endif
103
104typedef struct conn_item {
105	TAILQ_ENTRY(conn_item) entry;
106	int fd;
107	usockaddr usa;
108} conn_item_t;
109
110typedef struct conn_list {
111	TAILQ_HEAD(, conn_item) head;
112	int count;
113} conn_list_t;
114
115/* Globals. */
116static FILE *conn_fp;
117static char auth_userid[AUTH_MAX];
118static char auth_passwd[AUTH_MAX];
119static char auth_realm[AUTH_MAX];
120char host_name[64];
121char referer_host[64];
122char user_agent[1024];
123char gen_token[32]={0};
124
125#ifdef TRANSLATE_ON_FLY
126char Accept_Language[16];
127
128struct language_table language_tables[] = {
129	{"br", "BR"},
130	{"pt-BR", "BR"},
131	{"zh-cn", "CN"},
132	{"zh-Hans-CN", "CN"},
133	{"cs", "CZ"},
134	{"cs-cz", "CZ"},
135	{"da", "DA"},
136	{"da-DK", "DA"},
137	{"de", "DE"},
138	{"de-at", "DE"},
139	{"de-ch", "DE"},
140	{"de-de", "DE"},
141	{"de-li", "DE"},
142	{"de-lu", "DE"},
143	{"en", "EN"},
144	{"en-us", "EN"},
145	{"es", "ES"},
146	{"es-ec", "ES"},
147	{"es-py", "ES"},
148	{"es-pa", "ES"},
149	{"es-ni", "ES"},
150	{"es-gt", "ES"},
151	{"es-do", "ES"},
152	{"es-es", "ES"},
153	{"es-hn", "ES"},
154	{"es-ve", "ES"},
155	{"es-pr", "ES"},
156	{"es-ar", "ES"},
157	{"es-bo", "ES"},
158	{"es-us", "ES"},
159	{"es-co", "ES"},
160	{"es-cr", "ES"},
161	{"es-uy", "ES"},
162	{"es-pe", "ES"},
163	{"es-cl", "ES"},
164	{"es-mx", "ES"},
165	{"es-sv", "ES"},
166	{"fi", "FI"},
167	{"fi-FI", "FI"},
168	{"fr", "FR"},
169	{"fr-fr", "FR"},
170	{"fr-BE", "FR"},
171	{"fr-CA", "FR"},
172	{"fr-CH", "FR"},
173	{"fr-MC", "FR"},
174	{"fr-LU", "FR"},
175	{"hu-hu", "HU"},
176	{"hu", "HU"},
177	{"it", "IT"},
178	{"it-it", "IT"},
179	{"it-ch", "IT"},
180	{"ja", "JP"},
181	{"ja-JP", "JP"},
182	{"ko", "KR"},
183	{"ko-kr", "KR"},
184	{"ms", "MS"},
185	{"ms-MY", "MS"},
186	{"ms-BN", "MS"},
187	{"no", "NO"},
188	{"nb", "NO"},
189	{"nn", "NO"},
190	{"nb-NO", "NO"},
191	{"nn-NO", "NO"},
192	{"pl-pl", "PL"},
193	{"pl", "PL"},
194	{"ru", "RU"},
195	{"ru-ru", "RU"},
196	{"ro", "RO"},
197	{"ro-ro", "RO"},
198	{"sv", "SV"},
199	{"sv-FI", "SV"},
200	{"sv-SE", "SV"},
201	{"th", "TH"},
202	{"th-TH", "TH"},
203	{"th-TH-TH", "TH"},
204	{"tr", "TR"},
205	{"tr-TR", "TR"},
206	{"zh", "TW"},
207	{"zh-tw", "TW"},
208	{"zh-Hant-TW", "TW"},
209	{"zh-hk", "TW"},
210	{"uk", "UK"},
211	{NULL, NULL}
212};
213
214#endif //TRANSLATE_ON_FLY
215
216/* Forwards. */
217static int initialize_listen_socket(usockaddr* usa, const char *ifname);
218static int auth_check( char* dirname, char* authorization, char* url, char* cookies, int fromapp_flag);
219static int referer_check(char* referer, int fromapp_flag);
220char *generate_token(void);
221static void send_error( int status, char* title, char* extra_header, char* text );
222//#ifdef RTCONFIG_CLOUDSYNC
223static void send_page( int status, char* title, char* extra_header, char* text , int fromapp);
224//#endif
225static void send_headers( int status, char* title, char* extra_header, char* mime_type, int fromapp);
226static void send_token_headers( int status, char* title, char* extra_header, char* mime_type, int fromapp);
227static int match( const char* pattern, const char* string );
228static int match_one( const char* pattern, int patternlen, const char* string );
229static void handle_request(void);
230void send_login_page(int fromapp_flag, int error_status, char* url, int lock_time);
231void __send_login_page(int fromapp_flag, int error_status, char* url, int lock_time);
232int check_user_agent(char* user_agent);
233#ifdef RTCONFIG_IFTTT
234void add_ifttt_flag(void);
235#endif
236
237/* added by Joey */
238//2008.08 magic{
239//int redirect = 1;
240int redirect = 0;
241int change_passwd = 0;
242int reget_passwd = 0;
243int x_Setting = 0;
244int skip_auth = 0;
245char url[128];
246int http_port = SERVER_PORT;
247char *http_ifname = NULL;
248
249/* Added by Joey for handle one people at the same time */
250unsigned int login_ip=0; // the logined ip
251time_t login_timestamp=0; // the timestamp of the logined ip
252time_t login_timestamp_tmp=0; // the timestamp of the current session.
253time_t last_login_timestamp=0; // the timestamp of the current session.
254unsigned int login_ip_tmp=0; // the ip of the current session.
255unsigned int login_try=0;
256unsigned int last_login_ip = 0;	// the last logined ip 2008.08 magic
257/* limit login IP addr; 2012.03 Yau */
258struct {
259	struct in_addr ip;
260	struct in_addr netmask;
261} access_ip[4];
262unsigned int MAX_login;
263int lock_flag = 0;
264
265// 2008.08 magic {
266time_t request_timestamp = 0;
267time_t turn_off_auth_timestamp = 0;
268int temp_turn_off_auth = 0;	// for QISxxx.htm pages
269
270/* Const vars */
271const int int_1 = 1;
272
273void http_login(unsigned int ip, char *url);
274void http_login_timeout(unsigned int ip, char *cookies, int fromapp_flag);
275void http_logout(unsigned int ip, char *cookies, int fromapp_flag);
276int http_login_check(void);
277asus_token_t* search_token_in_list(char* token, asus_token_t **prev);
278
279#if 0
280static int check_if_inviteCode(const char *dirpath){
281	return 1;
282}
283#endif
284void sethost(char *host)
285{
286	char *cp;
287
288	if(!host) return;
289
290	memset(host_name, 0, sizeof(host_name));
291	strncpy(host_name, host, sizeof(host_name)-1);
292
293	cp = host_name;
294	for ( cp = cp + 7; *cp && *cp != '\r' && *cp != '\n'; cp++ );
295	*cp = '\0';
296}
297
298char *gethost(void)
299{
300	if(strlen(host_name)) {
301		return host_name;
302	}
303	else return(nvram_safe_get("lan_ipaddr"));
304}
305
306#include <sys/sysinfo.h>
307long uptime(void)
308{
309	struct sysinfo info;
310	sysinfo(&info);
311
312	return info.uptime;
313}
314
315static int
316initialize_listen_socket(usockaddr* usa, const char *ifname)
317{
318	struct ifreq ifr;
319	int fd;
320
321	memset(usa, 0, sizeof(usockaddr));
322	usa->sa.sa_family = AF_INET;
323	usa->sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
324	usa->sa_in.sin_port = htons(http_port);
325
326	fd = socket(usa->sa.sa_family, SOCK_STREAM, 0);
327	if (fd < 0) {
328		perror("socket");
329		return -1;
330	}
331
332	if (ifname) {
333		memset(&ifr, 0, sizeof(ifr));
334		strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
335		if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
336			perror("ioctl");
337			goto error;
338		}
339		usa->sa_in.sin_addr.s_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr;
340	}
341
342	fcntl(fd, F_SETFD, FD_CLOEXEC);
343	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &int_1, sizeof(int_1)) < 0) {
344		perror("setsockopt");
345		goto error;
346	}
347	if (bind(fd, &usa->sa, sizeof(struct sockaddr_in)) < 0) {
348		perror("bind");
349		goto error;
350	}
351	if (listen(fd, 1024) < 0) {
352		perror( "listen" );
353		goto error;
354	}
355
356	return fd;
357
358error:
359	close(fd);
360	return -1;
361}
362
363void
364send_login_page(int fromapp_flag, int error_status, char* url, int lock_time)
365{
366	char inviteCode[256]={0};
367	char url_tmp[64]={0};
368
369	if(url == NULL)
370		strncpy(url_tmp, "index.asp", sizeof(url_tmp));
371	else
372		strncpy(url_tmp, url, sizeof(url_tmp));
373
374	if(fromapp_flag == 0){
375		snprintf(inviteCode, sizeof(inviteCode), "<script>top.location.href='/Main_Login.asp?error_status=%d&page=%s&lock_time=%d';</script>",error_status, url_tmp, lock_time);
376	}else{
377		snprintf(inviteCode, sizeof(inviteCode), "\"error_status\":\"%d\"", error_status);
378	}
379	send_page( 200, "OK", (char*) 0, inviteCode, fromapp_flag);
380}
381
382void
383__send_login_page(int fromapp_flag, int error_status, char* url, int lock_time)
384{
385	login_try++;
386	last_login_timestamp = login_timestamp_tmp;
387
388	send_login_page(fromapp_flag, error_status, url, lock_time);
389}
390
391static int
392referer_check(char* referer, int fromapp_flag)
393{
394
395	char *auth_referer=NULL;
396	char *cp1=NULL, *cp2=NULL, *location_cp1=NULL;
397
398	if(fromapp_flag != 0)
399		return 0;
400	if(!referer){
401		send_login_page(fromapp_flag, NOREFERER, NULL, 0);
402		return NOREFERER;
403	}else{
404		location_cp1 = strstr(referer,"//");
405		if(location_cp1 != (char*) 0){
406			cp1 = &location_cp1[2];
407			if(strstr(cp1,"/") != (char*) 0){
408				cp2 = strtok(cp1, "/");
409				auth_referer = cp2;
410			}else
411				auth_referer = cp1;
412		}else
413			auth_referer = referer;
414
415	}
416	if(referer_host[0] == 0){
417		send_login_page(fromapp_flag, WEB_NOREFERER, NULL, 0);
418		return WEB_NOREFERER;
419	}
420	if(strncmp(DUT_DOMAIN_NAME, auth_referer, strlen(DUT_DOMAIN_NAME))==0){
421			strcpy(auth_referer, nvram_safe_get("lan_ipaddr"));
422	}
423	/* form based referer info? */
424	if(strncmp( auth_referer, referer_host, strlen(referer_host) ) == 0){
425		//_dprintf("asus token referer_check: the right user and password\n");
426		return 0;
427	}else{
428		//_dprintf("asus token referer_check: the wrong user and password\n");
429		send_login_page(fromapp_flag, REFERERFAIL, NULL, 0);
430		return REFERERFAIL;
431	}
432	send_login_page(fromapp_flag, REFERERFAIL, NULL, 0);
433	return REFERERFAIL;
434}
435
436#define	HEAD_HTTP_LOGIN	"HTTP login"	// copy from push_log/push_log.h
437
438static int
439auth_check( char* dirname, char* authorization ,char* url, char* cookies, int fromapp_flag)
440{
441	struct in_addr temp_ip_addr;
442	char *temp_ip_str;
443	time_t dt;
444	char asustoken[32];
445	char *cp=NULL, *location_cp;
446
447	memset(asustoken,0,sizeof(asustoken));
448
449	login_timestamp_tmp = uptime();
450	dt = login_timestamp_tmp - last_login_timestamp;
451	if(last_login_timestamp != 0 && dt > 60){
452		login_try = 0;
453		last_login_timestamp = 0;
454		lock_flag = 0;
455	}
456	if (MAX_login <= DEFAULT_LOGIN_MAX_NUM)
457		MAX_login = DEFAULT_LOGIN_MAX_NUM;
458	if(login_try >= MAX_login){
459		lock_flag = 1;
460		temp_ip_addr.s_addr = login_ip_tmp;
461		temp_ip_str = inet_ntoa(temp_ip_addr);
462
463		if(login_try%MAX_login == 0)
464			logmessage(HEAD_HTTP_LOGIN, "Detect abnormal logins at %d times. The newest one was from %s.", login_try, temp_ip_str);
465
466//#ifdef LOGIN_LOCK
467		send_login_page(fromapp_flag, LOGINLOCK, url, dt);
468		return LOGINLOCK;
469//#endif
470	}
471
472	/* Is this directory unprotected? */
473	if ( !strlen(auth_passwd) ){
474		/* Yes, let the request go through. */
475		return 0;
476	}
477
478	if(!cookies){
479		send_login_page(fromapp_flag, NOTOKEN, url, 0);
480		return NOTOKEN;
481	}else{
482		location_cp = strstr(cookies,"asus_token");
483		if(location_cp != NULL){
484			cp = &location_cp[11];
485			cp += strspn( cp, " \t" );
486			snprintf(asustoken, sizeof(asustoken), "%s", cp);
487		}else{
488			send_login_page(fromapp_flag, NOTOKEN, url, 0);
489			return NOTOKEN;
490		}
491	}
492	/* form based authorization info? */
493
494	if(search_token_in_list(asustoken, NULL) != NULL){
495		//_dprintf("asus token auth_check: the right user and password\n");
496#ifdef RTCONFIG_IFTTT
497		if(strncmp(url, GETIFTTTCGI, strlen(GETIFTTTCGI))==0) add_ifttt_flag();
498#endif
499		login_try = 0;
500		last_login_timestamp = 0;
501		lock_flag = 0;
502		return 0;
503	}else{
504		//_dprintf("asus token auth_check: the wrong user and password\n");
505		send_login_page(fromapp_flag, AUTHFAIL, url, 0);
506		return AUTHFAIL;
507	}
508
509	send_login_page(fromapp_flag, AUTHFAIL, url, 0);
510	return AUTHFAIL;
511}
512
513char *generate_token(void){
514
515	int a=0, b=0, c=0, d=0;
516	//char create_token[32]={0};
517
518	memset(gen_token,0,sizeof(gen_token));
519	srand (time(NULL));
520	a=rand();
521	b=rand();
522	c=rand();
523	d=rand();
524	snprintf(gen_token, sizeof(gen_token),"%d%d%d%d", a, b, c, d);
525
526	return gen_token;
527}
528
529static void
530send_error( int status, char* title, char* extra_header, char* text )
531{
532	send_headers( status, title, extra_header, "text/html", 0);
533	(void) fprintf( conn_fp, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, title );
534	(void) fprintf( conn_fp, "%s\n", text );
535	(void) fprintf( conn_fp, "</BODY></HTML>\n" );
536	(void) fflush( conn_fp );
537}
538
539//#ifdef RTCONFIG_CLOUDSYNC
540static void
541send_page( int status, char* title, char* extra_header, char* text , int fromapp){
542    if(fromapp == 0){
543	send_headers( status, title, extra_header, "text/html", fromapp);
544	(void) fprintf( conn_fp, "<HTML><HEAD>");
545	(void) fprintf( conn_fp, "%s\n", text );
546	(void) fprintf( conn_fp, "</HEAD></HTML>\n" );
547    }else{
548	send_headers( status, title, extra_header, "application/json;charset=UTF-8", fromapp );
549	(void) fprintf( conn_fp, "{\n");
550	(void) fprintf( conn_fp, "%s\n", text );
551	(void) fprintf( conn_fp, "}\n" );
552    }
553    (void) fflush( conn_fp );
554}
555//#endif
556
557static void
558send_headers( int status, char* title, char* extra_header, char* mime_type, int fromapp)
559{
560    time_t now;
561    char timebuf[100];
562    (void) fprintf( conn_fp, "%s %d %s\r\n", PROTOCOL, status, title );
563    (void) fprintf( conn_fp, "Server: %s\r\n", SERVER_NAME );
564    if (fromapp != 0){
565	(void) fprintf( conn_fp, "Cache-Control: no-store\r\n");
566	(void) fprintf( conn_fp, "Pragma: no-cache\r\n");
567	if(fromapp == FROM_DUTUtil){
568		(void) fprintf( conn_fp, "AiHOMEAPILevel: %d\r\n", EXTEND_AIHOME_API_LEVEL );
569		(void) fprintf( conn_fp, "Httpd_AiHome_Ver: %d\r\n", EXTEND_HTTPD_AIHOME_VER );
570		(void) fprintf( conn_fp, "Model_Name: %s\r\n", get_productid() );
571	}else if(fromapp == FROM_ASSIA){
572		(void) fprintf( conn_fp, "ASSIA_API_Level: %d\r\n", EXTEND_ASSIA_API_LEVEL );
573	}
574    }
575    now = time( (time_t*) 0 );
576    (void) strftime( timebuf, sizeof(timebuf), RFC1123FMT, gmtime( &now ) );
577    (void) fprintf( conn_fp, "Date: %s\r\n", timebuf );
578    if ( extra_header != (char*) 0 )
579	(void) fprintf( conn_fp, "%s\r\n", extra_header );
580    if ( mime_type != (char*) 0 ){
581	if(fromapp != 0)
582		(void) fprintf( conn_fp, "Content-Type: %s\r\n", "application/json;charset=UTF-8" );
583	else
584		(void) fprintf( conn_fp, "Content-Type: %s\r\n", mime_type );
585    }
586
587    (void) fprintf( conn_fp, "Connection: close\r\n" );
588    (void) fprintf( conn_fp, "\r\n" );
589}
590
591static void
592send_token_headers( int status, char* title, char* extra_header, char* mime_type, int fromapp)
593{
594    time_t now;
595    char timebuf[100];
596    char asus_token[32]={0};
597    memset(asus_token,0,sizeof(asus_token));
598
599    if(nvram_match("x_Setting", "0") && strcmp( gen_token, "") != 0){
600        strncpy(asus_token, gen_token, sizeof(asus_token));
601    }else{
602	strncpy(asus_token, generate_token(), sizeof(asus_token));
603        add_asus_token(asus_token);
604    }
605
606    (void) fprintf( conn_fp, "%s %d %s\r\n", PROTOCOL, status, title );
607    (void) fprintf( conn_fp, "Server: %s\r\n", SERVER_NAME );
608    if(fromapp == FROM_DUTUtil){
609	(void) fprintf( conn_fp, "AiHOMEAPILevel: %d\r\n", EXTEND_AIHOME_API_LEVEL );
610	(void) fprintf( conn_fp, "Httpd_AiHome_Ver: %d\r\n", EXTEND_HTTPD_AIHOME_VER );
611	(void) fprintf( conn_fp, "Model_Name: %s\r\n", get_productid() );
612    }else if(fromapp == FROM_ASSIA){
613	(void) fprintf( conn_fp, "ASSIA_API_Level: %d\r\n", EXTEND_ASSIA_API_LEVEL );
614    }
615    now = time( (time_t*) 0 );
616    (void) strftime( timebuf, sizeof(timebuf), RFC1123FMT, gmtime( &now ) );
617    (void) fprintf( conn_fp, "Date: %s\r\n", timebuf );
618    if ( extra_header != (char*) 0 )
619	(void) fprintf( conn_fp, "%s\r\n", extra_header );
620    if ( mime_type != (char*) 0 )
621	(void) fprintf( conn_fp, "Content-Type: %s\r\n", mime_type );
622
623	(void) fprintf( conn_fp, "Set-Cookie: asus_token=%s; HttpOnly;\r\n",asus_token );
624
625    (void) fprintf( conn_fp, "Connection: close\r\n" );
626    (void) fprintf( conn_fp, "\r\n" );
627}
628
629/* Simple shell-style filename matcher.  Only does ? * and **, and multiple
630** patterns separated by |.  Returns 1 or 0.
631*/
632int
633match( const char* pattern, const char* string )
634    {
635    const char* or;
636
637    for (;;)
638	{
639	or = strchr( pattern, '|' );
640	if ( or == (char*) 0 )
641	    return match_one( pattern, strlen( pattern ), string );
642	if ( match_one( pattern, or - pattern, string ) )
643	    return 1;
644	pattern = or + 1;
645	}
646    }
647
648
649static int
650match_one( const char* pattern, int patternlen, const char* string )
651    {
652    const char* p;
653
654    for ( p = pattern; p - pattern < patternlen; ++p, ++string )
655	{
656	if ( *p == '?' && *string != '\0' )
657	    continue;
658	if ( *p == '*' )
659	    {
660	    int i, pl;
661	    ++p;
662	    if ( *p == '*' )
663		{
664		/* Double-wildcard matches anything. */
665		++p;
666		i = strlen( string );
667		}
668	    else
669		/* Single-wildcard matches anything but slash. */
670		i = strcspn( string, "/" );
671	    pl = patternlen - ( p - pattern );
672	    for ( ; i >= 0; --i )
673		if ( match_one( p, pl, &(string[i]) ) )
674		    return 1;
675	    return 0;
676	    }
677	if ( *p != *string )
678	    return 0;
679	}
680    if ( *string == '\0' )
681	return 1;
682    return 0;
683}
684
685int web_write(const char *buffer, int len, FILE *stream)
686{
687	int n = len;
688	int r = 0;
689
690	while (n > 0) {
691		r = fwrite(buffer, 1, n, stream);
692		if (( r == 0) && (errno != EINTR)) return -1;
693		buffer += r;
694		n -= r;
695	}
696	return r;
697}
698
699int check_user_agent(char* user_agent){
700
701	int fromapp = 0;
702
703	if(user_agent != NULL){
704		char *cp1=NULL, *app_router=NULL, *app_platform=NULL, *app_framework=NULL, *app_verison=NULL;
705		cp1 = strdup(user_agent);
706
707		vstrsep(cp1, "-", &app_router, &app_platform, &app_framework, &app_verison);
708
709		if(app_router != NULL && app_framework != NULL && strcmp( app_router, "asusrouter") == 0){
710				fromapp=FROM_ASUSROUTER;
711			if(strcmp( app_framework, "DUTUtil") == 0)
712				fromapp=FROM_DUTUtil;
713			else if(strcmp( app_framework, "ASSIA") == 0)
714				fromapp=FROM_ASSIA;
715			else if(strcmp( app_framework, "IFTTT") == 0)
716				fromapp=FROM_IFTTT;
717		}
718		if(cp1) free(cp1);
719	}
720	return fromapp;
721}
722
723#ifdef RTCONFIG_IFTTT
724void add_ifttt_flag(void){
725
726	memset(user_agent, 0, sizeof(user_agent));
727	sprintf(user_agent, "%s",IFTTTUSERAGENT);
728	return;
729}
730#endif
731
732#if 0
733void
734do_file(char *path, FILE *stream)
735{
736	FILE *fp;
737	char buf[1024];
738	int nr;
739
740	if (!(fp = fopen(path, "r")))
741		return;
742	while ((nr = fread(buf, 1, sizeof(buf), fp)) > 0) {
743		web_write(buf, nr, stream);
744	}
745	fclose(fp);
746}
747#else
748int do_fwrite(const char *buffer, int len, FILE *stream)
749{
750	int n = len;
751	int r = 0;
752
753	while (n > 0) {
754		r = fwrite(buffer, 1, n, stream);
755		if ((r == 0) && (errno != EINTR)) return -1;
756		buffer += r;
757		n -= r;
758	}
759
760	return r;
761}
762
763void do_file(char *path, FILE *stream)
764{
765	FILE *fp;
766	char buf[1024];
767	int nr;
768
769	if ((fp = fopen(path, "r")) != NULL) {
770		while ((nr = fread(buf, 1, sizeof(buf), fp)) > 0)
771			do_fwrite(buf, nr, stream);
772		fclose(fp);
773	}
774}
775
776#endif
777int is_firsttime(void);
778
779time_t detect_timestamp, detect_timestamp_old, signal_timestamp;
780char detect_timestampstr[32];
781
782
783#define APPLYAPPSTR 	"applyapp.cgi"
784#define GETAPPSTR 	"getapp"
785#define APPGETCGI 	"appGet.cgi"
786
787#ifdef RTCONFIG_ROG
788#define APPLYROGSTR     "api.asp"
789#endif
790
791
792static void
793handle_request(void)
794{
795	char line[10000], *cur;
796	char *method, *path, *protocol, *authorization, *boundary, *alang, *cookies, *referer, *useragent;
797	char *cp;
798	char *file;
799	int len;
800	struct mime_handler *handler;
801	struct except_mime_handler *exhandler;
802	struct mime_referer *doreferer;
803	int mime_exception, do_referer, login_state = -1;
804	int fromapp=0;
805	int cl = 0, flags;
806	int auth_result = 1;
807	int referer_result = 1;
808#ifdef RTCONFIG_FINDASUS
809	int i, isDeviceDiscovery=0;
810	char id_local[32],prouduct_id[32];
811#endif
812
813	/* Initialize the request variables. */
814	authorization = boundary = cookies = referer = useragent = NULL;
815	host_name[0] = 0;
816	bzero( line, sizeof line );
817
818	/* Parse the first line of the request. */
819	if ( fgets( line, sizeof(line), conn_fp ) == (char*) 0 ) {
820		send_error( 400, "Bad Request", (char*) 0, "No request found." );
821		return;
822	}
823
824	method = path = line;
825	strsep(&path, " ");
826	//while (*path == ' ') path++;
827	while (path && *path == ' ') path++;	// oleg patch
828	protocol = path;
829	strsep(&protocol, " ");
830	//while (*protocol == ' ') protocol++;
831	while (protocol && *protocol == ' ') protocol++;    // oleg pat
832	cp = protocol;
833	strsep(&cp, " ");
834	if ( !method || !path || !protocol ) {
835		send_error( 400, "Bad Request", (char*) 0, "Can't parse request." );
836		return;
837	}
838	cur = protocol + strlen(protocol) + 1;
839
840#ifdef TRANSLATE_ON_FLY
841	memset(Accept_Language, 0, sizeof(Accept_Language));
842#endif
843
844	/* Parse the rest of the request headers. */
845	while ( fgets( cur, line + sizeof(line) - cur, conn_fp ) != (char*) 0 )
846	{
847		//_dprintf("handle_request:cur = %s\n",cur);
848		if ( strcmp( cur, "\n" ) == 0 || strcmp( cur, "\r\n" ) == 0 ) {
849			break;
850		}
851#ifdef TRANSLATE_ON_FLY
852		else if ( strncasecmp( cur, "Accept-Language:",16) ==0) {
853			char *p;
854			struct language_table *pLang;
855			char lang_buf[256];
856			memset(lang_buf, 0, sizeof(lang_buf));
857			alang = &cur[16];
858			strncpy(lang_buf, alang, sizeof(lang_buf)-1);
859			p = lang_buf;
860			while (p != NULL)
861			{
862				p = strtok (p, "\r\n ,;");
863				if (p == NULL)  break;
864				//2008.11 magic{
865				int i, len=strlen(p);
866
867				for (i=0;i<len;++i)
868					if (isupper(p[i])) {
869						p[i]=tolower(p[i]);
870					}
871
872				//2008.11 magic}
873				for (pLang = language_tables; pLang->Lang != NULL; ++pLang)
874				{
875					if (strcasecmp(p, pLang->Lang)==0)
876					{
877						char dictname[32];
878
879						if (!check_lang_support(pLang->Target_Lang))
880							continue;
881						snprintf(dictname,sizeof(dictname),"%s.dict", pLang->Target_Lang);
882						if(!check_if_file_exist(dictname))
883						{
884							//_dprintf("language(%s) is not supported!!\n", pLang->Target_Lang);
885							continue;
886						}
887						snprintf(Accept_Language,sizeof(Accept_Language),"%s",pLang->Target_Lang);
888						if (is_firsttime() && nvram_match("ui_Setting", "0")) {
889							_dprintf("%s", Accept_Language);
890							nvram_set("ui_Setting", "1");
891							nvram_set("preferred_lang", Accept_Language);
892
893						#ifdef RTCONFIG_DSL_TCLINUX
894							if(!strcmp(Accept_Language, "CZ") || !strcmp(Accept_Language, "DE")) {
895								int do_restart = 0;
896								if( nvram_match("dslx_annex", "4")
897									&& nvram_match("dsltmp_adslsyncsts", "down")
898								){
899									_dprintf("DSL: auto switch to annex b/j\n");
900									nvram_set("dslx_annex", "6");
901									do_restart = 1;
902								}
903								if(!strcmp(Accept_Language, "DE")
904									&& nvram_match("dslx_vdsl_profile", "0")) {
905									_dprintf("DSL: auto switch to 17a multi mode\n");
906									nvram_set("dslx_vdsl_profile", "1");
907									do_restart = 1;
908								}
909								if (do_restart)
910									notify_rc("restart_dsl_setting");
911							}
912						#endif
913						}
914
915						break;
916					}
917				}
918
919				if (Accept_Language[0] != 0) {
920					break;
921				}
922				p+=strlen(p)+1;
923			}
924
925			if (Accept_Language[0] == 0) {
926				// If all language setting of user's browser are not supported, use English.
927				//printf ("Auto detect language failed. Use English.\n");
928				strcpy (Accept_Language, "EN");
929
930				// 2008.10 magic {
931				if (is_firsttime())
932					nvram_set("preferred_lang", "EN");
933				// 2008.10 magic }
934			}
935		}
936#endif
937		else if ( strncasecmp( cur, "Authorization:", 14 ) == 0 )
938		{
939			cp = &cur[14];
940			cp += strspn( cp, " \t" );
941			authorization = cp;
942			cur = cp + strlen(cp) + 1;
943		}
944		else if ( strncasecmp( cur, "User-Agent:", 11 ) == 0 )
945		{
946			cp = &cur[11];
947			cp += strspn( cp, " \t" );
948			useragent = cp;
949			cur = cp + strlen(cp) + 1;
950		}
951		else if ( strncasecmp( cur, "Cookie:", 7 ) == 0 )
952		{
953			cp = &cur[7];
954			cp += strspn( cp, " \t" );
955			cookies = cp;
956			cur = cp + strlen(cp) + 1;
957		}
958		else if ( strncasecmp( cur, "Referer:", 8 ) == 0 )
959		{
960			cp = &cur[8];
961			cp += strspn( cp, " \t" );
962			referer = cp;
963			cur = cp + strlen(cp) + 1;
964			//_dprintf("httpd referer = %s\n", referer);
965		}
966		else if ( strncasecmp( cur, "Host:", 5 ) == 0 )
967		{
968			cp = &cur[5];
969			cp += strspn( cp, " \t" );
970			sethost(cp);
971			cur = cp + strlen(cp) + 1;
972#ifdef RTCONFIG_FINDASUS
973			sprintf(prouduct_id, "%s",get_productid());
974			for(i = 0 ; i < strlen(prouduct_id) ; i++ ){
975				prouduct_id[i] = tolower(prouduct_id[i]) ;
976			}
977			sprintf(id_local, "%s.local",prouduct_id);
978			if(!strncmp(cp, "findasus", 8) || !strncmp(cp, id_local,strlen(id_local)))
979				isDeviceDiscovery = 1;
980			else
981				isDeviceDiscovery = 0;
982#endif
983		}
984		else if (strncasecmp( cur, "Content-Length:", 15 ) == 0) {
985			cp = &cur[15];
986			cp += strspn( cp, " \t" );
987			cl = strtoul( cp, NULL, 0 );
988		}
989		else if ((cp = strstr( cur, "boundary=" ))) {
990			boundary = &cp[9];
991			for ( cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++ );
992			*cp = '\0';
993			cur = ++cp;
994		}
995	}
996
997	if ( strcasecmp( method, "get" ) != 0 && strcasecmp(method, "post") != 0 && strcasecmp(method, "head") != 0 ) {
998		send_error( 501, "Not Implemented", (char*) 0, "That method is not implemented." );
999		return;
1000	}
1001
1002	if ( path[0] != '/' ) {
1003		send_error( 400, "Bad Request", (char*) 0, "Bad filename." );
1004		return;
1005	}
1006	file = &(path[1]);
1007	len = strlen( file );
1008	if ( file[0] == '/' || strcmp( file, ".." ) == 0 || strncmp( file, "../", 3 ) == 0 || strstr( file, "/../" ) != (char*) 0 || strcmp( &(file[len-3]), "/.." ) == 0 ) {
1009		send_error( 400, "Bad Request", (char*) 0, "Illegal filename." );
1010		return;
1011	}
1012
1013//2008.08 magic{
1014	if (file[0] == '\0' || file[len-1] == '/'){
1015		if (is_firsttime()
1016#ifdef RTCONFIG_FINDASUS
1017		    && !isDeviceDiscovery
1018#endif
1019		   )
1020			//file = "QIS_wizard.htm";
1021			file = "QIS_default.cgi";
1022#ifdef RTCONFIG_FINDASUS
1023		else if(isDeviceDiscovery == 1)
1024			file = "find_device.asp";
1025#endif
1026		else
1027			file = "index.asp";
1028	}
1029
1030// 2007.11 James. {
1031	char *query;
1032	int file_len;
1033
1034	memset(url, 0, 128);
1035	if ((query = index(file, '?')) != NULL) {
1036		file_len = strlen(file)-strlen(query);
1037
1038		if(file_len > sizeof(url))
1039			file_len = sizeof(url);
1040
1041		strncpy(url, file, file_len);
1042	}
1043	else
1044	{
1045		strncpy(url, file, sizeof(url)-1);
1046	}
1047// 2007.11 James. }
1048
1049	if(strncmp(url, APPLYAPPSTR, strlen(APPLYAPPSTR))==0
1050#ifdef RTCONFIG_ROG
1051		|| strncmp(url, APPLYROGSTR, strlen(APPLYROGSTR))==0
1052#endif
1053	)
1054		fromapp=1;
1055	else if(strncmp(url, GETAPPSTR, strlen(GETAPPSTR))==0)  {
1056		fromapp=1;
1057		strcpy(url, url+strlen(GETAPPSTR));
1058		file += strlen(GETAPPSTR);
1059	}
1060
1061	memset(user_agent, 0, sizeof(user_agent));
1062	if(useragent != NULL)
1063		strncpy(user_agent, useragent, sizeof(user_agent)-1);
1064	else
1065		strcpy(user_agent, "");
1066
1067	fromapp = check_user_agent(useragent);
1068
1069	//printf("httpd url: %s file: %s\n", url, file);
1070	//_dprintf("httpd url: %s file: %s\n", url, file);
1071	mime_exception = 0;
1072	do_referer = 0;
1073
1074	if(!fromapp) {
1075		if(lock_flag == 1){
1076			time_t dt_t;
1077			login_timestamp_tmp = uptime();
1078			dt_t = login_timestamp_tmp - last_login_timestamp;
1079			if(last_login_timestamp != 0 && dt_t > 60){
1080				login_try = 0;
1081				last_login_timestamp = 0;
1082				lock_flag = 0;
1083			}else{
1084				if(strncmp(file, "Main_Login.asp?error_status=7", 29)==0 || strstr(url, ".png")){
1085				}else{
1086					send_login_page(fromapp, LOGINLOCK, url, dt_t);
1087					return;
1088				}
1089			}
1090		}
1091		http_login_timeout(login_ip_tmp, cookies, fromapp);	// 2008.07 James.
1092		login_state = http_login_check();
1093		// for each page, mime_exception is defined to do exception handler
1094
1095		mime_exception = 0;
1096
1097		// check exception first
1098		for (exhandler = &except_mime_handlers[0]; exhandler->pattern; exhandler++) {
1099			if(match(exhandler->pattern, url))
1100			{
1101				mime_exception = exhandler->flag;
1102				break;
1103			}
1104		}
1105
1106		do_referer = 0;
1107
1108		// check doreferer first
1109		for (doreferer = &mime_referers[0]; doreferer->pattern; doreferer++) {
1110			if(match(doreferer->pattern, url))
1111			{
1112				do_referer = doreferer->flag;
1113				break;
1114			}
1115		}
1116
1117		x_Setting = nvram_get_int("x_Setting");
1118	}
1119	else { // Jerry5 fix AiCloud login issue. 20120815
1120		x_Setting = nvram_get_int("x_Setting");
1121		//skip_auth = 0;
1122	}
1123	for (handler = &mime_handlers[0]; handler->pattern; handler++) {
1124		if (match(handler->pattern, url))
1125		{
1126			nvram_set("httpd_handle_request", url);
1127			nvram_set_int("httpd_handle_request_fromapp", fromapp);
1128			if(login_state==3 && !fromapp) { // few pages can be shown even someone else login
1129				if(!(mime_exception&MIME_EXCEPTION_MAINPAGE || strncmp(file, "Main_Login.asp?error_status=9", 29)==0 || ((!handler->auth) && strncmp(file, "Main_Login.asp", 14) != 0))) {
1130					if(strcasecmp(method, "post") == 0){
1131						if (handler->input) {
1132							handler->input(file, conn_fp, cl, boundary);
1133						}
1134					}
1135					send_login_page(fromapp, NOLOGIN, NULL, 0);
1136					return;
1137				}
1138			}
1139			if (handler->auth) {
1140				if ((mime_exception&MIME_EXCEPTION_NOAUTH_FIRST)&&!x_Setting) {
1141					//skip_auth=1;
1142				}
1143				else if((mime_exception&MIME_EXCEPTION_NOAUTH_ALL)) {
1144				}
1145				else {
1146					if(do_referer&CHECK_REFERER){
1147						referer_result = referer_check(referer, fromapp);
1148						if(referer_result != 0){
1149							if(strcasecmp(method, "post") == 0){
1150								if (handler->input) {
1151									handler->input(file, conn_fp, cl, boundary);
1152								}
1153								send_login_page(fromapp, referer_result, NULL, 0);
1154							}
1155							//if(!fromapp) http_logout(login_ip_tmp, cookies);
1156							return;
1157						}
1158					}
1159					handler->auth(auth_userid, auth_passwd, auth_realm);
1160					auth_result = auth_check(auth_realm, authorization, url, cookies, fromapp);
1161					if (auth_result != 0)
1162					{
1163						if(strcasecmp(method, "post") == 0){
1164							if (handler->input) {
1165								handler->input(file, conn_fp, cl, boundary);
1166							}
1167							send_login_page(fromapp, auth_result, NULL, 0);
1168						}
1169						//if(!fromapp) http_logout(login_ip_tmp, cookies);
1170						return;
1171					}
1172				}
1173
1174				if(!fromapp) {
1175					if (	!strstr(url, "QIS_")
1176							&& !strstr(url, ".js")
1177							&& !strstr(url, ".css")
1178							&& !strstr(url, ".gif")
1179							&& !strstr(url, ".png"))
1180						http_login(login_ip_tmp, url);
1181				}
1182			}else{
1183			}
1184
1185			if(!strcmp(file, "Logout.asp")){
1186				http_logout(login_ip_tmp, cookies, fromapp);
1187				send_login_page(fromapp, ISLOGOUT, NULL, 0);
1188				return;
1189			}
1190			if (strcasecmp(method, "post") == 0 && !handler->input) {
1191				send_error(501, "Not Implemented", NULL, "That method is not implemented.");
1192				return;
1193			}
1194// 2007.11 James. for QISxxx.htm pages }
1195			if (handler->input) {
1196				handler->input(file, conn_fp, cl, boundary);
1197#if defined(linux)
1198				if ((flags = fcntl(fileno(conn_fp), F_GETFL)) != -1 &&
1199						fcntl(fileno(conn_fp), F_SETFL, flags | O_NONBLOCK) != -1) {
1200					/* Read up to two more characters */
1201					if (fgetc(conn_fp) != EOF)
1202						(void)fgetc(conn_fp);
1203
1204					fcntl(fileno(conn_fp), F_SETFL, flags);
1205				}
1206#elif defined(vxworks)
1207				flags = 1;
1208				if (ioctl(fileno(conn_fp), FIONBIO, (int) &flags) != -1) {
1209					/* Read up to two more characters */
1210					if (fgetc(conn_fp) != EOF)
1211						(void)fgetc(conn_fp);
1212					flags = 0;
1213					ioctl(fileno(conn_fp), FIONBIO, (int) &flags);
1214				}
1215#endif
1216			}
1217			if(!strstr(file, ".cgi") && !strstr(file, "syslog.txt") && !(strstr(file,"uploadIconFile.tar")) && !(strstr(file,"networkmap.tar")) && !(strstr(file,".CFG")) && !(strstr(file,".log")) && !check_if_file_exist(file)
1218#ifdef RTCONFIG_USB_MODEM
1219					&& !strstr(file, "modemlog.txt")
1220#endif
1221#ifdef RTCONFIG_DSL_TCLINUX
1222					&& !strstr(file, "TCC.log")
1223#endif
1224					){
1225				send_error( 404, "Not Found", (char*) 0, "File not found." );
1226				return;
1227			}
1228			if(strncmp(url, "QIS_default.cgi", strlen(url))==0 && nvram_match("x_Setting", "0")){
1229				memset(referer_host, 0, sizeof(referer_host));
1230				if(strncmp(DUT_DOMAIN_NAME, host_name, strlen(DUT_DOMAIN_NAME))==0){
1231					strcpy(referer_host, nvram_safe_get("lan_ipaddr"));
1232				}else
1233					snprintf(referer_host,sizeof(host_name),"%s",host_name);
1234
1235				send_token_headers( 200, "Ok", handler->extra_header, handler->mime_type, fromapp);
1236
1237			}else if(strncmp(url, "login.cgi", strlen(url))!=0){
1238				send_headers( 200, "Ok", handler->extra_header, handler->mime_type, fromapp);
1239			}
1240
1241			if (strcasecmp(method, "head") != 0 && handler->output) {
1242				handler->output(file, conn_fp);
1243			}
1244
1245			break;
1246		}
1247	}
1248
1249	if (!handler->pattern){
1250		if(strlen(file) > 50 && !(strstr(file, "findasus"))){
1251			char inviteCode[256];
1252			snprintf(inviteCode, sizeof(inviteCode), "<script>location.href='/cloud_sync.asp?flag=%s';</script>", file);
1253			send_page( 200, "OK", (char*) 0, inviteCode, 0);
1254		}
1255		else
1256			send_error( 404, "Not Found", (char*) 0, "File not found." );
1257	}
1258	nvram_unset("httpd_handle_request");
1259	nvram_unset("httpd_handle_request_fromapp");
1260}
1261
1262asus_token_t* search_token_in_list(char* token, asus_token_t **prev)
1263{
1264	asus_token_t *ptr = head;
1265	asus_token_t *tmp = NULL;
1266	int found = 0;
1267	char *cp=NULL;
1268
1269	while(ptr != NULL)
1270	{
1271		if(!strncmp(token, ptr->token, 32))
1272        	{
1273			found = 1;
1274			break;
1275        	}
1276		else if(strncmp(token, "cgi_logout", 10) == 0){
1277			cp = strtok(ptr->useragent, "-");
1278
1279			if(strcmp( cp, "asusrouter") != 0){
1280				found = 1;
1281				break;
1282			}
1283        	}
1284		else
1285        	{
1286			tmp = ptr;
1287			ptr = ptr->next;
1288        	}
1289    	}
1290    	if(found == 1)
1291    	{
1292        	if(prev)
1293	            *prev = tmp;
1294        	return ptr;
1295	}
1296	else
1297    	{
1298        	return NULL;
1299    	}
1300}
1301
1302int delete_logout_from_list(char *cookies)
1303{
1304	asus_token_t *prev = NULL;
1305	asus_token_t *del = NULL;
1306
1307	char asustoken[32];
1308	char *cp=NULL, *location_cp;
1309
1310	memset(asustoken,0,sizeof(asustoken));
1311
1312	//int fromapp_flag=0;
1313
1314	if(!cookies || nvram_match("x_Setting", "0")){
1315		//send_login_page(fromapp_flag, NOTOKEN);
1316		return 0;
1317
1318	}else{
1319		if(strncmp(cookies, "cgi_logout", 10) == 0){
1320			strncpy(asustoken, cookies, sizeof(asustoken));
1321		}else{
1322			location_cp = strstr(cookies,"asus_token");
1323			if(location_cp != NULL){
1324				cp = &location_cp[11];
1325				cp += strspn( cp, " \t" );
1326				snprintf(asustoken, sizeof(asustoken), "%s", cp);
1327			}else{
1328				//send_login_page(fromapp_flag, NOTOKEN);
1329				return 0;
1330			}
1331		}
1332	}
1333
1334	del = search_token_in_list(asustoken,&prev);
1335	if(del == NULL)
1336	{
1337		return -1;
1338	}
1339	else
1340	{
1341		if(prev != NULL){
1342			prev->next = del->next;
1343		}
1344		if(del == curr)
1345		{
1346			curr = prev;
1347		}
1348		if(del == head)
1349		{
1350			head = del->next;
1351		}
1352	}
1353
1354	free(del);
1355	del = NULL;
1356
1357	return 0;
1358}
1359
1360//2008 magic{
1361void http_login_cache(usockaddr *u) {
1362	struct in_addr temp_ip_addr;
1363	char *temp_ip_str;
1364
1365	login_ip_tmp = (unsigned int)(u->sa_in.sin_addr.s_addr);
1366	temp_ip_addr.s_addr = login_ip_tmp;
1367	temp_ip_str = inet_ntoa(temp_ip_addr);
1368}
1369
1370void http_get_access_ip(void)
1371{
1372	struct in_addr addr4;
1373	char *nv, *nvp, *b, *ip;
1374	int i, size;
1375
1376	memset(&access_ip, 0, sizeof(access_ip));
1377
1378	nv = nvp = strdup(nvram_safe_get("http_clientlist"));
1379	i = 0;
1380	while (nv && (b = strsep(&nvp, "<")) != NULL && i < ARRAY_SIZE(access_ip)) {
1381		ip = strsep(&b, "/");
1382		size = (b && *b) ? strtoul(b, NULL, 10) : 32;
1383		if (inet_pton(AF_INET, ip, &addr4) > 0) {
1384			if (size > 32)
1385				size = 32;
1386			access_ip[i].ip.s_addr = addr4.s_addr;
1387			access_ip[i].netmask.s_addr = htonl(0xffffffffUL << (32 - size));
1388			i++;
1389		}
1390	}
1391	free(nv);
1392}
1393
1394void http_login(unsigned int ip, char *url) {
1395	if(strncmp(url, "Main_Login.asp", strlen(url))==0)
1396		return;
1397	struct in_addr login_ip_addr;
1398	char *login_ip_str;
1399	char login_ipstr[32], login_timestampstr[32];
1400
1401	if ((http_port != SERVER_PORT
1402/*	  && http_port != nvram_get_int("http_lanport")*/
1403#ifdef RTCONFIG_HTTPS
1404	  && http_port != SERVER_PORT_SSL
1405	  && http_port != nvram_get_int("https_lanport")
1406#endif
1407	    ) || ip == 0x100007f)
1408		return;
1409
1410	login_ip = ip;
1411	last_login_ip = 0;
1412
1413	login_ip_addr.s_addr = login_ip;
1414	login_ip_str = inet_ntoa(login_ip_addr);
1415	nvram_set("login_ip_str", login_ip_str);
1416
1417	login_timestamp = uptime();
1418
1419	memset(login_ipstr, 0, 32);
1420	sprintf(login_ipstr, "%u", login_ip);
1421	nvram_set("login_ip", login_ipstr);
1422
1423	memset(login_timestampstr, 0, 32);
1424	sprintf(login_timestampstr, "%lu", login_timestamp);
1425	nvram_set("login_timestamp", login_timestampstr);
1426}
1427
1428int http_client_ip_check(void)
1429{
1430	int i = 0;
1431
1432	if (nvram_match("http_client", "1")) {
1433		for (i = 0; i < ARRAY_SIZE(access_ip); i++) {
1434			if (access_ip[i].ip.s_addr == INADDR_ANY)
1435				continue;
1436			if ((login_ip_tmp & access_ip[i].netmask.s_addr) ==
1437			    (access_ip[i].ip.s_addr & access_ip[i].netmask.s_addr))
1438				return 1;
1439		}
1440		return 0;
1441	}
1442
1443	return 1;
1444}
1445
1446// 0: can not login, 1: can login, 2: loginer, 3: not loginer
1447int http_login_check(void)
1448{
1449	if ((http_port != SERVER_PORT
1450/*	  && http_port != nvram_get_int("http_lanport")*/
1451#ifdef RTCONFIG_HTTPS
1452	  && http_port != SERVER_PORT_SSL
1453	  && http_port != nvram_get_int("https_lanport")
1454#endif
1455	    ) || login_ip_tmp == 0x100007f)
1456		//return 1;
1457		return 0;	// 2008.01 James.
1458
1459	if (login_ip == 0)
1460		return 1;
1461	else if (login_ip == login_ip_tmp)
1462		return 2;
1463
1464	return 3;
1465}
1466
1467void http_login_timeout(unsigned int ip, char *cookies, int fromapp_flag)
1468{
1469	time_t now, login_ts;
1470
1471//	time(&now);
1472	now = uptime();
1473	login_ts = atol(nvram_safe_get("login_timestamp"));
1474
1475// 2007.10 James. for really logout. {
1476	//if (login_ip!=ip && (unsigned long)(now-login_timestamp) > 60) //one minitues
1477	if ((login_ip != 0 && login_ip != ip) && ((unsigned long)(now-login_ts) > 60)) //one minitues
1478// 2007.10 James }
1479	{
1480		http_logout(login_ip, cookies, fromapp_flag);
1481	}
1482}
1483
1484void http_logout(unsigned int ip, char *cookies, int fromapp_flag)
1485{
1486	if ((ip == login_ip || ip == 0 ) && fromapp_flag == 0) {
1487		last_login_ip = login_ip;
1488		login_ip = 0;
1489		login_timestamp = 0;
1490
1491		nvram_set("login_ip", "");
1492		nvram_set("login_timestamp", "");
1493		memset(referer_host, 0, sizeof(referer_host));
1494		delete_logout_from_list(cookies);
1495// 2008.03 James. {
1496		if (change_passwd == 1) {
1497			change_passwd = 0;
1498			reget_passwd = 1;
1499		}
1500// 2008.03 James. }
1501	}else if(fromapp_flag != 0){
1502		delete_logout_from_list(cookies);
1503}
1504}
1505//2008 magic}
1506//
1507
1508int is_auth(void)
1509{
1510	if (http_port==SERVER_PORT ||
1511/*	    http_port==nvram_get_int("http_lanport") ||*/
1512#ifdef RTCONFIG_HTTPS
1513	    http_port==SERVER_PORT_SSL ||
1514	    http_port==nvram_get_int("https_lanport") ||
1515#endif
1516		strcmp(nvram_get_x("PrinterStatus", "usb_webhttpcheck_x"), "1")==0) return 1;
1517	else return 0;
1518}
1519
1520int is_firsttime(void)
1521{
1522	if (strcmp(nvram_get("x_Setting"), "1")==0)
1523		return 0;
1524	else
1525		return 1;
1526}
1527
1528/* str_replace
1529* @param {char*} source
1530* @param {char*} find
1531* @param {char*} rep
1532* */
1533char *config_model_name(char *source, char *find,  char *rep){
1534   int find_L=strlen(find);
1535   int rep_L=strlen(rep);
1536   int length=strlen(source)+1;
1537   int gap=0;
1538
1539   char *result = (char*)malloc(sizeof(char) * length);
1540   strcpy(result, source);
1541
1542   char *former=source;
1543   char *location= strstr(former, find);
1544
1545	/* stop searching when there is no finding string */
1546   while(location!=NULL){
1547       gap+=(location - former);
1548       result[gap]='\0';
1549
1550       length+=(rep_L-find_L);
1551       result = (char*)realloc(result, length * sizeof(char));
1552       strcat(result, rep);
1553       gap+=rep_L;
1554
1555       former=location+find_L;
1556       strcat(result, former);
1557
1558       location= strstr(former, find);
1559   }
1560   return result;
1561}
1562
1563#ifdef TRANSLATE_ON_FLY
1564/* Whether a language support should be enabled or not.
1565 * @lang:
1566 * @return:
1567 * 	0:	lang should not be supported.
1568 *     <0:	invalid parameter.
1569 *     >0:	lang can be supported.
1570 */
1571int check_lang_support(char *lang)
1572{
1573	int r = 1;
1574
1575	if (!lang)
1576		return -1;
1577
1578#if defined(RTCONFIG_TCODE)
1579	if (!find_word(nvram_safe_get("rc_support"), "tcode") || !nvram_get("territory_code"))
1580		return 1;
1581	if (!strncmp(nvram_get("territory_code"), "UK", 2) ||
1582	    !strncmp(nvram_get("territory_code"), "NE", 2)) {
1583		if (!strcmp(lang, "DA") || !strcmp(lang, "EN") ||
1584		    !strcmp(lang, "FI") || !strcmp(lang, "NO") ||
1585		    !strcmp(lang, "SV")) {
1586			r = 1;
1587		} else {
1588			r = 0;
1589		}
1590	} else {
1591		if (!strcmp(lang, "DA") || !strcmp(lang, "FI") ||
1592		    !strcmp(lang, "NO") || !strcmp(lang, "SV")) {
1593			r = 0;
1594		} else {
1595			r = 1;
1596		}
1597	}
1598#endif
1599
1600	return r;
1601}
1602
1603#ifdef RTCONFIG_AUTODICT
1604int
1605load_dictionary (char *lang, pkw_t pkw)
1606{
1607	char dfn[16];
1608	char dummy_buf[16];
1609	int dict_item_idx;
1610	char* tmp_ptr;
1611	int dict_item; // number of dict item, now get from text file
1612	char *q;
1613	FILE *dfp = NULL;
1614	int remain_dict;
1615	int dict_size = 0;
1616//	struct timeval tv1, tv2;
1617	const char *eng_dict = "EN.dict";
1618#ifndef RELOAD_DICT
1619	static char loaded_dict[12] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
1620#endif  // RELOAD_DICT
1621#ifdef RTCONFIG_DYN_DICT_NAME
1622	char *dyn_dict_buf;
1623	char *dyn_dict_buf_new;
1624#endif
1625
1626//printf ("lang=%s\n", lang);
1627
1628//	gettimeofday (&tv1, NULL);
1629	if (lang == NULL || (lang != NULL && strlen (lang) == 0)) {
1630		// if "lang" is invalid, use English as default
1631		snprintf (dfn, sizeof (dfn), eng_dict);
1632	} else {
1633		snprintf (dfn, sizeof (dfn), "%s.dict", lang);
1634	}
1635
1636#ifndef RELOAD_DICT
1637//	printf ("loaded_dict (%s) v.s. dfn (%s)\n", loaded_dict, dfn);
1638	if (strcmp (dfn, loaded_dict) == 0) {
1639		return 1;
1640	}
1641	release_dictionary (pkw);
1642#endif  // RELOAD_DICT
1643
1644	do {
1645//		 printf("Open (%s) dictionary file.\n", dfn);
1646//
1647// Now DICT files all use UTF-8, it is no longer a text file
1648// it need to use open as binary
1649//
1650		dfp = fopen (dfn, "rb");
1651		if (dfp != NULL)	{
1652#ifndef RELOAD_DICT
1653			snprintf (loaded_dict, sizeof (loaded_dict), "%s", dfn);
1654#endif  // RELOAD_DICT
1655			break;
1656		}
1657
1658//		printf ("Open (%s) failure. errno %d (%s)\n", dfn, errno, strerror (errno));
1659		if (dfp == NULL && strcmp (dfn, eng_dict) == 0) {
1660			return 0;
1661		} else {
1662			// If we can't open specified language file, use English as default
1663			snprintf (dfn, sizeof (dfn), eng_dict);
1664		}
1665	} while (1);
1666
1667	memset (pkw, 0, sizeof (kw_t));
1668	fseek (dfp, 0L, SEEK_END);
1669	dict_size = ftell (dfp) + 128;
1670	// skip BOM header length
1671	dict_size -= 3;
1672	printf ("dict_size %d\n", dict_size);
1673
1674#ifdef RTCONFIG_DYN_DICT_NAME
1675	dyn_dict_buf = (char *) malloc(dict_size);
1676	fseek (dfp, 0L, SEEK_SET);
1677	// skip BOM
1678	fread (dummy_buf, 1, 3, dfp);
1679	// read to dict string buffer
1680	memset(dyn_dict_buf, 0, dict_size);
1681	fread (dyn_dict_buf, 1, dict_size, dfp);
1682	dyn_dict_buf_new = config_model_name(dyn_dict_buf, "ZVDYNMODELVZ", nvram_safe_get("productid"));
1683
1684	free(dyn_dict_buf);
1685
1686	dict_size = sizeof(char) * strlen(dyn_dict_buf_new);
1687	pkw->buf = (unsigned char *) (q = malloc (dict_size));
1688	strcpy(pkw->buf, dyn_dict_buf_new);
1689	free(dyn_dict_buf_new);
1690#else
1691	pkw->buf = (unsigned char *) (q = malloc (dict_size));
1692
1693	fseek (dfp, 0L, SEEK_SET);
1694	// skip BOM
1695	fread (dummy_buf, 1, 3, dfp);
1696	// read to dict string buffer
1697	memset(pkw->buf, 0, dict_size);
1698	fread (pkw->buf, 1, dict_size, dfp);
1699#endif
1700	// calc how many dict item , dict_item
1701	remain_dict = dict_size;
1702	tmp_ptr = (char *) pkw->buf;
1703	dict_item = 0;
1704	while (remain_dict>0) {
1705		if (*tmp_ptr == 0x0a) {
1706			dict_item++;
1707			tmp_ptr++;
1708			remain_dict--;
1709		}
1710		else if (*tmp_ptr == 0) {
1711			break;
1712		}
1713		else {
1714			tmp_ptr++;
1715			remain_dict--;
1716		}
1717	}
1718	// allocate memory according dict_item
1719	pkw->idx = malloc (dict_item * sizeof(unsigned char*));
1720
1721	printf ("dict_item %d\n", dict_item);
1722
1723	// get all string start and put to pkw->idx
1724	remain_dict = dict_size;
1725	for (dict_item_idx = 0; dict_item_idx < dict_item; dict_item_idx++) {
1726		pkw->idx[dict_item_idx] = (unsigned char *) q;
1727		while (remain_dict>0) {
1728			if (*q == 0x0a) {
1729				*q=0;
1730				q++;
1731				remain_dict--;
1732				break;
1733			}
1734			if (*q == 0) {
1735				break;
1736			}
1737			q++;
1738			remain_dict--;
1739		}
1740	}
1741
1742	pkw->len = dict_item;
1743
1744	fclose (dfp);
1745
1746	return 1;
1747}
1748
1749
1750void
1751release_dictionary (pkw_t pkw)
1752{
1753	if (pkw == NULL)	{
1754		return;
1755	}
1756
1757	//pkw->len = pkw->tlen = 0;
1758	pkw->len = 0;
1759
1760	if (pkw->idx != NULL)   {
1761		free (pkw->idx);
1762		pkw->idx = NULL;
1763	}
1764
1765	if (pkw->buf != NULL)   {
1766		free (pkw->buf);
1767		pkw->buf = NULL;
1768	}
1769}
1770
1771char*
1772search_desc (pkw_t pkw, char *name)
1773{
1774	int i;
1775	char *ret = NULL;
1776	int dict_idx;
1777	char name_buf[128];
1778
1779/*
1780	printf("search_desc:");
1781	printf(name);
1782	printf("\n");
1783*/
1784
1785	if (pkw == NULL || (pkw != NULL && pkw->len <= 0)) {
1786		return NULL;
1787	}
1788
1789	// remove equal
1790	memset(name_buf,0,sizeof(name_buf));
1791	// minus one for reserver one char for string zero char
1792	for (i = 0; i<sizeof(name_buf)-1; i++)  {
1793		if (*name == 0 || *name == '=') {
1794			break;
1795		}
1796		name_buf[i]=*name++;
1797	}
1798
1799/*
1800	for (i = 0; i < pkw->len; ++i)  {
1801		char *p;
1802		p = pkw->idx[i];
1803		if (strncmp (name, p, strlen (name)) == 0) {
1804			ret = p + strlen (name);
1805			break;
1806		}
1807	}
1808*/
1809
1810/*
1811	printf("search_desc:");
1812	printf(name_buf);
1813	printf("\n");
1814*/
1815
1816	dict_idx = atoi(name_buf);
1817//	printf("%d , %d\n",dict_idx,pkw->len);
1818	if (dict_idx < pkw->len) {
1819		ret = (char *) pkw->idx[dict_idx];
1820	}
1821	else {
1822		ret = (char *) pkw->idx[0];
1823	}
1824
1825/*
1826	printf("ret:");
1827	printf(ret);
1828	printf("\n");
1829*/
1830
1831	return ret;
1832}
1833#else
1834int
1835load_dictionary (char *lang, pkw_t pkw)
1836{
1837	char dfn[16];
1838	char *p, *q;
1839	FILE *dfp = NULL;
1840	int dict_size = 0;
1841//	struct timeval tv1, tv2;
1842	const char *eng_dict = "EN.dict";
1843#ifndef RELOAD_DICT
1844	static char loaded_dict[12] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
1845#endif  // RELOAD_DICT
1846
1847//	gettimeofday (&tv1, NULL);
1848	if (lang == NULL || (lang != NULL && strlen (lang) == 0)) {
1849		// if "lang" is invalid, use English as default
1850		snprintf (dfn, sizeof (dfn), eng_dict);
1851	} else {
1852		snprintf (dfn, sizeof (dfn), "%s.dict", lang);
1853	}
1854
1855#ifndef RELOAD_DICT
1856//	printf ("loaded_dict (%s) v.s. dfn (%s)\n", loaded_dict, dfn);
1857	if (strcmp (dfn, loaded_dict) == 0) {
1858		return 1;
1859	}
1860	release_dictionary (pkw);
1861#endif  // RELOAD_DICT
1862
1863	do {
1864//		 printf("Open (%s) dictionary file.\n", dfn);
1865		dfp = fopen (dfn, "r");
1866		if (dfp != NULL)	{
1867#ifndef RELOAD_DICT
1868			snprintf (loaded_dict, sizeof (loaded_dict), "%s", dfn);
1869#endif  // RELOAD_DICT
1870			break;
1871		}
1872
1873//		printf ("Open (%s) failure. errno %d (%s)\n", dfn, errno, strerror (errno));
1874		if (dfp == NULL && strcmp (dfn, eng_dict) == 0) {
1875			return 0;
1876		} else {
1877			// If we can't open specified language file, use English as default
1878			snprintf (dfn, sizeof (dfn), eng_dict);
1879		}
1880	} while (1);
1881
1882	memset (pkw, 0, sizeof (kw_t));
1883	fseek (dfp, 0L, SEEK_END);
1884	dict_size = ftell (dfp) + 128;
1885//	printf ("dict_size %d\n", dict_size);
1886	REALLOC_VECTOR (pkw->idx, pkw->len, pkw->tlen, sizeof (unsigned char*));
1887	pkw->buf = q = malloc (dict_size);
1888
1889	fseek (dfp, 0L, SEEK_SET);
1890#if 0
1891	while (!feof (dfp)) {
1892		// if pkw->idx is not enough, add 32 item to pkw->idx
1893		REALLOC_VECTOR (pkw->idx, pkw->len, pkw->tlen, sizeof (unsigned char*));
1894
1895		fscanf (dfp, "%[^\n]%*c", q);
1896		if ((p = strchr (q, '=')) != NULL) {
1897			pkw->idx[pkw->len] = q;
1898			pkw->len++;
1899			q = p + strlen (p);
1900			*q = '\0';
1901			q++;
1902		}
1903	}
1904#else
1905	while ((fscanf(dfp, "%[^\n]", q)) != EOF) {
1906		fgetc(dfp);
1907
1908		// if pkw->idx is not enough, add 32 item to pkw->idx
1909		REALLOC_VECTOR (pkw->idx, pkw->len, pkw->tlen, sizeof (unsigned char*));
1910
1911		if ((p = strchr (q, '=')) != NULL) {
1912			pkw->idx[pkw->len] = q;
1913			pkw->len++;
1914			q = p + strlen (p);
1915			*q = '\0';
1916			q++;
1917		}
1918	}
1919
1920#endif
1921
1922	fclose (dfp);
1923//	gettimeofday (&tv2, NULL);
1924//	printf("Load %d keywords spent %ldms\n", pkw->len, ((tv2.tv_sec * 1000000 + tv2.tv_usec) - (tv1.tv_sec * 1000000 + tv1.tv_usec)) / 1000);
1925
1926	return 1;
1927}
1928
1929
1930void
1931release_dictionary (pkw_t pkw)
1932{
1933	if (pkw == NULL)	{
1934		return;
1935	}
1936
1937	pkw->len = pkw->tlen = 0;
1938
1939	if (pkw->idx != NULL)   {
1940		free (pkw->idx);
1941		pkw->idx = NULL;
1942	}
1943
1944	if (pkw->buf != NULL)   {
1945		free (pkw->buf);
1946		pkw->buf = NULL;
1947	}
1948}
1949
1950char*
1951search_desc (pkw_t pkw, char *name)
1952{
1953	int i;
1954	char *p, *ret = NULL;
1955
1956	if (pkw == NULL || (pkw != NULL && pkw->len <= 0)) {
1957		return NULL;
1958	}
1959	for (i = 0; i < pkw->len; ++i)  {
1960		p = pkw->idx[i];
1961		if (strncmp (name, p, strlen (name)) == 0) {
1962			ret = p + strlen (name);
1963			break;
1964		}
1965	}
1966
1967	return ret;
1968}
1969#endif
1970#endif //TRANSLATE_ON_FLY
1971
1972void reapchild()	// 0527 add
1973{
1974	signal(SIGCHLD, reapchild);
1975	wait(NULL);
1976}
1977
1978int do_ssl = 0; 	// use Global for HTTPS upgrade judgment in web.c
1979int ssl_stream_fd; 	// use Global for HTTPS stream fd in web.c
1980int main(int argc, char **argv)
1981{
1982	usockaddr usa;
1983	int listen_fd[2];
1984	socklen_t sz;
1985	char pidfile[32];
1986	fd_set active_rfds;
1987	conn_list_t pool;
1988	int i, c;
1989	//int do_ssl = 0;
1990
1991	do_ssl = 0; // default
1992
1993	// usage : httpd -s -p [port]
1994	while ((c = getopt(argc, argv, "sp:i:")) != -1) {
1995		switch (c) {
1996		case 's':
1997#ifdef RTCONFIG_HTTPS
1998			do_ssl = 1;
1999#endif
2000			break;
2001		case 'p':
2002			http_port = atoi(optarg);
2003			break;
2004		case 'i':
2005			http_ifname = optarg;
2006			break;
2007		default:
2008			fprintf(stderr, "ERROR: unknown option %c\n", c);
2009			break;
2010		}
2011	}
2012
2013	/* -p might be specified before -s */
2014	if (http_port == 0) {
2015#ifdef RTCONFIG_HTTPS
2016		if (do_ssl) {
2017			http_port = SERVER_PORT_SSL;
2018		} else
2019#endif
2020		{
2021			http_port = SERVER_PORT;
2022		}
2023	}
2024
2025	//websSetVer();
2026	//2008.08 magic
2027	nvram_unset("login_timestamp");
2028	nvram_unset("login_ip");
2029	nvram_unset("login_ip_str");
2030	MAX_login = nvram_get_int("login_max_num");
2031	if(MAX_login <= DEFAULT_LOGIN_MAX_NUM)
2032		MAX_login = DEFAULT_LOGIN_MAX_NUM;
2033
2034	detect_timestamp_old = 0;
2035	detect_timestamp = 0;
2036	signal_timestamp = 0;
2037
2038	http_get_access_ip();
2039
2040	/* Ignore broken pipes */
2041	signal(SIGPIPE, SIG_IGN);
2042	signal(SIGCHLD, reapchild);	// 0527 add
2043
2044#ifdef RTCONFIG_HTTPS
2045	//if (do_ssl)
2046		start_ssl();
2047#endif
2048
2049	/* Initialize listen socket */
2050	for (i = 0; i < ARRAY_SIZE(listen_fd); i++)
2051		listen_fd[i] = -1;
2052	if ((listen_fd[0] = initialize_listen_socket(&usa, http_ifname)) < 2) {
2053		fprintf(stderr, "can't bind to %s address\n", http_ifname ? : "any");
2054		exit(errno);
2055	}
2056	if ((http_ifname && strcmp(http_ifname, "lo") != 0) &&
2057	    (listen_fd[1] = initialize_listen_socket(&usa, "lo")) < 2) {
2058		fprintf(stderr, "can't bind to %s address\n", "loopback");
2059		/* allow fail if previous bind to interface was ok */
2060		/* exit(errno); */
2061	}
2062
2063	FILE *pid_fp;
2064	if (http_port==SERVER_PORT)
2065		strcpy(pidfile, "/var/run/httpd.pid");
2066	else sprintf(pidfile, "/var/run/httpd-%d.pid", http_port);
2067
2068	if (!(pid_fp = fopen(pidfile, "w"))) {
2069		perror(pidfile);
2070		return errno;
2071	}
2072	fprintf(pid_fp, "%d", getpid());
2073	fclose(pid_fp);
2074
2075	/* Init connection pool */
2076	FD_ZERO(&active_rfds);
2077	TAILQ_INIT(&pool.head);
2078	pool.count = 0;
2079
2080	/* Loop forever handling requests */
2081	for (;;) {
2082		int max_fd, count;
2083		struct timeval tv;
2084		fd_set rfds;
2085		conn_item_t *item, *next;
2086
2087		memcpy(&rfds, &active_rfds, sizeof(rfds));
2088		max_fd = -1;
2089		if (pool.count < MAX_CONN_ACCEPT) {
2090			for (i = 0; i < ARRAY_SIZE(listen_fd); i++) {
2091				if (listen_fd[i] < 0)
2092					continue;
2093				FD_SET(listen_fd[i], &rfds);
2094				max_fd = max(listen_fd[i], max_fd);
2095			}
2096		}
2097		TAILQ_FOREACH(item, &pool.head, entry)
2098			max_fd = max(item->fd, max_fd);
2099
2100		/* Wait for new connection or incoming request */
2101		tv.tv_sec = MAX_CONN_TIMEOUT;
2102		tv.tv_usec = 0;
2103		while ((count = select(max_fd + 1, &rfds, NULL, NULL, &tv)) < 0 && errno == EINTR)
2104			continue;
2105		if (count < 0) {
2106			perror("select");
2107			return errno;
2108		}
2109
2110		/* Check and accept new connection */
2111		item = NULL;
2112		for (i = 0; count && i < ARRAY_SIZE(listen_fd); i++) {
2113			if (listen_fd[i] < 0 || !FD_ISSET(listen_fd[i], &rfds))
2114				continue;
2115
2116			item = malloc(sizeof(*item));
2117			if (item == NULL) {
2118				perror("malloc");
2119				return errno;
2120			}
2121			sz = sizeof(item->usa);
2122			while ((item->fd = accept(listen_fd[i], &item->usa.sa, &sz)) < 0 && errno == EINTR)
2123				continue;
2124			if (item->fd < 0) {
2125				perror("accept");
2126				free(item);
2127				continue;
2128			}
2129
2130			/* Set the KEEPALIVE option to cull dead connections */
2131			setsockopt(item->fd, SOL_SOCKET, SO_KEEPALIVE, &int_1, sizeof(int_1));
2132
2133			/* Add to active connections */
2134			FD_SET(item->fd, &active_rfds);
2135			TAILQ_INSERT_TAIL(&pool.head, item, entry);
2136			pool.count++;
2137		}
2138		/* Continue waiting over again */
2139		if (count && item)
2140			continue;
2141
2142		/* Check and process pending or expired requests */
2143		TAILQ_FOREACH_SAFE(item, &pool.head, entry, next) {
2144			if (count && !FD_ISSET(item->fd, &rfds))
2145				continue;
2146
2147			/* Delete from active connections */
2148			FD_CLR(item->fd, &active_rfds);
2149			TAILQ_REMOVE(&pool.head, item, entry);
2150			pool.count--;
2151
2152			/* Process request if any */
2153			if (count) {
2154#ifdef RTCONFIG_HTTPS
2155				if (do_ssl) {
2156					ssl_stream_fd = item->fd;
2157					if (!(conn_fp = ssl_server_fopen(item->fd))) {
2158						perror("fdopen(ssl)");
2159						goto skip;
2160					}
2161				} else
2162#endif
2163				if (!(conn_fp = fdopen(item->fd, "r+"))) {
2164					perror("fdopen");
2165					goto skip;
2166				}
2167
2168				http_login_cache(&item->usa);
2169				if (http_client_ip_check())
2170					handle_request();
2171				fflush(conn_fp);
2172#ifdef RTCONFIG_HTTPS
2173				if (!do_ssl)
2174#endif
2175				shutdown(item->fd, 2), item->fd = -1;
2176				fclose(conn_fp);
2177
2178			skip:
2179				/* Skip the rest of */
2180				if (--count == 0)
2181					next = NULL;
2182
2183			}
2184
2185			/* Close timed out and/or still alive */
2186			if (item->fd >= 0) {
2187				shutdown(item->fd, 2);
2188				close(item->fd);
2189			}
2190
2191			free(item);
2192		}
2193	}
2194
2195	for (i = 0; i < ARRAY_SIZE(listen_fd); i++) {
2196		if (listen_fd[i] < 0)
2197			continue;
2198		shutdown(listen_fd[i], 2);
2199		close(listen_fd[i]);
2200	}
2201
2202	return 0;
2203}
2204
2205#ifdef RTCONFIG_HTTPS
2206void save_cert(void)
2207{
2208	if (eval("tar", "-C", "/", "-czf", "/tmp/cert.tgz", "etc/cert.pem", "etc/key.pem") == 0) {
2209		if (nvram_set_file("https_crt_file", "/tmp/cert.tgz", 8192)) {
2210			nvram_commit_x();
2211		}
2212	}
2213	unlink("/tmp/cert.tgz");
2214}
2215
2216void erase_cert(void)
2217{
2218	unlink("/etc/cert.pem");
2219	unlink("/etc/key.pem");
2220	nvram_unset("https_crt_file");
2221	//nvram_unset("https_crt_gen");
2222	nvram_set("https_crt_gen", "0");
2223}
2224
2225void start_ssl(void)
2226{
2227	int ok;
2228	int save;
2229	int retry;
2230	unsigned long long sn;
2231	char t[32];
2232
2233	//fprintf(stderr,"[httpd] start_ssl running!!\n");
2234	//nvram_set("https_crt_gen", "1");
2235
2236	if (nvram_match("https_crt_gen", "1")) {
2237		erase_cert();
2238	}
2239
2240	retry = 1;
2241	while (1) {
2242		save = nvram_match("https_crt_save", "1");
2243
2244		if ((!f_exists("/etc/cert.pem")) || (!f_exists("/etc/key.pem"))) {
2245			ok = 0;
2246			if (save) {
2247				fprintf(stderr, "Save SSL certificate...\n"); // tmp test
2248				if (nvram_get_file("https_crt_file", "/tmp/cert.tgz", 8192)) {
2249					if (eval("tar", "-xzf", "/tmp/cert.tgz", "-C", "/", "etc/cert.pem", "etc/key.pem") == 0){
2250						system("cat /etc/key.pem /etc/cert.pem > /etc/server.pem");
2251						ok = 1;
2252					}
2253
2254					int save_intermediate_crt = nvram_match("https_intermediate_crt_save", "1");
2255					if(save_intermediate_crt){
2256						eval("tar", "-xzf", "/tmp/cert.tgz", "-C", "/", "etc/intermediate_cert.pem");
2257					}
2258
2259					unlink("/tmp/cert.tgz");
2260				}
2261			}
2262			if (!ok) {
2263				erase_cert();
2264				syslog(LOG_NOTICE, "Generating SSL certificate...");
2265				fprintf(stderr, "Generating SSL certificate...\n"); // tmp test
2266				// browsers seems to like this when the ip address moves...	-- zzz
2267				f_read("/dev/urandom", &sn, sizeof(sn));
2268
2269				sprintf(t, "%llu", sn & 0x7FFFFFFFFFFFFFFFULL);
2270				eval("gencert.sh", t);
2271			}
2272		}
2273
2274		if ((save) && (*nvram_safe_get("https_crt_file")) == 0) {
2275			save_cert();
2276		}
2277
2278		if (mssl_init("/etc/cert.pem", "/etc/key.pem")) return;
2279
2280		erase_cert();
2281
2282		if (!retry) exit(1);
2283		retry = 0;
2284	}
2285}
2286#endif
2287
2288