Annotation of embedaddon/coova-chilli/src/chilli.c, revision 1.1

1.1     ! misho       1: /* 
        !             2:  *
        !             3:  * chilli - ChilliSpot.org. A Wireless LAN Access Point Controller.
        !             4:  * Copyright (C) 2003, 2004, 2005 Mondru AB.
        !             5:  * Copyright (C) 2006 PicoPoint B.V.
        !             6:  * Copyright (c) 2007-2008 David Bird <david@coova.com>
        !             7:  *
        !             8:  * The contents of this file may be used under the terms of the GNU
        !             9:  * General Public License Version 2, provided that the above copyright
        !            10:  * notice and this permission notice is included in all copies or
        !            11:  * substantial portions of the software.
        !            12:  * 
        !            13:  */
        !            14: 
        !            15: #include "system.h"
        !            16: #include "tun.h"
        !            17: #include "ippool.h"
        !            18: #include "radius.h"
        !            19: #include "radius_wispr.h"
        !            20: #include "radius_chillispot.h"
        !            21: #include "redir.h"
        !            22: #include "syserr.h"
        !            23: #include "dhcp.h"
        !            24: #include "cmdline.h"
        !            25: #include "chilli.h"
        !            26: #include "options.h"
        !            27: #include "cmdsock.h"
        !            28: #include "net.h"
        !            29: 
        !            30: struct tun_t *tun;                /* TUN instance            */
        !            31: struct ippool_t *ippool;          /* Pool of IP addresses */
        !            32: struct radius_t *radius;          /* Radius client instance */
        !            33: struct dhcp_t *dhcp = NULL;       /* DHCP instance */
        !            34: struct redir_t *redir = NULL;     /* Redir instance */
        !            35: 
        !            36: int connections=0;
        !            37: struct app_conn_t *firstfreeconn=0; /* First free in linked list */
        !            38: struct app_conn_t *lastfreeconn=0;  /* Last free in linked list */
        !            39: struct app_conn_t *firstusedconn=0; /* First used in linked list */
        !            40: struct app_conn_t *lastusedconn=0;  /* Last used in linked list */
        !            41: 
        !            42: extern struct app_conn_t admin_session;
        !            43: 
        !            44: time_t mainclock;
        !            45: time_t checktime;
        !            46: time_t rereadtime;
        !            47: 
        !            48: static int keep_going = 1;
        !            49: /*static int do_timeouts = 1;*/
        !            50: static int do_sighup = 0;
        !            51: 
        !            52: /* some IPv4LL/APIPA(rfc 3927) specific stuff for uamanyip */
        !            53: struct in_addr ipv4ll_ip;
        !            54: struct in_addr ipv4ll_mask;
        !            55: 
        !            56: /* Forward declarations */
        !            57: static int acct_req(struct app_conn_t *conn, uint8_t status_type);
        !            58: 
        !            59: /* Fireman catches falling childs and eliminates zombies */
        !            60: static void fireman(int signum) { 
        !            61:   while (wait3(NULL, WNOHANG, NULL) > 0);
        !            62: }
        !            63: 
        !            64: /* Termination handler for clean shutdown */
        !            65: static void termination_handler(int signum) {
        !            66:   if (options.debug) log_dbg("SIGTERM received!\n");
        !            67:   keep_going = 0;
        !            68: }
        !            69: 
        !            70: /* Alarm handler for general house keeping 
        !            71: void static alarm_handler(int signum) {
        !            72:   if (options.debug) log_dbg("SIGALRM received!\n");
        !            73:   do_timeouts = 1;
        !            74: }*/
        !            75: 
        !            76: /* Sighup handler for rereading configuration file */
        !            77: static void sighup_handler(int signum) {
        !            78:   if (options.debug) log_dbg("SIGHUP received!\n");
        !            79:   do_sighup = 1;
        !            80: }
        !            81: 
        !            82: 
        !            83: static void set_sessionid(struct app_conn_t *appconn) {
        !            84:   snprintf(appconn->s_state.sessionid, sizeof(appconn->s_state.sessionid), 
        !            85:           "%.8x%.8x", (int) mainclock, appconn->unit);
        !            86:   /*log_dbg("!!!! RESET CLASSLEN !!!!");*/
        !            87:   appconn->s_state.redir.classlen = 0;
        !            88: }
        !            89: 
        !            90: /* Used to write process ID to file. Assume someone else will delete */
        !            91: void static log_pid(char *pidfile) {
        !            92:   FILE *file;
        !            93:   mode_t oldmask;
        !            94: 
        !            95:   oldmask = umask(022);
        !            96:   file = fopen(pidfile, "w");
        !            97:   umask(oldmask);
        !            98:   if(!file) return;
        !            99:   fprintf(file, "%d\n", getpid());
        !           100:   fclose(file);
        !           101: }
        !           102: 
        !           103: #ifdef LEAKY_BUCKET
        !           104: /* Perform leaky bucket on up- and downlink traffic */
        !           105: int static leaky_bucket(struct app_conn_t *conn, uint64_t octetsup, uint64_t octetsdown) {
        !           106:   
        !           107:   time_t timenow = mainclock;
        !           108:   uint64_t timediff; 
        !           109:   int result = 0;
        !           110: 
        !           111:   timediff = timenow - conn->s_state.last_time;
        !           112: 
        !           113:   if (options.debug && (conn->s_params.bandwidthmaxup || 
        !           114:                        conn->s_params.bandwidthmaxdown))
        !           115:     log_dbg("Leaky bucket timediff: %lld, bucketup: %lld, bucketdown: %lld, up: %lld, down: %lld", 
        !           116:            timediff, conn->s_state.bucketup, conn->s_state.bucketdown, 
        !           117:            octetsup, octetsdown);
        !           118: 
        !           119:   if (conn->s_params.bandwidthmaxup) {
        !           120:     /* Subtract what the leak since last time we visited */
        !           121:     if (conn->s_state.bucketup > ((timediff * conn->s_params.bandwidthmaxup) / 8)) {
        !           122:       conn->s_state.bucketup -= (timediff * conn->s_params.bandwidthmaxup) / 8;
        !           123:     }
        !           124:     else {
        !           125:       conn->s_state.bucketup = 0;
        !           126:     }
        !           127:     
        !           128:     if ((conn->s_state.bucketup + octetsup) > conn->s_state.bucketupsize) {
        !           129:       if (options.debug) log_dbg("Leaky bucket deleting uplink packet");
        !           130:       result = -1;
        !           131:     }
        !           132:     else {
        !           133:       conn->s_state.bucketup += octetsup;
        !           134:     }
        !           135:   }
        !           136: 
        !           137:   if (conn->s_params.bandwidthmaxdown) {
        !           138:     if (conn->s_state.bucketdown > ((timediff * conn->s_params.bandwidthmaxdown) / 8)) {
        !           139:       conn->s_state.bucketdown -= (timediff * conn->s_params.bandwidthmaxdown) / 8;
        !           140:     }
        !           141:     else {
        !           142:       conn->s_state.bucketdown = 0;
        !           143:     }
        !           144:     
        !           145:     if ((conn->s_state.bucketdown + octetsdown) > conn->s_state.bucketdownsize) {
        !           146:       if (options.debug) log_dbg("Leaky bucket deleting downlink packet");
        !           147:       result = -1;
        !           148:     }
        !           149:     else {
        !           150:       conn->s_state.bucketdown += octetsdown;
        !           151:     }
        !           152:   }
        !           153: 
        !           154:   conn->s_state.last_time = timenow;
        !           155:     
        !           156:   return result;
        !           157: }
        !           158: #endif
        !           159: 
        !           160: 
        !           161: /* Run external script */
        !           162: #define VAL_STRING   0
        !           163: #define VAL_IN_ADDR  1
        !           164: #define VAL_MAC_ADDR 2
        !           165: #define VAL_ULONG    3
        !           166: #define VAL_ULONG64  4
        !           167: #define VAL_USHORT   5
        !           168: 
        !           169: int set_env(char *name, char type, void *value, int len) {
        !           170:   char *v=0;
        !           171:   char s[1024];
        !           172: 
        !           173:   memset(s,0,sizeof(s));
        !           174: 
        !           175:   switch(type) {
        !           176: 
        !           177:   case VAL_IN_ADDR:
        !           178:     strncpy(s, inet_ntoa(*(struct in_addr *)value), sizeof(s)); 
        !           179:     v = s;
        !           180:     break;
        !           181: 
        !           182:   case VAL_MAC_ADDR:
        !           183:     {
        !           184:       uint8_t * mac = (uint8_t*)value;
        !           185:       snprintf(s, sizeof(s)-1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
        !           186:               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        !           187:       v = s;
        !           188:     }
        !           189:     break;
        !           190: 
        !           191:   case VAL_ULONG:
        !           192:     snprintf(s, sizeof(s)-1, "%ld", (long int)*(uint32_t *)value);
        !           193:     v = s;
        !           194:     break;
        !           195: 
        !           196:   case VAL_ULONG64:
        !           197:     snprintf(s, sizeof(s)-1, "%ld", (long int)*(uint64_t *)value);
        !           198:     v = s;
        !           199:     break;
        !           200: 
        !           201:   case VAL_USHORT:
        !           202:     snprintf(s, sizeof(s)-1, "%d", (int)(*(uint16_t *)value));
        !           203:     v = s;
        !           204:     break;
        !           205: 
        !           206:   case VAL_STRING:
        !           207:     if (len != 0) {
        !           208:       if (len >= sizeof(s)) {
        !           209:        return -1;
        !           210:       }
        !           211:       strncpy(s, (char*)value, len);
        !           212:       s[len] = 0;
        !           213:       v = s;
        !           214:     } else {
        !           215:       v = (char*)value;
        !           216:     }
        !           217:     break;
        !           218:   }
        !           219: 
        !           220:   if (name != NULL && v != NULL) {
        !           221:     if (setenv(name, v, 1) != 0) {
        !           222:       log_err(errno, "setenv(%s, %s, 1) did not return 0!", name, v);
        !           223:       return -1;
        !           224:     }
        !           225:   }
        !           226: 
        !           227:   return 0;
        !           228: }
        !           229: 
        !           230: int runscript(struct app_conn_t *appconn, char* script) {  
        !           231:   int status;
        !           232: 
        !           233:   if ((status = fork()) < 0) {
        !           234:     log_err(errno,
        !           235:            "fork() returned -1!");
        !           236:     return 0;
        !           237:   }
        !           238: 
        !           239:   if (status > 0) { /* Parent */
        !           240:     return 0; 
        !           241:   }
        !           242: 
        !           243: /*
        !           244:   if (clearenv() != 0) {
        !           245:     log_err(errno,
        !           246:            "clearenv() did not return 0!");
        !           247:     exit(0);
        !           248:   }
        !           249: */
        !           250: 
        !           251:   set_env("DEV", VAL_STRING, tun->_interfaces[0].devname, 0);
        !           252:   set_env("NET", VAL_IN_ADDR, &appconn->net, 0);
        !           253:   set_env("MASK", VAL_IN_ADDR, &appconn->mask, 0);
        !           254:   set_env("ADDR", VAL_IN_ADDR, &appconn->ourip, 0);
        !           255:   set_env("USER_NAME", VAL_STRING, appconn->s_state.redir.username, 0);
        !           256:   set_env("NAS_IP_ADDRESS", VAL_IN_ADDR,&options.radiuslisten, 0);
        !           257:   set_env("SERVICE_TYPE", VAL_STRING, "1", 0);
        !           258:   set_env("FRAMED_IP_ADDRESS", VAL_IN_ADDR, &appconn->hisip, 0);
        !           259:   set_env("FILTER_ID", VAL_STRING, appconn->s_params.filteridbuf, 0);
        !           260:   set_env("STATE", VAL_STRING, appconn->s_state.redir.statebuf, appconn->s_state.redir.statelen);
        !           261:   set_env("CLASS", VAL_STRING, appconn->s_state.redir.classbuf, appconn->s_state.redir.classlen);
        !           262:   set_env("SESSION_TIMEOUT", VAL_ULONG64, &appconn->s_params.sessiontimeout, 0);
        !           263:   set_env("IDLE_TIMEOUT", VAL_ULONG, &appconn->s_params.idletimeout, 0);
        !           264:   set_env("CALLING_STATION_ID", VAL_MAC_ADDR, appconn->hismac, 0);
        !           265:   set_env("CALLED_STATION_ID", VAL_MAC_ADDR, appconn->ourmac, 0);
        !           266:   set_env("NAS_ID", VAL_STRING, options.radiusnasid, 0);
        !           267:   set_env("NAS_PORT_TYPE", VAL_STRING, "19", 0);
        !           268:   set_env("ACCT_SESSION_ID", VAL_STRING, appconn->s_state.sessionid, 0);
        !           269:   set_env("ACCT_INTERIM_INTERVAL", VAL_USHORT, &appconn->s_params.interim_interval, 0);
        !           270:   set_env("WISPR_LOCATION_ID", VAL_STRING, options.radiuslocationid, 0);
        !           271:   set_env("WISPR_LOCATION_NAME", VAL_STRING, options.radiuslocationname, 0);
        !           272:   set_env("WISPR_BANDWIDTH_MAX_UP", VAL_ULONG, &appconn->s_params.bandwidthmaxup, 0);
        !           273:   set_env("WISPR_BANDWIDTH_MAX_DOWN", VAL_ULONG, &appconn->s_params.bandwidthmaxdown, 0);
        !           274:   /*set_env("WISPR-SESSION_TERMINATE_TIME", VAL_USHORT, &appconn->sessionterminatetime, 0);*/
        !           275:   set_env("CHILLISPOT_MAX_INPUT_OCTETS", VAL_ULONG64, &appconn->s_params.maxinputoctets, 0);
        !           276:   set_env("CHILLISPOT_MAX_OUTPUT_OCTETS", VAL_ULONG64, &appconn->s_params.maxoutputoctets, 0);
        !           277:   set_env("CHILLISPOT_MAX_TOTAL_OCTETS", VAL_ULONG64, &appconn->s_params.maxtotaloctets, 0);
        !           278: 
        !           279:   if (execl(script, script, (char *) 0) != 0) {
        !           280:       log_err(errno,
        !           281:              "execl() did not return 0!");
        !           282:       exit(0);
        !           283:   }
        !           284: 
        !           285:   exit(0);
        !           286: }
        !           287: 
        !           288: /***********************************************************
        !           289:  *
        !           290:  * Functions handling uplink protocol authentication.
        !           291:  * Called in response to radius access request response.
        !           292:  *
        !           293:  ***********************************************************/
        !           294: 
        !           295: static int newip(struct ippoolm_t **ipm, struct in_addr *hisip) {
        !           296:   if (ippool_newip(ippool, ipm, hisip, 1)) {
        !           297:     if (ippool_newip(ippool, ipm, hisip, 0)) {
        !           298:       log_err(0, "Failed to allocate either static or dynamic IP address");
        !           299:       return -1;
        !           300:     }
        !           301:   }
        !           302:   return 0;
        !           303: }
        !           304: 
        !           305: 
        !           306: /* 
        !           307:  * A few functions to manage connections 
        !           308:  */
        !           309: 
        !           310: int static initconn()
        !           311: {
        !           312:   checktime = rereadtime = mainclock;
        !           313:   return 0;
        !           314: }
        !           315: 
        !           316: int static newconn(struct app_conn_t **conn) {
        !           317:   int n;
        !           318: 
        !           319:   if (!firstfreeconn) {
        !           320: 
        !           321:     if (connections == APP_NUM_CONN) {
        !           322:       log_err(0, "reached max connections!");
        !           323:       return -1;
        !           324:     }
        !           325: 
        !           326:     n = ++connections;
        !           327: 
        !           328:     if (!(*conn = calloc(1, sizeof(struct app_conn_t)))) {
        !           329:       log_err(0, "Out of memory!");
        !           330:       return -1;
        !           331:     }
        !           332: 
        !           333:   } else {
        !           334: 
        !           335:     *conn = firstfreeconn;
        !           336:     n = (*conn)->unit;
        !           337: 
        !           338:     /* Remove from link of free */
        !           339:     if (firstfreeconn->next) {
        !           340:       firstfreeconn->next->prev = NULL;
        !           341:       firstfreeconn = firstfreeconn->next;
        !           342:     }
        !           343:     else { /* Took the last one */
        !           344:       firstfreeconn = NULL; 
        !           345:       lastfreeconn = NULL;
        !           346:     }
        !           347: 
        !           348:     /* Initialise structures */
        !           349:     memset(*conn, 0, sizeof(struct app_conn_t));
        !           350:   }
        !           351: 
        !           352:   /* Insert into link of used */
        !           353:   if (firstusedconn) {
        !           354:     firstusedconn->prev = *conn;
        !           355:     (*conn)->next = firstusedconn;
        !           356:   }
        !           357:   else { /* First insert */
        !           358:     lastusedconn = *conn;
        !           359:   }
        !           360:   
        !           361:   firstusedconn = *conn;
        !           362:   
        !           363:   (*conn)->inuse = 1;
        !           364:   (*conn)->unit = n;
        !           365:   
        !           366:   return 0; /* Success */
        !           367: }
        !           368: 
        !           369: int static freeconn(struct app_conn_t *conn) {
        !           370:   int n = conn->unit;
        !           371: 
        !           372:   /* Remove from link of used */
        !           373:   if ((conn->next) && (conn->prev)) {
        !           374:     conn->next->prev = conn->prev;
        !           375:     conn->prev->next = conn->next;
        !           376:   }
        !           377:   else if (conn->next) { /* && prev == 0 */
        !           378:     conn->next->prev = NULL;
        !           379:     firstusedconn = conn->next;
        !           380:   }
        !           381:   else if (conn->prev) { /* && next == 0 */
        !           382:     conn->prev->next = NULL;
        !           383:     lastusedconn = conn->prev;
        !           384:   }
        !           385:   else { /* if ((next == 0) && (prev == 0)) */
        !           386:     firstusedconn = NULL;
        !           387:     lastusedconn = NULL;
        !           388:   }
        !           389:   
        !           390:   /* Initialise structures */
        !           391:   memset(conn, 0, sizeof(struct app_conn_t));
        !           392:   conn->unit = n;
        !           393:   
        !           394:   /* Insert into link of free */
        !           395:   if (firstfreeconn) {
        !           396:     firstfreeconn->prev = conn;
        !           397:   }
        !           398:   else { /* First insert */
        !           399:     lastfreeconn = conn;
        !           400:   }
        !           401: 
        !           402:   conn->next = firstfreeconn;
        !           403:   firstfreeconn = conn;
        !           404: 
        !           405:   return 0;
        !           406: }
        !           407: 
        !           408: int static getconn(struct app_conn_t **conn, uint32_t nasip, uint32_t nasport) {
        !           409:   struct app_conn_t *appconn;
        !           410:   
        !           411:   /* Count the number of used connections */
        !           412:   appconn = firstusedconn;
        !           413:   while (appconn) {
        !           414:     if (!appconn->inuse) {
        !           415:       log_err(0, "Connection with inuse == 0!");
        !           416:     }
        !           417:     if ((appconn->nasip == nasip) && (appconn->nasport == nasport)) {
        !           418:       *conn = appconn;
        !           419:       return 0;
        !           420:     }
        !           421:     appconn = appconn->next;
        !           422:   }
        !           423: 
        !           424:   return -1; /* Not found */
        !           425: }
        !           426: 
        !           427: int static dnprot_terminate(struct app_conn_t *appconn) {
        !           428:   appconn->s_state.authenticated = 0;
        !           429:   printstatus(appconn);
        !           430:   switch (appconn->dnprot) {
        !           431:   case DNPROT_WPA:
        !           432:   case DNPROT_EAPOL:
        !           433:     if (appconn->dnlink)
        !           434:       ((struct dhcp_conn_t*) appconn->dnlink)->authstate = DHCP_AUTH_NONE;
        !           435:     return 0;
        !           436:   case DNPROT_MAC:
        !           437:   case DNPROT_UAM:
        !           438:   case DNPROT_DHCP_NONE:
        !           439:   case DNPROT_NULL:
        !           440:     if (appconn->dnlink)
        !           441:       ((struct dhcp_conn_t*) appconn->dnlink)->authstate = DHCP_AUTH_DNAT;
        !           442:     return 0;
        !           443:   default: 
        !           444:     log_err(0, "Unknown downlink protocol"); 
        !           445:     return 0;
        !           446:   }
        !           447: }
        !           448: 
        !           449: 
        !           450: 
        !           451: /* Check for:
        !           452:  * - Session-Timeout
        !           453:  * - Idle-Timeout
        !           454:  * - Interim-Interim accounting
        !           455:  * - Reread configuration file and DNS entries
        !           456:  */
        !           457: 
        !           458: void session_interval(struct app_conn_t *conn) {
        !           459:   time_t timenow = mainclock;
        !           460:   uint32_t sessiontime;
        !           461:   uint32_t idletime;
        !           462:   uint32_t interimtime;
        !           463: 
        !           464:   sessiontime = timenow - conn->s_state.start_time;
        !           465:   idletime    = timenow - conn->s_state.last_time;
        !           466:   interimtime = timenow - conn->s_state.interim_time;
        !           467:   
        !           468:   if ((conn->s_params.sessiontimeout) &&
        !           469:       (sessiontime > conn->s_params.sessiontimeout)) {
        !           470:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
        !           471:   }
        !           472:   else if ((conn->s_params.sessionterminatetime) && 
        !           473:           (timenow > conn->s_params.sessionterminatetime)) {
        !           474:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
        !           475:   }
        !           476:   else if ((conn->s_params.idletimeout) && 
        !           477:           (idletime > conn->s_params.idletimeout)) {
        !           478:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_IDLE_TIMEOUT);
        !           479:   }
        !           480:   else if ((conn->s_params.maxinputoctets) &&
        !           481:           (conn->s_state.input_octets > conn->s_params.maxinputoctets)) {
        !           482:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
        !           483:   }
        !           484:   else if ((conn->s_params.maxoutputoctets) &&
        !           485:           (conn->s_state.output_octets > conn->s_params.maxoutputoctets)) {
        !           486:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
        !           487:   }
        !           488:   else if ((conn->s_params.maxtotaloctets) &&
        !           489:           ((conn->s_state.input_octets + conn->s_state.output_octets) > 
        !           490:            conn->s_params.maxtotaloctets)) {
        !           491:     terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_SESSION_TIMEOUT);
        !           492:   }
        !           493:   else if ((conn->s_params.interim_interval) &&
        !           494:           (interimtime > conn->s_params.interim_interval)) {
        !           495:     acct_req(conn, RADIUS_STATUS_TYPE_INTERIM_UPDATE);
        !           496:   }
        !           497: }
        !           498: 
        !           499: int static checkconn()
        !           500: {
        !           501:   time_t timenow = mainclock;
        !           502:   struct app_conn_t *conn;
        !           503:   struct dhcp_conn_t* dhcpconn;
        !           504:   uint32_t checkdiff;
        !           505:   uint32_t rereaddiff;
        !           506: 
        !           507:   checkdiff = timenow - checktime;
        !           508: 
        !           509:   if (checkdiff < CHECK_INTERVAL)
        !           510:     return 0;
        !           511: 
        !           512:   checktime = timenow;
        !           513:   
        !           514:   if (admin_session.s_state.authenticated) {
        !           515:     session_interval(&admin_session);
        !           516:   }
        !           517: 
        !           518:   for (conn = firstusedconn; conn; conn=conn->next) {
        !           519:     if ((conn->inuse != 0) && (conn->s_state.authenticated == 1)) {
        !           520:       if (!(dhcpconn = (struct dhcp_conn_t *)conn->dnlink)) {
        !           521:        log_err(0, "No downlink protocol");
        !           522:        return -1;
        !           523:       }
        !           524:       session_interval(conn);
        !           525:     }
        !           526:   }
        !           527:   
        !           528:   /* Reread configuration file and recheck DNS */
        !           529:   if (options.interval) {
        !           530:     rereaddiff = timenow - rereadtime;
        !           531:     if (rereaddiff >= options.interval) {
        !           532:       rereadtime = timenow;
        !           533:       do_sighup = 1;
        !           534:     }
        !           535:   }
        !           536:   
        !           537:   return 0;
        !           538: }
        !           539: 
        !           540: /* Kill all connections and send Radius Acct Stop */
        !           541: int static killconn()
        !           542: {
        !           543:   struct app_conn_t *conn;
        !           544: 
        !           545:   for (conn = firstusedconn; conn; conn=conn->next) {
        !           546:     if ((conn->inuse != 0) && (conn->s_state.authenticated == 1)) {
        !           547:       terminate_appconn(conn, RADIUS_TERMINATE_CAUSE_NAS_REBOOT);
        !           548:     }
        !           549:   }
        !           550: 
        !           551:   if (admin_session.s_state.authenticated) {
        !           552:     admin_session.s_state.terminate_cause = RADIUS_TERMINATE_CAUSE_NAS_REBOOT;
        !           553:     acct_req(&admin_session, RADIUS_STATUS_TYPE_STOP);
        !           554:   }
        !           555: 
        !           556:   acct_req(&admin_session, RADIUS_STATUS_TYPE_ACCOUNTING_OFF);
        !           557: 
        !           558:   return 0;
        !           559: }
        !           560: 
        !           561: /* Compare a MAC address to the addresses given in the macallowed option */
        !           562: int static maccmp(unsigned char *mac) {
        !           563:   int i; 
        !           564: 
        !           565:   for (i=0; i<options.macoklen; i++)
        !           566:     if (!memcmp(mac, options.macok[i], PKT_ETH_ALEN))
        !           567:       return 0;
        !           568: 
        !           569:   return -1;
        !           570: }
        !           571: 
        !           572: int static macauth_radius(struct app_conn_t *appconn, 
        !           573:                          struct dhcp_fullpacket_t *dhcp_pkt, size_t dhcp_len) {
        !           574:   struct dhcp_conn_t *dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
        !           575:   struct radius_packet_t radius_pack;
        !           576:   char mac[MACSTRLEN+1];
        !           577: 
        !           578:   log_dbg("Starting mac radius authentication");
        !           579: 
        !           580:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
        !           581:     log_err(0, "radius_default_pack() failed");
        !           582:     return -1;
        !           583:   }
        !           584:   
        !           585:   /* Include his MAC address */
        !           586:   snprintf(mac, MACSTRLEN+1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
        !           587:           dhcpconn->hismac[0], dhcpconn->hismac[1],
        !           588:           dhcpconn->hismac[2], dhcpconn->hismac[3],
        !           589:           dhcpconn->hismac[4], dhcpconn->hismac[5]);
        !           590: 
        !           591:   strncpy(appconn->s_state.redir.username, mac, USERNAMESIZE);
        !           592: 
        !           593:   if (options.macsuffix)
        !           594:     strncat(appconn->s_state.redir.username, options.macsuffix, USERNAMESIZE);
        !           595: 
        !           596:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
        !           597:                 (uint8_t*) appconn->s_state.redir.username, 
        !           598:                 strlen(appconn->s_state.redir.username));
        !           599:   
        !           600:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
        !           601:                 (uint8_t*) (options.macpasswd ? options.macpasswd : appconn->s_state.redir.username), 
        !           602:                 options.macpasswd ? strlen(options.macpasswd) : strlen(appconn->s_state.redir.username));
        !           603:   
        !           604:   appconn->authtype = PAP_PASSWORD;
        !           605:   
        !           606:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
        !           607:                 (uint8_t*) mac, MACSTRLEN);
        !           608:   
        !           609:   radius_addcalledstation(radius, &radius_pack);
        !           610: 
        !           611:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT, 0, 0,
        !           612:                 appconn->unit, NULL, 0);
        !           613: 
        !           614:   radius_addnasip(radius, &radius_pack);
        !           615: 
        !           616:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_SERVICE_TYPE, 0, 0,
        !           617:                 RADIUS_SERVICE_TYPE_LOGIN, NULL, 0); /* WISPr_V1.0 */
        !           618:   
        !           619:   /* Include NAS-Identifier if given in configuration options */
        !           620:   if (options.radiusnasid)
        !           621:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
        !           622:                   (uint8_t*) options.radiusnasid, strlen(options.radiusnasid));
        !           623: 
        !           624:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0,
        !           625:                 (uint8_t*) appconn->s_state.sessionid, REDIR_SESSIONID_LEN-1);
        !           626: 
        !           627:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
        !           628:                 options.radiusnasporttype, NULL, 0);
        !           629: 
        !           630: 
        !           631:   if (options.radiuslocationid)
        !           632:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           633:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_ID, 0,
        !           634:                   (uint8_t*) options.radiuslocationid, 
        !           635:                   strlen(options.radiuslocationid));
        !           636: 
        !           637:   if (options.radiuslocationname)
        !           638:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           639:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_NAME, 0,
        !           640:                   (uint8_t*) options.radiuslocationname, 
        !           641:                   strlen(options.radiuslocationname));
        !           642: 
        !           643:   if (options.dhcpradius && dhcp_pkt) {
        !           644:     struct dhcp_tag_t *tag = 0;
        !           645: 
        !           646: #define maptag(OPT,VSA)\
        !           647:     if (!dhcp_gettag(&dhcp_pkt->dhcp, ntohs(dhcp_pkt->udph.len)-PKT_UDP_HLEN, &tag, OPT)) { \
        !           648:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC, \
        !           649:                     RADIUS_VENDOR_CHILLISPOT, VSA, 0, (uint8_t *) tag->v, tag->l); } 
        !           650:     /*
        !           651:      *  Mapping of DHCP options to RADIUS Vendor Specific Attributes
        !           652:      */
        !           653:     maptag( DHCP_OPTION_PARAMETER_REQUEST_LIST,  RADIUS_ATTR_CHILLISPOT_DHCP_PARAMETER_REQUEST_LIST );
        !           654:     maptag( DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, RADIUS_ATTR_CHILLISPOT_DHCP_VENDOR_CLASS_ID );
        !           655:     maptag( DHCP_OPTION_CLIENT_IDENTIFIER,       RADIUS_ATTR_CHILLISPOT_DHCP_CLIENT_ID );
        !           656:     maptag( DHCP_OPTION_CLIENT_FQDN,             RADIUS_ATTR_CHILLISPOT_DHCP_CLIENT_FQDN );
        !           657:     maptag( DHCP_OPTION_HOSTNAME,                RADIUS_ATTR_CHILLISPOT_DHCP_HOSTNAME );
        !           658: #undef maptag
        !           659:   }
        !           660:   
        !           661:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
        !           662:                 0, 0, 0, NULL, RADIUS_MD5LEN);
        !           663: 
        !           664:   return radius_req(radius, &radius_pack, appconn);
        !           665: }
        !           666: 
        !           667: 
        !           668: /*********************************************************
        !           669:  *
        !           670:  * radius proxy functions
        !           671:  * Used to send a response to a received radius request
        !           672:  *
        !           673:  *********************************************************/
        !           674: 
        !           675: /* Reply with an access reject */
        !           676: int static radius_access_reject(struct app_conn_t *conn) {
        !           677:   struct radius_packet_t radius_pack;
        !           678: 
        !           679:   conn->radiuswait = 0;
        !           680: 
        !           681:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REJECT)) {
        !           682:     log_err(0, "radius_default_pack() failed");
        !           683:     return -1;
        !           684:   }
        !           685: 
        !           686:   radius_pack.id = conn->radiusid;
        !           687:   radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
        !           688:   return 0;
        !           689: }
        !           690: 
        !           691: /* Reply with an access challenge */
        !           692: int static radius_access_challenge(struct app_conn_t *conn) {
        !           693:   struct radius_packet_t radius_pack;
        !           694:   size_t offset = 0;
        !           695:   size_t eaplen = 0;
        !           696: 
        !           697:   conn->radiuswait = 0;
        !           698: 
        !           699:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_CHALLENGE)){
        !           700:     log_err(0, "radius_default_pack() failed");
        !           701:     return -1;
        !           702:   }
        !           703: 
        !           704:   radius_pack.id = conn->radiusid;
        !           705: 
        !           706:   /* Include EAP */
        !           707:   do {
        !           708:     if ((conn->challen - offset) > RADIUS_ATTR_VLEN)
        !           709:       eaplen = RADIUS_ATTR_VLEN;
        !           710:     else
        !           711:       eaplen = conn->challen - offset;
        !           712: 
        !           713:     if (radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
        !           714:                       conn->chal + offset, eaplen)) {
        !           715:       log_err(0, "radius_default_pack() failed");
        !           716:       return -1;
        !           717:     }
        !           718:     offset += eaplen;
        !           719:   } while (offset < conn->challen);
        !           720:   
        !           721:   if (conn->s_state.redir.statelen) {
        !           722:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_STATE, 0, 0, 0,
        !           723:                   conn->s_state.redir.statebuf,
        !           724:                   conn->s_state.redir.statelen);
        !           725:   }
        !           726:   
        !           727:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
        !           728:                 0, 0, 0, NULL, RADIUS_MD5LEN);
        !           729:   
        !           730:   radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
        !           731:   return 0;
        !           732: }
        !           733: 
        !           734: /* Send off an access accept */
        !           735: 
        !           736: int static radius_access_accept(struct app_conn_t *conn) {
        !           737:   struct radius_packet_t radius_pack;
        !           738:   size_t offset = 0;
        !           739:   size_t eaplen = 0;
        !           740: 
        !           741:   uint8_t mppekey[RADIUS_ATTR_VLEN];
        !           742:   size_t mppelen;
        !           743: 
        !           744:   conn->radiuswait = 0;
        !           745: 
        !           746:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_ACCEPT)) {
        !           747:     log_err(0, "radius_default_pack() failed");
        !           748:     return -1;
        !           749:   }
        !           750: 
        !           751:   radius_pack.id = conn->radiusid;
        !           752: 
        !           753:   /* Include EAP (if present) */
        !           754:   offset = 0;
        !           755:   while (offset < conn->challen) {
        !           756:     if ((conn->challen - offset) > RADIUS_ATTR_VLEN)
        !           757:       eaplen = RADIUS_ATTR_VLEN;
        !           758:     else
        !           759:       eaplen = conn->challen - offset;
        !           760: 
        !           761:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
        !           762:                   conn->chal + offset, eaplen);
        !           763: 
        !           764:     offset += eaplen;
        !           765:   }
        !           766: 
        !           767:   if (conn->sendlen) {
        !           768:     radius_keyencode(radius, mppekey, RADIUS_ATTR_VLEN,
        !           769:                     &mppelen, conn->sendkey,
        !           770:                     conn->sendlen, conn->authenticator,
        !           771:                     radius->proxysecret, radius->proxysecretlen);
        !           772: 
        !           773:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           774:                   RADIUS_VENDOR_MS, RADIUS_ATTR_MS_MPPE_SEND_KEY, 0,
        !           775:                   (uint8_t *)mppekey, mppelen);
        !           776:   }
        !           777: 
        !           778:   if (conn->recvlen) {
        !           779:     radius_keyencode(radius, mppekey, RADIUS_ATTR_VLEN,
        !           780:                     &mppelen, conn->recvkey,
        !           781:                     conn->recvlen, conn->authenticator,
        !           782:                     radius->proxysecret, radius->proxysecretlen);
        !           783:     
        !           784:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           785:                   RADIUS_VENDOR_MS, RADIUS_ATTR_MS_MPPE_RECV_KEY, 0,
        !           786:                   (uint8_t *)mppekey, mppelen);
        !           787:   }
        !           788:   
        !           789:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
        !           790:                 0, 0, 0, NULL, RADIUS_MD5LEN);
        !           791: 
        !           792:   radius_resp(radius, &radius_pack, &conn->radiuspeer, conn->authenticator);
        !           793:   return 0;
        !           794: }
        !           795: 
        !           796: 
        !           797: /*********************************************************
        !           798:  *
        !           799:  * radius accounting functions
        !           800:  * Used to send accounting request to radius server
        !           801:  *
        !           802:  *********************************************************/
        !           803: 
        !           804: static int acct_req(struct app_conn_t *conn, uint8_t status_type)
        !           805: {
        !           806:   struct radius_packet_t radius_pack;
        !           807:   char mac[MACSTRLEN+1];
        !           808:   char portid[16+1];
        !           809:   time_t timenow;
        !           810:   uint32_t timediff;
        !           811: 
        !           812:   if (RADIUS_STATUS_TYPE_START == status_type) {
        !           813:     conn->s_state.start_time = mainclock;
        !           814:     conn->s_state.interim_time = mainclock;
        !           815:     conn->s_state.last_time = mainclock;
        !           816:     conn->s_state.input_packets = 0;
        !           817:     conn->s_state.output_packets = 0;
        !           818:     conn->s_state.input_octets = 0;
        !           819:     conn->s_state.output_octets = 0;
        !           820:   }
        !           821: 
        !           822:   if (RADIUS_STATUS_TYPE_INTERIM_UPDATE == status_type) {
        !           823:     conn->s_state.interim_time = mainclock;
        !           824:   }
        !           825: 
        !           826:   if (radius_default_pack(radius, &radius_pack, 
        !           827:                          RADIUS_CODE_ACCOUNTING_REQUEST)) {
        !           828:     log_err(0, "radius_default_pack() failed");
        !           829:     return -1;
        !           830:   }
        !           831: 
        !           832:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_STATUS_TYPE, 0, 0,
        !           833:                 status_type, NULL, 0);
        !           834: 
        !           835:   if (RADIUS_STATUS_TYPE_ACCOUNTING_ON != status_type &&
        !           836:       RADIUS_STATUS_TYPE_ACCOUNTING_OFF != status_type) {
        !           837: 
        !           838:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
        !           839:                   (uint8_t*) conn->s_state.redir.username, 
        !           840:                   strlen(conn->s_state.redir.username));
        !           841:     
        !           842:     if (conn->s_state.redir.classlen) {
        !           843:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_CLASS, 0, 0, 0,
        !           844:                     conn->s_state.redir.classbuf,
        !           845:                     conn->s_state.redir.classlen);
        !           846:     }
        !           847: 
        !           848:     if (conn->is_adminsession) {
        !           849:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_SERVICE_TYPE, 0, 0,
        !           850:                     RADIUS_SERVICE_TYPE_ADMIN_USER, NULL, 0); 
        !           851:     } else {
        !           852:       snprintf(mac, MACSTRLEN+1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
        !           853:               conn->hismac[0], conn->hismac[1],
        !           854:               conn->hismac[2], conn->hismac[3],
        !           855:               conn->hismac[4], conn->hismac[5]);
        !           856:       
        !           857:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
        !           858:                     (uint8_t*) mac, MACSTRLEN);
        !           859:       
        !           860:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
        !           861:                     options.radiusnasporttype, NULL, 0);
        !           862:       
        !           863:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT, 0, 0,
        !           864:                     conn->unit, NULL, 0);
        !           865: 
        !           866:       snprintf(portid, 16+1, "%.8d", conn->unit);
        !           867:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_ID, 0, 0, 0,
        !           868:                     (uint8_t*) portid, strlen(portid));
        !           869: 
        !           870:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0,
        !           871:                     ntohl(conn->hisip.s_addr), NULL, 0);
        !           872:       
        !           873:     }
        !           874:     
        !           875:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0,
        !           876:                   (uint8_t*) conn->s_state.sessionid, REDIR_SESSIONID_LEN-1);
        !           877:     
        !           878:   }
        !           879: 
        !           880:   radius_addnasip(radius, &radius_pack);
        !           881: 
        !           882:   radius_addcalledstation(radius, &radius_pack);
        !           883: 
        !           884: 
        !           885:   /* Include NAS-Identifier if given in configuration options */
        !           886:   if (options.radiusnasid)
        !           887:     (void) radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
        !           888:                   (uint8_t*) options.radiusnasid, 
        !           889:                   strlen(options.radiusnasid));
        !           890: 
        !           891:   /*
        !           892:   (void) radius_addattr(radius, &radius_pack, RADIUS_ATTR_FRAMED_MTU, 0, 0,
        !           893:   conn->mtu, NULL, 0);*/
        !           894: 
        !           895:   if ((status_type == RADIUS_STATUS_TYPE_STOP) ||
        !           896:       (status_type == RADIUS_STATUS_TYPE_INTERIM_UPDATE)) {
        !           897: 
        !           898:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_OCTETS, 0, 0,
        !           899:                   (uint32_t) conn->s_state.input_octets, NULL, 0);
        !           900:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_OCTETS, 0, 0,
        !           901:                   (uint32_t) conn->s_state.output_octets, NULL, 0);
        !           902: 
        !           903:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, 
        !           904:                   0, 0, (uint32_t) (conn->s_state.input_octets >> 32), NULL, 0);
        !           905:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, 
        !           906:                   0, 0, (uint32_t) (conn->s_state.output_octets >> 32), NULL, 0);
        !           907: 
        !           908:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_INPUT_PACKETS, 0, 0,
        !           909:                   conn->s_state.input_packets, NULL, 0);
        !           910:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_OUTPUT_PACKETS, 0, 0,
        !           911:                   conn->s_state.output_packets, NULL, 0);
        !           912: 
        !           913:     timenow = mainclock;
        !           914:     timediff = timenow - conn->s_state.start_time;
        !           915: 
        !           916:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_TIME, 0, 0,
        !           917:                   timediff, NULL, 0);  
        !           918:   }
        !           919: 
        !           920:   if (options.radiuslocationid)
        !           921:     (void) radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           922:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_ID, 0,
        !           923:                   (uint8_t*) options.radiuslocationid,
        !           924:                   strlen(options.radiuslocationid));
        !           925: 
        !           926:   if (options.radiuslocationname)
        !           927:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !           928:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_NAME, 0,
        !           929:                   (uint8_t*) options.radiuslocationname, 
        !           930:                   strlen(options.radiuslocationname));
        !           931: 
        !           932: 
        !           933:   if (status_type == RADIUS_STATUS_TYPE_STOP ||
        !           934:       status_type == RADIUS_STATUS_TYPE_ACCOUNTING_OFF) {
        !           935: 
        !           936:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_TERMINATE_CAUSE, 
        !           937:                   0, 0, conn->s_state.terminate_cause, NULL, 0);
        !           938: 
        !           939:     if (status_type == RADIUS_STATUS_TYPE_STOP) {
        !           940:       /* TODO: This probably belongs somewhere else */
        !           941:       if (options.condown) {
        !           942:        if (options.debug)
        !           943:          log_dbg("Calling connection down script: %s\n",options.condown);
        !           944:        runscript(conn, options.condown);
        !           945:       }
        !           946:     }
        !           947:   }
        !           948:   
        !           949:   radius_req(radius, &radius_pack, conn);
        !           950:   
        !           951:   return 0;
        !           952: }
        !           953: 
        !           954: 
        !           955: 
        !           956: /***********************************************************
        !           957:  *
        !           958:  * Functions handling downlink protocol authentication.
        !           959:  * Called in response to radius access request response.
        !           960:  *
        !           961:  ***********************************************************/
        !           962: 
        !           963: int static dnprot_reject(struct app_conn_t *appconn) {
        !           964:   struct dhcp_conn_t* dhcpconn = NULL;
        !           965:   /*struct ippoolm_t *ipm;*/
        !           966: 
        !           967:   switch (appconn->dnprot) {
        !           968: 
        !           969:   case DNPROT_EAPOL:
        !           970:     if (!(dhcpconn = (struct dhcp_conn_t*) appconn->dnlink)) {
        !           971:       log_err(0, "No downlink protocol");
        !           972:       return 0;
        !           973:     }
        !           974: 
        !           975:     dhcp_sendEAPreject(dhcpconn, NULL, 0);
        !           976:     return 0;
        !           977: 
        !           978:   case DNPROT_UAM:
        !           979:     log_err(0, "Rejecting UAM");
        !           980:     return 0;
        !           981: 
        !           982:   case DNPROT_WPA:
        !           983:     return radius_access_reject(appconn);
        !           984: 
        !           985:   case DNPROT_MAC:
        !           986:     /* remove the username since we're not logged in */
        !           987:     if (!appconn->s_state.authenticated)
        !           988:       strncpy(appconn->s_state.redir.username, "-", USERNAMESIZE);
        !           989: 
        !           990:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !           991:       log_err(0, "No downlink protocol");
        !           992:       return 0;
        !           993:     }
        !           994: 
        !           995:     if (options.macauthdeny) {
        !           996:       dhcpconn->authstate = DHCP_AUTH_DROP;
        !           997:       appconn->dnprot = DNPROT_NULL;
        !           998:     }
        !           999:     else {
        !          1000:       dhcpconn->authstate = DHCP_AUTH_NONE;
        !          1001:       appconn->dnprot = DNPROT_UAM;
        !          1002:     }
        !          1003: 
        !          1004:     return 0;    
        !          1005: 
        !          1006:   case DNPROT_NULL:
        !          1007:     return 0;
        !          1008: 
        !          1009:   default:
        !          1010:     log_err(0, "Unknown downlink protocol");
        !          1011:     return 0;
        !          1012:   }
        !          1013: }
        !          1014: 
        !          1015: int static dnprot_challenge(struct app_conn_t *appconn) {
        !          1016:   struct dhcp_conn_t* dhcpconn = NULL;
        !          1017: 
        !          1018:   switch (appconn->dnprot) {
        !          1019: 
        !          1020:   case DNPROT_EAPOL:
        !          1021:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !          1022:       log_err(0, "No downlink protocol");
        !          1023:       return 0;
        !          1024:     }
        !          1025: 
        !          1026:     dhcp_sendEAP(dhcpconn, appconn->chal, appconn->challen);
        !          1027:     break;
        !          1028: 
        !          1029:   case DNPROT_NULL:
        !          1030:   case DNPROT_UAM:
        !          1031:   case DNPROT_MAC:
        !          1032:     break;
        !          1033: 
        !          1034:   case DNPROT_WPA:
        !          1035:     radius_access_challenge(appconn);
        !          1036:     break;
        !          1037: 
        !          1038:   default:
        !          1039:     log_err(0, "Unknown downlink protocol");
        !          1040:   }
        !          1041: 
        !          1042:   return 0;
        !          1043: }
        !          1044: 
        !          1045: int static dnprot_accept(struct app_conn_t *appconn) {
        !          1046:   struct dhcp_conn_t* dhcpconn = NULL;
        !          1047:   
        !          1048:   if (appconn->is_adminsession) return 0;
        !          1049: 
        !          1050:   if (!appconn->hisip.s_addr) {
        !          1051:     log_err(0, "IP address not allocated");
        !          1052:     return 0;
        !          1053:   }
        !          1054: 
        !          1055:   switch (appconn->dnprot) {
        !          1056:   case DNPROT_EAPOL:
        !          1057:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !          1058:       log_err(0, "No downlink protocol");
        !          1059:       return 0;
        !          1060:     }
        !          1061: 
        !          1062:     dhcp_set_addrs(dhcpconn, 
        !          1063:                   &appconn->hisip, &appconn->mask,
        !          1064:                   &appconn->ourip, &appconn->mask,
        !          1065:                   &appconn->dns1, &appconn->dns2,
        !          1066:                   options.domain);
        !          1067:     
        !          1068:     /* This is the one and only place eapol authentication is accepted */
        !          1069: 
        !          1070:     dhcpconn->authstate = DHCP_AUTH_PASS;
        !          1071: 
        !          1072:     /* Tell client it was successful */
        !          1073:     dhcp_sendEAP(dhcpconn, appconn->chal, appconn->challen);
        !          1074: 
        !          1075:     log_warn(0, "Do not know how to set encryption keys on this platform!");
        !          1076:     break;
        !          1077: 
        !          1078:   case DNPROT_UAM:
        !          1079:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !          1080:       log_err(0, "No downlink protocol");
        !          1081:       return 0;
        !          1082:     }
        !          1083: 
        !          1084:     dhcp_set_addrs(dhcpconn, 
        !          1085:                   &appconn->hisip, &appconn->mask,
        !          1086:                   &appconn->ourip, &appconn->mask,
        !          1087:                   &appconn->dns1, &appconn->dns2,
        !          1088:                   options.domain);
        !          1089: 
        !          1090:     /* This is the one and only place UAM authentication is accepted */
        !          1091:     dhcpconn->authstate = DHCP_AUTH_PASS;
        !          1092:     appconn->s_params.flags &= ~REQUIRE_UAM_AUTH;
        !          1093:     break;
        !          1094: 
        !          1095:   case DNPROT_WPA:
        !          1096:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !          1097:       log_err(0, "No downlink protocol");
        !          1098:       return 0;
        !          1099:     }
        !          1100: 
        !          1101:     dhcp_set_addrs(dhcpconn, 
        !          1102:                   &appconn->hisip, &appconn->mask, 
        !          1103:                   &appconn->ourip, &appconn->mask, 
        !          1104:                   &appconn->dns1, &appconn->dns2,
        !          1105:                   options.domain);
        !          1106:     
        !          1107:     /* This is the one and only place WPA authentication is accepted */
        !          1108:     if (appconn->s_params.flags & REQUIRE_UAM_AUTH) {
        !          1109:       appconn->dnprot = DNPROT_DHCP_NONE;
        !          1110:       dhcpconn->authstate = DHCP_AUTH_NONE;
        !          1111:     }
        !          1112:     else {
        !          1113:       dhcpconn->authstate = DHCP_AUTH_PASS;
        !          1114:     }
        !          1115:     
        !          1116:     /* Tell access point it was successful */
        !          1117:     radius_access_accept(appconn);
        !          1118: 
        !          1119:     break;
        !          1120: 
        !          1121:   case DNPROT_MAC:
        !          1122:     if (!(dhcpconn = (struct dhcp_conn_t *)appconn->dnlink)) {
        !          1123:       log_err(0, "No downlink protocol");
        !          1124:       return 0;
        !          1125:     }
        !          1126: 
        !          1127:     dhcp_set_addrs(dhcpconn, 
        !          1128:                   &appconn->hisip, &appconn->mask, 
        !          1129:                   &appconn->ourip, &appconn->mask, 
        !          1130:                   &appconn->dns1, &appconn->dns2,
        !          1131:                   options.domain);
        !          1132:     
        !          1133:     dhcpconn->authstate = DHCP_AUTH_PASS;
        !          1134:     break;
        !          1135: 
        !          1136:   case DNPROT_NULL:
        !          1137:   case DNPROT_DHCP_NONE:
        !          1138:     return 0;
        !          1139: 
        !          1140:   default:
        !          1141:     log_err(0, "Unknown downlink protocol");
        !          1142:     return 0;
        !          1143:   }
        !          1144: 
        !          1145:   if (appconn->s_params.flags & REQUIRE_UAM_SPLASH)
        !          1146:     dhcpconn->authstate = DHCP_AUTH_SPLASH;
        !          1147:   
        !          1148:   if (!(appconn->s_params.flags & REQUIRE_UAM_AUTH)) {
        !          1149:     /* This is the one and only place state is switched to authenticated */
        !          1150:     appconn->s_state.authenticated = 1;
        !          1151:     
        !          1152:     /* Run connection up script */
        !          1153:     if (options.conup) {
        !          1154:       if (options.debug) log_dbg("Calling connection up script: %s\n", options.conup);
        !          1155:       runscript(appconn, options.conup);
        !          1156:     }
        !          1157:     
        !          1158:     printstatus(appconn);
        !          1159:     
        !          1160:     if (!(appconn->s_params.flags & IS_UAM_REAUTH))
        !          1161:       acct_req(appconn, RADIUS_STATUS_TYPE_START);
        !          1162:   }
        !          1163:   
        !          1164:   appconn->s_params.flags &= ~IS_UAM_REAUTH;
        !          1165:   return 0;
        !          1166: }
        !          1167: 
        !          1168: 
        !          1169: /*
        !          1170:  * Tun callbacks
        !          1171:  *
        !          1172:  * Called from the tun_decaps function. This method is passed either
        !          1173:  * a Ethernet frame or an IP packet. 
        !          1174:  */
        !          1175: 
        !          1176: int cb_tun_ind(struct tun_t *tun, void *pack, size_t len, int idx) {
        !          1177:   struct in_addr dst;
        !          1178:   struct ippoolm_t *ipm;
        !          1179:   struct app_conn_t *appconn;
        !          1180:   struct pkt_ipphdr_t *ipph;
        !          1181: 
        !          1182:   int ethhdr = !!(tun(tun, idx).flags & NET_ETHHDR);
        !          1183: 
        !          1184:   if (ethhdr) {
        !          1185:     struct pkt_ethhdr_t *ethh = (struct pkt_ethhdr_t *)pack;
        !          1186:     uint16_t prot = ntohs(ethh->prot);
        !          1187: 
        !          1188:     ipph = (struct pkt_ipphdr_t *)((char *)pack + PKT_ETH_HLEN);
        !          1189: 
        !          1190:     if (prot == PKT_ETH_PROTO_ARP) {
        !          1191:       /*
        !          1192:        * send arp reply with us being target
        !          1193:        */
        !          1194:       struct arp_fullpacket_t *p = (struct arp_fullpacket_t *)pack;
        !          1195:       struct arp_fullpacket_t packet;
        !          1196:       struct in_addr reqaddr;
        !          1197:       size_t length = sizeof(packet);
        !          1198:       
        !          1199:       log_dbg("arp: dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x prot=%.4x\n",
        !          1200:              ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5],
        !          1201:              ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
        !          1202:              ntohs(ethh->prot));
        !          1203:       
        !          1204:       /* Get local copy */
        !          1205:       memcpy(&reqaddr.s_addr, p->arp.tpa, PKT_IP_ALEN);
        !          1206:       
        !          1207:       if (ippool_getip(ippool, &ipm, &reqaddr)) {
        !          1208:        if (options.debug) 
        !          1209:            log_dbg("ARP for unknown IP %s\n", inet_ntoa(reqaddr));
        !          1210:        return 0;
        !          1211:       }
        !          1212:       
        !          1213:       if ((appconn  = (struct app_conn_t *)ipm->peer) == NULL ||
        !          1214:          (appconn->dnlink) == NULL) {
        !          1215:        log_err(0, "No peer protocol defined for ARP request");
        !          1216:        return 0;
        !          1217:       }
        !          1218:       
        !          1219:       /* Get packet default values */
        !          1220:       memset(&packet, 0, sizeof(packet));
        !          1221:       
        !          1222:       /* ARP Payload */
        !          1223:       packet.arp.hrd = htons(DHCP_HTYPE_ETH);
        !          1224:       packet.arp.pro = htons(PKT_ETH_PROTO_IP);
        !          1225:       packet.arp.hln = PKT_ETH_ALEN;
        !          1226:       packet.arp.pln = PKT_IP_ALEN;
        !          1227:       packet.arp.op  = htons(DHCP_ARP_REPLY);
        !          1228:       
        !          1229:       /* Source address */
        !          1230:       /*memcpy(packet.arp.sha, dhcp->arp_hwaddr, PKT_ETH_ALEN);
        !          1231:        memcpy(packet.arp.spa, &dhcp->ourip.s_addr, PKT_IP_ALEN);*/
        !          1232:       /*memcpy(packet.arp.sha, appconn->hismac, PKT_ETH_ALEN);*/
        !          1233:       memcpy(packet.arp.sha, tun->_interfaces[0].hwaddr, PKT_ETH_ALEN);
        !          1234:       memcpy(packet.arp.spa, &appconn->hisip.s_addr, PKT_IP_ALEN);
        !          1235:        
        !          1236:       /* Target address */
        !          1237:       /*memcpy(packet.arp.tha, &appconn->hismac, PKT_ETH_ALEN);
        !          1238:        memcpy(packet.arp.tpa, &appconn->hisip.s_addr, PKT_IP_ALEN); */
        !          1239:       memcpy(packet.arp.tha, p->arp.sha, PKT_ETH_ALEN);
        !          1240:       memcpy(packet.arp.tpa, p->arp.spa, PKT_IP_ALEN);
        !          1241:       
        !          1242:       /* Ethernet header */
        !          1243:       memcpy(packet.ethh.dst, p->ethh.src, PKT_ETH_ALEN);
        !          1244:       memcpy(packet.ethh.src, dhcp->ipif.hwaddr, PKT_ETH_ALEN);
        !          1245:       packet.ethh.prot = htons(PKT_ETH_PROTO_ARP);
        !          1246:       
        !          1247:       return tun_encaps(tun, &packet, length, idx);
        !          1248:     }
        !          1249:   } else {
        !          1250:     ipph = (struct pkt_ipphdr_t *)pack;
        !          1251:   }
        !          1252: 
        !          1253:   /*if (options.debug) 
        !          1254:     log_dbg("cb_tun_ind. Packet received: Forwarding to link layer");*/
        !          1255: 
        !          1256:   dst.s_addr = ipph->daddr;
        !          1257: 
        !          1258:   if (ippool_getip(ippool, &ipm, &dst)) {
        !          1259:     if (options.debug) 
        !          1260:       log_dbg("dropping packet with unknown destination: %s", inet_ntoa(dst));
        !          1261:     return 0;
        !          1262:   }
        !          1263:   
        !          1264:   if ((appconn = (struct app_conn_t *)ipm->peer) == NULL ||
        !          1265:       (appconn->dnlink) == NULL) {
        !          1266:     log_err(0, "No peer protocol defined");
        !          1267:     return 0;
        !          1268:   }
        !          1269:   
        !          1270:   /* If the ip src is uamlisten and psrc is uamport we won't call leaky_bucket */
        !          1271:   if ( ! (ipph->saddr  == options.uamlisten.s_addr && 
        !          1272:          (ipph->sport == htons(options.uamport) ||
        !          1273:           ipph->sport == htons(options.uamuiport)))) {
        !          1274:     if (appconn->s_state.authenticated == 1) {
        !          1275: 
        !          1276: #ifndef LEAKY_BUCKET
        !          1277:       appconn->s_state.last_time = mainclock;
        !          1278: #endif
        !          1279: 
        !          1280: #ifdef LEAKY_BUCKET
        !          1281: #ifndef COUNT_DOWNLINK_DROP
        !          1282:     if (leaky_bucket(appconn, 0, len)) return 0;
        !          1283: #endif
        !          1284: #endif
        !          1285:     if (options.swapoctets) {
        !          1286:       appconn->s_state.output_packets++;
        !          1287:       appconn->s_state.output_octets += len;
        !          1288:       if (admin_session.s_state.authenticated) {
        !          1289:        admin_session.s_state.output_packets++;
        !          1290:        admin_session.s_state.output_octets+=len;
        !          1291:       }
        !          1292:     } else {
        !          1293:       appconn->s_state.input_packets++;
        !          1294:       appconn->s_state.input_octets += len;
        !          1295:       if (admin_session.s_state.authenticated) {
        !          1296:        admin_session.s_state.input_packets++;
        !          1297:        admin_session.s_state.input_octets+=len;
        !          1298:       }
        !          1299:     }
        !          1300: #ifdef LEAKY_BUCKET
        !          1301: #ifdef COUNT_DOWNLINK_DROP
        !          1302:     if (leaky_bucket(appconn, 0, len)) return 0;
        !          1303: #endif
        !          1304: #endif
        !          1305:     }
        !          1306:   }
        !          1307: 
        !          1308:   switch (appconn->dnprot) {
        !          1309:   case DNPROT_NULL:
        !          1310:   case DNPROT_DHCP_NONE:
        !          1311:     break;
        !          1312: 
        !          1313:   case DNPROT_UAM:
        !          1314:   case DNPROT_WPA:
        !          1315:   case DNPROT_MAC:
        !          1316:   case DNPROT_EAPOL:
        !          1317:     dhcp_data_req((struct dhcp_conn_t *)appconn->dnlink, pack, len, ethhdr);
        !          1318:     break;
        !          1319: 
        !          1320:   default:
        !          1321:     log_err(0, "Unknown downlink protocol: %d", appconn->dnprot);
        !          1322:     break;
        !          1323:   }
        !          1324: 
        !          1325:   return 0;
        !          1326: }
        !          1327: 
        !          1328: 
        !          1329: /*********************************************************
        !          1330:  *
        !          1331:  * Redir callbacks
        !          1332:  *
        !          1333:  *********************************************************/
        !          1334: 
        !          1335: int cb_redir_getstate(struct redir_t *redir, struct in_addr *addr,
        !          1336:                      struct redir_conn_t *conn) {
        !          1337:   struct ippoolm_t *ipm;
        !          1338:   struct app_conn_t *appconn;
        !          1339:   struct dhcp_conn_t *dhcpconn;
        !          1340: 
        !          1341:   if (ippool_getip(ippool, &ipm, addr)) {
        !          1342:     return -1;
        !          1343:   }
        !          1344:   
        !          1345:   if ( (appconn  = (struct app_conn_t *)ipm->peer)        == NULL || 
        !          1346:        (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL ) {
        !          1347:     log_warn(0, "No peer protocol defined");
        !          1348:     return -1;
        !          1349:   }
        !          1350:   
        !          1351:   conn->nasip = options.radiuslisten;
        !          1352:   conn->nasport = appconn->unit;
        !          1353:   memcpy(conn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
        !          1354:   memcpy(conn->ourmac, dhcpconn->ourmac, PKT_ETH_ALEN);
        !          1355:   conn->ourip = appconn->ourip;
        !          1356:   conn->hisip = appconn->hisip;
        !          1357: 
        !          1358:   memcpy(&conn->s_params, &appconn->s_params, sizeof(appconn->s_params));
        !          1359:   memcpy(&conn->s_state,  &appconn->s_state,  sizeof(appconn->s_state));
        !          1360: 
        !          1361:   /* reset state */
        !          1362:   appconn->uamexit=0;
        !          1363: 
        !          1364:   return conn->s_state.authenticated == 1;
        !          1365: }
        !          1366: 
        !          1367: 
        !          1368: /*********************************************************
        !          1369:  *
        !          1370:  * Functions supporting radius callbacks
        !          1371:  *
        !          1372:  *********************************************************/
        !          1373: 
        !          1374: /* Handle an accounting request */
        !          1375: int accounting_request(struct radius_packet_t *pack,
        !          1376:                       struct sockaddr_in *peer) {
        !          1377:   struct radius_attr_t *hismacattr = NULL;
        !          1378:   struct radius_attr_t *typeattr = NULL;
        !          1379:   struct radius_attr_t *nasipattr = NULL;
        !          1380:   struct radius_attr_t *nasportattr = NULL;
        !          1381:   struct radius_packet_t radius_pack;
        !          1382:   struct app_conn_t *appconn = NULL;
        !          1383:   struct dhcp_conn_t *dhcpconn = NULL;
        !          1384:   uint8_t hismac[PKT_ETH_ALEN];
        !          1385:   char macstr[RADIUS_ATTR_VLEN];
        !          1386:   size_t macstrlen;
        !          1387:   unsigned int temp[PKT_ETH_ALEN];
        !          1388:   uint32_t nasip = 0;
        !          1389:   uint32_t nasport = 0;
        !          1390:   int i;
        !          1391: 
        !          1392: 
        !          1393:   if (radius_default_pack(radius, &radius_pack, 
        !          1394:                          RADIUS_CODE_ACCOUNTING_RESPONSE)) {
        !          1395:     log_err(0, "radius_default_pack() failed");
        !          1396:     return -1;
        !          1397:   }
        !          1398:   radius_pack.id = pack->id;
        !          1399:   
        !          1400:   /* Status type */
        !          1401:   if (radius_getattr(pack, &typeattr, RADIUS_ATTR_ACCT_STATUS_TYPE, 0, 0, 0)) {
        !          1402:     log_err(0, "Status type is missing from radius request");
        !          1403:     radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1404:     return 0;
        !          1405:   }
        !          1406: 
        !          1407:   if (typeattr->v.i != htonl(RADIUS_STATUS_TYPE_STOP)) {
        !          1408:     radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1409:     return 0;
        !          1410:   }
        !          1411: 
        !          1412: 
        !          1413:   /* NAS IP */
        !          1414:   if (!radius_getattr(pack, &nasipattr, RADIUS_ATTR_NAS_IP_ADDRESS, 0, 0, 0)) {
        !          1415:     if ((nasipattr->l-2) != sizeof(appconn->nasip)) {
        !          1416:       log_err(0, "Wrong length of NAS IP address");
        !          1417:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1418:     }
        !          1419:     nasip = nasipattr->v.i;
        !          1420:   }
        !          1421:   
        !          1422:   /* NAS PORT */
        !          1423:   if (!radius_getattr(pack, &nasportattr, RADIUS_ATTR_NAS_PORT, 0, 0, 0)) {
        !          1424:     if ((nasportattr->l-2) != sizeof(appconn->nasport)) {
        !          1425:       log_err(0, "Wrong length of NAS port");
        !          1426:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1427:     }
        !          1428:     nasport = nasportattr->v.i;
        !          1429:   }
        !          1430:   
        !          1431:   /* Calling Station ID (MAC Address) */
        !          1432:   if (!radius_getattr(pack, &hismacattr, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0)) {
        !          1433:     if (options.debug) {
        !          1434:       log_dbg("Calling Station ID is: %.*s", hismacattr->l-2, hismacattr->v.t);
        !          1435:     }
        !          1436:     if ((macstrlen = (size_t)hismacattr->l-2) >= (RADIUS_ATTR_VLEN-1)) {
        !          1437:       log_err(0, "Wrong length of called station ID");
        !          1438:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1439:     }
        !          1440:     memcpy(macstr, hismacattr->v.t, macstrlen);
        !          1441:     macstr[macstrlen] = 0;
        !          1442:     
        !          1443:     /* Replace anything but hex with space */
        !          1444:     for (i=0; i<macstrlen; i++) 
        !          1445:       if (!isxdigit(macstr[i])) macstr[i] = 0x20;
        !          1446:     
        !          1447:     if (sscanf (macstr, "%2x %2x %2x %2x %2x %2x",
        !          1448:                &temp[0], &temp[1], &temp[2], 
        !          1449:                &temp[3], &temp[4], &temp[5]) != 6) {
        !          1450:       log_err(0,
        !          1451:              "Failed to convert Calling Station ID to MAC Address");
        !          1452:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1453:     }
        !          1454:     
        !          1455:     for(i = 0; i < PKT_ETH_ALEN; i++) 
        !          1456:       hismac[i] = temp[i];
        !          1457:   }
        !          1458: 
        !          1459:   if (hismacattr) { /* Look for mac address.*/
        !          1460:     if (dhcp_hashget(dhcp, &dhcpconn, hismac)) {
        !          1461:       log_err(0, "Unknown connection");
        !          1462:       radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1463:       return 0;
        !          1464:     }
        !          1465:     if (!(dhcpconn->peer) || !((struct app_conn_t *)dhcpconn->peer)->uplink) {
        !          1466:       log_err(0,"No peer protocol defined");
        !          1467:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1468:     }
        !          1469:     appconn = (struct app_conn_t*) dhcpconn->peer;
        !          1470:   }
        !          1471:   else if (nasipattr && nasportattr) { /* Look for NAS IP / Port */
        !          1472:     if (getconn(&appconn, nasip, nasport)) {
        !          1473:       log_err(0, "Unknown connection");
        !          1474:       radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1475:       return 0;
        !          1476:     }
        !          1477:   }
        !          1478:   else {
        !          1479:     log_err(0,
        !          1480:            "Calling Station ID or NAS IP/Port is missing from radius request");
        !          1481:     radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1482:     return 0;
        !          1483:   }
        !          1484:   
        !          1485:   /* Silently ignore radius request if allready processing one */
        !          1486:   if (appconn->radiuswait) {
        !          1487:     if (appconn->radiuswait == 2) {
        !          1488:       log_dbg("Giving up on previous packet.. not dropping this one");
        !          1489:       appconn->radiuswait=0;
        !          1490:     } else {
        !          1491:       log_dbg("Dropping RADIUS while waiting");
        !          1492:       appconn->radiuswait++;
        !          1493:       return 0;
        !          1494:     }
        !          1495:   }
        !          1496:   
        !          1497:   /* TODO: Check validity of pointers */
        !          1498:   
        !          1499:   switch (appconn->dnprot) {
        !          1500:   case DNPROT_UAM:
        !          1501:     log_err(0,"Auth stop received for UAM");
        !          1502:     break;
        !          1503:   case DNPROT_WPA:
        !          1504:     dhcpconn = (struct dhcp_conn_t*) appconn->dnlink;
        !          1505:     if (!dhcpconn) {
        !          1506:       log_err(0,"No downlink protocol");
        !          1507:       return 0;
        !          1508:     }
        !          1509:     /* Connection is simply deleted */
        !          1510:     dhcp_freeconn(dhcpconn, RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
        !          1511:     break;
        !          1512:   default:
        !          1513:     log_err(0,"Unhandled downlink protocol %d", appconn->dnprot);
        !          1514:     radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1515:     return 0;
        !          1516:   }
        !          1517: 
        !          1518:   radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1519: 
        !          1520:   return 0;
        !          1521: }
        !          1522: 
        !          1523: 
        !          1524: int access_request(struct radius_packet_t *pack,
        !          1525:                   struct sockaddr_in *peer) {
        !          1526:   int n;
        !          1527:   struct radius_packet_t radius_pack;
        !          1528: 
        !          1529:   struct ippoolm_t *ipm = NULL;
        !          1530: 
        !          1531:   struct radius_attr_t *hisipattr = NULL;
        !          1532:   struct radius_attr_t *nasipattr = NULL;
        !          1533:   struct radius_attr_t *nasportattr = NULL;
        !          1534:   struct radius_attr_t *hismacattr = NULL;
        !          1535:   struct radius_attr_t *uidattr = NULL;
        !          1536:   struct radius_attr_t *pwdattr = NULL;
        !          1537:   struct radius_attr_t *eapattr = NULL;
        !          1538: 
        !          1539:   struct in_addr hisip;
        !          1540:   char pwd[RADIUS_ATTR_VLEN];
        !          1541:   size_t pwdlen;
        !          1542:   uint8_t hismac[PKT_ETH_ALEN];
        !          1543:   char macstr[RADIUS_ATTR_VLEN];
        !          1544:   size_t macstrlen;
        !          1545:   unsigned int temp[PKT_ETH_ALEN];
        !          1546:   char mac[MACSTRLEN+1];
        !          1547:   int i;
        !          1548: 
        !          1549:   struct app_conn_t *appconn = NULL;
        !          1550:   struct dhcp_conn_t *dhcpconn = NULL;
        !          1551: 
        !          1552:   uint8_t resp[EAP_LEN];         /* EAP response */
        !          1553:   size_t resplen;                /* Length of EAP response */
        !          1554: 
        !          1555:   size_t offset = 0;
        !          1556:   size_t eaplen = 0;
        !          1557:   int instance = 0;
        !          1558: 
        !          1559:   if (options.debug) 
        !          1560:     log_dbg("RADIUS Access-Request received");
        !          1561: 
        !          1562:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REJECT)) {
        !          1563:     log_err(0, "radius_default_pack() failed");
        !          1564:     return -1;
        !          1565:   }
        !          1566: 
        !          1567:   radius_pack.id = pack->id;
        !          1568: 
        !          1569:   /* User is identified by either IP address OR MAC address */
        !          1570:   
        !          1571:   /* Framed IP address (Conditional) */
        !          1572:   if (!radius_getattr(pack, &hisipattr, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0, 0)) {
        !          1573:     if (options.debug) {
        !          1574:       log_dbg("Framed IP address is: ");
        !          1575:       for (n=0; n<hisipattr->l-2; n++) log_dbg("%.2x", hisipattr->v.t[n]); 
        !          1576:       log_dbg("\n");
        !          1577:     }
        !          1578:     if ((hisipattr->l-2) != sizeof(hisip.s_addr)) {
        !          1579:       log_err(0, "Wrong length of framed IP address");
        !          1580:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1581:     }
        !          1582:     hisip.s_addr = hisipattr->v.i;
        !          1583:   }
        !          1584: 
        !          1585:   /* Calling Station ID: MAC Address (Conditional) */
        !          1586:   if (!radius_getattr(pack, &hismacattr, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0)) {
        !          1587:     if (options.debug) {
        !          1588:       log_dbg("Calling Station ID is: %.*s", hismacattr->l-2, hismacattr->v.t);
        !          1589:     }
        !          1590:     if ((macstrlen = (size_t)hismacattr->l-2) >= (RADIUS_ATTR_VLEN-1)) {
        !          1591:       log_err(0, "Wrong length of called station ID");
        !          1592:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1593:     }
        !          1594:     memcpy(macstr, hismacattr->v.t, macstrlen);
        !          1595:     macstr[macstrlen] = 0;
        !          1596: 
        !          1597:     /* Replace anything but hex with space */
        !          1598:     for (i=0; i<macstrlen; i++) 
        !          1599:       if (!isxdigit(macstr[i])) macstr[i] = 0x20;
        !          1600: 
        !          1601:     if (sscanf (macstr, "%2x %2x %2x %2x %2x %2x",
        !          1602:                &temp[0], &temp[1], &temp[2], 
        !          1603:                &temp[3], &temp[4], &temp[5]) != 6) {
        !          1604:       log_err(0, "Failed to convert Calling Station ID to MAC Address");
        !          1605:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1606:     }
        !          1607:     
        !          1608:     for(i = 0; i < PKT_ETH_ALEN; i++) 
        !          1609:       hismac[i] = temp[i];
        !          1610:   }
        !          1611: 
        !          1612:   /* Framed IP address or MAC Address must be given in request */
        !          1613:   if ((!hisipattr) && (!hismacattr)) {
        !          1614:     log_err(0, "Framed IP address or Calling Station ID is missing from radius request");
        !          1615:     return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1616:   }
        !          1617: 
        !          1618:   /* Username (Mandatory) */
        !          1619:   if (radius_getattr(pack, &uidattr, RADIUS_ATTR_USER_NAME, 0, 0, 0)) {
        !          1620:     log_err(0, "User-Name is missing from radius request");
        !          1621:     return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1622:   } 
        !          1623: 
        !          1624:   if (hisipattr) { /* Find user based on IP address */
        !          1625:     if (ippool_getip(ippool, &ipm, &hisip)) {
        !          1626:       log_err(0, "RADIUS-Request: IP Address not found");
        !          1627:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1628:     }
        !          1629:     
        !          1630:     if ((appconn  = (struct app_conn_t *)ipm->peer)        == NULL || 
        !          1631:        (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL) {
        !          1632:       log_err(0, "RADIUS-Request: No peer protocol defined");
        !          1633:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1634:     }
        !          1635:   }
        !          1636:   else if (hismacattr) { /* Look for mac address. If not found allocate new */
        !          1637:     if (dhcp_hashget(dhcp, &dhcpconn, hismac)) {
        !          1638:       if (dhcp_newconn(dhcp, &dhcpconn, hismac)) {
        !          1639:        log_err(0, "Out of connections");
        !          1640:        return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1641:       }
        !          1642:     }
        !          1643:     if (!(dhcpconn->peer)) {
        !          1644:       log_err(0, "No peer protocol defined");
        !          1645:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1646:     }
        !          1647:     appconn = (struct app_conn_t *)dhcpconn->peer;
        !          1648:     /*if (appconn->dnprot == DNPROT_DHCP_NONE)
        !          1649:     appconn->dnprot = DNPROT_WPA;*/
        !          1650:   }
        !          1651:   else {
        !          1652:     log_err(0, "Framed IP address or Calling Station ID is missing from radius request");
        !          1653:     return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1654:   }
        !          1655: 
        !          1656:   /* Silently ignore radius request if allready processing one */
        !          1657:   if (appconn->radiuswait) {
        !          1658:     if (appconn->radiuswait == 2) {
        !          1659:       log_dbg("Giving up on previous packet.. not dropping this one");
        !          1660:       appconn->radiuswait=0;
        !          1661:     } else {
        !          1662:       log_dbg("Dropping RADIUS while waiting");
        !          1663:       appconn->radiuswait++;
        !          1664:       return 0;
        !          1665:     }
        !          1666:   }
        !          1667:   
        !          1668:   /* Password */
        !          1669:   if (!radius_getattr(pack, &pwdattr, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0)) {
        !          1670:     if (radius_pwdecode(radius, (uint8_t*) pwd, RADIUS_ATTR_VLEN, &pwdlen, 
        !          1671:                        pwdattr->v.t, pwdattr->l-2, pack->authenticator,
        !          1672:                        radius->proxysecret,
        !          1673:                        radius->proxysecretlen)) {
        !          1674:       log_err(0, "radius_pwdecode() failed");
        !          1675:       return -1;
        !          1676:     }
        !          1677:     if (options.debug) log_dbg("Password is: %s\n", pwd);
        !          1678:   }
        !          1679: 
        !          1680:   /* Get EAP message */
        !          1681:   resplen = 0;
        !          1682:   do {
        !          1683:     eapattr=NULL;
        !          1684:     if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 
        !          1685:                        instance++)) {
        !          1686:       if ((resplen + (size_t)eapattr->l-2) > EAP_LEN) {
        !          1687:        log(LOG_INFO, "EAP message too long");
        !          1688:        return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1689:       }
        !          1690:       memcpy(resp + resplen, eapattr->v.t, (size_t)eapattr->l-2);
        !          1691:       resplen += (size_t)eapattr->l-2;
        !          1692:     }
        !          1693:   } while (eapattr);
        !          1694:   
        !          1695: 
        !          1696:   /* Passwd or EAP must be given in request */
        !          1697:   if ((!pwdattr) && (!resplen)) {
        !          1698:     log_err(0, "Password or EAP meaasge is missing from radius request");
        !          1699:     return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1700:   }
        !          1701: 
        !          1702:   /* ChilliSpot Notes:
        !          1703:      Dublicate logins should be allowed as it might be the terminal
        !          1704:      moving from one access point to another. It is however
        !          1705:      unacceptable to login with another username on top of an allready
        !          1706:      existing connection 
        !          1707: 
        !          1708:      TODO: New username should be allowed, but should result in
        !          1709:      a accounting stop message for the old connection.
        !          1710:      this does however pose a denial of service attack possibility 
        !          1711:   
        !          1712:      If allready logged in send back accept message with username
        !          1713:      TODO ? Should this be a reject: Dont login twice ? 
        !          1714:   */
        !          1715: 
        !          1716:   /* Terminate previous session if trying to login with another username */
        !          1717:   if ((appconn->s_state.authenticated == 1) && 
        !          1718:       ((strlen(appconn->s_state.redir.username) != uidattr->l-2) ||
        !          1719:        (memcmp(appconn->s_state.redir.username, uidattr->v.t, uidattr->l-2)))) {
        !          1720:     terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
        !          1721:     /* DWB: But, let's not reject someone who is trying to authenticate under
        !          1722:        a new (potentially) valid account - that is for the up-stream RADIUS to discern
        !          1723:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);*/
        !          1724:   }
        !          1725: 
        !          1726:   /* Radius auth only for DHCP */
        !          1727:   /*if ((appconn->dnprot != DNPROT_UAM) && (appconn->dnprot != DNPROT_WPA))  { */
        !          1728:     /*return radius_resp(radius, &radius_pack, peer, pack->authenticator);*/
        !          1729:   appconn->dnprot = DNPROT_WPA;
        !          1730:   /*  }*/
        !          1731: 
        !          1732:   /* NAS IP */
        !          1733:   if (!radius_getattr(pack, &nasipattr, RADIUS_ATTR_NAS_IP_ADDRESS, 0, 0, 0)) {
        !          1734:     if ((nasipattr->l-2) != sizeof(appconn->nasip)) {
        !          1735:       log_err(0, "Wrong length of NAS IP address");
        !          1736:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1737:     }
        !          1738:     appconn->nasip = nasipattr->v.i;
        !          1739:   }
        !          1740: 
        !          1741:   /* NAS PORT */
        !          1742:   if (!radius_getattr(pack, &nasportattr, RADIUS_ATTR_NAS_PORT, 0, 0, 0)) {
        !          1743:     if ((nasportattr->l-2) != sizeof(appconn->nasport)) {
        !          1744:       log_err(0, "Wrong length of NAS port");
        !          1745:       return radius_resp(radius, &radius_pack, peer, pack->authenticator);
        !          1746:     }
        !          1747:     appconn->nasport = nasportattr->v.i;
        !          1748:   }
        !          1749: 
        !          1750:   /* Store parameters for later use */
        !          1751:   if (uidattr->l-2<=USERNAMESIZE) {
        !          1752:     strncpy(appconn->s_state.redir.username, 
        !          1753:            (char *)uidattr->v.t, uidattr->l-2);
        !          1754:   }
        !          1755: 
        !          1756:   appconn->radiuswait = 1;
        !          1757:   appconn->radiusid = pack->id;
        !          1758: 
        !          1759:   if (pwdattr)
        !          1760:     appconn->authtype = PAP_PASSWORD;
        !          1761:   else
        !          1762:     appconn->authtype = EAP_MESSAGE;
        !          1763: 
        !          1764:   memcpy(&appconn->radiuspeer, peer, sizeof(*peer));
        !          1765:   memcpy(appconn->authenticator, pack->authenticator, RADIUS_AUTHLEN);
        !          1766:   memcpy(appconn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
        !          1767:   memcpy(appconn->ourmac, dhcpconn->ourmac, PKT_ETH_ALEN);
        !          1768: 
        !          1769:   /* Build up radius request */
        !          1770:   radius_pack.code = RADIUS_CODE_ACCESS_REQUEST;
        !          1771:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
        !          1772:                 uidattr->v.t, uidattr->l - 2);
        !          1773: 
        !          1774:   if (appconn->s_state.redir.statelen) {
        !          1775:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_STATE, 0, 0, 0,
        !          1776:                   appconn->s_state.redir.statebuf,
        !          1777:                   appconn->s_state.redir.statelen);
        !          1778:   }
        !          1779: 
        !          1780:   if (pwdattr)
        !          1781:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
        !          1782:                   (uint8_t*) pwd, pwdlen);
        !          1783: 
        !          1784:   /* Include EAP (if present) */
        !          1785:   offset = 0;
        !          1786:   while (offset < resplen) {
        !          1787: 
        !          1788:     if ((resplen - offset) > RADIUS_ATTR_VLEN)
        !          1789:       eaplen = RADIUS_ATTR_VLEN;
        !          1790:     else
        !          1791:       eaplen = resplen - offset;
        !          1792: 
        !          1793:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
        !          1794:                   resp + offset, eaplen);
        !          1795: 
        !          1796:     offset += eaplen;
        !          1797:   } 
        !          1798: 
        !          1799:   if (resplen) {
        !          1800:     if (options.wpaguests)
        !          1801:       radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1802:                     RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_CONFIG, 
        !          1803:                     0, (uint8_t*)"allow-wpa-guests", 16);
        !          1804: 
        !          1805:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
        !          1806:                   0, 0, 0, NULL, RADIUS_MD5LEN);
        !          1807:   }
        !          1808: 
        !          1809:   /* Include his MAC address */
        !          1810:   snprintf(mac, MACSTRLEN+1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
        !          1811:           appconn->hismac[0], appconn->hismac[1],
        !          1812:           appconn->hismac[2], appconn->hismac[3],
        !          1813:           appconn->hismac[4], appconn->hismac[5]);
        !          1814:   
        !          1815:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
        !          1816:                 (uint8_t*) mac, MACSTRLEN);
        !          1817:   
        !          1818:   radius_addcalledstation(radius, &radius_pack);
        !          1819:   
        !          1820:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
        !          1821:                 options.radiusnasporttype, NULL, 0);
        !          1822:   
        !          1823:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT, 0, 0,
        !          1824:                 appconn->unit, NULL, 0);
        !          1825:   
        !          1826:   radius_addnasip(radius, &radius_pack);
        !          1827:   
        !          1828:   /* Include NAS-Identifier if given in configuration options */
        !          1829:   if (options.radiusnasid)
        !          1830:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
        !          1831:                   (uint8_t*) options.radiusnasid, strlen(options.radiusnasid));
        !          1832:   
        !          1833:   return radius_req(radius, &radius_pack, appconn);
        !          1834: }
        !          1835: 
        !          1836: 
        !          1837: /*********************************************************
        !          1838:  *
        !          1839:  * radius proxy callback functions (request from radius server)
        !          1840:  *
        !          1841:  *********************************************************/
        !          1842: 
        !          1843: /* Radius callback when radius request has been received */
        !          1844: int cb_radius_ind(struct radius_t *rp, struct radius_packet_t *pack,
        !          1845:                  struct sockaddr_in *peer) {
        !          1846: 
        !          1847:   if (rp != radius) {
        !          1848:     log_err(0, "Radius callback from unknown instance");
        !          1849:     return 0;
        !          1850:   }
        !          1851:   
        !          1852:   switch (pack->code) {
        !          1853:   case RADIUS_CODE_ACCOUNTING_REQUEST: /* TODO: Exclude ??? */
        !          1854:     return accounting_request(pack, peer);
        !          1855:   case RADIUS_CODE_ACCESS_REQUEST:
        !          1856:     return access_request(pack, peer);
        !          1857:   default:
        !          1858:     log_err(0, "Unsupported radius request received: %d", pack->code);
        !          1859:     return 0;
        !          1860:   }
        !          1861: }
        !          1862: 
        !          1863: 
        !          1864: int upprot_getip(struct app_conn_t *appconn, 
        !          1865:                 struct in_addr *hisip, int statip) {
        !          1866:   struct ippoolm_t *ipm;
        !          1867: 
        !          1868:   /* If IP address is allready allocated: Fill it in */
        !          1869:   /* This should only happen for UAM */
        !          1870:   /* TODO */
        !          1871:   if (appconn->uplink) {
        !          1872:     ipm = (struct ippoolm_t *)appconn->uplink;
        !          1873:   }
        !          1874:   else {
        !          1875:     /* Allocate static or dynamic IP address */
        !          1876: 
        !          1877:     if (newip(&ipm, hisip))
        !          1878:       return dnprot_reject(appconn);
        !          1879: 
        !          1880:     appconn->hisip.s_addr = ipm->addr.s_addr;
        !          1881: 
        !          1882:     /* TODO: Too many "listen" and "our" addresses having around */
        !          1883:     appconn->ourip.s_addr = options.dhcplisten.s_addr;
        !          1884:     
        !          1885:     appconn->uplink = ipm;
        !          1886:     ipm->peer = appconn; 
        !          1887:   }
        !          1888: 
        !          1889:   return dnprot_accept(appconn);
        !          1890: 
        !          1891: }
        !          1892: 
        !          1893: void config_radius_session(struct session_params *params, struct radius_packet_t *pack, int reconfig) {
        !          1894:   struct radius_attr_t *attr = NULL;
        !          1895: 
        !          1896:   /* Session timeout */
        !          1897:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_SESSION_TIMEOUT, 0, 0, 0))
        !          1898:     params->sessiontimeout = ntohl(attr->v.i);
        !          1899:   else if (!reconfig)
        !          1900:     params->sessiontimeout = 0;
        !          1901: 
        !          1902:   /* Idle timeout */
        !          1903:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_IDLE_TIMEOUT, 0, 0, 0))
        !          1904:     params->idletimeout = ntohl(attr->v.i);
        !          1905:   else if (!reconfig) 
        !          1906:     params->idletimeout = 0;
        !          1907: 
        !          1908:   /* Filter ID */
        !          1909:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_FILTER_ID, 0, 0, 0)) {
        !          1910:     params->filteridlen = attr->l-2;
        !          1911:     memcpy(params->filteridbuf, attr->v.t, attr->l-2);
        !          1912:     params->filteridbuf[attr->l-2] = 0;
        !          1913:   }
        !          1914:   else if (!reconfig) {
        !          1915:     params->filteridlen = 0;
        !          1916:     params->filteridbuf[0] = 0;
        !          1917:   }
        !          1918: 
        !          1919:   /* Interim interval */
        !          1920:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 0, 0, 0)) {
        !          1921:     params->interim_interval = ntohl(attr->v.i);
        !          1922:     if (params->interim_interval < 60) {
        !          1923:       log_err(0, "Received too small radius Acct-Interim-Interval: %d; resettings to default.",
        !          1924:              params->interim_interval);
        !          1925:       params->interim_interval = options.definteriminterval;
        !          1926:     } 
        !          1927:   }
        !          1928:   else if (!reconfig)
        !          1929:     params->interim_interval = 0;
        !          1930: 
        !          1931:   /* Bandwidth up */
        !          1932:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1933:                      RADIUS_VENDOR_WISPR, 
        !          1934:                      RADIUS_ATTR_WISPR_BANDWIDTH_MAX_UP, 0))
        !          1935:     params->bandwidthmaxup = ntohl(attr->v.i);
        !          1936:   else if (!reconfig)
        !          1937:     params->bandwidthmaxup = 0;
        !          1938:   
        !          1939:   /* Bandwidth down */
        !          1940:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1941:                      RADIUS_VENDOR_WISPR, 
        !          1942:                      RADIUS_ATTR_WISPR_BANDWIDTH_MAX_DOWN, 0))
        !          1943:     params->bandwidthmaxdown = ntohl(attr->v.i);
        !          1944:   else if (!reconfig)
        !          1945:     params->bandwidthmaxdown = 0;
        !          1946: 
        !          1947: #ifdef RADIUS_ATTR_CHILLISPOT_BANDWIDTH_MAX_UP
        !          1948:   /* Bandwidth up */
        !          1949:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1950:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1951:                      RADIUS_ATTR_CHILLISPOT_BANDWIDTH_MAX_UP, 0))
        !          1952:     params->bandwidthmaxup = ntohl(attr->v.i) * 1000;
        !          1953: #endif
        !          1954: 
        !          1955: #ifdef RADIUS_ATTR_CHILLISPOT_BANDWIDTH_MAX_DOWN
        !          1956:   /* Bandwidth down */
        !          1957:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1958:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1959:                      RADIUS_ATTR_CHILLISPOT_BANDWIDTH_MAX_DOWN, 0))
        !          1960:     params->bandwidthmaxdown = ntohl(attr->v.i) * 1000;
        !          1961: #endif
        !          1962: 
        !          1963:   /* Max input octets */
        !          1964:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1965:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1966:                      RADIUS_ATTR_CHILLISPOT_MAX_INPUT_OCTETS, 0))
        !          1967:     params->maxinputoctets = ntohl(attr->v.i);
        !          1968:   else if (!reconfig)
        !          1969:     params->maxinputoctets = 0;
        !          1970: 
        !          1971:   /* Max output octets */
        !          1972:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1973:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1974:                      RADIUS_ATTR_CHILLISPOT_MAX_OUTPUT_OCTETS, 0))
        !          1975:     params->maxoutputoctets = ntohl(attr->v.i);
        !          1976:   else if (!reconfig)
        !          1977:     params->maxoutputoctets = 0;
        !          1978: 
        !          1979:   /* Max total octets */
        !          1980:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          1981:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1982:                      RADIUS_ATTR_CHILLISPOT_MAX_TOTAL_OCTETS, 0))
        !          1983:     params->maxtotaloctets = ntohl(attr->v.i);
        !          1984:   else if (!reconfig)
        !          1985:     params->maxtotaloctets = 0;
        !          1986: 
        !          1987:   /* Route Index, look-up by interface name */
        !          1988:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC, 
        !          1989:                      RADIUS_VENDOR_CHILLISPOT, 
        !          1990:                      RADIUS_ATTR_CHILLISPOT_ROUTE_TO_INTERFACE, 0)) {
        !          1991:     char name[256];
        !          1992:     memcpy(name, attr->v.t, attr->l-2);
        !          1993:     name[attr->l-2] = 0;
        !          1994:     params->routeidx = tun_name2idx(tun, name);
        !          1995:   }
        !          1996:   else if (!reconfig) {
        !          1997:     params->routeidx = tun->routeidx;
        !          1998:   }
        !          1999: 
        !          2000:   {
        !          2001:     const char *uamauth = "require-uam-auth";
        !          2002:     const char *uamallowed = "uamallowed=";
        !          2003:     const char *splash = "splash";
        !          2004:     size_t offset = 0;
        !          2005:     int is_splash = 0;
        !          2006: 
        !          2007:     /* Always reset the per session passthroughs */
        !          2008:     params->pass_through_count = 0;
        !          2009: 
        !          2010:     while (!radius_getnextattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2011:                               RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_CONFIG, 
        !          2012:                               0, &offset)) { 
        !          2013:       size_t len = (size_t)attr->l-2;
        !          2014:       char *val = (char *)attr->v.t;
        !          2015: 
        !          2016:       if (options.wpaguests && len == strlen(uamauth) && !memcmp(val, uamauth, len)) {
        !          2017:        log_dbg("received wpaguests");
        !          2018:        params->flags |= REQUIRE_UAM_AUTH;
        !          2019:       } 
        !          2020:       else if (len == strlen(splash) && !memcmp(val, splash, strlen(splash))) {
        !          2021:        log_dbg("received splash response");
        !          2022:        params->flags |= REQUIRE_UAM_SPLASH;
        !          2023:        is_splash = 1;
        !          2024:       }
        !          2025:       else if (len > strlen(uamallowed) && !memcmp(val, uamallowed, strlen(uamallowed))) {
        !          2026:        val[len]=0;
        !          2027:        pass_throughs_from_string(params->pass_throughs,
        !          2028:                                  SESSION_PASS_THROUGH_MAX,
        !          2029:                                  &params->pass_through_count,
        !          2030:                                  val + strlen(uamallowed));
        !          2031:       }
        !          2032:     }
        !          2033: 
        !          2034:     offset = 0;
        !          2035:     params->url[0]=0;
        !          2036:     while (!radius_getnextattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2037:                               RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_REDIRECTION_URL, 
        !          2038:                               0, &offset)) { 
        !          2039:       size_t clen, nlen = (size_t)attr->l-2;
        !          2040:       char *url = (char*)attr->v.t;
        !          2041:       clen = strlen((char*)params->url);
        !          2042: 
        !          2043:       if (clen + nlen > sizeof(params->url)-1) 
        !          2044:        nlen = sizeof(params->url)-clen-1;
        !          2045: 
        !          2046:       strncpy((char*)(params->url + clen), url, nlen);
        !          2047:       params->url[nlen+clen]=0;
        !          2048: 
        !          2049:       if (!splash)
        !          2050:        params->flags |= REQUIRE_REDIRECT;
        !          2051:     }
        !          2052:   }
        !          2053: 
        !          2054:   /* Session-Terminate-Time */
        !          2055:   if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2056:                      RADIUS_VENDOR_WISPR,
        !          2057:                      RADIUS_ATTR_WISPR_SESSION_TERMINATE_TIME, 0)) {
        !          2058:     char attrs[RADIUS_ATTR_VLEN+1];
        !          2059:     struct tm stt;
        !          2060:     int tzhour, tzmin;
        !          2061:     char *tz;
        !          2062:     int result;
        !          2063: 
        !          2064:     memcpy(attrs, attr->v.t, attr->l-2);
        !          2065:     attrs[attr->l-2] = 0;
        !          2066: 
        !          2067:     memset(&stt, 0, sizeof(stt));
        !          2068: 
        !          2069:     result = sscanf(attrs, "%d-%d-%dT%d:%d:%d %d:%d",
        !          2070:                    &stt.tm_year, &stt.tm_mon, &stt.tm_mday,
        !          2071:                    &stt.tm_hour, &stt.tm_min, &stt.tm_sec,
        !          2072:                    &tzhour, &tzmin);
        !          2073: 
        !          2074:     if (result == 8) { /* Timezone */
        !          2075:       /* tzhour and tzmin is hours and minutes east of GMT */
        !          2076:       /* timezone is defined as seconds west of GMT. Excludes DST */
        !          2077:       stt.tm_year -= 1900;
        !          2078:       stt.tm_mon  -= 1;
        !          2079:       stt.tm_hour -= tzhour; /* Adjust for timezone */
        !          2080:       stt.tm_min  -= tzmin;  /* Adjust for timezone */
        !          2081:       /*      stt.tm_hour += daylight;*/
        !          2082:       /*stt.tm_min  -= (timezone / 60);*/
        !          2083:       tz = getenv("TZ");
        !          2084:       setenv("TZ", "", 1); /* Set environment to UTC */
        !          2085:       tzset();
        !          2086:       params->sessionterminatetime = mktime(&stt);
        !          2087:       if (tz) 
        !          2088:        setenv("TZ", tz, 1); 
        !          2089:       else
        !          2090:        unsetenv("TZ");
        !          2091:       tzset();
        !          2092:     }
        !          2093:     else if (result >= 6) { /* Local time */
        !          2094:       tzset();
        !          2095:       stt.tm_year -= 1900;
        !          2096:       stt.tm_mon  -= 1;
        !          2097:       stt.tm_isdst = -1; /*daylight;*/
        !          2098:       params->sessionterminatetime = mktime(&stt);
        !          2099:     }
        !          2100:     else {
        !          2101:       params->sessionterminatetime = 0;
        !          2102:       log(LOG_WARNING, "Illegal WISPr-Session-Terminate-Time received: %s", attrs);
        !          2103:     }
        !          2104:   }
        !          2105:   else if (!reconfig)
        !          2106:     params->sessionterminatetime = 0;
        !          2107: }
        !          2108: 
        !          2109: static int chilliauth_cb(struct radius_t *radius,
        !          2110:                         struct radius_packet_t *pack,
        !          2111:                         struct radius_packet_t *pack_req, void *cbp) {
        !          2112:   struct radius_attr_t *attr = NULL;
        !          2113:   size_t offset = 0;
        !          2114: 
        !          2115:   if (!pack) { 
        !          2116:     log_err(0, "Radius request timed out");
        !          2117:     return 0;
        !          2118:   }
        !          2119: 
        !          2120:   if ((pack->code != RADIUS_CODE_ACCESS_REJECT) && 
        !          2121:       (pack->code != RADIUS_CODE_ACCESS_CHALLENGE) &&
        !          2122:       (pack->code != RADIUS_CODE_ACCESS_ACCEPT)) {
        !          2123:     log_err(0, "Unknown radius access reply code %d", pack->code);
        !          2124:     return 0;
        !          2125:   }
        !          2126: 
        !          2127:   /* ACCESS-ACCEPT */
        !          2128:   if (pack->code != RADIUS_CODE_ACCESS_ACCEPT) {
        !          2129:     log_err(0, "Administrative-User Login Failed");
        !          2130:     return 0;
        !          2131:   }
        !          2132: 
        !          2133:   while (!radius_getnextattr(pack, &attr, 
        !          2134:                             RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2135:                             RADIUS_VENDOR_CHILLISPOT,
        !          2136:                             RADIUS_ATTR_CHILLISPOT_CONFIG, 
        !          2137:                             0, &offset)) {
        !          2138:     char value[RADIUS_ATTR_VLEN+1] = "";
        !          2139:     strncpy(value, (const char *)attr->v.t, attr->l - 2);
        !          2140: 
        !          2141:     /* build the command line argv here and pass to config parser! */
        !          2142:     /* XXX */
        !          2143:     printf("%s\n", value);
        !          2144:   }
        !          2145: 
        !          2146:   if (!admin_session.s_state.authenticated) {
        !          2147:     admin_session.s_state.authenticated = 1;
        !          2148:     acct_req(&admin_session, RADIUS_STATUS_TYPE_START);
        !          2149:   }
        !          2150: 
        !          2151:   return 0;
        !          2152: }
        !          2153: 
        !          2154: int cb_radius_acct_conf(struct radius_t *radius, 
        !          2155:                        struct radius_packet_t *pack,
        !          2156:                        struct radius_packet_t *pack_req, void *cbp) {
        !          2157:   struct app_conn_t *appconn = (struct app_conn_t*) cbp;
        !          2158:   if (!appconn) {
        !          2159:     log_err(0,"No peer protocol defined");
        !          2160:     return 0;
        !          2161:   }
        !          2162:   config_radius_session(&appconn->s_params, pack, 1); /*XXX*/
        !          2163:   return 0;
        !          2164: }
        !          2165: 
        !          2166: /*********************************************************
        !          2167:  *
        !          2168:  * radius callback functions (response from radius server)
        !          2169:  *
        !          2170:  *********************************************************/
        !          2171: 
        !          2172: /* Radius callback when access accept/reject/challenge has been received */
        !          2173: int cb_radius_auth_conf(struct radius_t *radius, 
        !          2174:                        struct radius_packet_t *pack,
        !          2175:                        struct radius_packet_t *pack_req, void *cbp) {
        !          2176:   struct radius_attr_t *hisipattr = NULL;
        !          2177:   struct radius_attr_t *lmntattr = NULL;
        !          2178:   struct radius_attr_t *sendattr = NULL;
        !          2179:   struct radius_attr_t *recvattr = NULL;
        !          2180:   struct radius_attr_t *succattr = NULL;
        !          2181:   struct radius_attr_t *policyattr = NULL;
        !          2182:   struct radius_attr_t *typesattr = NULL;
        !          2183: 
        !          2184:   struct radius_attr_t *eapattr = NULL;
        !          2185:   struct radius_attr_t *stateattr = NULL;
        !          2186:   struct radius_attr_t *classattr = NULL;
        !          2187: 
        !          2188:   int instance = 0;
        !          2189:   struct in_addr *hisip = NULL;
        !          2190:   int statip = 0;
        !          2191: 
        !          2192:   struct app_conn_t *appconn = (struct app_conn_t*) cbp;
        !          2193: 
        !          2194:   if (options.debug)
        !          2195:     log_dbg("Received access request confirmation from radius server\n");
        !          2196:   
        !          2197:   if (!appconn) {
        !          2198:     log_err(0,"No peer protocol defined");
        !          2199:     return 0;
        !          2200:   }
        !          2201: 
        !          2202:   /* Initialise */
        !          2203:   appconn->s_state.redir.statelen = 0;
        !          2204:   appconn->challen  = 0;
        !          2205:   appconn->sendlen  = 0;
        !          2206:   appconn->recvlen  = 0;
        !          2207:   appconn->lmntlen  = 0;
        !          2208:   
        !          2209: 
        !          2210:   if (!pack) { /* Timeout */
        !          2211:     log_err(0, "Radius request timed out");
        !          2212:     return dnprot_reject(appconn);
        !          2213:   }
        !          2214: 
        !          2215:   /* ACCESS-REJECT */
        !          2216:   if (pack->code == RADIUS_CODE_ACCESS_REJECT) {
        !          2217:     if (options.debug)
        !          2218:       log_dbg("Received access reject from radius server");
        !          2219:     config_radius_session(&appconn->s_params, pack, 0); /*XXX*/
        !          2220:     return dnprot_reject(appconn);
        !          2221:   }
        !          2222: 
        !          2223:   /* Get State */
        !          2224:   if (!radius_getattr(pack, &stateattr, RADIUS_ATTR_STATE, 0, 0, 0)) {
        !          2225:     appconn->s_state.redir.statelen = stateattr->l-2;
        !          2226:     memcpy(appconn->s_state.redir.statebuf, stateattr->v.t, stateattr->l-2);
        !          2227:   }
        !          2228: 
        !          2229:   /* ACCESS-CHALLENGE */
        !          2230:   if (pack->code == RADIUS_CODE_ACCESS_CHALLENGE) {
        !          2231:     if (options.debug)
        !          2232:       log_dbg("Received access challenge from radius server");
        !          2233: 
        !          2234:     /* Get EAP message */
        !          2235:     appconn->challen = 0;
        !          2236:     do {
        !          2237:       eapattr=NULL;
        !          2238:       if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0, instance++)) {
        !          2239:        if ((appconn->challen + eapattr->l-2) > EAP_LEN) {
        !          2240:          log(LOG_INFO, "EAP message too long");
        !          2241:          return dnprot_reject(appconn);
        !          2242:        }
        !          2243:        memcpy(appconn->chal+appconn->challen, eapattr->v.t, eapattr->l-2);
        !          2244:        appconn->challen += eapattr->l-2;
        !          2245:       }
        !          2246:     } while (eapattr);
        !          2247:     
        !          2248:     if (!appconn->challen) {
        !          2249:       log(LOG_INFO, "No EAP message found");
        !          2250:       return dnprot_reject(appconn);
        !          2251:     }
        !          2252:     
        !          2253:     return dnprot_challenge(appconn);
        !          2254:   }
        !          2255:   
        !          2256:   /* ACCESS-ACCEPT */
        !          2257:   if (pack->code != RADIUS_CODE_ACCESS_ACCEPT) {
        !          2258:     log_err(0, "Unknown code of radius access request confirmation");
        !          2259:     return dnprot_reject(appconn);
        !          2260:   }
        !          2261: 
        !          2262:   /* Class */
        !          2263:   if (!radius_getattr(pack, &classattr, RADIUS_ATTR_CLASS, 0, 0, 0)) {
        !          2264:     appconn->s_state.redir.classlen = classattr->l-2;
        !          2265:     memcpy(appconn->s_state.redir.classbuf, classattr->v.t, classattr->l-2);
        !          2266:     /*log_dbg("!!!! CLASSLEN = %d !!!!", appconn->s_state.redir.classlen);*/
        !          2267:   }
        !          2268:   else {
        !          2269:     /*log_dbg("!!!! RESET CLASSLEN !!!!");*/
        !          2270:     appconn->s_state.redir.classlen = 0;
        !          2271:   }
        !          2272: 
        !          2273:   /* Framed IP address (Optional) */
        !          2274:   if (!radius_getattr(pack, &hisipattr, RADIUS_ATTR_FRAMED_IP_ADDRESS, 0, 0, 0)) {
        !          2275:     if ((hisipattr->l-2) != sizeof(struct in_addr)) {
        !          2276:       log_err(0, "Wrong length of framed IP address");
        !          2277:       return dnprot_reject(appconn);
        !          2278:     }
        !          2279:     hisip = (struct in_addr*) &(hisipattr->v.i);
        !          2280:     statip = 1;
        !          2281:   }
        !          2282:   else {
        !          2283:     hisip = (struct in_addr*) &appconn->reqip.s_addr;
        !          2284:   }
        !          2285: 
        !          2286:   config_radius_session(&appconn->s_params, pack, 0);
        !          2287: 
        !          2288:   if (options.dhcpradius) {
        !          2289:     struct dhcp_conn_t *dhcpconn = (struct dhcp_conn_t *)appconn->dnlink;
        !          2290:     struct radius_attr_t *attr = NULL;
        !          2291:     if (dhcpconn) {
        !          2292:       if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC, RADIUS_VENDOR_CHILLISPOT, 
        !          2293:                          RADIUS_ATTR_CHILLISPOT_DHCP_SERVER_NAME, 0)) {
        !          2294:        memcpy(dhcpconn->dhcp_opts.sname, attr->v.t, attr->l-2);
        !          2295:       }
        !          2296:       if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC, RADIUS_VENDOR_CHILLISPOT, 
        !          2297:                          RADIUS_ATTR_CHILLISPOT_DHCP_FILENAME, 0)) {
        !          2298:        memcpy(dhcpconn->dhcp_opts.file, attr->v.t, attr->l-2);
        !          2299:       }
        !          2300:       if (!radius_getattr(pack, &attr, RADIUS_ATTR_VENDOR_SPECIFIC, RADIUS_VENDOR_CHILLISPOT, 
        !          2301:                          RADIUS_ATTR_CHILLISPOT_DHCP_OPTION, 0)) {
        !          2302:        memcpy(dhcpconn->dhcp_opts.options, attr->v.t, 
        !          2303:               dhcpconn->dhcp_opts.option_length = attr->l-2);
        !          2304:       }
        !          2305:     }
        !          2306:   }
        !          2307: 
        !          2308:   if (appconn->s_params.sessionterminatetime) {
        !          2309:     time_t timenow = mainclock;
        !          2310:     if (timenow > appconn->s_params.sessionterminatetime) {
        !          2311:       log(LOG_WARNING, "WISPr-Session-Terminate-Time in the past received, rejecting");
        !          2312:       return dnprot_reject(appconn);
        !          2313:     }
        !          2314:   }
        !          2315: 
        !          2316: #ifdef LEAKY_BUCKET
        !          2317:   if (appconn->s_params.bandwidthmaxup) {
        !          2318: #ifdef BUCKET_SIZE
        !          2319:     appconn->s_state.bucketupsize = BUCKET_SIZE;
        !          2320: #else
        !          2321:     appconn->s_state.bucketupsize = appconn->s_params.bandwidthmaxup / 8000 * BUCKET_TIME;
        !          2322:     if (appconn->s_state.bucketupsize < BUCKET_SIZE_MIN) 
        !          2323:       appconn->s_state.bucketupsize = BUCKET_SIZE_MIN;
        !          2324: #endif
        !          2325:   }
        !          2326: #endif
        !          2327:   
        !          2328: #ifdef LEAKY_BUCKET
        !          2329:   if (appconn->s_params.bandwidthmaxdown) {
        !          2330: #ifdef BUCKET_SIZE
        !          2331:     appconn->s_state.bucketdownsize = BUCKET_SIZE;
        !          2332: #else
        !          2333:     appconn->s_state.bucketdownsize = appconn->s_params.bandwidthmaxdown / 8000 * BUCKET_TIME;
        !          2334:     if (appconn->s_state.bucketdownsize < BUCKET_SIZE_MIN) 
        !          2335:       appconn->s_state.bucketdownsize = BUCKET_SIZE_MIN;
        !          2336: #endif
        !          2337:   }
        !          2338: #endif
        !          2339: 
        !          2340:   /* EAP Message */
        !          2341:   appconn->challen = 0;
        !          2342:   do {
        !          2343:     eapattr=NULL;
        !          2344:     if (!radius_getattr(pack, &eapattr, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 
        !          2345:                        instance++)) {
        !          2346:       if ((appconn->challen + eapattr->l-2) > EAP_LEN) {
        !          2347:        log(LOG_INFO, "EAP message too long");
        !          2348:        return dnprot_reject(appconn);
        !          2349:       }
        !          2350:       memcpy(appconn->chal+appconn->challen,
        !          2351:             eapattr->v.t, eapattr->l-2);
        !          2352:       appconn->challen += eapattr->l-2;
        !          2353:     }
        !          2354:   } while (eapattr);
        !          2355: 
        !          2356:   /* Get sendkey */
        !          2357:   if (!radius_getattr(pack, &sendattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2358:                      RADIUS_VENDOR_MS,
        !          2359:                      RADIUS_ATTR_MS_MPPE_SEND_KEY, 0)) {
        !          2360:     if (radius_keydecode(radius, appconn->sendkey, RADIUS_ATTR_VLEN, &appconn->sendlen, 
        !          2361:                         (uint8_t *)&sendattr->v.t, sendattr->l-2, 
        !          2362:                         pack_req->authenticator,
        !          2363:                         radius->secret, radius->secretlen)) {
        !          2364:       log_err(0, "radius_keydecode() failed!");
        !          2365:       return dnprot_reject(appconn);
        !          2366:     }
        !          2367:   }
        !          2368:     
        !          2369:   /* Get recvkey */
        !          2370:   if (!radius_getattr(pack, &recvattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2371:                      RADIUS_VENDOR_MS,
        !          2372:                      RADIUS_ATTR_MS_MPPE_RECV_KEY, 0)) {
        !          2373:     if (radius_keydecode(radius, appconn->recvkey, RADIUS_ATTR_VLEN, &appconn->recvlen, 
        !          2374:                         (uint8_t *)&recvattr->v.t, recvattr->l-2, 
        !          2375:                         pack_req->authenticator,
        !          2376:                         radius->secret, radius->secretlen) ) {
        !          2377:       log_err(0, "radius_keydecode() failed!");
        !          2378:       return dnprot_reject(appconn);
        !          2379:     }
        !          2380:   }
        !          2381: 
        !          2382:   /* Get LMNT keys */
        !          2383:   if (!radius_getattr(pack, &lmntattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2384:                      RADIUS_VENDOR_MS,
        !          2385:                      RADIUS_ATTR_MS_CHAP_MPPE_KEYS, 0)) {
        !          2386: 
        !          2387:     /* TODO: Check length of vendor attributes */
        !          2388:     if (radius_pwdecode(radius, appconn->lmntkeys, RADIUS_MPPEKEYSSIZE,
        !          2389:                        &appconn->lmntlen, (uint8_t *)&lmntattr->v.t,
        !          2390:                        lmntattr->l-2, pack_req->authenticator,
        !          2391:                        radius->secret, radius->secretlen)) {
        !          2392:       log_err(0, "radius_pwdecode() failed");
        !          2393:       return dnprot_reject(appconn);
        !          2394:     }
        !          2395:   }
        !          2396:   
        !          2397:   /* Get encryption policy */
        !          2398:   if (!radius_getattr(pack, &policyattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2399:                      RADIUS_VENDOR_MS, 
        !          2400:                      RADIUS_ATTR_MS_MPPE_ENCRYPTION_POLICY, 0)) {
        !          2401:     appconn->policy = ntohl(policyattr->v.i);
        !          2402:   }
        !          2403:   
        !          2404:   /* Get encryption types */
        !          2405:   if (!radius_getattr(pack, &typesattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2406:                      RADIUS_VENDOR_MS, 
        !          2407:                      RADIUS_ATTR_MS_MPPE_ENCRYPTION_TYPES, 0)) {
        !          2408:     appconn->types = ntohl(typesattr->v.i);
        !          2409:   }
        !          2410:   
        !          2411: 
        !          2412:   /* Get MS_Chap_v2 SUCCESS */
        !          2413:   if (!radius_getattr(pack, &succattr, RADIUS_ATTR_VENDOR_SPECIFIC,
        !          2414:                      RADIUS_VENDOR_MS,
        !          2415:                      RADIUS_ATTR_MS_CHAP2_SUCCESS, 0)) {
        !          2416:     if ((succattr->l-5) != MS2SUCCSIZE) {
        !          2417:       log_err(0, "Wrong length of MS-CHAP2 success: %d", succattr->l-5);
        !          2418:       return dnprot_reject(appconn);
        !          2419:     }
        !          2420:     memcpy(appconn->ms2succ, ((void*)&succattr->v.t)+3, MS2SUCCSIZE);
        !          2421:   }
        !          2422: 
        !          2423:   /* for the admin session */
        !          2424:   if (appconn->is_adminsession) {
        !          2425:     return chilliauth_cb(radius, pack, pack_req, cbp);
        !          2426:   }
        !          2427: 
        !          2428:   switch(appconn->authtype) {
        !          2429: 
        !          2430:   case PAP_PASSWORD:
        !          2431:     appconn->policy = 0; /* TODO */
        !          2432:     break;
        !          2433: 
        !          2434:   case EAP_MESSAGE:
        !          2435:     if (!appconn->challen) {
        !          2436:       log(LOG_INFO, "No EAP message found");
        !          2437:       return dnprot_reject(appconn);
        !          2438:     }
        !          2439:     break;
        !          2440: 
        !          2441:   case CHAP_DIGEST_MD5:
        !          2442:     appconn->policy = 0; /* TODO */
        !          2443:     break;
        !          2444: 
        !          2445:   case CHAP_MICROSOFT:
        !          2446:     if (!lmntattr) {
        !          2447:       log(LOG_INFO, "No MPPE keys found");
        !          2448:       return dnprot_reject(appconn);
        !          2449:       }
        !          2450:     if (!succattr) {
        !          2451:       log_err(0, "No MS-CHAP2 success found");
        !          2452:       return dnprot_reject(appconn);
        !          2453:     }
        !          2454:     break;
        !          2455: 
        !          2456:   case CHAP_MICROSOFT_V2:
        !          2457:     if (!sendattr) {
        !          2458:       log(LOG_INFO, "No MPPE sendkey found");
        !          2459:       return dnprot_reject(appconn);
        !          2460:     }
        !          2461:     
        !          2462:     if (!recvattr) {
        !          2463:       log(LOG_INFO, "No MPPE recvkey found");
        !          2464:       return dnprot_reject(appconn);
        !          2465:     }
        !          2466:     
        !          2467:     break;
        !          2468: 
        !          2469:   default:
        !          2470:     log_err(0, "Unknown authtype");
        !          2471:     return dnprot_reject(appconn);
        !          2472:   }
        !          2473:   
        !          2474:   return upprot_getip(appconn, hisip, statip);
        !          2475: }
        !          2476: 
        !          2477: 
        !          2478: /* Radius callback when coa or disconnect request has been received */
        !          2479: int cb_radius_coa_ind(struct radius_t *radius, struct radius_packet_t *pack,
        !          2480:                      struct sockaddr_in *peer) {
        !          2481:   struct app_conn_t *appconn;
        !          2482:   struct radius_attr_t *uattr = NULL;
        !          2483:   struct radius_attr_t *sattr = NULL;
        !          2484:   struct radius_packet_t radius_pack;
        !          2485:   int found = 0;
        !          2486:   int iscoa = 0;
        !          2487: 
        !          2488:   if (options.debug)
        !          2489:     log_dbg("Received coa or disconnect request\n");
        !          2490:   
        !          2491:   if (pack->code != RADIUS_CODE_DISCONNECT_REQUEST &&
        !          2492:       pack->code != RADIUS_CODE_COA_REQUEST) {
        !          2493:     log_err(0, "Radius packet not supported: %d,\n", pack->code);
        !          2494:     return -1;
        !          2495:   }
        !          2496: 
        !          2497:   iscoa = pack->code == RADIUS_CODE_COA_REQUEST;
        !          2498: 
        !          2499:   /* Get username */
        !          2500:   if (radius_getattr(pack, &uattr, RADIUS_ATTR_USER_NAME, 0, 0, 0)) {
        !          2501:     log_warn(0, "Username must be included in disconnect request");
        !          2502:     return -1;
        !          2503:   }
        !          2504: 
        !          2505:   if (!radius_getattr(pack, &sattr, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0))
        !          2506:     if (options.debug) 
        !          2507:       log_dbg("Session-id present in disconnect. Only disconnecting that session\n");
        !          2508: 
        !          2509: 
        !          2510:   if (options.debug)
        !          2511:     log_dbg("Looking for session [username=%.*s,sessionid=%.*s]", 
        !          2512:            uattr->l-2, uattr->v.t, sattr ? sattr->l-2 : 3, sattr ? (char*)sattr->v.t : "all");
        !          2513:   
        !          2514:   for (appconn = firstusedconn; appconn; appconn = appconn->next) {
        !          2515:     if (!appconn->inuse) { log_err(0, "Connection with inuse == 0!"); }
        !          2516: 
        !          2517:     if ((appconn->s_state.authenticated) && 
        !          2518:        (strlen(appconn->s_state.redir.username) == uattr->l-2 && 
        !          2519:         !memcmp(appconn->s_state.redir.username, uattr->v.t, uattr->l-2)) &&
        !          2520:        (!sattr || 
        !          2521:         (strlen(appconn->s_state.sessionid) == sattr->l-2 && 
        !          2522:          !strncasecmp(appconn->s_state.sessionid, (char*)sattr->v.t, sattr->l-2)))) {
        !          2523: 
        !          2524:       if (options.debug)
        !          2525:        log_dbg("Found session\n");
        !          2526: 
        !          2527:       if (iscoa)
        !          2528:        config_radius_session(&appconn->s_params, pack, 0);
        !          2529:       else
        !          2530:        terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
        !          2531: 
        !          2532:       found = 1;
        !          2533:     }
        !          2534:   }
        !          2535: 
        !          2536:   if (found) {
        !          2537:     if (radius_default_pack(radius, &radius_pack, 
        !          2538:                            iscoa ? RADIUS_CODE_COA_ACK : RADIUS_CODE_DISCONNECT_ACK)) {
        !          2539:       log_err(0, "radius_default_pack() failed");
        !          2540:       return -1;
        !          2541:     }
        !          2542:   }
        !          2543:   else {
        !          2544:     if (radius_default_pack(radius, &radius_pack, 
        !          2545:                            iscoa ? RADIUS_CODE_COA_NAK : RADIUS_CODE_DISCONNECT_NAK)) {
        !          2546:       log_err(0, "radius_default_pack() failed");
        !          2547:       return -1;
        !          2548:     }
        !          2549:   }
        !          2550: 
        !          2551:   radius_pack.id = pack->id;
        !          2552:   (void) radius_coaresp(radius, &radius_pack, peer, pack->authenticator);
        !          2553: 
        !          2554:   return 0;
        !          2555: }
        !          2556: 
        !          2557: 
        !          2558: /***********************************************************
        !          2559:  *
        !          2560:  * dhcp callback functions
        !          2561:  *
        !          2562:  ***********************************************************/
        !          2563: 
        !          2564: /* DHCP callback for allocating new IP address */
        !          2565: /* In the case of WPA it is allready allocated,
        !          2566:  * for UAM address is allocated before authentication */
        !          2567: int cb_dhcp_request(struct dhcp_conn_t *conn, struct in_addr *addr, 
        !          2568:                    struct dhcp_fullpacket_t *dhcp_pkt, size_t dhcp_len) {
        !          2569:   struct app_conn_t *appconn = conn->peer;
        !          2570:   struct ippoolm_t *ipm;
        !          2571: 
        !          2572:   if (options.debug) 
        !          2573:     log_dbg("DHCP request for IP address");
        !          2574: 
        !          2575:   if (!appconn) {
        !          2576:     log_err(0, "Peer protocol not defined");
        !          2577:     return -1;
        !          2578:   }
        !          2579: 
        !          2580:   /* if uamanyip is on we have to filter out which ip's are allowed */
        !          2581:   if (options.uamanyip && addr && addr->s_addr) {
        !          2582:     if ((addr->s_addr & ipv4ll_mask.s_addr) == ipv4ll_ip.s_addr) {
        !          2583:       /* clients with an IPv4LL ip normally have no default gw assigned, rendering uamanyip useless
        !          2584:       They must rather get a proper dynamic ip via dhcp */
        !          2585:       log_dbg("IPv4LL/APIPA address requested, ignoring");
        !          2586:       return -1;
        !          2587:     }
        !          2588:   }
        !          2589: 
        !          2590:   appconn->reqip.s_addr = addr->s_addr; /* Save for MAC auth later */
        !          2591: 
        !          2592:   if (appconn->uplink) {
        !          2593: 
        !          2594:     /*
        !          2595:      *  IP Address is already known and allocated.
        !          2596:      */
        !          2597:     ipm = (struct ippoolm_t*) appconn->uplink;
        !          2598: 
        !          2599:   } else if ((options.macoklen) && 
        !          2600:             (appconn->dnprot == DNPROT_DHCP_NONE) &&
        !          2601:             !maccmp(conn->hismac)) {
        !          2602:     
        !          2603:     /*
        !          2604:      *  When using macallowed option, and hismac matches.
        !          2605:      */
        !          2606:     appconn->dnprot = DNPROT_MAC;
        !          2607: 
        !          2608:     if (options.macallowlocal) {
        !          2609: 
        !          2610:       /*
        !          2611:        *  Local MAC allowed list, authenticate without RADIUS.
        !          2612:        */
        !          2613:       upprot_getip(appconn, &appconn->reqip, 0);/**/
        !          2614:       dnprot_accept(appconn);
        !          2615:       log_info("Granted MAC=%.2X-%.2X-%.2X-%.2X-%.2X-%.2X with IP=%s access without radius auth" ,
        !          2616:                     conn->hismac[0], conn->hismac[1],
        !          2617:                     conn->hismac[2], conn->hismac[3],
        !          2618:                     conn->hismac[4], conn->hismac[5],
        !          2619:                     inet_ntoa(appconn->hisip));
        !          2620:     } else {
        !          2621: 
        !          2622:       /*
        !          2623:        *  Otherwise, authenticate with RADIUS.
        !          2624:        */
        !          2625:       macauth_radius(appconn, dhcp_pkt, dhcp_len);
        !          2626:     }
        !          2627: 
        !          2628:     return -1;
        !          2629: 
        !          2630:   } else if ((options.macauth) && 
        !          2631:             (appconn->dnprot == DNPROT_DHCP_NONE)) {
        !          2632:     
        !          2633:     /*
        !          2634:      *  Using macauth option to authenticate via RADIUS.
        !          2635:      */
        !          2636:     appconn->dnprot = DNPROT_MAC;
        !          2637: 
        !          2638:     macauth_radius(appconn, dhcp_pkt, dhcp_len);
        !          2639: 
        !          2640:     return -1;
        !          2641: 
        !          2642:   } else {
        !          2643: 
        !          2644:     if (appconn->dnprot != DNPROT_DHCP_NONE) {
        !          2645:       log_warn(0, "Requested IP address when already allocated");
        !          2646:     }
        !          2647:     
        !          2648:     /* Allocate dynamic IP address */
        !          2649:     /*XXX    if (ippool_newip(ippool, &ipm, &appconn->reqip, 0)) {*/
        !          2650:     if (newip(&ipm, &appconn->reqip)) {
        !          2651:       log_err(0, "Failed allocate dynamic IP address");
        !          2652:       return -1;
        !          2653:     }
        !          2654: 
        !          2655:     appconn->hisip.s_addr = ipm->addr.s_addr;
        !          2656:     
        !          2657:     log(LOG_NOTICE, "Client MAC=%.2X-%.2X-%.2X-%.2X-%.2X-%.2X assigned IP %s" , 
        !          2658:        conn->hismac[0], conn->hismac[1], 
        !          2659:        conn->hismac[2], conn->hismac[3],
        !          2660:        conn->hismac[4], conn->hismac[5], 
        !          2661:        inet_ntoa(appconn->hisip));
        !          2662: 
        !          2663:     /* TODO: Too many "listen" and "our" addresses hanging around */
        !          2664:     appconn->ourip.s_addr = options.dhcplisten.s_addr;
        !          2665:     
        !          2666:     appconn->uplink =  ipm;
        !          2667:     ipm->peer   = appconn; 
        !          2668:   }
        !          2669:   
        !          2670:   dhcp_set_addrs(conn, 
        !          2671:                 &ipm->addr, &options.mask, 
        !          2672:                 &appconn->ourip, &appconn->mask,
        !          2673:                 &options.dns1, &options.dns2, 
        !          2674:                 options.domain);
        !          2675: 
        !          2676:   /* if not already authenticated, ensure DNAT authstate */
        !          2677:   if (!appconn->s_state.authenticated)
        !          2678:     conn->authstate = DHCP_AUTH_DNAT;
        !          2679: 
        !          2680:   /* If IP was requested before authentication it was UAM */
        !          2681:   if (appconn->dnprot == DNPROT_DHCP_NONE)
        !          2682:     appconn->dnprot = DNPROT_UAM;
        !          2683: 
        !          2684:   return 0;
        !          2685: }
        !          2686: 
        !          2687: /* DHCP callback for establishing new connection */
        !          2688: int cb_dhcp_connect(struct dhcp_conn_t *conn) {
        !          2689:   struct app_conn_t *appconn;
        !          2690: 
        !          2691:   log(LOG_NOTICE, "New DHCP request from MAC=%.2X-%.2X-%.2X-%.2X-%.2X-%.2X" , 
        !          2692:       conn->hismac[0], conn->hismac[1], 
        !          2693:       conn->hismac[2], conn->hismac[3],
        !          2694:       conn->hismac[4], conn->hismac[5]);
        !          2695:   
        !          2696:   if (options.debug) 
        !          2697:     log_dbg("New DHCP connection established");
        !          2698: 
        !          2699:   /* Allocate new application connection */
        !          2700:   if (newconn(&appconn)) {
        !          2701:     log_err(0, "Failed to allocate connection");
        !          2702:     return 0;
        !          2703:   }
        !          2704: 
        !          2705:   appconn->dnlink =  conn;
        !          2706:   appconn->dnprot =  DNPROT_DHCP_NONE;
        !          2707:   conn->peer = appconn;
        !          2708: 
        !          2709:   appconn->net.s_addr = options.net.s_addr;
        !          2710:   appconn->mask.s_addr = options.mask.s_addr;
        !          2711:   appconn->dns1.s_addr = options.dns1.s_addr;
        !          2712:   appconn->dns2.s_addr = options.dns2.s_addr;
        !          2713: 
        !          2714:   memcpy(appconn->hismac, conn->hismac, PKT_ETH_ALEN);
        !          2715:   memcpy(appconn->ourmac, conn->ourmac, PKT_ETH_ALEN);
        !          2716:   
        !          2717:   set_sessionid(appconn);
        !          2718: 
        !          2719:   conn->authstate = DHCP_AUTH_NONE; /* TODO: Not yet authenticated */
        !          2720: 
        !          2721:   return 0;
        !          2722: }
        !          2723: 
        !          2724: int cb_dhcp_getinfo(struct dhcp_conn_t *conn, bstring b, int fmt) {
        !          2725:   time_t timenow = mainclock;
        !          2726:   struct app_conn_t *appconn;
        !          2727:   uint32_t sessiontime = 0;
        !          2728:   uint32_t idletime = 0;
        !          2729: 
        !          2730:   if (!conn->peer) return 2;
        !          2731:   appconn = (struct app_conn_t*) conn->peer;
        !          2732:   if (!appconn->inuse) return 2;
        !          2733: 
        !          2734:   if (appconn->s_state.authenticated) {
        !          2735:     sessiontime = timenow - appconn->s_state.start_time;
        !          2736:     idletime    = timenow - appconn->s_state.last_time;
        !          2737:   }
        !          2738: 
        !          2739:   switch(fmt) {
        !          2740:   case LIST_JSON_FMT:
        !          2741:     if (appconn->s_state.authenticated)
        !          2742:       session_json_fmt(&appconn->s_state, &appconn->s_params, b, 0);
        !          2743:     break;
        !          2744:   default:
        !          2745:     {
        !          2746:       bstring tmp = bfromcstr("");
        !          2747:       bassignformat(tmp, " %.*s %d %.*s %d/%d %d/%d %.*s", 
        !          2748:                    appconn->s_state.sessionid[0] ? strlen(appconn->s_state.sessionid) : 1,
        !          2749:                    appconn->s_state.sessionid[0] ? appconn->s_state.sessionid : "-",
        !          2750:                    appconn->s_state.authenticated,
        !          2751:                    appconn->s_state.redir.username[0] ? strlen(appconn->s_state.redir.username) : 1,
        !          2752:                    appconn->s_state.redir.username[0] ? appconn->s_state.redir.username : "-",
        !          2753:                    sessiontime, (int)appconn->s_params.sessiontimeout,
        !          2754:                    idletime, (int)appconn->s_params.idletimeout,
        !          2755:                    appconn->s_state.redir.userurl[0] ? strlen(appconn->s_state.redir.userurl) : 1,
        !          2756:                    appconn->s_state.redir.userurl[0] ? appconn->s_state.redir.userurl : "-");
        !          2757:       bconcat(b, tmp);
        !          2758:       bdestroy(tmp);
        !          2759:     }
        !          2760:   }
        !          2761:   return 0;
        !          2762: }
        !          2763: 
        !          2764: int terminate_appconn(struct app_conn_t *appconn, int terminate_cause) {
        !          2765:   if (appconn->s_state.authenticated == 1) { /* Only send accounting if logged in */
        !          2766:     dnprot_terminate(appconn);
        !          2767:     appconn->s_state.terminate_cause = terminate_cause;
        !          2768:     acct_req(appconn, RADIUS_STATUS_TYPE_STOP);
        !          2769: 
        !          2770:     /* should memory be cleared here?? */
        !          2771:     memset(&appconn->s_params, 0, sizeof(appconn->s_params));
        !          2772:     set_sessionid(appconn);
        !          2773:   }
        !          2774:   return 0;
        !          2775: }
        !          2776: 
        !          2777: /* Callback when a dhcp connection is deleted */
        !          2778: int cb_dhcp_disconnect(struct dhcp_conn_t *conn, int term_cause) {
        !          2779:   struct app_conn_t *appconn;
        !          2780: 
        !          2781:   log(LOG_INFO, "DHCP addr released by MAC=%.2X-%.2X-%.2X-%.2X-%.2X-%.2X IP=%s", 
        !          2782:       conn->hismac[0], conn->hismac[1], 
        !          2783:       conn->hismac[2], conn->hismac[3],
        !          2784:       conn->hismac[4], conn->hismac[5], 
        !          2785:       inet_ntoa(conn->hisip));
        !          2786:   
        !          2787:   if (options.debug) log_dbg("DHCP connection removed");
        !          2788: 
        !          2789:   if (!conn->peer) return 0; /* No appconn allocated. Stop here */
        !          2790:   appconn = (struct app_conn_t*) conn->peer;
        !          2791: 
        !          2792:   if ((appconn->dnprot != DNPROT_DHCP_NONE) &&
        !          2793:       (appconn->dnprot != DNPROT_UAM) &&
        !          2794:       (appconn->dnprot != DNPROT_MAC) &&
        !          2795:       (appconn->dnprot != DNPROT_WPA) &&
        !          2796:       (appconn->dnprot != DNPROT_EAPOL))  {
        !          2797:     return 0; /* DNPROT_WPA and DNPROT_EAPOL are unaffected by dhcp release? */
        !          2798:   }
        !          2799: 
        !          2800:   terminate_appconn(appconn, 
        !          2801:                    term_cause ? term_cause : 
        !          2802:                    appconn->s_state.terminate_cause ? 
        !          2803:                    appconn->s_state.terminate_cause :
        !          2804:                    RADIUS_TERMINATE_CAUSE_LOST_CARRIER);
        !          2805: 
        !          2806:   /* ALPAPAD */
        !          2807:   if (appconn->uplink) {
        !          2808:     if (options.uamanyip) {
        !          2809:       struct ippoolm_t *member = (struct ippoolm_t *) appconn->uplink;
        !          2810:       if (member->inuse  == 2) {
        !          2811:        struct in_addr mask;
        !          2812:        mask.s_addr = 0xffffffff;
        !          2813:        log_dbg("Removing route: %s %d\n", inet_ntoa(member->addr),
        !          2814:                net_del_route(&member->addr, &appconn->ourip, &mask));
        !          2815:       }
        !          2816:     }
        !          2817:     if (ippool_freeip(ippool, (struct ippoolm_t *) appconn->uplink)) {
        !          2818:       log_err(0, "ippool_freeip() failed!");
        !          2819:     }
        !          2820:   }
        !          2821:   
        !          2822:   freeconn(appconn);
        !          2823: 
        !          2824:   return 0;
        !          2825: }
        !          2826: 
        !          2827: 
        !          2828: /* Callback for receiving messages from dhcp */
        !          2829: int cb_dhcp_data_ind(struct dhcp_conn_t *conn, void *pack, size_t len) {
        !          2830:   struct app_conn_t *appconn = conn->peer;
        !          2831:   /*struct dhcp_ethhdr_t *ethh = (struct dhcp_ethhdr_t *)pack;*/
        !          2832:   struct pkt_ipphdr_t *ipph = (struct pkt_ipphdr_t *)((char*)pack + PKT_ETH_HLEN);
        !          2833: 
        !          2834:   /*if (options.debug)
        !          2835:     log_dbg("cb_dhcp_data_ind. Packet received. DHCP authstate: %d\n", 
        !          2836:     conn->authstate);*/
        !          2837: 
        !          2838:   if (ipph->saddr != conn->hisip.s_addr) {
        !          2839:     if (options.debug) 
        !          2840:       log_dbg("Received packet with spoofed source!");
        !          2841:     return 0;
        !          2842:   }
        !          2843: 
        !          2844:   if (!appconn) {
        !          2845:     log_err(0, "No peer protocol defined");
        !          2846:     return -1;
        !          2847:   }
        !          2848: 
        !          2849:   switch (appconn->dnprot) {
        !          2850:   case DNPROT_NULL:
        !          2851:   case DNPROT_DHCP_NONE:
        !          2852:     return -1;
        !          2853: 
        !          2854:   case DNPROT_UAM:
        !          2855:   case DNPROT_WPA:
        !          2856:   case DNPROT_MAC:
        !          2857:   case DNPROT_EAPOL:
        !          2858:     break;
        !          2859: 
        !          2860:   default:
        !          2861:     log_err(0, "Unknown downlink protocol: %d", appconn->dnprot);
        !          2862:     break;
        !          2863:   }
        !          2864: 
        !          2865:   /* If the ip dst is uamlisten and pdst is uamport we won't call leaky_bucket,
        !          2866:   *  and we always send these packets through to the tun/tap interface (index 0) 
        !          2867:   */
        !          2868:   if (ipph->daddr  == options.uamlisten.s_addr && 
        !          2869:       (ipph->dport == htons(options.uamport) ||
        !          2870:        ipph->dport == htons(options.uamuiport)))
        !          2871:     return tun_encaps(tun, pack, len, 0);
        !          2872:   
        !          2873:   if (appconn->s_state.authenticated == 1) {
        !          2874: 
        !          2875: #ifndef LEAKY_BUCKET
        !          2876:     appconn->s_state.last_time = mainclock;
        !          2877: #endif
        !          2878: 
        !          2879: #ifdef LEAKY_BUCKET
        !          2880: #ifndef COUNT_UPLINK_DROP
        !          2881:     if (leaky_bucket(appconn, len, 0)) return 0;
        !          2882: #endif
        !          2883: #endif
        !          2884:     if (options.swapoctets) {
        !          2885:       appconn->s_state.input_packets++;
        !          2886:       appconn->s_state.input_octets +=len;
        !          2887:       if (admin_session.s_state.authenticated) {
        !          2888:        admin_session.s_state.input_packets++;
        !          2889:        admin_session.s_state.input_octets+=len;
        !          2890:       }
        !          2891:     } else {
        !          2892:       appconn->s_state.output_packets++;
        !          2893:       appconn->s_state.output_octets +=len;
        !          2894:       if (admin_session.s_state.authenticated) {
        !          2895:        admin_session.s_state.output_packets++;
        !          2896:        admin_session.s_state.output_octets+=len;
        !          2897:       }
        !          2898:     }
        !          2899: #ifdef LEAKY_BUCKET
        !          2900: #ifdef COUNT_UPLINK_DROP
        !          2901:     if (leaky_bucket(appconn, len, 0)) return 0;
        !          2902: #endif
        !          2903: #endif
        !          2904:   }
        !          2905: 
        !          2906:   return tun_encaps(tun, pack, len, appconn->s_params.routeidx);
        !          2907: }
        !          2908: 
        !          2909: /* Callback for receiving messages from eapol */
        !          2910: int cb_dhcp_eap_ind(struct dhcp_conn_t *conn, void *pack, size_t len) {
        !          2911:   struct eap_packet_t *eap = (struct eap_packet_t *)pack;
        !          2912:   struct app_conn_t *appconn = conn->peer;
        !          2913:   struct radius_packet_t radius_pack;
        !          2914:   char mac[MACSTRLEN+1];
        !          2915:   size_t offset;
        !          2916: 
        !          2917:   if (options.debug) log_dbg("EAP Packet received");
        !          2918: 
        !          2919:   /* If this is the first EAPOL authentication request */
        !          2920:   if ((appconn->dnprot == DNPROT_DHCP_NONE) || 
        !          2921:       (appconn->dnprot == DNPROT_EAPOL)) {
        !          2922:     if ((eap->code == 2) && /* Response */
        !          2923:        (eap->type == 1) && /* Identity */
        !          2924:        (len > 5) &&        /* Must be at least 5 octets */
        !          2925:        ((len - 5) <= USERNAMESIZE )) {
        !          2926:       memcpy(appconn->s_state.redir.username, eap->payload, len - 5); 
        !          2927:       appconn->dnprot = DNPROT_EAPOL;
        !          2928:       appconn->authtype = EAP_MESSAGE;
        !          2929:     }
        !          2930:     else if (appconn->dnprot == DNPROT_DHCP_NONE) {
        !          2931:       log_err(0, "Initial EAP response was not a valid identity response!");
        !          2932:       return 0;
        !          2933:     }
        !          2934:   }
        !          2935: 
        !          2936:   /* Return if not EAPOL */
        !          2937:   if (appconn->dnprot != DNPROT_EAPOL) {
        !          2938:     log_warn(0, "Received EAP message, processing for authentication");
        !          2939:     appconn->dnprot = DNPROT_EAPOL;
        !          2940:     return 0;
        !          2941:   }
        !          2942:   
        !          2943:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
        !          2944:     log_err(0, "radius_default_pack() failed");
        !          2945:     return -1;
        !          2946:   }
        !          2947: 
        !          2948:   /* Build up radius request */
        !          2949:   radius_pack.code = RADIUS_CODE_ACCESS_REQUEST;
        !          2950: 
        !          2951:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
        !          2952:                        (uint8_t*) appconn->s_state.redir.username, 
        !          2953:                        strlen(appconn->s_state.redir.username));
        !          2954: 
        !          2955:   if (appconn->s_state.redir.statelen) {
        !          2956:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_STATE, 0, 0, 0,
        !          2957:                   appconn->s_state.redir.statebuf,
        !          2958:                   appconn->s_state.redir.statelen);
        !          2959:   }
        !          2960:   
        !          2961:   /* Include EAP (if present) */
        !          2962:   offset = 0;
        !          2963:   while (offset < len) {
        !          2964:     size_t eaplen;
        !          2965: 
        !          2966:     if ((len - offset) > RADIUS_ATTR_VLEN)
        !          2967:       eaplen = RADIUS_ATTR_VLEN;
        !          2968:     else
        !          2969:       eaplen = len - offset;
        !          2970: 
        !          2971:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_EAP_MESSAGE, 0, 0, 0,
        !          2972:                   pack + offset, eaplen);
        !          2973: 
        !          2974:     offset += eaplen;
        !          2975:   } 
        !          2976:   
        !          2977:   if (len)
        !          2978:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
        !          2979:                   0, 0, 0, NULL, RADIUS_MD5LEN);
        !          2980:   
        !          2981:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
        !          2982:                 options.radiusnasporttype, NULL, 0);
        !          2983:   
        !          2984:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT, 0, 0,
        !          2985:                 appconn->unit, NULL, 0);
        !          2986:   
        !          2987:   radius_addnasip(radius, &radius_pack);
        !          2988: 
        !          2989:   snprintf(mac, MACSTRLEN+1, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",
        !          2990:           appconn->hismac[0], appconn->hismac[1],
        !          2991:           appconn->hismac[2], appconn->hismac[3],
        !          2992:           appconn->hismac[4], appconn->hismac[5]);
        !          2993:   
        !          2994:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_CALLING_STATION_ID, 0, 0, 0,
        !          2995:                 (uint8_t*) mac, MACSTRLEN);
        !          2996:   
        !          2997:   radius_addcalledstation(radius, &radius_pack);
        !          2998:   
        !          2999:   /* Include NAS-Identifier if given in configuration options */
        !          3000:   if (options.radiusnasid)
        !          3001:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
        !          3002:                   (uint8_t*) options.radiusnasid,
        !          3003:                   strlen(options.radiusnasid));
        !          3004:   
        !          3005:   return radius_req(radius, &radius_pack, appconn);
        !          3006: }
        !          3007: 
        !          3008: 
        !          3009: /***********************************************************
        !          3010:  *
        !          3011:  * uam message handling functions
        !          3012:  *
        !          3013:  ***********************************************************/
        !          3014: 
        !          3015: int static uam_msg(struct redir_msg_t *msg) {
        !          3016: 
        !          3017:   struct ippoolm_t *ipm;
        !          3018:   struct app_conn_t *appconn = NULL;
        !          3019:   struct dhcp_conn_t* dhcpconn;
        !          3020: 
        !          3021:   if (ippool_getip(ippool, &ipm, &msg->mdata.addr)) {
        !          3022:     if (options.debug) 
        !          3023:       log_dbg("UAM login with unknown IP address: %s", inet_ntoa(msg->mdata.addr));
        !          3024:     return 0;
        !          3025:   }
        !          3026: 
        !          3027:   if ((appconn  = (struct app_conn_t *)ipm->peer)        == NULL || 
        !          3028:       (dhcpconn = (struct dhcp_conn_t *)appconn->dnlink) == NULL) {
        !          3029:     log_err(0, "No peer protocol defined");
        !          3030:     return 0;
        !          3031:   }
        !          3032: 
        !          3033:   if (msg->mdata.opt & REDIR_MSG_OPT_REDIR)
        !          3034:     memcpy(&appconn->s_state.redir, &msg->mdata.redir, sizeof(msg->mdata.redir));
        !          3035: 
        !          3036:   if (msg->mdata.opt & REDIR_MSG_OPT_PARAMS)
        !          3037:     memcpy(&appconn->s_params, &msg->mdata.params, sizeof(msg->mdata.params));
        !          3038: 
        !          3039:   switch(msg->mtype) {
        !          3040: 
        !          3041:   case REDIR_LOGIN:
        !          3042:     if (appconn->uamabort) {
        !          3043:       log_info("UAM login from username=%s IP=%s was aborted!", 
        !          3044:               msg->mdata.redir.username, inet_ntoa(appconn->hisip));
        !          3045:       appconn->uamabort = 0;
        !          3046:       return 0;
        !          3047:     }
        !          3048: 
        !          3049:     log_info("Successful UAM login from username=%s IP=%s", 
        !          3050:             msg->mdata.redir.username, inet_ntoa(appconn->hisip));
        !          3051:     
        !          3052:     /* Initialise */
        !          3053:     appconn->s_params.routeidx = tun->routeidx;
        !          3054:     appconn->s_state.redir.statelen = 0;
        !          3055:     appconn->challen  = 0;
        !          3056:     appconn->sendlen  = 0;
        !          3057:     appconn->recvlen  = 0;
        !          3058:     appconn->lmntlen  = 0;
        !          3059:     
        !          3060:     memcpy(appconn->hismac, dhcpconn->hismac, PKT_ETH_ALEN);
        !          3061:     memcpy(appconn->ourmac, dhcpconn->ourmac, PKT_ETH_ALEN);
        !          3062:     
        !          3063:     appconn->policy = 0; /* TODO */
        !          3064: 
        !          3065: #ifdef LEAKY_BUCKET
        !          3066: #ifdef BUCKET_SIZE
        !          3067:     appconn->s_state.bucketupsize = BUCKET_SIZE;
        !          3068: #else
        !          3069:     appconn->s_state.bucketupsize = appconn->s_params.bandwidthmaxup / 8000 * BUCKET_TIME;
        !          3070:     if (appconn->s_state.bucketupsize < BUCKET_SIZE_MIN) 
        !          3071:       appconn->s_state.bucketupsize = BUCKET_SIZE_MIN;
        !          3072: #endif
        !          3073: #endif
        !          3074: 
        !          3075: #ifdef LEAKY_BUCKET
        !          3076: #ifdef BUCKET_SIZE
        !          3077:     appconn->s_state.bucketdownsize = BUCKET_SIZE;
        !          3078: #else
        !          3079:     appconn->s_state.bucketdownsize = appconn->s_params.bandwidthmaxdown / 8000 * BUCKET_TIME;
        !          3080:     if (appconn->s_state.bucketdownsize < BUCKET_SIZE_MIN) 
        !          3081:       appconn->s_state.bucketdownsize = BUCKET_SIZE_MIN;
        !          3082: #endif
        !          3083: #endif
        !          3084: 
        !          3085:     return upprot_getip(appconn, NULL, 0);
        !          3086: 
        !          3087:   case REDIR_LOGOUT:
        !          3088: 
        !          3089:     log_info("Received UAM logoff from username=%s IP=%s",
        !          3090:             appconn->s_state.redir.username, inet_ntoa(appconn->hisip));
        !          3091: 
        !          3092:     if (options.debug)
        !          3093:       log_dbg("Received logoff from UAM\n");
        !          3094: 
        !          3095:     if (appconn->s_state.authenticated == 1) {
        !          3096:       terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
        !          3097:       appconn->s_state.uamtime = 0;
        !          3098:       appconn->s_params.sessiontimeout = 0;
        !          3099:       appconn->s_params.idletimeout = 0;
        !          3100:     }
        !          3101: 
        !          3102:     appconn->s_state.uamtime = mainclock;
        !          3103:     dhcpconn->authstate = DHCP_AUTH_DNAT;
        !          3104:     appconn->uamabort = 0;
        !          3105: 
        !          3106:     break;
        !          3107: 
        !          3108:   case REDIR_ABORT:
        !          3109:     
        !          3110:     log_info("Received UAM abort from IP=%s", inet_ntoa(appconn->hisip));
        !          3111: 
        !          3112:     appconn->uamabort = 1; /* Next login will be aborted */
        !          3113:     appconn->s_state.uamtime = 0;  /* Force generation of new challenge */
        !          3114:     dhcpconn->authstate = DHCP_AUTH_DNAT;
        !          3115: 
        !          3116:     terminate_appconn(appconn, RADIUS_TERMINATE_CAUSE_USER_REQUEST);
        !          3117: 
        !          3118:     break;
        !          3119: 
        !          3120:   case REDIR_CHALLENGE:
        !          3121:     appconn->s_state.uamtime = mainclock;
        !          3122:     appconn->uamabort = 0;
        !          3123:     break;
        !          3124: 
        !          3125:   case REDIR_NOTYET:
        !          3126:     break;
        !          3127:   }
        !          3128: 
        !          3129:   return 0;
        !          3130: }
        !          3131: 
        !          3132: static int cmdsock_accept(int sock) {
        !          3133:   struct sockaddr_un remote; 
        !          3134:   struct cmdsock_request req;
        !          3135: 
        !          3136:   bstring s = 0;
        !          3137:   size_t len;
        !          3138:   int csock;
        !          3139:   int rval = 0;
        !          3140: 
        !          3141:   if (options.debug) 
        !          3142:     log_dbg("Processing cmdsock request...\n");
        !          3143: 
        !          3144:   len = sizeof(remote);
        !          3145:   if ((csock = accept(sock, (struct sockaddr *)&remote, &len)) == -1) {
        !          3146:     perror("cmdsock_accept()/accept()");
        !          3147:     return -1;
        !          3148:   }
        !          3149: 
        !          3150:   if (read(csock, &req, sizeof(req)) != sizeof(req)) {
        !          3151:     perror("cmdsock_accept()/read()");
        !          3152:     close(csock);
        !          3153:     return -1;
        !          3154:   }
        !          3155: 
        !          3156:   switch(req.type) {
        !          3157: 
        !          3158:   case CMDSOCK_DHCP_LIST:
        !          3159:     s = bfromcstr("");
        !          3160:     if (dhcp) dhcp_list(dhcp, s, 0, 0,
        !          3161:                        req.options & CMDSOCK_OPT_JSON ? 
        !          3162:                        LIST_JSON_FMT : LIST_SHORT_FMT);
        !          3163:     write(csock, s->data, s->slen);
        !          3164:     break;
        !          3165:     
        !          3166:   case CMDSOCK_DHCP_DROP:
        !          3167:   case CMDSOCK_DHCP_RELEASE:
        !          3168:     if (dhcp) dhcp_release_mac(dhcp, req.data.mac, RADIUS_TERMINATE_CAUSE_ADMIN_RESET);
        !          3169:     break;
        !          3170: 
        !          3171:   case CMDSOCK_LIST:
        !          3172:     s = bfromcstr("");
        !          3173:     if (dhcp) dhcp_list(dhcp, s, 0, 0,
        !          3174:                        req.options & CMDSOCK_OPT_JSON ? 
        !          3175:                        LIST_JSON_FMT : LIST_LONG_FMT);
        !          3176:     write(csock, s->data, s->slen);
        !          3177:     break;
        !          3178: 
        !          3179:   case CMDSOCK_SHOW:
        !          3180:     /*ToDo*/
        !          3181:     break;
        !          3182: 
        !          3183:   case CMDSOCK_ROUTE_SET:
        !          3184:     {
        !          3185:       struct dhcp_conn_t *conn = dhcp->firstusedconn;
        !          3186:       log_dbg("looking to authorized session %s",inet_ntoa(req.data.sess.ip));
        !          3187:       while (conn && conn->inuse) {
        !          3188:        if (conn->peer) {
        !          3189:          struct app_conn_t * appconn = (struct app_conn_t*)conn->peer;
        !          3190:          if (!memcmp(appconn->hismac, req.data.mac, 6)) {
        !          3191:            log_dbg("routeidx %s %d",appconn->s_state.sessionid, req.data.sess.params.routeidx);
        !          3192:            appconn->s_params.routeidx = req.data.sess.params.routeidx;
        !          3193:            break;
        !          3194:          }
        !          3195:        }
        !          3196:        conn = conn->next;
        !          3197:       }
        !          3198:     }
        !          3199:     /* drop through */
        !          3200:   case CMDSOCK_ROUTE:
        !          3201:     {
        !          3202:       int i;
        !          3203:       bstring b = bfromcstr("routes:\n");
        !          3204:       write(csock, b->data, b->slen);
        !          3205:       for (i=0; i<tun->_interface_count; i++) {
        !          3206:        bassignformat(b, "idx: %d dev: %s%s\n", 
        !          3207:                      i, tun->_interfaces[i].devname,
        !          3208:                      i == 0 ? " (tun/tap)":"");
        !          3209:        write(csock, b->data, b->slen);
        !          3210:       }
        !          3211: 
        !          3212:       { 
        !          3213:        struct dhcp_conn_t *conn = dhcp->firstusedconn;
        !          3214:        bassignformat(b, "subscribers:\n");
        !          3215:        write(csock, b->data, b->slen);
        !          3216:        while (conn) {
        !          3217:          struct app_conn_t *appconn = (struct app_conn_t *)conn->peer;
        !          3218:          bassignformat(b, "mac: %.2X-%.2X-%.2X-%.2X-%.2X-%.2X -> idx: %d\n", 
        !          3219:                        appconn->hismac[0], appconn->hismac[1],
        !          3220:                        appconn->hismac[2], appconn->hismac[3],
        !          3221:                        appconn->hismac[4], appconn->hismac[5],
        !          3222:                        appconn->s_params.routeidx);
        !          3223:          write(csock, b->data, b->slen);
        !          3224:          conn = conn->next;
        !          3225:        }
        !          3226:       }
        !          3227:       bdestroy(b);
        !          3228:     }
        !          3229:     break;
        !          3230: 
        !          3231:   case CMDSOCK_AUTHORIZE:
        !          3232:     if (dhcp) {
        !          3233:       struct dhcp_conn_t *dhcpconn = dhcp->firstusedconn;
        !          3234:       log_dbg("looking to authorized session %s",inet_ntoa(req.data.sess.ip));
        !          3235:       while (dhcpconn && dhcpconn->inuse) {
        !          3236:        if (dhcpconn->peer) {
        !          3237:          struct app_conn_t * appconn = (struct app_conn_t*) dhcpconn->peer;
        !          3238:          if (  (req.data.sess.ip.s_addr == 0    || appconn->hisip.s_addr == req.data.sess.ip.s_addr) &&
        !          3239:                (req.data.sess.sessionid[0] == 0 || !strcmp(appconn->s_state.sessionid,req.data.sess.sessionid))
        !          3240:                ){
        !          3241:            char *uname = req.data.sess.username;
        !          3242:            log_dbg("remotely authorized session %s",appconn->s_state.sessionid);
        !          3243:            memcpy(&appconn->s_params, &req.data.sess.params, sizeof(req.data.sess.params));
        !          3244:            if (uname[0]) strncpy(appconn->s_state.redir.username, uname, USERNAMESIZE);
        !          3245:            dnprot_accept(appconn);
        !          3246:            break;
        !          3247:          }
        !          3248:        }
        !          3249:        dhcpconn = dhcpconn->next;
        !          3250:       }
        !          3251:     }
        !          3252:     break;
        !          3253: 
        !          3254:   default:
        !          3255:     perror("unknown command");
        !          3256:     close(csock);
        !          3257:     rval = -1;
        !          3258:   }
        !          3259: 
        !          3260:   if (s) bdestroy(s);
        !          3261:   shutdown(csock, 2);
        !          3262:   close(csock);
        !          3263: 
        !          3264:   return rval;
        !          3265: }
        !          3266: 
        !          3267: /* Function that will create and write a status file in statedir*/
        !          3268: int printstatus(struct app_conn_t *appconn) {
        !          3269:   char *statedir = options.statedir ? options.statedir : DEFSTATEDIR;
        !          3270:   struct app_conn_t *apptemp;
        !          3271:   FILE *file;
        !          3272:   char filedest[512];
        !          3273:   time_t timenow = mainclock;
        !          3274:   struct stat statbuf;
        !          3275: 
        !          3276:   if (!options.usestatusfile) 
        !          3277:     return 0;
        !          3278: 
        !          3279:   if (strlen(statedir)>sizeof(filedest)-1) 
        !          3280:     return -1;
        !          3281: 
        !          3282:   if (stat(statedir, &statbuf)) { 
        !          3283:     log_err(errno, "statedir (%s) does not exist", statedir); 
        !          3284:     return -1; 
        !          3285:   }
        !          3286: 
        !          3287:   if (!S_ISDIR(statbuf.st_mode)) { 
        !          3288:     log_err(0, "statedir (%s) not a directory", statedir); 
        !          3289:     return -1; 
        !          3290:   }
        !          3291: 
        !          3292:   strcpy(filedest, statedir);
        !          3293:   strcat(filedest, "/chillispot.state");
        !          3294: 
        !          3295:   file = fopen(filedest, "w");
        !          3296:   if (!file) { log_err(errno, "could not open file %s", filedest); return -1; }
        !          3297:   fprintf(file, "#Version:1.1\n");
        !          3298:   fprintf(file, "#SessionID = SID\n#Start-Time = ST\n");
        !          3299:   fprintf(file, "#SessionTimeOut = STO\n#SessionTerminateTime = STT\n");
        !          3300:   fprintf(file, "#Timestamp: %d\n", timenow);
        !          3301:   fprintf(file, "#User, IP, MAC, SID, ST, STO, STT\n");
        !          3302:   if(appconn == NULL)
        !          3303:   {
        !          3304:     fclose(file);
        !          3305:     return 0;
        !          3306:   }
        !          3307:   apptemp = appconn;
        !          3308:   while(apptemp != NULL)
        !          3309:   {
        !          3310:     if(apptemp->s_state.authenticated==1)
        !          3311:     {
        !          3312:       fprintf(file, "%s, %s, %.2X-%.2X-%.2X-%.2X-%.2X-%.2X, %s, %d, %d, %d\n",
        !          3313:        apptemp->s_state.redir.username,
        !          3314:        inet_ntoa(apptemp->hisip),
        !          3315:        apptemp->hismac[0], apptemp->hismac[1],
        !          3316:        apptemp->hismac[2], apptemp->hismac[3],
        !          3317:        apptemp->hismac[4], apptemp->hismac[5],
        !          3318:        apptemp->s_state.sessionid,
        !          3319:        apptemp->s_state.start_time,
        !          3320:        apptemp->s_params.sessiontimeout,
        !          3321:        apptemp->s_params.sessionterminatetime);
        !          3322:     }
        !          3323:     apptemp = apptemp->prev;
        !          3324:   }
        !          3325:   apptemp = appconn->next;
        !          3326:   while(apptemp != NULL)
        !          3327:   {
        !          3328:     if(apptemp->s_state.authenticated==1)
        !          3329:     {
        !          3330:       fprintf(file, "%s, %s, %.2X-%.2X-%.2X-%.2X-%.2X-%.2X, %s, %d, %d, %d\n",
        !          3331:        apptemp->s_state.redir.username,
        !          3332:        inet_ntoa(apptemp->hisip),
        !          3333:        apptemp->hismac[0], apptemp->hismac[1],
        !          3334:        apptemp->hismac[2], apptemp->hismac[3],
        !          3335:        apptemp->hismac[4], apptemp->hismac[5],
        !          3336:        apptemp->s_state.sessionid,
        !          3337:         apptemp->s_state.start_time,
        !          3338:        apptemp->s_params.sessiontimeout,
        !          3339:        apptemp->s_params.sessionterminatetime);
        !          3340:     }
        !          3341:     apptemp = apptemp->next;
        !          3342:   }
        !          3343:   fclose(file);
        !          3344:   return 0;
        !          3345: }
        !          3346: 
        !          3347: static void fixup_options() {
        !          3348:   /*
        !          3349:    * If we have no nasmac configured, lets default it here, after creating the dhcp
        !          3350:    */
        !          3351:   if (!options.nasmac) {
        !          3352:     char mac[24];
        !          3353: 
        !          3354:     sprintf(mac, "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X", 
        !          3355:            dhcp->ipif.hwaddr[0],dhcp->ipif.hwaddr[1],dhcp->ipif.hwaddr[2],
        !          3356:            dhcp->ipif.hwaddr[3],dhcp->ipif.hwaddr[4],dhcp->ipif.hwaddr[5]);
        !          3357:     
        !          3358:     options.nasmac = strdup(mac);
        !          3359:   }
        !          3360: 
        !          3361: }
        !          3362: 
        !          3363: int chilli_main(int argc, char **argv) {
        !          3364:   
        !          3365:   int maxfd = 0;               /* For select() */
        !          3366:   fd_set fds;                  /* For select() */
        !          3367:   struct timeval idleTime;     /* How long to select() */
        !          3368:   int status;
        !          3369:   int msgresult;
        !          3370: 
        !          3371:   struct redir_msg_t msg;
        !          3372:   struct sigaction act;
        !          3373:   /*  struct itimerval itval; */
        !          3374:   int lastSecond = 0, thisSecond;
        !          3375: 
        !          3376:   int cmdsock = -1;
        !          3377: 
        !          3378:   /* open a connection to the syslog daemon */
        !          3379:   /*openlog(PACKAGE, LOG_PID, LOG_DAEMON);*/
        !          3380:   openlog(PACKAGE, (LOG_PID | LOG_PERROR), LOG_DAEMON);
        !          3381: 
        !          3382:   /* Process options given in configuration file and command line */
        !          3383:   if (process_options(argc, argv, 0))
        !          3384:     exit(1);
        !          3385: 
        !          3386:   /* foreground                                                   */
        !          3387:   /* If flag not given run as a daemon                            */
        !          3388:   if (!options.foreground) {
        !          3389:     /* Close the standard file descriptors. */
        !          3390:     /* Is this really needed ? */
        !          3391:     freopen("/dev/null", "w", stdout);
        !          3392:     freopen("/dev/null", "w", stderr);
        !          3393:     freopen("/dev/null", "r", stdin);
        !          3394:     if (daemon(1, 1)) {
        !          3395:       log_err(errno, "daemon() failed!");
        !          3396:     }
        !          3397:   } 
        !          3398: 
        !          3399:   if (options.logfacility<0||options.logfacility>LOG_NFACILITIES)
        !          3400:     options.logfacility=LOG_FAC(LOG_LOCAL6);
        !          3401: 
        !          3402:   closelog(); 
        !          3403:   openlog(PACKAGE, LOG_PID, (options.logfacility<<3));
        !          3404:   
        !          3405:   /* This has to be done after we have our final pid */
        !          3406:   log_pid((options.pidfile && *options.pidfile) ? options.pidfile : DEFPIDFILE);
        !          3407: 
        !          3408:   if (options.debug) 
        !          3409:     log_dbg("ChilliSpot version %s started.\n", VERSION);
        !          3410: 
        !          3411:   syslog(LOG_INFO, "CoovaChilli(ChilliSpot) %s. Copyright 2002-2005 Mondru AB. Licensed under GPL. "
        !          3412:         "Copyright 2006-2008 David Bird <dbird@acm.org>. Licensed under GPL. "
        !          3413:         "See http://coova.org/ for details.", VERSION);
        !          3414: 
        !          3415:   mainclock = time(0);
        !          3416: 
        !          3417:   printstatus(NULL);
        !          3418: 
        !          3419:   /* Create a tunnel interface */
        !          3420:   if (tun_new(&tun)) {
        !          3421:     log_err(0, "Failed to create tun");
        !          3422:     exit(1);
        !          3423:   }
        !          3424: 
        !          3425:   /*tun_setaddr(tun, &options.dhcplisten,  &options.net, &options.mask);*/
        !          3426:   tun_setaddr(tun, &options.dhcplisten,  &options.dhcplisten, &options.mask);
        !          3427:   tun_set_cb_ind(tun, cb_tun_ind);
        !          3428: 
        !          3429:   if (tun) tun_maxfd(tun, maxfd);
        !          3430:   if (options.ipup) tun_runscript(tun, options.ipup);
        !          3431: 
        !          3432:   
        !          3433:   /* Create an instance of dhcp */
        !          3434:   if (dhcp_new(&dhcp, APP_NUM_CONN, options.dhcpif,
        !          3435:               options.dhcpusemac, options.dhcpmac, options.dhcpusemac, 
        !          3436:               &options.dhcplisten, options.lease, 1, 
        !          3437:               &options.uamlisten, options.uamport, 
        !          3438:               options.eapolenable)) {
        !          3439:     log_err(0, "Failed to create dhcp");
        !          3440:     exit(1);
        !          3441:   }
        !          3442: 
        !          3443:   net_maxfd(&dhcp->ipif, maxfd);
        !          3444:   net_maxfd(&dhcp->arpif, maxfd);
        !          3445:   net_maxfd(&dhcp->eapif, maxfd);
        !          3446: 
        !          3447:   fd_max(dhcp->relayfd, maxfd);
        !          3448:   
        !          3449:   dhcp_set_cb_request(dhcp, cb_dhcp_request);
        !          3450:   dhcp_set_cb_connect(dhcp, cb_dhcp_connect);
        !          3451:   dhcp_set_cb_disconnect(dhcp, cb_dhcp_disconnect);
        !          3452:   dhcp_set_cb_data_ind(dhcp, cb_dhcp_data_ind);
        !          3453:   dhcp_set_cb_eap_ind(dhcp, cb_dhcp_eap_ind);
        !          3454:   dhcp_set_cb_getinfo(dhcp, cb_dhcp_getinfo);
        !          3455: 
        !          3456:   if (dhcp_set(dhcp, (options.debug & DEBUG_DHCP))) {
        !          3457:     log_err(0, "Failed to set DHCP parameters");
        !          3458:     exit(1);
        !          3459:   }
        !          3460: 
        !          3461:   fixup_options();
        !          3462: 
        !          3463:   /* Create an instance of radius */
        !          3464:   if (radius_new(&radius,
        !          3465:                 &options.radiuslisten, options.coaport, options.coanoipcheck,
        !          3466:                 &options.proxylisten, options.proxyport,
        !          3467:                 &options.proxyaddr, &options.proxymask,
        !          3468:                 options.proxysecret)) {
        !          3469:     log_err(0, "Failed to create radius");
        !          3470:     return -1;
        !          3471:   }
        !          3472: 
        !          3473:   if (radius->fd > maxfd)
        !          3474:     maxfd = radius->fd;
        !          3475:   
        !          3476:   if ((radius->proxyfd != -1) && (radius->proxyfd > maxfd))
        !          3477:     maxfd = radius->proxyfd;
        !          3478:   
        !          3479:   radius_set(radius, dhcp ? dhcp->ipif.hwaddr : 0, (options.debug & DEBUG_RADIUS));
        !          3480:   radius_set_cb_auth_conf(radius, cb_radius_auth_conf);
        !          3481:   radius_set_cb_coa_ind(radius, cb_radius_coa_ind);
        !          3482:   radius_set_cb_ind(radius, cb_radius_ind);
        !          3483: 
        !          3484:   if (options.acct_update)
        !          3485:     radius_set_cb_acct_conf(radius, cb_radius_acct_conf);
        !          3486: 
        !          3487:   /* Initialise connections */
        !          3488:   initconn();
        !          3489:   
        !          3490:   /* Allocate ippool for dynamic IP address allocation */
        !          3491:   if (ippool_new(&ippool, 
        !          3492:                 options.dynip, 
        !          3493:                 options.dhcpstart, 
        !          3494:                 options.dhcpend, 
        !          3495:                 options.statip, 
        !          3496:                 options.allowdyn, 
        !          3497:                 options.allowstat)) {
        !          3498:     log_err(0, "Failed to allocate IP pool!");
        !          3499:     exit(1);
        !          3500:   }
        !          3501: 
        !          3502:   /* Create an instance of redir */
        !          3503:   if (redir_new(&redir, &options.uamlisten, options.uamport, options.uamuiport)) {
        !          3504:     log_err(0, "Failed to create redir");
        !          3505:     return -1;
        !          3506:   }
        !          3507: 
        !          3508:   if (redir->fd[0] > maxfd) maxfd = redir->fd[0];
        !          3509:   if (redir->fd[1] > maxfd) maxfd = redir->fd[1];
        !          3510:   redir_set(redir, (options.debug));
        !          3511:   redir_set_cb_getstate(redir, cb_redir_getstate);
        !          3512: 
        !          3513:   memset(&admin_session, 0, sizeof(admin_session));
        !          3514:   memcpy(admin_session.ourmac, dhcp->ipif.hwaddr, sizeof(dhcp->ipif.hwaddr));
        !          3515:   acct_req(&admin_session, RADIUS_STATUS_TYPE_ACCOUNTING_ON);
        !          3516: 
        !          3517:   if (options.adminuser) {
        !          3518:     admin_session.is_adminsession = 1;
        !          3519:     strncpy(admin_session.s_state.redir.username, 
        !          3520:            options.adminuser, sizeof(admin_session.s_state.redir.username));
        !          3521:     set_sessionid(&admin_session);
        !          3522:     chilliauth_radius(radius);
        !          3523:   }
        !          3524: 
        !          3525:   if (options.cmdsocket) {
        !          3526:     cmdsock = cmdsock_init();
        !          3527:     if (cmdsock > 0)
        !          3528:       maxfd = cmdsock;
        !          3529:   }
        !          3530: 
        !          3531:   /* Set up signal handlers */
        !          3532:   memset(&act, 0, sizeof(act));
        !          3533: 
        !          3534:   act.sa_handler = fireman;
        !          3535:   sigaction(SIGCHLD, &act, NULL);
        !          3536: 
        !          3537:   act.sa_handler = termination_handler;
        !          3538:   sigaction(SIGTERM, &act, NULL);
        !          3539:   sigaction(SIGINT, &act, NULL);
        !          3540: 
        !          3541:   act.sa_handler = sighup_handler;
        !          3542:   sigaction(SIGHUP, &act, NULL);
        !          3543: 
        !          3544:   /*
        !          3545:   act.sa_handler = alarm_handler;
        !          3546:   sigaction(SIGALRM, &act, NULL);
        !          3547: 
        !          3548:   memset(&itval, 0, sizeof(itval));
        !          3549:   itval.it_interval.tv_sec = 0;
        !          3550:   itval.it_interval.tv_usec = 500000; / * TODO 0.5 second * /
        !          3551:   itval.it_value.tv_sec = 0; 
        !          3552:   itval.it_value.tv_usec = 500000; / * TODO 0.5 second * /
        !          3553: 
        !          3554:   if (setitimer(ITIMER_REAL, &itval, NULL)) {
        !          3555:     log_err(errno, "setitimer() failed!");
        !          3556:   }
        !          3557:   */
        !          3558: 
        !          3559:   /* setup IPv4LL/APIPA network ip and mask for uamanyip exception */
        !          3560:   inet_aton("169.254.0.0", &ipv4ll_ip);
        !          3561:   inet_aton("255.255.0.0", &ipv4ll_mask);
        !          3562: 
        !          3563:   if (options.debug) 
        !          3564:     log_dbg("Waiting for client request...");
        !          3565: 
        !          3566: 
        !          3567:   /******************************************************************/
        !          3568:   /* Main select loop                                               */
        !          3569:   /******************************************************************/
        !          3570: 
        !          3571:   mainclock = time(0);
        !          3572:   while (keep_going) {
        !          3573: 
        !          3574:     if (do_sighup) {
        !          3575:       reprocess_options(argc, argv);
        !          3576:       fixup_options();
        !          3577: 
        !          3578:       do_sighup = 0;
        !          3579: 
        !          3580:       /* Reinit DHCP parameters */
        !          3581:       if (dhcp)
        !          3582:        dhcp_set(dhcp, (options.debug & DEBUG_DHCP));
        !          3583:       
        !          3584:       /* Reinit RADIUS parameters */
        !          3585:       radius_set(radius, dhcp ? dhcp->ipif.hwaddr : 0, (options.debug & DEBUG_RADIUS));
        !          3586:       
        !          3587:       /* Reinit Redir parameters */
        !          3588:       redir_set(redir, options.debug);
        !          3589: 
        !          3590:       if (options.adminuser)
        !          3591:        chilliauth_radius(radius);
        !          3592:     }
        !          3593: 
        !          3594:     if (lastSecond != (thisSecond = mainclock) /*do_timeouts*/) {
        !          3595:       radius_timeout(radius);
        !          3596: 
        !          3597:       if (dhcp) 
        !          3598:        dhcp_timeout(dhcp);
        !          3599:       
        !          3600:       checkconn();
        !          3601:       lastSecond = thisSecond;
        !          3602:       /*do_timeouts = 0;*/
        !          3603:     }
        !          3604: 
        !          3605:     fd_zero(&fds);
        !          3606: 
        !          3607:     if (tun) tun_fdset(tun, &fds);
        !          3608:     if (dhcp) {
        !          3609:       net_fdset(&dhcp->ipif, &fds);
        !          3610: #if defined(__linux__)
        !          3611:       net_fdset(&dhcp->arpif, &fds);
        !          3612:       net_fdset(&dhcp->eapif, &fds);
        !          3613:       fd_set(dhcp->relayfd, &fds);
        !          3614: #endif
        !          3615:     }
        !          3616: 
        !          3617:     fd_set(radius->fd, &fds);
        !          3618:     fd_set(radius->proxyfd, &fds);
        !          3619:     fd_set(redir->fd[0], &fds);
        !          3620:     fd_set(redir->fd[1], &fds);
        !          3621:     fd_set(cmdsock, &fds);
        !          3622: 
        !          3623:     idleTime.tv_sec = 0; /*IDLETIME;*/
        !          3624:     idleTime.tv_usec = 500;
        !          3625:     /*radius_timeleft(radius, &idleTime);
        !          3626:       if (dhcp) dhcp_timeleft(dhcp, &idleTime);*/
        !          3627:     switch (status = select(maxfd + 1, &fds, NULL, NULL, &idleTime /* NULL */)) {
        !          3628:     case -1:
        !          3629:       if (EINTR != errno) {
        !          3630:        log_err(errno, "select() returned -1!");
        !          3631:       }
        !          3632:       break;
        !          3633:     case 0:
        !          3634:     default:
        !          3635:       break;
        !          3636:     }
        !          3637: 
        !          3638:     mainclock = time(0);
        !          3639: 
        !          3640:     if ((msgresult = 
        !          3641:         TEMP_FAILURE_RETRY(msgrcv(redir->msgid, (struct msgbuf *)&msg, 
        !          3642:                                   sizeof(msg.mdata), 0, IPC_NOWAIT)))  == -1) {
        !          3643:       if ((errno != EAGAIN) && (errno != ENOMSG))
        !          3644:        log_err(errno, "msgrcv() failed!");
        !          3645:     }
        !          3646: 
        !          3647:     if (msgresult > 0) 
        !          3648:       uam_msg(&msg);
        !          3649:     
        !          3650:     if (status > 0) {
        !          3651: 
        !          3652:       if (tun) tun_ckset(tun, &fds);
        !          3653:      
        !          3654:       if (dhcp) {
        !          3655: 
        !          3656:        if (fd_isset(dhcp->relayfd, &fds) && dhcp_relay_decaps(dhcp) < 0)
        !          3657:          log_err(0, "dhcp_relay_decaps() failed!");
        !          3658:       
        !          3659: #if defined(__linux__)
        !          3660: 
        !          3661:        if (net_isset(&dhcp->ipif, &fds) && dhcp_decaps(dhcp) < 0)
        !          3662:          log_err(0, "dhcp_decaps() failed!");
        !          3663:       
        !          3664:        if (net_isset(&dhcp->arpif, &fds) && dhcp_arp_ind(dhcp) < 0)
        !          3665:          log_err(0, "dhcp_arpind() failed!");
        !          3666:        
        !          3667:        if (net_isset(&dhcp->eapif, &fds) && dhcp_eapol_ind(dhcp) < 0)
        !          3668:          log_err(0, "dhcp_eapol_ind() failed!");
        !          3669: 
        !          3670: #elif defined (__FreeBSD__)  || defined (__APPLE__) || defined (__OpenBSD__)
        !          3671: 
        !          3672:        if (net_isset(&dhcp->ipif, &fds) && dhcp_decaps(dhcp) < 0)
        !          3673:          log_err(0, "dhcp_decaps() failed!");
        !          3674: 
        !          3675: #endif
        !          3676: 
        !          3677:       }
        !          3678: 
        !          3679:       if (fd_isset(radius->fd, &fds) && radius_decaps(radius) < 0)
        !          3680:        log_err(0, "radius_ind() failed!");
        !          3681: 
        !          3682:       if (fd_isset(radius->proxyfd, &fds) && radius_proxy_ind(radius) < 0)
        !          3683:        log_err(0, "radius_proxy_ind() failed!");
        !          3684: 
        !          3685:       if (fd_isset(redir->fd[0], &fds) && redir_accept(redir, 0) < 0)
        !          3686:        log_err(0, "redir_accept() failed!");
        !          3687: 
        !          3688:       if (fd_isset(redir->fd[1], &fds) && redir_accept(redir, 1) < 0)
        !          3689:        log_err(0, "redir_accept() failed!");
        !          3690:       
        !          3691:       if (fd_isset(cmdsock, &fds) && cmdsock_accept(cmdsock) < 0)
        !          3692:        log_err(0, "cmdsock_accept() failed!");
        !          3693: 
        !          3694:     }
        !          3695:   }
        !          3696:   
        !          3697:   if (options.debug) 
        !          3698:     log_dbg("Terminating ChilliSpot!");
        !          3699: 
        !          3700:   killconn();
        !          3701: 
        !          3702:   if (redir) 
        !          3703:     redir_free(redir);
        !          3704: 
        !          3705:   if (radius) 
        !          3706:     radius_free(radius);
        !          3707: 
        !          3708:   if (dhcp) 
        !          3709:     dhcp_free(dhcp);
        !          3710: 
        !          3711:   if (tun && options.ipdown)
        !          3712:     tun_runscript(tun, options.ipdown);
        !          3713: 
        !          3714:   if (tun) 
        !          3715:     tun_free(tun);
        !          3716: 
        !          3717:   if (ippool) 
        !          3718:     ippool_free(ippool);
        !          3719: 
        !          3720:   return 0;
        !          3721:   
        !          3722: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>