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
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 <arpa/inet.h>	// 2008.01 James.
43#include <sys/time.h>
44#include <assert.h>
45//#include <etioctl.h>
46
47#include <httpd.h>
48#include <bcmnvram.h>	// 2007.12 James.
49#include "shutils.h"
50
51#ifdef vxworks
52static void fcntl(int a, int b, int c) {}
53#include <signal.h>
54#include <ioLib.h>
55#include <sockLib.h>
56extern int snprintf(char *str, size_t count, const char *fmt, ...);
57extern int strcasecmp(const char *s1, const char *s2);
58extern int strncasecmp(const char *s1, const char *s2, size_t n);
59extern char *strsep(char **stringp, char *delim);
60#define socklen_t 		int
61#define main			milli
62#else
63#include <error.h>
64#include <sys/signal.h>
65#endif
66
67// Added by Joey for ethtool
68#include <net/if.h>
69#include "ethtool-util.h"
70#ifndef SIOCETHTOOL
71#define SIOCETHTOOL 0x8946
72#endif
73
74#define SIOCDEVPRIVATE  0x89F0
75#define ETCPHYRD        14
76//#define SIOCGETCPHYRD (SIOCDEVPRIVATE + ETCPHYRD)
77#define SIOCGETCPHYRD   0x89FE
78//#include "etioctl.h"
79
80#define SERVER_NAME "httpd"
81#define SERVER_PORT 80
82#define PROTOCOL "HTTP/1.0"
83#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
84
85/* A multi-family sockaddr. */
86typedef union {
87	struct sockaddr sa;
88	struct sockaddr_in sa_in;
89} usockaddr;
90
91/* Globals. */
92int conn_fd;
93FILE *conn_fp;
94static char auth_userid[AUTH_MAX];
95static char auth_passwd[AUTH_MAX];
96static char auth_realm[AUTH_MAX];
97#ifdef TRANSLATE_ON_FLY
98char Accept_Language[16];
99#endif //TRANSLATE_ON_FLY
100
101// 2009.05 James. {
102#ifdef DLM
103#include <disk_initial.h>
104
105disk_info_t *DISKS_INFO = NULL;
106#endif
107// 2009.05 James. }
108
109/* Forwards. */
110void http_login_timeout(unsigned int ip);
111void http_login(unsigned int ip, char *url);
112void http_logout(unsigned int ip);
113
114static int initialize_listen_socket( usockaddr* usaP );
115static int auth_check( char* dirname, char* authorization, char* url );
116static void send_authenticate( char* realm );
117static void send_error( int status, char* title, char* extra_header, char* text );
118static void send_headers( int status, char* title, char* extra_header, char* mime_type );
119static int b64_decode( const char* str, unsigned char* space, int size );
120static int match( const char* pattern, const char* string );
121static int match_one( const char* pattern, int patternlen, const char* string );
122static void handle_request(void);
123
124/* added by Joey */
125//int redirect = 1;
126int redirect = 0;	// 2008.01 James.
127int change_passwd = 0;	// 2008.03 James.
128int reget_passwd = 0;	// 2008.03 James.
129char url[4096];
130char wan_if[16];
131int http_port=SERVER_PORT;
132
133/* Added by Joey for handle one people at the same time */
134unsigned int login_ip = 0;	// the logined ip
135time_t login_timestamp = 0;	// the timestamp of the logined ip
136unsigned int login_ip_tmp = 0;	// the ip of the current session.
137unsigned int last_login_ip = 0;	// the last logined ip
138
139// 2007.11 James {
140time_t request_timestamp = 0;
141time_t turn_off_auth_timestamp = 0;
142int temp_turn_off_auth = 0;	// for QISxxx.htm pages
143// 2007.11 James }
144
145static int
146initialize_listen_socket( usockaddr* usaP )
147    {
148    int listen_fd;
149    int i;
150
151    memset( usaP, 0, sizeof(usockaddr) );
152    usaP->sa.sa_family = AF_INET;
153    usaP->sa_in.sin_addr.s_addr = htonl( INADDR_ANY );
154    usaP->sa_in.sin_port = htons( http_port );
155
156    listen_fd = socket( usaP->sa.sa_family, SOCK_STREAM, 0 );
157    if ( listen_fd < 0 )
158	{
159	perror( "socket" );
160	return -1;
161	}
162    (void) fcntl( listen_fd, F_SETFD, 1 );
163    i = 1;
164    if ( setsockopt( listen_fd, SOL_SOCKET, SO_REUSEADDR, (char*) &i, sizeof(i) ) < 0 )
165	{
166	perror( "setsockopt" );
167	return -1;
168	}
169    if ( bind( listen_fd, &usaP->sa, sizeof(struct sockaddr_in) ) < 0 )
170	{
171	perror( "bind" );
172	return -1;
173	}
174    if ( listen( listen_fd, 1024 ) < 0 )
175	{
176	perror( "listen" );
177	return -1;
178	}
179    return listen_fd;
180    }
181
182
183static int
184auth_check( char* dirname, char* authorization, char* url )
185{
186	char authinfo[500];
187	char* authpass;
188	int l;
189
190	/* Is this directory unprotected? */
191	if ( !strlen(auth_passwd) ){
192		/* Yes, let the request go through. */
193		return 1;
194	}
195
196	/* Basic authorization info? */
197	if (!authorization || strncmp( authorization, "Basic ", 6 ) != 0)
198	{
199		printf("### No authorization in http request with %s! ###\n", url);
200		send_authenticate(dirname);
201		if(login_ip != 0)	// 2007.11 James
202			http_logout(login_ip_tmp);
203
204		last_login_ip = 0;	// 2007.11 James
205
206		return 0;
207	}
208
209	/* Decode it. */
210	l = b64_decode( &(authorization[6]), authinfo, sizeof(authinfo) );
211	authinfo[l] = '\0';
212
213	/* Split into user and password. */
214	authpass = strchr( authinfo, ':' );
215	if ( authpass == (char*) 0 ) {
216		/* No colon?  Bogus auth info. */
217		printf("### No password information in http request! ###\n");
218		send_authenticate(dirname);
219		http_logout(login_ip_tmp);
220
221		return 0;
222	}
223	*authpass++ = '\0';
224
225	/* Is this the right user and password? */
226	if ( !strcmp( auth_userid, authinfo ) && !strcmp( auth_passwd, authpass ))
227	{
228		/* Is this the first login after logout */
229		if (login_ip == 0 && last_login_ip == login_ip_tmp)
230		{
231			printf("### After logout, The first login ip is the last login ip! ###\n");
232			send_authenticate(dirname);
233
234			last_login_ip = 0;
235
236			return 0;
237		}
238
239		return 1;
240	}
241
242	printf("### userid or password is wrong! ###\n");
243	send_authenticate(dirname);
244	http_logout(login_ip_tmp);
245
246	return 0;
247}
248
249static void
250send_authenticate(char* realm)
251{
252	char header[10000];
253
254	if(!strcmp(realm, "WL500gpv2"))
255		(void)snprintf(header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", "WL-500gP V2");
256	else if(!strcmp(realm, "WL520gu"))
257		(void)snprintf(header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", "WL-520GU");
258	else
259		(void)snprintf(header, sizeof(header), "WWW-Authenticate: Basic realm=\"%s\"", realm);
260
261	send_error(401, "Unauthorized", header, "Authorization required.");
262}
263
264static void
265send_error(int status, char* title, char* extra_header, char* text)
266{
267	send_headers(status, title, extra_header, "text/html");
268	(void)fprintf(conn_fp, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\n<BODY BGCOLOR=\"#cc9999\"><H4>%d %s</H4>\n", status, title, status, title);
269	(void)fprintf(conn_fp, "%s\n", text);
270	(void)fprintf(conn_fp, "</BODY></HTML>\n");
271	(void)fflush(conn_fp);
272}
273
274static void
275send_headers(int status, char* title, char* extra_header, char* mime_type)
276{
277	time_t now;
278	char timebuf[100];
279
280	(void)fprintf(conn_fp, "%s %d %s\r\n", PROTOCOL, status, title);
281	(void)fprintf(conn_fp, "Server: %s\r\n", SERVER_NAME);
282	now = time((time_t*)0);
283	(void)strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime( &now ));
284	(void)fprintf(conn_fp, "Date: %s\r\n", timebuf);
285
286	if(extra_header != (char*)0)
287		(void)fprintf(conn_fp, "%s\r\n", extra_header);
288
289	if(mime_type != (char*)0)
290		(void)fprintf(conn_fp, "Content-Type: %s\r\n", mime_type);
291
292	(void)fprintf(conn_fp, "Connection: close\r\n");
293	(void)fprintf(conn_fp, "\r\n");
294}
295
296/* Base-64 decoding.  This represents binary data as printable ASCII
297** characters.  Three 8-bit binary bytes are turned into four 6-bit
298** values, like so:
299**
300**   [11111111]  [22222222]  [33333333]
301**
302**   [111111] [112222] [222233] [333333]
303**
304** Then the 6-bit values are represented using the characters "A-Za-z0-9+/".
305*/
306
307static int b64_decode_table[256] = {
308    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
309    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
310    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
311    52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
312    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
313    15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
314    -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
315    41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
316    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
317    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
318    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
319    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
320    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
321    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
322    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
323    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
324    };
325
326/* Do base-64 decoding on a string.  Ignore any non-base64 bytes.
327** Return the actual number of bytes generated.  The decoded size will
328** be at most 3/4 the size of the encoded, and may be smaller if there
329** are padding characters (blanks, newlines).
330*/
331static int
332b64_decode( const char* str, unsigned char* space, int size )
333    {
334    const char* cp;
335    int space_idx, phase;
336    int d, prev_d=0;
337    unsigned char c;
338
339    space_idx = 0;
340    phase = 0;
341    for ( cp = str; *cp != '\0'; ++cp )
342	{
343	d = b64_decode_table[(int)*cp];
344	if ( d != -1 )
345	    {
346	    switch ( phase )
347		{
348		case 0:
349		++phase;
350		break;
351		case 1:
352		c = ( ( prev_d << 2 ) | ( ( d & 0x30 ) >> 4 ) );
353		if ( space_idx < size )
354		    space[space_idx++] = c;
355		++phase;
356		break;
357		case 2:
358		c = ( ( ( prev_d & 0xf ) << 4 ) | ( ( d & 0x3c ) >> 2 ) );
359		if ( space_idx < size )
360		    space[space_idx++] = c;
361		++phase;
362		break;
363		case 3:
364		c = ( ( ( prev_d & 0x03 ) << 6 ) | d );
365		if ( space_idx < size )
366		    space[space_idx++] = c;
367		phase = 0;
368		break;
369		}
370	    prev_d = d;
371	    }
372	}
373    return space_idx;
374    }
375
376
377/* Simple shell-style filename matcher.  Only does ? * and **, and multiple
378** patterns separated by |.  Returns 1 or 0.
379*/
380static int match(const char* pattern, const char* string){
381	const char* or;
382
383	for(;;){
384		or = strchr(pattern, '|');
385		if(or == (char*)0)
386			return match_one(pattern, strlen(pattern), string);
387
388		if(match_one(pattern, or-pattern, string))
389	    	return 1;
390
391		pattern = or+1;
392	}
393}
394
395static int match_one(const char* pattern, int patternlen, const char* string){
396	const char* p;
397
398	for(p = pattern; p-pattern < patternlen; ++p, ++string){
399		if(*p == '?' && *string != '\0')
400			continue;
401
402		if(*p == '*'){
403			int i, pl;
404
405			++p;
406			if(*p == '*'){
407				/* Double-wildcard matches anything. */
408				++p;
409				i = strlen(string);
410			}
411			else
412				/* Single-wildcard matches anything but slash. */
413				i = strcspn(string, "/");
414
415			pl = patternlen-(p-pattern);
416			for(; i >= 0; --i)
417				if(match_one(p, pl, &(string[i])))
418					return 1;
419
420			return 0;
421		}
422
423		if(*p != *string)
424			return 0;
425	}
426
427    if(*string == '\0')
428		return 1;
429
430	return 0;
431}
432
433void
434do_file(char *path, FILE *stream)
435{
436	FILE *fp;
437	int c;
438
439	if (!(fp = fopen(path, "r")))
440		return;
441	while ((c = getc(fp)) != EOF)
442		fputc(c, stream);
443	fclose(fp);
444}
445
446
447static void
448handle_request(void)
449{
450	char line[10000], *cur;
451	char *method, *path, *protocol, *authorization, *boundary, *alang;
452	char *cp;
453	char *file;
454	int len;
455	struct mime_handler *handler;
456	int cl = 0, flags;
457	//int notfirstSetting = (int)strtol(nvram_safe_get("x_Setting"), NULL, 10);
458	int firstSetting = is_firsttime(); // 2009.06 James.
459	int changed_http_passwd = (int)strtol(nvram_safe_get("changed_http_passwd"), NULL, 10);
460
461	/* Initialize the request variables. */
462	authorization = boundary = NULL;
463	bzero( line, sizeof line );
464
465	/* Parse the first line of the request. */
466	if ( fgets( line, sizeof(line), conn_fp ) == (char*) 0 ) {
467		send_error( 400, "Bad Request", (char*) 0, "No request found." );
468		return;
469	}
470
471	method = path = line;
472	strsep(&path, " ");
473	while (*path == ' ') path++;
474	protocol = path;
475
476	strsep(&protocol, " ");
477	while (*protocol == ' ') protocol++;
478	cp = protocol;
479
480	strsep(&cp, " ");
481	if ( !method || !path || !protocol ) {
482		send_error( 400, "Bad Request", (char*) 0, "Can't parse request." );
483		return;
484	}
485	cur = protocol + strlen(protocol) + 1;
486
487#ifdef TRANSLATE_ON_FLY
488	memset(Accept_Language, 0, sizeof(Accept_Language));
489#endif
490
491	/* Parse the rest of the request headers. */
492	while ( fgets( cur, line + sizeof(line) - cur, conn_fp ) != (char*) 0 )
493	{
494		if ( strcmp( cur, "\n" ) == 0 || strcmp( cur, "\r\n" ) == 0 ){
495			break;
496		}
497#ifdef TRANSLATE_ON_FLY
498		else if ( strncasecmp( cur, "Accept-Language:",16) ==0){
499			char *p;
500			struct language_table *pLang;
501			char lang_buf[256];
502			memset(lang_buf, 0, sizeof(lang_buf));
503			alang = &cur[16];
504			strcpy(lang_buf, alang);
505			p = lang_buf;
506			while(p != NULL)
507			{
508				p = strtok (p, "\r\n ,;");
509				if (p == NULL)  break;
510// 2008.11 James. {
511				int i, len = strlen(p);
512
513				for(i = 0; i < len; ++i)
514					if(isupper(p[i])){
515						p[i] = tolower(p[i]);
516					}
517// 2008.11 James. }
518				for (pLang = language_tables; pLang->Lang != NULL; ++pLang)
519				{
520					if(strcasecmp(p, pLang->Lang)==0)
521					{
522						snprintf(Accept_Language, sizeof(Accept_Language), "%s", pLang->Target_Lang);
523
524						//if(notfirstSetting != 1)
525						if(firstSetting == 1) // 2009.06 James.
526							nvram_set("preferred_lang", Accept_Language);
527
528						break;
529					}
530				}
531
532				if(Accept_Language[0] != 0){
533					break;
534				}
535
536				p+=strlen(p)+1;
537			}
538
539			if (Accept_Language[0] == 0)    {
540				// If all language setting of user's browser are not supported, use English.
541				printf ("Auto detect language failed. Use English.\n");
542				strcpy (Accept_Language, "EN");
543
544// 2008.07 James. {
545				//if(notfirstSetting != 1)
546				if(firstSetting == 1) // 2009.06 James.
547					nvram_set("preferred_lang", "EN");
548// 2008.07 James. }
549			}
550		}
551#endif
552		else if ( strncasecmp( cur, "Authorization:", 14 ) == 0 )
553		{
554			cp = &cur[14];
555			cp += strspn( cp, " \t" );
556			authorization = cp;
557			cur = cp + strlen(cp) + 1;
558		}
559		else if (strncasecmp( cur, "Content-Length:", 15 ) == 0) {
560			cp = &cur[15];
561			cp += strspn( cp, " \t" );
562			cl = strtoul( cp, NULL, 0 );
563		}
564		else if ((cp = strstr( cur, "boundary=" ))) {
565			boundary = &cp[9];
566			for( cp = cp + 9; *cp && *cp != '\r' && *cp != '\n'; cp++ );
567			*cp = '\0';
568			cur = ++cp;
569		}
570	}
571
572	if ( strcasecmp( method, "get" ) != 0 && strcasecmp(method, "post") != 0 ) {
573		send_error( 501, "Not Implemented", (char*) 0, "That method is not implemented." );
574		return;
575	}
576
577	if ( path[0] != '/' ) {
578		send_error( 400, "Bad Request", (char*) 0, "Bad filename." );
579		return;
580	}
581
582	file = &(path[1]);
583	len = strlen( file );
584	if ( file[0] == '/' || strcmp( file, ".." ) == 0 || strncmp( file, "../", 3 ) == 0 || strstr( file, "/../" ) != (char*) 0 || strcmp( &(file[len-3]), "/.." ) == 0 ) {
585		send_error( 400, "Bad Request", (char*) 0, "Illegal filename." );
586		return;
587	}
588
589	if(file[0] == '\0' || file[len-1] == '/')
590		file = "index.asp";
591
592// 2007.11 James. {
593	char *query;
594	int file_len;
595
596	memset(url, 0, 4096);
597	if((query = index(file, '?')) != NULL){
598		file_len = strlen(file)-strlen(query);
599
600		strncpy(url, file, file_len);
601	}
602	else
603		strcpy(url, file);
604/*if(strstr(url, ".htm") || strstr(url, ".asp"))
605	cprintf("url: %s.\n", url);//*/
606// 2007.11 James. }
607
608	http_login_timeout(login_ip_tmp);	// 2008.07 James.
609
610	if(http_port == SERVER_PORT && http_login_check() == 0){
611// 2007.11 James. {
612		/*struct in_addr login_ip_addr;
613		char *login_ip_str;
614
615		login_ip_addr.s_addr = login_ip;
616		login_ip_str = inet_ntoa(login_ip_addr);
617
618		sprintf(line, "Please log out user, %s, first or wait for session timeout(60 seconds).", login_ip_str);
619
620		printf("resposne: %s \n", line);
621		send_error( 200, "Request is rejected", (char*) 0, line);
622		return;//*/
623
624		if((strstr(url, ".htm") != NULL
625						&& !(!strcmp(url, "error_page.htm")
626								//|| (strstr(url, "QIS_") != NULL && !nvram_match("x_Setting", "1") && login_ip == 0)
627								|| (strstr(url, "QIS_") != NULL && changed_http_passwd != 1 && login_ip == 0)
628								|| !strcmp(url, "gotoHomePage.htm")
629								))
630				|| (strstr(url, ".asp") != NULL && login_ip != 0)){
631			file = "Nologin.asp";
632
633			memset(url, 0, 4096);
634			strcpy(url, file);
635		}
636// 2007.11 James. }
637	}
638
639	//2006_12_11_Roly
640	//check wan port connect status when change webpages
641	//is_connected();	// 2008.03 James. Be replaced by wanduck.
642
643	for(handler = &mime_handlers[0]; handler->pattern; handler++)
644	{
645// 2007.11 James. for the correct result of match(). {
646		//if (match(handler->pattern, file))
647		if(match(handler->pattern, url))
648// 2007.11 James. for the correct result of match(). }
649		{
650// 2007.11 James. for QISxxx.htm pages {
651			request_timestamp = time((time_t *)0);
652
653			int login_state = http_login_check();
654			if((login_state == 1 || login_state == 2)
655					//&& !nvram_match("x_Setting", "1")
656					&& changed_http_passwd != 1
657					&& (strstr(url, "QIS_") != NULL
658							|| !strcmp(url, "result_of_get_changed_status_QIS.asp")
659							|| !strcmp(url, "detectWAN.asp")
660							// to avoid the interference of the other logined browser. {
661							|| !strcmp(url, "result_of_get_changed_status.asp")
662							|| !strcmp(url, "WPS_info.asp")
663							|| !strcmp(url, "WAN_info.asp")
664							// }
665							|| !strcmp(url, "start_apply.htm")
666							|| !strcmp(url, "start_apply2.htm")
667							)
668					){
669				turn_off_auth_timestamp = request_timestamp;
670				temp_turn_off_auth = 1;
671				redirect = 0;
672			}
673			else if(!strcmp(url, "error_page.htm")
674					|| !strcmp(url, "Nologin.asp")
675					|| !strcmp(url, "gotoHomePage.htm")
676					){
677				;	// do nothing.
678			}
679			else if(login_state == 2
680					&& !strcmp(url, "Logout.asp")){
681				turn_off_auth_timestamp = 0;
682				temp_turn_off_auth = 0;
683				redirect = 1;
684			}
685			else if(strstr(url, ".asp") != NULL
686					|| strstr(url, ".cgi") != NULL
687					|| strstr(url, ".htm") != NULL
688					|| strstr(url, ".CFG") != NULL
689					){
690				switch(login_state){
691					case -1:
692						return;
693					case 0:
694						printf("System error! the url would be changed to Nologin.asp in this case!\n");
695						break;
696					case 1:
697						turn_off_auth_timestamp = 0;
698						temp_turn_off_auth = 0;
699						redirect = 0;
700						break;
701					case 2:
702						/*if(strcmp(url, "WPS_info.asp") ||
703									strcmp(url, "WAN_info.asp")){//*/
704							turn_off_auth_timestamp = 0;
705							temp_turn_off_auth = 0;
706						//}
707						redirect = 0;
708						break;
709					default:
710						printf("System error! the login_state is wrong!\n");
711				}
712			}
713			else if(login_state == 2
714					&& temp_turn_off_auth
715					&& (unsigned long)(request_timestamp-turn_off_auth_timestamp) > 10
716					){
717				http_logout(login_ip_tmp);
718				turn_off_auth_timestamp = 0;
719				temp_turn_off_auth = 0;
720				redirect = 0;
721			}
722
723			if(handler->auth){
724				if(!temp_turn_off_auth){
725					handler->auth(auth_userid, auth_passwd, auth_realm);
726					if(!auth_check(auth_realm, authorization, url))
727						return;
728				}
729
730				if(!redirect)
731					http_login(login_ip_tmp, url);
732			}
733
734			if(strcasecmp(method, "post") == 0 && !handler->input){
735				send_error(501, "Not Implemented", NULL, "That method is not implemented.");
736				return;
737			}
738// 2007.11 James. for QISxxx.htm pages }
739
740			if(handler->input){
741				handler->input(file, conn_fp, cl, boundary);
742#if defined(linux)
743				/*if((flags = fcntl(fileno(conn_fp), F_GETFL)) != -1 &&
744						fcntl(fileno(conn_fp), F_SETFL, flags | O_NONBLOCK) != -1){//*/
745				if((flags = fcntl(conn_fd, F_GETFL)) != -1 &&
746						fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK) != -1){//*/
747					/* Read up to two more characters */
748					if(fgetc(conn_fp) != EOF)
749						(void)fgetc(conn_fp);
750
751					//fcntl(fileno(conn_fp), F_SETFL, flags);
752					fcntl(conn_fd, F_SETFL, flags);
753				}
754#elif defined(vxworks)
755				flags = 1;
756				//if(ioctl(fileno(conn_fp), FIONBIO, (int) &flags) != -1){
757				if(ioctl(conn_fd, FIONBIO, (int) &flags) != -1){
758					/* Read up to two more characters */
759					if(fgetc(conn_fp) != EOF)
760						(void)fgetc(conn_fp);
761					flags = 0;
762					//ioctl(fileno(conn_fp), FIONBIO, (int) &flags);
763					ioctl(conn_fd, FIONBIO, (int) &flags);
764				}
765#endif
766			}
767
768			send_headers( 200, "Ok", handler->extra_header, handler->mime_type );
769			if(handler->output){
770				handler->output(file, conn_fp);
771			}
772
773			break;
774		}
775	}
776
777	if(!handler->pattern)
778		send_error( 404, "Not Found", (char*) 0, "File not found." );
779
780	if(!strcmp(file, "Logout.asp")){
781		http_logout(login_ip_tmp);
782	}
783
784	if(!strcmp(file, "Reboot.asp")){
785		system("reboot");
786	}
787}
788
789void http_login_cache(usockaddr *u){
790	struct in_addr temp_ip_addr;
791	char *temp_ip_str;
792
793	login_ip_tmp = (unsigned int)(u->sa_in.sin_addr.s_addr);
794	temp_ip_addr.s_addr = login_ip_tmp;
795	temp_ip_str = inet_ntoa(temp_ip_addr);
796}
797
798void http_login(unsigned int ip, char *url){
799	/*struct in_addr login_ip_addr;
800	char *login_ip_str;//*/
801
802	if(http_port != SERVER_PORT || ip == 0x100007f)
803		return;
804
805	login_ip = ip;
806	last_login_ip = 0;
807
808	/*login_ip_addr.s_addr = login_ip;
809	login_ip_str = inet_ntoa(login_ip_addr);//*/
810
811	if(strcmp(url, "result_of_get_changed_status.asp")
812			&& strcmp(url, "result_of_get_changed_status_QIS.asp")
813			&& strcmp(url, "WPS_info.asp")
814			&& strcmp(url, "WAN_info.asp"))
815		login_timestamp = time((time_t *)0);
816
817	/*char login_ipstr[32], login_timestampstr[32];
818
819	memset(login_ipstr, 0, 32);
820	sprintf(login_ipstr, "%u", login_ip);
821	nvram_set("login_ip", login_ipstr);
822
823	if(strcmp(url, "result_of_get_changed_status.asp")
824			&& strcmp(url, "result_of_get_changed_status_QIS.asp")
825			&& strcmp(url, "WPS_info.asp")
826			&& strcmp(url, "WAN_info.asp")){
827		memset(login_timestampstr, 0, 32);
828		sprintf(login_timestampstr, "%lu", login_timestamp);
829		nvram_set("login_timestamp", login_timestampstr);
830	}//*/
831}
832
833// -1: can not login, 0: not loginer, 1: can login, 2: loginer.
834int http_login_check(void){
835	if(http_port != SERVER_PORT || login_ip_tmp == 0x100007f)
836		//return 1;
837		return -1;	// 2008.01 James.
838
839	//http_login_timeout(login_ip_tmp);	// 2008.07 James.
840
841	if(login_ip == 0)
842		return 1;
843	else if(login_ip == login_ip_tmp)
844		return 2;
845
846	return 0;
847}
848
849void http_login_timeout(unsigned int ip)
850{
851	time_t now;
852
853	time(&now);
854
855// 2007.10 James. for really logout. {
856	//if (login_ip!=ip && (unsigned long)(now-login_timestamp) > 60) //one minitues
857	if((login_ip != 0 && login_ip != ip) && (unsigned long)(now-login_timestamp) > 60) //one minitues
858// 2007.10 James }
859	{
860		http_logout(login_ip);
861	}
862}
863
864void http_logout(unsigned int ip){
865	if(ip == login_ip){
866		last_login_ip = login_ip;
867		login_ip = 0;
868		login_timestamp = 0;
869
870		/*nvram_set("login_ip", "");
871		nvram_set("login_timestamp", "");//*/
872
873// 2008.03 James. {
874		if(change_passwd == 1){
875			change_passwd = 0;
876			reget_passwd = 1;
877		}
878// 2008.03 James. }
879	}
880}
881
882int is_auth(void)
883{
884	if(http_port == SERVER_PORT || !strcmp(nvram_get_x("PrinterStatus", "usb_webhttpcheck_x"), "1"))
885		return 1;
886	else
887		return 0;
888}
889
890int is_phyconnected(void){
891	int fd, err;
892	struct ifreq ifr;
893	struct ethtool_cmd ecmd;
894	int flag;
895
896	memset(&ifr, 0, sizeof(ifr));
897
898	strcpy(ifr.ifr_name, wan_if);
899
900	fd = socket(AF_INET, SOCK_DGRAM, 0);
901	if(fd < 0){
902		//printf("fd error\n");
903		return 0;
904	}
905
906	ecmd.cmd = ETHTOOL_GSET;
907	ifr.ifr_data = (caddr_t)&ecmd;
908	err = ioctl(fd, SIOCETHTOOL, (void*)&ifr);
909	if(err == 0){
910		char tmpstr[60];
911		flag = 0;
912
913#ifdef CDMA
914		if(!nvram_match("hsdpa_product", "")) // HSDPA
915			flag = 1;
916#endif
917		//2006_06_16_Roly
918		//detect wan port(eth1) connection
919		int vecarg[2];
920		int verbuf;
921
922		vecarg[0] = strtoul("0x01", NULL, 0) << 16;
923		vecarg[0] |= strtoul("0x00", NULL, 0) & 0xffff;
924
925		sprintf(tmpstr, "0x%04x\n", vecarg[1]);
926
927		ifr.ifr_data = (caddr_t) vecarg;
928		if(ioctl(fd, SIOCGETCPHYRD, (caddr_t)&ifr) < 0)
929			printf("etcphyrd error\n");
930		close(fd);
931
932		verbuf = vecarg[1];
933
934#ifdef WL500GPV2
935		if((verbuf&0x0010) != 0)
936#elif WL520GU
937		if((verbuf&0x0001) != 0)
938#else
939		if((verbuf&0x0000) != 0)
940#endif
941			flag = 1;
942
943		if(!flag){
944			nvram_set("wan_status_t", "Disconnected");
945			nvram_set("wan_reason_t", "Cable is not attached");
946		}
947		else if(!strcmp(nvram_get_x("", "wan_status_t"), "Disconnected") && strcmp(nvram_get_x("", "wan_ipaddr_t"), "")){
948			nvram_set("wan_status_t", "Connected");
949		}
950
951		return flag;
952	}
953	else{
954		close(fd);
955		//printf("err error\n");
956		return 0;
957	}
958}
959
960int is_fileexist(char *filename)
961{
962	FILE *fp;
963
964	fp=fopen(filename, "r");
965
966	if (fp==NULL) return 0;
967	fclose(fp);
968	return 1;
969}
970
971#if 0
972int is_connected(void){
973	FILE *fp;
974	char line[128], *reason;
975
976	/* check if physical connection exist */
977	if(!is_phyconnected())
978		return 0;
979
980	/* check if connection static is CONNECTED */
981	if(!strcmp(nvram_get_x("WANIPAddress", "wan_status_t"), "Disconnected")){
982		fp = fopen("/tmp/wanstatus.log", "r");
983		if(fp != NULL){
984			fgets(line, sizeof(line), fp);
985			reason = strchr(line, ',');
986			if(reason != NULL)
987				nvram_set("wan_reason_t", reason+1);
988			fclose(fp);
989		}
990
991		return 0;
992	}
993
994	return 1;
995}
996#endif
997
998int firsttime = -1; // 2009.06 James.
999
1000int is_firsttime(void)
1001{
1002	/*if(!strcmp(nvram_get_x("General", "x_Setting"), "1"))
1003		return 0;
1004	else
1005		return 1;//*/
1006	//static int firsttime = -1; // 2009.06 James.
1007
1008	if(firsttime == -1){
1009		if(!strcmp(nvram_get_x("General", "x_Setting"), "1"))
1010			firsttime = 0;
1011		else
1012			firsttime = 1;
1013	}
1014
1015	return firsttime;
1016}
1017
1018#ifdef TRANSLATE_ON_FLY
1019int
1020load_dictionary (char *lang, pkw_t pkw)
1021{
1022        char dfn[16];
1023        char *p, *q;
1024        FILE *dfp = NULL;
1025        int dict_size = 0;
1026        struct timeval tv1, tv2;
1027        const char *eng_dict = "EN.dict";
1028#ifndef RELOAD_DICT
1029        static char loaded_dict[12] = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
1030#endif  // RELOAD_DICT
1031
1032        gettimeofday (&tv1, NULL);
1033        if (lang == NULL || (lang != NULL && strlen (lang) == 0))       {
1034                // if "lang" is invalid, use English as default
1035                snprintf (dfn, sizeof (dfn), eng_dict);
1036        } else {
1037                snprintf (dfn, sizeof (dfn), "%s.dict", lang);
1038        }
1039
1040#ifndef RELOAD_DICT
1041        //printf ("loaded_dict (%s) v.s. dfn (%s)\n", loaded_dict, dfn);
1042        if (strcmp (dfn, loaded_dict) == 0)     {
1043                return 1;
1044        }
1045        release_dictionary (pkw);
1046#endif  // RELOAD_DICT
1047
1048        do      {
1049                 printf("Open (%s) dictionary file.\n", dfn);
1050                dfp = fopen (dfn, "r");
1051                if (dfp != NULL)        {
1052#ifndef RELOAD_DICT
1053                        snprintf (loaded_dict, sizeof (loaded_dict), "%s", dfn);
1054#endif  // RELOAD_DICT
1055                        break;
1056                }
1057
1058                printf ("Open (%s) failure. errno %d (%s)\n", dfn, errno, strerror (errno));
1059                if (dfp == NULL && strcmp (dfn, eng_dict) == 0) {
1060                        return 0;
1061                } else {
1062                        // If we can't open specified language file, use English as default
1063                        snprintf (dfn, sizeof (dfn), eng_dict);
1064			nvram_set("preferred_lang", "EN");
1065                }
1066        } while (1);
1067
1068        memset (pkw, 0, sizeof (kw_t));
1069        fseek (dfp, 0L, SEEK_END);
1070        dict_size = ftell (dfp) + 128;
1071        printf ("dict_size %d\n", dict_size);
1072        REALLOC_VECTOR (pkw->idx, pkw->len, pkw->tlen, sizeof (unsigned char*));
1073        pkw->buf = q = malloc (dict_size);
1074
1075        fseek (dfp, 0L, SEEK_SET);
1076        while (!feof (dfp))     {
1077                // if pkw->idx is not enough, add 32 item to pkw->idx
1078                REALLOC_VECTOR (pkw->idx, pkw->len, pkw->tlen, sizeof (unsigned char*));
1079
1080                fscanf (dfp, "%[^\n]%*c", q);
1081                if ((p = strchr (q, '=')) != NULL)      {
1082                        pkw->idx[pkw->len] = q;
1083                        pkw->len++;
1084                        q = p + strlen (p);
1085                        *q = '\0';
1086                        q++;
1087                }
1088        }
1089
1090        fclose (dfp);
1091        gettimeofday (&tv2, NULL);
1092         printf("Load %d keywords spent %ldms\n", pkw->len, ((tv2.tv_sec * 1000000 + tv2.tv_usec) - (tv1.tv_sec * 1000000 + tv1.tv_usec)) / 1000);
1093
1094        return 1;
1095}
1096
1097
1098void
1099release_dictionary (pkw_t pkw)
1100{
1101        if (pkw == NULL)        {
1102                return;
1103        }
1104
1105        pkw->len = pkw->tlen = 0;
1106
1107        if (pkw->idx != NULL)   {
1108                free (pkw->idx);
1109                pkw->idx = NULL;
1110        }
1111
1112        if (pkw->buf != NULL)   {
1113                free (pkw->buf);
1114                pkw->buf = NULL;
1115        }
1116}
1117
1118char*
1119search_desc (pkw_t pkw, char *name)
1120{
1121        int i;
1122        char *p, *ret = NULL;
1123
1124        if (pkw == NULL || (pkw != NULL && pkw->len <= 0))      {
1125                return NULL;
1126        }
1127        for (i = 0; i < pkw->len; ++i)  {
1128                p = pkw->idx[i];
1129                if (strncmp (name, p, strlen (name)) == 0)      {
1130                        ret = p + strlen (name);
1131                        break;
1132                }
1133        }
1134
1135        return ret;
1136}
1137#endif //TRANSLATE_ON_FLY
1138
1139
1140
1141int main(int argc, char **argv)
1142{
1143	usockaddr usa;
1144	int listen_fd;
1145	//int conn_fd;
1146	socklen_t sz = sizeof(usa);
1147	char pidfile[32];
1148
1149	// Added by Joey for handling WAN Interface
1150	// usage: httpd [wan interface] [port]
1151	if(argc > 2)
1152		http_port = atoi(argv[2]);
1153
1154	if(argc > 1)
1155		strcpy(wan_if, argv[1]);
1156	else
1157		strcpy(wan_if, "");
1158
1159	//websSetVer();
1160
1161	// 2008.03 James.
1162	/*nvram_unset("login_timestamp");
1163	nvram_unset("login_ip");//*/
1164
1165	/* Ignore broken pipes */
1166	signal(SIGPIPE, SIG_IGN);
1167
1168	/* Initialize listen socket */
1169	if ((listen_fd = initialize_listen_socket(&usa)) < 0) {
1170		fprintf(stderr, "can't bind to any address\n" );
1171		exit(errno);
1172	}
1173
1174#if !defined(DEBUG) && !defined(vxworks)
1175	{
1176	FILE *pid_fp;
1177	/* Daemonize and log PID */
1178	//if (http_port==SERVER_PORT)
1179	//{
1180		if (daemon(1, 1) == -1)
1181		{
1182			perror("daemon");
1183			exit(errno);
1184		}
1185	//}
1186	if (http_port==SERVER_PORT)
1187		strcpy(pidfile, "/var/run/httpd.pid");
1188	else sprintf(pidfile, "/var/run/httpd-%d.pid", http_port);
1189
1190	if (!(pid_fp = fopen(pidfile, "w"))) {
1191		perror(pidfile);
1192		return errno;
1193	}
1194	fprintf(pid_fp, "%d", getpid());
1195	fclose(pid_fp);
1196	}
1197#endif
1198
1199	/* Loop forever handling requests */
1200	for (;;) {
1201		if ((conn_fd = accept(listen_fd, &usa.sa, &sz)) < 0) {
1202			perror("accept");
1203			return errno;
1204		}
1205		if (!(conn_fp = fdopen(conn_fd, "r+"))) {
1206			perror("fdopen");
1207			return errno;
1208		}
1209
1210		http_login_cache(&usa);
1211
1212		handle_request();
1213		fflush(conn_fp);
1214		fclose(conn_fp);
1215		close(conn_fd);
1216
1217#ifdef DLM
1218		if(DISKS_INFO != NULL)
1219			free_disk_data(&DISKS_INFO); // 2009.05 James.
1220#endif
1221	}
1222
1223	shutdown(listen_fd, 2);
1224	close(listen_fd);
1225
1226	return 0;
1227}
1228