WIP -- reading configuration.
authorLinus Nordberg <linus@nordu.net>
Sun, 3 Oct 2010 23:31:01 +0000 (01:31 +0200)
committerLinus Nordberg <linus@nordu.net>
Sun, 3 Oct 2010 23:31:01 +0000 (01:31 +0200)
lib/conf.c [new file with mode: 0644]
lib/err.c
lib/examples/Makefile
lib/examples/client-blocking.c
lib/examples/client.conf [new file with mode: 0644]
lib/include/radsec/radsec-impl.h
lib/include/radsec/radsec.h
lib/radsec.c

diff --git a/lib/conf.c b/lib/conf.c
new file mode 100644 (file)
index 0000000..9acf4d4
--- /dev/null
@@ -0,0 +1,104 @@
+#include <confuse.h>
+#include <string.h>
+#include <radsec/radsec.h>
+#include <radsec/radsec-impl.h>
+
+#if 0
+  realm NAME {
+      type = STRING
+      server {
+          hostname = STRING
+         service = STRING
+         secret = STRING
+         timeout = INT         /* optional */
+         tries = INT           /* optional */
+      }
+  }
+#endif
+
+int
+rs_context_read_config(struct rs_handle *ctx, const char *config_file)
+{
+#warning "Missing some error handling in rs_context_config_read()"
+  cfg_opt_t server_opts[] =
+    {
+      CFG_STR ("hostname", NULL, CFGF_NONE),
+      CFG_STR ("service", "radius", CFGF_NONE),
+      CFG_STR ("secret", NULL, CFGF_NONE),
+      CFG_INT ("timeout", 3, CFGF_NONE),
+      CFG_INT ("tries", 1, CFGF_NONE),
+      CFG_END ()
+    };
+  cfg_opt_t realm_opts[] =
+    {
+      CFG_STR ("type", "UDP", CFGF_NONE),
+      CFG_SEC ("server", server_opts, CFGF_MULTI),
+      CFG_END ()
+    };
+  cfg_opt_t opts[] =
+    {
+      CFG_SEC ("realm", realm_opts, CFGF_TITLE | CFGF_MULTI),
+      CFG_END ()
+    };
+  cfg_t *cfg, *cfg_realm, *cfg_server;
+  int i, j;
+
+  cfg = cfg_init (opts, CFGF_NONE);
+  if (cfg_parse (cfg, config_file) == CFG_PARSE_ERROR)
+    return rs_err_ctx_push (ctx, RSE_CONFIG, "%s: invalid configuration file",
+                           config_file);
+  for (i = 0; i < cfg_size (cfg, "realm"); i++)
+    {
+      struct rs_realm *r = rs_malloc (ctx, sizeof(*r));
+      const char *typestr;
+      enum rs_conn_type type;
+
+      if (!r)
+       return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__, NULL);
+      memset (r, 0, sizeof(*r));
+      if (ctx->realms)
+       ctx->realms->next = r;
+      else
+       ctx->realms = r;
+      cfg_realm = cfg_getnsec (cfg, "realm", i);
+      r->name = strdup (cfg_title (cfg_realm));
+      typestr = cfg_getstr (cfg_realm, "type");
+      if (!strcmp (typestr, "UDP"))
+       type = RS_CONN_TYPE_UDP;
+      else if (!strcmp (typestr, "TCP"))
+       type = RS_CONN_TYPE_TCP;
+      else if (!strcmp (typestr, "TLS"))
+       type = RS_CONN_TYPE_TLS;
+      else if (!strcmp (typestr, "DTLS"))
+       type = RS_CONN_TYPE_DTLS;
+      else
+       return rs_err_ctx_push_fl (ctx, RSE_CONFIG, __FILE__, __LINE__,
+                                  "%s: invalid connection type", typestr);
+      for (j = 0; j < cfg_size (cfg_realm, "server"); j++)
+       {
+         struct rs_peer *p = _rs_peer_create (ctx, &r->peers);
+         if (!p)
+           return rs_err_ctx_push_fl (ctx, RSE_NOMEM, __FILE__, __LINE__,
+                                      NULL);
+
+         cfg_server = cfg_getnsec (cfg_realm, "server", j);
+         _rs_resolv (&p->addr, type, cfg_getstr (cfg_server, "hostname"),
+                     cfg_getstr (cfg_server, "service"));
+         p->secret = strdup (cfg_getstr (cfg_server, "secret"));
+         p->timeout = cfg_getint (cfg_server, "timeout");
+         p->tries = cfg_getint (cfg_server, "tries");
+       }
+    }
+  return RSE_OK;
+}
+
+struct rs_realm
+*rs_conf_find_realm(struct rs_handle *ctx, const char *name)
+{
+  struct rs_realm *r;
+
+  for (r = ctx->realms; r; r = r->next)
+    if (!strcmp (r->name, name))
+       return r;
+  return NULL;
+}
index 00de47f..71a8380 100644 (file)
--- a/lib/err.c
+++ b/lib/err.c
@@ -18,22 +18,23 @@ const char *_errtxt[] = {
   "no peer configured"         /* 8 RSE_NOPEER */
   "libevent error"             /* 9 RSE_EVENT */
   "connection error"           /* 10 RSE_CONNERR */
-  "ERR 11"                     /*  RSE_ */
+  "invalid configuration file" /* 11 RSE_CONFIG */
   "ERR 12"                     /*  RSE_ */
   "ERR 13"                     /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
-  "ERR "                       /*  RSE_ */
+  "ERR 14"                     /*  RSE_ */
+  "ERR 15"                     /*  RSE_ */
+  "ERR 16"                     /*  RSE_ */
+  "ERR 17"                     /*  RSE_ */
+  "ERR 18"                     /*  RSE_ */
+  "ERR 19"                     /*  RSE_ */
+  "ERR 20"                     /*  RSE_ */
   "some error"                 /* 21 RSE_SOME_ERROR */
 };
 #define ERRTXT_SIZE (sizeof(_errtxt) / sizeof(*_errtxt))
 
 static struct rs_error *
-_err_new (unsigned int code, const char *file, int line, const char *fmt, va_list args)
+_err_vcreate (unsigned int code, const char *file, int line, const char *fmt,
+             va_list args)
 {
   struct rs_error *err;
 
@@ -64,10 +65,23 @@ _err_new (unsigned int code, const char *file, int line, const char *fmt, va_lis
   return err;
 }
 
+struct rs_error *
+_rs_err_create (unsigned int code, const char *file, int line, const char *fmt,
+               ...)
+{
+  struct rs_error *err;
+
+  va_list args;
+  va_start (args, fmt);
+  err = _err_vcreate (code, file, line, fmt, args);
+  va_end (args);
+  return err;
+}
+
 static int
 _ctx_err_vpush_fl (struct rs_handle *ctx, int code, const char *file, int line, const char *fmt, va_list args)
 {
-  struct rs_error *err = _err_new (code, file, line, fmt, args);
+  struct rs_error *err = _err_vcreate (code, file, line, fmt, args);
 
   if (err)
     ctx->err = err;
@@ -94,13 +108,20 @@ rs_err_ctx_push_fl (struct rs_handle *ctx, int code, const char *file, int line,
   return code;
 }
 
+int
+_rs_err_conn_push_err (struct rs_connection *conn, struct rs_error *err)
+{
+  conn->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)
 {
-  struct rs_error *err = _err_new (code, file, line, fmt, args);
+  struct rs_error *err = _err_vcreate (code, file, line, fmt, args);
 
   if (err)
-    conn->err = err;
+    _rs_err_conn_push_err (conn, err);
   return code;
 }
 
index 4802c4b..cf3441b 100644 (file)
@@ -1,6 +1,6 @@
 SPECIAL = 
 #SPECIAL += -DUSE_REQUEST_OBJECT
-#SPECIAL += -DUSE_CONFIG_FILE
+SPECIAL += -DUSE_CONFIG_FILE
 
 CFLAGS = -Wall -g -I ../include $(SPECIAL)
 
@@ -9,7 +9,7 @@ HFILES = ../include/radsec/radsec.h ../include/radsec/radsec-impl.h
 all: client-blocking
 
 client-blocking: client-blocking.c ../libradsec.a $(HFILES)
-       $(CC) $(CFLAGS) -o $@ $< -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec -L /usr/local/lib -levent_core
+       $(CC) $(CFLAGS) -o $@ $< -lconfuse -L /usr/lib/freeradius -lfreeradius-radius -L .. -lradsec -L /usr/local/lib -levent_core
 
 clean:
        -rm *.o *.gch client-blocking
index 0e6ad39..8cd9968 100644 (file)
@@ -20,7 +20,6 @@ blocking_client (const char *av1, const char *av2)
 {
   struct rs_handle *h;
   struct rs_connection *conn;
-  struct rs_peer *server;
   struct rs_packet *req, *resp;
   RADIUS_PACKET *fr_pkt;
   VALUE_PAIR *fr_vp;
@@ -29,19 +28,23 @@ blocking_client (const char *av1, const char *av2)
     return NULL;
 
 #if !defined (USE_CONFIG_FILE)
-  if (rs_conn_create (h, &conn, NULL))
-    return rs_err_conn_pop (conn);
-  rs_conn_set_type (conn, RS_CONN_TYPE_UDP);
-  if (rs_server_create (conn, &server))
-    return rs_err_conn_pop (conn);
-  if (rs_server_set_address (server, av1, atoi (av2)))
-    return rs_err_conn_pop (conn);
-  rs_server_set_timeout (server, 1);
-  rs_server_set_tries (server, 3);
-  if (rs_server_set_secret (server, SECRET))
-    return rs_err_conn_pop (conn);
+  {
+    struct rs_peer *server;
+
+    if (rs_conn_create (h, &conn, NULL))
+      return rs_err_conn_pop (conn);
+    rs_conn_set_type (conn, RS_CONN_TYPE_UDP);
+    if (rs_server_create (conn, &server))
+      return rs_err_conn_pop (conn);
+    if (rs_server_set_address (server, av1, av2))
+      return rs_err_conn_pop (conn);
+    rs_server_set_timeout (server, 1);
+    rs_server_set_tries (server, 3);
+    if (rs_server_set_secret (server, SECRET))
+      return rs_err_conn_pop (conn);
+  }
 #else
-  if (rs_context_config_read (h, av1))
+  if (rs_context_read_config (h, av1))
     return rs_err_ctx_pop (h);
   if (rs_conn_create (h, &conn, av2))
     return rs_err_conn_pop (conn);
diff --git a/lib/examples/client.conf b/lib/examples/client.conf
new file mode 100644 (file)
index 0000000..5f9536f
--- /dev/null
@@ -0,0 +1,10 @@
+realm blocking {
+    type = "UDP"
+    server {
+        hostname = "localhost"
+       service = "1820"
+       secret = "sikrit"
+       timeout = 1         /* optional */
+       tries = 10            /* optional */
+    }
+}
index 503b2e5..9421fd6 100644 (file)
@@ -46,6 +46,7 @@ struct rs_realm {
     char *name;
     enum rs_conn_type type;
     struct rs_peer *peers;
+    struct rs_realm *next;
 };
 
 struct rs_handle {
@@ -79,6 +80,13 @@ struct rs_attr {
     VALUE_PAIR *vp;
 };
 
+/* Nonpublic functions.  */
+struct rs_error *_rs_resolv (struct evutil_addrinfo **addr, rs_conn_type_t type, const char *hostname, const char *service);
+struct rs_peer *_rs_peer_create (struct rs_handle *ctx, struct rs_peer **rootp);
+struct rs_error *_rs_err_create (unsigned int code, const char *file, int line, const char *fmt, ...);
+int _rs_err_conn_push_err (struct rs_connection *conn, struct rs_error *err);
+
+
 /* Convenience macros.  */
 #define rs_calloc(h, nmemb, size) \
     (h->alloc_scheme.calloc ? h->alloc_scheme.calloc : calloc)(nmemb, size)
index c108d8a..982c430 100644 (file)
@@ -16,6 +16,7 @@ enum rs_err_code {
     RSE_NOPEER = 8,
     RSE_EVENT = 9,
     RSE_CONNERR = 10,
+    RSE_CONFIG = 11,
     RSE_SOME_ERROR = 21,
 };
 
@@ -89,7 +90,7 @@ int rs_conn_receive_packet(struct rs_connection *conn, struct rs_packet **pkt_ou
 
 /* Server and client.  */
 int rs_server_create(struct rs_connection *conn, struct rs_peer **server);
-int rs_server_set_address(struct rs_peer *server, const char *hostname, int port);
+int rs_server_set_address(struct rs_peer *server, const char *hostname, const char *service);
 int rs_server_set_secret(struct rs_peer *server, const char *secret);
 void rs_server_set_timeout(struct rs_peer *server, int timeout);
 void rs_server_set_tries(struct rs_peer *server, int tries);
index adf5576..96182a6 100644 (file)
@@ -73,12 +73,6 @@ int rs_context_set_alloc_scheme(struct rs_handle *ctx, struct rs_alloc_scheme *s
                             "%s: NYI", __func__);
 }
 
-int rs_context_config_read(struct rs_handle *ctx, const char *config_file)
-{
-  return rs_err_ctx_push_fl (ctx, RSE_NOSYS, __FILE__, __LINE__,
-                            "%s: NYI", __func__);
-}
-
 int
 rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn,
               const char *config)
@@ -95,8 +89,12 @@ rs_conn_create(struct rs_handle *ctx, struct rs_connection **conn,
          struct rs_realm *r = rs_conf_find_realm (ctx, config);
          if (r)
            {
+             struct rs_peer *p;
+
              c->type = r->type;
-             c->peers = r->peers; /* FIXME: Copy?  */
+             c->peers = r->peers; /* FIXME: Copy instead?  */
+             for (p = c->peers; p; p = p->next)
+               p->conn = c;
            }
        }
     }
@@ -111,22 +109,21 @@ rs_conn_set_type(struct rs_connection *conn, rs_conn_type_t type)
   conn->type = type;
 }
 
-struct addrinfo *
-_resolv (struct rs_connection *conn, const char *hostname, int port)
+
+struct rs_error *
+_rs_resolv (struct evutil_addrinfo **addr, rs_conn_type_t type,
+           const char *hostname, const char *service)
 {
   int err;
-  char portstr[6];
   struct evutil_addrinfo hints, *res = NULL;
 
-  snprintf (portstr, sizeof(portstr), "%d", port);
   memset (&hints, 0, sizeof(struct evutil_addrinfo));
   hints.ai_family = AF_UNSPEC; /* v4 or v6.  */
   hints.ai_flags = AI_ADDRCONFIG;
-  switch (conn->type)
+  switch (type)
     {
     case RS_CONN_TYPE_NONE:
-      rs_err_conn_push_fl (conn, RSE_INVALID_CONN, __FILE__, __LINE__, NULL);
-      return NULL;
+      return _rs_err_create (RSE_INVALID_CONN, __FILE__, __LINE__, NULL, NULL);
     case RS_CONN_TYPE_TCP:
       /* Fall through.  */
     case RS_CONN_TYPE_TLS:
@@ -140,33 +137,30 @@ _resolv (struct rs_connection *conn, const char *hostname, int port)
       hints.ai_protocol = IPPROTO_UDP;
       break;
     }
-  err = evutil_getaddrinfo (hostname, portstr, &hints, &res);
+  err = evutil_getaddrinfo (hostname, service, &hints, &res);
   if (err)
-    rs_err_conn_push_fl (conn, RSE_BADADDR, __FILE__, __LINE__,
-                        "%s:%d: bad host name or port (%s)",
-                        hostname, port, evutil_gai_strerror(err));
-  return res;                  /* Simply use first result.  */
+    return _rs_err_create (RSE_BADADDR, __FILE__, __LINE__,
+                          "%s:%s: bad host name or service name (%s)",
+                          hostname, service, evutil_gai_strerror(err));
+  *addr = res;                 /* Simply use first result.  */
+  return NULL;
 }
 
-static struct rs_peer *
-_peer_new (struct rs_connection *conn)
+struct rs_peer *
+_rs_peer_create (struct rs_handle *ctx, struct rs_peer **rootp)
 {
   struct rs_peer *p;
 
-  p = (struct rs_peer *) malloc (sizeof(*p));
+  p = (struct rs_peer *) rs_malloc (ctx, sizeof(*p));
   if (p)
     {
       memset (p, 0, sizeof(struct rs_peer));
-      p->conn = conn;
       p->fd = -1;
-      p->next = conn->peers;
-      if (conn->peers)
-       conn->peers->next = p;
+      if (*rootp)
+       (*rootp)->next = p;
       else
-       conn->peers = p;
+       *rootp = p;
     }
-  else
-    rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
   return p;
 }
 
@@ -175,22 +169,30 @@ rs_server_create (struct rs_connection *conn, struct rs_peer **server)
 {
   struct rs_peer *srv;
 
-  srv = _peer_new (conn);
+  srv = _rs_peer_create (conn->ctx, &conn->peers);
   if (srv)
     {
+      srv->conn = conn;
       srv->timeout = 1;
       srv->tries = 3;
     }
+  else
+    return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
   if (*server)
     *server = srv;
-  return srv ? RSE_OK : -1;
+  return RSE_OK;
 }
 
 int
-rs_server_set_address (struct rs_peer *server, const char *hostname, int port)
+rs_server_set_address (struct rs_peer *server, const char *hostname,
+                      const char *service)
 {
-  server->addr = _resolv (server->conn, hostname, port);
-  return server->addr ? RSE_OK : -1;
+  struct rs_error *err;
+
+  err = _rs_resolv (&server->addr, server->conn->type, hostname, service);
+  if (err)
+    return _rs_err_conn_push_err (server->conn, err);
+  return RSE_OK;
 }
 
 void