Annotation of embedaddon/coova-chilli/src/redir.c, revision 1.1.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 = "&amp;";  break;
                    117:     case '\"': x = "&quot;"; break;
                    118:     case '<':  x = "&lt;";   break;
                    119:     case '>':  x = "&gt;";   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&amp;uamip=%s&amp;uamport=%d&amp;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>