Merge libradsec-new-client.
authorLinus Nordberg <linus@nordberg.se>
Fri, 27 Apr 2012 15:00:17 +0000 (17:00 +0200)
committerLinus Nordberg <linus@nordberg.se>
Fri, 27 Apr 2012 15:00:17 +0000 (17:00 +0200)
17 files changed:
1  2 
lib/HACKING
lib/Makefile.am
lib/conf.c
lib/configure.ac
lib/conn.c
lib/err.c
lib/event.c
lib/examples/client-blocking.c
lib/examples/client.conf
lib/include/radsec/radsec-impl.h
lib/include/radsec/radsec.h
lib/packet.c
lib/peer.c
lib/radsec.c
lib/rsp_tlscommon.h
lib/tcp.c
lib/tests/test-udp.c

diff --combined lib/HACKING
@@@ -18,22 -18,11 +18,19 @@@ examples/client -r examples/client.con
    - Application runs its own event loop, using fd's for select and
      performs I/O using the libradsec send/receive calls
      (a.k.a. on-your-own mode)
- - Fully reentrant (FIXME: issues with libfreeradius-radius?)
  - User chooses allocation regime
  
 +Note that as of 0.0.2.dev libradsec suffers from way too much focus on
 +the behaviour of a blocking client and is totally useless as a server.
 +Not only does it lack most of the functions needed for writing a
 +server but it also contains at least one architectural mishap which
 +kills the server idea.  A connection timeout (TCP) or a retransmit
 +timeout (UDP) will result in the event loop being broken.  The same is
 +thing will happen if there's an error on a TCP connection, f.ex. a
 +failing certificate validation (TLS).
  * Dependencies
  Details apply to Ubuntu 10.10.
  
- - libfreeradius-radius (2.1.9+dfsg-1ubuntu1)
-   sudo apt-get install libfreeradius-dev libfreeradius2
  - libconfuse (2.7-1)
    sudo apt-get install libconfuse-dev libconfuse0
  - libevent from source (release-2.0.10-stable)
  - [TCP] short read
  - [TCP] short write
  - [TLS] basic tls support
 +- [TLS] preshared key support
 +- [TLS] verification of CN
  ** Known issues
  - error stack is only one entry deep
  - custom allocation scheme is not used in all places
  ** Not implemented
  - server failover
 -- [TLS] verification of CN
 -- [TLS] preshared key support
  - [DTLS] support
  
  * Found a bug?
diff --combined lib/Makefile.am
@@@ -1,23 -1,7 +1,23 @@@
  AUTOMAKE_OPTIONS = foreign
  ACLOCAL_AMFLAGS = -I m4
  
- SUBDIRS = . examples include 
 +# Shared library interface version, i.e. -version-info to Libtool,
 +# expressed as three integers CURRENT:REVISION:AGE.
 +
 +# CURRENT is the version number of the current interface.  Increment
 +#       CURRENT when the library interface changes.
 +
 +# REVISION is the version number of the _implementation_ of the
 +#          CURRENT interface.  Set REVISION to 0 when CURRENT changes,
 +#          else increment.
 +
 +# AGE is the number of interfaces this library implements, i.e. how
 +#     many versions before CURRENT that are supported.  Increment AGE
 +#     when the library interface is _extended_.  Set AGE to 0 when the
 +#     library interface is _changed_.
 +
 +
+ SUBDIRS = radius . include examples
  
  INCLUDES = -I$(srcdir)/include
  AM_CFLAGS = -Wall -g
@@@ -25,6 -9,7 +25,7 @@@
  lib_LTLIBRARIES = libradsec.la
  
  libradsec_la_SOURCES = \
+       avp.c \
        compat.c \
        conf.c \
        conn.c \
@@@ -37,8 -22,7 +38,8 @@@
        request.c \
        send.c \
        tcp.c \
 -      udp.c
 +      udp.c \
 +      util.c
  
  libradsec_la_SOURCES += \
        rsp_debug.c \
@@@ -52,5 -36,6 +53,6 @@@ libradsec_la_SOURCES += 
        rsp_tlscommon.c
  endif
  
+ libradsec_la_LIBADD = radius/libradsec-radius.la
  libradsec_la_LDFLAGS = -version-info 0:0:0 -export-symbols radsec.sym
- libradsec_la_CFLAGS = $(AM_CFLAGS) -DDEBUG -DDEBUG_LEVENT 
+ libradsec_la_CFLAGS = $(AM_CFLAGS) -DHAVE_CONFIG_H -Werror # -DDEBUG -DDEBUG_LEVENT 
diff --combined lib/conf.c
@@@ -6,17 -6,15 +6,17 @@@
  #endif
  
  #include <confuse.h>
+ #include <stdlib.h>
  #include <string.h>
 +#include <assert.h>
  #include <radsec/radsec.h>
  #include <radsec/radsec-impl.h>
  #include "peer.h"
 +#include "util.h"
  #include "debug.h"
  
  #if 0
    # common config options
-   dictionary = STRING
  
    # common realm config options
    realm NAME {
        #cacertpath = STRING
        certfile = STRING
        certkeyfile = STRING
 +      pskstr = STRING # Transport pre-shared key, UTF-8 form.
 +      pskhexstr = STRING # Transport pre-shared key, ASCII hex form.
 +      pskid = STRING
 +      pskex = "PSK"|"DHE_PSK"|"RSA_PSK"
    }
  
    # client specific realm config options
        server {
            hostname = STRING
          service = STRING
 -        secret = STRING
 +          secret = STRING       # RADIUS secret
        }
    }
  #endif
  
 -/* FIXME: Leaking memory in error cases?  */
 +/* FIXME: Leaking memory in error cases.  */
  int
  rs_context_read_config(struct rs_context *ctx, const char *config_file)
  {
        /*CFG_STR ("cacertpath", NULL, CFGF_NONE),*/
        CFG_STR ("certfile", NULL, CFGF_NONE),
        CFG_STR ("certkeyfile", NULL, CFGF_NONE),
 +      CFG_STR ("pskstr", NULL, CFGF_NONE),
 +      CFG_STR ("pskhexstr", NULL, CFGF_NONE),
 +      CFG_STR ("pskid", NULL, CFGF_NONE),
 +      CFG_STR ("pskex", "PSK", CFGF_NONE),
        CFG_SEC ("server", server_opts, CFGF_MULTI),
        CFG_END ()
      };
    cfg_opt_t opts[] =
      {
-       CFG_STR ("dictionary", NULL, CFGF_NONE),
        CFG_SEC ("realm", realm_opts, CFGF_TITLE | CFGF_MULTI),
        CFG_END ()
      };
    if (config == NULL)
      return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
    ctx->config = config;
-   config->dictionary = cfg_getstr (cfg, "dictionary");
  
    for (i = 0; i < cfg_size (cfg, "realm"); i++)
      {
        struct rs_realm *r = NULL;
        const char *typestr;
 +      char *pskstr = NULL, *pskhexstr = NULL;
  
        r = rs_calloc (ctx, 1, sizeof(*r));
        if (r == NULL)
          config->realms = r;
        }
        cfg_realm = cfg_getnsec (cfg, "realm", i);
 -      /* We use a copy of the return value of cfg_title() since it's const.  */
        s = cfg_title (cfg_realm);
        if (s == NULL)
        return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__,
                                   "missing realm name");
 -      r->name = strdup (s);
 +      /* We use a copy of the return value of cfg_title() since it's const.  */
 +      r->name = rs_strdup (ctx, s);
        if (r->name == NULL)
 -      return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
 +      return RSE_NOMEM;
  
        typestr = cfg_getstr (cfg_realm, "type");
        if (strcmp (typestr, "UDP") == 0)
        else if (strcmp (typestr, "DTLS") == 0)
        r->type = RS_CONN_TYPE_DTLS;
        else
 -      return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__,
 -                                 "invalid connection type: %s", typestr);
 +      return rs_err_ctx_push (ctx, RSE_CONFIG,
 +                                "%s: invalid connection type: %s",
 +                                r->name, typestr);
        r->timeout = cfg_getint (cfg_realm, "timeout");
        r->retries = cfg_getint (cfg_realm, "retries");
  
        r->certfile = cfg_getstr (cfg_realm, "certfile");
        r->certkeyfile = cfg_getstr (cfg_realm, "certkeyfile");
  
 +      pskstr = cfg_getstr (cfg_realm, "pskstr");
 +      pskhexstr = cfg_getstr (cfg_realm, "pskhexstr");
 +      if (pskstr || pskhexstr)
 +        {
 +#if defined RS_ENABLE_TLS_PSK
 +          char *kex = cfg_getstr (cfg_realm, "pskex");
 +          rs_cred_type_t type = RS_CRED_NONE;
 +          struct rs_credentials *cred = NULL;
 +          assert (kex != NULL);
 +
 +          if (!strcmp (kex, "PSK"))
 +            type = RS_CRED_TLS_PSK;
 +          else
 +            {
 +              /* TODO: push a warning on the error stack:*/
 +              /*rs_err_ctx_push (ctx, RSE_WARN, "%s: unsupported PSK key exchange"
 +                               " algorithm -- PSK not used", kex);*/
 +            }
 +
 +          if (type != RS_CRED_NONE)
 +            {
 +              cred = rs_calloc (ctx, 1, sizeof (*cred));
 +              if (cred == NULL)
 +                return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
 +                                           NULL);
 +              cred->type = type;
 +              cred->identity = cfg_getstr (cfg_realm, "pskid");
 +              if (pskhexstr)
 +                {
 +                  cred->secret_encoding = RS_KEY_ENCODING_ASCII_HEX;
 +                  cred->secret = pskhexstr;
 +                  if (pskstr)
 +                    ;      /* TODO: warn that we're ignoring pskstr */
 +                }
 +              else
 +                {
 +                  cred->secret_encoding = RS_KEY_ENCODING_UTF8;
 +                  cred->secret = pskstr;
 +                }
 +
 +              r->transport_cred = cred;
 +            }
 +#else  /* !RS_ENABLE_TLS_PSK */
 +          /* TODO: push a warning on the error stack: */
 +          /* rs_err_ctx_push (ctx, RSE_WARN, "libradsec wasn't configured with "
 +                           "support for TLS preshared keys, ignoring pskstr "
 +                           "and pskhexstr");*/
 +#endif  /* RS_ENABLE_TLS_PSK */
 +        }
 +
 +      /* For TLS and DTLS realms, validate that we either have (i) CA
 +         cert file or path or (ii) PSK.  */
 +      if ((r->type == RS_CONN_TYPE_TLS || r->type == RS_CONN_TYPE_DTLS)
 +          && (r->cacertfile == NULL && r->cacertpath == NULL)
 +          && r->transport_cred == NULL)
 +        return rs_err_ctx_push (ctx, RSE_CONFIG,
 +                                "%s: missing both CA file/path and PSK",
 +                                r->name);
 +
        /* Add peers, one per server stanza.  */
        for (j = 0; j < cfg_size (cfg_realm, "server"); j++)
        {
          p->realm = r;
  
          cfg_server = cfg_getnsec (cfg_realm, "server", j);
 -        /* FIXME: Handle resolve errors, possibly by postponing name
 -           resolution.  */
 -        rs_resolv (&p->addr, r->type, cfg_getstr (cfg_server, "hostname"),
 -                   cfg_getstr (cfg_server, "service"));
 +        p->hostname = cfg_getstr (cfg_server, "hostname");
 +          p->service = cfg_getstr (cfg_server, "service");
          p->secret = cfg_getstr (cfg_server, "secret");
        }
      }
diff --combined lib/configure.ac
@@@ -17,30 -17,21 +17,29 @@@ AC_CHECK_LIB([confuse], [cfg_init],
      AC_MSG_ERROR([required library libconfuse not found]))
  AC_CHECK_LIB([event_core], [event_get_version],,
      AC_MSG_ERROR([required library libevent_core not found]))
- AC_CHECK_LIB([freeradius-radius], [rad_alloc],,
-     AC_MSG_ERROR([required library libfreeradius-radius not found]))
  
  # Enable-knobs.
 +## Enable TLS (RadSec).
  AH_TEMPLATE([RS_ENABLE_TLS], [TLS (RadSec) enabled])
 -AH_TEMPLATE([RADPROT_TLS], [])
 +AH_TEMPLATE([RADPROT_TLS], [])  dnl Legacy.
  AC_ARG_ENABLE([tls], AS_HELP_STRING([--enable-tls], [enable TLS (RadSec)]),
      [AC_CHECK_LIB([event_openssl], [bufferevent_openssl_socket_new],,
           AC_MSG_ERROR([required library event_openssl not found]))
       AC_DEFINE([RS_ENABLE_TLS])
 -     AC_DEFINE([RADPROT_TLS])])
 +     AC_DEFINE([RADPROT_TLS])]) dnl Legacy.
  AM_CONDITIONAL([RS_ENABLE_TLS], [test "${enable_tls+set}" = set])
 +## Enable TLS-PSK (preshared keys).
 +AH_TEMPLATE([RS_ENABLE_TLS_PSK], [TLS-PSK (TLS preshared keys) enabled])
 +AC_ARG_ENABLE([tls-psk], AS_HELP_STRING([--enable-tls-psk], [enable TLS-PSK (TLS preshared keys)]),
 +    [AC_CHECK_LIB([ssl], [SSL_set_psk_client_callback],,
 +         AC_MSG_ERROR([required library openssl with SSL_set_psk_client_callback() not found]))
 +     AC_DEFINE([RS_ENABLE_TLS_PSK])])
 +AM_CONDITIONAL([RS_ENABLE_TLS_PSK], [test "${enable_tls_psk+set}" = set])
  
  # Checks for header files.
  AC_CHECK_HEADERS(
-     [netdb.h netinet/in.h stdint.h stdlib.h string.h sys/socket.h unistd.h])
+     [sys/time.h time.h netdb.h netinet/in.h stdint.h stdlib.h strings.h string.h \
+      sys/socket.h unistd.h syslog.h sys/select.h fcntl.h arpa/inet.h])
  
  # Checks for typedefs, structures, and compiler characteristics.
  AC_TYPE_SIZE_T
@@@ -51,6 -42,7 +50,7 @@@ AC_TYPE_UINT8_
  AC_CHECK_FUNCS([memset socket strdup strerror strrchr])
  
  AC_CONFIG_FILES([Makefile
+                radius/Makefile
                 include/Makefile
                   examples/Makefile
                   tests/Makefile])
diff --combined lib/conn.c
@@@ -6,6 -6,8 +6,8 @@@
  #endif
  
  #include <string.h>
+ #include <stdlib.h>
+ #include <errno.h>
  #include <assert.h>
  #include <event2/event.h>
  #include <event2/bufferevent.h>
@@@ -222,7 -224,7 +224,7 @@@ rs_conn_receive_packet (struct rs_conne
  
    assert (conn);
    assert (conn->realm);
 -  assert (!conn_user_dispatch_p (conn)); /* Dispatching mode only.  */
 +  assert (!conn_user_dispatch_p (conn)); /* Blocking mode only.  */
  
    if (rs_packet_create (conn, &pkt))
      return -1;
                                    "event_add: %s",
                                    evutil_gai_strerror (err));
  
 -      /* Activae retransmission timer.  */
 +      /* Activate retransmission timer.  */
        conn_activate_timeout (pkt->conn);
      }
  
        || (req_msg
          && packet_verify_response (pkt->conn, pkt, req_msg) != RSE_OK))
      {
 -      assert (rs_err_conn_peek_code (pkt->conn));
 +      if (rs_err_conn_peek_code (pkt->conn) == RSE_OK)
 +        /* No packet and no error on the stack _should_ mean that the
 +           server hung up on us.  */
 +        rs_err_conn_push (pkt->conn, RSE_DISCO, "no response");
        return rs_err_conn_peek_code (conn);
      }
  
diff --combined lib/err.c
+++ b/lib/err.c
@@@ -6,35 -6,56 +6,58 @@@
  #endif
  
  #include <stdio.h>
+ #include <stdlib.h>
  #include <string.h>
  #include <assert.h>
  #include <radsec/radsec.h>
  #include <radsec/radsec-impl.h>
  
  static const char *_errtxt[] = {
-   "SUCCESS",                  /* 0 RSE_OK */
-   "out of memory",            /* 1 RSE_NOMEM */
-   "not yet implemented",      /* 2 RSE_NOSYS */
-   "invalid handle",           /* 3 RSE_INVALID_CTX */
-   "invalid connection",               /* 4 RSE_INVALID_CONN */
-   "connection type mismatch", /* 5 RSE_CONN_TYPE_MISMATCH */
-   "FreeRadius error",         /* 6 RSE_FR */
-   "bad hostname or port",     /* 7 RSE_BADADDR */
-   "no peer configured",               /* 8 RSE_NOPEER */
-   "libevent error",           /* 9 RSE_EVENT */
-   "socket error",             /* 10 RSE_SOCKERR */
-   "invalid configuration file",       /* 11 RSE_CONFIG */
-   "authentication failed",    /* 12 RSE_BADAUTH */
-   "internal error",           /* 13 RSE_INTERNAL */
-   "SSL error",                        /* 14 RSE_SSLERR */
-   "invalid packet",           /* 15 RSE_INVALID_PKT */
-   "connect timeout",          /* 16 RSE_TIMEOUT_CONN */
-   "invalid argument",         /* 17 RSE_INVAL */
-   "I/O timeout",              /* 18 RSE_TIMEOUT_IO */
-   "timeout",                  /* 19 RSE_TIMEOUT */
-   "peer disconnected",                /* 20 RSE_DISCO */
-   "invalid credentials",        /* 21 RSE_CRED */
-   "certificate validation error", /* 22 RSE_CERT */
+   "SUCCESS",                                  /* 0 RSE_OK */
+   "out of memory",                            /* 1 RSE_NOMEM */
+   "not yet implemented",                      /* 2 RSE_NOSYS */
+   "invalid handle",                           /* 3 RSE_INVALID_CTX */
+   "invalid connection",                               /* 4 RSE_INVALID_CONN */
+   "connection type mismatch",                 /* 5 RSE_CONN_TYPE_MISMATCH */
+   "FreeRadius error",                         /* 6 RSE_FR */
+   "bad hostname or port",                     /* 7 RSE_BADADDR */
+   "no peer configured",                               /* 8 RSE_NOPEER */
+   "libevent error",                           /* 9 RSE_EVENT */
+   "socket error",                             /* 10 RSE_SOCKERR */
+   "invalid configuration file",                       /* 11 RSE_CONFIG */
+   "authentication failed",                    /* 12 RSE_BADAUTH */
+   "internal error",                           /* 13 RSE_INTERNAL */
+   "SSL error",                                        /* 14 RSE_SSLERR */
+   "invalid packet",                           /* 15 RSE_INVALID_PKT */
+   "connect timeout",                          /* 16 RSE_TIMEOUT_CONN */
+   "invalid argument",                         /* 17 RSE_INVAL */
+   "I/O timeout",                              /* 18 RSE_TIMEOUT_IO */
+   "timeout",                                  /* 19 RSE_TIMEOUT */
+   "peer disconnected",                                /* 20 RSE_DISCO */
+   "resource is in use",                               /* 21 RSE_INUSE */
+   "packet is too small",                      /* 22 RSE_PACKET_TOO_SMALL */
+   "packet is too large",                      /* 23 RSE_PACKET_TOO_LARGE */
+   "attribute overflows packet",                       /* 24 RSE_ATTR_OVERFLOW */
+   "attribute is too small",                   /* 25 RSE_ATTR_TOO_SMALL */
+   "attribute is too large",                   /* 26 RSE_ATTR_TOO_LARGE */
+   "unknown attribute",                                /* 27 RSE_ATTR_UNKNOWN */
+   "invalid name for attribute",                       /* 28 RSE_ATTR_BAD_NAME */
+   "invalid value for attribute",              /* 29 RSE_ATTR_VALUE_MALFORMED */
+   "invalid attribute",                                /* 30 RSE_ATTR_INVALID */
+   "too many attributes in the packet",                /* 31 RSE_TOO_MANY_ATTRS */
+   "attribute type unknown",                   /* 32 RSE_ATTR_TYPE_UNKNOWN */
+   "invalid message authenticator",            /* 33 RSE_MSG_AUTH_LEN */
+   "incorrect message authenticator",          /* 34 RSE_MSG_AUTH_WRONG */
+   "request is required",                      /* 35 RSE_REQUEST_REQUIRED */
+   "invalid request code",                     /* 36 RSE_REQUEST_CODE_INVALID */
+   "incorrect request authenticator",          /* 37 RSE_AUTH_VECTOR_WRONG */
+   "response code is unsupported",             /* 38 RSE_INVALID_RESPONSE_CODE */
+   "response ID is invalid",                   /* 39 RSE_INVALID_RESPONSE_ID */
+   "response from the wrong source address",   /* 40 RSE_INVALID_RESPONSE_SRC */
+   "no packet data",                           /* 41 RSE_NO_PACKET_DATA */
+   "vendor is unknown",                                /* 42 RSE_VENDOR_UNKNOWN */
++  "invalid credentials",                        /* 43 RSE_CRED */
++  "certificate validation error",               /* 44 RSE_CERT */
  };
  #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt))
  
diff --combined lib/event.c
@@@ -6,6 -6,9 +6,9 @@@
  #endif
  
  #include <assert.h>
+ #include <string.h>
+ #include <errno.h>
  #include <event2/event.h>
  #include <event2/bufferevent.h>
  #if defined (RS_ENABLE_TLS)
@@@ -19,8 -22,6 +22,8 @@@
  #if defined (RS_ENABLE_TLS)
  #include "tls.h"
  #endif
 +#include "err.h"
 +#include "radsec.h"
  #include "event.h"
  #include "packet.h"
  #include "conn.h"
@@@ -99,16 -100,9 +102,16 @@@ event_init_socket (struct rs_connectio
    if (conn->fd != -1)
      return RSE_OK;
  
 -  assert (p->addr);
 -  conn->fd = socket (p->addr->ai_family, p->addr->ai_socktype,
 -                   p->addr->ai_protocol);
 +  if (p->addr_cache == NULL)
 +    {
 +      struct rs_error *err =
 +        rs_resolve (&p->addr_cache, p->realm->type, p->hostname, p->service);
 +      if (err != NULL)
 +        return err_conn_push_err (conn, err);
 +    }
 +
 +  conn->fd = socket (p->addr_cache->ai_family, p->addr_cache->ai_socktype,
 +                   p->addr_cache->ai_protocol);
    if (conn->fd < 0)
      return rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,
                                "socket: %d (%s)",
@@@ -177,8 -171,8 +180,8 @@@ event_do_connect (struct rs_connection 
    {
      char host[80], serv[80];
  
 -    getnameinfo (p->addr->ai_addr,
 -               p->addr->ai_addrlen,
 +    getnameinfo (p->addr_cache->ai_addr,
 +               p->addr_cache->ai_addrlen,
                 host, sizeof(host), serv, sizeof(serv),
                 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
      rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));
    if (p->conn->bev)           /* TCP */
      {
        conn_activate_timeout (conn); /* Connect timeout.  */
 -      err = bufferevent_socket_connect (p->conn->bev, p->addr->ai_addr,
 -                                      p->addr->ai_addrlen);
 +      err = bufferevent_socket_connect (p->conn->bev, p->addr_cache->ai_addr,
 +                                      p->addr_cache->ai_addrlen);
        if (err < 0)
        rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__,
                             "bufferevent_socket_connect: %s",
      }
    else                                /* UDP */
      {
 -      err = connect (p->conn->fd, p->addr->ai_addr, p->addr->ai_addrlen);
 +      err = connect (p->conn->fd,
 +                     p->addr_cache->ai_addr,
 +                     p->addr_cache->ai_addrlen);
        if (err < 0)
        {
          sockerr = evutil_socket_geterror (p->conn->fd);
@@@ -236,22 -228,10 +239,22 @@@ event_on_disconnect (struct rs_connecti
      conn->callbacks.disconnected_cb (conn->user_data);
  }
  
 -void
 +/** Internal connect event returning 0 on success or -1 on error.  */
 +int
  event_on_connect (struct rs_connection *conn, struct rs_packet *pkt)
  {
    assert (!conn->is_connecting);
 +
 +#if defined (RS_ENABLE_TLS)
 +  if (conn->realm->type == RS_CONN_TYPE_TLS
 +      || conn->realm->type == RS_CONN_TYPE_DTLS)
 +    if (tls_verify_cert (conn) != RSE_OK)
 +      {
 +        rs_debug (("%s: server cert verification failed\n", __func__));
 +        return -1;
 +      }
 +#endif        /* RS_ENABLE_TLS */
 +
    conn->is_connected = 1;
    rs_debug (("%s: %p connected\n", __func__, conn->active_peer));
  
  
    if (pkt)
      packet_do_send (pkt);
 +
 +  return 0;
  }
  
  int
@@@ -4,12 -4,10 +4,12 @@@
  #include <string.h>
  #include <unistd.h>
  #include <stdlib.h>
 +#include <assert.h>
  #include <event2/event.h>
- #include <freeradius/libradius.h>
  #include <radsec/radsec.h>
+ #include <radsec/radsec-impl.h>
  #include <radsec/request.h>
 +#include "err.h"
  #include "debug.h"            /* For rs_dump_packet().  */
  
  #define SECRET "sikrit"
@@@ -17,8 -15,7 +17,8 @@@
  #define USER_PW "password"
  
  struct rs_error *
 -blocking_client (const char *av1, const char *av2, int use_request_object_flag)
 +blocking_client (const char *config_fn, const char *configuration,
 +                 int use_request_object_flag)
  {
    struct rs_context *h = NULL;
    struct rs_connection *conn = NULL;
    struct rs_error *err = NULL;
  
    if (rs_context_create (&h))
 -    return NULL;
 +    {
 +      err = err_create (RSE_INTERNAL, NULL, 0, "unable to create context");
 +      assert (err != NULL);
 +      return err;
 +    }
  
  #if !defined (USE_CONFIG_FILE)
    {
      struct rs_peer *server;
  
-     if (rs_context_init_freeradius_dict (h, "/usr/share/freeradius/dictionary"))
-       goto cleanup;
      if (rs_conn_create (h, &conn, NULL))
        goto cleanup;
      rs_conn_set_type (conn, RS_CONN_TYPE_UDP);
        goto cleanup;
    }
  #else  /* defined (USE_CONFIG_FILE) */
 -  if (rs_context_read_config (h, av1))
 +  if (rs_context_read_config (h, config_fn))
      goto cleanup;
-   if (rs_context_init_freeradius_dict (h, NULL))
-     goto cleanup;
 -  if (rs_conn_create (h, &conn, av2))
 +  if (rs_conn_create (h, &conn, configuration))
      goto cleanup;
  #endif        /* defined (USE_CONFIG_FILE) */
  
    if (resp)
      {
        rs_dump_packet (resp);
-       if (rs_packet_frpkt (resp)->code == PW_AUTHENTICATION_ACK)
+       if (rs_packet_code (resp) == PW_ACCESS_ACCEPT)
        printf ("Good auth.\n");
        else
-       printf ("Bad auth: %d\n", rs_packet_frpkt (resp)->code);
+       printf ("Bad auth: %d\n", rs_packet_code (resp));
      }
    else
      fprintf (stderr, "%s: no response\n", __func__);
    return err;
  }
  
 +void
 +usage (int argc, char *argv[])
 +{
 +  fprintf (stderr, "usage: %s: [-r] config-file config-name\n", argv[0]);
 +  exit (1);
 +}
 +
  int
  main (int argc, char *argv[])
  {
        argc--;
        argv++;
      }
 +  if (argc < 3)
 +    usage (argc, argv);
    err = blocking_client (argv[1], argv[2], use_request_object_flag);
    if (err)
      {
diff --combined lib/examples/client.conf
@@@ -1,5 -1,3 +1,3 @@@
- dictionary = "/home/linus/usr/moonshot/share/freeradius/dictionary"
  realm blocking-udp {
      type = "UDP"
      timeout = 2
@@@ -18,10 -16,6 +16,10 @@@ realm blocking-tls 
      cacertfile = "tests/demoCA/newcerts/01.pem"
      certfile = "tests/demoCA/newcerts/02.pem"
      certkeyfile = "tests/demoCA/private/c2key.pem"
 +    #pskstr = "sikrit psk"
 +    pskhexstr = "deadbeef4711"
 +    pskid = "Client_identity"
 +    pskex = "PSK"
      server {
          hostname = "localhost"
        service = "2083"
@@@ -3,7 -3,9 +3,9 @@@
  
  /* See the file COPYING for licensing information.  */
  
- #include <freeradius/libradius.h>
+ #ifndef _RADSEC_RADSEC_IMPL_H_
+ #define _RADSEC_RADSEC_IMPL_H_ 1
  #include <event2/util.h>
  #include <confuse.h>
  #if defined(RS_ENABLE_TLS)
  /* Data types.  */
  enum rs_cred_type {
      RS_CRED_NONE = 0,
 -    RS_CRED_TLS_PSK_RSA,      /* RFC 4279.  */
 +    /* TLS pre-shared keys, RFC 4279.  */
 +    RS_CRED_TLS_PSK,
 +    /* RS_CRED_TLS_DH_PSK, */
 +    /* RS_CRED_TLS_RSA_PSK, */
  };
  typedef unsigned int rs_cred_type_t;
  
 +enum rs_key_encoding {
 +    RS_KEY_ENCODING_UTF8 = 1,
 +    RS_KEY_ENCODING_ASCII_HEX = 2,
 +};
 +typedef unsigned int rs_key_encoding_t;
 +
  #if defined (__cplusplus)
  extern "C" {
  #endif
@@@ -37,8 -30,6 +39,8 @@@ struct rs_credentials 
      enum rs_cred_type type;
      char *identity;
      char *secret;
 +    enum rs_key_encoding secret_encoding;
 +    unsigned int secret_len;
  };
  
  struct rs_error {
  struct rs_peer {
      struct rs_connection *conn;
      struct rs_realm *realm;
 -    struct evutil_addrinfo *addr;
 -    char *secret;
 +    char *hostname;
 +    char *service;
 +    char *secret;               /* RADIUS secret.  */
 +    struct evutil_addrinfo *addr_cache;
      struct rs_peer *next;
  };
  
@@@ -67,14 -56,12 +69,13 @@@ struct rs_realm 
      char *cacertpath;
      char *certfile;
      char *certkeyfile;
 +    struct rs_credentials *transport_cred;
      struct rs_peer *peers;
      struct rs_realm *next;
  };
  
  /** Top configuration object.  */
  struct rs_config {
-     char *dictionary;
      struct rs_realm *realms;
      cfg_t *cfg;
  };
@@@ -83,7 -70,6 +84,6 @@@ struct rs_context 
      struct rs_config *config;
      struct rs_alloc_scheme alloc_scheme;
      struct rs_error *err;
-     fr_randctx fr_randctx;
  };
  
  struct rs_connection {
@@@ -91,6 -77,7 +91,6 @@@
      struct rs_realm *realm;   /* Owned by ctx.  */
      struct event_base *evb;   /* Event base.  */
      struct event *tev;                /* Timeout event.  */
 -    struct rs_credentials transport_credentials;
      struct rs_conn_callbacks callbacks;
      void *user_data;
      struct rs_peer *peers;
@@@ -121,14 -108,22 +121,16 @@@ enum rs_packet_flags 
      rs_packet_sent_flag,
  };
  
+ struct radius_packet;
  struct rs_packet {
      struct rs_connection *conn;
      unsigned int flags;
      uint8_t hdr[RS_HEADER_LEN];
-     RADIUS_PACKET *rpkt;      /* FreeRADIUS object.  */
+     struct radius_packet *rpkt;       /* FreeRADIUS object.  */
      struct rs_packet *next;   /* Used for UDP output queue.  */
  };
  
 -/* Nonpublic functions (in radsec.c -- FIXME: move?).  */
 -struct rs_error *rs_resolv (struct evutil_addrinfo **addr,
 -                          rs_conn_type_t type,
 -                          const char *hostname,
 -                          const char *service);
 -
  #if defined (__cplusplus)
  }
  #endif
  #define min(a, b) ((a) < (b) ? (a) : (b))
  #define max(a, b) ((a) > (b) ? (a) : (b))
  
+ #endif /* _RADSEC_RADSEC_IMPL_H_ */
  /* Local Variables: */
  /* c-file-style: "stroustrup" */
  /* End: */
@@@ -3,14 -3,24 +3,24 @@@
  
  /* See the file COPYING for licensing information.  */
  
- #include <unistd.h>
- #include <sys/time.h>
+ #ifndef _RADSEC_RADSEC_H_
+ #define _RADSEC_RADSEC_H_ 1
  
- #ifdef SYSCONFDIR
- #define RS_FREERADIUS_DICT SYSCONFDIR "/raddb/dictionary"
- #else  /* !SYSCONFDIR */
- #define RS_FREERADIUS_DICT "/usr/local/raddb/dictionary"
- #endif  /* !SYSCONFDIR */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+ #ifdef HAVE_SYS_TIME_H
+ #include <sys/time.h>
+ #endif
+ #ifdef HAVE_ARPA_INET_H
+ #include <arpa/inet.h>
+ #endif
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+ #ifdef HAVE_STDINT_H
+ #include <stdint.h>
+ #endif
  
  enum rs_error_code {
      RSE_OK = 0,
@@@ -19,7 -29,7 +29,7 @@@
      RSE_INVALID_CTX = 3,
      RSE_INVALID_CONN = 4,
      RSE_CONN_TYPE_MISMATCH = 5,
-     RSE_FR = 6,                       /* FreeRADIUS error.  */
+     RSE_FR = 6,
      RSE_BADADDR = 7,
      RSE_NOPEER = 8,
      RSE_EVENT = 9,            /* libevent error.  */
      RSE_TIMEOUT_CONN = 16,    /* Connection timeout.  */
      RSE_INVAL = 17,           /* Invalid argument.  */
      RSE_TIMEOUT_IO = 18,      /* I/O timeout.  */
 -    RSE_TIMEOUT= 19,          /* High level timeout.  */
 +    RSE_TIMEOUT = 19,         /* High level timeout.  */
      RSE_DISCO = 20,
-     RSE_CRED = 21,              /* Credentials.  */
-     RSE_CERT = 22,              /* Cert validation.  */
+     RSE_INUSE = 21,
+     RSE_PACKET_TOO_SMALL = 22,
+     RSE_PACKET_TOO_LARGE = 23,
+     RSE_ATTR_OVERFLOW = 24,
+     RSE_ATTR_TOO_SMALL = 25,
+     RSE_ATTR_TOO_LARGE = 26,
+     RSE_ATTR_UNKNOWN = 27,
+     RSE_ATTR_BAD_NAME = 28,
+     RSE_ATTR_VALUE_MALFORMED = 29,
+     RSE_ATTR_INVALID = 30,
+     RSE_TOO_MANY_ATTRS = 31,
+     RSE_ATTR_TYPE_UNKNOWN = 32,
+     RSE_MSG_AUTH_LEN = 33,
+     RSE_MSG_AUTH_WRONG = 34,
+     RSE_REQUEST_REQUIRED = 35,
+     RSE_INVALID_REQUEST_CODE = 36,
+     RSE_AUTH_VECTOR_WRONG = 37,
+     RSE_INVALID_RESPONSE_CODE = 38,
+     RSE_INVALID_RESPONSE_ID = 39,
+     RSE_INVALID_RESPONSE_SRC = 40,
+     RSE_NO_PACKET_DATA = 41,
+     RSE_VENDOR_UNKNOWN = 42,
 -    RSE_MAX = RSE_VENDOR_UNKNOWN
++    RSE_CRED = 43,
++    RSE_CERT = 44,
++    RSE_MAX = RSE_CERT
  };
  
  enum rs_conn_type {
  };
  typedef unsigned int rs_conn_type_t;
  
+ typedef enum rs_attr_type_t {
+     RS_TYPE_INVALID = 0,              /**< Invalid data type */
+     RS_TYPE_STRING,                   /**< printable-text */
+     RS_TYPE_INTEGER,                  /**< a 32-bit unsigned integer */
+     RS_TYPE_IPADDR,                   /**< an IPv4 address */
+     RS_TYPE_DATE,                     /**< a 32-bit date, of seconds since January 1, 1970 */
+     RS_TYPE_OCTETS,                   /**< a sequence of binary octets */
+     RS_TYPE_IFID,                     /**< an Interface Id */
+     RS_TYPE_IPV6ADDR,                 /**< an IPv6 address */
+     RS_TYPE_IPV6PREFIX,                       /**< an IPv6 prefix */
+     RS_TYPE_BYTE,                     /**< an 8-bit integer */
+     RS_TYPE_SHORT,                    /**< a 16-bit integer */
+ } rs_attr_type_t;
+ #define       PW_ACCESS_REQUEST               1
+ #define       PW_ACCESS_ACCEPT                2
+ #define       PW_ACCESS_REJECT                3
+ #define       PW_ACCOUNTING_REQUEST           4
+ #define       PW_ACCOUNTING_RESPONSE          5
+ #define       PW_ACCOUNTING_STATUS            6
+ #define PW_PASSWORD_REQUEST           7
+ #define PW_PASSWORD_ACK                       8
+ #define PW_PASSWORD_REJECT            9
+ #define       PW_ACCOUNTING_MESSAGE           10
+ #define PW_ACCESS_CHALLENGE           11
+ #define PW_STATUS_SERVER              12
+ #define PW_STATUS_CLIENT              13
+ #define PW_DISCONNECT_REQUEST         40
+ #define PW_DISCONNECT_ACK             41
+ #define PW_DISCONNECT_NAK             42
+ #define PW_COA_REQUEST                        43
+ #define PW_COA_ACK                    44
+ #define PW_COA_NAK                    45
  
  #if defined (__cplusplus)
  extern "C" {
@@@ -59,7 -123,8 +125,8 @@@ struct rs_packet;           /* radsec-impl.h *
  struct rs_conn;                       /* radsec-impl.h */
  struct rs_error;              /* radsec-impl.h */
  struct rs_peer;                       /* radsec-impl.h */
- struct radius_packet;         /* <freeradius/libradius.h> */
+ struct radius_packet;         /* <radius/client.h> */
+ struct value_pair;            /* <radius/client.h> */
  struct event_base;            /* <event2/event-internal.h> */
  
  typedef void *(*rs_calloc_fp) (size_t nmemb, size_t size);
@@@ -89,6 -154,8 +156,8 @@@ struct rs_conn_callbacks 
      rs_conn_packet_sent_cb sent_cb;
  };
  
+ typedef struct value_pair rs_avp;
+ typedef const struct value_pair rs_const_avp;
  
  /* Function prototypes.  */
  
@@@ -109,20 -176,6 +178,6 @@@ int rs_context_create(struct rs_contex
      all other libradsec objects have been freed.  */
  void rs_context_destroy(struct rs_context *ctx);
  
- /** Initialize FreeRADIUS dictionary needed for creating packets.
-     \a ctx Context.
-     \a dict Optional string with full path to FreeRADIUS dictionary.
-     If \a dict is NULL the path to the dictionary file is taken from
-     the "dictionary" configuration directive.  Note that the
-     configuration file must be read prior to using this option (see \a
-     rs_context_read_config).
-     \return RSE_OK (0) on success, RSE_NOMEM on memory allocation
-     error and RSE_FR on FreeRADIUS error.  */
- int rs_context_init_freeradius_dict(struct rs_context *ctx, const char *dict);
  /** Set allocation scheme to use.  \a scheme is the allocation scheme
      to use, see \a rs_alloc_scheme.  \return On success, RSE_OK (0) is
      returned.  On error, !0 is returned and a struct \a rs_error is
@@@ -253,9 -306,6 +308,6 @@@ void rs_packet_destroy(struct rs_packe
      rs_err_conn_pop.  */
  int rs_packet_send(struct rs_packet *pkt, void *user_data);
  
- /** Return the FreeRADIUS packet associated with packet \a pkt.  */
- struct radius_packet *rs_packet_frpkt(struct rs_packet *pkt);
  /** Create a RADIUS authentication request packet associated with
      connection \a conn.  Optionally, User-Name and User-Password
      attributes are added to the packet using the data in \a user_name
@@@ -265,6 -315,28 +317,28 @@@ int rs_packet_create_authn_request(stru
                                   const char *user_name,
                                   const char *user_pw);
  
+ /*** Append \a tail to packet \a pkt.  */
+ int
+ rs_packet_append_avp(struct rs_packet *pkt,
+                    unsigned int attribute, unsigned int vendor,
+                    const void *data, size_t data_len);
+ /*** Get pointer to \a pkt attribute value pairs. */
+ void
+ rs_packet_avps(struct rs_packet *pkt, rs_avp ***vps);
+ /*** Get RADIUS packet type of \a pkt. */
+ unsigned int
+ rs_packet_code(struct rs_packet *pkt);
+ /*** Get RADIUS AVP from \a pkt. */
+ rs_const_avp *
+ rs_packet_find_avp(struct rs_packet *pkt, unsigned int attr, unsigned int vendor);
+ /*** Set packet identifier in \a pkt; returns old identifier */
+ int
+ rs_packet_set_id (struct rs_packet *pkt, int id);
  /************/
  /* Config.  */
  /************/
@@@ -311,10 -383,203 +385,203 @@@ void rs_err_free(struct rs_error *err)
  char *rs_err_msg(struct rs_error *err);
  int rs_err_code(struct rs_error *err, int dofree_flag);
  
+ /************/
+ /* AVPs.    */
+ /************/
+ #define rs_avp_is_string(vp)    (rs_avp_typeof(vp) == RS_TYPE_STRING)
+ #define rs_avp_is_integer(vp)   (rs_avp_typeof(vp) == RS_TYPE_INTEGER)
+ #define rs_avp_is_ipaddr(vp)    (rs_avp_typeof(vp) == RS_TYPE_IPADDR)
+ #define rs_avp_is_date(vp)      (rs_avp_typeof(vp) == RS_TYPE_DATE)
+ #define rs_avp_is_octets(vp)    (rs_avp_typeof(vp) == RS_TYPE_OCTETS)
+ #define rs_avp_is_ifid(vp)      (rs_avp_typeof(vp) == RS_TYPE_IFID)
+ #define rs_avp_is_ipv6addr(vp)          (rs_avp_typeof(vp) == RS_TYPE_IPV6ADDR)
+ #define rs_avp_is_ipv6prefix(vp)  (rs_avp_typeof(vp) == RS_TYPE_IPV6PREFIX)
+ #define rs_avp_is_byte(vp)      (rs_avp_typeof(vp) == RS_TYPE_BYTE)
+ #define rs_avp_is_short(vp)     (rs_avp_typeof(vp) == RS_TYPE_SHORT)
+ #define rs_avp_is_tlv(vp)       (rs_avp_typeof(vp) == RS_TYPE_TLV)
+ /**  The maximum length of a RADIUS attribute.
+  *
+  *  The RFCs require that a RADIUS attribute transport no more than
+  *  253 octets of data.  We add an extra byte for a trailing NUL, so
+  *  that the VALUE_PAIR::vp_strvalue field can be handled as a C
+  *  string.
+  */
+ #define RS_MAX_STRING_LEN         254
+ /** Free the AVP list \a vps */
+ void
+ rs_avp_free(rs_avp **vps);
+ /** Return the length of AVP \a vp in bytes */
+ size_t
+ rs_avp_length(rs_const_avp *vp);
+ /** Return the type of \a vp */
+ rs_attr_type_t
+ rs_avp_typeof(rs_const_avp *vp);
+ /** Retrieve the attribute and vendor ID of \a vp */
+ void
+ rs_avp_attrid(rs_const_avp *vp, unsigned int *attr, unsigned int *vendor);
+ /** Add \a vp to the list pointed to by \a head */
+ void
+ rs_avp_append(rs_avp **head, rs_avp *vp);
+ /** Find an AVP in \a vp that matches \a attr and \a vendor */
+ rs_avp *
+ rs_avp_find(rs_avp *vp, unsigned int attr, unsigned int vendor);
+ /** Find an AVP in \a vp that matches \a attr and \a vendor */
+ rs_const_avp *
+ rs_avp_find_const(rs_const_avp *vp, unsigned int attr, unsigned int vendor);
+ /** Alloc a new AVP for \a attr and \a vendor */
+ rs_avp *
+ rs_avp_alloc(unsigned int attr, unsigned int vendor);
+ /** Duplicate existing AVP \a vp */
+ rs_avp *
+ rs_avp_dup(rs_const_avp *vp);
+ /** Remove matching AVP from list \a vps */
+ int
+ rs_avp_delete(rs_avp **vps, unsigned int attr, unsigned int vendor);
+ /** Return next AVP in list */
+ rs_avp *
+ rs_avp_next(rs_avp *vp);
+ /** Return next AVP in list */
+ rs_const_avp *
+ rs_avp_next_const(rs_const_avp *avp);
+ /** Return string value of \a vp */
+ const char *
+ rs_avp_string_value(rs_const_avp *vp);
+ /** Set AVP \a vp to string \a str */
+ int
+ rs_avp_string_set(rs_avp *vp, const char *str);
+ /** Return integer value of \a vp */
+ uint32_t
+ rs_avp_integer_value(rs_const_avp *vp);
+ /** Set AVP \a vp to integer \a val */
+ int
+ rs_avp_integer_set(rs_avp *vp, uint32_t val);
+ /** Return IPv4 value of \a vp */
+ uint32_t
+ rs_avp_ipaddr_value(rs_const_avp *vp);
+ /** Set AVP \a vp to IPv4 address \a in */
+ int
+ rs_avp_ipaddr_set(rs_avp *vp, struct in_addr in);
+ /** Return POSIX time value of \a vp */
+ time_t
+ rs_avp_date_value(rs_const_avp *vp);
+ /** Set AVP \a vp to POSIX time \a date */
+ int
+ rs_avp_date_set(rs_avp *vp, time_t date);
+ /** Return constant pointer to octets in \a vp */
+ const unsigned char *
+ rs_avp_octets_value_const_ptr(rs_const_avp *vp);
+ /** Return pointer to octets in \a vp */
+ unsigned char *
+ rs_avp_octets_value_ptr(rs_avp *vp);
+ /** Retrieve octet pointer \a p and length \a len from \a vp */
+ int
+ rs_avp_octets_value_byref(rs_avp *vp,
+                         unsigned char **p,
+                         size_t *len);
+ /** Copy octets from \a vp into \a buf and \a len */
+ int
+ rs_avp_octets_value(rs_const_avp *vp,
+                   unsigned char *buf,
+                   size_t *len);
+ /**
+  * Copy octets possibly fragmented across multiple VPs
+  * into \a buf and \a len
+  */
+ int
+ rs_avp_fragmented_value(rs_const_avp *vps,
+                       unsigned char *buf,
+                       size_t *len);
+ /** Copy \a len octets in \a buf to AVP \a vp */
+ int
+ rs_avp_octets_set(rs_avp *vp,
+                 const unsigned char *buf,
+                 size_t len);
+ /** Return IFID value of \a vp */
+ int
+ rs_avp_ifid_value(rs_const_avp *vp, uint8_t val[8]);
+ int
+ rs_avp_ifid_set(rs_avp *vp, const uint8_t val[8]);
+ /** Return byte value of \a vp */
+ uint8_t
+ rs_avp_byte_value(rs_const_avp *vp);
+ /** Set AVP \a vp to byte \a val */
+ int
+ rs_avp_byte_set(rs_avp *vp, uint8_t val);
+ /** Return short value of \a vp */
+ uint16_t
+ rs_avp_short_value(rs_const_avp *vp);
+ /** Set AVP \a vp to short integer \a val */
+ int
+ rs_avp_short_set(rs_avp *vp, uint16_t val);
+ /** Display possibly \a canonical attribute name into \a buffer */
+ int
+ rs_attr_display_name (unsigned int attr,
+                       unsigned int vendor,
+                       char *buffer,
+                       size_t bufsize,
+                       int canonical);
+ /** Display AVP \a vp into \a buffer */
+ size_t
+ rs_avp_display_value(rs_const_avp *vp,
+                      char *buffer,
+                      size_t buflen);
+ int
+ rs_attr_parse_name (const char *name,
+                   unsigned int *attr,
+                   unsigned int *vendor);
+ /** Lookup attribute \a name */
+ int
+ rs_attr_find(const char *name,
+              unsigned int *attr,
+              unsigned int *vendor);
+ /** Return dictionary name for AVP \a vp */
+ const char *
+ rs_avp_name(rs_const_avp *vp);
  #if defined (__cplusplus)
  }
  #endif
  
+ #endif /* _RADSEC_RADSEC_H_ */
  /* Local Variables: */
  /* c-file-style: "stroustrup" */
  /* End: */
diff --combined lib/packet.c
@@@ -6,6 -6,7 +6,7 @@@
  #endif
  
  #include <assert.h>
+ #include <radius/client.h>
  #include <event2/bufferevent.h>
  #include <radsec/radsec.h>
  #include <radsec/radsec-impl.h>
@@@ -24,6 -25,8 +25,8 @@@ packet_verify_response (struct rs_conne
                        struct rs_packet *response,
                        struct rs_packet *request)
  {
+   int err;
    assert (conn);
    assert (conn->active_peer);
    assert (conn->active_peer->secret);
    assert (request);
    assert (request->rpkt);
  
+   response->rpkt->secret = conn->active_peer->secret;
+   response->rpkt->sizeof_secret = strlen (conn->active_peer->secret);
    /* Verify header and message authenticator.  */
-   if (rad_verify (response->rpkt, request->rpkt, conn->active_peer->secret))
+   err = nr_packet_verify (response->rpkt, request->rpkt);
+   if (err)
      {
-       conn_close (&conn);
-       return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__,
-                                 "rad_verify: %s", fr_strerror ());
+       if (conn->is_connected)
+       rs_conn_disconnect(conn);
+       return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,
+                                 "nr_packet_verify");
      }
  
    /* Decode and decrypt.  */
-   if (rad_decode (response->rpkt, request->rpkt, conn->active_peer->secret))
+   err = nr_packet_decode (response->rpkt, request->rpkt);
+   if (err)
      {
-       conn_close (&conn);
-       return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__,
-                                 "rad_decode: %s", fr_strerror ());
+       if (conn->is_connected)
+       rs_conn_disconnect(conn);
+       return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,
+                                 "nr_packet_decode");
      }
  
    return RSE_OK;
@@@ -57,7 -67,7 +67,7 @@@
  int
  packet_do_send (struct rs_packet *pkt)
  {
-   VALUE_PAIR *vp = NULL;
+   int err;
  
    assert (pkt);
    assert (pkt->conn);
    assert (pkt->conn->active_peer->secret);
    assert (pkt->rpkt);
  
-   /* Add a Message-Authenticator, RFC 2869, if not already present.  */
-   /* FIXME: Make Message-Authenticator optional?  */
-   vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
-   if (!vp)
-     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
-                               "paircreate: %s", fr_strerror ());
-   pairreplace (&pkt->rpkt->vps, vp);
+   pkt->rpkt->secret = pkt->conn->active_peer->secret;
+   pkt->rpkt->sizeof_secret = strlen (pkt->rpkt->secret);
  
    /* Encode message.  */
-   if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
-     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
-                               "rad_encode: %s", fr_strerror ());
+   err = nr_packet_encode (pkt->rpkt, NULL);
+   if (err < 0)
+     return rs_err_conn_push_fl (pkt->conn, -err, __FILE__, __LINE__,
+                               "nr_packet_encode");
    /* Sign message.  */
-   if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret))
-     return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
-                               "rad_sign: %s", fr_strerror ());
+   err = nr_packet_sign (pkt->rpkt, NULL);
+   if (err < 0)
+     return rs_err_conn_push_fl (pkt->conn, -err, __FILE__, __LINE__,
+                               "nr_packet_sign");
  #if defined (DEBUG)
    {
      char host[80], serv[80];
  
 -    getnameinfo (pkt->conn->active_peer->addr->ai_addr,
 -               pkt->conn->active_peer->addr->ai_addrlen,
 +    getnameinfo (pkt->conn->active_peer->addr_cache->ai_addr,
 +               pkt->conn->active_peer->addr_cache->ai_addrlen,
                 host, sizeof(host), serv, sizeof(serv),
                 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);
      rs_debug (("%s: about to send this to %s:%s:\n", __func__, host, serv));
    if (pkt->conn->bev)         /* TCP.  */
      {
        int err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data,
-                                  pkt->rpkt->data_len);
+                                  pkt->rpkt->length);
        if (err < 0)
        return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__,
                                    "bufferevent_write: %s",
@@@ -122,21 -129,36 +129,36 @@@ rs_packet_create (struct rs_connection 
  {
    struct rs_packet *p;
    RADIUS_PACKET *rpkt;
+   int err;
  
    *pkt_out = NULL;
  
-   rpkt = rad_alloc (1);
-   if (!rpkt)
+   rpkt = rs_malloc (conn->ctx, sizeof(*rpkt) + RS_MAX_PACKET_LEN);
+   if (rpkt == NULL)
      return rs_err_conn_push (conn, RSE_NOMEM, __func__);
-   rpkt->id = conn->nextid++;
  
-   p = (struct rs_packet *) malloc (sizeof (struct rs_packet));
-   if (!p)
+   /*
+    * This doesn't make sense; the packet identifier is constant for
+    * an entire conversation. A separate API should be provided to
+    * allow the application to set the packet ID, or a conversation
+    * object should group related packets together.
+    */
+ #if 0
+   rpkt->id = conn->nextid++
+ #endif
+   err = nr_packet_init (rpkt, NULL, NULL,
+                       PW_ACCESS_REQUEST,
+                       rpkt + 1, RS_MAX_PACKET_LEN);
+   if (err < 0)
+     return rs_err_conn_push (conn, -err, __func__);
+   p = (struct rs_packet *) rs_calloc (conn->ctx, 1, sizeof (*p));
+   if (p == NULL)
      {
-       rad_free (&rpkt);
+       rs_free (conn->ctx, rpkt);
        return rs_err_conn_push (conn, RSE_NOMEM, __func__);
      }
-   memset (p, 0, sizeof (struct rs_packet));
    p->conn = conn;
    p->rpkt = rpkt;
  
@@@ -150,41 -172,31 +172,31 @@@ rs_packet_create_authn_request (struct 
                                const char *user_name, const char *user_pw)
  {
    struct rs_packet *pkt;
-   VALUE_PAIR *vp = NULL;
+   int err;
  
    if (rs_packet_create (conn, pkt_out))
      return -1;
    pkt = *pkt_out;
-   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
+   pkt->rpkt->code = PW_ACCESS_REQUEST;
  
    if (user_name)
      {
-       vp = pairmake ("User-Name", user_name, T_OP_EQ);
-       if (vp == NULL)
-       return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__,
-                                   "pairmake: %s", fr_strerror ());
-       pairadd (&pkt->rpkt->vps, vp);
+       err = rs_packet_append_avp (pkt, PW_USER_NAME, 0, user_name, 0);
+       if (err)
+       return err;
      }
  
    if (user_pw)
      {
-       vp = pairmake ("User-Password", user_pw, T_OP_EQ);
-       if (vp == NULL)
-       return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__,
-                                   "pairmake: %s", fr_strerror ());
-       pairadd (&pkt->rpkt->vps, vp);
+       err = rs_packet_append_avp (pkt, PW_USER_PASSWORD, 0, user_pw, 0);
+       if (err)
+       return err;
      }
  
    return RSE_OK;
  }
  
- struct radius_packet *
- rs_packet_frpkt (struct rs_packet *pkt)
- {
-   assert (pkt);
-   return pkt->rpkt;
- }
  void
  rs_packet_destroy (struct rs_packet *pkt)
  {
    assert (pkt->conn);
    assert (pkt->conn->ctx);
  
-   rad_free (&pkt->rpkt); /* Note: This frees the VALUE_PAIR's too.  */
+   rs_avp_free (&pkt->rpkt->vps);
+   rs_free (pkt->conn->ctx, pkt->rpkt);
    rs_free (pkt->conn->ctx, pkt);
  }
+ int
+ rs_packet_append_avp (struct rs_packet *pkt, 
+                       unsigned int attr, unsigned int vendor,
+                       const void *data, size_t data_len)
+ {
+   const DICT_ATTR *da;
+   int err;
+   assert (pkt);
+   da = nr_dict_attr_byvalue (attr, vendor);
+   if (da == NULL)
+     return RSE_ATTR_TYPE_UNKNOWN;
+   err = nr_packet_attr_append (pkt->rpkt, NULL, da, data, data_len);
+   if (err < 0)
+     return rs_err_conn_push (pkt->conn, -err, __func__);
+   return RSE_OK;
+ }
+ void
+ rs_packet_avps (struct rs_packet *pkt, rs_avp ***vps)
+ {
+   assert (pkt);
+   *vps = &pkt->rpkt->vps;
+ }
+ unsigned int
+ rs_packet_code (struct rs_packet *pkt)
+ {
+   assert (pkt);
+   return pkt->rpkt->code;
+ }
+ rs_const_avp *
+ rs_packet_find_avp (struct rs_packet *pkt, unsigned int attr, unsigned int vendor)
+ {
+   assert (pkt);
+   return rs_avp_find_const (pkt->rpkt->vps, attr, vendor);
+ }
+ int
+ rs_packet_set_id (struct rs_packet *pkt, int id)
+ {
+   int old = pkt->rpkt->id;
+   pkt->rpkt->id = id;
+   return old;
+ }
diff --combined lib/peer.c
@@@ -6,11 -6,13 +6,14 @@@
  #endif
  
  #include <assert.h>
+ #include <stdlib.h>
+ #include <string.h>
  #include <radsec/radsec.h>
  #include <radsec/radsec-impl.h>
  #include "err.h"
  #include "peer.h"
 +#include "util.h"
  
  struct rs_peer *
  peer_pick_peer (struct rs_connection *conn)
@@@ -67,17 -69,16 +70,17 @@@ rs_peer_create (struct rs_connection *c
  
  int
  rs_peer_set_address (struct rs_peer *peer, const char *hostname,
 -                     const char *service)
 +                     const char *service)
  {
 -  struct rs_error *err;
 -
    assert (peer);
 -  assert (peer->realm);
 +  assert (peer->conn);
 +  assert (peer->conn->ctx);
 +
 +  peer->hostname = rs_strdup (peer->conn->ctx, hostname);
 +  peer->service = rs_strdup (peer->conn->ctx, service);
 +  if (peer->hostname == NULL || peer->service == NULL)
 +    return RSE_NOMEM;
  
 -  err = rs_resolv (&peer->addr, peer->realm->type, hostname, service);
 -  if (err)
 -    return err_conn_push_err (peer->conn, err);
    return RSE_OK;
  }
  
diff --combined lib/radsec.c
@@@ -12,7 -12,7 +12,7 @@@
  #include <libgen.h>
  #include <assert.h>
  
- #include <freeradius/libradius.h>
+ #include <radius/client.h>
  #include <event2/event.h>
  #include <event2/util.h>
  #include <radsec/radsec.h>
@@@ -39,14 -39,8 +39,8 @@@ rs_context_create (struct rs_context **
  #if defined (RS_ENABLE_TLS)
    ssl_init ();
  #endif
- #if defined (DEBUG)
-   fr_log_fp = stderr;
-   fr_debug_flag = 1;
- #endif
-   debug_init ("libradsec");   /* radsecproxy compat, FIXME: remove */
  
-   fr_randinit (&h->fr_randctx, 0);
-   fr_rand_seed (NULL, 0);
+   debug_init ("libradsec");   /* radsecproxy compat, FIXME: remove */
  
    if (ctx != NULL)
      *ctx = h;
    return RSE_OK;
  }
  
- /** Initialize freeradius dictionary.  */
- int
- rs_context_init_freeradius_dict (struct rs_context *ctx, const char *dict)
- {
-   int r = RSE_OK;
-   size_t dictlen;
-   char *dir = NULL;
-   char *fn = NULL;
-   if (dict == NULL)
-     if (ctx->config != NULL && ctx->config->dictionary)
-       dict = ctx->config->dictionary;
-   if (dict == NULL)
-     dict = RS_FREERADIUS_DICT;
-   dictlen = strlen (dict);
-   dir = rs_calloc (ctx, 1, dictlen + 1);
-   fn = rs_calloc (ctx, 1, dictlen + 1);
-   if (dir == NULL || fn == NULL)
-     {
-       r = rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
-       goto out;
-     }
-   strncpy (dir, dict, dictlen);
-   strncpy (fn, dict, dictlen);
-   if (dict_init (dirname (dir), basename (fn)) < 0)
-     {
-       r = rs_err_ctx_push_fl (ctx, RSE_FR, __FILE__, __LINE__,
-                             "failing dict_init(\"%s\")", dict);
-       goto out;
-     }
-  out:
-   if (dir)
-     rs_free (ctx, dir);
-   if (fn)
-     rs_free (ctx, fn);
-   return r;
- }
  struct rs_error *
 -rs_resolv (struct evutil_addrinfo **addr,
 -         rs_conn_type_t type,
 -         const char *hostname,
 -         const char *service)
 +rs_resolve (struct evutil_addrinfo **addr,
 +            rs_conn_type_t type,
 +            const char *hostname,
 +            const char *service)
  {
    int err;
    struct evutil_addrinfo hints, *res = NULL;
@@@ -150,16 -102,12 +102,16 @@@ rs_context_destroy (struct rs_context *
          for (p = r->peers; p; )
            {
              struct rs_peer *tmp = p;
 -            if (p->addr)
 -              evutil_freeaddrinfo (p->addr);
 +            if (p->addr_cache)
 +                {
 +                  evutil_freeaddrinfo (p->addr_cache);
 +                  p->addr_cache = NULL;
 +                }
              p = p->next;
              rs_free (ctx, tmp);
            }
          free (r->name);
 +          rs_free (ctx, r->transport_cred);
          r = r->next;
          rs_free (ctx, tmp);
        }
diff --combined lib/rsp_tlscommon.h
@@@ -6,6 -6,6 +6,7 @@@
   * copyright notice and this permission notice appear in all copies.
   */
  
++#include <netinet/in.h>
  #include <openssl/ssl.h>
  
  #if defined (__cplusplus)
@@@ -34,10 -34,9 +35,10 @@@ void ssl_init()
  struct tls *tlsgettls(char *alt1, char *alt2);
  SSL_CTX *tlsgetctx(uint8_t type, struct tls *t);
  X509 *verifytlscert(SSL *ssl);
 +int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr);
 +int subjectaltnameregexp(X509 *cert, int type, const char *exact,  const regex_t *regex);
 +int cnregexp(X509 *cert, const char *exact, const regex_t *regex);
  int verifyconfcert(X509 *cert, struct clsrvconf *conf);
 -int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val);
 -int addmatchcertattr(struct clsrvconf *conf);
  #endif
  
  #if defined (__cplusplus)
diff --combined lib/tcp.c
+++ b/lib/tcp.c
@@@ -12,6 -12,7 +12,7 @@@
  #include <event2/bufferevent_ssl.h>
  #include <openssl/err.h>
  #endif
+ #include <radius/client.h>
  #include <radsec/radsec.h>
  #include <radsec/radsec-impl.h>
  #include "tcp.h"
@@@ -35,26 -36,19 +36,19 @@@ _read_header (struct rs_packet *pkt
    if (n == RS_HEADER_LEN)
      {
        pkt->flags |= rs_packet_hdr_read_flag;
-       pkt->rpkt->data_len = (pkt->hdr[2] << 8) + pkt->hdr[3];
-       if (pkt->rpkt->data_len < 20 || pkt->rpkt->data_len > 4096)
+       pkt->rpkt->length = (pkt->hdr[2] << 8) + pkt->hdr[3];
+       if (pkt->rpkt->length < 20 || pkt->rpkt->length > RS_MAX_PACKET_LEN)
        {
          conn_close (&pkt->conn);
          return rs_err_conn_push (pkt->conn, RSE_INVALID_PKT,
                                   "invalid packet length: %d",
-                                  pkt->rpkt->data_len);
-       }
-       pkt->rpkt->data = rs_malloc (pkt->conn->ctx, pkt->rpkt->data_len);
-       if (!pkt->rpkt->data)
-       {
-         conn_close (&pkt->conn);
-         return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__,
-                                     NULL);
+                                  pkt->rpkt->length);
        }
        memcpy (pkt->rpkt->data, pkt->hdr, RS_HEADER_LEN);
        bufferevent_setwatermark (pkt->conn->bev, EV_READ,
-                               pkt->rpkt->data_len - RS_HEADER_LEN, 0);
+                               pkt->rpkt->length - RS_HEADER_LEN, 0);
        rs_debug (("%s: packet header read, total pkt len=%d\n",
-                __func__, pkt->rpkt->data_len));
+                __func__, pkt->rpkt->length));
      }
    else if (n < 0)
      {
@@@ -74,17 -68,18 +68,18 @@@ static in
  _read_packet (struct rs_packet *pkt)
  {
    size_t n = 0;
+   int err;
  
    rs_debug (("%s: trying to read %d octets of packet data\n", __func__,
-            pkt->rpkt->data_len - RS_HEADER_LEN));
+            pkt->rpkt->length - RS_HEADER_LEN));
  
    n = bufferevent_read (pkt->conn->bev,
                        pkt->rpkt->data + RS_HEADER_LEN,
-                       pkt->rpkt->data_len - RS_HEADER_LEN);
+                       pkt->rpkt->length - RS_HEADER_LEN);
  
    rs_debug (("%s: read %ld octets of packet data\n", __func__, n));
  
-   if (n == pkt->rpkt->data_len - RS_HEADER_LEN)
+   if (n == pkt->rpkt->length - RS_HEADER_LEN)
      {
        bufferevent_disable (pkt->conn->bev, EV_READ);
        rs_debug (("%s: complete packet read\n", __func__));
         - invalid code field
         - attribute lengths >= 2
         - attribute sizes adding up correctly  */
-       if (!rad_packet_ok (pkt->rpkt, 0))
+       err = nr_packet_ok (pkt->rpkt);
+       if (err != RSE_OK)
        {
          conn_close (&pkt->conn);
-         return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__,
-                                     "invalid packet: %s", fr_strerror ());
+         return rs_err_conn_push_fl (pkt->conn, err, __FILE__, __LINE__,
+                                     "invalid packet");
        }
  
  #if defined (DEBUG)
      rs_debug (("%s: buffer frozen when reading packet\n", __func__));
    else                                /* Short packet.  */
      rs_debug (("%s: waiting for another %d octets\n", __func__,
-              pkt->rpkt->data_len - RS_HEADER_LEN - n));
+              pkt->rpkt->length - RS_HEADER_LEN - n));
  
    return 0;
  }
@@@ -158,32 -154,24 +154,32 @@@ tcp_event_cb (struct bufferevent *bev, 
  {
    struct rs_packet *pkt = (struct rs_packet *) user_data;
    struct rs_connection *conn = NULL;
 -  struct rs_peer *p = NULL;
    int sockerr = 0;
  #if defined (RS_ENABLE_TLS)
    unsigned long tlserr = 0;
  #endif
 +#if defined (DEBUG)
 +  struct rs_peer *p = NULL;
 +#endif
  
    assert (pkt);
    assert (pkt->conn);
 -  assert (pkt->conn->active_peer);
    conn = pkt->conn;
 +#if defined (DEBUG)
 +  assert (pkt->conn->active_peer);
    p = conn->active_peer;
 +#endif
  
    conn->is_connecting = 0;
    if (events & BEV_EVENT_CONNECTED)
      {
        if (conn->tev)
        evtimer_del (conn->tev); /* Cancel connect timer.  */
 -      event_on_connect (conn, pkt);
 +      if (event_on_connect (conn, pkt))
 +        {
 +          event_on_disconnect (conn);
 +          event_loopbreak (conn);
 +        }
      }
    else if (events & BEV_EVENT_EOF)
      {
      {
        rs_debug (("%s: %p times out on %s\n", __func__, p,
                 (events & BEV_EVENT_READING) ? "read" : "write"));
 -      rs_err_conn_push_fl (pkt->conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
 +      rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);
      }
    else if (events & BEV_EVENT_ERROR)
      {
        if (sockerr == 0)       /* FIXME: True that errno == 0 means closed? */
        {
          event_on_disconnect (conn);
 -        rs_err_conn_push_fl (pkt->conn, RSE_DISCO, __FILE__, __LINE__, NULL);
 +        rs_err_conn_push_fl (conn, RSE_DISCO, __FILE__, __LINE__, NULL);
        }
        else
        {
          rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr,
                     evutil_socket_error_to_string (sockerr)));
 -        rs_err_conn_push_fl (pkt->conn, RSE_SOCKERR, __FILE__, __LINE__,
 +        rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,
                               "%d: %d (%s)", conn->fd, sockerr,
                               evutil_socket_error_to_string (sockerr));
        }
            {
              rs_debug (("%s: openssl error: %s\n", __func__,
                         ERR_error_string (tlserr, NULL)));
 -            rs_err_conn_push_fl (pkt->conn, RSE_SSLERR, __FILE__, __LINE__,
 +            rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
                                   ERR_error_string (tlserr, NULL));
            }
        }
diff --combined lib/tests/test-udp.c
@@@ -1,6 -1,5 +1,5 @@@
  #include <stdlib.h>
  #include <cgreen/cgreen.h>
- #include <freeradius/libradius.h>
  #include "radsec/radsec.h"
  #include "radsec/request.h"
  #include "udp.h"
@@@ -19,7 -18,7 +18,7 @@@ authenticate (struct rs_connection *con
    rs_request_add_reqpkt (req, msg);
    assert_true (rs_request_send (req, &resp) == 0);
    //printf ("%s\n", rs_err_msg (rs_err_conn_pop (conn), 1));
-   assert_true (rs_packet_frpkt (resp)->code == PW_AUTHENTICATION_ACK);
+   assert_true (rs_packet_code(resp) == PW_ACCESS_ACCEPT);
  
    rs_request_destroy (req);
  }
@@@ -35,32 -34,28 +34,30 @@@ send_more_than_one_msg_in_one_packet (s
    assert_true (rs_packet_send (msg1, NULL) == 0);
  }
  
++#if 0
  static void
  send_large_packet (struct rs_connection *conn)
  {
    struct rs_packet *msg0;
 -  struct rs_attr *attr_x;
 +  struct radius_packet *frpkt = NULL;
    char *buf;
    int f;
  
-   buf = malloc (4096);
+   buf = malloc (RS_MAX_PACKET_LEN);
    assert_true (buf != NULL);
-   memset (buf, 0, 4096);
+   memset (buf, 0, RS_MAX_PACKET_LEN);
  
    assert_true (rs_packet_create (conn, &msg0) == 0);
-   frpkt = rs_packet_frpkt (msg0);
-   assert_true (frpkt != NULL);
    /* 16 chunks --> heap corruption in evbuffer_drain detected by free() */
    for (f = 0; f < 15; f++)
      {
-       VALUE_PAIR *vp = NULL;
        memset (buf, 'a' + f, 252);
-       vp = pairmake ("EAP-Message", buf, T_OP_EQ);
-       assert_true (vp != NULL);
-       pairadd (&frpkt->vps, vp);
 -      rs_attr_create (conn, &attr_x, "EAP-Message", buf);
 -      rs_packet_add_attr (msg0, attr_x);
++      //vp = pairmake ("EAP-Message", buf, T_OP_EQ);
++      assert_true (rs_packet_append_avp (msg0, fixme...) == RSE_OK);
      }
    assert_true (rs_packet_send (msg0, NULL) == 0);
  }
++#endif  /* 0 */
  
  /* ************************************************************ */
  static struct setup {
@@@ -78,12 -73,11 +75,12 @@@ test_auth (
  
    setup.config_file = "test.conf";
    setup.config_name = "test-udp-auth";
 -  setup.username = "molgan";
 +  setup.username = "molgan@PROJECT-MOONSHOT.ORG";
    setup.pw = "password";
  
 -  assert_true (rs_context_create (&ctx, NULL) == 0);
 +  assert_true (rs_context_create (&ctx) == 0);
    assert_true (rs_context_read_config (ctx, setup.config_file) == 0);
 +  assert_true (rs_context_init_freeradius_dict (ctx, NULL) == 0);
    assert_true (rs_conn_create (ctx, &conn, setup.config_name) == 0);
  
    authenticate (conn, setup.username, setup.pw);
@@@ -101,7 -95,7 +98,7 @@@ test_buffering_cb (const uint8_t *buf, 
    hd (buf, len);
  #endif
    assert_true (len >= 20);
-   assert_true (len <= 4096);
+   assert_true (len <= RS_MAX_PACKET_LEN);
    assert_true ((buf[2] << 8) +  buf[3] == len);
    return len;
  }
@@@ -114,9 -108,8 +111,8 @@@ test_buffering (
    struct timeval timeout;
    struct polldata *polldata;
  
 -  assert_true (rs_context_create (&ctx, NULL) == 0);
 +  assert_true (rs_context_create (&ctx) == 0);
    assert_true (rs_context_read_config (ctx, "test.conf") == 0);
-   assert_true (rs_context_init_freeradius_dict (ctx, NULL) == 0);
    assert_true (rs_conn_create (ctx, &conn, "test-udp-buffering") == 0);
  
    timeout.tv_sec = 0;
    assert_true (udp_poll (polldata) > 0);
    assert_true (udp_poll (polldata) > 0);
  
 +#if 0
 +"
 +send_large_packet() disabled, it's hanging after
 +
 +Sending Access-Request of id 1 to (null) port 0
 +        Message-Authenticator = 0x00000000000000000000000000000000
 +packet_do_send: about to send this to localhost:11820:
 +        Code: 1, Identifier: 1, Lenght: 38
 +rs_packet_send: entering event loop
 +_evcb: fd=5 what = WRITE
 +rs_packet_send: event loop done
 +"
    send_large_packet (conn);
    assert_true (udp_poll (polldata) > 0);
 +#endif  /* 0 */
  
    udp_free_polldata (polldata);
    rs_conn_destroy (conn);