Annotation of embedaddon/coova-chilli/src/radius.c, revision 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>