summaryrefslogtreecommitdiffstats
path: root/src/lib/krad/attrset.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krad/attrset.c')
-rw-r--r--src/lib/krad/attrset.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
new file mode 100644
index 0000000000..fbd0621a08
--- /dev/null
+++ b/src/lib/krad/attrset.c
@@ -0,0 +1,244 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krad/attrset.c - RADIUS attribute set functions for libkrad */
+/*
+ * Copyright 2013 Red Hat, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <k5-int.h>
+#include <k5-queue.h>
+#include "internal.h"
+
+#include <string.h>
+
+TAILQ_HEAD(attr_head, attr_st);
+
+typedef struct attr_st attr;
+struct attr_st {
+ TAILQ_ENTRY(attr_st) list;
+ krad_attr type;
+ krb5_data attr;
+ char buffer[MAX_ATTRSIZE];
+};
+
+struct krad_attrset_st {
+ krb5_context ctx;
+ struct attr_head list;
+};
+
+krb5_error_code
+krad_attrset_new(krb5_context ctx, krad_attrset **set)
+{
+ krad_attrset *tmp;
+
+ tmp = calloc(1, sizeof(krad_attrset));
+ if (tmp == NULL)
+ return ENOMEM;
+ tmp->ctx = ctx;
+ TAILQ_INIT(&tmp->list);
+
+ *set = tmp;
+ return 0;
+}
+
+void
+krad_attrset_free(krad_attrset *set)
+{
+ attr *a;
+
+ if (set == NULL)
+ return;
+
+ while (!TAILQ_EMPTY(&set->list)) {
+ a = TAILQ_FIRST(&set->list);
+ TAILQ_REMOVE(&set->list, a, list);
+ zap(a->buffer, sizeof(a->buffer));
+ free(a);
+ }
+
+ free(set);
+}
+
+krb5_error_code
+krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data)
+{
+ krb5_error_code retval;
+ attr *tmp;
+
+ retval = kr_attr_valid(type, data);
+ if (retval != 0)
+ return retval;
+
+ tmp = calloc(1, sizeof(attr));
+ if (tmp == NULL)
+ return ENOMEM;
+
+ tmp->type = type;
+ tmp->attr = make_data(tmp->buffer, data->length);
+ memcpy(tmp->attr.data, data->data, data->length);
+
+ TAILQ_INSERT_TAIL(&set->list, tmp, list);
+ return 0;
+}
+
+krb5_error_code
+krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num)
+{
+ krb5_data data;
+
+ num = htonl(num);
+ data = make_data(&num, sizeof(num));
+ return krad_attrset_add(set, type, &data);
+}
+
+void
+krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx)
+{
+ attr *a;
+
+ TAILQ_FOREACH(a, &set->list, list) {
+ if (a->type == type && indx-- == 0) {
+ TAILQ_REMOVE(&set->list, a, list);
+ zap(a->buffer, sizeof(a->buffer));
+ free(a);
+ return;
+ }
+ }
+}
+
+const krb5_data *
+krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx)
+{
+ attr *a;
+
+ TAILQ_FOREACH(a, &set->list, list) {
+ if (a->type == type && indx-- == 0)
+ return &a->attr;
+ }
+
+ return NULL;
+}
+
+krb5_error_code
+krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
+{
+ krb5_error_code retval;
+ krad_attrset *tmp;
+ attr *a;
+
+ retval = krad_attrset_new(set->ctx, &tmp);
+ if (retval != 0)
+ return retval;
+
+ TAILQ_FOREACH(a, &set->list, list) {
+ retval = krad_attrset_add(tmp, a->type, &a->attr);
+ if (retval != 0) {
+ krad_attrset_free(tmp);
+ return retval;
+ }
+ }
+
+ *copy = tmp;
+ return 0;
+}
+
+krb5_error_code
+kr_attrset_encode(const krad_attrset *set, const char *secret,
+ const unsigned char *auth,
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
+{
+ unsigned char buffer[MAX_ATTRSIZE];
+ krb5_error_code retval;
+ size_t i = 0, attrlen;
+ attr *a;
+
+ if (set == NULL) {
+ *outlen = 0;
+ return 0;
+ }
+
+ TAILQ_FOREACH(a, &set->list, list) {
+ retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
+ buffer, &attrlen);
+ if (retval != 0)
+ return retval;
+
+ if (i + attrlen + 2 > MAX_ATTRSETSIZE)
+ return EMSGSIZE;
+
+ outbuf[i++] = a->type;
+ outbuf[i++] = attrlen + 2;
+ memcpy(&outbuf[i], buffer, attrlen);
+ i += attrlen;
+ }
+
+ *outlen = i;
+ return 0;
+}
+
+krb5_error_code
+kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret,
+ const unsigned char *auth, krad_attrset **set_out)
+{
+ unsigned char buffer[MAX_ATTRSIZE];
+ krb5_data tmp;
+ krb5_error_code retval;
+ krad_attr type;
+ krad_attrset *set;
+ size_t i, len;
+
+ *set_out = NULL;
+
+ retval = krad_attrset_new(ctx, &set);
+ if (retval != 0)
+ return retval;
+
+ for (i = 0; i + 2 < in->length; ) {
+ type = in->data[i++];
+ tmp = make_data(&in->data[i + 1], in->data[i] - 2);
+ i += tmp.length + 1;
+
+ retval = (in->length < i) ? EBADMSG : 0;
+ if (retval != 0)
+ goto cleanup;
+
+ retval = kr_attr_decode(ctx, secret, auth, type, &tmp, buffer, &len);
+ if (retval != 0)
+ goto cleanup;
+
+ tmp = make_data(buffer, len);
+ retval = krad_attrset_add(set, type, &tmp);
+ if (retval != 0)
+ goto cleanup;
+ }
+
+ *set_out = set;
+ set = NULL;
+
+cleanup:
+ zap(buffer, sizeof(buffer));
+ krad_attrset_free(set);
+ return retval;
+}