diff options
| author | Linus Nordberg <linus@nordu.net> | 2010-10-11 10:41:58 +0200 | 
|---|---|---|
| committer | Linus Nordberg <linus@nordu.net> | 2010-10-11 10:41:58 +0200 | 
| commit | ff55882798b6c482faec920d30a4ffdc10b306f7 (patch) | |
| tree | 2bc7e2b5665f281b98bff37e2805f07616e3a55b | |
| parent | 391369cb26363980cbe37d30c41d48a03dd46ef5 (diff) | |
Request object implementation and bug fixes by Luke Howard.
| -rw-r--r-- | lib/err.c | 2 | ||||
| -rw-r--r-- | lib/include/radsec/radsec-impl.h | 1 | ||||
| -rw-r--r-- | lib/include/radsec/radsec.h | 2 | ||||
| -rw-r--r-- | lib/include/radsec/request-impl.h | 6 | ||||
| -rw-r--r-- | lib/packet.c | 64 | ||||
| -rw-r--r-- | lib/request.c | 177 | 
6 files changed, 220 insertions, 32 deletions
| @@ -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;  } | 
