From 5d1a02eb41025020b8c25ab927baca978fb733a9 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 10 Oct 2010 11:47:43 +0200 Subject: Rename rs_req_* --> rs_request_. Contributed by Luke Howard. --- lib/examples/client-blocking.c | 4 ++-- lib/include/radsec/request.h | 6 +++--- lib/request.c | 8 ++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index bb9e653..66f4859 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -63,9 +63,9 @@ blocking_client (const char *av1, const char *av2) { struct rs_request *request; - if (rs_request_new (conn, &request)) + if (rs_request_create (conn, &request)) return rs_err_conn_pop (conn); - if (rs_req_send (request, req, &resp)) + if (rs_request_send (request, req, &resp)) return rs_err_conn_pop (conn); rs_request_destroy (request); } diff --git a/lib/include/radsec/request.h b/lib/include/radsec/request.h index 3827da5..939345e 100644 --- a/lib/include/radsec/request.h +++ b/lib/include/radsec/request.h @@ -2,6 +2,6 @@ struct rs_request; -int rs_req_create(struct rs_connection *conn, struct rs_request **req_out); -void rs_req_destroy(struct rs_request *request); -int rs_req_send(struct rs_request *request, struct rs_packet *req, struct rs_packet **resp); +int rs_request_create(struct rs_connection *conn, struct rs_request **req_out); +void rs_request_destroy(struct rs_request *request); +int rs_request_send(struct rs_request *request, struct rs_packet *req, struct rs_packet **resp); diff --git a/lib/request.c b/lib/request.c index 3d4b096..f0b15e0 100644 --- a/lib/request.c +++ b/lib/request.c @@ -1,14 +1,18 @@ /* See the file COPYING for licensing information. */ #include +#include #include #include #include #include #include +static int +_rs_decrypt_mppe(struct rs_request *request, VALUE_PAIR *vp); + int -rs_req_create (struct rs_connection *conn, struct rs_request **req_out) +rs_request_create (struct rs_connection *conn, struct rs_request **req_out) { struct rs_request *req = rs_malloc (conn->ctx, sizeof(*req)); if (!req) @@ -20,7 +24,7 @@ rs_req_create (struct rs_connection *conn, struct rs_request **req_out) } void -rs_req_destroy(struct rs_request *request) +rs_request_destroy (struct rs_request *request) { rs_packet_destroy (request->req); rs_packet_destroy (request->resp); -- cgit v1.1 From 8a676ab2d88022aea68a2a31ac83dfe25d64e175 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 10 Oct 2010 15:53:37 +0200 Subject: Robustness fixes (and some callback invocation) by Luke Howard. * lib/packet.c (_packet_create): Set packet identity properly. (_do_send): Return an int. (_do_send): Don't ignore rad_encode() errors. (_do_send): Do invoke rad_sign(). (_event_cb): Invoke callbacks. (_event_cb): Honour _do_send() return code. (_read_cb): Check packet (by invoking rad_packet_ok()). (_read_cb): Don't ignore rad_decode() errors. (_read_cb): Invoke callbacks. --- lib/include/radsec/radsec-impl.h | 2 ++ lib/packet.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index b46bc47..d2ea095 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -63,9 +63,11 @@ struct rs_connection { enum rs_conn_type type; struct rs_credentials transport_credentials; struct rs_conn_callbacks callbacks; + void *user_data; struct rs_peer *peers; struct rs_peer *active_peer; struct rs_error *err; + int nextid; }; struct rs_packet { diff --git a/lib/packet.c b/lib/packet.c index 54bfc01..6b95b73 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -24,7 +24,7 @@ _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out) rpkt = rad_alloc (1); if (!rpkt) return rs_err_conn_push (conn, RSE_NOMEM, __func__); - rpkt->id = -1; + rpkt->id = conn->nextid++; p = (struct rs_packet *) malloc (sizeof (struct rs_packet)); if (!p) @@ -40,12 +40,17 @@ _packet_create (struct rs_connection *conn, struct rs_packet **pkt_out) return RSE_OK; } -static void +static int _do_send (struct rs_packet *pkt) { int err; - rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret); + if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) + return rs_err_conn_push_fl (pkg->conn, RSE_FR, __FILE__, __LINE__, + "rad_encode: %s", fr_strerror ()); + if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) + return rs_err_conn_push_fl (pkg->conn, RSE_FR, __FILE__, __LINE__, + "rad_sign: %s", fr_strerror ()); assert (pkt->rpkt); #if defined (DEBUG) { @@ -63,16 +68,19 @@ _do_send (struct rs_packet *pkt) err = bufferevent_write (pkt->conn->bev, pkt->rpkt->data, pkt->rpkt->data_len); if (err < 0) - rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, - "bufferevent_write: %s", evutil_gai_strerror(err)); + return rs_err_conn_push_fl (pkt->conn, RSE_EVENT, __FILE__, __LINE__, + "bufferevent_write: %s", + evutil_gai_strerror(err)); + return RSE_OK; } static void _event_cb (struct bufferevent *bev, short events, void *ctx) { - struct rs_packet *pkt = (struct rs_packet *) ctx; + struct rs_packet *pkt = (struct rs_packet *)ctx; struct rs_connection *conn; struct rs_peer *p; + int err; assert (pkt); assert (pkt->conn); @@ -84,10 +92,17 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) if (events & BEV_EVENT_CONNECTED) { p->is_connected = 1; + if (conn->callbacks.connected_cb) + conn->callbacks.connected_cb (conn->user_data); + #if defined (DEBUG) fprintf (stderr, "%s: connected\n", __func__); #endif - _do_send (pkt); + err = _do_send (pkt); + if (err) + return err; + if (conn->callbacks.sent_cb) + conn->callbacks.sent_cb (conn->user_data); /* Packet will be freed in write callback. */ } else if (events & BEV_EVENT_ERROR) @@ -162,7 +177,14 @@ _read_cb (struct bufferevent *bev, void *ctx) #if defined (DEBUG) fprintf (stderr, "%s: complete packet read\n", __func__); #endif - rad_decode (pkt->rpkt, NULL, pkt->conn->active_peer->secret); + if (!rad_packet_ok (pkt->rpkt, 0) != 0) + return; + if (rad_decode (pkt->rpkt, NULL, pkt->conn->active_peer->secret) != 0) + return; + + if (pkt->conn->callbacks.received_cb) + pkt->conn->callbacks.received_cb(pkt, pkt->conn->user_data); + if (event_base_loopbreak (pkt->conn->evb) < 0) abort (); /* FIXME */ } @@ -335,6 +357,7 @@ int rs_packet_send (struct rs_packet *pkt, void *user_data) { struct rs_connection *conn; + assert (pkt); conn = pkt->conn; -- cgit v1.1 From 735f0808c02e705e7649c58471d36ca367c50017 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 10 Oct 2010 15:56:01 +0200 Subject: Cosmetics. --- lib/attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/attr.c b/lib/attr.c index 49735d9..4e66235 100644 --- a/lib/attr.c +++ b/lib/attr.c @@ -21,7 +21,7 @@ rs_attr_create(struct rs_connection *conn, struct rs_attr **attr, const char *ty { rs_attr_destroy (a); return rs_err_conn_push_fl (conn, RSE_FR, __FILE__, __LINE__, - "pairmake: %s", fr_strerror()); + "pairmake: %s", fr_strerror ()); } a->vp = vp; -- cgit v1.1 From 391369cb26363980cbe37d30c41d48a03dd46ef5 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Sun, 10 Oct 2010 16:00:11 +0200 Subject: Compile again after bad fixes. --- lib/packet.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/packet.c b/lib/packet.c index 6b95b73..6f2088d 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -46,10 +46,10 @@ _do_send (struct rs_packet *pkt) int err; if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) - return rs_err_conn_push_fl (pkg->conn, RSE_FR, __FILE__, __LINE__, + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_encode: %s", fr_strerror ()); if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) - return rs_err_conn_push_fl (pkg->conn, RSE_FR, __FILE__, __LINE__, + return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_sign: %s", fr_strerror ()); assert (pkt->rpkt); #if defined (DEBUG) @@ -98,9 +98,8 @@ _event_cb (struct bufferevent *bev, short events, void *ctx) #if defined (DEBUG) fprintf (stderr, "%s: connected\n", __func__); #endif - err = _do_send (pkt); - if (err) - return err; + if (_do_send (pkt)) + return; if (conn->callbacks.sent_cb) conn->callbacks.sent_cb (conn->user_data); /* Packet will be freed in write callback. */ -- cgit v1.1 From ff55882798b6c482faec920d30a4ffdc10b306f7 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Mon, 11 Oct 2010 10:41:58 +0200 Subject: Request object implementation and bug fixes by Luke Howard. --- lib/err.c | 2 +- lib/include/radsec/radsec-impl.h | 1 + lib/include/radsec/radsec.h | 2 + lib/include/radsec/request-impl.h | 6 ++ lib/packet.c | 64 ++++++++------ lib/request.c | 177 ++++++++++++++++++++++++++++++++++++-- 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 + * + * 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 + +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; } -- cgit v1.1 From 06936d1f263c456017e20ea6c74d2756e1e30fcc Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Sat, 9 Oct 2010 11:54:37 +0200 Subject: Have rad_decode() verify responses. --- lib/examples/client-blocking.c | 14 +++-- lib/include/radsec/radsec-impl.h | 1 + lib/include/radsec/radsec.h | 1 + lib/include/radsec/request-impl.h | 6 -- lib/packet.c | 41 +++++++++++-- lib/request.c | 126 +------------------------------------- 6 files changed, 49 insertions(+), 140 deletions(-) diff --git a/lib/examples/client-blocking.c b/lib/examples/client-blocking.c index 66f4859..365b3b0 100644 --- a/lib/examples/client-blocking.c +++ b/lib/examples/client-blocking.c @@ -55,10 +55,16 @@ blocking_client (const char *av1, const char *av2) #if !defined(USE_REQUEST_OBJECT) if (rs_packet_send (req, NULL)) - return rs_err_conn_pop (conn); - req = NULL; - if (rs_conn_receive_packet (conn, &resp)) - return rs_err_conn_pop (conn); + { + rs_packet_destroy (req); + return rs_err_conn_pop (conn); + } + if (rs_conn_receive_packet (conn, req, &resp)) + { + rs_packet_destroy (req); + return rs_err_conn_pop (conn); + } + rs_packet_destroy (req); #else { struct rs_request *request; diff --git a/lib/include/radsec/radsec-impl.h b/lib/include/radsec/radsec-impl.h index 3ce01d0..6e5ee83 100644 --- a/lib/include/radsec/radsec-impl.h +++ b/lib/include/radsec/radsec-impl.h @@ -76,6 +76,7 @@ struct rs_packet { char hdr_read_flag; uint8_t hdr[4]; RADIUS_PACKET *rpkt; + struct rs_packet *original; }; struct rs_attr { diff --git a/lib/include/radsec/radsec.h b/lib/include/radsec/radsec.h index db1e1a7..dd784cc 100644 --- a/lib/include/radsec/radsec.h +++ b/lib/include/radsec/radsec.h @@ -97,6 +97,7 @@ int rs_conn_select_server(struct rs_connection *conn, const char *name); int rs_conn_get_current_server(struct rs_connection *conn, const char *name, size_t buflen); int rs_conn_receive_packet(struct rs_connection *conn, + struct rs_packet *request, struct rs_packet **pkt_out); int rs_conn_fd(struct rs_connection *conn); diff --git a/lib/include/radsec/request-impl.h b/lib/include/radsec/request-impl.h index 4fa0ca9..339dfea 100644 --- a/lib/include/radsec/request-impl.h +++ b/lib/include/radsec/request-impl.h @@ -7,10 +7,4 @@ 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 9abd698..7872a5a 100644 --- a/lib/packet.c +++ b/lib/packet.c @@ -44,6 +44,16 @@ static int _do_send (struct rs_packet *pkt) { int err; + VALUE_PAIR *vp; + + assert (pkt->rpkt); + assert (!pkt->original); + + vp = paircreate (PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); + if (!vp) + return rs_err_conn_push_fl (pkt->conn, RSE_NOMEM, __FILE__, __LINE__, + "rad_encode: %s", fr_strerror ()); + pairadd (&pkt->rpkt->vps, vp); if (rad_encode (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, @@ -51,7 +61,6 @@ _do_send (struct rs_packet *pkt) if (rad_sign (pkt->rpkt, NULL, pkt->conn->active_peer->secret)) return rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, "rad_sign: %s", fr_strerror ()); - assert (pkt->rpkt); #if defined (DEBUG) { char host[80], serv[80]; @@ -183,11 +192,28 @@ _read_cb (struct bufferevent *bev, void *ctx) #endif if (!rad_packet_ok (pkt->rpkt, 0) != 0) return; - if (rad_decode (pkt->rpkt, NULL, pkt->conn->active_peer->secret) != 0) - return; + assert (pkt->original); + + /* Verify header and message authenticator. */ + if (rad_verify (pkt->rpkt, pkt->original->rpkt, + pkt->conn->active_peer->secret)) + { + rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "rad_verify: %s", fr_strerror ()); + return; + } + + /* decode and decrypt */ + if (rad_decode (pkt->rpkt, pkt->original->rpkt, + pkt->conn->active_peer->secret)) + { + rs_err_conn_push_fl (pkt->conn, RSE_FR, __FILE__, __LINE__, + "rad_decode: %s", fr_strerror ()); + return; + } if (pkt->conn->callbacks.received_cb) - pkt->conn->callbacks.received_cb(pkt, pkt->conn->user_data); + pkt->conn->callbacks.received_cb (pkt, pkt->conn->user_data); if (event_base_loopbreak (pkt->conn->evb) < 0) abort (); /* FIXME */ @@ -396,7 +422,9 @@ rs_packet_send (struct rs_packet *pkt, void *user_data) } int -rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet **pkt_out) +rs_conn_receive_packet (struct rs_connection *conn, + struct rs_packet *request, + struct rs_packet **pkt_out) { struct rs_packet *pkt; @@ -406,6 +434,7 @@ rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet **pkt_out) return -1; pkt = *pkt_out; pkt->conn = conn; + pkt->original = request; if (_conn_open (conn, pkt)) return -1; @@ -433,6 +462,8 @@ rs_conn_receive_packet (struct rs_connection *conn, struct rs_packet **pkt_out) #endif } + pkt->original = NULL; + return RSE_OK; } diff --git a/lib/request.c b/lib/request.c index 85278f3..5cb87bb 100644 --- a/lib/request.c +++ b/lib/request.c @@ -8,9 +8,6 @@ #include #include -static int -_rs_decrypt_mppe(struct rs_request *request, VALUE_PAIR *vp); - int rs_request_create (struct rs_connection *conn, struct rs_request **req_out) { @@ -55,37 +52,6 @@ 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 @@ -99,7 +65,6 @@ rs_request_send(struct rs_request *request, struct rs_packet *req, struct rs_packet **resp) { int err; - VALUE_PAIR *vp; struct rs_connection *conn; assert (request); @@ -114,104 +79,15 @@ rs_request_send(struct rs_request *request, struct rs_packet *req, conn->callbacks.received_cb = _rs_req_packet_received; conn->callbacks.sent_cb = _rs_req_packet_sent; - 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); + err = rs_conn_receive_packet(request->conn, request->req, 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 - * - * 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 - -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; -} -- cgit v1.1