summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordu.net>2010-10-11 10:41:58 +0200
committerLinus Nordberg <linus@nordu.net>2010-10-11 10:41:58 +0200
commitff55882798b6c482faec920d30a4ffdc10b306f7 (patch)
tree2bc7e2b5665f281b98bff37e2805f07616e3a55b /lib
parent391369cb26363980cbe37d30c41d48a03dd46ef5 (diff)
Request object implementation and bug fixes by Luke Howard.
Diffstat (limited to 'lib')
-rw-r--r--lib/err.c2
-rw-r--r--lib/include/radsec/radsec-impl.h1
-rw-r--r--lib/include/radsec/radsec.h2
-rw-r--r--lib/include/radsec/request-impl.h6
-rw-r--r--lib/packet.c64
-rw-r--r--lib/request.c177
6 files changed, 220 insertions, 32 deletions
diff --git a/lib/err.c b/lib/err.c
index 116c995..51e4421 100644
--- 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_ */
diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h
index d2ea095..3ce01d0 100644
--- a/lib/include/radsec/radsec-impl.h
+++ b/lib/include/radsec/radsec-impl.h
@@ -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 {
diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h
index c8b43bf..db1e1a7 100644
--- a/lib/include/radsec/radsec.h
+++ b/lib/include/radsec/radsec.h
@@ -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);
diff --git a/lib/include/radsec/request-impl.h b/lib/include/radsec/request-impl.h
index 339dfea..4fa0ca9 100644
--- a/lib/include/radsec/request-impl.h
+++ b/lib/include/radsec/request-impl.h
@@ -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
diff --git a/lib/packet.c b/lib/packet.c
index 6f2088d..9abd698 100644
--- a/lib/packet.c
+++ b/lib/packet.c
@@ -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;
}
diff --git a/lib/request.c b/lib/request.c
index f0b15e0..85278f3 100644
--- a/lib/request.c
+++ b/lib/request.c
@@ -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;
}