Enable building #WITHOUT_PROXY
[freeradius.git] / src / modules / rlm_jradius / rlm_jradius.c
index 44b9bb1..bd8179e 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * rlm_jradius - The FreeRADIUS JRadius Server Module
  * Copyright (C) 2004-2006 PicoPoint, B.V.
- * Copyright (c) 2007 David Bird
+ * Copyright (c) 2007-2008 David Bird
  * 
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -42,7 +42,6 @@ RCSID("$Id$")
 #include <freeradius-devel/radiusd.h>
 #include <freeradius-devel/modules.h>
 #include <freeradius-devel/conffile.h>
-#define STR_VALUE(p) ((p)->data.strvalue)
 
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
@@ -68,6 +67,10 @@ static const int JRADIUS_checksimul   = 5;
 static const int JRADIUS_pre_proxy    = 6;
 static const int JRADIUS_post_proxy   = 7;
 static const int JRADIUS_post_auth    = 8;
+#ifdef WITH_COA
+static const int JRADIUS_recv_coa     = 9;
+static const int JRADIUS_send_coa     = 10;
+#endif
 
 #define LOG_PREFIX  "rlm_jradius: "
 #define MAX_HOSTS   4
@@ -95,6 +98,8 @@ typedef struct jradius_inst {
   uint32_t   ipaddr [MAX_HOSTS];
   int        port   [MAX_HOSTS];
   int        timeout;
+  int        read_timeout;
+  int        write_timeout;
   int        allow_codechange;
   int        allow_idchange;
   int        onfail;
@@ -117,6 +122,8 @@ static CONF_PARSER module_config[] = {
   { "secondary",    PW_TYPE_STRING_PTR,  offsetof(JRADIUS, host[1]),    NULL,  NULL},
   { "tertiary",     PW_TYPE_STRING_PTR,  offsetof(JRADIUS, host[2]),    NULL,  NULL},
   { "timeout",      PW_TYPE_INTEGER,     offsetof(JRADIUS, timeout),    NULL,  "5"},
+  { "read_timeout", PW_TYPE_INTEGER,     offsetof(JRADIUS, read_timeout), NULL,  "90"},
+  { "write_timeout",PW_TYPE_INTEGER,     offsetof(JRADIUS, write_timeout),NULL,  "90"},
   { "onfail",       PW_TYPE_STRING_PTR,  offsetof(JRADIUS, onfail_s),   NULL,  NULL},
   { "keepalive",    PW_TYPE_BOOLEAN,     offsetof(JRADIUS, keepalive),  NULL,  "yes"},
   { "connections",  PW_TYPE_INTEGER,     offsetof(JRADIUS, jrsock_cnt), NULL,  "8"},
@@ -125,6 +132,80 @@ static CONF_PARSER module_config[] = {
   { NULL, -1, 0, NULL, NULL }
 };
 
+static int
+sock_read(JRADIUS * inst, JRSOCK *jrsock, uint8_t *b, size_t blen) {
+  int fd = jrsock->con.sock;
+  int timeout = inst->read_timeout;
+  struct timeval tv;
+  ssize_t c;
+  size_t recd = 0;
+  fd_set fds;
+
+  while (recd < blen) {
+
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+    
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+    
+    if (select(fd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &tv) == -1)
+      return -1;
+    
+    if (FD_ISSET(fd, &fds))
+#ifdef WIN32
+      c = recv(fd, b + recd, blen-recd, 0);
+#else
+      c = read(fd, b + recd, blen-recd);
+#endif
+    else
+      return -1;
+
+    if (c <= 0) return -1;
+    recd += c;
+  }
+
+  if (recd < blen) return -1;
+  return recd;
+}
+
+static int
+sock_write(JRADIUS * inst, JRSOCK *jrsock, char *b, size_t blen) {
+  int fd = jrsock->con.sock;
+  int timeout = inst->write_timeout;
+  struct timeval tv;
+  ssize_t c;
+  size_t sent = 0;
+  fd_set fds;
+
+  while (sent < blen) {
+
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+    
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+    
+    if (select(fd + 1, (fd_set *) 0, &fds, (fd_set *) 0, &tv) == -1)
+      return -1;
+    
+    if (FD_ISSET(fd, &fds)) 
+#ifdef WIN32
+      c = send(fd, b+sent, blen-sent, 0);
+#else
+      c = write(fd, b+sent, blen-sent);
+#endif
+    else
+      return -1;
+
+    if (c <= 0) return -1;
+    sent += c;
+  }
+
+  if (sent != blen) return -1;
+  return sent;
+}
+
 static int connect_socket(JRSOCK *jrsock, JRADIUS *inst)
 {
   struct sockaddr_in local_addr, serv_addr;
@@ -229,12 +310,12 @@ static int connect_socket(JRSOCK *jrsock, JRADIUS *inst)
 
   /*
    *     If we previously set the socket to non-blocking, restore blocking 
-   */
   if (inst->timeout > 0 &&
       fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK) == -1) {
     radlog(L_ERR, LOG_PREFIX "could not set blocking on socket");
     goto failed;
   }
+   */
 
   jrsock->state = is_connected;
   jrsock->con.sock = sock;
@@ -246,7 +327,8 @@ static int connect_socket(JRSOCK *jrsock, JRADIUS *inst)
   return 0;
 }
 
-static void close_socket(JRADIUS * inst, JRSOCK *jrsock) {
+static void close_socket(UNUSED JRADIUS * inst, JRSOCK *jrsock)
+{
   radlog(L_INFO, "rlm_jradius: Closing JRadius connection %d", jrsock->id);
   if (jrsock->con.sock > 0) { 
     shutdown(jrsock->con.sock, 2); 
@@ -266,10 +348,6 @@ static void free_socket(JRADIUS * inst, JRSOCK *jrsock) {
   }
 }
 
-static int socket_send(JRSOCK *jrsock, unsigned char *b, unsigned int blen) {
-  return send(jrsock->con.sock, b, blen, 0);
-}
-
 static int init_socketpool(JRADIUS * inst)
 {
   int i, rcode;
@@ -379,7 +457,7 @@ static JRSOCK * get_socket(JRADIUS * inst)
   return NULL;
 }
 
-static int release_socket(JRADIUS * inst, JRSOCK * jrsock)
+static int release_socket(UNUSED JRADIUS * inst, JRSOCK * jrsock)
 {
 #ifdef HAVE_PTHREAD_H
   pthread_mutex_unlock(&jrsock->mutex);
@@ -417,7 +495,7 @@ static int jradius_instantiate(CONF_SECTION *conf, void **instance)
       if (sscanf(b, "%[^:]:%d", host, &port) == 2) { h = host; p = port; }
 
       if (h) {
-       lrad_ipaddr_t ipaddr;
+       fr_ipaddr_t ipaddr;
        if (ip_hton(h, AF_INET, &ipaddr) < 0) {
          radlog(L_ERR, "Can't find IP address for host %s", h);
          continue;
@@ -491,7 +569,7 @@ static int pack_bytes(byte_array * ba, unsigned char *d, unsigned int dlen)
 /*
  *     Pack an integer into a byte array buffer (adjusting for byte-order)
  */
-static int pack_int(byte_array * ba, unsigned int i)
+static int pack_uint32(byte_array * ba, uint32_t i)
 {
   if (ba->left < 4) return -1;
 
@@ -505,6 +583,36 @@ static int pack_int(byte_array * ba, unsigned int i)
 }
 
 /*
+ *     Pack a short into a byte array buffer (adjusting for byte-order)
+ */
+static int pack_uint16(byte_array * ba, uint16_t i)
+{
+  if (ba->left < 2) return -1;
+
+  i = htons(i);
+
+  memcpy((void *)(ba->b + ba->pos), (void *)&i, 2);
+  ba->pos  += 2;
+  ba->left -= 2;
+
+  return 0;
+}
+
+/*
+ *     Pack a byte into a byte array buffer 
+ */
+static int pack_uint8(byte_array * ba, uint8_t i)
+{
+  if (ba->left < 1) return -1;
+
+  memcpy((void *)(ba->b + ba->pos), (void *)&i, 1);
+  ba->pos  += 1;
+  ba->left -= 1;
+
+  return 0;
+}
+
+/*
  *     Pack one byte array buffer into another byte array buffer
  */
 static int pack_array(byte_array * ba, byte_array * a)
@@ -523,27 +631,36 @@ static int pack_array(byte_array * ba, byte_array * a)
  */
 static int pack_vps(byte_array * ba, VALUE_PAIR * vps)
 {
+  uint32_t i;
   VALUE_PAIR * vp;
 
   for (vp = vps; vp != NULL; vp = vp->next) {
 
-    radlog(L_DBG, LOG_PREFIX "packing attribute %s (type: %d; len: %d)", 
-          vp->name, vp->attribute, vp->length);
+    radlog(L_DBG, LOG_PREFIX "packing attribute %s (type: %d; len: %d)",          vp->name, vp->attribute, vp->length);
 
-    if (pack_int(ba, vp->attribute) == -1) return -1;
-    if (pack_int(ba, vp->length)    == -1) return -1;
-    if (pack_int(ba, vp->operator)  == -1) return -1;
+    i = vp->attribute;         /* element is int, not uint32_t */
+    if (pack_uint32(ba, i) == -1) return -1;
+    i = vp->length;
+    if (pack_uint32(ba, i) == -1) return -1;
+    i = vp->operator;
+    if (pack_uint32(ba, i) == -1) return -1;
 
     switch (vp->type) {
+      case PW_TYPE_BYTE:
+       if (pack_uint8(ba, vp->lvalue) == -1) return -1;
+       break;
+      case PW_TYPE_SHORT:
+       if (pack_uint16(ba, vp->lvalue) == -1) return -1;
+       break;
       case PW_TYPE_INTEGER:
       case PW_TYPE_DATE:
-       if (pack_int(ba, vp->lvalue) == -1) return -1;
+       if (pack_uint32(ba, vp->lvalue) == -1) return -1;
        break;
       case PW_TYPE_IPADDR:
-       if (pack_bytes(ba, (void *)&vp->lvalue, vp->length) == -1) return -1;
+       if (pack_bytes(ba, (void *)&vp->vp_ipaddr, vp->length) == -1) return -1;
        break;
       default:
-       if (pack_bytes(ba, (void *)STR_VALUE(vp), vp->length) == -1) return -1;
+       if (pack_bytes(ba, (void *)vp->vp_octets, vp->length) == -1) return -1;
        break;
     }
   }
@@ -562,15 +679,20 @@ static int pack_packet(byte_array * ba, RADIUS_PACKET * p)
 
   init_byte_array(&pba, buff, sizeof(buff));
 
-  if (pack_vps   (&pba, p->vps) == -1) return -1;
+  if (pack_vps(&pba, p->vps) == -1) return -1;
 
   radlog(L_DBG, LOG_PREFIX "packing packet with code: %d (attr length: %d)", p->code, pba.pos);
 
-  if (pack_byte  (ba, p->code)  == -1) return -1;
-  if (pack_byte  (ba, p->id)    == -1) return -1;
-  if (pack_int   (ba, pba.pos)  == -1) return -1;
+#ifdef EXTENDED_FMT
+  if (pack_uint32(ba, p->code) == -1) return -1;
+  if (pack_uint32(ba, p->id) == -1) return -1;
+#else
+  if (pack_byte(ba, p->code) == -1) return -1;
+  if (pack_byte(ba, p->id) == -1) return -1;
+#endif
+  if (pack_uint32(ba, pba.pos) == -1) return -1;
   if (pba.pos == 0) return 0;
-  if (pack_array (ba, &pba)     == -1) return -1;
+  if (pack_array(ba, &pba) == -1) return -1;
 
   return 0;
 }
@@ -582,38 +704,54 @@ static int pack_request(byte_array * ba, REQUEST *r)
 
   init_byte_array(&pba, buff, sizeof(buff));
 
-  if (pack_vps   (&pba, r->config_items) == -1) return -1;
-  if (pack_int   (ba, pba.pos)  == -1) return -1;
+  if (pack_vps(&pba, r->config_items) == -1) return -1;
+  if (pack_uint32(ba, pba.pos) == -1) return -1;
   if (pba.pos == 0) return 0;
-  if (pack_array (ba, &pba)     == -1) return -1;
+  if (pack_array(ba, &pba) == -1) return -1;
       
   return 0;
 }
 
-/*
- *     Read a single byte from socket
- */
-static int read_byte(JRSOCK *jrsock, unsigned char *b)
+static uint32_t unpack_uint32(unsigned char *c)
 {
-  return (read(jrsock->con.sock, b, 1) == 1) ? 0 : -1;
+  uint32_t ii;
+  memcpy((void *)&ii, c, 4);
+  return ntohl(ii);
 }
 
-static void unpack_int(unsigned char *c, unsigned int *i)
+static uint16_t unpack_uint16(unsigned char *c)
 {
-  unsigned int ii;
-  memcpy((void *)&ii, c, 4);
-  *i = ntohl(ii);
+  uint16_t ii;
+  memcpy((void *)&ii, c, 2);
+  return ntohs(ii);
+}
+
+static uint8_t unpack_uint8(unsigned char *c)
+{
+  uint8_t ii;
+  memcpy((void *)&ii, c, 1);
+  return ii;
+}
+
+
+
+/*
+ *     Read a single byte from socket
+ */
+static int read_byte(JRADIUS *inst, JRSOCK *jrsock, uint8_t *b)
+{
+  return (sock_read(inst, jrsock, b, 1) == 1) ? 0 : -1;
 }
 
 /*
  *     Read an integer from the socket (adjusting for byte-order)
  */
-static int read_int(JRSOCK *jrsock, unsigned int *i)
+static int read_uint32(JRADIUS *inst, JRSOCK *jrsock, uint32_t *i)
 {
-  unsigned char c[4];
+  uint32_t ii;
 
-  if (read(jrsock->con.sock, c, 4) != 4) return -1;
-  unpack_int(c, i);
+  if (sock_read(inst, jrsock, (uint8_t *)&ii, 4) != 4) return -1;
+  *i = ntohl(ii);
 
   return 0;
 }
@@ -621,17 +759,17 @@ static int read_int(JRSOCK *jrsock, unsigned int *i)
 /*
  *     Read a value-pair list from the socket
  */
-static int read_vps(JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
+static int read_vps(JRADIUS *inst, JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
 {
   VALUE_PAIR *vp;
   unsigned char buff[MESSAGE_LEN];
-  unsigned int alen, atype, aop;
+  uint32_t alen, atype, aop;
   int rlen = 0;
   
   while (rlen < plen) {
-    if (read_int (jrsock, &atype) == -1) return -1; rlen += 4;
-    if (read_int (jrsock, &alen)  == -1) return -1; rlen += 4;
-    if (read_int (jrsock, &aop)   == -1) return -1; rlen += 4; 
+    if (read_uint32(inst, jrsock, &atype) == -1) return -1; rlen += 4;
+    if (read_uint32(inst, jrsock, &alen)  == -1) return -1; rlen += 4;
+    if (read_uint32(inst, jrsock, &aop)   == -1) return -1; rlen += 4; 
 
     radlog(L_DBG, LOG_PREFIX "reading attribute: type=%d; len=%d", atype, alen);
 
@@ -640,13 +778,13 @@ static int read_vps(JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
       return -1;
     }
 
-    if (read(jrsock->con.sock, buff, alen) != (int)alen) return -1; rlen += alen;
+    if (sock_read(inst, jrsock, buff, alen) != (int)alen) return -1; rlen += alen;
     buff[alen]=0;
 
     /*
      *     Create new attribute
      */
-    vp = paircreate(atype, -1);
+    vp = paircreate(atype, 0, -1);
     vp->operator = aop;
 
     if (vp->type == -1) {
@@ -659,27 +797,50 @@ static int read_vps(JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
     }
 
     /*
+     *     WiMAX combo-ip address
+     *     paircreate() cannot recognize the real type of the address.
+     *     ..ugly code...
+     */
+    if (vp->type==PW_TYPE_COMBO_IP) {
+        switch (alen) {
+            case 4:
+                vp->type = PW_TYPE_IPADDR;
+                break;
+            case 16:
+                vp->type = PW_TYPE_IPV6ADDR;
+                break;
+        }
+    }
+
+    /*
      *     Fill in the attribute value based on type
      */
     switch (vp->type) {
+      case PW_TYPE_BYTE:
+       vp->lvalue = unpack_uint8(buff);
+       vp->length = 1;
+       break;
+
+      case PW_TYPE_SHORT:
+       vp->lvalue = unpack_uint16(buff);
+       vp->length = 2;
+       break;
+
       case PW_TYPE_INTEGER:
       case PW_TYPE_DATE:
-       {
-          unpack_int(buff, &vp->lvalue);
-         vp->length = 4;
-       }
+       vp->lvalue = unpack_uint32(buff);
+       vp->length = 4;
        break;
 
       case PW_TYPE_IPADDR:
-       memcpy((void *)&vp->lvalue, buff, 4);
+       memcpy((void *)&vp->vp_ipaddr, buff, 4);
        vp->length = 4;
        break;
 
       default:
-        if (alen < sizeof(STR_VALUE(vp))) {
-         memcpy((void *)STR_VALUE(vp), buff, alen);
-           vp->length = alen;
-       }
+        if (alen >= sizeof(vp->vp_octets)) alen = sizeof(vp->vp_octets) - 1;
+       memcpy((void *)vp->vp_octets, buff, alen);
+       vp->length = alen;
        break;
     }
 
@@ -697,13 +858,22 @@ static int read_vps(JRSOCK *jrsock, VALUE_PAIR **pl, int plen)
  */
 static int read_packet(JRADIUS * inst, JRSOCK *jrsock, RADIUS_PACKET *p)
 {
-  unsigned char code;
-  unsigned char id;
-  unsigned int plen;
+  uint32_t code;
+  uint32_t id;
+  uint32_t plen;
+
+#ifdef EXTENDED_FMT
+  if (read_uint32(inst, jrsock, &code) == -1) return -1;
+  if (read_uint32(inst, jrsock, &id)   == -1) return -1;
+#else
+  { uint8_t c = 0;
+  if (read_byte(inst, jrsock, &c) == -1) return -1;
+  code = c;
+  if (read_byte(inst, jrsock, &c) == -1) return -1;
+  id = c; }
+#endif
 
-  if (read_byte (jrsock, &code) == -1) return -1;
-  if (read_byte (jrsock, &id)   == -1) return -1;
-  if (read_int  (jrsock, &plen) == -1) return -1;
+  if (read_uint32(inst, jrsock, &plen) == -1) return -1;
 
   radlog(L_DBG, LOG_PREFIX "reading packet: code=%d len=%d", (int)code, plen);
 
@@ -714,9 +884,9 @@ static int read_packet(JRADIUS * inst, JRSOCK *jrsock, RADIUS_PACKET *p)
     }
 
   if (inst->allow_idchange)
-    if (id != p->id) {
+    if ((int)id != p->id) {
       radlog(L_INFO, LOG_PREFIX "changing packet id from %d to %d", p->id, id);
-      p->id = id;
+      p->id = (int)id;
     }
   
   /*
@@ -726,16 +896,16 @@ static int read_packet(JRADIUS * inst, JRSOCK *jrsock, RADIUS_PACKET *p)
 
   if (plen == 0) return 0;
 
-  if (read_vps (jrsock, &p->vps, plen) == -1) return -1;
+  if (read_vps(inst, jrsock, &p->vps, plen) == -1) return -1;
 
   return 0;
 }
 
-static int read_request(JRSOCK *jrsock, REQUEST *p)
+static int read_request(JRADIUS *inst, JRSOCK *jrsock, REQUEST *p)
 {
   unsigned int plen;
 
-  if (read_int(jrsock, &plen) == -1) return -1;
+  if (read_uint32(inst, jrsock, &plen) == -1) return -1;
 
   radlog(L_DBG, LOG_PREFIX "reading request: config_item: len=%d", plen);
 
@@ -746,7 +916,7 @@ static int read_request(JRSOCK *jrsock, REQUEST *p)
 
   if (plen == 0) return 0;
 
-  if (read_vps(jrsock, &p->config_items, plen) == -1) return -1;
+  if (read_vps(inst, jrsock, &p->config_items, plen) == -1) return -1;
 
   return 0;
 }
@@ -754,8 +924,8 @@ static int read_request(JRSOCK *jrsock, REQUEST *p)
 static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy)
 {
   JRADIUS        * inst    = instance;
-  RADIUS_PACKET  * request = isproxy ? req->proxy : req->packet;
-  RADIUS_PACKET  * reply   = isproxy ? req->proxy_reply : req->reply;
+  RADIUS_PACKET  * request = req->packet;
+  RADIUS_PACKET  * reply   = req->reply;
   JRSOCK         * jrsock  = 0;
   JRSOCK           sjrsock;
 
@@ -773,6 +943,13 @@ static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy
 #define W_ERR(s) { err=s; goto packerror;  }
 #define R_ERR(s) { err=s; goto parseerror; }
 
+#ifdef WITH_PROXY
+  if (isproxy) {
+         request = req->proxy;
+         reply   = req->proxy_reply;
+  }
+#endif
+
   if (inst->keepalive) {
     jrsock = get_socket(inst);
     if (!jrsock) return exitstatus;
@@ -791,7 +968,7 @@ static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy
   /*
    *     Create byte array to send to jradius
    */
-  if ((rc = pack_int    (&ba, nlen))                  == -1)  W_ERR("pack_int(nlen)");
+  if ((rc = pack_uint32 (&ba, nlen))                  == -1)  W_ERR("pack_uint32(nlen)");
   if ((rc = pack_bytes  (&ba, (void *)n, nlen))       == -1)  W_ERR("pack_bytes(name)");
   if ((rc = pack_byte   (&ba, func))                  == -1)  W_ERR("pack_byte(fun)");
   if ((rc = pack_byte   (&ba, pcount))                == -1)  W_ERR("pack_byte(pcnt)");
@@ -811,8 +988,8 @@ static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy
     }
   }
   radlog(L_DBG, LOG_PREFIX "sending %d bytes to socket %d", ba.pos, jrsock->id);
-  if (socket_send(jrsock, ba.b, ba.pos) != (int)ba.pos ||
-      (rc = read_byte (jrsock, &rcode)) == -1) {
+  if (sock_write(inst, jrsock, ba.b, ba.pos) != (int)ba.pos ||
+      (rc = read_byte(inst, jrsock, &rcode)) == -1) {
     /*
      *   With an error on the write or the first read, try closing the socket
      *   and reconnecting to see if that improves matters any (tries this only once)
@@ -827,25 +1004,25 @@ static int rlm_jradius_call(char func, void *instance, REQUEST *req, int isproxy
   /*
    *     Read result
    */
-  if ((rc = read_byte (jrsock, &pcount)) == -1)  R_ERR("read_byte(pcnt)");
+  if ((rc = read_byte(inst, jrsock, &pcount)) == -1)  R_ERR("read_byte(pcnt)");
 
   radlog(L_DBG, LOG_PREFIX "return code %d; receiving %d packets", (int)rcode, (int)pcount);
 
   if (pcount > 0 && request) if ((rc = read_packet (inst, jrsock, request)) == -1)  R_ERR("read_packet(req)");
   if (pcount > 1 && reply)   if ((rc = read_packet (inst, jrsock, reply))   == -1)  R_ERR("read_packet(rep)");
 
-  if ((rc = read_request (jrsock, req)) == -1) R_ERR("read_request()");
+  if ((rc = read_request(inst, jrsock, req)) == -1) R_ERR("read_request()");
 
   /*
    *    Since we deleted all the attribute lists in the request,
    *    we need to reconfigure a few pointers in the REQUEST object
    */
   if (req->username) {
-    req->username = pairfind(request->vps, PW_USER_NAME);
+    req->username = pairfind(request->vps, PW_USER_NAME, 0);
   }
   if (req->password) {
-    req->password = pairfind(request->vps, PW_PASSWORD);
-    if (!req->password) req->password = pairfind(request->vps, PW_CHAP_PASSWORD);
+    req->password = pairfind(request->vps, PW_PASSWORD, 0);
+    if (!req->password) req->password = pairfind(request->vps, PW_CHAP_PASSWORD, 0);
   }
 
   /*
@@ -912,6 +1089,17 @@ static int jradius_post_auth(void *instance, REQUEST *request)
   return rlm_jradius_call(JRADIUS_post_auth, instance, request, 0);
 }
 
+#ifdef WITH_COA
+static int jradius_recv_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_recv_coa, instance, request, 0);
+}
+static int jradius_send_coa(void *instance, REQUEST *request)
+{
+  return rlm_jradius_call(JRADIUS_send_coa, instance, request, 0);
+}
+#endif
+
 static int jradius_detach(void *instance)
 {
   JRADIUS *inst = (JRADIUS *) instance;
@@ -935,6 +1123,10 @@ module_t rlm_jradius = {
     jradius_pre_proxy,
     jradius_post_proxy,
     jradius_post_auth
+#ifdef WITH_COA
+    , jradius_recv_coa,
+    jradius_send_coa
+#endif
   },
 };