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