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

1.1       misho       1: /* 
                      2:  *
                      3:  * Radius client functions.
                      4:  * Copyright (C) 2003, 2004, 2005 Mondru AB.
                      5:  * Copyright (c) 2006-2008 David Bird <david@coova.com>
                      6:  * 
                      7:  * The contents of this file may be used under the terms of the GNU
                      8:  * General Public License Version 2, provided that the above copyright
                      9:  * notice and this permission notice is included in all copies or
                     10:  * substantial portions of the software.
                     11:  * 
                     12:  */
                     13: 
                     14: #include "system.h"
                     15: #include "syserr.h"
                     16: #include "radius.h"
                     17: #include "md5.h"
                     18: #include "dhcp.h"
                     19: #include "redir.h"
                     20: #include "chilli.h"
                     21: #include "options.h"
                     22: #include "radius_wispr.h"
                     23: #include "radius_chillispot.h"
                     24: 
                     25: 
                     26: void radius_addnasip(struct radius_t *radius, struct radius_packet_t *pack)  {
                     27:   struct in_addr inaddr;
                     28:   struct in_addr *paddr = 0;
                     29: 
                     30:   if (options.nasip && *options.nasip)
                     31:     if (inet_aton(options.nasip, &inaddr))
                     32:       paddr = &inaddr;
                     33: 
                     34:   if (!paddr && options.radiuslisten.s_addr != 0)
                     35:     paddr = &options.radiuslisten;
                     36: 
                     37:   if (!paddr)
                     38:     paddr = &options.uamlisten;
                     39:     
                     40:   radius_addattr(radius, pack, RADIUS_ATTR_NAS_IP_ADDRESS, 0, 0, ntohl(paddr->s_addr), NULL, 0); 
                     41: }
                     42: 
                     43: void radius_addcalledstation(struct radius_t *radius, struct radius_packet_t *pack)  {
                     44:   uint8_t b[24];
                     45:   uint8_t *mac= (uint8_t*)"";
                     46: 
                     47:   if (options.nasmac)
                     48:     mac = (uint8_t *)options.nasmac;
                     49:   else 
                     50:     sprintf((char*)(mac=b), "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X", 
                     51:            radius->nas_hwaddr[0],radius->nas_hwaddr[1],radius->nas_hwaddr[2],
                     52:            radius->nas_hwaddr[3],radius->nas_hwaddr[4],radius->nas_hwaddr[5]);
                     53: 
                     54:   radius_addattr(radius, pack, RADIUS_ATTR_CALLED_STATION_ID, 0, 0, 0, mac, strlen((char*)mac)); 
                     55: }
                     56: 
                     57: int radius_printqueue(struct radius_t *this) {
                     58:   int n;
                     59:   printf("next %d, first %d, last %d\n", 
                     60:         this->next, this->first, this ->last);
                     61: 
                     62:   for(n=0; n<256; n++) {
                     63:     if (this->queue[n].state) {
                     64:       printf("%3d %3d %3d %3d %8d %8d %d\n",
                     65:             n, this->queue[n].state,
                     66:             this->queue[n].next,
                     67:             this->queue[n].prev,
                     68:             (int) this->queue[n].timeout.tv_sec,
                     69:             (int) this->queue[n].timeout.tv_usec,
                     70:             (int) this->queue[n].retrans);
                     71:     }
                     72:   }
                     73: 
                     74:   return 0;
                     75: }
                     76: 
                     77: /* 
                     78:  * radius_hmac_md5()
                     79:  * Calculate HMAC MD5 on a radius packet. 
                     80:  */
                     81: int radius_hmac_md5(struct radius_t *this, struct radius_packet_t *pack, 
                     82:                    char *secret, int secretlen, uint8_t *dst) {
                     83:   unsigned char digest[RADIUS_MD5LEN];
                     84:   size_t length;
                     85: 
                     86:   MD5_CTX context;
                     87: 
                     88:   uint8_t *key;
                     89:   size_t key_len;
                     90: 
                     91:   unsigned char k_ipad[65];
                     92:   unsigned char k_opad[65];
                     93:   unsigned char tk[RADIUS_MD5LEN];
                     94:   int i;
                     95: 
                     96:   if (secretlen > 64) { /* TODO: If Microsoft truncate to 64 instead */
                     97:     MD5Init(&context);
                     98:     MD5Update(&context, (uint8_t*)secret, secretlen);
                     99:     MD5Final(tk, &context);
                    100:     key = tk;
                    101:     key_len = 16;
                    102:   }
                    103:   else {
                    104:     key = (uint8_t*)secret;
                    105:     key_len = secretlen;
                    106:   }
                    107: 
                    108:   length = ntohs(pack->length);
                    109: 
                    110:   memset(k_ipad, 0x36, sizeof k_ipad);
                    111:   memset(k_opad, 0x5c, sizeof k_opad);
                    112: 
                    113:   for (i=0; i<key_len; i++) {
                    114:     k_ipad[i] ^= key[i];
                    115:     k_opad[i] ^= key[i];
                    116:   }
                    117: 
                    118:   /* Perform inner MD5 */
                    119:   MD5Init(&context);
                    120:   MD5Update(&context, k_ipad, 64);
                    121:   MD5Update(&context, (uint8_t*) pack, length);
                    122:   MD5Final(digest, &context);
                    123: 
                    124:   /* Perform outer MD5 */
                    125:   MD5Init(&context);
                    126:   MD5Update(&context, k_opad, 64);
                    127:   MD5Update(&context, digest, 16);
                    128:   MD5Final(digest, &context);
                    129:   
                    130:   memcpy(dst, digest, RADIUS_MD5LEN);
                    131: 
                    132:   return 0;
                    133: }
                    134: 
                    135: /* 
                    136:  * radius_acctreq_authenticator()
                    137:  * Update a packet with an accounting request authenticator
                    138:  */
                    139: int radius_acctreq_authenticator(struct radius_t *this,
                    140:                                 struct radius_packet_t *pack) {
                    141: 
                    142:   /* From RFC 2866: Authenticator is the MD5 hash of:
                    143:      Code + Identifier + Length + 16 zero octets + request attributes +
                    144:      shared secret */
                    145:   
                    146:   MD5_CTX context;
                    147: 
                    148:   memset(pack->authenticator, 0, RADIUS_AUTHLEN);
                    149: 
                    150:   /* Get MD5 hash on secret + authenticator */
                    151:   MD5Init(&context);
                    152:   MD5Update(&context, (void*) pack, ntohs(pack->length));
                    153:   MD5Update(&context, (uint8_t*) this->secret, this->secretlen);
                    154:   MD5Final(pack->authenticator, &context);
                    155:   
                    156:   return 0;
                    157: }
                    158: 
                    159: 
                    160: /* 
                    161:  * radius_authresp_authenticator()
                    162:  * Update a packet with an authentication response authenticator
                    163:  */
                    164: int radius_authresp_authenticator(struct radius_t *this,
                    165:                                 struct radius_packet_t *pack,
                    166:                                 uint8_t *req_auth,
                    167:                                 char *secret, size_t secretlen) {
                    168: 
                    169:   /* From RFC 2865: Authenticator is the MD5 hash of:
                    170:      Code + Identifier + Length + request authenticator + request attributes +
                    171:      shared secret */
                    172:   
                    173:   MD5_CTX context;
                    174: 
                    175:   memcpy(pack->authenticator, req_auth, RADIUS_AUTHLEN);
                    176: 
                    177:   /* Get MD5 hash on secret + authenticator */
                    178:   MD5Init(&context);
                    179:   MD5Update(&context, (void*) pack, ntohs(pack->length));
                    180:   MD5Update(&context, (uint8_t*) secret, secretlen);
                    181:   MD5Final(pack->authenticator, &context);
                    182:   
                    183:   return 0;
                    184: }
                    185: 
                    186: 
                    187: /* 
                    188:  * radius_queue_in()
                    189:  * Place data in queue for later retransmission.
                    190:  */
                    191: int radius_queue_in(struct radius_t *this, struct radius_packet_t *pack,
                    192:                    void *cbp) {
                    193:   struct timeval *tv;
                    194:   struct radius_attr_t *ma = NULL; /* Message authenticator */
                    195: 
                    196:   if (this->debug) {
                    197:     log_dbg("radius_queue_in");
                    198:     radius_printqueue(this);
                    199:   }
                    200: 
                    201:   if (this->queue[this->next].state == 1) {
                    202:     log_err(0, "radius queue is full!");
                    203:     /* Queue is not really full. It only means that the next space
                    204:        in queue is not available, but there might be space elsewhere */
                    205:     return -1;
                    206:   }
                    207: 
                    208:   pack->id = this->next;
                    209: 
                    210:   /* If packet contains message authenticator: Calculate it! */
                    211:   if (!radius_getattr(pack, &ma, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0,0,0)) {
                    212:     radius_hmac_md5(this, pack, this->secret, this->secretlen, ma->v.t);
                    213:   }
                    214:   
                    215:   /* If accounting request: Calculate authenticator */
                    216:   if (pack->code == RADIUS_CODE_ACCOUNTING_REQUEST)
                    217:     radius_acctreq_authenticator(this, pack);
                    218: 
                    219:   memcpy(&this->queue[this->next].p, pack, RADIUS_PACKSIZE);
                    220:   this->queue[this->next].state = 1;
                    221:   this->queue[this->next].cbp = cbp;
                    222:   this->queue[this->next].retrans = 0;
                    223: 
                    224:   tv = &this->queue[this->next].timeout;
                    225:   gettimeofday(tv, NULL);
                    226: 
                    227:   tv->tv_sec += options.radiustimeout;
                    228: 
                    229:   this->queue[this->next].lastsent = this->lastreply;
                    230: 
                    231:   /* Insert in linked list for handling timeouts */
                    232:   this->queue[this->next].next = -1;         /* Last in queue */
                    233:   this->queue[this->next].prev = this->last; /* Link to previous */
                    234: 
                    235:   if (this->last != -1)
                    236:     this->queue[this->last].next=this->next; /* Link previous to us */
                    237:   this->last = this->next;                   /* End of queue */
                    238: 
                    239:   if (this->first == -1)
                    240:     this->first = this->next; /* First and last */
                    241: 
                    242:   this->next++; /* next = next % RADIUS_QUEUESIZE */
                    243: 
                    244:   if (this->debug) {
                    245:     printf("radius_queue_out end\n");
                    246:     radius_printqueue(this);
                    247:   }
                    248: 
                    249:   return 0;
                    250: }
                    251: 
                    252: 
                    253: /* 
                    254:  * radius_queue_in()
                    255:  * Remove data from queue.
                    256:  */
                    257: int radius_queue_out(struct radius_t *this, struct radius_packet_t *pack,
                    258:                     int id, void **cbp) {
                    259: 
                    260:   if (this->debug) if (this->debug) printf("radius_queue_out\n");
                    261: 
                    262:   if (this->queue[id].state != 1) {
                    263:     log_err(0, "No such id in radius queue: %d!", id);
                    264:     return -1;
                    265:   }
                    266: 
                    267:   if (this->debug) {
                    268:     log_dbg("radius_queue_out");
                    269:     radius_printqueue(this);
                    270:   }
                    271:   
                    272:   memcpy(pack, &this->queue[id].p, RADIUS_PACKSIZE);
                    273:   *cbp = this->queue[id].cbp;
                    274: 
                    275:   this->queue[id].state = 0;
                    276: 
                    277:   /* Remove from linked list */
                    278:   if (this->queue[id].next == -1) /* Are we the last in queue? */
                    279:     this->last = this->queue[id].prev;
                    280:   else
                    281:     this->queue[this->queue[id].next].prev = this->queue[id].prev;
                    282:     
                    283:   if (this->queue[id].prev == -1) /* Are we the first in queue? */
                    284:     this->first = this->queue[id].next;
                    285:   else
                    286:     this->queue[this->queue[id].prev].next = this->queue[id].next;
                    287: 
                    288:   if (this->debug) {
                    289:     log_dbg("radius_queue_out end");
                    290:     radius_printqueue(this);
                    291:   }
                    292: 
                    293:   return 0;
                    294: }
                    295: 
                    296: /* 
                    297:  * radius_queue_reschedule()
                    298:  * Recalculate the timeout value of a packet in the queue.
                    299:  */
                    300: int radius_queue_reschedule(struct radius_t *this, int id) {
                    301:   struct timeval *tv;
                    302: 
                    303:   /* sanity check */
                    304:   if (id < 0 || id >= RADIUS_QUEUESIZE) {
                    305:     log_err(0, "bad id (%d)", id);
                    306:     return -1;
                    307:   }
                    308: 
                    309:   if (this->debug) 
                    310:     log_dbg("radius_queue_reschedule");
                    311: 
                    312:   if (this->queue[id].state != 1) {
                    313:     log_err(0, "No such id in radius queue: %d!", id);
                    314:     return -1;
                    315:   }
                    316: 
                    317:   if (this->debug) {
                    318:     log_dbg("radius_reschedule");
                    319:     radius_printqueue(this);
                    320:   }
                    321: 
                    322:   this->queue[id].retrans++;
                    323: 
                    324:   tv = &this->queue[id].timeout;
                    325:   gettimeofday(tv, NULL);
                    326: 
                    327:   tv->tv_sec += options.radiustimeout;
                    328: 
                    329:   /* Remove from linked list */
                    330:   if (this->queue[id].next == -1) /* Are we the last in queue? */
                    331:     this->last = this->queue[id].prev;
                    332:   else
                    333:     this->queue[this->queue[id].next].prev = this->queue[id].prev;
                    334:     
                    335:   if (this->queue[id].prev == -1) /* Are we the first in queue? */
                    336:     this->first = this->queue[id].next;
                    337:   else
                    338:     this->queue[this->queue[id].prev].next = this->queue[id].next;
                    339: 
                    340:   /* Insert in linked list for handling timeouts */
                    341:   this->queue[id].next = -1;         /* Last in queue */
                    342:   this->queue[id].prev = this->last; /* Link to previous (could be -1) */
                    343: 
                    344:   if (this->last != -1)
                    345:     this->queue[this->last].next=id; /* If not empty: link previous to us */
                    346: 
                    347:   this->last = id;                   /* End of queue */
                    348: 
                    349:   if (this->first == -1)
                    350:     this->first = id;                /* First and last */
                    351: 
                    352:   if (this->debug) {
                    353:     radius_printqueue(this);
                    354:   }
                    355: 
                    356:   return 0;
                    357: }
                    358: 
                    359: 
                    360: /* 
                    361:  * radius_cmptv()
                    362:  * Returns an integer less than, equal to or greater than zero if tv1
                    363:  * is found, respectively, to be less than, to match or be greater than tv2.
                    364:  */
                    365: int 
                    366: radius_cmptv(struct timeval *tv1, struct timeval *tv2)
                    367: {
                    368:   struct timeval diff;
                    369: 
                    370:   if (0) {
                    371:     printf("tv1 %8d %8d tv2 %8d %8d\n", 
                    372:           (int) tv1->tv_sec, (int) tv1->tv_usec, 
                    373:           (int) tv2->tv_sec, (int) tv2->tv_usec);
                    374:   }
                    375:   
                    376:   /* First take the difference with |usec| < 1000000 */
                    377:   diff.tv_sec = (tv1->tv_usec  - tv2->tv_usec) / 1000000 +
                    378:                 (tv1->tv_sec   - tv2->tv_sec);
                    379:   diff.tv_usec = (tv1->tv_usec - tv2->tv_usec) % 1000000;
                    380: 
                    381:   if (0) {
                    382:     printf("tv1 %8d %8d tv2 %8d %8d diff %8d %8d\n", 
                    383:           (int) tv1->tv_sec, (int) tv1->tv_usec, 
                    384:           (int) tv2->tv_sec, (int) tv2->tv_usec, 
                    385:           (int) diff.tv_sec, (int) diff.tv_usec);
                    386:   }
                    387: 
                    388:   /* If sec and usec have different polarity add or subtract 1 second */
                    389:   if ((diff.tv_sec > 0) & (diff.tv_usec < 0)) {
                    390:     diff.tv_sec--;
                    391:     diff.tv_usec += 1000000;
                    392:   }
                    393:   if ((diff.tv_sec < 0) & (diff.tv_usec > 0)) {
                    394:     diff.tv_sec++;
                    395:     diff.tv_usec -= 1000000;
                    396:   }
                    397:   if (0) {
                    398:     printf("tv1 %8d %8d tv2 %8d %8d diff %8d %8d\n", 
                    399:           (int) tv1->tv_sec, (int) tv1->tv_usec, 
                    400:           (int) tv2->tv_sec, (int) tv2->tv_usec, 
                    401:           (int) diff.tv_sec, (int) diff.tv_usec);
                    402:   }
                    403: 
                    404:   if (diff.tv_sec < 0) {if (0) printf("-1\n"); return -1; }
                    405:   if (diff.tv_sec > 0) {if (0) printf("1\n"); return  1; }
                    406: 
                    407:   if (diff.tv_usec < 0) {if (0) printf("-1\n"); return -1;}
                    408:   if (diff.tv_usec > 0) {if (0) printf("1\n"); return  1;}
                    409:   if (0) printf("0 \n");
                    410:   return 0;
                    411: 
                    412: }
                    413: 
                    414: 
                    415: /* 
                    416:  * radius_timeleft()
                    417:  * Determines how nuch time is left until we need to call 
                    418:  * radius_timeout().
                    419:  * Only modifies timeout if new value is lower than current value.
                    420:  */
                    421: int 
                    422: radius_timeleft(struct radius_t *this, struct timeval *timeout) 
                    423: {
                    424:   struct timeval now, later, diff;
                    425: 
                    426:   if (this->first == -1) /* Queue is empty */
                    427:     return 0;
                    428: 
                    429:   gettimeofday(&now, NULL);
                    430:   later.tv_sec = this->queue[this->first].timeout.tv_sec;
                    431:   later.tv_usec = this->queue[this->first].timeout.tv_usec;
                    432: 
                    433:   /* First take the difference with |usec| < 1000000 */
                    434:   diff.tv_sec = (later.tv_usec  - now.tv_usec) / 1000000 +
                    435:                 (later.tv_sec   - now.tv_sec);
                    436:   diff.tv_usec = (later.tv_usec - now.tv_usec) % 1000000;
                    437: 
                    438:   /* If sec and usec have different polarity add or subtract 1 second */
                    439:   if ((diff.tv_sec > 0) & (diff.tv_usec < 0)) {
                    440:     diff.tv_sec--;
                    441:     diff.tv_usec += 1000000;
                    442:   }
                    443:   if ((diff.tv_sec < 0) & (diff.tv_usec > 0)) {
                    444:     diff.tv_sec++;
                    445:     diff.tv_usec -= 1000000;
                    446:   }
                    447: 
                    448:   /* If negative set to zero */
                    449:   if ((diff.tv_sec < 0) || (diff.tv_usec < 0)) {
                    450:     diff.tv_sec = 0;
                    451:     diff.tv_usec = 0;
                    452:   }
                    453: 
                    454:   /* If original was smaller do nothing */
                    455:   if (radius_cmptv(timeout, &diff) <=0) 
                    456:     return 0;
                    457: 
                    458:   timeout->tv_sec = diff.tv_sec;
                    459:   timeout->tv_usec = diff.tv_usec;
                    460:   return 0;
                    461: }
                    462: 
                    463: /* 
                    464:  * radius_timeout()
                    465:  * Retransmit any outstanding packets. This function should be called at
                    466:  * regular intervals. Use radius_timeleft() to determine how much time is 
                    467:  * left before this function should be called.
                    468:  */
                    469: int radius_timeout(struct radius_t *this) {
                    470:   /* Retransmit any outstanding packets */
                    471:   /* Remove from queue if maxretrans exceeded */
                    472:   struct timeval now;
                    473:   struct sockaddr_in addr;
                    474:   struct radius_packet_t pack_req;
                    475:   void *cbp;
                    476: 
                    477:   gettimeofday(&now, NULL);
                    478: 
                    479: #if(1)
                    480:   if (this->debug) {
                    481:     log_dbg("radius_timeout %8d %8d", (int)now.tv_sec, (int)now.tv_usec);
                    482:     radius_printqueue(this);
                    483:   }
                    484: #endif
                    485: 
                    486:   while (this->first != -1 && 
                    487:         radius_cmptv(&now, &this->queue[this->first].timeout) >= 0) {
                    488:     
                    489:     if (this->queue[this->first].retrans < options.radiusretry) {
                    490:       memset(&addr, 0, sizeof(addr));
                    491:       addr.sin_family = AF_INET;
                    492:       
                    493:       if (this->queue[this->first].retrans == (options.radiusretrysec-1)) {
                    494:        /* Use the other server for next retransmission */
                    495:        if (this->queue[this->first].lastsent) {
                    496:          addr.sin_addr = this->hisaddr0;
                    497:          this->queue[this->first].lastsent = 0;
                    498:        }
                    499:        else {
                    500:          addr.sin_addr = this->hisaddr1;
                    501:          this->queue[this->first].lastsent = 1;
                    502:        }
                    503:       } 
                    504:       else {
                    505:        /* Use the same server for next retransmission */
                    506:        if (this->queue[this->first].lastsent) {
                    507:          addr.sin_addr = this->hisaddr1;
                    508:        }
                    509:        else {
                    510:          addr.sin_addr = this->hisaddr0;
                    511:        }
                    512:       }
                    513:       
                    514:       /* Use the correct port for accounting and authentication */
                    515:       if (this->queue[this->first].p.code == RADIUS_CODE_ACCOUNTING_REQUEST)
                    516:        addr.sin_port = htons(this->acctport);
                    517:       else
                    518:        addr.sin_port = htons(this->authport);
                    519:       
                    520:       
                    521:       if (sendto(this->fd, &this->queue[this->first].p,
                    522:                 ntohs(this->queue[this->first].p.length), 0,
                    523:                 (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                    524:        log_err(errno, "sendto() failed!");
                    525:        radius_queue_reschedule(this, this->first);
                    526:        return -1;
                    527:       }
                    528: 
                    529:       radius_queue_reschedule(this, this->first);
                    530:     }
                    531:     else { /* Finished retrans */
                    532:       if (radius_queue_out(this, &pack_req, this->first, &cbp)) {
                    533:        log_warn(0, "Matching request was not found in queue: %d!", this->first);
                    534:        return -1;
                    535:       }
                    536: 
                    537:       if ((pack_req.code == RADIUS_CODE_ACCOUNTING_REQUEST) &&
                    538:          (this->cb_acct_conf))
                    539:          return this->cb_acct_conf(this, NULL, &pack_req, cbp);
                    540: 
                    541:       if ((pack_req.code == RADIUS_CODE_ACCESS_REQUEST) &&
                    542:          (this->cb_auth_conf))
                    543:        return this->cb_auth_conf(this, NULL, &pack_req, cbp);
                    544:     }    
                    545:   }
                    546:   
                    547:   if (this->debug) {
                    548:     printf("radius_timeout\n");
                    549:     if (this->first > 0) {
                    550:       printf("first %d, timeout %8d %8d\n", this->first, 
                    551:             (int) this->queue[this->first].timeout.tv_sec, 
                    552:             (int) this->queue[this->first].timeout.tv_usec); 
                    553:     }
                    554:     radius_printqueue(this);
                    555:   }
                    556: 
                    557:   return 0;
                    558: }
                    559: 
                    560: 
                    561: 
                    562: /* 
                    563:  * radius_addattr()
                    564:  * Add an attribute to a packet. The packet length is modified 
                    565:  * accordingly.
                    566:  * If data==NULL and dlen!=0 insert null attribute.
                    567:  */
                    568: int 
                    569: radius_addattr(struct radius_t *this, struct radius_packet_t *pack, 
                    570:               uint8_t type, uint32_t vendor_id, uint8_t vendor_type,
                    571:               uint32_t value, uint8_t *data, uint16_t dlen) {
                    572:   struct radius_attr_t *a;
                    573:   char passwd[RADIUS_PWSIZE];
                    574:   uint16_t length = ntohs(pack->length);
                    575:   uint16_t vlen;
                    576:   size_t pwlen;
                    577: 
                    578:   a = (struct radius_attr_t *)((uint8_t*)pack + length);
                    579: 
                    580:   if (type == RADIUS_ATTR_USER_PASSWORD) {
                    581:     radius_pwencode(this, 
                    582:                    (uint8_t*) passwd, RADIUS_PWSIZE, 
                    583:                    &pwlen, 
                    584:                    data, dlen, 
                    585:                    pack->authenticator,
                    586:                    this->secret, this->secretlen);
                    587:     data = (uint8_t *)passwd;
                    588:     dlen = (uint16_t)pwlen;
                    589:   }
                    590: 
                    591:   if (type != RADIUS_ATTR_VENDOR_SPECIFIC) {
                    592:     if (dlen) { /* If dlen != 0 it is a text/string attribute */
                    593:       vlen = dlen;
                    594:     }
                    595:     else {
                    596:       vlen = 4; /* address, integer or time */
                    597:     }
                    598:     
                    599:     if (vlen > RADIUS_ATTR_VLEN) {
                    600:       log_warn(0, "Truncating RADIUS attribute (type:%d/%d/%d) from %d to %d bytes [%s]", 
                    601:               type, vendor_id, vendor_type, vlen, RADIUS_ATTR_VLEN, data);
                    602:       vlen = RADIUS_ATTR_VLEN;
                    603:     }
                    604: 
                    605:     if ((length+vlen+2) > RADIUS_PACKSIZE) {
                    606:       log_err(0, "No more space!");
                    607:       return -1;
                    608:     }
                    609: 
                    610:     length += vlen + 2;
                    611: 
                    612:     pack->length = htons(length);
                    613: 
                    614:     a->t = type;
                    615:     a->l = vlen+2;
                    616: 
                    617:     if (data)
                    618:       memcpy(a->v.t, data, vlen);
                    619:     else if (dlen)
                    620:       memset(a->v.t, 0, vlen);
                    621:     else
                    622:       a->v.i = htonl(value);
                    623:   }
                    624:   else { /* Vendor specific */
                    625:     if (dlen) { /* If dlen != 0 it is a text/string attribute */
                    626:       vlen = dlen;
                    627:     }
                    628:     else {
                    629:       vlen = 4; /* address, integer or time */
                    630:     }
                    631: 
                    632:     if (vlen > RADIUS_ATTR_VLEN-8) {
                    633:       log_warn(0, "Truncating RADIUS attribute (type:%d/%d/%d) from %d to %d [%s]", 
                    634:               type, vendor_id, vendor_type, vlen, RADIUS_ATTR_VLEN-8, data);
                    635:       vlen = RADIUS_ATTR_VLEN-8;
                    636:     }
                    637: 
                    638:     if ((length+vlen+2) > RADIUS_PACKSIZE) { 
                    639:       log_err(0, "No more space!");
                    640:       return -1;
                    641:     }
                    642: 
                    643:     length += vlen + 8;
                    644: 
                    645:     pack->length = htons(length);
                    646: 
                    647:     a->t = type;
                    648:     a->l = vlen+8;
                    649: 
                    650:     a->v.vv.i = htonl(vendor_id);
                    651:     a->v.vv.t = vendor_type;
                    652:     a->v.vv.l = vlen+2;
                    653: 
                    654:     if (data)
                    655:       memcpy(((void*) a)+8, data, dlen);
                    656:     else if (dlen)
                    657:       memset(((void*) a)+8, 0, dlen); 
                    658:     else
                    659:       a->v.vv.v.i = htonl(value);
                    660:   }
                    661: 
                    662:   return 0;
                    663: }
                    664: 
                    665: 
                    666: /* 
                    667:  * radius_getattr()
                    668:  * Search for an attribute in a packet. Returns -1 if attribute is not found.
                    669:  * The first instance matching attributes will be skipped
                    670:  */
                    671: int
                    672: radius_getattr(struct radius_packet_t *pack, struct radius_attr_t **attr,
                    673:               uint8_t type, uint32_t vendor_id, uint8_t vendor_type,
                    674:               int instance) {
                    675:   size_t offset = 0;
                    676:   return radius_getnextattr(pack, attr, type, vendor_id, vendor_type, instance, &offset);
                    677: }
                    678: 
                    679: int
                    680: radius_getnextattr(struct radius_packet_t *pack, struct radius_attr_t **attr,
                    681:               uint8_t type, uint32_t vendor_id, uint8_t vendor_type,
                    682:               int instance, size_t *roffset) {
                    683:   struct radius_attr_t *t;
                    684:   size_t len = ntohs(pack->length) - RADIUS_HDRSIZE;
                    685:   size_t offset = *roffset;
                    686:   int count = 0;
                    687: 
                    688:   if (0) {
                    689:     printf("radius_getattr payload(len=%d,off=%d) %.2x %.2x %.2x %.2x\n",
                    690:           len, offset, pack->payload[0], pack->payload[1], pack->payload[2], 
                    691:           pack->payload[3]);
                    692:   }
                    693: 
                    694:   while (offset < len) {
                    695:     t = (struct radius_attr_t *)(&pack->payload[offset]);
                    696: 
                    697:     if (0) {
                    698:       printf("radius_getattr %d %d %d %.2x %.2x \n", t->t, t->l, 
                    699:             ntohl(t->v.vv.i), (int) t->v.vv.t, (int) t->v.vv.l);
                    700:     }
                    701: 
                    702:     offset +=  t->l;
                    703:     
                    704:     if (t->t != type) 
                    705:       continue;
                    706:     
                    707:     if (t->t == RADIUS_ATTR_VENDOR_SPECIFIC && 
                    708:        (ntohl(t->v.vv.i) != vendor_id || t->v.vv.t != vendor_type))
                    709:       continue;
                    710:     
                    711:     if (count == instance) {
                    712:       
                    713:       if (type == RADIUS_ATTR_VENDOR_SPECIFIC)
                    714:        *attr = (struct radius_attr_t *) &t->v.vv.t;
                    715:       else
                    716:        *attr = t;
                    717:       
                    718:       if (0) printf("Found\n");
                    719:       
                    720:       *roffset = offset;
                    721:       return 0;
                    722:     }
                    723:     else {
                    724:       count++;
                    725:     }
                    726:   }
                    727:   
                    728:   return -1; /* Not found */
                    729: }
                    730: 
                    731: /* 
                    732:  * radius_countattr()
                    733:  * Count the number of instances of an attribute in a packet.
                    734:  */
                    735: int 
                    736: radius_countattr(struct radius_packet_t *pack, uint8_t type) {
                    737:   struct radius_attr_t *t;
                    738:   size_t offset = 0;
                    739:   int count = 0;
                    740:   
                    741:   /* Need to check pack -> length */
                    742:   
                    743:   do {
                    744:     t = (struct radius_attr_t*)(&pack->payload[offset]);
                    745:     if (t->t == type) {
                    746:       count++;
                    747:     }
                    748:     offset +=  2 + t->l;
                    749:   } while (offset < ntohs(pack->length));
                    750:   
                    751:   if (0) printf("Count %d\n", count);
                    752:   return count;
                    753: }
                    754: 
                    755: 
                    756: /* 
                    757:  * radius_cmpattr()
                    758:  * Compare two attributes to see if they are the same.
                    759:  */
                    760: int 
                    761: radius_cmpattr(struct radius_attr_t *t1, struct radius_attr_t *t2) {
                    762:   if (t1->t != t2->t) return -1;
                    763:   if (t1->l != t2->l) return -1;
                    764:   if (memcmp(t1->v.t, t2->v.t, t1->l)) return -1; /* Also int/time/addr */
                    765:   return 0;
                    766: }
                    767: 
                    768: 
                    769: /*
                    770:  * radius_keydecode()
                    771:  * Decode an MPPE key using MD5.
                    772:  */
                    773: int radius_keydecode(struct radius_t *this, 
                    774:                     uint8_t *dst, size_t dstsize, size_t *dstlen, 
                    775:                     uint8_t *src, size_t srclen,
                    776:                     uint8_t *authenticator, 
                    777:                     char *secret, size_t secretlen) {
                    778:   MD5_CTX context;
                    779:   unsigned char b[RADIUS_MD5LEN];
                    780:   int blocks;
                    781:   int i, n;
                    782: 
                    783:   blocks = ((int)srclen - 2) / RADIUS_MD5LEN;
                    784: 
                    785:   if ((blocks * RADIUS_MD5LEN + 2) != (int)srclen) {
                    786:     log_err(0, "radius_keydecode: srclen must be 2 plus n*16");
                    787:     return -1;
                    788:   }
                    789: 
                    790:   if (blocks < 1) {
                    791:     log_err(0, "radius_keydecode srclen must be at least 18");
                    792:     return -1;
                    793:   }
                    794: 
                    795:   /* Get MD5 hash on secret + authenticator (First 16 octets) */
                    796:   MD5Init(&context);
                    797:   MD5Update(&context, (uint8_t *)secret, secretlen);
                    798:   MD5Update(&context, authenticator, RADIUS_AUTHLEN);
                    799:   MD5Update(&context, src, 2);
                    800:   MD5Final(b, &context);
                    801: 
                    802:   if ((src[2] ^ b[0]) > dstsize) {
                    803:     log_err(0,"radius_keydecode dstsize too small");
                    804:     return -1; 
                    805:   }
                    806: 
                    807:   if ((src[2] ^ b[0]) > (srclen - 3)) {
                    808:     log_err(0,"radius_keydecode dstlen > srclen - 3");
                    809:     return -1; 
                    810:   }
                    811: 
                    812:   *dstlen = (size_t)(src[2] ^ b[0]);
                    813: 
                    814:   for (i = 1; i < RADIUS_MD5LEN; i++)
                    815:     if ((i-1) < (int)*dstlen)
                    816:       dst[i-1] = src[i+2] ^ b[i];
                    817: 
                    818:   /* Next blocks of 16 octets */
                    819:   for (n=1; n < blocks; n++) {
                    820:     MD5Init(&context);
                    821:     MD5Update(&context, (uint8_t *)secret, secretlen);
                    822:     MD5Update(&context, &src[2 + ((n-1) * RADIUS_MD5LEN)], RADIUS_MD5LEN);
                    823:     MD5Final(b, &context);
                    824:     for (i = 0; i < RADIUS_MD5LEN; i++)
                    825:       if ((i-1+n*RADIUS_MD5LEN) < (int)*dstlen)
                    826:        dst[i-1+n*RADIUS_MD5LEN] = src[i+2+n*RADIUS_MD5LEN] ^ b[i];
                    827:   }
                    828: 
                    829:   return 0;
                    830: }
                    831: 
                    832: /* 
                    833:  * radius_keyencode()
                    834:  * Encode an MPPE key using MD5.
                    835:  */
                    836: int radius_keyencode(struct radius_t *this, 
                    837:                     uint8_t *dst, size_t dstsize, size_t *dstlen, 
                    838:                     uint8_t *src, size_t srclen,
                    839:                     uint8_t *authenticator, 
                    840:                     char *secret, size_t secretlen) {
                    841:   MD5_CTX context;
                    842:   unsigned char b[RADIUS_MD5LEN];
                    843:   int blocks;
                    844:   int i, n;
                    845: 
                    846:   blocks = ((int)srclen + 1) / RADIUS_MD5LEN;
                    847:   if ((blocks * RADIUS_MD5LEN) < ((int)srclen + 1)) blocks++;
                    848:   
                    849:   if (((blocks * RADIUS_MD5LEN) + 2) > (int)dstsize) {
                    850:     log_err(0, "radius_keyencode dstsize too small");
                    851:     return -1;
                    852:   }
                    853: 
                    854:   *dstlen = (size_t)((blocks * RADIUS_MD5LEN) + 2);
                    855: 
                    856:   /* Read two salt octets */
                    857:   if (fread(dst, 1, 2, this->urandom_fp) != 2) {
                    858:     log_err(errno, "fread() failed");
                    859:     return -1;
                    860:   }
                    861: 
                    862:   /* Get MD5 hash on secret + authenticator (First 16 octets) */
                    863:   MD5Init(&context);
                    864:   MD5Update(&context, (uint8_t *)secret, secretlen);
                    865:   MD5Update(&context, authenticator, RADIUS_AUTHLEN);
                    866:   MD5Update(&context, dst, 2);
                    867:   MD5Final(b, &context);
                    868:   dst[2] = (uint8_t)srclen ^ b[0]; /* Length of key */
                    869:   for (i = 1; i < RADIUS_MD5LEN; i++)
                    870:     if ((i-1) < (int)srclen)
                    871:       dst[i+2] = src[i-1] ^ b[i];
                    872:     else
                    873:       dst[i+2] = b[i];
                    874: 
                    875:   /* Get MD5 hash on secret + c(n-1) (Next j 16 octets) */
                    876:   for (n=1; n < blocks; n++) {
                    877:     MD5Init(&context);
                    878:     MD5Update(&context, (uint8_t *)secret, secretlen);
                    879:     MD5Update(&context, &dst[2 + ((n-1) * RADIUS_MD5LEN)], RADIUS_MD5LEN);
                    880:     MD5Final(b, &context);
                    881:     for (i = 0; i < RADIUS_MD5LEN; i++)
                    882:       if ((i-1) < (int)srclen)
                    883:        dst[i+2+n*RADIUS_MD5LEN] = src[i-1+n*RADIUS_MD5LEN] ^ b[i];
                    884:       else
                    885:        dst[i+2+n*RADIUS_MD5LEN] = b[i];
                    886:   }
                    887: 
                    888:   return 0;
                    889: }
                    890: 
                    891: 
                    892: /* 
                    893:  * radius_pwdecode()
                    894:  * Decode a password using MD5. Also used for MSCHAPv1 MPPE keys.
                    895:  */
                    896: int radius_pwdecode(struct radius_t *this, 
                    897:                    uint8_t *dst, size_t dstsize, size_t *dstlen, 
                    898:                    uint8_t *src, size_t srclen, 
                    899:                    uint8_t *authenticator, 
                    900:                    char *secret, size_t secretlen) {
                    901:   int i, n;
                    902:   MD5_CTX context;
                    903:   unsigned char output[RADIUS_MD5LEN];
                    904: 
                    905:   if (srclen > dstsize) {
                    906:     log_err(0, "radius_pwdecode srclen larger than dstsize");
                    907:     return -1;
                    908:   }
                    909: 
                    910:   if (srclen % RADIUS_MD5LEN) {
                    911:     log_err(0, "radius_pwdecode srclen is not multiple of 16 octets");
                    912:     return -1;
                    913:   }
                    914: 
                    915:   *dstlen = srclen;
                    916: 
                    917:   if (this->debug) {
                    918:     printf("pwdecode srclen %d\n", srclen);
                    919:     for (n=0; n< srclen; n++) {
                    920:       printf("%.2x ", src[n]);
                    921:       if ((n % 16) == 15)
                    922:        printf("\n");
                    923:     }
                    924:     printf("\n");
                    925: 
                    926:     printf("pwdecode authenticator \n");
                    927:     for (n=0; n< RADIUS_AUTHLEN; n++) {
                    928:       printf("%.2x ", authenticator[n]);
                    929:       if ((n % 16) == 15)
                    930:        printf("\n");
                    931:     }
                    932:     printf("\n");
                    933: 
                    934:     printf("pwdecode secret \n");
                    935:     for (n=0; n< secretlen; n++) {
                    936:       printf("%.2x ", secret[n]);
                    937:       if ((n % 16) == 15)
                    938:        printf("\n");
                    939:     }
                    940:     printf("\n");
                    941:   }
                    942: 
                    943:   /* Get MD5 hash on secret + authenticator */
                    944:   MD5Init(&context);
                    945:   MD5Update(&context, (uint8_t*) secret, secretlen);
                    946:   MD5Update(&context, authenticator, RADIUS_AUTHLEN);
                    947:   MD5Final(output, &context);
                    948: 
                    949:   /* XOR first 16 octets of passwd with MD5 hash */
                    950:   for (i = 0; i < RADIUS_MD5LEN; i++)
                    951:     dst[i] = src[i] ^ output[i];
                    952: 
                    953:   /* Continue with the remaining octets of passwd if any */
                    954:   for (n = 0; n < 128 && n < (*dstlen - RADIUS_AUTHLEN); n += RADIUS_AUTHLEN) {
                    955:     MD5Init(&context);
                    956:     MD5Update(&context, (uint8_t*) secret, secretlen);
                    957:     MD5Update(&context, src + n, RADIUS_AUTHLEN);
                    958:     MD5Final(output, &context);
                    959:     for (i = 0; i < RADIUS_AUTHLEN; i++)
                    960:       dst[i + n + RADIUS_AUTHLEN] = src[i + n + RADIUS_AUTHLEN] ^ output[i];
                    961:   }    
                    962: 
                    963:   if (this->debug) {
                    964:     printf("pwdecode dest \n");
                    965:     for (n=0; n< 32; n++) {
                    966:       printf("%.2x ", dst[n]);
                    967:       if ((n % 16) == 15)
                    968:        printf("\n");
                    969:     }
                    970:     printf("\n");
                    971:   }
                    972: 
                    973:   return 0;
                    974: }
                    975: 
                    976: 
                    977: /* 
                    978:  * radius_pwencode()
                    979:  * Encode a password using MD5.
                    980:  */
                    981: int radius_pwencode(struct radius_t *this, 
                    982:                    uint8_t *dst, size_t dstsize,
                    983:                    size_t *dstlen, 
                    984:                    uint8_t *src, size_t srclen, 
                    985:                    uint8_t *authenticator, 
                    986:                    char *secret, size_t secretlen) {
                    987: 
                    988:   unsigned char output[RADIUS_MD5LEN];
                    989:   MD5_CTX context;
                    990:   size_t i, n;
                    991: 
                    992:   memset(dst, 0, dstsize);
                    993: 
                    994:   /* Make dstlen multiple of 16 */
                    995:   if (srclen & 0x0f) 
                    996:     *dstlen = (srclen & 0xf0) + 0x10; /* Padding 1 to 15 zeros */
                    997:   else
                    998:     *dstlen = srclen;                 /* No padding */
                    999: 
                   1000:   /* Is dstsize too small ? */
                   1001:   if (dstsize <= *dstlen) {
                   1002:     *dstlen = 0;
                   1003:     return -1;
                   1004:   }
                   1005: 
                   1006:   /* Copy first 128 octets of src into dst */
                   1007:   if (srclen > 128) 
                   1008:     memcpy(dst, src, 128);
                   1009:   else
                   1010:     memcpy(dst, src, srclen);
                   1011: 
                   1012:   /* Get MD5 hash on secret + authenticator */
                   1013:   MD5Init(&context);
                   1014:   MD5Update(&context, (uint8_t*) secret, secretlen);
                   1015:   MD5Update(&context, authenticator, RADIUS_AUTHLEN);
                   1016:   MD5Final(output, &context);
                   1017: 
                   1018:   /* XOR first 16 octets of dst with MD5 hash */
                   1019:   for (i = 0; i < RADIUS_MD5LEN; i++)
                   1020:     dst[i] ^= output[i];
                   1021: 
                   1022:   /* if (*dstlen <= RADIUS_MD5LEN) return 0;  Finished */
                   1023: 
                   1024:   /* Continue with the remaining octets of dst if any */
                   1025:   for (n = 0; 
                   1026:        n < 128 && n < (*dstlen - RADIUS_AUTHLEN); 
                   1027:        n += RADIUS_AUTHLEN) {
                   1028:     MD5Init(&context);
                   1029:     MD5Update(&context, (uint8_t*) secret, secretlen);
                   1030:     MD5Update(&context, dst + n, RADIUS_AUTHLEN);
                   1031:     MD5Final(output, &context);
                   1032:     for (i = 0; i < RADIUS_AUTHLEN; i++)
                   1033:       dst[i + n + RADIUS_AUTHLEN] ^= output[i];
                   1034:   }    
                   1035: 
                   1036:   return 0;
                   1037: }
                   1038: 
                   1039: 
                   1040: /* 
                   1041:  * radius_new()
                   1042:  * Allocate a new radius instance.
                   1043:  */
                   1044: int radius_new(struct radius_t **this,
                   1045:               struct in_addr *listen, uint16_t port, int coanocheck,
                   1046:               struct in_addr *proxylisten, uint16_t proxyport,
                   1047:               struct in_addr *proxyaddr, struct in_addr *proxymask,
                   1048:               char* proxysecret) {
                   1049:   struct sockaddr_in addr;
                   1050:   struct radius_t *new_radius;
                   1051: 
                   1052:   /* Allocate storage for instance */
                   1053:   if (!(new_radius = calloc(sizeof(struct radius_t), 1))) {
                   1054:     log_err(0, "calloc() failed");
                   1055:     return -1;
                   1056:   }
                   1057: 
                   1058:   new_radius->coanocheck = coanocheck;
                   1059: 
                   1060:   /* Radius parameters */
                   1061:   new_radius->ouraddr.s_addr = listen->s_addr;
                   1062:   new_radius->ourport = port;
                   1063: 
                   1064:   /* Proxy parameters */
                   1065:   if (proxylisten && proxyport && proxysecret) {
                   1066:     new_radius->proxylisten.s_addr = proxylisten->s_addr;
                   1067:     new_radius->proxyport = proxyport;
                   1068:     
                   1069:     if (proxyaddr)
                   1070:       new_radius->proxyaddr.s_addr = proxyaddr->s_addr;
                   1071:     else
                   1072:       new_radius->proxyaddr.s_addr = ~0;
                   1073:     
                   1074:     if (proxymask)
                   1075:       new_radius->proxymask.s_addr = proxymask->s_addr;
                   1076:     else
                   1077:       new_radius->proxymask.s_addr = 0;
                   1078:     
                   1079:     if ((new_radius->proxysecretlen = strlen(proxysecret)) < RADIUS_SECRETSIZE) {
                   1080:       memcpy(new_radius->proxysecret, proxysecret, new_radius->proxysecretlen);
                   1081:     }
                   1082:   }
                   1083: 
                   1084:   /* Initialise queue */
                   1085:   new_radius->next = 0;
                   1086:   new_radius->first = -1;
                   1087:   new_radius->last = -1;
                   1088:   
                   1089:   if ((new_radius->urandom_fp = fopen("/dev/urandom", "r")) < 0) {
                   1090:     log_err(errno, "fopen(/dev/urandom, r) failed");
                   1091:     free(new_radius);
                   1092:     return -1;
                   1093:   }
                   1094:   
                   1095:   /* Initialise radius socket */
                   1096:   if ((new_radius->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
                   1097:     log_err(errno, "socket() failed!");
                   1098:     fclose(new_radius->urandom_fp);
                   1099:     free(new_radius);
                   1100:     return -1;
                   1101:   }
                   1102: 
                   1103:   memset(&addr, 0, sizeof(addr));
                   1104:   addr.sin_family = AF_INET;
                   1105:   addr.sin_addr = new_radius->ouraddr;
                   1106:   addr.sin_port = htons(new_radius->ourport);
                   1107:   
                   1108:   if (bind(new_radius->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                   1109:     log_err(errno, "bind() failed!");
                   1110:     fclose(new_radius->urandom_fp);
                   1111:     close(new_radius->fd);
                   1112:     free(new_radius);
                   1113:     return -1;
                   1114:   }
                   1115: 
                   1116:   /* Initialise proxy socket */
                   1117:   if (proxylisten && proxyport && proxysecret) {
                   1118:     if ((new_radius->proxyfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
                   1119:       log_err(errno, "socket() failed for proxyfd!");
                   1120:       fclose(new_radius->urandom_fp);
                   1121:       close(new_radius->fd);
                   1122:       free(new_radius);
                   1123:       return -1;
                   1124:     }
                   1125:     
                   1126:     memset(&addr, 0, sizeof(addr));
                   1127:     addr.sin_family = AF_INET;
                   1128:     addr.sin_addr = new_radius->proxylisten;
                   1129:     addr.sin_port = htons(new_radius->proxyport);
                   1130:     
                   1131:     if (bind(new_radius->proxyfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                   1132:       log_err(errno, "bind() failed for proxylisten!");
                   1133:       fclose(new_radius->urandom_fp);
                   1134:       close(new_radius->fd);
                   1135:       close(new_radius->proxyfd);
                   1136:       free(new_radius);
                   1137:       return -1;
                   1138:     }
                   1139:   }
                   1140:   else {
                   1141:     new_radius->proxyfd = -1; /* Indicate that proxy is not used */
                   1142:   }
                   1143: 
                   1144:   *this = new_radius;
                   1145:   return 0;
                   1146: }
                   1147: 
                   1148: 
                   1149: /* 
                   1150:  * radius_free()
                   1151:  * Free a radius instance. (Undo radius_new() 
                   1152:  */
                   1153: int 
                   1154: radius_free(struct radius_t *this)
                   1155: {
                   1156:   if (fclose(this->urandom_fp)) {
                   1157:     log_err(errno, "fclose() failed!");
                   1158:   }
                   1159:   if (close(this->fd)) {
                   1160:     log_err(errno, "close() failed!");
                   1161:   }
                   1162:   free(this);
                   1163:   return 0;
                   1164: }
                   1165: 
                   1166: void radius_set(struct radius_t *this, unsigned char *hwaddr, int debug) {
                   1167:   this->debug = debug;
                   1168: 
                   1169:   /* Remote radius server parameters */
                   1170:   this->hisaddr0.s_addr = options.radiusserver1.s_addr;
                   1171:   this->hisaddr1.s_addr = options.radiusserver2.s_addr;
                   1172: 
                   1173:   if (options.radiusauthport) {
                   1174:     this->authport = options.radiusauthport;
                   1175:   }
                   1176:   else {
                   1177:     this->authport = RADIUS_AUTHPORT;
                   1178:   }
                   1179:   
                   1180:   if (options.radiusacctport) {
                   1181:     this->acctport = options.radiusacctport;
                   1182:   }
                   1183:   else {
                   1184:     this->acctport = RADIUS_ACCTPORT;
                   1185:   }
                   1186: 
                   1187:   if ((this->secretlen = strlen(options.radiussecret)) > RADIUS_SECRETSIZE) {
                   1188:     log_err(0, "Radius secret too long. Truncating to %d characters", 
                   1189:            RADIUS_SECRETSIZE);
                   1190:     this->secretlen = RADIUS_SECRETSIZE;
                   1191:   }
                   1192: 
                   1193:   if (hwaddr)
                   1194:     memcpy(this->nas_hwaddr, hwaddr, sizeof(this->nas_hwaddr));
                   1195: 
                   1196:   memcpy(this->secret, options.radiussecret, this->secretlen);
                   1197: 
                   1198:   this->lastreply = 0; /* Start out using server 0 */  
                   1199:   return;
                   1200: }
                   1201: 
                   1202: 
                   1203: /* 
                   1204:  * radius_set_cb_ind()
                   1205:  * Set callback function received requests
                   1206:  */
                   1207: int radius_set_cb_ind(struct radius_t *this,
                   1208:   int (*cb_ind) (struct radius_t *radius, struct radius_packet_t *pack,
                   1209:                 struct sockaddr_in *peer)) {
                   1210: 
                   1211:   this->cb_ind = cb_ind;
                   1212:   return 0;
                   1213: }
                   1214: 
                   1215: 
                   1216: /* 
                   1217:  * radius_set_cb_auth_conf()
                   1218:  * Set callback function for responses to access request
                   1219:  */
                   1220: int
                   1221: radius_set_cb_auth_conf(struct radius_t *this,
                   1222: int (*cb_auth_conf) (struct radius_t *radius, struct radius_packet_t *pack,
                   1223:                       struct radius_packet_t *pack_req, void *cbp)) {
                   1224: 
                   1225:   this->cb_auth_conf = cb_auth_conf;
                   1226:   return 0;
                   1227: }
                   1228: 
                   1229: /* 
                   1230:  * radius_set_cb_acct_conf()
                   1231:  * Set callback function for responses to accounting request
                   1232:  */
                   1233: int
                   1234: radius_set_cb_acct_conf(struct radius_t *this,
                   1235: int (*cb_acct_conf) (struct radius_t *radius, struct radius_packet_t *pack,
                   1236:                     struct radius_packet_t *pack_req, void *cbp)) {
                   1237: 
                   1238:   this->cb_acct_conf = cb_acct_conf;
                   1239:   return 0;
                   1240: }
                   1241: 
                   1242: /* 
                   1243:  * radius_set_cb_coa_ind()
                   1244:  * Set callback function for coa and disconnect request
                   1245:  */
                   1246: int
                   1247: radius_set_cb_coa_ind(struct radius_t *this,
                   1248: int (*cb_coa_ind) (struct radius_t *radius, struct radius_packet_t *pack,
                   1249:                   struct sockaddr_in *peer)) {
                   1250: 
                   1251:   this->cb_coa_ind = cb_coa_ind;
                   1252:   return 0;
                   1253: }
                   1254: 
                   1255: 
                   1256: /* 
                   1257:  * radius_req()
                   1258:  * Send of a packet and place it in the retransmit queue
                   1259:  */
                   1260: int radius_req(struct radius_t *this,
                   1261:               struct radius_packet_t *pack,
                   1262:               void *cbp)
                   1263: {
                   1264:   struct sockaddr_in addr;
                   1265:   size_t len = ntohs(pack->length);
                   1266: 
                   1267:   /* Place packet in queue */
                   1268:   if (radius_queue_in(this, pack, cbp)) {
                   1269:     return -1;
                   1270:   }
                   1271: 
                   1272:   memset(&addr, 0, sizeof(addr));
                   1273:   addr.sin_family = AF_INET;
                   1274: 
                   1275:   if (this->debug) printf("Lastreply: %d\n", this->lastreply);
                   1276: 
                   1277:   if (!this->lastreply) {
                   1278:     addr.sin_addr = this->hisaddr0;
                   1279:   }
                   1280:   else {
                   1281:     addr.sin_addr = this->hisaddr1;
                   1282:   }
                   1283: 
                   1284:   if (pack->code == RADIUS_CODE_ACCOUNTING_REQUEST)
                   1285:     addr.sin_port = htons(this->acctport);
                   1286:   else
                   1287:     addr.sin_port = htons(this->authport);
                   1288:       
                   1289:   
                   1290:   if (sendto(this->fd, pack, len, 0,
                   1291:             (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                   1292:     log_err(errno, "sendto() failed!");
                   1293:     return -1;
                   1294:   } 
                   1295:     
                   1296:   return 0;
                   1297: }
                   1298: 
                   1299: 
                   1300: /* 
                   1301:  * radius_resp()
                   1302:  * Send of a packet (no retransmit queue)
                   1303:  */
                   1304: int radius_resp(struct radius_t *this,
                   1305:                struct radius_packet_t *pack,
                   1306:                struct sockaddr_in *peer, uint8_t *req_auth) {
                   1307: 
                   1308:   size_t len = ntohs(pack->length);
                   1309:   struct radius_attr_t *ma = NULL; /* Message authenticator */
                   1310: 
                   1311:   /* Prepare for message authenticator TODO */
                   1312:   memset(pack->authenticator, 0, RADIUS_AUTHLEN);
                   1313:   memcpy(pack->authenticator, req_auth, RADIUS_AUTHLEN);
                   1314: 
                   1315:   /* If packet contains message authenticator: Calculate it! */
                   1316:   if (!radius_getattr(pack, &ma, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0,0,0)) {
                   1317:     radius_hmac_md5(this, pack, this->proxysecret, this->proxysecretlen, ma->v.t);
                   1318:   }
                   1319: 
                   1320:   radius_authresp_authenticator(this, pack, req_auth, 
                   1321:                                this->proxysecret,
                   1322:                                this->proxysecretlen);
                   1323:   
                   1324:   if (sendto(this->proxyfd, pack, len, 0,
                   1325:             (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
                   1326:     log_err(errno, "sendto() failed!");
                   1327:     return -1;
                   1328:   } 
                   1329:   
                   1330:   return 0;
                   1331: }
                   1332: 
                   1333: /* 
                   1334:  * radius_coaresp()
                   1335:  * Send of a packet (no retransmit queue)
                   1336:  */
                   1337: int radius_coaresp(struct radius_t *this,
                   1338:                   struct radius_packet_t *pack,
                   1339:                   struct sockaddr_in *peer, uint8_t *req_auth) {
                   1340: 
                   1341:   size_t len = ntohs(pack->length);
                   1342:   struct radius_attr_t *ma = NULL; /* Message authenticator */
                   1343: 
                   1344:   /* Prepare for message authenticator TODO */
                   1345:   memset(pack->authenticator, 0, RADIUS_AUTHLEN);
                   1346:   memcpy(pack->authenticator, req_auth, RADIUS_AUTHLEN);
                   1347: 
                   1348:   /* If packet contains message authenticator: Calculate it! */
                   1349:   if (!radius_getattr(pack, &ma, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0,0,0)) {
                   1350:     radius_hmac_md5(this, pack, this->secret, this->secretlen, ma->v.t);
                   1351:   }
                   1352: 
                   1353:   radius_authresp_authenticator(this, pack, req_auth,
                   1354:                                this->secret,
                   1355:                                this->secretlen);
                   1356:   
                   1357:   if (sendto(this->fd, pack, len, 0,
                   1358:             (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) {
                   1359:     log_err(errno, "sendto() failed!");
                   1360:     return -1;
                   1361:   } 
                   1362:   
                   1363:   return 0;
                   1364: }
                   1365: 
                   1366: 
                   1367: /* 
                   1368:  * radius_default_pack()
                   1369:  * Return an empty packet which can be used in subsequent to 
                   1370:  * radius_addattr()
                   1371:  */
                   1372: int
                   1373: radius_default_pack(struct radius_t *this,
                   1374:                    struct radius_packet_t *pack, 
                   1375:                    int code)
                   1376: {
                   1377:   memset(pack, 0, RADIUS_PACKSIZE);
                   1378:   pack->code = code;
                   1379:   pack->id = 0; /* Let the send procedure queue the packet and assign id */
                   1380:   pack->length = htons(RADIUS_HDRSIZE);
                   1381:   
                   1382:   if (fread(pack->authenticator, 1, RADIUS_AUTHLEN, this->urandom_fp) != RADIUS_AUTHLEN) {
                   1383:     log_err(errno, "fread() failed");
                   1384:     return -1;
                   1385:   }
                   1386: 
                   1387:   /* always add the chillispot version to requests */
                   1388:   radius_addattr(this, pack, RADIUS_ATTR_VENDOR_SPECIFIC,
                   1389:                 RADIUS_VENDOR_CHILLISPOT, RADIUS_ATTR_CHILLISPOT_VERSION, 
                   1390:                 0, (uint8_t*)VERSION, strlen(VERSION));
                   1391:   
                   1392:   return 0;
                   1393: }
                   1394: 
                   1395: 
                   1396: /* 
                   1397:  * radius_authcheck()
                   1398:  * Check that the authenticator on a reply is correct.
                   1399:  */
                   1400: int radius_authcheck(struct radius_t *this, struct radius_packet_t *pack, 
                   1401:                     struct radius_packet_t *pack_req)
                   1402: {
                   1403:   uint8_t auth[RADIUS_AUTHLEN];
                   1404:   MD5_CTX context;
                   1405: 
                   1406:   MD5Init(&context);
                   1407:   MD5Update(&context, (uint8_t *) pack, RADIUS_HDRSIZE-RADIUS_AUTHLEN);
                   1408:   MD5Update(&context, pack_req->authenticator, RADIUS_AUTHLEN);
                   1409:   MD5Update(&context, ((uint8_t *) pack) + RADIUS_HDRSIZE, 
                   1410:            ntohs(pack->length) - RADIUS_HDRSIZE);
                   1411:   MD5Update(&context, (uint8_t *)this->secret, this->secretlen);
                   1412:   MD5Final(auth, &context);
                   1413:   
                   1414:   return memcmp(pack->authenticator, auth, RADIUS_AUTHLEN);
                   1415: }
                   1416: 
                   1417: /* 
                   1418:  * radius_acctcheck()
                   1419:  * Check that the authenticator on an accounting request is correct.
                   1420:  */
                   1421: int radius_acctcheck(struct radius_t *this, struct radius_packet_t *pack)
                   1422: {
                   1423:   uint8_t auth[RADIUS_AUTHLEN];
                   1424:   uint8_t padd[RADIUS_AUTHLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                   1425:   MD5_CTX context;
                   1426:   
                   1427:   MD5Init(&context);
                   1428:   MD5Update(&context, (uint8_t *)pack, RADIUS_HDRSIZE-RADIUS_AUTHLEN);
                   1429:   MD5Update(&context, (uint8_t *)padd, RADIUS_AUTHLEN);
                   1430:   MD5Update(&context, ((uint8_t *)pack) + RADIUS_HDRSIZE, 
                   1431:            ntohs(pack->length) - RADIUS_HDRSIZE);
                   1432:   MD5Update(&context, (uint8_t *)this->secret, this->secretlen);
                   1433:   MD5Final(auth, &context);
                   1434:   
                   1435:   return memcmp(pack->authenticator, auth, RADIUS_AUTHLEN);
                   1436: }
                   1437: 
                   1438: 
                   1439: /* 
                   1440:  * radius_decaps()
                   1441:  * Read and process a received radius packet.
                   1442:  */
                   1443: int radius_decaps(struct radius_t *this) {
                   1444:   ssize_t status;
                   1445:   struct radius_packet_t pack;
                   1446:   struct radius_packet_t pack_req;
                   1447:   void *cbp;
                   1448:   struct sockaddr_in addr;
                   1449:   socklen_t fromlen = sizeof(addr);
                   1450:   int coarequest = 0;
                   1451: 
                   1452:   if (this->debug) 
                   1453:     log_dbg("Received radius packet");
                   1454:   
                   1455:   if ((status = recvfrom(this->fd, &pack, sizeof(pack), 0, 
                   1456:                         (struct sockaddr *) &addr, &fromlen)) <= 0) {
                   1457:     log_err(errno, "recvfrom() failed");
                   1458:     return -1;
                   1459:   }
                   1460: 
                   1461:   if (status < RADIUS_HDRSIZE) {
                   1462:     log_warn(0, "Received radius packet which is too short: %d < %d!",
                   1463:             status, RADIUS_HDRSIZE);
                   1464:     return -1;
                   1465:   }
                   1466: 
                   1467:   if (ntohs(pack.length) != (uint16_t)status) {
                   1468:     log_warn(errno, "Received radius packet with wrong length field %d != %d!",
                   1469:             ntohs(pack.length), status);
                   1470:     return -1;
                   1471:   }
                   1472: 
                   1473: 
                   1474:   switch (pack.code) {
                   1475:   case RADIUS_CODE_DISCONNECT_REQUEST:
                   1476:   case RADIUS_CODE_COA_REQUEST:
                   1477:     coarequest = 1;
                   1478:     break;
                   1479:   default:
                   1480:     coarequest = 0;
                   1481:   }
                   1482: 
                   1483:   if (!coarequest) {
                   1484:     /* Check that reply is from correct address */
                   1485:     if ((addr.sin_addr.s_addr != this->hisaddr0.s_addr) &&
                   1486:        (addr.sin_addr.s_addr != this->hisaddr1.s_addr)) {
                   1487:       log_warn(0, "Received radius reply from wrong address %.8x!",
                   1488:              addr.sin_addr.s_addr);
                   1489:       return -1;
                   1490:     }
                   1491:     
                   1492:     /* Check that UDP source port is correct */
                   1493:     if ((addr.sin_port != htons(this->authport)) &&
                   1494:        (addr.sin_port != htons(this->acctport))) {
                   1495:       log_warn(0, "Received radius packet from wrong port %.4x!",
                   1496:              addr.sin_port);
                   1497:       return -1;
                   1498:     }
                   1499:     
                   1500:     if (radius_queue_out(this, &pack_req, pack.id, &cbp)) {
                   1501:       log_warn(0, "Matching request was not found in queue: %d!", pack.id);
                   1502:       return -1;
                   1503:     }
                   1504: 
                   1505:     if (radius_authcheck(this, &pack, &pack_req)) {
                   1506:       log_warn(0, "Authenticator does not match request!");
                   1507:       return -1;
                   1508:     }
                   1509: 
                   1510:     /* Set which radius server to use next */
                   1511:     if (addr.sin_addr.s_addr == this->hisaddr0.s_addr)
                   1512:       this->lastreply = 0;
                   1513:     else
                   1514:       this->lastreply = 1;
                   1515:     
                   1516:   }
                   1517:   else {
                   1518:     if (!this->coanocheck) {
                   1519:       /* Check that request is from correct address */
                   1520:       if ((addr.sin_addr.s_addr != this->hisaddr0.s_addr) &&
                   1521:          (addr.sin_addr.s_addr != this->hisaddr1.s_addr)) {
                   1522:        log_warn(0, "Received radius request from wrong address %.8x!",
                   1523:                addr.sin_addr.s_addr);
                   1524:        return -1;
                   1525:       }
                   1526:     }
                   1527: 
                   1528:     if (radius_acctcheck(this, &pack)) {
                   1529:       log_warn(0, "Authenticator did not match MD5 of packet!");
                   1530:       return -1;
                   1531:     }
                   1532:   }
                   1533:     
                   1534:   /* TODO: Check consistency of attributes vs packet length */
                   1535:   
                   1536:   switch (pack.code) {
                   1537:   case RADIUS_CODE_ACCESS_ACCEPT:
                   1538:   case RADIUS_CODE_ACCESS_REJECT:
                   1539:   case RADIUS_CODE_ACCESS_CHALLENGE:
                   1540:   case RADIUS_CODE_DISCONNECT_ACK:
                   1541:   case RADIUS_CODE_DISCONNECT_NAK:
                   1542:   case RADIUS_CODE_STATUS_ACCEPT:
                   1543:   case RADIUS_CODE_STATUS_REJECT:
                   1544:     if (this->cb_auth_conf)
                   1545:       return this->cb_auth_conf(this, &pack, &pack_req, cbp);
                   1546:     else
                   1547:       return 0;
                   1548:     break;
                   1549:   case RADIUS_CODE_ACCOUNTING_RESPONSE:
                   1550:     if (this->cb_acct_conf)
                   1551:       return this->cb_acct_conf(this, &pack, &pack_req, cbp);
                   1552:     else
                   1553:       return 0;
                   1554:     break;
                   1555:   case RADIUS_CODE_DISCONNECT_REQUEST:
                   1556:   case RADIUS_CODE_COA_REQUEST:
                   1557:     if (this->cb_coa_ind)
                   1558:       return this->cb_coa_ind(this, &pack, &addr);
                   1559:     else
                   1560:       return 0;
                   1561:     break;
                   1562:   default:
                   1563:     log_warn(0, "Received unknown radius packet %d!", pack.code);
                   1564:     return -1;
                   1565:   }
                   1566:   
                   1567:   log_warn(0, "Received unknown radius packet %d!", pack.code);
                   1568:   return -1;
                   1569: }
                   1570: 
                   1571: /* 
                   1572:  * radius_proxy_ind()
                   1573:  * Read and process a received radius packet.
                   1574:  */
                   1575: int radius_proxy_ind(struct radius_t *this) {
                   1576:   ssize_t status;
                   1577:   struct radius_packet_t pack;
                   1578:   struct sockaddr_in addr;
                   1579:   socklen_t fromlen = sizeof(addr);
                   1580: 
                   1581:   if (this->debug) 
                   1582:     log_dbg("Received radius packet");
                   1583:   
                   1584:   if ((status = recvfrom(this->proxyfd, &pack, sizeof(pack), 0, 
                   1585:                         (struct sockaddr *) &addr, &fromlen)) <= 0) {
                   1586:     log_err(errno, "recvfrom() failed");
                   1587:     return -1;
                   1588:   }
                   1589: 
                   1590:   if (status < RADIUS_HDRSIZE) {
                   1591:     log_warn(0, "Received radius packet which is too short: %d < %d!",
                   1592:            status, RADIUS_HDRSIZE);
                   1593:     return -1;
                   1594:   }
                   1595: 
                   1596:   if (ntohs(pack.length) != (uint16_t)status) {
                   1597:     log_err(0, "Received radius packet with wrong length field %d != %d!",
                   1598:            ntohs(pack.length), status);
                   1599:     return -1;
                   1600:   }
                   1601: 
                   1602:   /* Is this a known request? */
                   1603:   if ((this->cb_ind) &&
                   1604:       ((pack.code == RADIUS_CODE_ACCESS_REQUEST) ||
                   1605:        (pack.code == RADIUS_CODE_ACCOUNTING_REQUEST) ||
                   1606:        (pack.code == RADIUS_CODE_DISCONNECT_REQUEST) ||
                   1607:        (pack.code == RADIUS_CODE_STATUS_REQUEST))) {
                   1608: 
                   1609:     /* Check that request is from a known client */
                   1610:     /* Any of the two servers or from one of the clients */
                   1611:     if ((addr.sin_addr.s_addr & this->proxymask.s_addr)!= 
                   1612:        this->proxyaddr.s_addr) {
                   1613:       log_warn(0, "Received radius request from wrong address %.8x!",
                   1614:               addr.sin_addr.s_addr);
                   1615:       return -1;
                   1616:     }
                   1617:     
                   1618:     return this->cb_ind(this, &pack, &addr);
                   1619:   }
                   1620: 
                   1621:   log_warn(0, "Received unknown radius packet %d!", pack.code);
                   1622:   return -1;
                   1623: }
                   1624: 
                   1625: struct app_conn_t admin_session;
                   1626: 
                   1627: int chilliauth_radius(struct radius_t *radius) {
                   1628:   struct radius_packet_t radius_pack;
                   1629:   int ret = -1;
                   1630: 
                   1631:   if (radius_default_pack(radius, &radius_pack, RADIUS_CODE_ACCESS_REQUEST)) {
                   1632:     log_err(0, "radius_default_pack() failed");
                   1633:     return ret;
                   1634:   }
                   1635: 
                   1636:   /* adminuser is required */
                   1637:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_NAME, 0, 0, 0,
                   1638:                 (uint8_t *)options.adminuser, strlen(options.adminuser));
                   1639: 
                   1640:   if (options.adminpasswd)
                   1641:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_USER_PASSWORD, 0, 0, 0,
                   1642:                   (uint8_t *)options.adminpasswd, strlen(options.adminpasswd));
                   1643: 
                   1644:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_SERVICE_TYPE, 0, 0,
                   1645:                 RADIUS_SERVICE_TYPE_ADMIN_USER, NULL, 0); 
                   1646: 
                   1647:   
                   1648:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_PORT_TYPE, 0, 0,
                   1649:                 options.radiusnasporttype, NULL, 0);
                   1650: 
                   1651:   radius_addnasip(radius, &radius_pack);
                   1652: 
                   1653:   radius_addcalledstation(radius, &radius_pack);
                   1654: 
                   1655:   if (options.radiusnasid)
                   1656:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_NAS_IDENTIFIER, 0, 0, 0,
                   1657:                   (uint8_t *)options.radiusnasid, strlen(options.radiusnasid));
                   1658:   
                   1659:   if (options.radiuslocationid)
                   1660:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
                   1661:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_ID, 0,
                   1662:                   (uint8_t *)options.radiuslocationid, strlen(options.radiuslocationid));
                   1663:   
                   1664:   if (options.radiuslocationname)
                   1665:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_VENDOR_SPECIFIC,
                   1666:                   RADIUS_VENDOR_WISPR, RADIUS_ATTR_WISPR_LOCATION_NAME, 0,
                   1667:                   (uint8_t *)options.radiuslocationname, 
                   1668:                   strlen(options.radiuslocationname));
                   1669: 
                   1670:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_ACCT_SESSION_ID, 0, 0, 0,
                   1671:                 (uint8_t*)admin_session.s_state.sessionid, REDIR_SESSIONID_LEN-1);
                   1672: 
                   1673:   if (admin_session.s_state.redir.classlen) {
                   1674:     radius_addattr(radius, &radius_pack, RADIUS_ATTR_CLASS, 0, 0, 0,
                   1675:                   admin_session.s_state.redir.classbuf,
                   1676:                   admin_session.s_state.redir.classlen);
                   1677:   }
                   1678: 
                   1679:   radius_addattr(radius, &radius_pack, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 
                   1680:                 0, 0, 0, NULL, RADIUS_MD5LEN);
                   1681: 
                   1682:   return radius_req(radius, &radius_pack, &admin_session); 
                   1683: }
                   1684: 

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