Path: blob/main/crypto/krb5/src/lib/krad/attrset.c
39537 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/* lib/krad/attrset.c - RADIUS attribute set functions for libkrad */2/*3* Copyright 2013 Red Hat, Inc. All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions are met:7*8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10*11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in13* the documentation and/or other materials provided with the14* distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS17* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED18* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A19* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER20* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,21* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,22* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR23* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF24* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING25* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS26* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/2829#include <k5-int.h>30#include <k5-queue.h>31#include "internal.h"3233#include <string.h>3435K5_TAILQ_HEAD(attr_head, attr_st);3637typedef struct attr_st attr;38struct attr_st {39K5_TAILQ_ENTRY(attr_st) list;40krad_attr type;41krb5_data attr;42char buffer[MAX_ATTRSIZE];43};4445struct krad_attrset_st {46krb5_context ctx;47struct attr_head list;48};4950krb5_error_code51krad_attrset_new(krb5_context ctx, krad_attrset **set)52{53krad_attrset *tmp;5455tmp = calloc(1, sizeof(krad_attrset));56if (tmp == NULL)57return ENOMEM;58tmp->ctx = ctx;59K5_TAILQ_INIT(&tmp->list);6061*set = tmp;62return 0;63}6465void66krad_attrset_free(krad_attrset *set)67{68attr *a;6970if (set == NULL)71return;7273while (!K5_TAILQ_EMPTY(&set->list)) {74a = K5_TAILQ_FIRST(&set->list);75K5_TAILQ_REMOVE(&set->list, a, list);76zap(a->buffer, sizeof(a->buffer));77free(a);78}7980free(set);81}8283krb5_error_code84krad_attrset_add(krad_attrset *set, krad_attr type, const krb5_data *data)85{86krb5_error_code retval;87attr *tmp;8889retval = kr_attr_valid(type, data);90if (retval != 0)91return retval;9293tmp = calloc(1, sizeof(attr));94if (tmp == NULL)95return ENOMEM;9697tmp->type = type;98tmp->attr = make_data(tmp->buffer, data->length);99memcpy(tmp->attr.data, data->data, data->length);100101K5_TAILQ_INSERT_TAIL(&set->list, tmp, list);102return 0;103}104105krb5_error_code106krad_attrset_add_number(krad_attrset *set, krad_attr type, krb5_ui_4 num)107{108krb5_data data;109110num = htonl(num);111data = make_data(&num, sizeof(num));112return krad_attrset_add(set, type, &data);113}114115void116krad_attrset_del(krad_attrset *set, krad_attr type, size_t indx)117{118attr *a;119120K5_TAILQ_FOREACH(a, &set->list, list) {121if (a->type == type && indx-- == 0) {122K5_TAILQ_REMOVE(&set->list, a, list);123zap(a->buffer, sizeof(a->buffer));124free(a);125return;126}127}128}129130const krb5_data *131krad_attrset_get(const krad_attrset *set, krad_attr type, size_t indx)132{133attr *a;134135K5_TAILQ_FOREACH(a, &set->list, list) {136if (a->type == type && indx-- == 0)137return &a->attr;138}139140return NULL;141}142143krb5_error_code144krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)145{146krb5_error_code retval;147krad_attrset *tmp;148attr *a;149150retval = krad_attrset_new(set->ctx, &tmp);151if (retval != 0)152return retval;153154K5_TAILQ_FOREACH(a, &set->list, list) {155retval = krad_attrset_add(tmp, a->type, &a->attr);156if (retval != 0) {157krad_attrset_free(tmp);158return retval;159}160}161162*copy = tmp;163return 0;164}165166/* Place an encoded attributes into outbuf at position *i. Increment *i by the167* length of the encoding. */168static krb5_error_code169append_attr(krb5_context ctx, const char *secret,170const uint8_t *auth, krad_attr type, const krb5_data *data,171uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i)172{173uint8_t buffer[MAX_ATTRSIZE];174size_t attrlen;175krb5_error_code retval;176177retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen);178if (retval)179return retval;180181if (attrlen > MAX_ATTRSETSIZE - *i - 2)182return EMSGSIZE;183184outbuf[(*i)++] = type;185outbuf[(*i)++] = attrlen + 2;186memcpy(outbuf + *i, buffer, attrlen);187*i += attrlen;188189return 0;190}191192krb5_error_code193kr_attrset_encode(const krad_attrset *set, const char *secret,194const uint8_t *auth, krb5_boolean add_msgauth,195unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)196{197krb5_error_code retval;198const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 };199krb5_data zerodata;200size_t i = 0;201attr *a;202203if (set == NULL) {204*outlen = 0;205return 0;206}207208if (add_msgauth) {209/* Encode Message-Authenticator as the first attribute, per210* draft-ietf-radext-deprecating-radius-03 section 5.2. */211zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE);212retval = append_attr(set->ctx, secret, auth,213KRAD_ATTR_MESSAGE_AUTHENTICATOR, &zerodata,214outbuf, &i);215if (retval)216return retval;217}218219K5_TAILQ_FOREACH(a, &set->list, list) {220retval = append_attr(set->ctx, secret, auth, a->type, &a->attr,221outbuf, &i);222if (retval)223return retval;224}225226*outlen = i;227return 0;228}229230krb5_error_code231kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret,232const unsigned char *auth, krad_attrset **set_out)233{234unsigned char buffer[MAX_ATTRSIZE];235krb5_data tmp;236krb5_error_code retval;237krad_attr type;238krad_attrset *set;239size_t i, len;240241*set_out = NULL;242243retval = krad_attrset_new(ctx, &set);244if (retval != 0)245return retval;246247for (i = 0; i + 2 < in->length; ) {248type = in->data[i++];249tmp = make_data(&in->data[i + 1], (uint8_t)in->data[i] - 2);250i += tmp.length + 1;251252retval = (in->length < i) ? EBADMSG : 0;253if (retval != 0)254goto cleanup;255256retval = kr_attr_decode(ctx, secret, auth, type, &tmp, buffer, &len);257if (retval != 0)258goto cleanup;259260tmp = make_data(buffer, len);261retval = krad_attrset_add(set, type, &tmp);262if (retval != 0)263goto cleanup;264}265266*set_out = set;267set = NULL;268269cleanup:270zap(buffer, sizeof(buffer));271krad_attrset_free(set);272return retval;273}274275276