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