summaryrefslogtreecommitdiff
path: root/lib/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/message.c')
-rw-r--r--lib/message.c265
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;
+}