diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile.am | 39 | ||||
| -rw-r--r-- | lib/conn.c | 38 | ||||
| -rw-r--r-- | lib/err.c | 50 | ||||
| -rw-r--r-- | lib/err.h | 7 | ||||
| -rw-r--r-- | lib/event.c | 76 | ||||
| -rw-r--r-- | lib/examples/client-blocking.c | 40 | ||||
| -rw-r--r-- | lib/include/radsec/radsec-impl.h | 100 | ||||
| -rw-r--r-- | lib/include/radsec/radsec.h | 24 | ||||
| -rw-r--r-- | lib/message.c | 24 | ||||
| -rw-r--r-- | lib/peer.c | 98 | ||||
| -rw-r--r-- | lib/peer.h | 1 | ||||
| -rw-r--r-- | lib/radsec.sym | 5 | ||||
| -rw-r--r-- | lib/send.c | 19 | ||||
| -rw-r--r-- | lib/tcp.c | 10 | ||||
| -rw-r--r-- | lib/tls.c | 20 | ||||
| -rw-r--r-- | lib/udp.c | 2 | ||||
| -rw-r--r-- | lib/util.c | 9 | 
17 files changed, 360 insertions, 202 deletions
| diff --git a/lib/Makefile.am b/lib/Makefile.am index 06ea8d5..6d62c97 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -3,19 +3,22 @@ ACLOCAL_AMFLAGS = -I m4  # 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. - +# +# 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. - +# 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_. +# 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_. +VER_CUR = 1 +VER_REV = 0 +VER_AGE = 0  SUBDIRS = radius radsecproxy . include examples @@ -44,13 +47,19 @@ libradsec_la_SOURCES = \  	util.c  if RS_ENABLE_TLS -libradsec_la_SOURCES += tls.c +  libradsec_la_SOURCES += tls.c  else -libradsec_la_SOURCES += md5.c +  libradsec_la_SOURCES += md5.c  endif  EXTRA_DIST = HACKING LICENSE -libradsec_la_LIBADD = radsecproxy/libradsec-radsecproxy.la radius/libradsec-radius.la -libradsec_la_LDFLAGS = -version-info 0:0:0 -export-symbols radsec.sym -libradsec_la_CFLAGS = $(AM_CFLAGS) -DHAVE_CONFIG_H -Werror # -DDEBUG -DDEBUG_LEVENT  +libradsec_la_CFLAGS = \ +	$(AM_CFLAGS) -DHAVE_CONFIG_H \ +	-DDEBUG -DDEBUG_LEVENT +libradsec_la_LDFLAGS = \ +	-version-info $(VER_CUR):$(VER_REV):$(VER_AGE) \ +	-export-symbols radsec.sym +libradsec_la_LIBADD = \ +	radsecproxy/libradsec-radsecproxy.la \ +	radius/libradsec-radius.la @@ -1,5 +1,5 @@  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +   See LICENSE for licensing information. */  #if defined HAVE_CONFIG_H  #include <config.h> @@ -25,7 +25,7 @@ conn_close (struct rs_connection **connp)    int r = 0;    assert (connp);    assert (*connp); -  if ((*connp)->is_connected) +  if ((*connp)->state == RS_CONN_STATE_CONNECTED)      r = rs_conn_disconnect (*connp);    if (r == RSE_OK)      *connp = NULL; @@ -53,7 +53,7 @@ conn_activate_timeout (struct rs_connection *conn)    if (conn->base_.timeout.tv_sec || conn->base_.timeout.tv_usec)      {        rs_debug (("%s: activating timer: %d.%d\n", __func__, -		 conn->timeout.tv_sec, conn->timeout.tv_usec)); +		 conn->base_.timeout.tv_sec, conn->base_.timeout.tv_usec));        if (evtimer_add (conn->tev, &conn->base_.timeout))  	return rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,  				    "evtimer_add: %d", errno); @@ -64,7 +64,7 @@ conn_activate_timeout (struct rs_connection *conn)  int  conn_type_tls (const struct rs_connection *conn)  { -  assert (conn->active_peer); +  assert (conn->base_.active_peer);    return conn->base_.realm->type == RS_CONN_TYPE_TLS      || conn->base_.realm->type == RS_CONN_TYPE_DTLS;  } @@ -72,9 +72,9 @@ conn_type_tls (const struct rs_connection *conn)  int  conn_cred_psk (const struct rs_connection *conn)  { -  assert (conn->active_peer); -  return conn->active_peer->transport_cred && -    conn->active_peer->transport_cred->type == RS_CRED_TLS_PSK; +  assert (conn->base_.active_peer); +  return conn->base_.active_peer->transport_cred && +    conn->base_.active_peer->transport_cred->type == RS_CRED_TLS_PSK;  }  void @@ -111,23 +111,21 @@ conn_configure (struct rs_context *ctx,        struct rs_realm *r = rs_conf_find_realm (ctx, config);        if (r)  	{ -	  struct rs_peer *p; -  	  connbase->realm = r;  	  connbase->peers = r->peers; /* FIXME: Copy instead?  */ +#if 0  	  for (p = connbase->peers; p != NULL; p = p->next) -	    p->conn = TO_GENERIC_CONN(connbase); +	    p->connbase = connbase; +#endif  	  connbase->timeout.tv_sec = r->timeout;  	  connbase->tryagain = r->retries;  	} -      else -	{ -	  connbase->realm = rs_malloc (ctx, sizeof (struct rs_realm)); -	  if (!connbase->realm) -	    return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, -				       NULL); -	  memset (connbase->realm, 0, sizeof (struct rs_realm)); -	} +    } +  if (connbase->realm == NULL) +    { +      connbase->realm = rs_calloc (ctx, 1, sizeof (struct rs_realm)); +      if (connbase->realm == NULL) +        return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);      }    return RSE_OK;  } @@ -200,7 +198,7 @@ rs_conn_destroy (struct rs_connection *conn)    /* NOTE: conn->realm is owned by context.  */    /* NOTE: conn->peers is owned by context.  */ -  if (conn->is_connected) +  if (conn->state == RS_CONN_STATE_CONNECTED)      err = rs_conn_disconnect (conn);  #if defined (RS_ENABLE_TLS) @@ -284,7 +282,7 @@ struct event_base  int rs_conn_get_fd (struct rs_connection *conn)  {    assert (conn); -  assert (conn->active_peer); +  assert (conn->base_.active_peer);    return conn->base_.fd;  } @@ -1,5 +1,5 @@  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +   See LICENSE for licensing information. */  #if defined HAVE_CONFIG_H  #include <config.h> @@ -156,26 +156,41 @@ rs_err_ctx_push_fl (struct rs_context *ctx, int code, const char *file,  }  int -err_conn_push_err (struct rs_connection *conn, struct rs_error *err) +err_connbase_push_err (struct rs_conn_base *connbase, struct rs_error *err)  { -  if (conn->base_.err) -    rs_err_free (conn->base_.err); -  conn->base_.err = err;		/* FIXME: use a stack */ +  if (connbase->err) +    rs_err_free (connbase->err); +  connbase->err = err;		/* FIXME: use a stack */    return err->code;  }  static int -_conn_err_vpush_fl (struct rs_connection *conn, int code, const char *file, -		    int line, const char *fmt, va_list args) +_connbase_err_vpush_fl (struct rs_conn_base *connbase, int code, +                        const char *file, int line, const char *fmt, +                        va_list args)  {    struct rs_error *err = _err_vcreate (code, file, line, fmt, args);    if (!err)      return RSE_NOMEM; -  return err_conn_push_err (conn, err); +  return err_connbase_push_err (connbase, err); +} + +int +rs_err_connbase_push (struct rs_conn_base *connbase, int code, +                      const char *fmt, ...) +{ +  int r = 0; + +  va_list args; +  va_start (args, fmt); +  r = _connbase_err_vpush_fl (connbase, code, NULL, 0, fmt, args); +  va_end (args); + +  return r;  }  int @@ -185,7 +200,22 @@ rs_err_conn_push (struct rs_connection *conn, int code, const char *fmt, ...)    va_list args;    va_start (args, fmt); -  r = _conn_err_vpush_fl (conn, code, NULL, 0, fmt, args); +  r = _connbase_err_vpush_fl (TO_BASE_CONN (conn), code, NULL, 0, fmt, args); +  va_end (args); + +  return r; +} + +int +rs_err_connbase_push_fl (struct rs_conn_base *connbase, int code, +                         const char *file, +                         int line, const char *fmt, ...) +{ +  int r = 0; + +  va_list args; +  va_start (args, fmt); +  r = _connbase_err_vpush_fl (connbase, code, file, line, fmt, args);    va_end (args);    return r; @@ -199,7 +229,7 @@ rs_err_conn_push_fl (struct rs_connection *conn, int code, const char *file,    va_list args;    va_start (args, fmt); -  r = _conn_err_vpush_fl (conn, code, file, line, fmt, args); +  r = _connbase_err_vpush_fl (TO_BASE_CONN (conn), code, file, line, fmt, args);    va_end (args);    return r; @@ -1,9 +1,10 @@ -/* Copyright 2011 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +/* Copyright 2011,2013 NORDUnet A/S. All rights reserved. +   See LICENSE for licensing information. */  struct rs_error *err_create (unsigned int code,  			     const char *file,  			     int line,  			     const char *fmt,  			     ...); -int err_conn_push_err (struct rs_connection *conn, struct rs_error *err); +int err_connbase_push_err (struct rs_conn_base *, struct rs_error *); +int rs_err_connbase_push (struct rs_conn_base *, int, const char *, ...); diff --git a/lib/event.c b/lib/event.c index f7b936a..c651e4b 100644 --- a/lib/event.c +++ b/lib/event.c @@ -1,5 +1,5 @@  /* Copyright 2011,2013 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +   See LICENSE for licensing information. */  #if defined HAVE_CONFIG_H  #include <config.h> @@ -72,8 +72,8 @@ event_conn_timeout_cb (int fd, short event, void *data)    if (event & EV_TIMEOUT)      {        rs_debug (("%s: connection timeout on %p (fd %d) connecting to %p\n", -		 __func__, conn, conn->fd, conn->active_peer)); -      conn->is_connecting = 0; +		 __func__, conn, conn->base_.fd, conn->base_.active_peer)); +      conn->state = RS_CONN_STATE_UNDEFINED;        rs_err_conn_push_fl (conn, RSE_TIMEOUT_CONN, __FILE__, __LINE__, NULL);        event_loopbreak (conn);      } @@ -90,7 +90,7 @@ event_retransmit_timeout_cb (int fd, short event, void *data)    if (event & EV_TIMEOUT)      {        rs_debug (("%s: retransmission timeout on %p (fd %d) sending to %p\n", -		 __func__, conn, conn->fd, conn->active_peer)); +		 __func__, conn, conn->base_.fd, conn->base_.active_peer));        rs_err_conn_push_fl (conn, RSE_TIMEOUT_IO, __FILE__, __LINE__, NULL);        event_loopbreak (conn);      } @@ -107,7 +107,7 @@ event_init_socket (struct rs_connection *conn, struct rs_peer *p)        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); +        return err_connbase_push_err (TO_BASE_CONN (conn), err);      }    conn->base_.fd = socket (p->addr_cache->ai_family, p->addr_cache->ai_socktype, @@ -171,59 +171,67 @@ event_init_bufferevent (struct rs_connection *conn, struct rs_peer *peer)  void  event_do_connect (struct rs_connection *conn)  { -  struct rs_peer *p;    int err, sockerr; +  struct sockaddr *peer_addr; +  size_t peer_addrlen;    assert (conn); -  assert (conn->active_peer); -  p = conn->active_peer; +  assert (conn->base_.active_peer); +  assert (conn->base_.active_peer->addr_cache); +  peer_addr = conn->base_.active_peer->addr_cache->ai_addr; +  peer_addrlen = conn->base_.active_peer->addr_cache->ai_addrlen; + +  /* We don't connect listeners. */ +  assert (conn->base_.magic == RS_CONN_MAGIC_GENERIC);  #if defined (DEBUG)    {      char host[80], serv[80]; -    getnameinfo (p->addr_cache->ai_addr, -		 p->addr_cache->ai_addrlen, -		 host, sizeof(host), serv, sizeof(serv), +    getnameinfo (peer_addr, peer_addrlen, +		 host, sizeof(host), +                 serv, sizeof(serv),  		 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/);      rs_debug (("%s: connecting to %s:%s\n", __func__, host, serv));    }  #endif -  if (p->conn->base_.bev)		/* TCP */ +  if (conn->base_.bev)		/* TCP */      {        conn_activate_timeout (conn); /* Connect timeout.  */ -      err = bufferevent_socket_connect (p->conn->base_.bev, -                                        p->addr_cache->ai_addr, -					p->addr_cache->ai_addrlen); +      err = bufferevent_socket_connect (conn->base_.bev, +                                        peer_addr, peer_addrlen);        if (err < 0) -	rs_err_conn_push_fl (p->conn, RSE_EVENT, __FILE__, __LINE__, -			     "bufferevent_socket_connect: %s", -			     evutil_gai_strerror (err)); +	rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__, +                             "bufferevent_socket_connect: %s", +                             evutil_gai_strerror (err));        else -	p->conn->is_connecting = 1; +	conn->state = RS_CONN_STATE_CONNECTING;      }    else				/* UDP */      { -      err = connect (p->conn->base_.fd, -                     p->addr_cache->ai_addr, -                     p->addr_cache->ai_addrlen); +      err = connect (conn->base_.fd, peer_addr, peer_addrlen);        if (err < 0)  	{ -	  sockerr = evutil_socket_geterror (p->conn->fd); -	  rs_debug (("%s: %d: connect: %d (%s)\n", __func__, p->conn->fd, +	  sockerr = evutil_socket_geterror (conn->base_.fd); +	  rs_debug (("%s: %d: connect: %d (%s)\n", __func__, +                     conn->base_.fd,  		     sockerr, evutil_socket_error_to_string (sockerr))); -	  rs_err_conn_push_fl (p->conn, RSE_SOCKERR, __FILE__, __LINE__, -			       "%d: connect: %d (%s)", p->conn->base_.fd, sockerr, +	  rs_err_conn_push_fl (conn, RSE_SOCKERR, +                               __FILE__, __LINE__, +                               "%d: connect: %d (%s)", conn->base_.fd, +                               sockerr,  			       evutil_socket_error_to_string (sockerr));  	} +      else +	conn->state = RS_CONN_STATE_CONNECTING;      }  }  int  event_loopbreak (struct rs_connection *conn)  { -  int err = event_base_loopbreak (conn->base_.ctx->evb); +  int err = event_base_loopbreak (TO_BASE_CONN(conn)->ctx->evb);    if (err < 0)      rs_err_conn_push_fl (conn, RSE_EVENT, __FILE__, __LINE__,  			 "event_base_loopbreak: %s", @@ -235,9 +243,9 @@ event_loopbreak (struct rs_connection *conn)  void  event_on_disconnect (struct rs_connection *conn)  { -  conn->is_connecting = 0; -  conn->is_connected = 0; -  rs_debug (("%s: %p disconnected\n", __func__, conn->active_peer)); +  conn->state = RS_CONN_STATE_UNDEFINED; +  rs_debug (("%s: %p disconnected\n", __func__, +             TO_BASE_CONN(conn)->active_peer));    if (conn->callbacks.disconnected_cb)      conn->callbacks.disconnected_cb (conn->base_.user_data);  } @@ -246,8 +254,8 @@ event_on_disconnect (struct rs_connection *conn)  int  event_on_connect (struct rs_connection *conn, struct rs_message *msg)  { -  assert (!conn->is_connecting); -  assert (conn->active_peer); +  assert (conn->state == RS_CONN_STATE_CONNECTING); +  assert (conn->base_.active_peer);  #if defined (RS_ENABLE_TLS)    if (conn_type_tls(conn) && !conn_cred_psk(conn)) @@ -258,8 +266,8 @@ event_on_connect (struct rs_connection *conn, struct rs_message *msg)        }  #endif	/* RS_ENABLE_TLS */ -  conn->is_connected = 1; -  rs_debug (("%s: %p connected\n", __func__, conn->active_peer)); +  conn->state = RS_CONN_STATE_CONNECTED; +  rs_debug (("%s: %p connected\n", __func__, TO_BASE_CONN(conn)->active_peer));    if (conn->callbacks.connected_cb)      conn->callbacks.connected_cb (conn->base_.user_data); diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index 3ea4b51..d2ee9f4 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -1,7 +1,11 @@  /* RADIUS/RadSec client using libradsec in blocking mode. */ +/* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved. +   See LICENSE for licensing information. */ +  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <assert.h>  #include <radsec/radsec.h>  #include <radsec/request.h> @@ -13,7 +17,7 @@  #define USER_PW "password"  struct rs_error * -blocking_client (const char *config_fn, const char *configuration, +blocking_client (const char *av1, const char *av2, const char *av3,                   int use_request_object_flag)  {    struct rs_context *h = NULL; @@ -22,6 +26,15 @@ blocking_client (const char *config_fn, const char *configuration,    struct rs_message *req = NULL, *resp = NULL;    struct rs_error *err = NULL;    int r; +#if defined (USE_CONFIG_FILE) +  const char *config_fn= av1; +  const char *configuration = av2; +#else +  const char *host = av1; +  const char *service = av2; +  const char *proto = av3; +  struct rs_peer *server; +#endif    r = rs_context_create (&h);    if (r) @@ -31,15 +44,25 @@ blocking_client (const char *config_fn, const char *configuration,      }  #if !defined (USE_CONFIG_FILE) +  /* Do it without a configuration file by setting all stuff "by +   hand".  Doesn't work for TLS at the moment because we don't have an +   API for setting the X509 cert file names and such. */    { -    struct rs_peer *server; +    int conn_type = RS_CONN_TYPE_UDP;      if (rs_conn_create (h, &conn, NULL))        goto cleanup; -    rs_conn_set_type (conn, RS_CONN_TYPE_UDP); -    if (rs_peer_create (conn, &server)) +    if (proto) +      { +        if (!strncmp (proto, "udp", strlen ("udp"))) +          conn_type = RS_CONN_TYPE_UDP; +        else if (!strncmp (proto, "tls", strlen ("tls"))) +          conn_type = RS_CONN_TYPE_TLS; +      } +    rs_conn_set_type (conn, conn_type); +    if (rs_peer_create_for_conn (conn, &server))        goto cleanup; -    if (rs_peer_set_address (server, av1, av2)) +    if (rs_peer_set_address (server, host, service))        goto cleanup;      rs_peer_set_timeout (server, 1);      rs_peer_set_retries (server, 3); @@ -85,6 +108,10 @@ blocking_client (const char *config_fn, const char *configuration,    err = rs_err_ctx_pop (h);    if (err == RSE_OK)      err = rs_err_conn_pop (conn); +#if !defined (USE_CONFIG_FILE) +  rs_peer_free_address (server); +  rs_peer_free_secret (server); +#endif    if (resp)      rs_message_destroy (resp);    if (request) @@ -118,7 +145,8 @@ main (int argc, char *argv[])      }    if (argc < 3)      usage (argc, argv); -  err = blocking_client (argv[1], argv[2], use_request_object_flag); +  err = blocking_client (argv[1], argv[2], argc >= 3 ? argv[3] : NULL, +                         use_request_object_flag);    if (err)      {        fprintf (stderr, "error: %s: %d\n", rs_err_msg (err), rs_err_code (err, 0)); diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index fecf8f2..45ce7f6 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -1,5 +1,5 @@  /** @file libradsec-impl.h -    @brief Libraray internal header file for libradsec.  */ +    @brief Libraray internal header file for libradsec. */  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.     See LICENSE for licensing information. */ @@ -15,13 +15,18 @@  #endif  #include "compat.h" -/* Constants.  */ +/**************/ +/* Constants. */  #define RS_HEADER_LEN 4 +#define RS_CONN_MAGIC_BASE 0xAE004711u +#define RS_CONN_MAGIC_GENERIC 0x843AEF47u +#define RS_CONN_MAGIC_LISTENER 0xDCB04783u -/* Data types.  */ +/***************/ +/* Data types. */  enum rs_cred_type {      RS_CRED_NONE = 0, -    /* TLS pre-shared keys, RFC 4279.  */ +    /* TLS pre-shared keys, RFC 4279. */      RS_CRED_TLS_PSK,      /* RS_CRED_TLS_DH_PSK, */      /* RS_CRED_TLS_RSA_PSK, */ @@ -34,6 +39,17 @@ enum rs_key_encoding {  };  typedef unsigned int rs_key_encoding_t; +enum rs_peer_type { +    RS_PEER_TYPE_CLIENT = 1, +    RS_PEER_TYPE_SERVER = 2 +}; + +enum rs_conn_subtype { +    RS_CONN_OBJTYPE_BASE = 1, +    RS_CONN_OBJTYPE_GENERIC, +    RS_CONN_OBJTYPE_LISTENER, +}; +  #if defined (__cplusplus)  extern "C" {  #endif @@ -50,19 +66,14 @@ struct rs_error {      char buf[1024];  }; -enum rs_peer_type { -    RS_PEER_TYPE_CLIENT = 1, -    RS_PEER_TYPE_SERVER = 2 -}; - -/** Configuration object for a connection.  */ +/** Configuration object for a connection. */  struct rs_peer {      enum rs_peer_type type; -    struct rs_connection *conn; +    struct rs_conn_base *connbase; /**< For error handling. */      struct rs_realm *realm;      char *hostname;      char *service; -    char *secret;               /* RADIUS secret.  */ +    char *secret;               /* RADIUS secret. */      struct evutil_addrinfo *addr_cache;      char *cacertfile;      char *cacertpath; @@ -72,17 +83,18 @@ struct rs_peer {      struct rs_peer *next;  }; -/** Configuration object for a RADIUS realm.  */ +/** Configuration object for a RADIUS realm. */  struct rs_realm {      char *name;      enum rs_conn_type type;      int timeout;      int retries; +    struct rs_listener *listeners;      struct rs_peer *peers;      struct rs_realm *next;  }; -/** Top configuration object.  */ +/** Top configuration object. */  struct rs_config {      struct rs_realm *realms;      cfg_t *cfg; @@ -93,47 +105,51 @@ struct rs_context {      struct rs_config *config;      struct rs_alloc_scheme alloc_scheme;      struct rs_error *err; -    struct event_base *evb;	/* Event base.  */ -}; - -enum rs_conn_subtype { -    RS_CONN_OBJTYPE_BASE = 1, -    RS_CONN_OBJTYPE_GENERIC, -    RS_CONN_OBJTYPE_LISTENER, +    struct event_base *evb;	/* Event base. */  }; -#define RS_CONN_MAGIC_BASE 0xAE004711u -#define RS_CONN_MAGIC_GENERIC 0x843AEF47u -#define RS_CONN_MAGIC_LISTENER 0xDCB04783u  /** Base class for a connection. */  struct rs_conn_base {      uint32_t magic;             /* Must be one of RS_CONN_MAGIC_*. */      struct rs_context *ctx; -    struct rs_realm *realm;	/* Owned by ctx.  */ -    struct rs_peer *peers;      /*< Configured peers. */ +    struct rs_realm *realm;	/* Owned by ctx. */ +    /** For a listener, allowed client addr/port pairs. +     For an outgoing connection, set of servers. +     For an incoming connection, the peer (as the only entry). */ +    struct rs_peer *peers;      /**< Configured peers. */ +    struct rs_peer *active_peer; /**< The other end of the connection. */      struct timeval timeout; -    int tryagain;		/* For server failover.  */ +    int tryagain;		/* For server failover. */      void *user_data;      struct rs_error *err; -    int fd;			/* Socket.  */ -    /* TCP transport specifics.  */ -    struct bufferevent *bev;	/* Buffer event.  */ -    /* UDP transport specifics.  */ -    struct event *wev;		/* Write event (for UDP).  */ -    struct event *rev;		/* Read event (for UDP).  */ +    int fd;			/* Socket. */ +    /* TCP transport specifics. */ +    struct bufferevent *bev;	/* Buffer event. */ +    /* UDP transport specifics. */ +    struct event *wev;		/* Write event (for UDP). */ +    struct event *rev;		/* Read event (for UDP). */ +}; + + +enum rs_conn_state { +    RS_CONN_STATE_UNDEFINED = 0, +    RS_CONN_STATE_CONNECTING, +    RS_CONN_STATE_CONNECTED,  };  /** A "generic" connection. */  struct rs_connection {      struct rs_conn_base base_; -    struct event *tev;		/* Timeout event.  */ +    struct event *tev;		/* Timeout event. */      struct rs_conn_callbacks callbacks; -    struct rs_peer *active_peer; +    enum rs_conn_state state; +#if 0      char is_connecting;		/* FIXME: replace with a single state member */      char is_connected;		/* FIXME: replace with a single state member */ -    struct rs_message *out_queue; /* Queue for outgoing UDP packets.  */ +#endif                          /* 0 */ +    struct rs_message *out_queue; /* Queue for outgoing UDP packets. */  #if defined(RS_ENABLE_TLS) -    /* TLS specifics.  */ +    /* TLS specifics. */      SSL_CTX *tls_ctx;      SSL *tls_ssl;  #endif @@ -145,6 +161,7 @@ struct rs_listener {      struct rs_conn_base base_;      struct evconnlistener *evlistener;      struct rs_listener_callbacks callbacks; +    struct rs_listener *next;  };  enum rs_message_flags { @@ -159,16 +176,16 @@ struct rs_message {      struct rs_connection *conn;      unsigned int flags;      uint8_t hdr[RS_HEADER_LEN]; -    struct radius_packet *rpkt;	/* FreeRADIUS object.  */ -    struct rs_message *next;	/* Used for UDP output queue.  */ +    struct radius_packet *rpkt;	/* FreeRADIUS object. */ +    struct rs_message *next;	/* Used for UDP output queue. */  };  #if defined (__cplusplus)  }  #endif -/************************/ -/* Convenience macros.  */ +/***********************/ +/* Convenience macros. */  /* Memory allocation. */  #define rs_calloc(h, nmemb, size) ((h)->alloc_scheme.calloc != NULL \ @@ -192,6 +209,7 @@ struct rs_message {  #define SUBTYPE_P(p, subtype, basemember) \    ((void*) (((char*)(p)) - STRUCT_OFFSET(subtype, basemember)))  #define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) +#define TO_BASE_CONN(c) (&((c)->base_))  static struct rs_connection *TO_GENERIC_CONN (struct rs_conn_base *);  static struct rs_listener *TO_LISTENER_CONN (struct rs_conn_base *);  static INLINE struct rs_connection *TO_GENERIC_CONN (struct rs_conn_base *b) diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index 021f677..cb98db7 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -1,5 +1,5 @@  /** \file radsec.h -    \brief Public interface for libradsec.  */ +    \brief Public interface for libradsec. */  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved.     See LICENSE for licensing information. */ @@ -136,6 +136,7 @@ extern "C" {  /* Data types.  */  struct rs_context;		/* radsec-impl.h */ +struct rs_conn_base;            /* radsec-impl.h */  struct rs_connection;		/* radsec-impl.h */  struct rs_listener;             /* radsec-impl.h */  struct rs_message;		/* radsec-impl.h */ @@ -175,8 +176,10 @@ struct rs_conn_callbacks {  typedef void (*rs_listener_new_conn_cb) (struct rs_connection *conn,                                           void *user_data); +typedef void (*rs_listener_error_cb) (void *user_data);  struct rs_listener_callbacks {      rs_listener_new_conn_cb new_conn_cb; +    rs_listener_error_cb error_cb;  };  typedef struct value_pair rs_avp; @@ -327,11 +330,20 @@ int rs_conn_get_fd(struct rs_connection *conn);  void rs_conn_set_timeout(struct rs_connection *conn, struct timeval *tv);  /* Peer -- client and server.  */ -int rs_peer_create(struct rs_connection *conn, struct rs_peer **peer_out); +/** Create a peer and add it to list of peers held by \a conn. */ +int rs_peer_create_for_conn (struct rs_connection *conn, +                             struct rs_peer **peer_out); +/** Create a peer and add it to list of peers held by \a listener. */ +int rs_peer_create_for_listener (struct rs_listener *listener, +                                 struct rs_peer **peer_out); +/** Set RADIUS secret for \a peer. Free resurces with \a rs_peer_free_secret. */ +int rs_peer_set_secret(struct rs_peer *peer, const char *secret); +/** Free resources allocated by \a rs_peer_set_secret. */ +void rs_peer_free_secret (struct rs_peer *peer);  int rs_peer_set_address(struct rs_peer *peer,  			const char *hostname,  			const char *service); -int rs_peer_set_secret(struct rs_peer *peer, const char *secret); +void rs_peer_free_address (struct rs_peer *peer);  void rs_peer_set_timeout(struct rs_peer *peer, int timeout);  void rs_peer_set_retries(struct rs_peer *peer, int retries); @@ -427,6 +439,12 @@ int rs_err_conn_push_fl(struct rs_connection *conn,  			int line,  			const char *fmt,  			...); +int rs_err_connbase_push_fl (struct rs_conn_base *connbase, +                             int code, +                             const char *file, +                             int line, +                             const char *fmt, +                             ...);  /** Pop the first error from the error FIFO associated with connection      \a conn or NULL if there are no errors in the FIFO.  */  struct rs_error *rs_err_conn_pop(struct rs_connection *conn); diff --git a/lib/message.c b/lib/message.c index e010f94..47590ca 100644 --- a/lib/message.c +++ b/lib/message.c @@ -1,5 +1,5 @@  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +   See LICENSE for licensing information. */  #if defined HAVE_CONFIG_H  #include <config.h> @@ -28,21 +28,21 @@ message_verify_response (struct rs_connection *conn,    int err;    assert (conn); -  assert (conn->active_peer); -  assert (conn->active_peer->secret); +  assert (conn->base_.active_peer); +  assert (conn->base_.active_peer->secret);    assert (response);    assert (response->rpkt);    assert (request);    assert (request->rpkt); -  response->rpkt->secret = conn->active_peer->secret; -  response->rpkt->sizeof_secret = strlen (conn->active_peer->secret); +  response->rpkt->secret = conn->base_.active_peer->secret; +  response->rpkt->sizeof_secret = strlen (conn->base_.active_peer->secret);    /* Verify header and message authenticator.  */    err = nr_packet_verify (response->rpkt, request->rpkt);    if (err)      { -      if (conn->is_connected) +      if (conn->state == RS_CONN_STATE_CONNECTED)  	rs_conn_disconnect(conn);        return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,  				  "nr_packet_verify"); @@ -52,7 +52,7 @@ message_verify_response (struct rs_connection *conn,    err = nr_packet_decode (response->rpkt, request->rpkt);    if (err)      { -      if (conn->is_connected) +      if (conn->state == RS_CONN_STATE_CONNECTED)  	rs_conn_disconnect(conn);        return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__,  				  "nr_packet_decode"); @@ -71,11 +71,11 @@ message_do_send (struct rs_message *msg)    assert (msg);    assert (msg->conn); -  assert (msg->conn->active_peer); -  assert (msg->conn->active_peer->secret); +  assert (msg->conn->base_.active_peer); +  assert (msg->conn->base_.active_peer->secret);    assert (msg->rpkt); -  msg->rpkt->secret = msg->conn->active_peer->secret; +  msg->rpkt->secret = msg->conn->base_.active_peer->secret;    msg->rpkt->sizeof_secret = strlen (msg->rpkt->secret);    /* Encode message.  */ @@ -92,8 +92,8 @@ message_do_send (struct rs_message *msg)    {      char host[80], serv[80]; -    getnameinfo (msg->conn->active_peer->addr_cache->ai_addr, -		 msg->conn->active_peer->addr_cache->ai_addrlen, +    getnameinfo (msg->conn->base_.active_peer->addr_cache->ai_addr, +		 msg->conn->base_.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)); @@ -1,5 +1,5 @@  /* Copyright 2010,2011,2013 NORDUnet A/S. All rights reserved. -   See LICENSE for licensing information.  */ +   See LICENSE for licensing information. */  #if defined HAVE_CONFIG_H  #include <config.h> @@ -20,12 +20,12 @@ peer_pick_peer (struct rs_connection *conn)  {    assert (conn); -  if (conn->active_peer) -    conn->active_peer = conn->active_peer->next; /* Next.  */ -  if (!conn->active_peer) -    conn->active_peer = conn->base_.peers; /* From the top.  */ +  if (conn->base_.active_peer) +    conn->base_.active_peer = conn->base_.active_peer->next; /* Next.  */ +  if (!conn->base_.active_peer) +    conn->base_.active_peer = conn->base_.peers; /* From the top.  */ -  return conn->active_peer; +  return conn->base_.active_peer;  }  struct rs_peer * @@ -33,10 +33,9 @@ peer_create (struct rs_context *ctx, struct rs_peer **rootp)  {    struct rs_peer *p; -  p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p)); +  p = (struct rs_peer *) rs_calloc (ctx, 1, sizeof(*p));    if (p)      { -      memset (p, 0, sizeof(struct rs_peer));        if (*rootp)  	{  	  p->next = (*rootp)->next; @@ -48,36 +47,49 @@ peer_create (struct rs_context *ctx, struct rs_peer **rootp)    return p;  } -/* Public functions.  */  int -rs_peer_create (struct rs_connection *conn, struct rs_peer **peer_out) +peer_create_for_connbase (struct rs_conn_base *connbase, +                          struct rs_peer **peer_out)  {    struct rs_peer *peer; -  peer = peer_create (conn->base_.ctx, &conn->base_.peers); -  if (peer) -    { -      peer->conn = conn; -      peer->realm->timeout = 2;	/* FIXME: Why?  */ -      peer->realm->retries = 2;	/* FIXME: Why?  */ -    } -  else -    return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL); +  peer = peer_create (connbase->ctx, &connbase->peers); +  if (peer == NULL) +    return rs_err_connbase_push_fl (connbase, RSE_NOMEM, __FILE__, __LINE__, +                                    NULL); +  peer->connbase = connbase; +  peer->realm = connbase->realm; +    if (*peer_out)      *peer_out = peer;    return RSE_OK;  } +/* Public functions.  */ +int +rs_peer_create_for_conn (struct rs_connection *conn, struct rs_peer **peer_out) +{ +  return peer_create_for_connbase (TO_BASE_CONN (conn), peer_out); +} +  int -rs_peer_set_address (struct rs_peer *peer, const char *hostname, +rs_peer_create_for_listener (struct rs_listener *listener, +                             struct rs_peer **peer_out) +{ +  return peer_create_for_connbase (TO_BASE_CONN (listener), peer_out); +} + +int +rs_peer_set_address (struct rs_peer *peer, +                     const char *hostname,                       const char *service)  {    assert (peer); -  assert (peer->conn); -  assert (peer->conn->base_.ctx); +  assert (peer->connbase); +  assert (peer->connbase->ctx); -  peer->hostname = rs_strdup (peer->conn->base_.ctx, hostname); -  peer->service = rs_strdup (peer->conn->base_.ctx, service); +  peer->hostname = rs_strdup (peer->connbase->ctx, hostname); +  peer->service = rs_strdup (peer->connbase->ctx, service);    if (peer->hostname == NULL || peer->service == NULL)      return RSE_NOMEM; @@ -85,12 +97,28 @@ rs_peer_set_address (struct rs_peer *peer, const char *hostname,  }  void +rs_peer_free_address (struct rs_peer *peer) +{ +  assert (peer); +  assert (peer->connbase); +  assert (peer->connbase->ctx); + +  if (peer->hostname) +    rs_free (peer->connbase->ctx, peer->hostname); +  peer->hostname = NULL; +  if (peer->service) +    rs_free (peer->connbase->ctx, peer->service); +  peer->service = NULL; +} + +void  rs_peer_set_timeout (struct rs_peer *peer, int timeout)  {    assert (peer);    assert (peer->realm);    peer->realm->timeout = timeout;  } +  void  rs_peer_set_retries (struct rs_peer *peer, int retries)  { @@ -102,12 +130,26 @@ rs_peer_set_retries (struct rs_peer *peer, int retries)  int  rs_peer_set_secret (struct rs_peer *peer, const char *secret)  { -  if (peer->secret) -    free (peer->secret); -  peer->secret = (char *) malloc (strlen(secret) + 1); +  assert (peer); +  assert (peer->connbase); +  assert (peer->connbase->ctx); + +  rs_peer_free_secret (peer); +  peer->secret = rs_calloc (peer->connbase->ctx, 1, strlen(secret) + 1);    if (!peer->secret) -    return rs_err_conn_push (peer->conn, RSE_NOMEM, NULL); +    return rs_err_connbase_push (peer->connbase, RSE_NOMEM, NULL);    strcpy (peer->secret, secret);    return RSE_OK;  } +void +rs_peer_free_secret (struct rs_peer *peer) +{ +  assert (peer); +  assert (peer->connbase); +  assert (peer->connbase->ctx); + +  if (peer->secret) +    rs_free (peer->connbase->ctx, peer->secret); +  peer->secret = NULL; +} @@ -3,3 +3,4 @@  struct rs_peer *peer_create (struct rs_context *ctx, struct rs_peer **rootp);  struct rs_peer *peer_pick_peer (struct rs_connection *conn); +int peer_create_for_connbase (struct rs_conn_base *, struct rs_peer **); diff --git a/lib/radsec.sym b/lib/radsec.sym index 7e64560..6ad1361 100644 --- a/lib/radsec.sym +++ b/lib/radsec.sym @@ -77,7 +77,10 @@ rs_message_create  rs_message_create_authn_request  rs_message_destroy  rs_message_send -rs_peer_create +rs_peer_create_for_conn +rs_peer_create_for_listener +rs_peer_free_address +rs_peer_free_secret  rs_peer_set_address  rs_peer_set_retries  rs_peer_set_secret @@ -24,12 +24,12 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)    if (event_init_eventbase (conn))      return -1; -  if (!conn->active_peer) +  if (!conn->base_.active_peer)      peer_pick_peer (conn); -  if (!conn->active_peer) +  if (!conn->base_.active_peer)      return rs_err_conn_push_fl (conn, RSE_NOPEER, __FILE__, __LINE__, NULL); -  if (event_init_socket (conn, conn->active_peer)) +  if (event_init_socket (conn, conn->base_.active_peer))      return -1;    if (conn->base_.realm->type == RS_CONN_TYPE_TCP @@ -37,7 +37,7 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)      {        if (tcp_init_connect_timer (conn))  	return -1; -      if (event_init_bufferevent (conn, conn->active_peer)) +      if (event_init_bufferevent (conn, conn->base_.active_peer))  	return -1;      }    else @@ -48,9 +48,9 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)  	return -1;      } -  if (!conn->is_connected) -    if (!conn->is_connecting) -      event_do_connect (conn); +  if (conn->state != RS_CONN_STATE_CONNECTED +      && conn->state != RS_CONN_STATE_CONNECTING) +    event_do_connect (conn);    return RSE_OK;  } @@ -58,7 +58,8 @@ _conn_open (struct rs_connection *conn, struct rs_message *msg)  static int  _conn_is_open_p (struct rs_connection *conn)  { -  return conn->active_peer && conn->is_connected; +  return conn->state == RS_CONN_STATE_CONNECTED +    && conn->base_.active_peer != NULL;  }  /* User callback used when we're dispatching for user.  */ @@ -92,7 +93,7 @@ rs_message_send (struct rs_message *msg, void *user_data)    assert (conn->base_.ctx);    assert (conn->base_.ctx->evb); -  assert (conn->active_peer); +  assert (conn->base_.active_peer);    assert (conn->base_.fd >= 0);    conn->base_.user_data = user_data; @@ -109,7 +109,8 @@ _read_message (struct rs_message *msg)        /* Find out what happens if there's data left in the buffer.  */        {  	size_t rest = 0; -	rest = evbuffer_get_length (bufferevent_get_input (msg->conn->bev)); +	rest = +          evbuffer_get_length (bufferevent_get_input (msg->conn->base_.bev));  	if (rest)  	  rs_debug (("%s: returning with %d octets left in buffer\n", __func__,  		     rest)); @@ -178,11 +179,10 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data)    assert (msg->conn);    conn = msg->conn;  #if defined (DEBUG) -  assert (msg->conn->active_peer); -  p = conn->active_peer; +  assert (msg->conn->base_.active_peer); +  p = conn->base_.active_peer;  #endif -  conn->is_connecting = 0;    if (events & BEV_EVENT_CONNECTED)      {        if (conn->tev) @@ -213,7 +213,7 @@ tcp_event_cb (struct bufferevent *bev, short events, void *user_data)  	}        else  	{ -	  rs_debug (("%s: %d: %d (%s)\n", __func__, conn->fd, sockerr, +	  rs_debug (("%s: %d: %d (%s)\n", __func__, conn->base_.fd, sockerr,  		     evutil_socket_error_to_string (sockerr)));  	  rs_err_conn_push_fl (conn, RSE_SOCKERR, __FILE__, __LINE__,  			       "%d: %d (%s)", conn->base_.fd, sockerr, @@ -26,14 +26,14 @@ _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)      {        memset (c, 0, sizeof (struct tls));        /* _conn_open() should've picked a peer by now. */ -      assert (conn->active_peer); +      assert (conn->base_.active_peer);        /* TODO: Make sure old radsecproxy code doesn't free these all  	 of a sudden, or strdup them.  */        c->name = realm->name; -      c->cacertfile = conn->active_peer->cacertfile; +      c->cacertfile = conn->base_.active_peer->cacertfile;        c->cacertpath = NULL;	/* NYI */ -      c->certfile = conn->active_peer->certfile; -      c->certkeyfile = conn->active_peer->certkeyfile; +      c->certfile = conn->base_.active_peer->certfile; +      c->certkeyfile = conn->base_.active_peer->certkeyfile;        c->certkeypwd = NULL;	/* NYI */        c->cacheexpiry = 0;	/* NYI */        c->crlcheck = 0;		/* NYI */ @@ -60,7 +60,7 @@ psk_client_cb (SSL *ssl,    conn = SSL_get_ex_data (ssl, 0);    assert (conn != NULL); -  cred = conn->active_peer->transport_cred; +  cred = conn->base_.active_peer->transport_cred;    assert (cred != NULL);    /* NOTE: Ignoring identity hint from server.  */ @@ -126,7 +126,7 @@ rs_tls_init (struct rs_connection *conn)    assert (conn->base_.ctx);    ctx = conn->base_.ctx; -  tlsconf = _get_tlsconf (conn, conn->active_peer->realm); +  tlsconf = _get_tlsconf (conn, conn->base_.active_peer->realm);    if (!tlsconf)      return -1;    ssl_ctx = tlsgetctx (RAD_TLS, tlsconf); @@ -147,7 +147,7 @@ rs_tls_init (struct rs_connection *conn)      }  #if defined RS_ENABLE_TLS_PSK -  if (conn->active_peer->transport_cred != NULL) +  if (conn->base_.active_peer->transport_cred != NULL)      {        SSL_set_psk_client_callback (ssl, psk_client_cb);        SSL_set_ex_data (ssl, 0, conn); @@ -203,9 +203,9 @@ tls_verify_cert (struct rs_connection *conn)    struct in6_addr addr;    const char *hostname = NULL; -  assert (conn->active_peer->conn == conn); -  assert (conn->active_peer->hostname != NULL); -  hostname = conn->active_peer->hostname; +  assert (conn->base_.active_peer != NULL); +  assert (conn->base_.active_peer->hostname != NULL); +  hostname = conn->base_.active_peer->hostname;    /* verifytlscert() performs basic verification as described by       OpenSSL VERIFY(1), i.e. verification of the certificate chain.  */ @@ -129,7 +129,7 @@ _evcb (evutil_socket_t fd, short what, void *user_data)        assert (msg);        assert (msg->conn); -      if (!msg->conn->is_connected) +      if (msg->conn->state == RS_CONN_STATE_CONNECTING)  	event_on_connect (msg->conn, msg);        if (msg->conn->out_queue) @@ -11,9 +11,10 @@ rs_strdup (struct rs_context *ctx, const char *s)  {    char *buf = rs_calloc (ctx, 1, strlen (s) + 1); -  if (buf != NULL) -    return strcpy (buf, s); +  if (buf) +    strcpy (buf, s); +  else +    rs_err_ctx_push (ctx, RSE_NOMEM, NULL); -  rs_err_ctx_push (ctx, RSE_NOMEM, NULL); -  return NULL; +  return buf;  } | 
