• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/lighttpd-1.4.39/src/
1#include "base.h"
2#include "log.h"
3#include "buffer.h"
4
5#include "plugin.h"
6
7#include <ctype.h>
8#include <stdlib.h>
9#include <string.h>
10#include <dlinklist.h>
11#include "md5.h"
12
13#if EMBEDDED_EANBLE
14#ifndef APP_IPKG
15#include "disk_share.h"
16#endif
17#endif
18
19#define DBE 1
20
21typedef struct {
22	array *access_deny;
23	array *auth_deny;
24
25#if 0
26	int loglevel;
27    buffer *name;    // cookie name to extract auth info
28    int override;    // how to handle incoming Auth header
29    buffer *authurl; // page to go when unauthorized
30    buffer *key;     // key for cookie verification
31    int timeout;     // life duration of last-stage auth token
32    buffer *options; // options for last-stage auth token cookie
33#endif
34
35} plugin_config;
36
37typedef struct {
38	PLUGIN_DATA;
39
40	plugin_config **config_storage;
41
42	plugin_config conf;
43
44	buffer *tmp_buf;
45
46	//smb_info_t *smb_info_list;
47
48#if 0
49	array *users;
50#endif
51
52} plugin_data;
53
54#if 0
55#define HEADER(con, key)                                                \
56    (data_string *)array_get_element((con)->request.headers, (key))
57
58#define MD5_LEN 16
59
60/**********************************************************************
61 * supporting functions
62 **********************************************************************/
63
64//
65// helper to generate "configuration in current context".
66//
67static plugin_config *
68merge_config(server *srv, connection *con, plugin_data *pd) {
69#define PATCH(x) pd->conf.x = pc->x
70#define MATCH(k) if (buffer_is_equal_string(du->key, CONST_STR_LEN(k)))
71#define MERGE(k, x) MATCH(k) PATCH(x)
72
73    size_t i, j;
74    plugin_config *pc = pd->config_storage[0]; // start from global context
75
76    // load initial config in global context
77    PATCH(loglevel);
78    PATCH(name);
79    PATCH(override);
80    PATCH(authurl);
81    PATCH(key);
82    PATCH(timeout);
83    PATCH(options);
84
85    // merge config from sub-contexts
86    for (i = 1; i < srv->config_context->used; i++) {
87        data_config *dc = (data_config *)srv->config_context->data[i];
88
89        // condition didn't match
90        if (! config_check_cond(srv, con, dc)) continue;
91
92        // merge config
93        pc = pd->config_storage[i];
94        for (j = 0; j < dc->value->used; j++) {
95            data_unset *du = dc->value->data[j];
96
97            // describe your merge-policy here...
98            MERGE("auth-ticket.loglevel", loglevel);
99            MERGE("auth-ticket.name", name);
100            MERGE("auth-ticket.override", override);
101            MERGE("auth-ticket.authurl", authurl);
102            MERGE("auth-ticket.key", key);
103            MERGE("auth-ticket.timeout", timeout);
104            MERGE("auth-ticket.options", options);
105        }
106    }
107    return &(pd->conf);
108#undef PATCH
109#undef MATCH
110#undef MERGE
111}
112
113//
114// fills (appends) given buffer with "current" URL.
115//
116static buffer *
117self_url(connection *con, buffer *url, buffer_encoding_t enc) {
118    buffer_append_string_encoded(url, CONST_BUF_LEN(con->uri.scheme), enc);
119    buffer_append_string_encoded(url, CONST_STR_LEN("://"), enc);
120    buffer_append_string_encoded(url, CONST_BUF_LEN(con->uri.authority), enc);
121    buffer_append_string_encoded(url, CONST_BUF_LEN(con->request.uri), enc);
122    return url;
123}
124
125//
126// Generates appropriate response depending on policy.
127//
128static handler_t
129endauth2(server *srv, connection *con, plugin_config *pc) {
130    // pass through if no redirect target is specified
131    if (buffer_is_empty(pc->authurl)) {
132        Cdbg(DBE, "endauth - continuing");
133        return HANDLER_GO_ON;
134    }
135    Cdbg(DBE, "endauth - redirecting:%s", pc->authurl->ptr);
136
137    // prepare redirection header
138    buffer *url = buffer_init_buffer(pc->authurl);
139    buffer_append_string(url, strchr(url->ptr, '?') ? "&url=" : "?url=");
140    self_url(con, url, ENCODING_REL_URI);
141    response_header_insert(srv, con,
142                           CONST_STR_LEN("Location"), CONST_BUF_LEN(url));
143    buffer_free(url);
144
145    // prepare response
146    con->http_status = 307;
147    con->mode = DIRECT;
148    con->file_finished = 1;
149
150    return HANDLER_FINISHED;
151}
152
153static handler_t
154endauth(server *srv, connection *con, plugin_config *pc) {
155    // prepare response
156    con->http_status = 401;
157    con->mode = DIRECT;
158    con->file_finished = 1;
159
160    return HANDLER_FINISHED;
161}
162
163
164inline static int
165min(int a, int b) {
166    return a > b ? b : a;
167}
168
169// generate hex-encoded random string
170static int
171gen_random(buffer *b, int len) {
172    buffer_string_prepare_append(b, len);
173    while (len--) {
174        char c = int2hex(rand() >> 24);
175        buffer_append_string_len(b, &c, 1);
176    }
177    return 0;
178}
179
180// encode bytes into hexstring
181static int
182hex_encode(buffer *b, const uint8_t *s, int len) {
183    buffer_copy_string_hex(b, (const char *)s, len);
184	return 0;
185}
186
187// decode hexstring into bytes
188static int
189hex_decode(buffer *b, const char *s) {
190    char c0, c1;
191
192    buffer_string_prepare_append(b, strlen(s) >> 1);
193    while ((c0 = *s++) && (c1 = *s++)) {
194        char v = (hex2int(c0) << 4) | hex2int(c1);
195        buffer_append_string_len(b, &v, 1);
196    }
197    return 0;
198}
199
200// XOR-based encryption
201static int
202decrypt(buffer *buf, uint8_t *key, int keylen) {
203    int i;
204
205    for (i = buf->used - 1; i >= 0; i--) {
206        buf->ptr[i] ^= (i > 0 ? buf->ptr[i - 1] : 0) ^ key[i % keylen];
207
208        // sanity check - result should be base64-encoded authinfo
209        if (! isprint(buf->ptr[i])) {
210            return -1;
211        }
212    }
213    return 0;
214}
215
216//
217// update header using (verified) authentication info.
218//
219static void
220update_header(server *srv, connection *con,
221              plugin_data *pd, plugin_config *pc, buffer *authinfo) {
222    buffer *field, *token;
223
224    //DEBUG("sb", "decrypted authinfo:", authinfo);
225
226    // insert auth header
227    field = buffer_init_string("Basic ");
228
229    //rescbr: bugfix: authinfo does not end with \0
230    buffer_append_string_len(field, authinfo->ptr, authinfo->used);
231    array_set_key_value(con->request.headers,
232                        CONST_STR_LEN("Authorization"), CONST_BUF_LEN(field));
233
234    // generate random token and relate it with authinfo
235    gen_random(token = buffer_init(), MD5_LEN * 2); // length in hex string
236    Cdbg(DBE, "pairing authinfo with token:%s", token->ptr);
237    buffer_copy_int(field, time(NULL));
238    buffer_append_string(field, ":");
239
240    //rescbr: bugfix: authinfo does not end with \0
241    buffer_append_string_len(field, authinfo->ptr, authinfo->used);
242    array_set_key_value(pd->users, CONST_BUF_LEN(token), CONST_BUF_LEN(field));
243
244    // insert opaque auth token
245    buffer_copy_buffer(field, pc->name);
246    buffer_append_string(field, "=token:");
247    buffer_append_string_buffer(field, token);
248    buffer_append_string(field, "; ");
249    buffer_append_string_buffer(field, pc->options);
250    Cdbg(DBE, "generating token cookie:%s", field->ptr);
251    response_header_append(srv, con,
252                           CONST_STR_LEN("Set-Cookie"), CONST_BUF_LEN(field));
253
254    // update REMOTE_USER field
255    base64_decode(field, authinfo->ptr);
256    char *pw = strchr(field->ptr, ':'); *pw = '\0';
257    Cdbg(DBE, "identified username:%s", field->ptr);
258
259#if 0
260#if LIGHTTPD_VERSION_ID < VER_ID(1, 4, 33)
261    buffer_copy_string_len(con->authed_user, field->ptr, strlen(field->ptr));
262#else
263    data_string *ds;
264    if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
265        if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
266            ds = data_string_init();
267        }
268        buffer_copy_string(ds->key, "REMOTE_USER");
269        array_insert_unique(con->environment, (data_unset *)ds);
270    }
271    buffer_copy_string_len(ds->value, field->ptr, strlen(field->ptr));
272#endif
273#else
274	data_string *ds;
275    if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
276        if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
277            ds = data_string_init();
278        }
279        buffer_copy_string(ds->key, "REMOTE_USER");
280        array_insert_unique(con->environment, (data_unset *)ds);
281    }
282    buffer_copy_string_len(ds->value, field->ptr, strlen(field->ptr));
283#endif
284
285    buffer_free(field);
286    buffer_free(token);
287}
288
289//
290// Handle token given in cookie.
291//
292// Expected Cookie Format:
293//   <name>=token:<random-token-to-be-verified>
294//
295static handler_t
296handle_token(server *srv, connection *con,
297             plugin_data *pd, plugin_config *pc, char *token) {
298    data_string *entry =
299        (data_string *)array_get_element(pd->users, token);
300
301    // Check for existence
302    if (! entry) return endauth(srv, con, pc);
303
304    Cdbg(DBE, "found token entry:%s", entry->value->ptr);
305
306    // Check for timeout
307    time_t t0 = time(NULL);
308    time_t t1 = strtol(entry->value->ptr, NULL, 10);
309    Cdbg(DBE, "t0: %d, t1: %d, timeout: %d", t0, t1, pc->timeout);
310    if (t0 - t1 > pc->timeout) return endauth(srv, con, pc);
311
312    // Check for existence of actual authinfo
313    char *authinfo = strchr(entry->value->ptr, ':');
314    if (! authinfo) return endauth(srv, con, pc);
315
316    // All passed. Inject as BasicAuth header
317    buffer *field = buffer_init_string("Basic ");
318    buffer_append_string(field, authinfo + 1);
319    array_set_key_value(con->request.headers,
320                        CONST_STR_LEN("Authorization"), CONST_BUF_LEN(field));
321
322    // update REMOTE_USER field
323    base64_decode(field, authinfo + 1);
324    char *pw = strchr(field->ptr, ':'); *pw = '\0';
325    Cdbg(DBE, "identified user:", field->ptr);
326
327#if 0
328#if LIGHTTPD_VERSION_ID < VER_ID(1, 4, 33)
329    buffer_copy_string_len(con->authed_user, field->ptr, strlen(field->ptr));
330#else
331    data_string *ds;
332    if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
333        if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
334            ds = data_string_init();
335        }
336        buffer_copy_string(ds->key, "REMOTE_USER");
337        array_insert_unique(con->environment, (data_unset *)ds);
338    }
339    buffer_copy_string_len(ds->value, field->ptr, strlen(field->ptr));
340#endif
341#else
342	data_string *ds;
343    if (NULL == (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER"))) {
344        if (NULL == (ds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
345            ds = data_string_init();
346        }
347        buffer_copy_string(ds->key, "REMOTE_USER");
348        array_insert_unique(con->environment, (data_unset *)ds);
349    }
350    buffer_copy_string_len(ds->value, field->ptr, strlen(field->ptr));
351#endif
352
353    buffer_free(field);
354
355    Cdbg(DBE, "all check passed");
356    return HANDLER_GO_ON;
357}
358
359//
360// Check for redirected auth request in cookie.
361//
362// Expected Cookie Format:
363//   <name>=crypt:<hash>:<data>
364//
365//   hash    = hex(MD5(key + timesegment + data))
366//   data    = hex(encrypt(MD5(timesegment + key), payload))
367//   payload = base64(username + ":" + password)
368//
369static handler_t
370handle_crypt(server *srv, connection *con,
371             plugin_data *pd, plugin_config *pc, char *line) {
372    li_MD5_CTX ctx;
373    uint8_t hash[MD5_LEN];
374    char    tmp[256];
375
376    // Check for existence of data part
377    char *data = strchr(line, ':');
378    if (! data) return endauth(srv, con, pc);
379
380    Cdbg(DBE, "verifying crypt cookie...data=%s", data);
381
382    // Verify signature.
383    // Also, find time segment when this auth request was encrypted.
384    time_t t1, t0 = time(NULL);
385    buffer *buf = buffer_init();
386    for (t1 = t0 - (t0 % 5); t0 - t1 < 10; t1 -= 5) {
387        Cdbg(DBE, "t0: %d, t1: %d", t0, t1);
388
389        // compute hash for this time segment
390        sprintf(tmp, "%lu", t1);
391        li_MD5_Init(&ctx);
392        li_MD5_Update(&ctx, CONST_BUF_LEN(pc->key));
393        li_MD5_Update(&ctx, tmp, strlen(tmp));
394        li_MD5_Update(&ctx, data + 1, strlen(data + 1));
395        li_MD5_Final(hash, &ctx);
396        hex_encode(buf, hash, sizeof(hash));
397
398        Cdbg(DBE, "computed hash: %s", buf->ptr);
399
400        // verify by comparing hash
401        if (strncasecmp(buf->ptr, line, data - line) == 0) {
402            break; // hash verified and time segment found
403        }
404    }
405    buffer_free(buf);
406
407    // Has this found time segment expired?
408    if (! (t0 - t1 < 10)) {
409        Cdbg(DBE, "timeout detected");
410        return endauth(srv, con, pc);
411    }
412
413    Cdbg(DBE, "timeout check passed");
414
415    // compute temporal encryption key (= MD5(t1, key))
416    sprintf(tmp, "%lu", t1);
417    li_MD5_Init(&ctx);
418    li_MD5_Update(&ctx, tmp, strlen(tmp));
419    li_MD5_Update(&ctx, CONST_BUF_LEN(pc->key));
420    li_MD5_Final(hash, &ctx);
421
422    // decrypt
423    hex_decode(buf = buffer_init(), data + 1);
424    if (decrypt(buf, hash, sizeof(hash)) != 0) {
425        Cdbg(DBE, "decryption error");
426
427        buffer_free(buf);
428        return endauth(srv, con, pc);
429    }
430
431    // update header using decrypted authinfo
432    update_header(srv, con, pd, pc, buf);
433
434    buffer_free(buf);
435    return HANDLER_GO_ON;
436}
437#endif
438
439/**********************************************************************
440 * module interface
441 **********************************************************************/
442
443INIT_FUNC(mod_aicloud_auth_init) {
444	plugin_data *p;
445
446	p = calloc(1, sizeof(*p));
447
448#if 0
449	p->users = array_init();
450#endif
451
452	return p;
453}
454
455FREE_FUNC(mod_aicloud_auth_free) {
456	plugin_data *p = p_d;
457
458	UNUSED(srv);
459
460	if (!p) return HANDLER_GO_ON;
461
462#if 0
463	// Free plugin data
464    array_free(p->users);
465#endif
466
467	if (p->config_storage) {
468		size_t i;
469		for (i = 0; i < srv->config_context->used; i++) {
470			plugin_config *s = p->config_storage[i];
471
472			array_free(s->access_deny);
473			array_free(s->auth_deny);
474
475#if 0
476			// free configuration
477            buffer_free(s->name);
478            buffer_free(s->authurl);
479            buffer_free(s->key);
480#endif
481
482			free(s);
483		}
484		free(p->config_storage);
485	}
486
487	free(p);
488
489	return HANDLER_GO_ON;
490}
491
492SETDEFAULTS_FUNC(mod_aicloud_auth_set_defaults) {
493	plugin_data *p = p_d;
494	size_t i = 0;
495
496	config_values_t cv[] = {
497		{ "url.access-deny",             NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
498		{ "url.aicloud-auth-deny",       NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
499#if 0
500		{ "auth-ticket.loglevel",        NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
501		{ "auth-ticket.name",            NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
502		{ "auth-ticket.override",        NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
503		{ "auth-ticket.authurl",         NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
504		{ "auth-ticket.key",             NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
505		{ "auth-ticket.timeout",         NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },
506		{ "auth-ticket.options",         NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
507#endif
508		{ NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
509	};
510
511	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
512
513	for (i = 0; i < srv->config_context->used; i++) {
514		plugin_config *s;
515
516		s = calloc(1, sizeof(plugin_config));
517		s->access_deny    = array_init();
518		s->auth_deny      = array_init();
519
520#if 0
521		s->loglevel = 1;
522        s->name     = buffer_init();
523        s->override = 2;
524        s->authurl  = buffer_init();
525        s->key      = buffer_init();
526        s->timeout  = 86400;
527        s->options  = buffer_init();
528#endif
529
530		cv[0].destination = s->access_deny;
531		cv[1].destination = s->auth_deny;
532
533#if 0
534		cv[2].destination = &(s->loglevel);
535        cv[3].destination = s->name;
536        cv[4].destination = &(s->override);
537        cv[5].destination = s->authurl;
538        cv[6].destination = s->key;
539        cv[7].destination = &(s->timeout);
540        cv[8].destination = s->options;
541#endif
542
543		p->config_storage[i] = s;
544
545		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
546			return HANDLER_ERROR;
547		}
548	}
549
550	return HANDLER_GO_ON;
551}
552
553static void aicloud_check_direct_file(server *srv, connection *con)
554{
555	config_values_t cv[] = {
556		{ "alias.url",		NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
557		{ NULL,             NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
558	};
559
560	size_t i, j;
561	for (i = 1; i < srv->config_context->used; i++) {
562		int found = 0;
563		array* alias = array_init();
564		cv[0].destination = alias;
565
566		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
567			continue;
568		}
569
570		for (j = 0; j < alias->used; j++) {
571			data_string *ds = (data_string *)alias->data[j];
572
573			if( strncmp(con->request.uri->ptr, ds->key->ptr, ds->key->used-1) == 0 ){
574				con->mode = DIRECT;
575				found = 1;
576				break;
577			}
578		}
579
580		array_free(alias);
581
582		if(found==1)
583			break;
584	}
585}
586
587#define PATCH(x) \
588	p->conf.x = s->x;
589
590static int check_aicloud_auth_url(server *srv, connection *con, plugin_data *p){
591	smb_info_t *c;
592	int i, j, k;
593	plugin_config *s;
594
595	/* skip the first, the global context */
596	for (i = 1; i < srv->config_context->used; i++) {
597		data_config *dc = (data_config *)srv->config_context->data[i];
598		s = p->config_storage[i];
599
600		/* condition didn't match */
601		if (!config_check_cond(srv, con, dc)) continue;
602
603		/* merge config */
604		for (j = 0; j < dc->value->used; j++) {
605			data_unset *du = dc->value->data[j];
606
607			if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.aicloud-auth-deny"))) {
608				PATCH(auth_deny);
609			}
610		}
611	}
612
613	if(p->conf.auth_deny){
614
615		for (k = 0; k < p->conf.auth_deny->used; k++) {
616			data_string *ds = (data_string *)p->conf.auth_deny->data[k];
617
618			if (ds->value->used == 0) continue;
619
620			if (strstr(con->uri.path->ptr, ds->value->ptr)) {
621
622				data_string *ds_user_agent = (data_string *)array_get_element(con->request.headers, "user-Agent");
623				if(!ds_user_agent){
624					return 0;
625				}
626
627				if(srv->smb_srv_info_list==NULL)
628					return 0;
629
630				for (c = srv->smb_srv_info_list; c; c = c->next) {
631
632					if( buffer_is_empty(c->server) &&
633						buffer_is_empty(c->share) &&
634						buffer_is_equal(c->src_ip, con->dst_addr_buf) &&
635						buffer_is_equal(c->user_agent, ds_user_agent->value) ){
636
637						if(buffer_is_empty(c->username)){
638							return 0;
639						}
640						else{
641							return 1;
642						}
643					}
644				}
645
646				return 0;
647			}
648		}
649
650	}
651
652	return 1;
653}
654
655static void get_aicloud_connection_auth_type(server *srv, connection *con)
656{
657	data_string *ds;
658	int found = 0;
659
660	aicloud_check_direct_file(srv, con);
661
662	if(con->mode==DIRECT)
663		return;
664
665	if (NULL == (ds = (data_string *)array_get_element(con->request.headers, "user-Agent")))
666		return;
667
668	config_values_t cv[] = {
669		{ "smbdav.auth_ntlm",    NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
670		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
671	};
672
673	size_t i, j;
674	for (i = 1; i < srv->config_context->used; i++) {
675		int found = 0;
676		array* auth_ntlm_array = array_init();
677		cv[0].destination = auth_ntlm_array;
678
679		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
680			continue;
681		}
682
683		for (j = 0; j < auth_ntlm_array->used; j++) {
684			data_string *ds2 = (data_string *)auth_ntlm_array->data[j];
685
686			if(ds2->key->used){
687				/*
688				Cdbg(DBE, "ds2->key=%s, ds2->value=%s",
689					ds2->key->ptr,
690					ds2->value->ptr );
691				*/
692				if( strncmp(ds->value->ptr, ds2->value->ptr, ds2->value->used-1) == 0 ){
693					con->mode = SMB_NTLM;
694					found = 1;
695					break;
696				}
697			}
698		}
699
700		array_free(auth_ntlm_array);
701
702		if(found==1)
703			break;
704	}
705
706}
707
708static void aicloud_connection_smb_info_url_patch(server *srv, connection *con)
709{
710	char strr[2048]="\0";
711	char uri[2048]="\0";
712
713	UNUSED(srv);
714
715	char* pch = strchr(con->request.uri->ptr,'?');
716	if(pch){
717		buffer_copy_string_len(con->url_options, pch+1, strlen(pch)-1);
718		int len = pch-con->request.uri->ptr;
719		strncpy(uri,con->request.uri->ptr, len);
720	}
721	else{
722		strcpy(uri,con->request.uri->ptr);
723	}
724
725	if(con->mode == DIRECT){
726		sprintf(strr, "%s", uri);
727	}
728	else {
729		if(con->smb_info&&con->smb_info->server->used) {
730			if(con->mode == SMB_BASIC){
731				if(con->smb_info->username->used&&con->smb_info->password->used){
732					sprintf(strr, "smb://%s:%s@%s", con->smb_info->username->ptr, con->smb_info->password->ptr, uri+1);
733				}
734				else
735					sprintf(strr, "smb://%s", uri+1);
736			}
737			else if(con->mode == SMB_NTLM){
738				sprintf(strr, "smb://%s", uri+1);
739			}
740		} else {
741			sprintf(strr, "smb://");
742		}
743	}
744
745	buffer_copy_string(con->url.path, strr);
746	buffer_copy_string(con->url.rel_path, uri);
747
748	buffer_urldecode_path(con->url.path);
749	buffer_urldecode_path(con->url.rel_path);
750
751}
752
753static smb_info_t *smbdav_get_smb_info_from_pool(server *srv, connection *con, plugin_data *p)
754{
755	smb_info_t *c;
756
757	if(srv->smb_srv_info_list==NULL||con->mode==DIRECT)
758		return NULL;
759
760	//- Get user-Agent
761	data_string *ds = (data_string *)array_get_element(con->request.headers, "user-Agent");
762	if(ds==NULL){
763		return NULL;
764	}
765
766	if(buffer_is_empty(con->asus_token)){
767		return NULL;
768	}
769
770	char pWorkgroup[30]={0};
771	char pServer[64]={0};
772	char pShare[1280]={0};
773	char pPath[1280]={0};
774
775	smbc_wrapper_parse_path2(con, pWorkgroup, pServer, pShare, pPath);
776
777	buffer* buffer_server = buffer_init();
778	if(pServer[0] != '\0')
779		buffer_append_string(buffer_server,pServer);
780
781	buffer* buffer_share = buffer_init();
782	if(pShare[0] != '\0')
783		buffer_append_string(buffer_share,pShare);
784
785	int count = 0;
786
787	for (c = srv->smb_srv_info_list; c; c = c->next) {
788
789		count++;
790
791		Cdbg(DBE, "%d, c->asus_token=[%s], con->asus_token=[%s]", count, c->asus_token->ptr, con->asus_token->ptr);
792		if(!buffer_is_equal(c->asus_token, con->asus_token))
793			continue;
794
795		Cdbg(DBE, "%d, c->server=[%s], buffer_server=[%s]", count, c->server->ptr, buffer_server->ptr);
796		if(!buffer_is_equal(c->server, buffer_server))
797			continue;
798
799		//Cdbg(DBE, "c->share=[%s], buffer_share=[%s]", c->share->ptr, buffer_share->ptr);
800		//if(con->mode==SMB_BASIC && !buffer_is_equal(c->share, buffer_share))
801		//	continue;
802
803		Cdbg(DBE, "%d, c->src_ip=[%s], dst_addr_buf=[%s]", count, c->src_ip->ptr, con->dst_addr_buf->ptr);
804		if(!buffer_is_equal(c->src_ip, con->dst_addr_buf))
805			continue;
806
807		Cdbg(DBE, "%d, c->user_agent=[%s], user_agent=[%s]", count, c->user_agent->ptr, ds->value->ptr);
808		if(!buffer_is_equal(c->user_agent, ds->value)){
809			continue;
810		}
811
812		//Cdbg(DBE, "return %d, c->server=[%s]", count, c->server->ptr);
813
814		buffer_free(buffer_server);
815		buffer_free(buffer_share);
816
817		return c;
818	}
819
820	buffer_free(buffer_server);
821	buffer_free(buffer_share);
822
823	return NULL;
824}
825
826static int aicloud_connection_smb_info_init(server *srv, connection *con, plugin_data *p)
827{
828	UNUSED(srv);
829
830	char pWorkgroup[30]={0};
831	char pServer[64]={0};
832	char pShare[1280]={0};
833	char pPath[1280]={0};
834
835	smbc_wrapper_parse_path2(con, pWorkgroup, pServer, pShare, pPath);
836
837	buffer* bworkgroup = buffer_init();
838	buffer* bserver = buffer_init();
839	buffer* bshare = buffer_init();
840	buffer* bpath = buffer_init();
841	URI_QUERY_TYPE qflag = SMB_FILE_QUERY;
842
843	if(pWorkgroup[0] != '\0')
844		buffer_copy_string(bworkgroup, pWorkgroup);
845
846	if(pServer[0] != '\0') {
847		int isHost = smbc_check_connectivity(con->physical_auth_url->ptr);
848		if(isHost) {
849			buffer_copy_string(bserver, pServer);
850		}
851		else{
852			buffer_free(bworkgroup);
853			buffer_free(bserver);
854			buffer_free(bshare);
855			buffer_free(bpath);
856			return 2;
857		}
858	}
859	else {
860		if(qflag == SMB_FILE_QUERY) {
861			qflag = SMB_HOST_QUERY;
862		}
863	}
864
865	if(pServer[0] != '\0' && pShare[0] != '\0') {
866		buffer_copy_string(bshare, pShare);
867	}
868	else {
869		if(qflag == SMB_FILE_QUERY)  {
870			qflag = SMB_SHARE_QUERY;
871		}
872	}
873
874	if(pServer[0] != '\0' && pShare[0] != '\0' && pPath[0] != '\0') {
875		buffer_copy_string(bpath, pPath);
876		qflag = SMB_FILE_QUERY;
877	}
878
879	data_string *ds = (data_string *)array_get_element(con->request.headers, "user-Agent");
880
881	smb_info_t *smb_info;
882
883	if( isBrowser(con) == 1 || con->mode == SMB_NTLM ){
884
885		//- From browser, like IE, Chrome, Firefox, Safari
886		if(smb_info = smbdav_get_smb_info_from_pool(srv, con, p)){
887			Cdbg(DBE, "Get smb_info from pool smb_info->qflag=[%d], smb_info->user=[%s], smb_info->pass=[%s]",
888				smb_info->qflag, smb_info->username->ptr, smb_info->password->ptr);
889		}
890		else{
891			smb_info = calloc(1, sizeof(smb_info_t));
892			smb_info->username = buffer_init();
893			smb_info->password = buffer_init();
894			smb_info->workgroup = buffer_init();
895			smb_info->server = buffer_init();
896			smb_info->share = buffer_init();
897			smb_info->path = buffer_init();
898			smb_info->user_agent = buffer_init();
899			smb_info->src_ip = buffer_init();
900			smb_info->asus_token = buffer_init();
901
902			if(con->mode == SMB_NTLM){
903				smb_info->cli = smbc_cli_initialize();
904				if(!buffer_is_empty(bserver)){
905					smbc_cli_connect(smb_info->cli, bserver->ptr, SMB_PORT);
906				}
907				smb_info->ntlmssp_state = NULL;
908				smb_info->state = NTLMSSP_INITIAL;
909			}
910
911			DLIST_ADD(srv->smb_srv_info_list, smb_info);
912		}
913		con->smb_info = smb_info;
914
915	}
916	else{
917		smb_info = calloc(1, sizeof(smb_info_t));
918		smb_info->username = buffer_init();
919		smb_info->password = buffer_init();
920		smb_info->workgroup = buffer_init();
921		smb_info->server = buffer_init();
922		smb_info->share = buffer_init();
923		smb_info->path = buffer_init();
924		smb_info->user_agent = buffer_init();
925		smb_info->src_ip = buffer_init();
926		smb_info->asus_token = buffer_init();
927
928		con->smb_info = smb_info;
929	}
930
931	con->smb_info->auth_time = time(NULL);
932	con->smb_info->auth_right = 0;
933
934	if(ds)
935		buffer_copy_string(con->smb_info->user_agent, ds->value->ptr);
936
937	con->smb_info->qflag = qflag;
938	buffer_copy_buffer(con->smb_info->workgroup, bworkgroup);
939	buffer_copy_buffer(con->smb_info->server, bserver);
940	buffer_copy_buffer(con->smb_info->share, bshare);
941	buffer_copy_buffer(con->smb_info->path, bpath);
942	buffer_copy_buffer(con->smb_info->src_ip, con->dst_addr_buf);
943	buffer_copy_buffer(con->smb_info->asus_token, con->asus_token);
944
945	Cdbg(DBE, "con->smb_info->workgroup=[%s]", con->smb_info->workgroup->ptr);
946	Cdbg(DBE, "con->smb_info->server=[%s]", con->smb_info->server->ptr);
947	Cdbg(DBE, "con->smb_info->share=[%s]", con->smb_info->share->ptr);
948	Cdbg(DBE, "con->smb_info->path=[%s]", con->smb_info->path->ptr);
949	Cdbg(DBE, "con->smb_info->user_agent=[%s]", con->smb_info->user_agent->ptr);
950	Cdbg(DBE, "con->smb_info->src_ip=[%s]", con->smb_info->src_ip->ptr);
951	Cdbg(DBE, "con->smb_info->qflag=[%d]", con->smb_info->qflag);
952	Cdbg(DBE, "con->smb_info->asus_token=[%s]", con->smb_info->asus_token->ptr);
953
954	buffer_free(bworkgroup);
955	buffer_free(bserver);
956	buffer_free(bshare);
957	buffer_free(bpath);
958
959	return 1;
960}
961
962void sambaname2ip(server *srv, connection *con){
963
964#if EMBEDDED_EANBLE
965
966	char* aa = nvram_get_smbdav_str();
967
968	if(aa==NULL){
969		return;
970	}
971
972	char* str_smbdav_list = (char*)malloc(strlen(aa)+1);
973	strcpy(str_smbdav_list, aa);
974	#ifdef APP_IPKG
975	free(aa);
976	#endif
977	if(str_smbdav_list!=NULL){
978		char * pch1;
979		char * pch;
980		pch = strtok(str_smbdav_list, "<>");
981
982		while(pch!=NULL){
983
984			char name[50]={0}, ip[20]={0};
985			int name_len, ip_len;
986
987			//- PC Name
988			name_len = strlen(pch);
989			strncpy(name, pch, name_len);
990			name[name_len] = '\0';
991
992			//- IP Address
993			pch = strtok(NULL,"<>");
994			ip_len = strlen(pch);
995			strncpy(ip, pch, ip_len);
996			ip[ip_len] = '\0';
997
998			//- MAC Address
999			pch = strtok(NULL,"<>");
1000
1001			//- PC Online?
1002			pch = strtok(NULL,"<>");
1003
1004			int index = strstr(con->request.uri->ptr, name) - con->request.uri->ptr;
1005			if(index==1 && strcmp(pch, "1")==0){
1006				char buff[4096];
1007				char* tmp = replace_str(con->request.uri->ptr,
1008									    name,
1009									    ip,
1010									    (char *)&buff[0]);
1011
1012				buffer_copy_string(con->request.uri, tmp);
1013
1014				buffer_copy_string(con->match_smb_ip, ip);
1015				buffer_copy_string(con->replace_smb_name, name);
1016
1017				break;
1018			}
1019
1020			pch = strtok(NULL,"<>");
1021		}
1022
1023		free(str_smbdav_list);
1024	}
1025#else
1026	size_t j;
1027	int length, filesize;
1028	char* g_temp_file = "/tmp/arpping_list";
1029	FILE* fp = fopen(g_temp_file, "r");
1030	if(fp!=NULL){
1031
1032		char str[1024];
1033
1034		while(fgets(str,sizeof(str),fp) != NULL)
1035		{
1036      		// strip trailing '\n' if it exists
1037      		int len = strlen(str)-1;
1038      		if(str[len] == '\n')
1039         		str[len] = 0;
1040
1041			char name[50]={0}, ip[20]={0};
1042			int name_len, ip_len;
1043			char * pch;
1044
1045			//- PC Name
1046			pch = strtok(str,"<");
1047			name_len = strlen(pch);
1048			strncpy(name, pch, name_len);
1049			name[name_len] = '\0';
1050
1051			//- IP Address
1052			pch = strtok(NULL,"<");
1053			ip_len = strlen(pch);
1054			strncpy(ip, pch, ip_len);
1055			ip[ip_len] = '\0';
1056
1057			//- MAC Address
1058			pch = strtok(NULL,"<");
1059
1060			//- PC Online?
1061			pch = strtok(NULL,"<");
1062
1063			int index = strstr(con->request.uri->ptr, name) - con->request.uri->ptr;
1064			if(index==1 && strcmp(pch, "1")==0){
1065				char buff[4096];
1066				char* tmp = replace_str(con->request.uri->ptr,
1067									    name,
1068									    ip,
1069									    (char *)&buff[0]);
1070
1071				buffer_copy_string(con->request.uri, tmp);
1072
1073				buffer_copy_string(con->match_smb_ip, ip);
1074				buffer_copy_string(con->replace_smb_name, name);
1075
1076				break;
1077			}
1078
1079		}
1080
1081		fclose(fp);
1082	}
1083#endif
1084
1085}
1086
1087URIHANDLER_FUNC(mod_aicloud_auth_physical_handler){
1088	plugin_data *p = p_d;
1089	//plugin_config *pc = merge_config(srv, con, p);
1090	int s_len;
1091	size_t k;
1092	int res = HANDLER_UNSET;
1093	//char buf[1024]; // cookie content
1094    //char key[32];   // <AuthName> key
1095    //char *cs;       // pointer to (some part of) <AuthName> key
1096	data_string *ds;
1097
1098	if (con->uri.path->used == 0) return HANDLER_GO_ON;
1099
1100#if EMBEDDED_EANBLE
1101#if 0
1102	data_string *ds_useragent = (data_string *)array_get_element(con->request.headers, "user-Agent");
1103
1104	int isBrowser = ( ds_useragent && (strstr( ds_useragent->value->ptr, "Mozilla" ) || strstr( ds_useragent->value->ptr, "Opera" ))) ? 1 : 0;
1105	if( isBrowser &&
1106		con->srv_socket->is_ssl==0 &&
1107		buffer_is_equal_string(con->request.uri, CONST_STR_LEN("/")) ){
1108		con->http_status = 452;
1109		return HANDLER_FINISHED;
1110	}
1111#else
1112	if( con->srv_socket->is_ssl==0 &&
1113		buffer_is_equal_string(con->request.uri, CONST_STR_LEN("/")) ){
1114		con->http_status = 452;
1115		return HANDLER_FINISHED;
1116	}
1117#endif
1118#endif
1119
1120	sambaname2ip(srv, con);
1121
1122	//Cdbg(DBE, "con->request.uri=%s", con->request.uri->ptr);
1123
1124	con->mode = SMB_BASIC;
1125
1126	get_aicloud_connection_auth_type(srv, con);
1127
1128	if( con->mode == DIRECT ){
1129		if( !check_aicloud_auth_url(srv, con, p) ){
1130			smbc_wrapper_response_401(srv, con);
1131			return HANDLER_FINISHED;
1132		}
1133
1134		aicloud_connection_smb_info_url_patch(srv, con);
1135		return HANDLER_GO_ON;
1136	}
1137	else if( strncmp(con->request.uri->ptr, "/query_field.json", 17)==0 ||
1138		     strncmp(con->request.uri->ptr, "/GetCaptchaImage", 16)==0 ){
1139		if( !check_aicloud_auth_url(srv, con, p) ){
1140			smbc_wrapper_response_401(srv, con);
1141			return HANDLER_FINISHED;
1142		}
1143		return HANDLER_GO_ON;
1144	}
1145
1146	Cdbg(DBE,"***************************************");
1147	Cdbg(DBE,"enter do_connection_auth..con->mode = %d, con->request.uri=[%s]", con->mode, con->request.uri->ptr);
1148
1149	config_cond_cache_reset(srv, con);
1150	config_patch_connection(srv, con, COMP_SERVER_SOCKET);
1151	config_patch_connection(srv, con, COMP_HTTP_URL);
1152
1153	buffer_copy_buffer(con->physical_auth_url, con->conf.document_root);
1154	buffer_append_string(con->physical_auth_url, con->request.uri->ptr+1);
1155
1156	int result = aicloud_connection_smb_info_init(srv, con, p);
1157	if( result == 0 ){
1158		return HANDLER_FINISHED;
1159	}
1160	else if( result == 2 ){
1161		//- Unable to complete the connection, the device is not turned on, or network problems caused!
1162		con->http_status = 451;
1163		return HANDLER_FINISHED;
1164	}
1165
1166	if(con->mode == SMB_NTLM) {
1167		//try to get NTLM authentication information from HTTP request
1168		res = ntlm_authentication_handler(srv, con, p);
1169	}
1170	else if(con->mode == SMB_BASIC){
1171		//try to get username/password from HTTP request
1172		res = basic_authentication_handler(srv, con, p);
1173	}
1174
1175#if 0
1176	// check for cookie
1177	if ((ds = HEADER(con, "Cookie")) == NULL && res != HANDLER_UNSET) return endauth(srv, con, pc);
1178
1179	if( ds!=NULL && res != HANDLER_UNSET ){
1180		Cdbg(DBE, "Cookie=%s", ds->value->ptr);
1181		// prepare cstring for processing
1182    	memset(key, 0, sizeof(key));
1183	    memset(buf, 0, sizeof(buf));
1184    	strncpy(key, pc->name->ptr,  min(sizeof(key) - 1, pc->name->used));
1185	    strncpy(buf, ds->value->ptr, min(sizeof(buf) - 1, ds->value->used));
1186		Cdbg(DBE, "parsing for key:%s", key);
1187
1188		 // check for "<AuthName>=" entry in a cookie
1189	    for (cs = buf; (cs = strstr(cs, key)) != NULL; ) {
1190	        Cdbg(DBE, "checking cookie entry: %s", cs);
1191
1192	        // check if found entry matches exactly for "KEY=" part.
1193	        cs += pc->name->used - 1;  // jump to the end of "KEY" part
1194	        while (isspace(*cs)) cs++; // whitespace can be skipped
1195
1196	        // break forward if this was an exact match
1197	        if (*cs++ == '=') {
1198	            char *eot = strchr(cs, ';');
1199	            if (eot) *eot = '\0';
1200	            break;
1201	        }
1202	    }
1203
1204	    if (! cs) return endauth(srv, con, pc); // not found - rejecting
1205
1206		// unescape payload
1207	    buffer *tmp = buffer_init_string(cs);
1208	    buffer_urldecode_path(tmp);
1209	    memset(buf, 0, sizeof(buf));
1210	    strncpy(buf, tmp->ptr, min(sizeof(buf) - 1, tmp->used));
1211	    buffer_free(tmp);
1212	    cs = buf;
1213
1214	    // Allow access if client already has an "authorized" token.
1215	    if (strncmp(cs, "token:", 6) == 0) {
1216	        return handle_token(srv, con, p, pc, cs + 6);
1217	    }
1218
1219	    // Verify "non-authorized" CookieAuth request in encrypted format.
1220	    // Once verified, give out authorized token ("token:..." cookie).
1221	    if (strncmp(cs, "crypt:", 6) == 0) {
1222	        return handle_crypt(srv, con, p, pc, cs + 6);
1223	    }
1224	}
1225#endif
1226
1227	//- 20120202 Jerry add
1228	//srv->smb_srv_info_list = p->smb_info_list;
1229	aicloud_connection_smb_info_url_patch(srv, con);
1230
1231	buffer_reset(con->physical_auth_url);
1232
1233	if(res != HANDLER_UNSET){
1234		return HANDLER_FINISHED;
1235	}
1236
1237	/* not found */
1238	return HANDLER_GO_ON;
1239}
1240
1241int mod_aicloud_auth_plugin_init(plugin *p);
1242int mod_aicloud_auth_plugin_init(plugin *p) {
1243	p->version     = LIGHTTPD_VERSION_ID;
1244	p->name        = buffer_init_string("aicloud_auth");
1245
1246	p->init        = mod_aicloud_auth_init;
1247	p->set_defaults = mod_aicloud_auth_set_defaults;
1248	p->handle_physical = mod_aicloud_auth_physical_handler;
1249	p->cleanup     = mod_aicloud_auth_free;
1250
1251	p->data        = NULL;
1252
1253	return 0;
1254}
1255