File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / coova-chilli / src / radius.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:48:25 2012 UTC (13 years, 1 month ago) by misho
Branches: coova-chilli, MAIN
CVS tags: v1_0_12, HEAD
coova-chilli

    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>