More changes to make a common naming scheme. This breaks
[freeradius.git] / src / modules / rlm_jradius / rlm_jradius.c
1 /**
2  * rlm_jradius - The FreeRADIUS JRadius Server Module
3  * Copyright (C) 2004-2006 PicoPoint, B.V.
4  * Copyright (c) 2007 David Bird
5  * 
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
14  * for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  *  This module is used to connect FreeRADIUS to the JRadius server. 
21  *  JRadius is a Java RADIUS client and server framework, see doc/rlm_jradius
22  *  and http://jradius.net/ for more information. 
23  *
24  *  Author(s): David Bird <dbird@acm.org>
25  *
26  *  Connection pooling code based on rlm_sql, see rlm_sql/sql.c for copyright and license.
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/signal.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <poll.h>
36
37 #include <freeradius-devel/ident.h>
38 RCSID("$Id$")
39
40 #include <freeradius-devel/autoconf.h>
41 #include <freeradius-devel/libradius.h>
42 #include <freeradius-devel/radiusd.h>
43 #include <freeradius-devel/modules.h>
44 #include <freeradius-devel/conffile.h>
45
46 #ifdef HAVE_PTHREAD_H
47 #include <pthread.h>
48 #endif
49
50 #ifdef HAVE_SYS_SOCKET_H
51 #include <sys/socket.h>
52 #endif
53
54 #ifndef O_NONBLOCK
55 #define O_NONBLOCK O_NDELAY
56 #endif
57
58 static const int JRADIUS_PORT         = 1814;
59 static const int HALF_MESSAGE_LEN     = 16384;
60 static const int MESSAGE_LEN          = 32768;
61
62 static const int JRADIUS_authenticate = 1;
63 static const int JRADIUS_authorize    = 2;
64 static const int JRADIUS_preacct      = 3;
65 static const int JRADIUS_accounting   = 4;
66 static const int JRADIUS_checksimul   = 5;
67 static const int JRADIUS_pre_proxy    = 6;
68 static const int JRADIUS_post_proxy   = 7;
69 static const int JRADIUS_post_auth    = 8;
70
71 #define LOG_PREFIX  "rlm_jradius: "
72 #define MAX_HOSTS   4
73
74 typedef struct jradius_socket {
75   int  id;
76 #ifdef HAVE_PTHREAD_H
77   pthread_mutex_t mutex;
78 #endif
79   struct jradius_socket *next;
80   enum { is_connected, not_connected } state;
81   
82   union {
83     int sock;
84   } con;
85 } JRSOCK;
86
87 typedef struct jradius_inst {
88   time_t      connect_after;
89   JRSOCK    * sock_pool;
90   JRSOCK    * last_used;
91
92   char     * name;
93   char     * host   [MAX_HOSTS];
94   uint32_t   ipaddr [MAX_HOSTS];
95   int        port   [MAX_HOSTS];
96   int        timeout;
97   int        allow_codechange;
98   int        allow_idchange;
99   int        onfail;
100   char     * onfail_s;
101   int        keepalive;
102   int        jrsock_cnt;
103 } JRADIUS;
104
105 typedef struct _byte_array
106 {
107   unsigned int size;
108   unsigned int pos;
109   unsigned int left;
110   unsigned char * b;
111 } byte_array;
112
113 static CONF_PARSER module_config[] = {
114   { "name",         PW_TYPE_STRING_PTR,  offsetof(JRADIUS, name),       NULL,  "localhost"},
115   { "primary",      PW_TYPE_STRING_PTR,  offsetof(JRADIUS, host[0]),    NULL,  "localhost"},
116   { "secondary",    PW_TYPE_STRING_PTR,  offsetof(JRADIUS, host[1]),    NULL,  NULL},
117   { "tertiary",     PW_TYPE_STRING_PTR,  offsetof(JRADIUS, host[2]),    NULL,  NULL},
118   { "timeout",      PW_TYPE_INTEGER,     offsetof(JRADIUS, timeout),    NULL,  "5"},
119   { "onfail",       PW_TYPE_STRING_PTR,  offsetof(JRADIUS, onfail_s),   NULL,  NULL},
120   { "keepalive",    PW_TYPE_BOOLEAN,     offsetof(JRADIUS, keepalive),  NULL,  "yes"},
121   { "connections",  PW_TYPE_INTEGER,     offsetof(JRADIUS, jrsock_cnt), NULL,  "8"},
122   { "allow_codechange", PW_TYPE_BOOLEAN, offsetof(JRADIUS, allow_codechange),  NULL,  "no"},
123   { "allow_idchange",   PW_TYPE_BOOLEAN, offsetof(JRADIUS, allow_idchange),    NULL,  "no"},
124   { NULL, -1, 0, NULL, NULL }
125 };
126
127 static int connect_socket(JRSOCK *jrsock, JRADIUS *inst)
128 {
129   struct sockaddr_in local_addr, serv_addr;
130   int i, connected = 0;
131   char buff[128];
132   int sock;
133
134   /*
135    *     Connect to jradius servers until we succeed or die trying
136    */
137   for (i = 0; !connected && i < MAX_HOSTS && inst->ipaddr[i] > 0; i++) {
138
139     /*
140      *     Allocate a TCP socket
141      */
142     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
143       radlog(L_ERR, LOG_PREFIX "could not allocate TCP socket");
144       goto failed;
145     }
146     
147     /*
148      *     If we have a timeout value set, make the socket non-blocking
149      */
150     if (inst->timeout > 0 &&
151         fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK) == -1) {
152       radlog(L_ERR, LOG_PREFIX "could not set non-blocking on socket");
153       goto failed;
154     }
155     
156     /*
157      *     Bind to any local port
158      */
159     memset(&local_addr, 0, sizeof(local_addr));
160     local_addr.sin_family = AF_INET;
161     local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
162     local_addr.sin_port = htons(0);
163     
164     if (bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) {
165       radlog(L_ERR, LOG_PREFIX "could not locally bind TCP socket");
166       goto failed;
167     }
168     
169     /*
170      *     Attempt connection to remote server
171      */
172     memset(&serv_addr, 0, sizeof(serv_addr));
173     serv_addr.sin_family = AF_INET;
174     memcpy((char *) &serv_addr.sin_addr, &(inst->ipaddr[i]), 4);
175     serv_addr.sin_port = htons(inst->port[i]);
176     
177     if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
178       if (inst->timeout > 0 && (errno == EINPROGRESS || errno == EWOULDBLOCK)) {
179         /*
180          *     Wait to see if non-blocking socket connects or times-out
181          */
182         struct pollfd pfd;
183         memset(&pfd, 0, sizeof(pfd));
184
185         pfd.fd = sock;
186         pfd.events = POLLOUT;
187
188         if (poll(&pfd, 1, inst->timeout * 1000) == 1 && pfd.revents) {
189           /*
190            *     Lets make absolutely sure we are connected
191            */
192           struct sockaddr_in sa;
193           unsigned int salen = sizeof(sa);
194           if (getpeername(sock, (struct sockaddr *) &sa, &salen) != -1) {
195             /*
196              *     CONNECTED! break out of for-loop
197              */
198             connected = 1;
199             break;
200           }
201         }
202       }
203
204       /*
205        *     Timed-out
206        */
207       radlog(L_ERR, LOG_PREFIX "could not connect to %s:%d", 
208              ip_ntoa(buff, inst->ipaddr[i]), inst->port[i]);
209
210     } else {
211       /*
212        *     CONNECTED (instantly)! break out of for-loop
213        */
214       connected = 1;
215       break;
216     }
217
218     /*
219      *     Unable to connect, cleanup and start over
220      */
221     close(sock); sock=0;
222   }
223
224   if (!connected) {
225     radlog(L_ERR, LOG_PREFIX "could not find any jradius server!");
226     goto failed;
227   }
228
229   /*
230    *     If we previously set the socket to non-blocking, restore blocking 
231    */
232   if (inst->timeout > 0 &&
233       fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK) == -1) {
234     radlog(L_ERR, LOG_PREFIX "could not set blocking on socket");
235     goto failed;
236   }
237
238   jrsock->state = is_connected;
239   jrsock->con.sock = sock;
240   return 1;
241
242  failed:
243   if (sock > 0) { shutdown(sock, 2); close(sock); }
244   jrsock->state = not_connected;
245   return 0;
246 }
247
248 static void close_socket(UNUSED JRADIUS * inst, JRSOCK *jrsock)
249 {
250   radlog(L_INFO, "rlm_jradius: Closing JRadius connection %d", jrsock->id);
251   if (jrsock->con.sock > 0) { 
252     shutdown(jrsock->con.sock, 2); 
253     close(jrsock->con.sock); 
254   }
255   jrsock->state = not_connected;
256   jrsock->con.sock = 0;
257 }
258
259 static void free_socket(JRADIUS * inst, JRSOCK *jrsock) {
260   close_socket(inst, jrsock);
261   if (inst->keepalive) {
262 #ifdef HAVE_PTHREAD_H
263     pthread_mutex_destroy(&jrsock->mutex);
264 #endif
265     free(jrsock);
266   }
267 }
268
269 static int socket_send(JRSOCK *jrsock, unsigned char *b, unsigned int blen) {
270   return send(jrsock->con.sock, b, blen, 0);
271 }
272
273 static int init_socketpool(JRADIUS * inst)
274 {
275   int i, rcode;
276   int success = 0;
277   JRSOCK *jrsock;
278   
279   inst->connect_after = 0;
280   inst->sock_pool = NULL;
281   
282   for (i = 0; i < inst->jrsock_cnt; i++) {
283     radlog(L_INFO, "rlm_jradius: starting JRadius connection %d", i);
284     
285     if ((jrsock = rad_malloc(sizeof(*jrsock))) == 0) return -1;
286     
287     memset(jrsock, 0, sizeof(*jrsock));
288     jrsock->id = i;
289     jrsock->state = not_connected;
290
291 #ifdef HAVE_PTHREAD_H
292     rcode = pthread_mutex_init(&jrsock->mutex,NULL);
293     if (rcode != 0) {
294       radlog(L_ERR, "rlm_jradius: Failed to init lock: %s", strerror(errno));
295       return 0;
296     }
297 #endif
298
299     if (time(NULL) > inst->connect_after)
300       if (connect_socket(jrsock, inst))
301         success = 1;
302     
303     jrsock->next = inst->sock_pool;
304     inst->sock_pool = jrsock;
305   }
306   inst->last_used = NULL;
307   
308   if (!success) {
309     radlog(L_DBG, "rlm_jradius: Failed to connect to JRadius server.");
310   }
311   
312   return 1;
313 }
314
315 static void free_socketpool(JRADIUS * inst)
316 {
317   JRSOCK *cur;
318   JRSOCK *next;
319
320   for (cur = inst->sock_pool; cur; cur = next) {
321     next = cur->next;
322     free_socket(inst, cur);
323   }
324   
325   inst->sock_pool = NULL;
326 }
327
328 static JRSOCK * get_socket(JRADIUS * inst)
329 {
330   JRSOCK *cur, *start;
331   int tried_to_connect = 0;
332   int unconnected = 0;
333
334   start = inst->last_used;
335   if (!start) start = inst->sock_pool;
336   
337   cur = start;
338   
339   while (cur) {
340 #ifdef HAVE_PTHREAD_H
341     if (pthread_mutex_trylock(&cur->mutex) != 0) {
342       goto next;
343     } 
344 #endif
345     
346     if ((cur->state == not_connected) && (time(NULL) > inst->connect_after)) {
347       radlog(L_INFO, "rlm_jradius: Trying to (re)connect unconnected handle %d", cur->id);
348       tried_to_connect++;
349       connect_socket(cur, inst);
350     }
351     
352     if (cur->state == not_connected) {
353       radlog(L_DBG, "rlm_jradius: Ignoring unconnected handle %d", cur->id);
354       unconnected++;
355 #ifdef HAVE_PTHREAD_H
356       pthread_mutex_unlock(&cur->mutex);
357 #endif
358       goto next;
359     }
360     
361     radlog(L_DBG, "rlm_jradius: Reserving JRadius socket id: %d", cur->id);
362     
363     if (unconnected != 0 || tried_to_connect != 0) {
364       radlog(L_INFO, "rlm_jradius: got socket %d after skipping %d unconnected handles, tried to reconnect %d though", 
365              cur->id, unconnected, tried_to_connect);
366     }
367
368     inst->last_used = cur->next;
369     return cur;
370     
371   next:
372     cur = cur->next;
373     if (!cur) cur = inst->sock_pool;
374     if (cur == start) break;
375   }
376   
377   radlog(L_INFO, "rlm_jradius: There are no sockets to use! skipped %d, tried to connect %d", 
378          unconnected, tried_to_connect);
379   return NULL;
380 }
381
382 static int release_socket(UNUSED JRADIUS * inst, JRSOCK * jrsock)
383 {
384 #ifdef HAVE_PTHREAD_H
385   pthread_mutex_unlock(&jrsock->mutex);
386 #endif
387   
388   radlog(L_DBG, "rlm_jradius: Released JRadius socket id: %d", jrsock->id);
389   
390   return 0;
391 }
392
393
394 /*
395  *     Initialize the jradius module
396  */
397 static int jradius_instantiate(CONF_SECTION *conf, void **instance)
398 {
399   JRADIUS *inst = (JRADIUS *) instance;
400   char host[128], b[128], *h;
401   int i, p, idx, port;
402
403   inst = rad_malloc(sizeof(JRADIUS));
404   memset(inst, 0, sizeof(JRADIUS));
405
406   if (cf_section_parse(conf, inst, module_config) < 0) {
407     free(inst);
408     return -1;
409   }
410
411   for (i = 0, idx = 0; i < MAX_HOSTS; i++) {
412     if (inst->host[i] && strlen(inst->host[i]) < sizeof(host)) {
413       h = inst->host[i];
414       p = JRADIUS_PORT;
415       
416       strcpy(b, h);
417       if (sscanf(b, "%[^:]:%d", host, &port) == 2) { h = host; p = port; }
418
419       if (h) {
420         fr_ipaddr_t ipaddr;
421         if (ip_hton(h, AF_INET, &ipaddr) < 0) {
422           radlog(L_ERR, "Can't find IP address for host %s", h);
423           continue;
424         }
425         if ((inst->ipaddr[idx] = ipaddr.ipaddr.ip4addr.s_addr) != htonl(INADDR_NONE)) {
426           inst->port[idx] = p;
427           radlog(L_INFO, LOG_PREFIX "configuring jradius server %s:%d", h, p);
428           idx++;
429         } else {
430           radlog(L_ERR, LOG_PREFIX "invalid jradius server %s", h);
431         }
432       }
433     }
434   }
435
436   if (inst->keepalive) init_socketpool(inst);
437
438   inst->onfail = RLM_MODULE_FAIL;
439
440   if (inst->onfail_s) {
441     if      (!strcmp(inst->onfail_s, "NOOP"))    inst->onfail = RLM_MODULE_NOOP;
442     else if (!strcmp(inst->onfail_s, "REJECT"))  inst->onfail = RLM_MODULE_REJECT;
443     else if (!strcmp(inst->onfail_s, "OK"))      inst->onfail = RLM_MODULE_OK;
444     else if (!strcmp(inst->onfail_s, "FAIL"))    inst->onfail = RLM_MODULE_FAIL;
445     else radlog(L_ERR, LOG_PREFIX "invalid jradius 'onfail' state %s", inst->onfail_s);
446   }
447
448   *instance = inst;
449
450   return 0;
451 }
452
453 /*
454  *     Initialize a byte array buffer structure
455  */
456 static void init_byte_array(byte_array * ba, unsigned char *b, int blen)
457 {
458   ba->b = b;
459   ba->size = ba->left = blen;
460   ba->pos = 0;
461 }
462
463 /*
464  *     Pack a single byte into a byte array buffer
465  */
466 static int pack_byte(byte_array * ba, unsigned char c)
467 {
468   if (ba->left < 1) return -1;
469
470   ba->b[ba->pos] = c;
471   ba->pos++;
472   ba->left--;
473
474   return 0;
475 }
476
477 /*
478  *     Pack an array of bytes into a byte array buffer
479  */
480 static int pack_bytes(byte_array * ba, unsigned char *d, unsigned int dlen)
481 {
482   if (ba->left < dlen) return -1;
483
484   memcpy((void *)(ba->b + ba->pos), d, dlen);
485   ba->pos  += dlen;
486   ba->left -= dlen;
487
488   return 0;
489 }
490
491 /*
492  *     Pack an integer into a byte array buffer (adjusting for byte-order)
493  */
494 static int pack_uint32(byte_array * ba, uint32_t i)
495 {
496   if (ba->left < 4) return -1;
497
498   i = htonl(i);
499
500   memcpy((void *)(ba->b + ba->pos), (void *)&i, 4);
501   ba->pos  += 4;
502   ba->left -= 4;
503
504   return 0;
505 }
506
507 /*
508  *     Pack one byte array buffer into another byte array buffer
509  */
510 static int pack_array(byte_array * ba, byte_array * a)
511 {
512   if (ba->left < a->pos) return -1;
513
514   memcpy((void *)(ba->b + ba->pos), (void *)a->b, a->pos);
515   ba->pos  += a->pos;
516   ba->left -= a->pos;
517
518   return 0;
519 }
520
521 /*
522  *     Pack radius attributes into a byte array buffer
523  */
524 static int pack_vps(byte_array * ba, VALUE_PAIR * vps)
525 {
526   uint32_t i;
527   VALUE_PAIR * vp;
528
529   for (vp = vps; vp != NULL; vp = vp->next) {
530
531     radlog(L_DBG, LOG_PREFIX "packing attribute %s (type: %d; len: %d)", 
532            vp->name, vp->attribute, vp->length);
533
534     i = vp->attribute;          /* element is int, not uint32_t */
535     if (pack_uint32(ba, i) == -1) return -1;
536     i = vp->length;
537     if (pack_uint32(ba, i) == -1) return -1;
538     i = vp->operator;
539     if (pack_uint32(ba, i) == -1) return -1;
540
541     switch (vp->type) {
542       case PW_TYPE_INTEGER:
543       case PW_TYPE_DATE:
544         if (pack_uint32(ba, vp->lvalue) == -1) return -1;
545         break;
546       case PW_TYPE_IPADDR:
547         if (pack_bytes(ba, (void *)&vp->vp_ipaddr, vp->length) == -1) return -1;
548         break;
549       default:
550         if (pack_bytes(ba, (void *)vp->vp_octets, vp->length) == -1) return -1;
551         break;
552     }
553   }
554
555   return 0;
556 }
557
558 /*
559  *     Pack a radius packet into a byte array buffer
560  */
561 static int pack_packet(byte_array * ba, RADIUS_PACKET * p)
562 {
563   /*unsigned char code = p->code;*/
564   unsigned char buff[HALF_MESSAGE_LEN];
565   byte_array pba;
566
567   init_byte_array(&pba, buff, sizeof(buff));
568
569   if (pack_vps   (&pba, p->vps) == -1) return -1;
570
571   radlog(L_DBG, LOG_PREFIX "packing packet with code: %d (attr length: %d)", p->code, pba.pos);
572
573   if (pack_byte  (ba, p->code)  == -1) return -1;
574   if (pack_byte  (ba, p->id)    == -1) return -1;
575   if (pack_uint32   (ba, pba.pos)  == -1) return -1;
576   if (pba.pos == 0) return 0;
577   if (pack_array (ba, &pba)     == -1) return -1;
578
579   return 0;
580 }
581
582 static int pack_request(byte_array * ba, REQUEST *r)
583 {
584   unsigned char buff[HALF_MESSAGE_LEN];
585   byte_array pba;
586
587   init_byte_array(&pba, buff, sizeof(buff));
588
589   if (pack_vps   (&pba, r->config_items) == -1) return -1;
590   if (pack_uint32   (ba, pba.pos)  == -1) return -1;
591   if (pba.pos == 0) return 0;
592   if (pack_array (ba, &pba)     == -1) return -1;
593       
594   return 0;
595 }
596
597 /*
598  *     Read a single byte from socket
599  */
600 static int read_byte(JRSOCK *jrsock, unsigned char *b)
601 {
602   return (read(jrsock->con.sock, b, 1) == 1) ? 0 : -1;
603 }
604
605 static void unpack_uint32(unsigned char *c, uint32_t *i)
606 {
607   uint32_t ii;
608   memcpy((void *)&ii, c, 4);
609   *i = ntohl(ii);
610 }
611
612 /*
613  *     Read an integer from the socket (adjusting for byte-order)
614  */
615 static int read_uint32(JRSOCK *jrsock, uint32_t *i)
616 {
617   uint32_t ii;
618
619   if (read(jrsock->con.sock, &ii, 4) != 4) return -1;
620   *i = ntohl(ii);
621
622   return 0;
623 }
624
625 /*
626  *     Read a value-pair list from the socket
627  */
628 static int read_vps(JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
629 {
630   VALUE_PAIR *vp;
631   unsigned char buff[MESSAGE_LEN];
632   uint32_t alen, atype, aop;
633   int rlen = 0;
634   
635   while (rlen < plen) {
636     if (read_uint32 (jrsock, &atype) == -1) return -1; rlen += 4;
637     if (read_uint32 (jrsock, &alen)  == -1) return -1; rlen += 4;
638     if (read_uint32 (jrsock, &aop)   == -1) return -1; rlen += 4; 
639
640     radlog(L_DBG, LOG_PREFIX "reading attribute: type=%d; len=%d", atype, alen);
641
642     if (alen >= sizeof(buff)) {
643       radlog(L_ERR, LOG_PREFIX "packet value too large (len: %d)", alen);
644       return -1;
645     }
646
647     if (read(jrsock->con.sock, buff, alen) != (int)alen) return -1; rlen += alen;
648     buff[alen]=0;
649
650     /*
651      *     Create new attribute
652      */
653     vp = paircreate(atype, -1);
654     vp->operator = aop;
655
656     if (vp->type == -1) {
657       /*
658        *     FreeRADIUS should know about the same attributes that JRadius knows
659        */
660       radlog(L_ERR, LOG_PREFIX "received attribute we do not recognize (type: %d)", atype);
661       pairbasicfree(vp);
662       continue;
663     }
664
665     /*
666      *     Fill in the attribute value based on type
667      */
668     switch (vp->type) {
669       case PW_TYPE_INTEGER:
670       case PW_TYPE_DATE:
671         {
672           unpack_uint32(buff, &vp->lvalue);
673           vp->length = 4;
674         }
675         break;
676
677       case PW_TYPE_IPADDR:
678         memcpy((void *)&vp->vp_ipaddr, buff, 4);
679         vp->length = 4;
680         break;
681
682       default:
683         if (alen >= sizeof(vp->vp_octets)) alen = sizeof(vp->vp_octets) - 1;
684         memcpy((void *)vp->vp_octets, buff, alen);
685         vp->length = alen;
686         break;
687     }
688
689     /*
690      *     Add the attribute to the packet
691      */
692     pairadd(pl, vp);
693   } 
694
695   return rlen;
696 }
697
698 /*
699  *     Read a radius packet from the socket
700  */
701 static int read_packet(JRADIUS * inst, JRSOCK *jrsock, RADIUS_PACKET *p)
702 {
703   unsigned char code;
704   unsigned char id;
705   unsigned int plen;
706
707   if (read_byte (jrsock, &code) == -1) return -1;
708   if (read_byte (jrsock, &id)   == -1) return -1;
709   if (read_uint32  (jrsock, &plen) == -1) return -1;
710
711   radlog(L_DBG, LOG_PREFIX "reading packet: code=%d len=%d", (int)code, plen);
712
713   if (inst->allow_codechange)
714     if (code != p->code) {
715       radlog(L_INFO, LOG_PREFIX "changing packet code from %d to %d", p->code, code);
716       p->code = code;
717     }
718
719   if (inst->allow_idchange)
720     if (id != p->id) {
721       radlog(L_INFO, LOG_PREFIX "changing packet id from %d to %d", p->id, id);
722       p->id = id;
723     }
724   
725   /*
726    *     Delete previous attribute list
727    */
728   pairfree(&p->vps);
729
730   if (plen == 0) return 0;
731
732   if (read_vps (jrsock, &p->vps, plen) == -1) return -1;
733
734   return 0;
735 }
736
737 static int read_request(JRSOCK *jrsock, REQUEST *p)
738 {
739   unsigned int plen;
740
741   if (read_uint32(jrsock, &plen) == -1) return -1;
742
743   radlog(L_DBG, LOG_PREFIX "reading request: config_item: len=%d", plen);
744
745   /*
746    *     Delete previous attribute list
747    */
748   pairfree(&p->config_items);
749
750   if (plen == 0) return 0;
751
752   if (read_vps(jrsock, &p->config_items, plen) == -1) return -1;
753
754   return 0;
755 }
756
757 static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy)
758 {
759   JRADIUS        * inst    = instance;
760   RADIUS_PACKET  * request = isproxy ? req->proxy : req->packet;
761   RADIUS_PACKET  * reply   = isproxy ? req->proxy_reply : req->reply;
762   JRSOCK         * jrsock  = 0;
763   JRSOCK           sjrsock;
764
765   int exitstatus = inst->onfail;
766   unsigned char rcode, pcount;
767
768   unsigned char buff[MESSAGE_LEN];
769   byte_array ba;
770
771   char * n = inst->name;
772   unsigned int nlen = strlen(n);
773   const char * err = 0;
774   int rc, attempt2=0;
775
776 #define W_ERR(s) { err=s; goto packerror;  }
777 #define R_ERR(s) { err=s; goto parseerror; }
778
779   if (inst->keepalive) {
780     jrsock = get_socket(inst);
781     if (!jrsock) return exitstatus;
782   } else {
783     jrsock = &sjrsock;
784     memset(jrsock, 0, sizeof(*jrsock));
785     jrsock->state = not_connected;
786   }
787
788   init_byte_array(&ba, buff, sizeof(buff));
789
790   pcount = 0;
791   if (request) pcount++;
792   if (reply) pcount++;
793
794   /*
795    *     Create byte array to send to jradius
796    */
797   if ((rc = pack_uint32    (&ba, nlen))                  == -1)  W_ERR("pack_uint32(nlen)");
798   if ((rc = pack_bytes  (&ba, (void *)n, nlen))       == -1)  W_ERR("pack_bytes(name)");
799   if ((rc = pack_byte   (&ba, func))                  == -1)  W_ERR("pack_byte(fun)");
800   if ((rc = pack_byte   (&ba, pcount))                == -1)  W_ERR("pack_byte(pcnt)");
801   if (pcount > 0 && (rc = pack_packet (&ba, request)) == -1)  W_ERR("pack_packet(req)");
802   if (pcount > 1 && (rc = pack_packet (&ba, reply))   == -1)  W_ERR("pack_packet(rep)");
803   if ((rc = pack_request(&ba, req))                   == -1)  W_ERR("pack_request()");
804
805   /*
806    *     Send data
807    */
808  start_over:
809   if (jrsock->state == not_connected) {
810     if (attempt2) radlog(L_ERR, LOG_PREFIX "reconnecting socket id %d", jrsock->id);
811     if (!connect_socket(jrsock, inst)) {
812       if (attempt2) radlog(L_ERR, LOG_PREFIX "could not reconnect socket %d, giving up", jrsock->id);
813       goto cleanup;
814     }
815   }
816   radlog(L_DBG, LOG_PREFIX "sending %d bytes to socket %d", ba.pos, jrsock->id);
817   if (socket_send(jrsock, ba.b, ba.pos) != (int)ba.pos ||
818       (rc = read_byte (jrsock, &rcode)) == -1) {
819     /*
820      *   With an error on the write or the first read, try closing the socket
821      *   and reconnecting to see if that improves matters any (tries this only once)
822      */
823     radlog(L_ERR, LOG_PREFIX "error sending request with socket %d", jrsock->id);
824     if (!inst->keepalive || attempt2) W_ERR("socket_send/first_read");
825     close_socket(inst, jrsock);
826     attempt2 = 1;
827     goto start_over;
828   }
829
830   /*
831    *     Read result
832    */
833   if ((rc = read_byte (jrsock, &pcount)) == -1)  R_ERR("read_byte(pcnt)");
834
835   radlog(L_DBG, LOG_PREFIX "return code %d; receiving %d packets", (int)rcode, (int)pcount);
836
837   if (pcount > 0 && request) if ((rc = read_packet (inst, jrsock, request)) == -1)  R_ERR("read_packet(req)");
838   if (pcount > 1 && reply)   if ((rc = read_packet (inst, jrsock, reply))   == -1)  R_ERR("read_packet(rep)");
839
840   if ((rc = read_request (jrsock, req)) == -1) R_ERR("read_request()");
841
842   /*
843    *    Since we deleted all the attribute lists in the request,
844    *    we need to reconfigure a few pointers in the REQUEST object
845    */
846   if (req->username) {
847     req->username = pairfind(request->vps, PW_USER_NAME);
848   }
849   if (req->password) {
850     req->password = pairfind(request->vps, PW_PASSWORD);
851     if (!req->password) req->password = pairfind(request->vps, PW_CHAP_PASSWORD);
852   }
853
854   /*
855    *    All done, set return code and cleanup
856    */
857   exitstatus = (int)rcode;
858   goto cleanup;
859
860  parseerror:
861   radlog(L_ERR, LOG_PREFIX "problem parsing the data [%s]",err);
862   if (inst->keepalive) close_socket(inst, jrsock);
863   goto cleanup;
864
865  packerror:
866   radlog(L_ERR, LOG_PREFIX "problem packing the data[%s]",err);
867   if (inst->keepalive) close_socket(inst, jrsock);
868
869  cleanup:
870   if (inst->keepalive) 
871     release_socket(inst, jrsock);
872   else  
873     close_socket(inst, jrsock);
874
875   return exitstatus;
876 }
877
878 static int jradius_authenticate(void *instance, REQUEST *request)
879 {
880   return rlm_jradius_call(JRADIUS_authenticate, instance, request, 0);
881 }
882
883 static int jradius_authorize(void *instance, REQUEST *request)
884 {
885   return rlm_jradius_call(JRADIUS_authorize, instance, request, 0);
886 }
887
888 static int jradius_preacct(void *instance, REQUEST *request)
889 {
890   return rlm_jradius_call(JRADIUS_preacct, instance, request, 0);
891 }
892
893 static int jradius_accounting(void *instance, REQUEST *request)
894 {
895   return rlm_jradius_call(JRADIUS_accounting, instance, request, 0);
896 }
897
898 static int jradius_checksimul(void *instance, REQUEST *request)
899 {
900   return rlm_jradius_call(JRADIUS_checksimul, instance, request, 0);
901 }
902
903 static int jradius_pre_proxy(void *instance, REQUEST *request)
904 {
905   return rlm_jradius_call(JRADIUS_pre_proxy, instance, request, 1);
906 }
907
908 static int jradius_post_proxy(void *instance, REQUEST *request)
909 {
910   return rlm_jradius_call(JRADIUS_post_proxy, instance, request, 1);
911 }
912
913 static int jradius_post_auth(void *instance, REQUEST *request)
914 {
915   return rlm_jradius_call(JRADIUS_post_auth, instance, request, 0);
916 }
917
918 static int jradius_detach(void *instance)
919 {
920   JRADIUS *inst = (JRADIUS *) instance;
921   free_socketpool(inst);
922   free(inst);
923   return 0;
924 }
925
926 module_t rlm_jradius = {
927   RLM_MODULE_INIT,
928   "jradius",
929   RLM_TYPE_THREAD_SAFE,
930   jradius_instantiate,
931   jradius_detach,
932   {
933     jradius_authenticate,
934     jradius_authorize,
935     jradius_preacct,
936     jradius_accounting,
937     jradius_checksimul,
938     jradius_pre_proxy,
939     jradius_post_proxy,
940     jradius_post_auth
941   },
942 };
943