diff options
author | Linus Nordberg <linus@nordberg.se> | 2013-01-24 14:06:35 +0100 |
---|---|---|
committer | Linus Nordberg <linus@nordberg.se> | 2013-01-24 14:06:35 +0100 |
commit | 1e3a2613b356bf542fd75c198e9c9813e24f08d1 (patch) | |
tree | 6a3f90c5a50fbf8ccb202dea54dff847a7702f7d /lib/message.c | |
parent | 49047aa9d70c81b91ebe2446a6e84e659f59506c (diff) |
Rename most 'package' to 'message'.
RADIUS (RFC2865) is defined to be transported over UDP so the term
"radius packet" makes a lot of sense. RADIUS/TCP (RFC6613) and
RADIUS/TLS (RFC6614), a.k.a. RadSec, use stream transport protocols
though. The term "message" doesn't imply any kind of transport -- a
message can be sent using datagrams as well as in a stream.
This (large) commit changes 'package' to 'message' where it makes
sense. It does not touch the 'radius' subdirectory. It includes
preprocessor directives (#define) to make the public interface
compatible with previous releases of the library.
Diffstat (limited to 'lib/message.c')
-rw-r--r-- | lib/message.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/lib/message.c b/lib/message.c new file mode 100644 index 0000000..bdefed3 --- /dev/null +++ b/lib/message.c @@ -0,0 +1,265 @@ +/* Copyright 2010, 2011 NORDUnet A/S. All rights reserved. + See LICENSE for licensing information. */ + +#if defined HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#include <radius/client.h> +#include <event2/bufferevent.h> +#include <radsec/radsec.h> +#include <radsec/radsec-impl.h> +#include "conn.h" +#include "debug.h" +#include "message.h" + +#if defined (DEBUG) +#include <netdb.h> +#include <sys/socket.h> +#include <event2/buffer.h> +#endif + +int +message_verify_response (struct rs_connection *conn, + struct rs_message *response, + struct rs_message *request) +{ + int err; + + assert (conn); + assert (conn->active_peer); + assert (conn->active_peer->secret); + assert (response); + assert (response->rpkt); + assert (request); + assert (request->rpkt); + + response->rpkt->secret = conn->active_peer->secret; + response->rpkt->sizeof_secret = strlen (conn->active_peer->secret); + + /* Verify header and message authenticator. */ + err = nr_packet_verify (response->rpkt, request->rpkt); + if (err) + { + if (conn->is_connected) + rs_conn_disconnect(conn); + return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__, + "nr_packet_verify"); + } + + /* Decode and decrypt. */ + err = nr_packet_decode (response->rpkt, request->rpkt); + if (err) + { + if (conn->is_connected) + rs_conn_disconnect(conn); + return rs_err_conn_push_fl (conn, -err, __FILE__, __LINE__, + "nr_packet_decode"); + } + + return RSE_OK; +} + + +/* Badly named function for preparing a RADIUS message and queue it. + FIXME: Rename. */ +int +message_do_send (struct rs_message *msg) +{ + int err; + + assert (msg); + assert (msg->conn); + assert (msg->conn->active_peer); + assert (msg->conn->active_peer->secret); + assert (msg->rpkt); + + msg->rpkt->secret = msg->conn->active_peer->secret; + msg->rpkt->sizeof_secret = strlen (msg->rpkt->secret); + + /* Encode message. */ + err = nr_packet_encode (msg->rpkt, NULL); + if (err < 0) + return rs_err_conn_push_fl (msg->conn, -err, __FILE__, __LINE__, + "nr_packet_encode"); + /* Sign message. */ + err = nr_packet_sign (msg->rpkt, NULL); + if (err < 0) + return rs_err_conn_push_fl (msg->conn, -err, __FILE__, __LINE__, + "nr_packet_sign"); +#if defined (DEBUG) + { + char host[80], serv[80]; + + getnameinfo (msg->conn->active_peer->addr_cache->ai_addr, + msg->conn->active_peer->addr_cache->ai_addrlen, + host, sizeof(host), serv, sizeof(serv), + 0 /* NI_NUMERICHOST|NI_NUMERICSERV*/); + rs_debug (("%s: about to send this to %s:%s:\n", __func__, host, serv)); + rs_dump_message (msg); + } +#endif + + /* Put message in output buffer. */ + if (msg->conn->bev) /* TCP. */ + { + int err = bufferevent_write (msg->conn->bev, msg->rpkt->data, + msg->rpkt->length); + if (err < 0) + return rs_err_conn_push_fl (msg->conn, RSE_EVENT, __FILE__, __LINE__, + "bufferevent_write: %s", + evutil_gai_strerror (err)); + } + else /* UDP. */ + { + struct rs_message **pp = &msg->conn->out_queue; + + while (*pp && (*pp)->next) + *pp = (*pp)->next; + *pp = msg; + } + + return RSE_OK; +} + +/* Public functions. */ +int +rs_message_create (struct rs_connection *conn, struct rs_message **msg_out) +{ + struct rs_message *p; + RADIUS_PACKET *rpkt; + int err; + + *msg_out = NULL; + + rpkt = rs_malloc (conn->ctx, sizeof(*rpkt) + RS_MAX_PACKET_LEN); + if (rpkt == NULL) + return rs_err_conn_push (conn, RSE_NOMEM, __func__); + + /* + * This doesn't make sense; the packet identifier is constant for + * an entire conversation. A separate API should be provided to + * allow the application to set the packet ID, or a conversation + * object should group related packets together. + */ +#if 0 + rpkt->id = conn->nextid++ +#endif + + err = nr_packet_init (rpkt, NULL, NULL, + PW_ACCESS_REQUEST, + rpkt + 1, RS_MAX_PACKET_LEN); + if (err < 0) + return rs_err_conn_push (conn, -err, __func__); + + p = (struct rs_message *) rs_calloc (conn->ctx, 1, sizeof (*p)); + if (p == NULL) + { + rs_free (conn->ctx, rpkt); + return rs_err_conn_push (conn, RSE_NOMEM, __func__); + } + p->conn = conn; + p->rpkt = rpkt; + + *msg_out = p; + return RSE_OK; +} + +int +rs_message_create_authn_request (struct rs_connection *conn, + struct rs_message **msg_out, + const char *user_name, + const char *user_pw, + const char *secret) +{ + struct rs_message *msg; + int err; + + if (rs_message_create (conn, msg_out)) + return -1; + + msg = *msg_out; + msg->rpkt->code = PW_ACCESS_REQUEST; + + if (user_name) + { + err = rs_message_append_avp (msg, PW_USER_NAME, 0, user_name, 0); + if (err) + return err; + } + + if (user_pw) + { + msg->rpkt->secret = secret; + err = rs_message_append_avp (msg, PW_USER_PASSWORD, 0, user_pw, 0); + if (err) + return err; + } + + return RSE_OK; +} + +void +rs_message_destroy (struct rs_message *msg) +{ + assert (msg); + assert (msg->conn); + assert (msg->conn->ctx); + + rs_avp_free (&msg->rpkt->vps); + rs_free (msg->conn->ctx, msg->rpkt); + rs_free (msg->conn->ctx, msg); +} + +int +rs_message_append_avp (struct rs_message *msg, + unsigned int attr, unsigned int vendor, + const void *data, size_t data_len) +{ + const DICT_ATTR *da; + int err; + + assert (msg); + + da = nr_dict_attr_byvalue (attr, vendor); + if (da == NULL) + return RSE_ATTR_TYPE_UNKNOWN; + + err = nr_packet_attr_append (msg->rpkt, NULL, da, data, data_len); + if (err < 0) + return rs_err_conn_push (msg->conn, -err, __func__); + + return RSE_OK; +} + +void +rs_message_avps (struct rs_message *msg, rs_avp ***vps) +{ + assert (msg); + *vps = &msg->rpkt->vps; +} + +unsigned int +rs_message_code (struct rs_message *msg) +{ + assert (msg); + return msg->rpkt->code; +} + +rs_const_avp * +rs_message_find_avp (struct rs_message *msg, unsigned int attr, unsigned int vendor) +{ + assert (msg); + return rs_avp_find_const (msg->rpkt->vps, attr, vendor); +} + +int +rs_message_set_id (struct rs_message *msg, int id) +{ + int old = msg->rpkt->id; + + msg->rpkt->id = id; + + return old; +} |