xref: /freebsd/crypto/krb5/src/lib/krad/attrset.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krad/attrset.c - RADIUS attribute set functions for libkrad */
3 /*
4  * Copyright 2013 Red Hat, Inc.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *    1. Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *
12  *    2. Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <k5-int.h>
31 #include <k5-queue.h>
32 #include "internal.h"
33 
34 #include <string.h>
35 
36 K5_TAILQ_HEAD(attr_head, attr_st);
37 
38 typedef struct attr_st attr;
39 struct attr_st {
40     K5_TAILQ_ENTRY(attr_st) list;
41     krad_attr type;
42     krb5_data attr;
43     char buffer[MAX_ATTRSIZE];
44 };
45 
46 struct krad_attrset_st {
47     krb5_context ctx;
48     struct attr_head list;
49 };
50 
51 krb5_error_code
52 krad_attrset_new(krb5_context ctx, krad_attrset **set)
53 {
54     krad_attrset *tmp;
55 
56     tmp = calloc(1, sizeof(krad_attrset));
57     if (tmp == NULL)
58         return ENOMEM;
59     tmp->ctx = ctx;
60     K5_TAILQ_INIT(&tmp->list);
61 
62     *set = tmp;
63     return 0;
64 }
65 
66 void
67 krad_attrset_free(krad_attrset *set)
68 {
69     attr *a;
70 
71     if (set == NULL)
72         return;
73 
74     while (!K5_TAILQ_EMPTY(&set->list)) {
75         a = K5_TAILQ_FIRST(&set->list);
76         K5_TAILQ_REMOVE(&set->list, a, list);
77         zap(a->buffer, sizeof(a->buffer));
78         free(a);
79     }
80 
81     free(set);
82 }
83 
84 krb5_error_code
85 krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data)
86 {
87     krb5_error_code retval;
88     attr *tmp;
89 
90     retval = kr_attr_valid(type, data);
91     if (retval != 0)
92         return retval;
93 
94     tmp = calloc(1, sizeof(attr));
95     if (tmp == NULL)
96         return ENOMEM;
97 
98     tmp->type = type;
99     tmp->attr = make_data(tmp->buffer, data->length);
100     memcpy(tmp->attr.data, data->data, data->length);
101 
102     K5_TAILQ_INSERT_TAIL(&set->list, tmp, list);
103     return 0;
104 }
105 
106 krb5_error_code
107 krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num)
108 {
109     krb5_data data;
110 
111     num = htonl(num);
112     data = make_data(&num, sizeof(num));
113     return krad_attrset_add(set, type, &data);
114 }
115 
116 void
117 krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx)
118 {
119     attr *a;
120 
121     K5_TAILQ_FOREACH(a, &set->list, list) {
122         if (a->type == type && indx-- == 0) {
123             K5_TAILQ_REMOVE(&set->list, a, list);
124             zap(a->buffer, sizeof(a->buffer));
125             free(a);
126             return;
127         }
128     }
129 }
130 
131 const krb5_data *
132 krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx)
133 {
134     attr *a;
135 
136     K5_TAILQ_FOREACH(a, &set->list, list) {
137         if (a->type == type && indx-- == 0)
138             return &a->attr;
139     }
140 
141     return NULL;
142 }
143 
144 krb5_error_code
145 krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
146 {
147     krb5_error_code retval;
148     krad_attrset *tmp;
149     attr *a;
150 
151     retval = krad_attrset_new(set->ctx, &tmp);
152     if (retval != 0)
153         return retval;
154 
155     K5_TAILQ_FOREACH(a, &set->list, list) {
156         retval = krad_attrset_add(tmp, a->type, &a->attr);
157         if (retval != 0) {
158             krad_attrset_free(tmp);
159             return retval;
160         }
161     }
162 
163     *copy = tmp;
164     return 0;
165 }
166 
167 krb5_error_code
168 kr_attrset_encode(const krad_attrset *set, const char *secret,
169                   const unsigned char *auth,
170                   unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
171 {
172     unsigned char buffer[MAX_ATTRSIZE];
173     krb5_error_code retval;
174     size_t i = 0, attrlen;
175     attr *a;
176 
177     if (set == NULL) {
178         *outlen = 0;
179         return 0;
180     }
181 
182     K5_TAILQ_FOREACH(a, &set->list, list) {
183         retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
184                                 buffer, &attrlen);
185         if (retval != 0)
186             return retval;
187 
188         if (i + attrlen + 2 > MAX_ATTRSETSIZE)
189             return EMSGSIZE;
190 
191         outbuf[i++] = a->type;
192         outbuf[i++] = attrlen + 2;
193         memcpy(&outbuf[i], buffer, attrlen);
194         i += attrlen;
195     }
196 
197     *outlen = i;
198     return 0;
199 }
200 
201 krb5_error_code
202 kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret,
203                   const unsigned char *auth, krad_attrset **set_out)
204 {
205     unsigned char buffer[MAX_ATTRSIZE];
206     krb5_data tmp;
207     krb5_error_code retval;
208     krad_attr type;
209     krad_attrset *set;
210     size_t i, len;
211 
212     *set_out = NULL;
213 
214     retval = krad_attrset_new(ctx, &set);
215     if (retval != 0)
216         return retval;
217 
218     for (i = 0; i + 2 < in->length; ) {
219         type = in->data[i++];
220         tmp = make_data(&in->data[i + 1], (uint8_t)in->data[i] - 2);
221         i += tmp.length + 1;
222 
223         retval = (in->length < i) ? EBADMSG : 0;
224         if (retval != 0)
225             goto cleanup;
226 
227         retval = kr_attr_decode(ctx, secret, auth, type, &tmp, buffer, &len);
228         if (retval != 0)
229             goto cleanup;
230 
231         tmp = make_data(buffer, len);
232         retval = krad_attrset_add(set, type, &tmp);
233         if (retval != 0)
234             goto cleanup;
235     }
236 
237     *set_out = set;
238     set = NULL;
239 
240 cleanup:
241     zap(buffer, sizeof(buffer));
242     krad_attrset_free(set);
243     return retval;
244 }
245