Request object implementation and bug fixes by Luke Howard.
authorLinus Nordberg <linus@nordu.net>
Mon, 11 Oct 2010 08:41:58 +0000 (10:41 +0200)
committerLinus Nordberg <linus@nordu.net>
Mon, 11 Oct 2010 08:41:58 +0000 (10:41 +0200)
lib/err.c
lib/include/radsec/radsec-impl.h
lib/include/radsec/radsec.h
lib/include/radsec/request-impl.h
lib/packet.c
lib/request.c

index 116c995..51e4421 100644 (file)
--- a/lib/err.c
+++ b/lib/err.c
@@ -19,7 +19,7 @@ const char *_errtxt[] = {
   "libevent error"             /* 9 RSE_EVENT */
   "connection error"           /* 10 RSE_CONNERR */
   "invalid configuration file" /* 11 RSE_CONFIG */
-  "ERR 12"                     /*  RSE_ */
+  "authentication failed"      /*  RSE_BADAUTH */
   "ERR 13"                     /*  RSE_ */
   "ERR 14"                     /*  RSE_ */
   "ERR 15"                     /*  RSE_ */
index d2ea095..3ce01d0 100644 (file)
@@ -68,6 +68,7 @@ struct rs_connection {
     struct rs_peer *active_peer;
     struct rs_error *err;
     int nextid;
+    int user_dispatch_flag : 1;        /* User does the dispatching.  */
 };
 
 struct rs_packet {
index c8b43bf..db1e1a7 100644 (file)
@@ -17,6 +17,7 @@ enum rs_err_code {
     RSE_EVENT = 9,
     RSE_CONNERR = 10,
     RSE_CONFIG = 11,
+    RSE_BADAUTH = 12,
     RSE_SOME_ERROR = 21,
 };
 
@@ -118,6 +119,7 @@ int rs_packet_send(struct rs_packet *pkt, void *data);
 struct radius_packet *rs_packet_frpkt(struct rs_packet *pkt);
 
 /* Attribute.  */
+/* FIXME: Replace (or complement) with a wrapper for paircreate().  */
 int rs_attr_create(struct rs_connection *conn, struct rs_attr **attr,
                   const char *type, const char *val);
 void rs_attr_destroy(struct rs_attr *attr);
index 339dfea..4fa0ca9 100644 (file)
@@ -7,4 +7,10 @@ struct rs_request
   struct rs_packet *req;
   struct rs_packet *resp;
   struct rs_conn_callbacks saved_cb;
+  int verified;
 };
+
+#define VENDORPEC_MS                        311 /* RFC 2548 */
+
+#define PW_MS_MPPE_SEND_KEY                 16
+#define PW_MS_MPPE_RECV_KEY                 17
index 6f2088d..9abd698 100644 (file)
@@ -120,17 +120,22 @@ _write_cb (struct bufferevent *bev, void *ctx)
 #endif
   if (event_base_loopbreak (pkt->conn->evb) < 0)
     abort ();                  /* FIXME */
-  rs_packet_destroy (pkt);
+  if (!pkt->conn->callbacks.sent_cb) /* Callback owns the packet now.  */
+    rs_packet_destroy (pkt);
 }
 
 static void
 _read_cb (struct bufferevent *bev, void *ctx)
 {
-  struct rs_packet *pkt = (struct rs_packet *) ctx;
+  struct rs_packet *pkt = (struct rs_packet *)ctx;
   size_t n;
 
   assert (pkt);
   assert (pkt->conn);
+
+  pkt->rpkt->sockfd = pkt->conn->active_peer->fd; /* FIXME: Why?  */
+  pkt->rpkt->vps = NULL;                         /* FIXME: Why?  */
+
   if (!pkt->hdr_read_flag)
     {
       n = bufferevent_read (pkt->conn->bev, pkt->hdr, RS_HEADER_LEN);
@@ -340,14 +345,20 @@ rs_packet_create_acc_request (struct rs_connection *conn,
   pkt = *pkt_out;
   pkt->rpkt->code = PW_AUTHENTICATION_REQUEST;
 
-  if (rs_attr_create (conn, &attr, "User-Name", user_name))
-    return -1;
-  rs_packet_add_attr (pkt, attr);
+  if (user_name)
+    {
+      if (rs_attr_create (conn, &attr, "User-Name", user_name))
+       return -1;
+      rs_packet_add_attr (pkt, attr);
 
-  if (rs_attr_create (conn, &attr, "User-Password", user_pw))
-    return -1;
-  /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
-  rs_packet_add_attr (pkt, attr);
+      if (user_pw)
+       {
+         if (rs_attr_create (conn, &attr, "User-Password", user_pw))
+           return -1;
+         /* FIXME: need this too? rad_pwencode(user_pw, &pwlen, SECRET, reqauth) */
+         rs_packet_add_attr (pkt, attr);
+       }
+    }
 
   return RSE_OK;
 }
@@ -371,14 +382,10 @@ rs_packet_send (struct rs_packet *pkt, void *user_data)
   assert (conn->active_peer);
   assert (conn->active_peer->fd >= 0);
 
-  if (conn->callbacks.connected_cb || conn->callbacks.disconnected_cb
-      || conn->callbacks.received_cb || conn->callbacks.sent_cb)
-    ;          /* FIXME: install event callbacks, other than below */
-  else
-    {
-      bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
-      event_base_dispatch (conn->evb);
-    }
+  conn->user_data = user_data;
+  bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
+  if (!conn->user_dispatch_flag)
+    event_base_dispatch (conn->evb);
 
 #if defined (DEBUG)
   fprintf (stderr, "%s: event loop done\n", __func__);
@@ -409,17 +416,22 @@ rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet **pkt_out)
 
   bufferevent_setwatermark (conn->bev, EV_READ, RS_HEADER_LEN, 0);
   bufferevent_enable (conn->bev, EV_READ);
-  event_base_dispatch (conn->evb);
-#if defined (DEBUG)
-  fprintf (stderr, "%s: event loop done", __func__);
-  if (event_base_got_break(conn->evb))
+  bufferevent_setcb (conn->bev, _read_cb, _write_cb, _event_cb, pkt);
+
+  if (!conn->user_dispatch_flag)
     {
-      fprintf (stderr, ", got this:\n");
-      rs_dump_packet (pkt);
-    }
-  else
-    fprintf (stderr, ", no reply\n");
+      event_base_dispatch (conn->evb);
+#if defined (DEBUG)
+      fprintf (stderr, "%s: event loop done", __func__);
+      if (event_base_got_break(conn->evb))
+       {
+         fprintf (stderr, ", got this:\n");
+         rs_dump_packet (pkt);
+       }
+      else
+       fprintf (stderr, ", no reply\n");
 #endif
+    }
 
   return RSE_OK;
 }
index f0b15e0..85278f3 100644 (file)
@@ -39,12 +39,179 @@ _timer_cb(evutil_socket_t fd, short what, void *arg)
 }
 #endif
 
+static void
+_rs_req_connected(void *user_data)
+{
+  struct rs_request *request = (struct rs_request *)user_data;
+}
+
+static void
+_rs_req_disconnected(void *user_data)
+{
+  struct rs_request *request = (struct rs_request *)user_data;
+}
+
+static void
+_rs_req_packet_received(const struct rs_packet *pkt, void *user_data)
+{
+  struct rs_request *request = (struct rs_request *)user_data;
+  int err;
+  VALUE_PAIR *vp;
+
+  assert (request);
+  assert (request->conn);
+  assert (request->req);
+
+  err = rad_verify(pkt->rpkt, request->req->rpkt,
+                  pkt->conn->active_peer->secret);
+  if (err)
+    return;
+
+  for (vp = pkt->rpkt->vps; vp != NULL; vp = vp->next)
+    {
+      if (VENDOR(vp->attribute) != VENDORPEC_MS)
+       continue;
+
+      switch (vp->attribute & 0xffff)
+       {
+         case PW_MS_MPPE_SEND_KEY:
+         case PW_MS_MPPE_RECV_KEY:
+           err = _rs_decrypt_mppe (request, vp);
+           if (err)
+             return;
+           break;
+         default:
+           break;
+       }
+    }
+
+  request->verified = 1;
+}
+
+static void
+_rs_req_packet_sent(void *user_data)
+{
+  struct rs_request *request = (struct rs_request *)user_data;
+}
+
 int
-rs_req_send(struct rs_request *request, struct rs_packet *req,
-           struct rs_packet **resp)
+rs_request_send(struct rs_request *request, struct rs_packet *req,
+               struct rs_packet **resp)
 {
-  /* install our own callback, backing up any user provided one in
-     req->saved_cb*/
+  int err;
+  VALUE_PAIR *vp;
+  struct rs_connection *conn;
+
+  assert (request);
+  assert (request->conn);
+  conn = request->conn;
+
+  request->req = req;          /* take ownership */
+  request->saved_cb = conn->callbacks;
+
+  conn->callbacks.connected_cb = _rs_req_connected;
+  conn->callbacks.disconnected_cb = _rs_req_disconnected;
+  conn->callbacks.received_cb = _rs_req_packet_received;
+  conn->callbacks.sent_cb = _rs_req_packet_sent;
 
-  return -1;
+  assert(request->verified == 0);
+
+  vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
+  pairadd(&request->req->rpkt->vps, vp);
+
+  err = rs_packet_send(request->req, request);
+  if (err)
+    goto cleanup;
+
+  err = rs_conn_receive_packet(request->conn, resp);
+  if (err)
+    goto cleanup;
+
+  if (!request->verified)
+    {
+      err = rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
+      goto cleanup;
+    }
+
+cleanup:
+  conn->callbacks = request->saved_cb;
+  return err;
+}
+
+/*
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+#include <openssl/md5.h>
+
+static int
+_rs_decrypt_mppe(struct rs_request *request, VALUE_PAIR *vp)
+{
+  unsigned char *key = vp->vp_octets;
+  size_t len = vp->length;
+  unsigned char plain[1 + MAX_STRING_LEN], *ppos = plain, *res;
+  const unsigned char *pos;
+  size_t left, plen;
+  unsigned char hash[MD5_DIGEST_LENGTH];
+  int i, first = 1;
+  const unsigned char *addr[3];
+  struct rs_connection *conn;
+
+  assert (request);
+  assert (request->conn);
+  conn = request->conn;
+
+  if (vp->type != PW_TYPE_OCTETS)
+    return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
+
+  pos = key + 2;
+  left = len - 2;
+  if (left % 16)
+    return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
+
+  plen = left;
+  if (plen > MAX_STRING_LEN)
+    return rs_err_conn_push_fl (conn, RSE_BADAUTH, __FILE__, __LINE__, NULL);
+
+  plain[0] = 0;
+
+  while (left)
+    {
+      MD5_CTX md5;
+
+      MD5_Init (&md5);
+      MD5_Update (&md5, conn->active_peer->secret,
+                 strlen (conn->active_peer->secret));
+      if (first)
+       {
+         MD5_Update (&md5, request->req->rpkt->vector, MD5_DIGEST_LENGTH);
+         MD5_Update (&md5, key, 2);
+         first = 0;
+       }
+      else
+       {
+         MD5_Update (&md5, pos - MD5_DIGEST_LENGTH, MD5_DIGEST_LENGTH);
+       }
+      MD5_Final (hash, &md5);
+
+      for (i = 0; i < MD5_DIGEST_LENGTH; i++)
+       *ppos++ = *pos++ ^ hash[i];
+      left -= MD5_DIGEST_LENGTH;
+    }
+
+  if (plain[0] == 0 || plain[0] > plen - 1)
+    return rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
+
+  memcpy (vp->vp_octets, plain + 1, plain[0]);
+  vp->length = plain[0];
+
+  return RSE_OK;
 }