Trust router response handler
[freeradius.git] / src / modules / rlm_realm / trustrouter_integ.c
index ee94097..6756319 100644 (file)
 #include <trust_router/tid.h>
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/modules.h>
 #include "trustrouter_integ.h"
+#include <trust_router/tr_dh.h>
+#include <freeradius-devel/realms.h>
+
+static TIDC_INSTANCE *global_tidc = NULL;
+
+
+struct resp_opaque {
+  REALM *output_realm;
+  TID_RC result;
+  char err_msg[1024];
+};
 
-static TIDC_INSTANCE *global_tidc;
-static int tidc_response_received = 0;
 
 int tr_init(void) 
 {
-  if (NULL == (global_tidc = tidc_create()))
+  if (NULL == (global_tidc = tidc_create())) {
+    fprintf(stderr, "tr_init: Error creating global TIDC instance.\n");
     return -1;
-  else
-    return 0;
+  }
+  if (NULL == (global_tidc->client_dh = tr_create_dh_params(NULL, 0))) {
+    fprintf(stderr, "tr_init: Error creating client DH params.\n");
+    return 1;
+  }
+  return 0;
 }
 
-static void tr_response_func (TIDC_INSTANCE *tidc, TID_REQ *req, TID_RESP *resp, void *cookie)
+static fr_tls_server_conf_t *construct_tls( TIDC_INSTANCE *inst,
+                                           TID_SRVR_BLK *server)
 {
+  fr_tls_server_conf_t *tls = rad_malloc(sizeof(*tls));
+  unsigned char *key_buf = NULL;
+  ssize_t keylen;
+  char *hexbuf = NULL;
+  int i;
 
-}
-
+  if (tls == NULL)
+    goto error;
+  memset(tls, 0, sizeof(*tls));
+  keylen = tr_compute_dh_key(&key_buf, server->aaa_server_dh->pub_key,
+                            inst->client_dh);
+  if (keylen <= 0) {
+    DEBUG2("DH error");
+    goto error;
+  }
+  hexbuf = rad_malloc(keylen*2 + 1);
+  if (hexbuf == NULL)
+    goto error;
+  tr_bin_to_hex(key_buf, keylen, hexbuf,
+            2*keylen + 1);
+  tls->psk_password = hexbuf;
+  tls->psk_identity = tr_name_strdup(server->key_name);
 
-#if 0
+  fprintf (stderr, "construct_tls: Client key generated (key name = %s):\n", tls->psk_identity);
+  for (i = 0; i < keylen; i++) {
+    printf("%.2x", key_buf[i]); 
+  }
+  printf("\n");
 
-static void tr_response_func(UNUSED tpqc_instance *inst,
-                            const tpq_resp *response, void *cookie)
+  tls->cipher_list = strdup("PSK");
+  tls->fragment_size = 4200;
+  tls->ctx = tls_init_ctx(tls, 1);
+  if (tls->ctx == NULL)
+    goto error;
+  memset(key_buf, 0, keylen);
+  free(key_buf);
+    return tls;
+ error:
+    if (key_buf) {
+      memset(key_buf, 0, keylen);
+      free(key_buf);
+    }
+    if (hexbuf) {
+      memset(hexbuf, 0, keylen*2);
+      free(hexbuf);
+    }
+    if (tls)
+      free(tls);
+    return NULL;
+}
+  
+static void tr_response_func( TIDC_INSTANCE *inst,
+                            UNUSED TID_REQ *req, TID_RESP *resp,
+                            void *cookie)
 {
-       home_server *hs = NULL;
-       home_pool_t *pool = NULL;
-       REALM *nr = NULL;
-       char home_pool_name[256];
-       fr_ipaddr_t home_server_ip;
-
-       /*xxx There's a race if this is called in two threads for the same realm. Imagine if the home pool is not found in either thread, is inserted in one thread and then the second thread's insert fails. The second thread will fail. Probably not a huge deal because a retransmit will make the world great again.*/
-       home_server_ip = /*xxx something from response*/
-               hs = home_server_find( home_server_ip, /*xxx port from response*/,
-                                      /*xxx proto from response*/);
-       if (hs) {
-               /*confirm that hs is good enough to use; I think this mainly involves making sure we find the key credible. */
-               abort();
-       } else {
-               hs = rad_malloc(sizeof(*hs));
-               if (!hs) return;
-               memset(hs, 0, sizeof(*hs));
-               hs->type = HOME_TYPE_AUTH;
-               hs->ipaddr = *home_server_ip;
-               hs-> name = /*name from response*/
-                       hs->hostname = /*name from response*/
-                       hs->port = /*port from response*/
-                       hs->proto = /*proto from response*/
-                       hs->tls = response_to_tls(response);
-               if (hs->tls == NULL) goto error;
-               if (!realms_home_server_add(hs, NULL, 0))
-                       goto error;
-       }
-       strlcpy(home_pool_name, "hp-", sizeof(home_pool_name);
-               strlcat(home_pool_name, response->realm,, sizeof(home_pool_name));
-               pool = home_pool_byname(home_pool_name, HOME_SERVER_AUTH);
-               if (pool == NULL) {
-                       pool = rad_malloc(sizeof(*pool));
-                       if (pool == NULL) goto error;
-                       memset(pool, 0, sizeof(*pool));
-                       pool->type = HOME_POOL_CLIENT_PORT_BALANCE;
-                       pool->server_type = HOME_TYPE_AUTH;
-                       pool->name = strdup(home_pool_name);
-                       if (pool->name == NULL) goto error;
-                       pool->num_home_servers = 1;
-                       pool->servers[0] = hs;
-                       if (!realms_pool_add(pool)) goto error;
-               }
+  home_server *hs = NULL;
+  TID_SRVR_BLK *server;
+  home_pool_t *pool = NULL;
+  REALM *nr = NULL;
+  char home_pool_name[256];
+  int pool_added = 0;
+  fr_ipaddr_t home_server_ip;
+  struct resp_opaque  *opaque = (struct resp_opaque *) cookie;
+  size_t num_servers = 0;
+
+  /*xxx There's a race if this is called in two threads for the
+    same realm. Imagine if the home pool is not found in either
+    thread, is inserted in one thread and then the second
+    thread's insert fails. The second thread will fail. Probably
+    not a huge deal because a retransmit will make the world
+    great again.*/
+  if (resp->result != TID_SUCCESS) {
+    size_t err_msg_len;
+    opaque->result = resp->result;
+    memset(opaque->err_msg, 0, sizeof(opaque->err_msg));
+    if (resp->err_msg) {
+      err_msg_len = resp->err_msg->len+1;
+      if (err_msg_len > sizeof(opaque->err_msg))
+       err_msg_len = sizeof(opaque->err_msg);
+      strlcpy(opaque->err_msg, resp->err_msg->buf, err_msg_len);
+    }
+    return;
+  }
+  server = resp->servers;
+  while (server) {
+    num_servers++;
+    server = server->next;
+  }
+  strlcpy(home_pool_name, "hp-", sizeof(home_pool_name));
+  tr_name_strlcat(home_pool_name, resp->realm, sizeof(home_pool_name));
+  pool = home_pool_byname(home_pool_name, HOME_TYPE_AUTH);
+  if (pool == NULL) {
+    size_t i = 0;
+    pool = rad_malloc(sizeof(*pool) + num_servers *sizeof(home_server *));
+                 
+    if (pool == NULL) goto error;
+    memset(pool, 0, sizeof(*pool));
+    pool->type = HOME_POOL_CLIENT_PORT_BALANCE;
+    pool->server_type = HOME_TYPE_AUTH;
+    pool->name = strdup(home_pool_name);
+    if (pool->name == NULL) goto error;
+    pool->num_home_servers = num_servers;
+
+    server = resp->servers;
+    while (server) {
+      home_server_ip.af = AF_INET;
+      home_server_ip.scope = 0;
+      home_server_ip.ipaddr.ip4addr = server->aaa_server_addr;
+         
+      hs = home_server_find( &home_server_ip, 2083,
+                            IPPROTO_TCP);
+      if (hs) {
+       DEBUG2("Found existing home_server %s", hs->name);
+      } else {
+       hs = rad_malloc(sizeof(*hs));
+       if (!hs) return;
+       memset(hs, 0, sizeof(*hs));
+       hs->type = HOME_TYPE_AUTH;
+       hs->ipaddr = home_server_ip;
+       /* TBD -- update name to be unique per server */
+       hs-> name = strdup("blah");
+         hs->hostname =strdup("blah");
+         hs->port = 2083;
+       hs->proto = IPPROTO_TCP;
+       hs->secret = strdup("radsec");
+       hs->tls = construct_tls(inst, server);
+       if (hs->tls == NULL) goto error;
+       if (!realms_home_server_add(hs, NULL, 0))
+         goto error;
+      }
+      pool->servers[i++] = hs;
+      hs = NULL;
+      server = server->next;
+    }
+                       
+    if (!realms_pool_add(pool, NULL)) goto error;
+    pool_added = 1;
+  }
                
-               nr = rad_malloc(sizeof (REALM));
-               if (nr == NULL) goto error;
-               memset(nr, 0, sizeof(REALM));
-               nr->name = strdup(response->realm);
-               nr->auth_pool = pool;
-               if (!realms_realm_add(nr)) goto error;
+  nr = rad_malloc(sizeof (REALM));
+  if (nr == NULL) goto error;
+  memset(nr, 0, sizeof(REALM));
+  nr->name = tr_name_strdup(resp->realm);
+  nr->auth_pool = pool;
+  if (!realms_realm_add(nr, NULL)) goto error;
+  opaque->output_realm = nr;
                
-               /*do something with the cookie to let the poor other theread know to go forward*/
                
-               return;
+  return;
                
-       error:
-               /*What do we do here? We don't actually have a way to delete things from the tree, so we can't free them.
-                */
-               /*I guess we could have partial unwinding for the parts we haven't added yet*/
-
+ error:
+  if (hs)
+    free(hs);
+  if (pool && (!pool_added)) {
+    if (pool->name)
+      free((char *) pool->name);
+    free(pool);
+  }
+  if (nr)
+    free(nr);
+  return;
+}
                
-#endif
 
 REALM *tr_query_realm(const char *q_realm,
                      const char  *q_community,
@@ -115,9 +224,6 @@ REALM *tr_query_realm(const char *q_realm,
     printf("Error in tidc_send_request, rc = %d.\n", rc);
     return NULL;
   }
-    
-  /* Wait for a response */
-  while (!tidc_response_received);
 
   return cookie->output_realm;
 }