Annotation of embedaddon/coova-chilli/src/redir.c, revision 1.1
1.1 ! misho 1: /*
! 2: * HTTP redirection functions.
! 3: * Copyright (C) 2004, 2005 Mondru AB.
! 4: * Copyright (c) 2006-2007 David Bird <david@cova.com>
! 5: *
! 6: * The contents of this file may be used under the terms of the GNU
! 7: * General Public License Version 2, provided that the above copyright
! 8: * notice and this permission notice is included in all copies or
! 9: * substantial portions of the software.
! 10: *
! 11: */
! 12:
! 13: #include "system.h"
! 14: #include "syserr.h"
! 15: #include "radius.h"
! 16: #include "radius_wispr.h"
! 17: #include "radius_chillispot.h"
! 18: #include "redir.h"
! 19: #include "md5.h"
! 20: #include "dhcp.h"
! 21: #include "chilli.h"
! 22: #include "options.h"
! 23:
! 24: static int optionsdebug = 0; /* TODO: Should be changed to instance */
! 25:
! 26: static int keep_going = 1; /* OK as global variable for child process */
! 27:
! 28: static int termstate = REDIR_TERM_INIT; /* When we were terminated */
! 29:
! 30: char credits[] =
! 31: "<H1>CoovaChilli(ChilliSpot) " VERSION "</H1>"
! 32: "<p>Copyright 2002-2005 Mondru AB</p>"
! 33: "<p>Copyright 2006-2007 Coova.org</p>"
! 34: "ChilliSpot is an Open Source captive portal or wireless LAN access point "
! 35: "controller developed by the community at <a href=\"http://coova.org\">coova.org</a>. "
! 36: "It is licensed under the Gnu Public License (GPL). ";
! 37:
! 38: struct redir_socket{int fd[2];};
! 39: static unsigned char redir_radius_id=0;
! 40: static int redir_getparam(struct redir_t *redir, char *src, char *param, bstring dst);
! 41: extern time_t mainclock;
! 42:
! 43: /* Termination handler for clean shutdown */
! 44: static void redir_termination(int signum) {
! 45: if (optionsdebug) log_dbg("Terminating redir client!\n");
! 46: keep_going = 0;
! 47: }
! 48:
! 49: /* Alarm handler for ensured shutdown */
! 50: static void redir_alarm(int signum) {
! 51: log_warn(0, "Client process timed out: %d", termstate);
! 52: exit(0);
! 53: }
! 54:
! 55: /* Generate a 16 octet random challenge */
! 56: static int redir_challenge(unsigned char *dst) {
! 57: FILE *file;
! 58:
! 59: if ((file = fopen("/dev/urandom", "r")) == NULL) {
! 60: log_err(errno, "fopen(/dev/urandom, r) failed");
! 61: return -1;
! 62: }
! 63:
! 64: if (fread(dst, 1, REDIR_MD5LEN, file) != REDIR_MD5LEN) {
! 65: log_err(errno, "fread() failed");
! 66: return -1;
! 67: }
! 68:
! 69: fclose(file);
! 70: return 0;
! 71: }
! 72:
! 73: /* Convert 32+1 octet ASCII hex string to 16 octet unsigned char */
! 74: static int redir_hextochar(unsigned char *src, unsigned char * dst) {
! 75: char x[3];
! 76: int n;
! 77: int y;
! 78:
! 79: for (n=0; n< REDIR_MD5LEN; n++) {
! 80: x[0] = src[n*2+0];
! 81: x[1] = src[n*2+1];
! 82: x[2] = 0;
! 83: if (sscanf (x, "%2x", &y) != 1) {
! 84: log_err(0, "HEX conversion failed!");
! 85: return -1;
! 86: }
! 87: dst[n] = (unsigned char) y;
! 88: }
! 89:
! 90: return 0;
! 91: }
! 92:
! 93: /* Convert 16 octet unsigned char to 32+1 octet ASCII hex string */
! 94: static int redir_chartohex(unsigned char *src, char *dst) {
! 95: char x[3];
! 96: int n;
! 97:
! 98: for (n=0; n<REDIR_MD5LEN; n++) {
! 99: snprintf(x, 3, "%.2x", src[n]);
! 100: dst[n*2+0] = x[0];
! 101: dst[n*2+1] = x[1];
! 102: }
! 103:
! 104: dst[REDIR_MD5LEN*2] = 0;
! 105: return 0;
! 106: }
! 107:
! 108: static int redir_xmlencode(char *src, int srclen, char *dst, int dstsize) {
! 109: char *x;
! 110: int n;
! 111: int i = 0;
! 112:
! 113: for (n=0; n<srclen; n++) {
! 114: x=0;
! 115: switch(src[n]) {
! 116: case '&': x = "&"; break;
! 117: case '\"': x = """; break;
! 118: case '<': x = "<"; break;
! 119: case '>': x = ">"; break;
! 120: default:
! 121: if (i < dstsize - 1) dst[i++] = src[n];
! 122: break;
! 123: }
! 124: if (x) {
! 125: if (i < dstsize - strlen(x)) {
! 126: strncpy(dst + i, x, strlen(x));
! 127: i += strlen(x);
! 128: }
! 129: }
! 130: }
! 131: dst[i] = 0;
! 132: return 0;
! 133: }
! 134:
! 135: static int bstrtocstr(bstring src, char *dst, unsigned int len) {
! 136: int l;
! 137:
! 138: if (!src || src->slen == 0) {
! 139: strcpy(dst,"");
! 140: return 0;
! 141: }
! 142:
! 143: l = src->slen;
! 144: if (l > len) l = len;
! 145: strncpy(dst, (char*)src->data, len);
! 146: return 0;
! 147: }
! 148:
! 149: /* Encode src as urlencoded and place null terminated result in dst */
! 150: static int redir_urlencode(bstring src, bstring dst) {
! 151: char x[3];
! 152: int n;
! 153:
! 154: bassigncstr(dst, "");
! 155: for (n=0; n<src->slen; n++) {
! 156: if ((('A' <= src->data[n]) && (src->data[n] <= 'Z')) ||
! 157: (('a' <= src->data[n]) && (src->data[n] <= 'z')) ||
! 158: (('0' <= src->data[n]) && (src->data[n] <= '9')) ||
! 159: ('-' == src->data[n]) ||
! 160: ('_' == src->data[n]) ||
! 161: ('.' == src->data[n]) ||
! 162: ('!' == src->data[n]) ||
! 163: ('~' == src->data[n]) ||
! 164: ('*' == src->data[n])) {
! 165: bconchar(dst,src->data[n]);
! 166: }
! 167: else {
! 168: snprintf(x, 3, "%.2x", src->data[n]);
! 169: bconchar(dst, '%');
! 170: bconchar(dst, x[0]);
! 171: bconchar(dst, x[1]);
! 172: }
! 173: }
! 174: return 0;
! 175: }
! 176:
! 177: /* Decode urlencoded src and place null terminated result in dst */
! 178: static int redir_urldecode(bstring src, bstring dst) {
! 179: char x[3];
! 180: int n = 0;
! 181: unsigned int c;
! 182:
! 183: bassigncstr(dst, "");
! 184: while (n<src->slen) {
! 185: if (src->data[n] == '%') {
! 186: if ((n+2) < src->slen) {
! 187: x[0] = src->data[n+1];
! 188: x[1] = src->data[n+2];
! 189: x[2] = 0;
! 190: c = '_';
! 191: sscanf(x, "%x", &c);
! 192: bconchar(dst,c);
! 193: }
! 194: n += 3;
! 195: }
! 196: else {
! 197: bconchar(dst,src->data[n]);
! 198: n++;
! 199: }
! 200: }
! 201: return 0;
! 202: }
! 203:
! 204: /* Make an XML Reply */
! 205: static int redir_xmlreply(struct redir_t *redir,
! 206: struct redir_conn_t *conn, int res, long int timeleft, char* hexchal,
! 207: char* reply, char* redirurl, bstring b) {
! 208: bstring bt;
! 209:
! 210: if (redir->no_uamwispr &&
! 211: !(redir->chillixml)) return 0;
! 212:
! 213: bt = bfromcstr("");
! 214:
! 215: bcatcstr(b,
! 216: "<!--\r\n"
! 217: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
! 218:
! 219: if (!redir->no_uamwispr) {
! 220: bcatcstr(b,
! 221: "<WISPAccessGatewayParam\r\n"
! 222: " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n"
! 223: " xsi:noNamespaceSchemaLocation=\"http://www.acmewisp.com/WISPAccessGatewayParam.xsd\""
! 224: ">\r\n");
! 225:
! 226: switch (res) {
! 227:
! 228: case REDIR_ALREADY:
! 229: bcatcstr(b,
! 230: "<AuthenticationPollReply>\r\n"
! 231: "<MessageType>140</MessageType>\r\n"
! 232: "<ResponseCode>102</ResponseCode>\r\n"
! 233: "<ReplyMessage>Already logged on</ReplyMessage>\r\n"
! 234: "</AuthenticationPollReply>\r\n");
! 235: break;
! 236:
! 237: case REDIR_FAILED_REJECT:
! 238: bcatcstr(b,
! 239: "<AuthenticationPollReply>\r\n"
! 240: "<MessageType>140</MessageType>\r\n"
! 241: "<ResponseCode>100</ResponseCode>\r\n");
! 242:
! 243: if (reply) {
! 244: bassignformat(bt, "<ReplyMessage>%s</ReplyMessage>\r\n", reply);
! 245: bconcat(b, bt);
! 246: }
! 247: else {
! 248: bcatcstr(b, "<ReplyMessage>Invalid Password</ReplyMessage>\r\n");
! 249: }
! 250:
! 251: bcatcstr(b, "</AuthenticationPollReply>\r\n");
! 252: break;
! 253:
! 254: case REDIR_FAILED_OTHER:
! 255: bcatcstr(b,
! 256: "<AuthenticationPollReply>\r\n"
! 257: "<MessageType>140</MessageType>\r\n"
! 258: "<ResponseCode>102</ResponseCode>\r\n");
! 259:
! 260: if (reply) {
! 261: bassignformat(bt, "<ReplyMessage>%s</ReplyMessage>\r\n", reply);
! 262: bconcat(b, bt);
! 263: }
! 264: else {
! 265: bcatcstr(b, "<ReplyMessage>Radius error</ReplyMessage>\r\n");
! 266: }
! 267:
! 268: bcatcstr(b, "</AuthenticationPollReply>\r\n");
! 269: break;
! 270:
! 271: case REDIR_SUCCESS:
! 272: bcatcstr(b,
! 273: "<AuthenticationPollReply>\r\n"
! 274: "<MessageType>140</MessageType>\r\n"
! 275: "<ResponseCode>50</ResponseCode>\r\n");
! 276:
! 277: if (reply) {
! 278: bassignformat(bt, "<ReplyMessage>%s</ReplyMessage>\r\n", reply);
! 279: bconcat(b, bt);
! 280: }
! 281:
! 282: bassignformat(bt, "<LogoffURL>http://%s:%d/logoff</LogoffURL>\r\n",
! 283: inet_ntoa(redir->addr), redir->port);
! 284: bconcat(b, bt);
! 285:
! 286: if (redirurl) {
! 287: bassignformat(bt, "<RedirectionURL>%s</RedirectionURL>\r\n", redirurl);
! 288: bconcat(b, bt);
! 289: }
! 290: bcatcstr(b, "</AuthenticationPollReply>\r\n");
! 291: break;
! 292:
! 293: case REDIR_LOGOFF:
! 294: bcatcstr(b,
! 295: "<LogoffReply>\r\n"
! 296: "<MessageType>130</MessageType>\r\n"
! 297: "<ResponseCode>150</ResponseCode>\r\n"
! 298: "</LogoffReply>\r\n");
! 299: break;
! 300:
! 301: case REDIR_SPLASH:
! 302: case REDIR_NOTYET:
! 303: bcatcstr(b,
! 304: "<Redirect>\r\n"
! 305: "<AccessProcedure>1.0</AccessProcedure>\r\n");
! 306:
! 307: if (redir->radiuslocationid) {
! 308: bassignformat(bt, "<AccessLocation>%s</AccessLocation>\r\n", redir->radiuslocationid);
! 309: bconcat(b, bt);
! 310: }
! 311:
! 312: if (redir->radiuslocationname) {
! 313: bassignformat(bt, "<LocationName>%s</LocationName>\r\n", redir->radiuslocationname);
! 314: bconcat(b, bt);
! 315: }
! 316:
! 317: bassignformat(bt, "<LoginURL>%s%cres=smartclient&uamip=%s&uamport=%d&challenge=%s</LoginURL>\r\n",
! 318: options.wisprlogin ? options.wisprlogin : redir->url,
! 319: strchr(options.wisprlogin ? options.wisprlogin : redir->url, '?') ? '&' : '?',
! 320: inet_ntoa(redir->addr), redir->port, hexchal);
! 321: bconcat(b, bt);
! 322:
! 323: bassignformat(bt, "<AbortLoginURL>http://%s:%d/abort</AbortLoginURL>\r\n",
! 324: inet_ntoa(redir->addr), redir->port);
! 325: bconcat(b, bt);
! 326:
! 327: bcatcstr(b,
! 328: "<MessageType>100</MessageType>\r\n"
! 329: "<ResponseCode>0</ResponseCode>\r\n"
! 330: "</Redirect>\r\n");
! 331: break;
! 332:
! 333: case REDIR_ABORT_ACK:
! 334: bcatcstr(b,
! 335: "<AbortLoginReply>\r\n"
! 336: "<MessageType>150</MessageType>\r\n"
! 337: "<ResponseCode>151</ResponseCode>\r\n"
! 338: "</AbortLoginReply>\r\n");
! 339: break;
! 340:
! 341: case REDIR_ABORT_NAK:
! 342: bcatcstr(b,
! 343: "<AbortLoginReply>\r\n"
! 344: "<MessageType>150</MessageType>\r\n"
! 345: "<ResponseCode>50</ResponseCode>\r\n");
! 346: bassignformat(bt, "<LogoffURL>http://%s:%d/logoff</LogoffURL>\r\n",
! 347: inet_ntoa(redir->addr), redir->port);
! 348: bconcat(b, bt);
! 349: bcatcstr(b, "</AbortLoginReply>\r\n");
! 350: break;
! 351:
! 352: case REDIR_STATUS:
! 353: bcatcstr(b,
! 354: "<AuthenticationPollReply>\r\n"
! 355: "<MessageType>140</MessageType>\r\n");
! 356: if (conn->s_state.authenticated != 1) {
! 357: bcatcstr(b,
! 358: "<ResponseCode>150</ResponseCode>\r\n"
! 359: "<ReplyMessage>Not logged on</ReplyMessage>\r\n");
! 360: } else {
! 361: bcatcstr(b,
! 362: "<ResponseCode>50</ResponseCode>\r\n"
! 363: "<ReplyMessage>Already logged on</ReplyMessage>\r\n");
! 364: }
! 365: bcatcstr(b, "</AuthenticationPollReply>\r\n");
! 366: break;
! 367:
! 368: default:
! 369: log_err(0, "Unknown res in switch");
! 370: bdestroy(bt);
! 371: return -1;
! 372:
! 373: }
! 374: bcatcstr(b, "</WISPAccessGatewayParam>\r\n");
! 375: }
! 376:
! 377: if (redir->chillixml) {
! 378: bcatcstr(b, "<ChilliSpotSession>\r\n");
! 379: switch (res) {
! 380: case REDIR_SPLASH:
! 381: case REDIR_NOTYET:
! 382: bassignformat(bt, "<Challenge>%s</Challenge>\r\n", hexchal);
! 383: bconcat(b, bt);
! 384: break;
! 385: case REDIR_STATUS:
! 386: if (conn->s_state.authenticated == 1) {
! 387: time_t timenow = time(0);
! 388: uint32_t sessiontime;
! 389:
! 390: sessiontime = timenow - conn->s_state.start_time;
! 391:
! 392: bcatcstr(b, "<State>1</State>\r\n");
! 393:
! 394: bassignformat(bt, "<StartTime>%d</StartTime>\r\n" , conn->s_state.start_time);
! 395: bconcat(b, bt);
! 396:
! 397: bassignformat(bt, "<SessionTime>%d</SessionTime>\r\n", sessiontime);
! 398: bconcat(b, bt);
! 399:
! 400: if (timeleft) {
! 401: bassignformat(bt, "<TimeLeft>%d</TimeLeft>\r\n", timeleft);
! 402: bconcat(b, bt);
! 403: }
! 404:
! 405: bassignformat(bt, "<Timeout>%d</Timeout>\r\n", conn->s_params.sessiontimeout);
! 406: bconcat(b, bt);
! 407:
! 408: bassignformat(bt, "<InputOctets>%d</InputOctets>\r\n", conn->s_state.input_octets);
! 409: bconcat(b, bt);
! 410:
! 411: bassignformat(bt, "<OutputOctets>%d</OutputOctets>\r\n", conn->s_state.output_octets);
! 412: bconcat(b, bt);
! 413:
! 414: bassignformat(bt, "<MaxInputOctets>%d</MaxInputOctets>\r\n", conn->s_params.maxinputoctets);
! 415: bconcat(b, bt);
! 416:
! 417: bassignformat(bt, "<MaxOutputOctets>%d</MaxOutputOctets>\r\n", conn->s_params.maxoutputoctets);
! 418: bconcat(b, bt);
! 419:
! 420: bassignformat(bt, "<MaxTotalOctets>%d</MaxTotalOctets>\r\n", conn->s_params.maxtotaloctets);
! 421: bconcat(b, bt);
! 422: }
! 423: else {
! 424: bcatcstr(b, "<State>0</State>\r\n");
! 425: }
! 426:
! 427: break;
! 428:
! 429: case REDIR_ALREADY:
! 430: bcatcstr(b, "<Already>1</Already>\r\n");
! 431: break;
! 432:
! 433: case REDIR_FAILED_REJECT:
! 434: case REDIR_FAILED_OTHER:
! 435: if (reply) {
! 436: bassignformat(bt, "<ReplyMessage>%s</ReplyMessage>\r\n", reply);
! 437: bconcat(b, bt);
! 438: }
! 439: bcatcstr(b, "<State>0</State>\r\n");
! 440:
! 441: break;
! 442: case REDIR_SUCCESS:
! 443: if (reply) {
! 444: bassignformat(bt, "<ReplyMessage>%s</ReplyMessage>\r\n", reply);
! 445: bconcat(b, bt);
! 446: }
! 447: bcatcstr(b, "<State>1</State>\r\n");
! 448: break;
! 449: case REDIR_LOGOFF:
! 450: bcatcstr(b, "<State>0</State>\r\n");
! 451: break;
! 452: case REDIR_ABORT_ACK:
! 453: bcatcstr(b, "<Abort_ack>1</Abort_ack>\r\n");
! 454: break;
! 455: case REDIR_ABORT_NAK:
! 456: bcatcstr(b, "<Abort_nak>1</Abort_nak>\r\n");
! 457: break;
! 458: default:
! 459: log_err(0, "Unknown res in switch");
! 460: bdestroy(bt);
! 461: return -1;
! 462: }
! 463: bcatcstr(b, "</ChilliSpotSession>\r\n");
! 464: }
! 465:
! 466: bcatcstr(b, "-->\r\n");
! 467: bdestroy(bt);
! 468: return 0;
! 469: }
! 470:
! 471: static int redir_buildurl(struct redir_conn_t *conn, bstring str,
! 472: struct redir_t *redir, char *resp,
! 473: long int timeleft, char* hexchal, char* uid,
! 474: char* userurl, char* reply, char* redirurl,
! 475: uint8_t *hismac, struct in_addr *hisip) {
! 476: char *redir_url = redir->url;
! 477: bstring bt = bfromcstr("");
! 478: bstring bt2 = bfromcstr("");
! 479:
! 480: if ((conn->s_params.flags & REQUIRE_UAM_SPLASH) &&
! 481: conn->s_params.url[0]) {
! 482: redir_url = conn->s_params.url;
! 483: }
! 484:
! 485: bassignformat(str, "%s%cres=%s&uamip=%s&uamport=%d",
! 486: redir_url, strchr(redir_url, '?') ? '&' : '?',
! 487: resp, inet_ntoa(redir->addr), redir->port);
! 488:
! 489: if (hexchal) {
! 490: bassignformat(bt, "&challenge=%s", hexchal);
! 491: bconcat(str, bt);
! 492: bassigncstr(bt,"");
! 493: }
! 494:
! 495: if (conn->type == REDIR_STATUS) {
! 496: int starttime = conn->s_state.start_time;
! 497: if (starttime) {
! 498: int sessiontime;
! 499: time_t timenow = time(0);
! 500:
! 501: sessiontime = timenow - starttime;
! 502:
! 503: bassignformat(bt, "&starttime=%ld", starttime);
! 504: bconcat(str, bt);
! 505: bassignformat(bt, "&sessiontime=%ld", sessiontime);
! 506: bconcat(str, bt);
! 507: }
! 508:
! 509: if (conn->s_params.sessiontimeout) {
! 510: bassignformat(bt, "&sessiontimeout=%ld", conn->s_params.sessiontimeout);
! 511: bconcat(str, bt);
! 512: }
! 513:
! 514: if (conn->s_params.sessionterminatetime) {
! 515: bassignformat(bt, "&stoptime=%ld", conn->s_params.sessionterminatetime);
! 516: bconcat(str, bt);
! 517: }
! 518: }
! 519:
! 520: if (uid) {
! 521: bcatcstr(str, "&uid=");
! 522: bassigncstr(bt, uid);
! 523: redir_urlencode(bt, bt2);
! 524: bconcat(str, bt2);
! 525: }
! 526:
! 527: if (timeleft) {
! 528: bassignformat(bt, "&timeleft=%ld", timeleft);
! 529: bconcat(str, bt);
! 530: }
! 531:
! 532: if (hismac) {
! 533: bcatcstr(str, "&mac=");
! 534: bassignformat(bt, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
! 535: hismac[0], hismac[1],
! 536: hismac[2], hismac[3],
! 537: hismac[4], hismac[5]);
! 538: redir_urlencode(bt, bt2);
! 539: bconcat(str, bt2);
! 540: }
! 541:
! 542: if (hisip) {
! 543: bassignformat(bt, "&ip=%s", inet_ntoa(*hisip));
! 544: bconcat(str, bt);
! 545: }
! 546:
! 547: if (reply) {
! 548: bcatcstr(str, "&reply=");
! 549: bassigncstr(bt, reply);
! 550: redir_urlencode(bt, bt2);
! 551: bconcat(str, bt2);
! 552: }
! 553:
! 554: if (redir->ssid) {
! 555: bcatcstr(str, "&ssid=");
! 556: bassigncstr(bt, redir->ssid);
! 557: redir_urlencode(bt, bt2);
! 558: bconcat(str, bt2);
! 559: }
! 560:
! 561: if (redir->nasmac) {
! 562: bcatcstr(str, "&called=");
! 563: bassigncstr(bt, redir->nasmac);
! 564: redir_urlencode(bt, bt2);
! 565: bconcat(str, bt2);
! 566: }
! 567:
! 568: if (redir->radiusnasid) {
! 569: bcatcstr(str, "&nasid=");
! 570: bassigncstr(bt, redir->radiusnasid);
! 571: redir_urlencode(bt, bt2);
! 572: bconcat(str, bt2);
! 573: }
! 574:
! 575: if (conn->lang[0]) {
! 576: bcatcstr(str, "&lang=");
! 577: bassigncstr(bt, conn->lang);
! 578: redir_urlencode(bt, bt2);
! 579: bconcat(str, bt2);
! 580: }
! 581:
! 582: if (redirurl) {
! 583: bcatcstr(str, "&redirurl=");
! 584: bassigncstr(bt, redirurl);
! 585: redir_urlencode(bt, bt2);
! 586: bconcat(str, bt2);
! 587: }
! 588:
! 589: if (userurl) {
! 590: bcatcstr(str, "&userurl=");
! 591: bassigncstr(bt, userurl);
! 592: redir_urlencode(bt, bt2);
! 593: bconcat(str, bt2);
! 594: }
! 595:
! 596: if (redir->secret && *redir->secret) { /* take the md5 of the url+uamsecret as a checksum */
! 597: MD5_CTX context;
! 598: unsigned char cksum[16];
! 599: char hex[32+1];
! 600: int i;
! 601:
! 602: MD5Init(&context);
! 603: MD5Update(&context, (uint8_t*)str->data, str->slen);
! 604: MD5Update(&context, (uint8_t*)redir->secret, strlen(redir->secret));
! 605: MD5Final(cksum, &context);
! 606:
! 607: hex[0]=0;
! 608: for (i=0; i<16; i++)
! 609: sprintf(hex+strlen(hex), "%.2X", cksum[i]);
! 610:
! 611: bcatcstr(str, "&md=");
! 612: bcatcstr(str, hex);
! 613: }
! 614:
! 615: bdestroy(bt);
! 616: bdestroy(bt2);
! 617: return 0;
! 618: }
! 619:
! 620: ssize_t
! 621: tcp_write_timeout(int timeout, struct redir_socket *sock, char *buf, size_t len) {
! 622: fd_set fdset;
! 623: struct timeval tv;
! 624: int fd = sock->fd[1];
! 625:
! 626: FD_ZERO(&fdset);
! 627: FD_SET(fd,&fdset);
! 628:
! 629: tv.tv_sec = timeout;
! 630: tv.tv_usec = 0;
! 631:
! 632: if (select(fd + 1,(fd_set *) 0,&fdset,(fd_set *) 0,&tv) == -1)
! 633: return -1;
! 634:
! 635: if (FD_ISSET(fd, &fdset))
! 636: #if WIN32
! 637: return send(fd,buf,len,0);
! 638: #else
! 639: return write(fd,buf,len);
! 640: #endif
! 641:
! 642: return -1;
! 643: }
! 644:
! 645: static int timeout = 10;
! 646:
! 647: ssize_t
! 648: tcp_write(struct redir_socket *sock, char *buf, size_t len) {
! 649: ssize_t c;
! 650: size_t r = 0;
! 651: while (r < len) {
! 652: c = tcp_write_timeout(timeout, sock, buf+r, len-r);
! 653: if (c <= 0) return (ssize_t)r;
! 654: r += (size_t)c;
! 655: }
! 656: return (ssize_t)r;
! 657: }
! 658:
! 659: static int redir_json_reply(struct redir_t *redir, int res, struct redir_conn_t *conn,
! 660: char *hexchal, char *userurl, char *redirurl, uint8_t *hismac,
! 661: char *reply, char *qs, bstring s) {
! 662: bstring tmp = bfromcstr("");
! 663: bstring json = bfromcstr("");
! 664:
! 665: unsigned char flg = 0;
! 666: #define FLG_cb 1
! 667: #define FLG_chlg 2
! 668: #define FLG_sess 4
! 669: #define FLG_loc 8
! 670: #define FLG_redir 16
! 671:
! 672: int state = conn->s_state.authenticated;
! 673: int splash = (conn->s_params.flags & REQUIRE_UAM_SPLASH) == REQUIRE_UAM_SPLASH;
! 674:
! 675: redir_getparam(redir, qs, "callback", tmp);
! 676:
! 677: if (tmp->slen) {
! 678: bconcat(json, tmp);
! 679: bcatcstr(json, "(");
! 680: flg |= FLG_cb;
! 681: }
! 682:
! 683: switch (res) {
! 684: case REDIR_ALREADY:
! 685: flg |= FLG_sess;
! 686: break;
! 687:
! 688: case REDIR_FAILED_REJECT:
! 689: case REDIR_FAILED_OTHER:
! 690: flg |= FLG_chlg;
! 691: flg |= FLG_redir;
! 692: break;
! 693:
! 694: case REDIR_SUCCESS:
! 695: flg |= FLG_sess;
! 696: flg |= FLG_redir;
! 697: state = 1;
! 698: break;
! 699:
! 700: case REDIR_LOGOFF:
! 701: flg |= FLG_sess | FLG_chlg;
! 702: break;
! 703:
! 704: case REDIR_SPLASH:
! 705: case REDIR_NOTYET:
! 706: flg |= FLG_chlg;
! 707: flg |= FLG_loc;
! 708: flg |= FLG_redir;
! 709: break;
! 710:
! 711: case REDIR_ABORT_ACK:
! 712: case REDIR_ABORT_NAK:
! 713: case REDIR_ABOUT:
! 714: break;
! 715:
! 716: case REDIR_STATUS:
! 717: if (state && !splash) {
! 718: flg |= FLG_sess;
! 719: } else {
! 720: flg |= FLG_chlg;
! 721: flg |= FLG_loc;
! 722: }
! 723: flg |= FLG_redir;
! 724: break;
! 725:
! 726: default:
! 727: break;
! 728: }
! 729:
! 730: if (state && splash)
! 731: state = 3;
! 732:
! 733: bcatcstr(json, "{\"version\":\"1.0\",\"clientState\":");
! 734:
! 735: bassignformat(tmp, "%d", state);
! 736: bconcat(json, tmp);
! 737:
! 738: if (reply) {
! 739: bcatcstr(json, ",\"message\":\"");
! 740: bcatcstr(json, reply);
! 741: bcatcstr(json, "\"");
! 742: }
! 743:
! 744: if ((flg & FLG_chlg) && hexchal) {
! 745: bcatcstr(json, ",\"challenge\":\"");
! 746: bcatcstr(json, hexchal);
! 747: bcatcstr(json, "\"");
! 748: }
! 749:
! 750: if (flg & FLG_loc) {
! 751: bcatcstr(json,",\"location\":{\"name\":\"");
! 752: if (redir->locationname)
! 753: bcatcstr(json, redir->locationname);
! 754: else if (redir->radiuslocationname)
! 755: bcatcstr(json, redir->radiuslocationname);
! 756: bcatcstr(json,"\"");
! 757: bcatcstr(json,"}");
! 758: }
! 759:
! 760: if (flg & FLG_redir)
! 761: session_redir_json_fmt(json, userurl, redirurl, hismac);
! 762:
! 763: if (flg & FLG_sess)
! 764: session_json_fmt(&conn->s_state, &conn->s_params,
! 765: json, res == REDIR_SUCCESS);
! 766:
! 767: bcatcstr(json, "}");
! 768:
! 769: if (flg & FLG_cb) {
! 770: bcatcstr(json, ")");
! 771: }
! 772:
! 773: bassigncstr(s, "HTTP/1.1 200 OK\r\n");
! 774: bcatcstr(s, "Cache-Control: no-cache, must-revalidate\r\n");
! 775:
! 776: bcatcstr(s, "Content-Length: ");
! 777: bassignformat(tmp , "%ld", blength(json) );
! 778: bconcat(s, tmp);
! 779:
! 780: bcatcstr(s, "\r\nContent-type: ");
! 781: if (tmp->slen) bcatcstr(s, "text/javascript");
! 782: else bcatcstr(s, "application/json");
! 783:
! 784: bcatcstr(s, "\r\n\r\n");
! 785: bconcat(s, json);
! 786:
! 787: if (options.debug) {
! 788: log_dbg("sending json: %s\n", json->data);
! 789: }
! 790:
! 791: bdestroy(json);
! 792: bdestroy(tmp);
! 793:
! 794: return 0;
! 795: }
! 796:
! 797: /* Make an HTTP redirection reply and send it to the client */
! 798: static int redir_reply(struct redir_t *redir, struct redir_socket *sock,
! 799: struct redir_conn_t *conn, int res, bstring url,
! 800: long int timeleft, char* hexchal, char* uid,
! 801: char* userurl, char* reply, char* redirurl,
! 802: uint8_t *hismac, struct in_addr *hisip, char *qs) {
! 803:
! 804: char *resp = NULL;
! 805: bstring buffer;
! 806:
! 807: switch (res) {
! 808: case REDIR_ALREADY:
! 809: resp = "already";
! 810: break;
! 811: case REDIR_FAILED_REJECT:
! 812: case REDIR_FAILED_OTHER:
! 813: resp = "failed";
! 814: break;
! 815: case REDIR_SUCCESS:
! 816: resp = "success";
! 817: break;
! 818: case REDIR_LOGOFF:
! 819: resp = "logoff";
! 820: break;
! 821: case REDIR_NOTYET:
! 822: resp = "notyet";
! 823: break;
! 824: case REDIR_SPLASH:
! 825: resp = "splash";
! 826: break;
! 827: case REDIR_ABORT_ACK:
! 828: resp = "logoff";
! 829: break;
! 830: case REDIR_ABORT_NAK:
! 831: resp = "already";
! 832: break;
! 833: case REDIR_ABOUT:
! 834: case REDIR_ABORT:
! 835: break;
! 836: case REDIR_STATUS:
! 837: resp = conn->s_state.authenticated == 1 ? "already" : "notyet";
! 838: break;
! 839: default:
! 840: log_err(0, "Unknown res in switch");
! 841: return -1;
! 842: }
! 843:
! 844: buffer = bfromcstralloc(1024, "");
! 845:
! 846: if (conn->format == REDIR_FMT_JSON) {
! 847:
! 848: redir_json_reply(redir, res, conn, hexchal, userurl, redirurl, hismac, reply, qs, buffer);
! 849:
! 850: } else if (resp) {
! 851: bcatcstr(buffer, "HTTP/1.0 302 Moved Temporarily\r\nLocation: ");
! 852:
! 853: if (url) {
! 854: bconcat(buffer, url);
! 855: } else {
! 856: bstring bt = bfromcstralloc(1024,"");
! 857: if (redir_buildurl(conn, bt, redir, resp, timeleft, hexchal,
! 858: uid, userurl, reply, redirurl, hismac, hisip) == -1) {
! 859: bdestroy(bt);
! 860: bdestroy(buffer);
! 861: return -1;
! 862: }
! 863: log_dbg("here: %s\n", bt->data);
! 864: bconcat(buffer, bt);
! 865: bdestroy(bt);
! 866: }
! 867:
! 868: bcatcstr(buffer,
! 869: "\r\n\r\n<HTML><BODY><H2>Browser error!</H2>"
! 870: "Browser does not support redirects!</BODY>\r\n");
! 871:
! 872: redir_xmlreply(redir, conn, res, timeleft, hexchal, reply, redirurl, buffer);
! 873:
! 874: bcatcstr(buffer, "\r\n</HTML>\r\n");
! 875:
! 876: } else {
! 877: bassigncstr(buffer,
! 878: "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"
! 879: "<HTML><HEAD><TITLE>CoovaChilli</TITLE></HEAD><BODY>");
! 880: bcatcstr(buffer, credits);
! 881: bcatcstr(buffer, "</BODY></HTML>\r\n");
! 882: }
! 883:
! 884: if (tcp_write(sock, (char*)buffer->data, buffer->slen) < 0) {
! 885: log_err(errno, "tcp_write() failed!");
! 886: bdestroy(buffer);
! 887: return -1;
! 888: }
! 889:
! 890: bdestroy(buffer);
! 891: return 0;
! 892: }
! 893:
! 894: /* Allocate new instance of redir */
! 895: int redir_new(struct redir_t **redir,
! 896: struct in_addr *addr, int port, int uiport) {
! 897: struct sockaddr_in address;
! 898: int optval = 1;
! 899: int n = 0;
! 900:
! 901: if (!(*redir = calloc(1, sizeof(struct redir_t)))) {
! 902: log_err(errno, "calloc() failed");
! 903: return EOF;
! 904: }
! 905:
! 906: (*redir)->addr = *addr;
! 907: (*redir)->port = port;
! 908: (*redir)->uiport = uiport;
! 909: (*redir)->starttime = 0;
! 910:
! 911: if (((*redir)->fd[0] = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
! 912: log_err(errno, "socket() failed");
! 913: return -1;
! 914: }
! 915:
! 916: if (uiport && ((*redir)->fd[1] = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
! 917: log_err(errno, "socket() failed");
! 918: return -1;
! 919: }
! 920:
! 921: /* Set up address */
! 922: address.sin_family = AF_INET;
! 923: #if defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 924: address.sin_len = sizeof (struct sockaddr_in);
! 925: #endif
! 926:
! 927: for (n = 0; n < 2 && (*redir)->fd[n]; n++) {
! 928:
! 929: switch(n) {
! 930: case 0:
! 931: address.sin_addr.s_addr = addr->s_addr;
! 932: address.sin_port = htons(port);
! 933: break;
! 934: case 1:
! 935: /* XXX: binding to 0.0.0.0:uiport (should be configurable?) */
! 936: address.sin_addr.s_addr = INADDR_ANY;
! 937: address.sin_port = htons(uiport);
! 938: break;
! 939: }
! 940:
! 941: if (setsockopt((*redir)->fd[n], SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) {
! 942: log_err(errno, "setsockopt() failed");
! 943: close((*redir)->fd[n]);
! 944: (*redir)->fd[n]=0;
! 945: break;
! 946: }
! 947:
! 948: /* TODO: FreeBSD?
! 949: if (setsockopt((*redir)->fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval))) {
! 950: log_err(errno, "setsockopt() failed");
! 951: close((*redir)->fd);
! 952: return -1;
! 953: }
! 954: */
! 955:
! 956: while (bind((*redir)->fd[n], (struct sockaddr *)&address, sizeof(address))) {
! 957: if ((EADDRINUSE == errno) && (10 > n++)) {
! 958: log_warn(0, "UAM port already in use. Waiting for retry.");
! 959: if (sleep(30)) { /* In case we got killed */
! 960: close((*redir)->fd[n]);
! 961: (*redir)->fd[n]=0;
! 962: break;
! 963: }
! 964: }
! 965: else {
! 966: log_err(errno, "bind() failed");
! 967: close((*redir)->fd[n]);
! 968: (*redir)->fd[n]=0;
! 969: break;
! 970: }
! 971: }
! 972:
! 973: if (listen((*redir)->fd[n], REDIR_MAXLISTEN)) {
! 974: log_err(errno, "listen() failed");
! 975: close((*redir)->fd[n]);
! 976: (*redir)->fd[n]=0;
! 977: break;
! 978: }
! 979: }
! 980:
! 981: if (((*redir)->msgid = msgget(IPC_PRIVATE, 0)) < 0) {
! 982: log_err(errno, "msgget() failed");
! 983: log_err(0, "Most likely your computer does not have System V IPC installed");
! 984: return -1;
! 985: }
! 986:
! 987: return 0;
! 988: }
! 989:
! 990:
! 991: /* Free instance of redir */
! 992: int redir_free(struct redir_t *redir) {
! 993: int n;
! 994: for (n = 0; n < 2 && redir->fd[n]; n++) {
! 995: if (close(redir->fd[n])) {
! 996: log_err(errno, "close() failed");
! 997: }
! 998: }
! 999:
! 1000: if (msgctl(redir->msgid, IPC_RMID, NULL)) {
! 1001: log_err(errno, "msgctl() failed");
! 1002: }
! 1003:
! 1004: free(redir);
! 1005: return 0;
! 1006: }
! 1007:
! 1008: /* Set redir parameters */
! 1009: void redir_set(struct redir_t *redir, int debug) {
! 1010: optionsdebug = debug; /* TODO: Do not change static variable from instance */
! 1011: redir->debug = debug;
! 1012: redir->no_uamsuccess = options.no_uamsuccess;
! 1013: redir->no_uamwispr = options.no_uamwispr;
! 1014: redir->chillixml = options.chillixml;
! 1015: redir->url = options.uamurl;
! 1016: redir->homepage = options.uamhomepage;
! 1017: redir->secret = options.uamsecret;
! 1018: redir->ssid = options.ssid;
! 1019: redir->nasmac = options.nasmac;
! 1020: redir->nasip = options.nasip;
! 1021: redir->radiusserver0 = options.radiusserver1;
! 1022: redir->radiusserver1 = options.radiusserver2;
! 1023: redir->radiusauthport = options.radiusauthport;
! 1024: redir->radiusacctport = options.radiusacctport;
! 1025: redir->radiussecret = options.radiussecret;
! 1026: redir->radiusnasid = options.radiusnasid;
! 1027: redir->radiuslocationid = options.radiuslocationid;
! 1028: redir->radiuslocationname = options.radiuslocationname;
! 1029: redir->locationname = options.locationname;
! 1030: redir->radiusnasporttype = options.radiusnasporttype;
! 1031: return;
! 1032: }
! 1033:
! 1034: /* Get a parameter of an HTTP request. Parameter is url decoded */
! 1035: /* TODO: Should be merged with other parsers */
! 1036: static int redir_getparam(struct redir_t *redir, char *src, char *param, bstring dst) {
! 1037: char *p1;
! 1038: char *p2;
! 1039: char sstr[255];
! 1040: int len = 0;
! 1041:
! 1042: strncpy(sstr, param, sizeof(sstr));
! 1043: sstr[sizeof(sstr)-1] = 0;
! 1044: strncat(sstr, "=", sizeof(sstr));
! 1045: sstr[sizeof(sstr)-1] = 0;
! 1046:
! 1047: if (!(p1 = strcasestr(src, sstr))) return -1;
! 1048: p1 += strlen(sstr);
! 1049:
! 1050: /* The parameter ends with a & or null */
! 1051: p2 = strstr(p1, "&");
! 1052:
! 1053: if (p2) len = p2 - p1;
! 1054: else len = strlen(p1);
! 1055:
! 1056: if (len) {
! 1057: bstring s = blk2bstr(p1, len);
! 1058: redir_urldecode(s, dst);
! 1059: bdestroy(s);
! 1060: } else
! 1061: bassigncstr(dst, "");
! 1062:
! 1063: log_dbg("The parameter %s is: [%.*s]", param, dst->slen, dst->data);/**/
! 1064:
! 1065: return 0;
! 1066: }
! 1067:
! 1068: /* Read the an HTTP request from a client */
! 1069: /* If POST is allowed, 1 is the input value of ispost */
! 1070: static int redir_getreq(struct redir_t *redir, struct redir_socket *sock,
! 1071: struct redir_conn_t *conn, int *ispost, size_t *clen,
! 1072: char *qs, size_t qslen) {
! 1073: int fd = sock->fd[0];
! 1074: fd_set fds;
! 1075: struct timeval idleTime;
! 1076: int status;
! 1077: ssize_t recvlen = 0;
! 1078: size_t buflen = 0;
! 1079: char buffer[REDIR_MAXBUFFER];
! 1080: char host[256];
! 1081: char path[256];
! 1082: int i, lines=0, done=0;
! 1083: char *eol;
! 1084:
! 1085: memset(buffer, 0, sizeof(buffer));
! 1086: memset(host, 0, sizeof(host));
! 1087: memset(path, 0, sizeof(path));
! 1088:
! 1089: /* read whatever the client send to us */
! 1090: while (!done && (redir->starttime + REDIR_HTTP_MAX_TIME) > time(NULL)) {
! 1091: FD_ZERO(&fds);
! 1092: FD_SET(fd, &fds);
! 1093:
! 1094: idleTime.tv_sec = 0;
! 1095: idleTime.tv_usec = REDIR_HTTP_SELECT_TIME;
! 1096:
! 1097: switch (status = select(fd + 1, &fds, NULL, NULL, &idleTime)) {
! 1098: case -1:
! 1099: log_err(errno,"select() returned -1!");
! 1100: return -1;
! 1101: case 0:
! 1102: log_dbg("HTTP request timeout!");
! 1103: return -1;
! 1104: default:
! 1105: break;
! 1106: }
! 1107:
! 1108: if ((status > 0) && FD_ISSET(fd, &fds)) {
! 1109: if (buflen + 2 >= sizeof(buffer)) { /* ensure space for a least one more byte + null */
! 1110: log_err(0, "Too much data in http request!");
! 1111: return -1;
! 1112: }
! 1113:
! 1114: /* if post is allowed, we do not buffer on the read (to not eat post data) */
! 1115: if ((recvlen = recv(fd, buffer + buflen, (*ispost) ? 1 : sizeof(buffer) - 1 - buflen, 0)) < 0) {
! 1116: if (errno != ECONNRESET)
! 1117: log_err(errno, "recv() failed!");
! 1118: return -1;
! 1119: }
! 1120:
! 1121: if (recvlen == 0) done=1;
! 1122: buflen += recvlen;
! 1123: buffer[buflen] = 0;
! 1124: }
! 1125:
! 1126: if (buflen == 0) {
! 1127: log_dbg("No data in HTTP request!");
! 1128: return -1;
! 1129: }
! 1130:
! 1131: while ((eol = strstr(buffer, "\r\n"))) {
! 1132: size_t linelen = eol - buffer;
! 1133: *eol = 0;
! 1134:
! 1135: if (lines++ == 0) { /* first line */
! 1136: size_t dstlen = 0;
! 1137: char *p1 = buffer;
! 1138: char *p2;
! 1139:
! 1140: if (optionsdebug)
! 1141: log_dbg("http-request: %s", buffer);
! 1142:
! 1143: if (!strncmp("GET ", p1, 4)) { p1 += 4; *ispost = 0; }
! 1144: else if (!strncmp("HEAD ", p1, 5)) { p1 += 5; *ispost = 0; }
! 1145: else if ((*ispost) &&
! 1146: !strncmp("POST ", p1, 5)) { p1 += 5; *ispost = 1; }
! 1147: else {
! 1148: if (optionsdebug)
! 1149: log_dbg("Unhandled http request: %s", buffer);
! 1150: return -1;
! 1151: }
! 1152:
! 1153: while (*p1 == ' ') p1++; /* Advance through additional white space */
! 1154: if (*p1 == '/') p1++;
! 1155: else return -1;
! 1156:
! 1157: /* The path ends with a ? or a space */
! 1158: p2 = strchr(p1, '?');
! 1159: if (!p2) p2 = strchr(p1, ' ');
! 1160: if (!p2) return -1;
! 1161: dstlen = p2 - p1;
! 1162:
! 1163: if (dstlen >= sizeof(path)-1)
! 1164: dstlen = sizeof(path)-1;
! 1165:
! 1166: strncpy(path, p1, dstlen);
! 1167:
! 1168: if (optionsdebug)
! 1169: log_dbg("The path: %s", path);
! 1170:
! 1171: /* TODO: Should also check the Host: to make sure we are talking directly to uamlisten */
! 1172:
! 1173: if (!strncmp(path, "json/", 5) && strlen(path) > 6) {
! 1174: int i, last=strlen(path)-5;
! 1175:
! 1176: conn->format = REDIR_FMT_JSON;
! 1177:
! 1178: for (i=0; i < last; i++)
! 1179: path[i] = path[i+5];
! 1180:
! 1181: path[last]=0;
! 1182:
! 1183: log_dbg("The (json format) path: %s", path);
! 1184: }
! 1185:
! 1186: if ((!strcmp(path, "logon")) || (!strcmp(path, "login")))
! 1187: conn->type = REDIR_LOGIN;
! 1188: else if ((!strcmp(path, "logoff")) || (!strcmp(path, "logout")))
! 1189: conn->type = REDIR_LOGOUT;
! 1190: else if (!strncmp(path, "www/", 4) && strlen(path) > 4)
! 1191: conn->type = REDIR_WWW;
! 1192: else if (!strcmp(path, "status"))
! 1193: conn->type = REDIR_STATUS;
! 1194: else if (!strncmp(path, "msdownload", 10))
! 1195: { conn->type = REDIR_MSDOWNLOAD; return 0; }
! 1196: else if (!strcmp(path, "prelogin"))
! 1197: { conn->type = REDIR_PRELOGIN; return 0; }
! 1198: else if (!strcmp(path, "abort"))
! 1199: { conn->type = REDIR_ABORT; return 0; }
! 1200:
! 1201: if (*p2 == '?') {
! 1202: p1 = p2 + 1;
! 1203: p2 = strchr(p1, ' ');
! 1204:
! 1205: if (p2) {
! 1206: dstlen = p2 - p1;
! 1207:
! 1208: if (dstlen >= qslen-1)
! 1209: dstlen = qslen-1;
! 1210:
! 1211: strncpy(qs, p1, dstlen);
! 1212:
! 1213: if (optionsdebug)
! 1214: log_dbg("Query string: %s", qs);
! 1215: }
! 1216: }
! 1217: } else if (linelen == 0) {
! 1218: /* end of headers */
! 1219: /*log_dbg("end of http-request");*/
! 1220: done = 1;
! 1221: break;
! 1222: } else {
! 1223: /* headers */
! 1224: char *p;
! 1225: size_t len;
! 1226:
! 1227: if (!strncasecmp(buffer,"Host:",5)) {
! 1228: p = buffer + 5;
! 1229: while (*p && isspace(*p)) p++;
! 1230: len = strlen(p);
! 1231: if (len >= sizeof(host)-1)
! 1232: len = sizeof(host)-1;
! 1233: strncpy(host, p, len);
! 1234: host[len]=0;
! 1235: if (optionsdebug)
! 1236: log_dbg("Host: %s",host);
! 1237: }
! 1238: else if (!strncasecmp(buffer,"Content-Length:",15)) {
! 1239: p = buffer + 15;
! 1240: while (*p && isspace(*p)) p++;
! 1241: len = strlen(p);
! 1242: if (len > 0) *clen = atoi(p);
! 1243: if (optionsdebug)
! 1244: log_dbg("Content-Length: %s",p);
! 1245: }
! 1246: else if (!strncasecmp(buffer,"User-Agent:",11)) {
! 1247: p = buffer + 11;
! 1248: while (*p && isspace(*p)) p++;
! 1249: len = strlen(p);
! 1250: if (len >= sizeof(conn->useragent)-1)
! 1251: len = sizeof(conn->useragent)-1;
! 1252: strncpy(conn->useragent, p, len);
! 1253: conn->useragent[len]=0;
! 1254: if (optionsdebug)
! 1255: log_dbg("User-Agent: %s",conn->useragent);
! 1256: }
! 1257: }
! 1258:
! 1259: /* shift buffer */
! 1260: linelen += 2;
! 1261: for (i = 0; i < (int)(buflen - linelen); i++)
! 1262: buffer[i] = buffer[(int)linelen+i];
! 1263:
! 1264: buflen -= linelen;
! 1265: }
! 1266: }
! 1267:
! 1268: switch(conn->type) {
! 1269:
! 1270: case REDIR_STATUS:
! 1271: return 0;
! 1272:
! 1273: case REDIR_LOGIN:
! 1274: {
! 1275: bstring bt = bfromcstr("");
! 1276:
! 1277: if (!redir_getparam(redir, qs, "lang", bt))
! 1278: bstrtocstr(bt, conn->lang, sizeof(conn->lang));
! 1279:
! 1280: if (!redir_getparam(redir, qs, "ident", bt) && bt->slen)
! 1281: conn->chap_ident = atoi((char*)bt->data);
! 1282:
! 1283: if (redir_getparam(redir, qs, "username", bt)) {
! 1284: log_err(0, "No username found in login request");
! 1285: bdestroy(bt);
! 1286: return -1;
! 1287: }
! 1288:
! 1289: bstrtocstr(bt, conn->s_state.redir.username, sizeof(conn->s_state.redir.username));
! 1290: log_dbg("-->> Setting username=[%s]",conn->s_state.redir.username);
! 1291:
! 1292: if (!redir_getparam(redir, qs, "userurl", bt)) {
! 1293: bstring bt2 = bfromcstr("");
! 1294: redir_urldecode(bt, bt2);
! 1295: bstrtocstr(bt2, conn->s_state.redir.userurl, sizeof(conn->s_state.redir.userurl));
! 1296: if (optionsdebug)
! 1297: log_dbg("-->> Setting userurl=[%s]",conn->s_state.redir.userurl);
! 1298: bdestroy(bt2);
! 1299: }
! 1300:
! 1301: if (!redir_getparam(redir, qs, "response", bt)) {
! 1302: redir_hextochar(bt->data, conn->chappassword);
! 1303: conn->chap = 1;
! 1304: conn->password[0] = 0;
! 1305: }
! 1306: else if (!redir_getparam(redir, qs, "password", bt)) {
! 1307: redir_hextochar(bt->data, conn->password);
! 1308: conn->chap = 0;
! 1309: conn->chappassword[0] = 0;
! 1310: } else {
! 1311: if (optionsdebug)
! 1312: log_dbg("No password found!");
! 1313: bdestroy(bt);
! 1314: return -1;
! 1315: }
! 1316: bdestroy(bt);
! 1317: }
! 1318: break;
! 1319:
! 1320: case REDIR_LOGOUT:
! 1321: case REDIR_PRELOGIN:
! 1322: {
! 1323: bstring bt = bfromcstr("");
! 1324: if (!redir_getparam(redir, qs, "userurl", bt)) {
! 1325: bstring bt2 = bfromcstr("");
! 1326: redir_urldecode(bt, bt2);
! 1327: bstrtocstr(bt2, conn->s_state.redir.userurl, sizeof(conn->s_state.redir.userurl));
! 1328: if (optionsdebug)
! 1329: log_dbg("-->> Setting userurl=[%s]",conn->s_state.redir.userurl);
! 1330: bdestroy(bt2);
! 1331: }
! 1332: bdestroy(bt);
! 1333: }
! 1334: break;
! 1335:
! 1336: case REDIR_WWW:
! 1337: {
! 1338: bstring bt = bfromcstr(path+4);
! 1339: bstring bt2 = bfromcstr("");
! 1340: redir_urldecode(bt, bt2);
! 1341: bstrtocstr(bt2,conn->wwwfile, sizeof(conn->wwwfile));
! 1342: if (optionsdebug)
! 1343: log_dbg("Serving file %s", conn->wwwfile);
! 1344: bdestroy(bt2);
! 1345: bdestroy(bt);
! 1346: }
! 1347: break;
! 1348:
! 1349: default:
! 1350: {
! 1351: /* some basic checks for urls we don't care about */
! 1352:
! 1353: snprintf(conn->s_state.redir.userurl, sizeof(conn->s_state.redir.userurl), "http://%s/%s%s%s",
! 1354: host, path, qs[0] ? "?" : "", qs[0] ? qs : "");
! 1355:
! 1356: if (optionsdebug)
! 1357: log_dbg("-->> Setting userurl=[%s]",conn->s_state.redir.userurl);
! 1358: }
! 1359: break;
! 1360:
! 1361: }
! 1362:
! 1363: return 0;
! 1364: }
! 1365:
! 1366: /* Radius callback when access accept/reject/challenge has been received */
! 1367: static int redir_cb_radius_auth_conf(struct radius_t *radius,
! 1368: struct radius_packet_t *pack,
! 1369: struct radius_packet_t *pack_req, void *cbp) {
! 1370: struct redir_conn_t *conn = (struct redir_conn_t*) cbp;
! 1371: struct radius_attr_t *stateattr = NULL;
! 1372: struct radius_attr_t *classattr = NULL;
! 1373: struct radius_attr_t *attr = NULL;
! 1374: char attrs[RADIUS_ATTR_VLEN+1];
! 1375:
! 1376: if (optionsdebug)
! 1377: log_dbg("Received access request confirmation from radius server\n");
! 1378:
! 1379: if (!conn) {
! 1380: log_err(0, "No peer protocol defined");
! 1381: conn->response = REDIR_FAILED_OTHER;
! 1382: return 0;
! 1383: }
! 1384:
! 1385: if (!pack) { /* Timeout */
! 1386: log_err(0, "Radius request timed out");
! 1387: conn->response = REDIR_FAILED_OTHER;
! 1388: return 0;
! 1389: }
! 1390:
! 1391: /* We expect ACCESS-ACCEPT, ACCESS-REJECT (or ACCESS-CHALLENGE) */
! 1392: if ((pack->code != RADIUS_CODE_ACCESS_REJECT) &&
! 1393: (pack->code != RADIUS_CODE_ACCESS_CHALLENGE) &&
! 1394: (pack->code != RADIUS_CODE_ACCESS_ACCEPT)) {
! 1395: log_err(0, "Unknown radius access reply code %d", pack->code);
! 1396: conn->response = REDIR_FAILED_OTHER;
! 1397: return 0;
! 1398: }
! 1399:
! 1400: /* Reply message (might be present in both ACCESS-ACCEPT and ACCESS-REJECT */
! 1401: if (!radius_getattr(pack, &attr, RADIUS_ATTR_REPLY_MESSAGE, 0, 0, 0)) {
! 1402: memcpy(conn->replybuf, attr->v.t, attr->l-2);
! 1403: conn->replybuf[attr->l-2] = 0;
! 1404: conn->reply = conn->replybuf;
! 1405: }
! 1406: else {
! 1407: conn->replybuf[0] = 0;
! 1408: conn->reply = NULL;
! 1409: }
! 1410:
! 1411: config_radius_session(&conn->s_params, pack, 0);
! 1412:
! 1413: /* Class */
! 1414: if (!radius_getattr(pack, &classattr, RADIUS_ATTR_CLASS, 0, 0, 0)) {
! 1415: conn->s_state.redir.classlen = classattr->l-2;
! 1416: memcpy(conn->s_state.redir.classbuf, classattr->v.t, classattr->l-2);
! 1417: log_dbg("!!!! CLASSLEN = %d !!!!", conn->s_state.redir.classlen);
! 1418: }
! 1419: /*else {
! 1420: log_dbg("!!!! RESET CLASSLEN !!!!");
! 1421: conn->s_state.redir.classlen = 0;
! 1422: }*/
! 1423:
! 1424: if (pack->code != RADIUS_CODE_ACCESS_ACCEPT) {
! 1425: /* ACCESS-REJECT */
! 1426: conn->response = REDIR_FAILED_REJECT;
! 1427: return 0;
! 1428: }
! 1429:
! 1430: /* ACCESS-ACCEPT */
! 1431:
! 1432: /* State */
! 1433: if (!radius_getattr(pack, &stateattr, RADIUS_ATTR_STATE, 0, 0, 0)) {
! 1434: conn->s_state.redir.statelen = stateattr->l-2;
! 1435: memcpy(conn->s_state.redir.statebuf, stateattr->v.t, stateattr->l-2);
! 1436: }
! 1437: else {
! 1438: conn->s_state.redir.statelen = 0;
! 1439: }
! 1440:
! 1441: if (conn->s_params.sessionterminatetime) {
! 1442: time_t timenow = time(0);
! 1443: if (timenow > conn->s_params.sessionterminatetime) {
! 1444: conn->response = REDIR_FAILED_OTHER;
! 1445: log_warn(0, "WISPr-Session-Terminate-Time in the past received: %s", attrs);
! 1446: return 0;
! 1447: }
! 1448: }
! 1449:
! 1450: conn->response = REDIR_SUCCESS;
! 1451: return 0;
! 1452: }
! 1453:
! 1454: /* Send radius Access-Request and wait for answer */
! 1455: static int redir_radius(struct redir_t *redir, struct in_addr *addr,
! 1456: struct redir_conn_t *conn, char reauth) {
! 1457: unsigned char chap_password[REDIR_MD5LEN + 2];
! 1458: unsigned char chap_challenge[REDIR_MD5LEN];
! 1459: unsigned char user_password[REDIR_MD5LEN + 1];
! 1460: struct radius_packet_t radius_pack;
! 1461: struct radius_t *radius; /* Radius client instance */
! 1462: struct timeval idleTime; /* How long to select() */
! 1463: time_t endtime, now; /* for radius wait */
! 1464: int maxfd = 0; /* For select() */
! 1465: fd_set fds; /* For select() */
! 1466: int status;
! 1467:
! 1468: MD5_CTX context;
! 1469:
! 1470: char mac[REDIR_MACSTRLEN+1];
! 1471: char url[REDIR_URL_LEN];
! 1472: int n;
! 1473:
! 1474: if (radius_new(&radius,
! 1475: &redir->radiuslisten, 0, 0,
! 1476: NULL, 0, NULL, NULL, NULL)) {
! 1477: log_err(0, "Failed to create radius");
! 1478: return -1;
! 1479: }
! 1480:
! 1481: radius->next = redir_radius_id;
! 1482:
! 1483: if (radius->fd > maxfd)
! 1484: maxfd = radius->fd;
! 1485:
! 1486: radius_set(radius, dhcp ? dhcp->ipif.hwaddr : 0, (options.debug & DEBUG_RADIUS));
! 1487:
! 1488: radius_set_cb_auth_conf(radius, redir_cb_radius_auth_conf);
! 1489:
! 1490: radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST);
! 1491:
! 1492: if (optionsdebug)
! 1493: log_dbg("created radius packet (code=%d, id=%d, len=%d)\n",
! 1494: radius_pack.code, radius_pack.id, ntohs(radius_pack.length));
! 1495:
! 1496: radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
! 1497: (uint8_t*) conn->s_state.redir.username, strlen(conn->s_state.redir.username));
! 1498:
! 1499: /* If lang on logon url, then send it with attribute ChilliSpot-Lang */
! 1500: if(conn->lang[0])
! 1501: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1502: RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_LANG,
! 1503: 0, (uint8_t*) conn->lang, strlen(conn->lang));
! 1504:
! 1505: if (options.radiusoriginalurl)
! 1506: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1507: RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_ORIGINALURL,
! 1508: 0, (uint8_t*) conn->s_state.redir.userurl, strlen(conn->s_state.redir.userurl));
! 1509:
! 1510: if (redir->secret && *redir->secret) {
! 1511: /*fprintf(stderr,"SECRET: [%s]\n",redir->secret);*/
! 1512: /* Get MD5 hash on challenge and uamsecret */
! 1513: MD5Init(&context);
! 1514: MD5Update(&context, conn->s_state.redir.uamchal, REDIR_MD5LEN);
! 1515: MD5Update(&context, (uint8_t*) redir->secret, strlen(redir->secret));
! 1516: MD5Final(chap_challenge, &context);
! 1517: }
! 1518: else {
! 1519: memcpy(chap_challenge, conn->s_state.redir.uamchal, REDIR_MD5LEN);
! 1520: }
! 1521:
! 1522: if (conn->chap == 0) {
! 1523: for (n=0; n < REDIR_MD5LEN; n++)
! 1524: user_password[n] = conn->password[n] ^ chap_challenge[n];
! 1525:
! 1526: radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
! 1527: (uint8_t*)user_password, REDIR_MD5LEN);
! 1528: }
! 1529: else if (conn->chap == 1) {
! 1530: chap_password[0] = conn->chap_ident; /* Chap ident found on logon url */
! 1531: memcpy(chap_password+1, conn->chappassword, REDIR_MD5LEN);
! 1532:
! 1533: radius_addattr(radius, &radius_pack, RADIUS_ATTR_CHAP_CHALLENGE, 0, 0, 0,
! 1534: chap_challenge, REDIR_MD5LEN);
! 1535:
! 1536: radius_addattr(radius, &radius_pack, RADIUS_ATTR_CHAP_PASSWORD, 0, 0, 0,
! 1537: chap_password, REDIR_MD5LEN+1);
! 1538: }
! 1539:
! 1540: radius_addnasip(radius, &radius_pack);
! 1541:
! 1542: radius_addattr(radius, &radius_pack, RADIUS_ATTR_SERVICE_TYPE, 0, 0,
! 1543: RADIUS_SERVICE_TYPE_LOGIN, NULL, 0); /* WISPr_V1.0 */
! 1544:
! 1545: radius_addattr(radius, &radius_pack, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0,
! 1546: ntohl(conn->hisip.s_addr), NULL, 0); /* WISPr_V1.0 */
! 1547:
! 1548: /* Include his MAC address */
! 1549: snprintf(mac, REDIR_MACSTRLEN+1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
! 1550: conn->hismac[0], conn->hismac[1],
! 1551: conn->hismac[2], conn->hismac[3],
! 1552: conn->hismac[4], conn->hismac[5]);
! 1553:
! 1554: radius_addattr(radius, &radius_pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
! 1555: (uint8_t*) mac, REDIR_MACSTRLEN);
! 1556:
! 1557: radius_addcalledstation(radius, &radius_pack);
! 1558:
! 1559:
! 1560: if (redir->radiusnasid)
! 1561: radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
! 1562: (uint8_t*) redir->radiusnasid,
! 1563: strlen(redir->radiusnasid)); /* WISPr_V1.0 */
! 1564:
! 1565:
! 1566: radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0,
! 1567: (uint8_t*) conn->s_state.sessionid, REDIR_SESSIONID_LEN-1);
! 1568:
! 1569: log_dbg("!!!! CLASSLEN = %d !!!!", conn->s_state.redir.classlen);
! 1570: if (conn->s_state.redir.classlen) {
! 1571: radius_addattr(radius, &radius_pack, RADIUS_ATTR_CLASS, 0, 0, 0,
! 1572: conn->s_state.redir.classbuf,
! 1573: conn->s_state.redir.classlen);
! 1574: }
! 1575:
! 1576: radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
! 1577: redir->radiusnasporttype, NULL, 0);
! 1578:
! 1579: radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT, 0, 0,
! 1580: conn->nasport, NULL, 0);
! 1581:
! 1582: if (redir->radiuslocationid)
! 1583: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1584: RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_ID, 0,
! 1585: (uint8_t*) redir->radiuslocationid,
! 1586: strlen(redir->radiuslocationid));
! 1587:
! 1588: if (redir->radiuslocationname)
! 1589: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1590: RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_NAME, 0,
! 1591: (uint8_t*) redir->radiuslocationname,
! 1592: strlen(redir->radiuslocationname));
! 1593:
! 1594: if (snprintf(url, sizeof(url)-1, "http://%s:%d/logoff",
! 1595: inet_ntoa(redir->addr), redir->port) > 0)
! 1596: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1597: RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOGOFF_URL, 0,
! 1598: (uint8_t*)url, strlen(url));
! 1599:
! 1600: if (options.openidauth)
! 1601: radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
! 1602: RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_CONFIG,
! 1603: 0, (uint8_t*)"allow-openidauth", 16);
! 1604:
! 1605: radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
! 1606: 0, 0, 0, NULL, RADIUS_MD5LEN);
! 1607:
! 1608: if (optionsdebug)
! 1609: log_dbg("sending radius packet (code=%d, id=%d, len=%d)\n",
! 1610: radius_pack.code, radius_pack.id, ntohs(radius_pack.length));
! 1611:
! 1612: radius_req(radius, &radius_pack, conn);
! 1613:
! 1614: now = time(NULL);
! 1615: endtime = now + REDIR_RADIUS_MAX_TIME;
! 1616:
! 1617: while (endtime > now) {
! 1618:
! 1619: FD_ZERO(&fds);
! 1620: if (radius->fd != -1) FD_SET(radius->fd, &fds);
! 1621: if (radius->proxyfd != -1) FD_SET(radius->proxyfd, &fds);
! 1622:
! 1623: idleTime.tv_sec = 0;
! 1624: idleTime.tv_usec = REDIR_RADIUS_SELECT_TIME;
! 1625: radius_timeleft(radius, &idleTime);
! 1626:
! 1627: switch (status = select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
! 1628: case -1:
! 1629: log_err(errno, "select() returned -1!");
! 1630: break;
! 1631: case 0:
! 1632: /*log_dbg("Select returned 0");*/
! 1633: radius_timeout(radius);
! 1634: break;
! 1635: default:
! 1636: break;
! 1637: }
! 1638:
! 1639: if (status > 0) {
! 1640: if ((radius->fd != -1) && FD_ISSET(radius->fd, &fds) &&
! 1641: radius_decaps(radius) < 0) {
! 1642: log_err(0, "radius_ind() failed!");
! 1643: }
! 1644:
! 1645: if ((radius->proxyfd != -1) && FD_ISSET(radius->proxyfd, &fds) &&
! 1646: radius_proxy_ind(radius) < 0) {
! 1647: log_err(0, "radius_proxy_ind() failed!");
! 1648: }
! 1649: }
! 1650:
! 1651: if (conn->response) {
! 1652: radius_free(radius);
! 1653: return 0;
! 1654: }
! 1655:
! 1656: now = time(NULL);
! 1657: }
! 1658:
! 1659: return 0;
! 1660: }
! 1661:
! 1662: int set_nonblocking(int fd) {
! 1663: int flags = fcntl(fd, F_GETFL);
! 1664: if (flags < 0) return -1;
! 1665: fcntl(fd, F_SETFL, flags | O_NONBLOCK);
! 1666: return 0;
! 1667: }
! 1668:
! 1669: int clear_nonblocking(int fd) {
! 1670: int flags = fcntl(fd, F_GETFL);
! 1671: if (flags < 0) return -1;
! 1672: fcntl(fd, F_SETFL, flags & (~O_NONBLOCK));
! 1673: return 0;
! 1674: }
! 1675:
! 1676: int is_local_user(struct redir_t *redir, struct redir_conn_t *conn) {
! 1677: unsigned char user_password[REDIR_MD5LEN+1];
! 1678: unsigned char chap_challenge[REDIR_MD5LEN];
! 1679: unsigned char tmp[REDIR_MD5LEN+1];
! 1680: char u[256]; char p[256];
! 1681: size_t usernamelen, sz=1024;
! 1682: ssize_t len;
! 1683: int match=0;
! 1684: char *line=0;
! 1685: MD5_CTX context;
! 1686: FILE *f;
! 1687:
! 1688: if (!options.localusers) return 0;
! 1689:
! 1690: log_dbg("checking %s for user %s", options.localusers, conn->s_state.redir.username);
! 1691:
! 1692: if (!(f = fopen(options.localusers, "r"))) {
! 1693: log_err(errno, "fopen() failed opening %s!", options.localusers);
! 1694: return 0;
! 1695: }
! 1696:
! 1697: if (options.debug) {/*debug*/
! 1698: char buffer[64];
! 1699: redir_chartohex(conn->s_state.redir.uamchal, buffer);
! 1700: log_dbg("challenge: %s", buffer);
! 1701: }/**/
! 1702:
! 1703: if (redir->secret && *redir->secret) {
! 1704: MD5Init(&context);
! 1705: MD5Update(&context, (uint8_t*)conn->s_state.redir.uamchal, REDIR_MD5LEN);
! 1706: MD5Update(&context, (uint8_t*)redir->secret, strlen(redir->secret));
! 1707: MD5Final(chap_challenge, &context);
! 1708: }
! 1709: else {
! 1710: memcpy(chap_challenge, conn->s_state.redir.uamchal, REDIR_MD5LEN);
! 1711: }
! 1712:
! 1713: if (options.debug) {/*debug*/
! 1714: char buffer[64];
! 1715: redir_chartohex(chap_challenge, buffer);
! 1716: log_dbg("chap challenge: %s", buffer);
! 1717: }/**/
! 1718:
! 1719: if (conn->chap == 0) {
! 1720: int n;
! 1721: for (n=0; n < REDIR_MD5LEN; n++)
! 1722: user_password[n] = conn->password[n] ^ chap_challenge[n];
! 1723: }
! 1724: else if (conn->chap == 1) {
! 1725: memcpy(user_password, conn->chappassword, REDIR_MD5LEN);
! 1726: }
! 1727:
! 1728: user_password[REDIR_MD5LEN] = 0;
! 1729:
! 1730: log_dbg("looking for %s", conn->s_state.redir.username);
! 1731: usernamelen = strlen(conn->s_state.redir.username);
! 1732:
! 1733: line=(char*)malloc(sz);
! 1734: while ((len = getline(&line, &sz, f)) > 0) {
! 1735: if (len > 3 && len < sizeof(u) && line[0] != '#') {
! 1736: char *pl=line, /* pointer to current line */
! 1737: *pu=u, /* pointer to username */
! 1738: *pp=p; /* pointer to password */
! 1739:
! 1740: /* username until the first ':' */
! 1741: while (*pl && *pl != ':') *pu++ = *pl++;
! 1742:
! 1743: /* skip over ':' otherwise error */
! 1744: if (*pl == ':') pl++;
! 1745: else {
! 1746: log_warn(0, "not a valid localusers line: %s", line);
! 1747: continue;
! 1748: }
! 1749:
! 1750: /* password until the next ':' */
! 1751: while (*pl && *pl != ':' && *pl != '\n') *pp++ = *pl++;
! 1752:
! 1753: *pu = 0; /* null terminate */
! 1754: *pp = 0;
! 1755:
! 1756: if (usernamelen == strlen(u) &&
! 1757: !strncmp(conn->s_state.redir.username, u, usernamelen)) {
! 1758:
! 1759: log_dbg("found %s, checking password", u);
! 1760:
! 1761: if (conn->chap == 0) {
! 1762: int n;
! 1763: for (n=0; n < REDIR_MD5LEN; n++)
! 1764: tmp[n] = p[n] ^ chap_challenge[n];
! 1765: }
! 1766: else if (conn->chap == 1) {
! 1767: MD5Init(&context);
! 1768: MD5Update(&context, (uint8_t*)&conn->chap_ident, 1);
! 1769: MD5Update(&context, (uint8_t*)p, strlen(p));
! 1770: MD5Update(&context, chap_challenge, REDIR_MD5LEN);
! 1771: MD5Final(tmp, &context);
! 1772: }
! 1773:
! 1774: tmp[REDIR_MD5LEN] = 0;
! 1775:
! 1776: if (!memcmp(user_password, tmp, REDIR_MD5LEN))
! 1777: match = 1;
! 1778:
! 1779: break;
! 1780: }
! 1781: }
! 1782: }
! 1783:
! 1784: log_dbg("user %s %s", conn->s_state.redir.username, match ? "found" : "not found");
! 1785:
! 1786: fclose(f);
! 1787: free(line);
! 1788: return match;
! 1789: }
! 1790:
! 1791:
! 1792: /* redir_accept() does the following:
! 1793: 1) forks a child process
! 1794: 2) Accepts the tcp connection
! 1795: 3) Analyses a HTTP get request
! 1796: 4) GET request can be one of the following:
! 1797: a) Logon request with username and challenge response
! 1798: - Does a radius request
! 1799: - If OK send result to parent and redirect to welcome page
! 1800: - Else redirect to error login page
! 1801: b) Logoff request
! 1802: - Send logoff request to parent
! 1803: - Redirect to login page?
! 1804: c) Request for another server
! 1805: - Redirect to login server.
! 1806:
! 1807: Incoming requests are identified only by their IP address. No MAC
! 1808: address information is obtained. The main security problem is denial
! 1809: of service attacks by malicious hosts sending logoff requests for
! 1810: clients. This can be prevented by checking incoming packets for
! 1811: matching MAC and src IP addresses.
! 1812: */
! 1813:
! 1814: int redir_accept(struct redir_t *redir, int idx) {
! 1815: int status;
! 1816: int new_socket;
! 1817: struct sockaddr_in address;
! 1818: socklen_t addrlen;
! 1819:
! 1820: addrlen = sizeof(struct sockaddr_in);
! 1821:
! 1822: if ((new_socket = accept(redir->fd[idx], (struct sockaddr *)&address, &addrlen)) < 0) {
! 1823: if (errno != ECONNABORTED)
! 1824: log_err(errno, "accept() failed!");
! 1825: return 0;
! 1826: }
! 1827:
! 1828: /* This forks a new process. The child really should close all
! 1829: unused file descriptors and free memory allocated. This however
! 1830: is performed when the process exits, so currently we don't
! 1831: care */
! 1832:
! 1833: redir_radius_id++;
! 1834:
! 1835: if ((status = fork()) < 0) {
! 1836: log_err(errno, "fork() returned -1!");
! 1837: close(new_socket);
! 1838: return 0;
! 1839: }
! 1840:
! 1841: if (status > 0) { /* Parent */
! 1842: close(new_socket);
! 1843: return 0;
! 1844: }
! 1845:
! 1846:
! 1847: #if defined(F_DUPFD)
! 1848: if (fcntl(new_socket,F_GETFL,0) == -1) return -1;
! 1849: close(0);
! 1850: if (fcntl(new_socket,F_DUPFD,0) == -1) return -1;
! 1851: if (fcntl(new_socket,F_GETFL,1) == -1) return -1;
! 1852: close(1);
! 1853: if (fcntl(new_socket,F_DUPFD,1) == -1) return -1;
! 1854: #else
! 1855: if (dup2(new_socket,0) == -1) return -1;
! 1856: if (dup2(new_socket,1) == -1) return -1;
! 1857: #endif
! 1858:
! 1859: if (idx == 1 && options.uamui) {
! 1860: char *binqqargs[2] = { options.uamui, 0 } ;
! 1861: char buffer[128];
! 1862:
! 1863: snprintf(buffer,sizeof(buffer)-1,"%s",inet_ntoa(address.sin_addr));
! 1864: setenv("TCPREMOTEIP",buffer,1);
! 1865: setenv("REMOTE_ADDR",buffer,1);
! 1866: snprintf(buffer,sizeof(buffer)-1,"%d",ntohs(address.sin_port));
! 1867: setenv("TCPREMOTEPORT",buffer,1);
! 1868: setenv("REMOTE_PORT",buffer,1);
! 1869:
! 1870: execv(*binqqargs, binqqargs);
! 1871:
! 1872: } else {
! 1873: return redir_main(redir, 0, 1, &address, idx);
! 1874: }
! 1875:
! 1876: return 0;
! 1877: }
! 1878:
! 1879: static void redir_close(int infd, int outfd) {
! 1880: char b[128];
! 1881:
! 1882: /* Close of socket */
! 1883: if (shutdown(outfd, SHUT_WR) != 0)
! 1884: log_dbg("shutdown socket for writing");
! 1885:
! 1886: if (!set_nonblocking(infd))
! 1887: while(read(infd, b, sizeof(b)) > 0);
! 1888:
! 1889: if (shutdown(infd, SHUT_RD) != 0)
! 1890: log_dbg("shutdown socket for reading");
! 1891:
! 1892: close(outfd);
! 1893: close(infd);
! 1894: exit(0);
! 1895: }
! 1896:
! 1897:
! 1898: int redir_main(struct redir_t *redir, int infd, int outfd, struct sockaddr_in *address, int isui) {
! 1899: char hexchal[1+(2*REDIR_MD5LEN)];
! 1900: unsigned char challenge[REDIR_MD5LEN];
! 1901: size_t bufsize = REDIR_MAXBUFFER;
! 1902: char buffer[bufsize+1];
! 1903: char qs[REDIR_USERURLSIZE];
! 1904: struct redir_msg_t msg;
! 1905: ssize_t buflen;
! 1906:
! 1907: /**
! 1908: * connection state
! 1909: * 0 == un-authenticated
! 1910: * 1 == authenticated
! 1911: */
! 1912: int state = 0;
! 1913:
! 1914: /**
! 1915: * require splash or not
! 1916: */
! 1917: int splash = 0;
! 1918:
! 1919: struct redir_conn_t conn;
! 1920: struct sigaction act, oldact;
! 1921: struct itimerval itval;
! 1922: struct redir_socket socket;
! 1923: int ispost = isui;
! 1924: size_t clen = 0;
! 1925:
! 1926:
! 1927: #define redir_memcopy(msgtype) \
! 1928: redir_challenge(challenge); \
! 1929: redir_chartohex(challenge, hexchal); \
! 1930: msg.mtype = msgtype; \
! 1931: memcpy(conn.s_state.redir.uamchal, challenge, REDIR_MD5LEN); \
! 1932: if (options.debug) { \
! 1933: log_dbg("---->>> resetting challenge: %s", hexchal); \
! 1934: }
! 1935:
! 1936:
! 1937: #define redir_msg_send(msgopt) \
! 1938: msg.mdata.opt = msgopt; \
! 1939: msg.mdata.addr = address->sin_addr; \
! 1940: memcpy(&msg.mdata.params, &conn.s_params, sizeof(msg.mdata.params)); \
! 1941: memcpy(&msg.mdata.redir, &conn.s_state.redir, sizeof(msg.mdata.redir)); \
! 1942: if (msgsnd(redir->msgid, (struct msgbuf *)&msg, sizeof(msg.mdata), 0) < 0) { \
! 1943: log_err(errno, "msgsnd() failed!"); \
! 1944: redir_close(infd, outfd); \
! 1945: }
! 1946:
! 1947: /*
! 1948: * Initializations
! 1949: */
! 1950: memset(&socket,0,sizeof(socket));
! 1951: memset(hexchal, 0, sizeof(hexchal));
! 1952: memset(&conn, 0, sizeof(conn));
! 1953: memset(&msg, 0, sizeof(msg));
! 1954: memset(&act, 0, sizeof(act));
! 1955: memset(qs, 0, sizeof(qs));
! 1956:
! 1957: socket.fd[0] = infd;
! 1958: socket.fd[1] = outfd;
! 1959:
! 1960: redir->starttime = time(NULL);
! 1961:
! 1962: if (set_nonblocking(socket.fd[0])) {
! 1963: log_err(errno, "fcntl() failed");
! 1964: redir_close(infd, outfd);
! 1965: }
! 1966:
! 1967: act.sa_handler = redir_termination;
! 1968: sigaction(SIGTERM, &act, &oldact);
! 1969: sigaction(SIGINT, &act, &oldact);
! 1970: act.sa_handler = redir_alarm;
! 1971: sigaction(SIGALRM, &act, &oldact);
! 1972:
! 1973: memset(&itval, 0, sizeof(itval));
! 1974: itval.it_interval.tv_sec = REDIR_MAXTIME;
! 1975: itval.it_interval.tv_usec = 0;
! 1976: itval.it_value.tv_sec = REDIR_MAXTIME;
! 1977: itval.it_value.tv_usec = 0;
! 1978:
! 1979: if (setitimer(ITIMER_REAL, &itval, NULL)) {
! 1980: log_err(errno, "setitimer() failed!");
! 1981: }
! 1982:
! 1983: if (optionsdebug)
! 1984: log_dbg("Calling redir_getstate()");
! 1985:
! 1986: /*
! 1987: * Fetch the state of the client
! 1988: */
! 1989:
! 1990: termstate = REDIR_TERM_GETSTATE;
! 1991:
! 1992: if (!redir->cb_getstate) {
! 1993: log_err(0, "No cb_getstate() defined!");
! 1994: redir_close(infd, outfd);
! 1995: }
! 1996:
! 1997: /* get_state returns 0 for unauth'ed and 1 for auth'ed */
! 1998: state = redir->cb_getstate(redir, &address->sin_addr, &conn);
! 1999: if (state == -1) {
! 2000: redir_close(infd, outfd);
! 2001: }
! 2002:
! 2003: splash = (conn.s_params.flags & REQUIRE_UAM_SPLASH) == REQUIRE_UAM_SPLASH;
! 2004:
! 2005:
! 2006: /*
! 2007: * Parse the request, updating the status
! 2008: */
! 2009: if (optionsdebug)
! 2010: log_dbg("Get HTTP Request");
! 2011:
! 2012: termstate = REDIR_TERM_GETREQ;
! 2013: if (redir_getreq(redir, &socket, &conn, &ispost, &clen, qs, sizeof(qs))) {
! 2014: log_dbg("Error calling get_req. Terminating\n");
! 2015: redir_close(infd, outfd);
! 2016: }
! 2017:
! 2018: if (optionsdebug)
! 2019: log_dbg("Process HTTP Request");
! 2020:
! 2021: if (conn.type == REDIR_WWW) {
! 2022: int fd = -1;
! 2023: if (options.wwwdir && conn.wwwfile && *conn.wwwfile) {
! 2024: char *ctype = "text/plain";
! 2025: char *filename = conn.wwwfile;
! 2026: size_t namelen = strlen(filename);
! 2027: int parse = 0;
! 2028:
! 2029: /* check filename */
! 2030: { char *p;
! 2031: for (p=filename; *p; p++) {
! 2032: if (*p >= 'a' && *p <= 'z') continue;
! 2033: if (*p >= 'A' && *p <= 'Z') continue;
! 2034: if (*p >= '0' && *p <= '9') continue;
! 2035: if (*p == '.' || *p == '_') continue;
! 2036: /* invalid file name! */
! 2037: log_err(0, "invalid www request [%s]!", filename);
! 2038: redir_close(infd, outfd);
! 2039: }
! 2040: }
! 2041:
! 2042: /* serve the local content */
! 2043:
! 2044: if (!strcmp(filename + (namelen - 5), ".html")) ctype = "text/html";
! 2045: else if (!strcmp(filename + (namelen - 4), ".gif")) ctype = "image/gif";
! 2046: else if (!strcmp(filename + (namelen - 3), ".js")) ctype = "text/javascript";
! 2047: else if (!strcmp(filename + (namelen - 4), ".css")) ctype = "text/css";
! 2048: else if (!strcmp(filename + (namelen - 4), ".jpg")) ctype = "image/jpeg";
! 2049: else if (!strcmp(filename + (namelen - 4), ".dat")) ctype = "application/x-ns-proxy-autoconfig";
! 2050: else if (!strcmp(filename + (namelen - 4), ".png")) ctype = "image/png";
! 2051: else if (!strcmp(filename + (namelen - 4), ".swf")) ctype = "application/x-shockwave-flash";
! 2052: else if (!strcmp(filename + (namelen - 4), ".chi")){ ctype = "text/html"; parse = 1; }
! 2053: else {
! 2054: /* we do not serve it! */
! 2055: log_err(0, "invalid file extension! [%s]", filename);
! 2056: redir_close(infd, outfd);
! 2057: }
! 2058:
! 2059: if (parse) {
! 2060: if (!options.wwwbin) {
! 2061: log_err(0, "the 'wwwbin' setting must be configured for CGI use");
! 2062: redir_close(infd, outfd);
! 2063: }
! 2064:
! 2065: if (clear_nonblocking(socket.fd[0])) {
! 2066: log_err(errno, "fcntl() failed");
! 2067: }
! 2068:
! 2069: /* XXX: Todo: look for malicious content! */
! 2070:
! 2071: sprintf(buffer,"%d", clen > 0 ? clen : 0);
! 2072: setenv("CONTENT_LENGTH", buffer, 1);
! 2073: setenv("REQUEST_METHOD", ispost ? "POST" : "GET", 1);
! 2074: setenv("QUERY_STRING", qs, 1);
! 2075:
! 2076: log_dbg("Running: %s %s/%s",options.wwwbin, options.wwwdir, filename);
! 2077: sprintf(buffer, "%s/%s", options.wwwdir, filename);
! 2078:
! 2079: {
! 2080: char *binqqargs[3] = { options.wwwbin, buffer, 0 } ;
! 2081: int status;
! 2082:
! 2083: if ((status = fork()) < 0) {
! 2084: log_err(errno, "fork() returned -1!");
! 2085: /* lets just execv and ignore the extra crlf problem */
! 2086: execv(*binqqargs, binqqargs);
! 2087: }
! 2088:
! 2089: if (status > 0) { /* Parent */
! 2090: /* now wait for the child (the cgi-prog) to finish
! 2091: * and let redir_close remove unwanted data
! 2092: * (for instance) extra crlf from ie7 in POSTs)
! 2093: * to avoid a tcp-reset.
! 2094: */
! 2095: wait(NULL);
! 2096: }
! 2097: else {
! 2098: /* Child */
! 2099: execv(*binqqargs, binqqargs);
! 2100: }
! 2101: }
! 2102:
! 2103: redir_close(infd, outfd);
! 2104: }
! 2105:
! 2106: if (!chroot(options.wwwdir) && !chdir("/")) {
! 2107:
! 2108: fd = open(filename, O_RDONLY);
! 2109:
! 2110: if (fd > 0) {
! 2111:
! 2112: if (clear_nonblocking(socket.fd[0])) {
! 2113: log_err(errno, "fcntl() failed");
! 2114: }
! 2115:
! 2116: buflen = snprintf(buffer, bufsize,
! 2117: "HTTP/1.0 200 OK\r\nContent-type: %s\r\n\r\n", ctype);
! 2118:
! 2119: if (tcp_write(&socket, buffer, (size_t) buflen) < 0) {
! 2120: log_err(errno, "tcp_write() failed!");
! 2121: }
! 2122:
! 2123: while ((buflen = read(fd, buffer, bufsize)) > 0)
! 2124: if (tcp_write(&socket, buffer, (size_t) buflen) < 0)
! 2125: log_err(errno, "tcp_write() failed!");
! 2126:
! 2127: close(fd);
! 2128: redir_close(infd, outfd); /* which exits */
! 2129: }
! 2130: else log_err(0, "could not open local content file %s!", filename);
! 2131: }
! 2132: else log_err(0, "chroot to %s was not successful\n", options.wwwdir);
! 2133: }
! 2134: else log_err(0, "Required: 'wwwdir' (in chilli.conf) and 'file' query-string param\n");
! 2135:
! 2136: redir_close(infd, outfd);
! 2137: }
! 2138:
! 2139: termstate = REDIR_TERM_PROCESS;
! 2140: if (optionsdebug) log_dbg("Processing received request");
! 2141:
! 2142: /* default hexchal for use in replies */
! 2143: redir_chartohex(conn.s_state.redir.uamchal, hexchal);
! 2144:
! 2145: switch (conn.type) {
! 2146:
! 2147: case REDIR_LOGIN: {
! 2148: char reauth = 0;
! 2149:
! 2150: /* Was client was already logged on? */
! 2151: if (state == 1) {
! 2152: if (splash) {
! 2153: log_dbg("redir_accept: SPLASH reauth");
! 2154: reauth = 1;
! 2155: } else {
! 2156: log_dbg("redir_accept: already logged on");
! 2157: redir_reply(redir, &socket, &conn, REDIR_ALREADY, NULL, 0,
! 2158: NULL, NULL, conn.s_state.redir.userurl, NULL,
! 2159: NULL, conn.hismac, &conn.hisip, qs);
! 2160: redir_close(infd, outfd);
! 2161: }
! 2162: }
! 2163:
! 2164: /* Did the challenge expire? */
! 2165: if ((conn.s_state.uamtime + REDIR_CHALLENGETIMEOUT2) < time(NULL)) {
! 2166: log_dbg("redir_accept: challenge expired: %d : %d", conn.s_state.uamtime, time(NULL));
! 2167:
! 2168: redir_memcopy(REDIR_CHALLENGE);
! 2169: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2170:
! 2171: redir_reply(redir, &socket, &conn, REDIR_FAILED_OTHER, NULL,
! 2172: 0, hexchal, NULL, NULL, NULL,
! 2173: NULL, conn.hismac, &conn.hisip, qs);
! 2174:
! 2175: redir_close(infd, outfd);
! 2176: }
! 2177:
! 2178: if (is_local_user(redir, &conn)) {
! 2179: conn.response = REDIR_SUCCESS;
! 2180: }
! 2181: else {
! 2182: termstate = REDIR_TERM_RADIUS;
! 2183:
! 2184: if (optionsdebug)
! 2185: log_dbg("redir_accept: Sending radius request\n");
! 2186:
! 2187: redir_radius(redir, &address->sin_addr, &conn, reauth);
! 2188: termstate = REDIR_TERM_REPLY;
! 2189:
! 2190: if (optionsdebug)
! 2191: log_dbg("Received radius reply\n");
! 2192: }
! 2193:
! 2194: if (options.defsessiontimeout && !conn.s_params.sessiontimeout)
! 2195: conn.s_params.sessiontimeout = options.defsessiontimeout;
! 2196:
! 2197: if (options.defidletimeout && !conn.s_params.idletimeout)
! 2198: conn.s_params.idletimeout = options.defidletimeout;
! 2199:
! 2200: if (options.defbandwidthmaxdown && !conn.s_params.bandwidthmaxdown)
! 2201: conn.s_params.bandwidthmaxdown = options.defbandwidthmaxdown;
! 2202:
! 2203: if (options.defbandwidthmaxup && !conn.s_params.bandwidthmaxup)
! 2204: conn.s_params.bandwidthmaxup = options.defbandwidthmaxup;
! 2205:
! 2206: if (options.definteriminterval && !conn.s_params.interim_interval)
! 2207: conn.s_params.interim_interval = options.definteriminterval;
! 2208:
! 2209: if (conn.response == REDIR_SUCCESS) { /* Radius-Accept */
! 2210: bstring besturl = bfromcstr((char*)conn.s_params.url);
! 2211:
! 2212: conn.s_params.flags &= ~REQUIRE_UAM_SPLASH;
! 2213:
! 2214: if (reauth) {
! 2215: conn.s_params.flags |= IS_UAM_REAUTH;
! 2216: }
! 2217:
! 2218: msg.mtype = REDIR_LOGIN;
! 2219:
! 2220: if (! (besturl && besturl->slen))
! 2221: bassigncstr(besturl, conn.s_state.redir.userurl);
! 2222:
! 2223: if (redir->no_uamsuccess && besturl && besturl->slen)
! 2224: redir_reply(redir, &socket, &conn, REDIR_SUCCESS, besturl, conn.s_params.sessiontimeout,
! 2225: NULL, conn.s_state.redir.username, conn.s_state.redir.userurl, conn.reply,
! 2226: (char *)conn.s_params.url, conn.hismac, &conn.hisip, qs);
! 2227: else
! 2228: redir_reply(redir, &socket, &conn, REDIR_SUCCESS, NULL, conn.s_params.sessiontimeout,
! 2229: NULL, conn.s_state.redir.username, conn.s_state.redir.userurl, conn.reply,
! 2230: (char *)conn.s_params.url, conn.hismac, &conn.hisip, qs);
! 2231:
! 2232: bdestroy(besturl);
! 2233: }
! 2234: else {
! 2235: bstring besturl = bfromcstr((char *)conn.s_params.url);
! 2236: int hasnexturl = (besturl && besturl->slen > 5);
! 2237:
! 2238: if (!hasnexturl) {
! 2239: redir_memcopy(REDIR_CHALLENGE);
! 2240: } else {
! 2241: msg.mtype = REDIR_NOTYET;
! 2242: }
! 2243:
! 2244: redir_reply(redir, &socket, &conn, REDIR_FAILED_REJECT,
! 2245: hasnexturl ? besturl : NULL,
! 2246: 0, hexchal, NULL, conn.s_state.redir.userurl, conn.reply,
! 2247: (char *)conn.s_params.url, conn.hismac, &conn.hisip, qs);
! 2248:
! 2249: bdestroy(besturl);
! 2250: }
! 2251:
! 2252: if (optionsdebug) log_dbg("-->> Msg userurl=[%s]\n",conn.s_state.redir.userurl);
! 2253: redir_msg_send(REDIR_MSG_OPT_REDIR | REDIR_MSG_OPT_PARAMS);
! 2254:
! 2255: redir_close(infd, outfd);
! 2256: }
! 2257:
! 2258: case REDIR_LOGOUT:
! 2259: {
! 2260: bstring besturl = bfromcstr((char *)conn.s_params.url);
! 2261:
! 2262: redir_memcopy(REDIR_LOGOUT);
! 2263: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2264:
! 2265: conn.s_state.authenticated=0;
! 2266:
! 2267: if (! (besturl && besturl->slen))
! 2268: bassigncstr(besturl, conn.s_state.redir.userurl);
! 2269:
! 2270: if (redir->no_uamsuccess && besturl && besturl->slen)
! 2271: redir_reply(redir, &socket, &conn, REDIR_LOGOFF, besturl, 0,
! 2272: hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2273: NULL, conn.hismac, &conn.hisip, qs);
! 2274: else
! 2275: redir_reply(redir, &socket, &conn, REDIR_LOGOFF, NULL, 0,
! 2276: hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2277: NULL, conn.hismac, &conn.hisip, qs);
! 2278:
! 2279: bdestroy(besturl);
! 2280:
! 2281: redir_close(infd, outfd);
! 2282: }
! 2283:
! 2284: case REDIR_PRELOGIN:
! 2285:
! 2286: /* Did the challenge expire? */
! 2287: if ((conn.s_state.uamtime + REDIR_CHALLENGETIMEOUT1) < time(NULL)) {
! 2288: redir_memcopy(REDIR_CHALLENGE);
! 2289: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2290: }
! 2291:
! 2292: if (state == 1) {
! 2293: redir_reply(redir, &socket, &conn, REDIR_ALREADY,
! 2294: NULL, 0, NULL, NULL, conn.s_state.redir.userurl, NULL,
! 2295: NULL, conn.hismac, &conn.hisip, qs);
! 2296: }
! 2297: else {
! 2298: redir_reply(redir, &socket, &conn, REDIR_NOTYET,
! 2299: NULL, 0, hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2300: NULL, conn.hismac, &conn.hisip, qs);
! 2301: }
! 2302: redir_close(infd, outfd);
! 2303:
! 2304: case REDIR_ABORT:
! 2305:
! 2306: if (state == 1) {
! 2307: redir_reply(redir, &socket, &conn, REDIR_ABORT_NAK,
! 2308: NULL, 0, NULL, NULL, conn.s_state.redir.userurl, NULL,
! 2309: NULL, conn.hismac, &conn.hisip, qs);
! 2310: }
! 2311: else {
! 2312: redir_memcopy(REDIR_ABORT);
! 2313: redir_msg_send(0);
! 2314:
! 2315: redir_reply(redir, &socket, &conn, REDIR_ABORT_ACK,
! 2316: NULL, 0, hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2317: NULL, conn.hismac, &conn.hisip, qs);
! 2318: }
! 2319: redir_close(infd, outfd);
! 2320:
! 2321: case REDIR_ABOUT:
! 2322: redir_reply(redir, &socket, &conn, REDIR_ABOUT, NULL,
! 2323: 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, qs);
! 2324: redir_close(infd, outfd);
! 2325:
! 2326: case REDIR_STATUS:
! 2327: {
! 2328: uint32_t sessiontime;
! 2329: uint32_t timeleft;
! 2330: time_t timenow = time(0);
! 2331:
! 2332: /* Did the challenge expire? */
! 2333: if ((conn.s_state.uamtime + REDIR_CHALLENGETIMEOUT1) < time(NULL)) {
! 2334: redir_memcopy(REDIR_CHALLENGE);
! 2335: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2336: }
! 2337:
! 2338: sessiontime = timenow - conn.s_state.start_time;
! 2339:
! 2340: if (conn.s_params.sessiontimeout)
! 2341: timeleft = conn.s_params.sessiontimeout - sessiontime;
! 2342: else
! 2343: timeleft = 0;
! 2344:
! 2345: redir_reply(redir, &socket, &conn, REDIR_STATUS, NULL, timeleft,
! 2346: hexchal, conn.s_state.redir.username, conn.s_state.redir.userurl, conn.reply,
! 2347: (char *)conn.s_params.url, conn.hismac, &conn.hisip, qs);
! 2348:
! 2349: redir_close(infd, outfd);
! 2350: }
! 2351:
! 2352: case REDIR_MSDOWNLOAD:
! 2353: buflen = snprintf(buffer, bufsize, "HTTP/1.0 403 Forbidden\r\n\r\n");
! 2354: tcp_write(&socket, buffer, buflen);
! 2355: redir_close(infd, outfd);
! 2356: }
! 2357:
! 2358: /* It was not a request for a known path. It must be an original request */
! 2359: if (optionsdebug)
! 2360: log_dbg("redir_accept: Original request");
! 2361:
! 2362:
! 2363: /* Did the challenge expire? */
! 2364: if ((conn.s_state.uamtime + REDIR_CHALLENGETIMEOUT1) < time(NULL)) {
! 2365: redir_memcopy(REDIR_CHALLENGE);
! 2366: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2367: }
! 2368: else {
! 2369: redir_chartohex(conn.s_state.redir.uamchal, hexchal);
! 2370: /*
! 2371: redir_memcopy(REDIR_CHALLENGE);
! 2372: redir_msg_send(REDIR_MSG_OPT_REDIR);
! 2373: */
! 2374: }
! 2375:
! 2376: if (redir->homepage) {
! 2377: bstring url = bfromcstralloc(1024,"");
! 2378: bstring urlenc = bfromcstralloc(1024,"");
! 2379:
! 2380: char *resp = splash ? "splash" : "notyet";
! 2381: if (redir_buildurl(&conn, url, redir, resp, 0, hexchal, NULL,
! 2382: conn.s_state.redir.userurl, NULL, NULL, conn.hismac, &conn.hisip) == -1) {
! 2383: log_err(errno, "redir_buildurl failed!");
! 2384: redir_close(infd, outfd);
! 2385: }
! 2386:
! 2387: redir_urlencode(url, urlenc);
! 2388:
! 2389: bassignformat(url, "%s%cloginurl=",
! 2390: redir->homepage, strchr(redir->homepage, '?') ? '&' : '?');
! 2391: bconcat(url, urlenc);
! 2392:
! 2393: redir_reply(redir, &socket, &conn, splash ? REDIR_SPLASH : REDIR_NOTYET, url,
! 2394: 0, hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2395: NULL, conn.hismac, &conn.hisip, qs);
! 2396: }
! 2397: else if (state == 1) {
! 2398: redir_reply(redir, &socket, &conn, splash ? REDIR_SPLASH : REDIR_ALREADY, NULL, 0,
! 2399: splash ? hexchal : NULL, NULL, conn.s_state.redir.userurl, NULL,
! 2400: NULL, conn.hismac, &conn.hisip, qs);
! 2401: }
! 2402: else {
! 2403: redir_reply(redir, &socket, &conn, splash ? REDIR_SPLASH : REDIR_NOTYET, NULL,
! 2404: 0, hexchal, NULL, conn.s_state.redir.userurl, NULL,
! 2405: NULL, conn.hismac, &conn.hisip, qs);
! 2406: }
! 2407:
! 2408: redir_close(infd, outfd);
! 2409: return -1; /* never gets here */
! 2410: }
! 2411:
! 2412:
! 2413: /* Set callback to determine state information for the connection */
! 2414: int redir_set_cb_getstate(struct redir_t *redir,
! 2415: int (*cb_getstate) (struct redir_t *redir, struct in_addr *addr,
! 2416: struct redir_conn_t *conn)) {
! 2417: redir->cb_getstate = cb_getstate;
! 2418: return 0;
! 2419: }
! 2420:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>