|
Packit |
fd8b60 |
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
fd8b60 |
/* lib/krad/packet.c - Packet functions for libkrad */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Copyright 2013 Red Hat, Inc. All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in
|
|
Packit |
fd8b60 |
* the documentation and/or other materials provided with the
|
|
Packit |
fd8b60 |
* distribution.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
Packit |
fd8b60 |
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
Packit |
fd8b60 |
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
fd8b60 |
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
|
Packit |
fd8b60 |
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
fd8b60 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
fd8b60 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
fd8b60 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
fd8b60 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
fd8b60 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
fd8b60 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include "internal.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <arpa/inet.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
typedef unsigned char uchar;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* RFC 2865 */
|
|
Packit |
fd8b60 |
#define OFFSET_CODE 0
|
|
Packit |
fd8b60 |
#define OFFSET_ID 1
|
|
Packit |
fd8b60 |
#define OFFSET_LENGTH 2
|
|
Packit |
fd8b60 |
#define OFFSET_AUTH 4
|
|
Packit |
fd8b60 |
#define OFFSET_ATTR 20
|
|
Packit |
fd8b60 |
#define AUTH_FIELD_SIZE (OFFSET_ATTR - OFFSET_AUTH)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define offset(d, o) (&(d)->data[o])
|
|
Packit |
fd8b60 |
#define pkt_code_get(p) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE))
|
|
Packit |
fd8b60 |
#define pkt_code_set(p, v) (*(krad_code *)offset(&(p)->pkt, OFFSET_CODE)) = v
|
|
Packit |
fd8b60 |
#define pkt_id_get(p) (*(uchar *)offset(&(p)->pkt, OFFSET_ID))
|
|
Packit |
fd8b60 |
#define pkt_id_set(p, v) (*(uchar *)offset(&(p)->pkt, OFFSET_ID)) = v
|
|
Packit |
fd8b60 |
#define pkt_len_get(p) load_16_be(offset(&(p)->pkt, OFFSET_LENGTH))
|
|
Packit |
fd8b60 |
#define pkt_len_set(p, v) store_16_be(v, offset(&(p)->pkt, OFFSET_LENGTH))
|
|
Packit |
fd8b60 |
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
|
|
Packit |
fd8b60 |
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
|
|
Packit |
fd8b60 |
|
|
Packit Bot |
805b76 |
struct krad_packet_st {
|
|
Packit Bot |
805b76 |
char buffer[KRAD_PACKET_SIZE_MAX];
|
|
Packit Bot |
805b76 |
krad_attrset *attrset;
|
|
Packit Bot |
805b76 |
krb5_data pkt;
|
|
Packit Bot |
805b76 |
};
|
|
Packit Bot |
805b76 |
|
|
Packit |
fd8b60 |
typedef struct {
|
|
Packit |
fd8b60 |
uchar x[(UCHAR_MAX + 1) / 8];
|
|
Packit |
fd8b60 |
} idmap;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Ensure the map is empty. */
|
|
Packit |
fd8b60 |
static inline void
|
|
Packit |
fd8b60 |
idmap_init(idmap *map)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
memset(map, 0, sizeof(*map));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Set an id as already allocated. */
|
|
Packit |
fd8b60 |
static inline void
|
|
Packit |
fd8b60 |
idmap_set(idmap *map, uchar id)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
map->x[id / 8] |= 1 << (id % 8);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Determine whether or not an id is used. */
|
|
Packit |
fd8b60 |
static inline krb5_boolean
|
|
Packit |
fd8b60 |
idmap_isset(const idmap *map, uchar id)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return (map->x[id / 8] & (1 << (id % 8))) != 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Find an unused id starting the search at the value specified in id.
|
|
Packit |
fd8b60 |
* NOTE: For optimal security, the initial value of id should be random. */
|
|
Packit |
fd8b60 |
static inline krb5_error_code
|
|
Packit |
fd8b60 |
idmap_find(const idmap *map, uchar *id)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_int16 i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = *id; i >= 0 && i <= UCHAR_MAX; (*id % 2 == 0) ? i++ : i--) {
|
|
Packit |
fd8b60 |
if (!idmap_isset(map, i))
|
|
Packit |
fd8b60 |
goto success;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = *id; i >= 0 && i <= UCHAR_MAX; (*id % 2 == 1) ? i++ : i--) {
|
|
Packit |
fd8b60 |
if (!idmap_isset(map, i))
|
|
Packit |
fd8b60 |
goto success;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return ERANGE;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
success:
|
|
Packit |
fd8b60 |
*id = i;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate size bytes of random data into the buffer. */
|
|
Packit |
fd8b60 |
static inline krb5_error_code
|
|
Packit |
fd8b60 |
randomize(krb5_context ctx, void *buffer, unsigned int size)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_data rdata = make_data(buffer, size);
|
|
Packit |
fd8b60 |
return krb5_c_random_make_octets(ctx, &rdata);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate a radius packet id. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
id_generate(krb5_context ctx, krad_packet_iter_cb cb, void *data, uchar *id)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
const krad_packet *tmp;
|
|
Packit |
fd8b60 |
idmap used;
|
|
Packit |
fd8b60 |
uchar i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = randomize(ctx, &i, sizeof(i));
|
|
Packit |
fd8b60 |
if (retval != 0) {
|
|
Packit |
fd8b60 |
if (cb != NULL)
|
|
Packit |
fd8b60 |
(*cb)(data, TRUE);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (cb != NULL) {
|
|
Packit |
fd8b60 |
idmap_init(&used);
|
|
Packit |
fd8b60 |
for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE))
|
|
Packit |
fd8b60 |
idmap_set(&used, tmp->pkt.data[1]);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = idmap_find(&used, &i);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*id = i;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate a random authenticator field. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
auth_generate_random(krb5_context ctx, uchar *rauth)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_ui_4 trunctime;
|
|
Packit |
fd8b60 |
time_t currtime;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Get the least-significant four bytes of the current time. */
|
|
Packit |
fd8b60 |
currtime = time(NULL);
|
|
Packit |
fd8b60 |
if (currtime == (time_t)-1)
|
|
Packit |
fd8b60 |
return errno;
|
|
Packit |
fd8b60 |
trunctime = (krb5_ui_4)currtime;
|
|
Packit |
fd8b60 |
memcpy(rauth, &trunctime, sizeof(trunctime));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Randomize the rest of the buffer. */
|
|
Packit |
fd8b60 |
return randomize(ctx, rauth + sizeof(trunctime),
|
|
Packit |
fd8b60 |
AUTH_FIELD_SIZE - sizeof(trunctime));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate a response authenticator field. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
auth_generate_response(krb5_context ctx, const char *secret,
|
|
Packit |
fd8b60 |
const krad_packet *response, const uchar *auth,
|
|
Packit |
fd8b60 |
uchar *rauth)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krb5_checksum hash;
|
|
Packit |
fd8b60 |
krb5_data data;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Allocate the temporary buffer. */
|
|
Packit |
fd8b60 |
retval = alloc_data(&data, response->pkt.length + strlen(secret));
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Encoded RADIUS packet with the request's
|
|
Packit |
fd8b60 |
* authenticator and the secret at the end. */
|
|
Packit |
fd8b60 |
memcpy(data.data, response->pkt.data, response->pkt.length);
|
|
Packit |
fd8b60 |
memcpy(data.data + OFFSET_AUTH, auth, AUTH_FIELD_SIZE);
|
|
Packit |
fd8b60 |
memcpy(data.data + response->pkt.length, secret, strlen(secret));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Hash it. */
|
|
Packit Bot |
805b76 |
retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
|
Packit Bot |
805b76 |
&hash);
|
|
Packit |
fd8b60 |
free(data.data);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
memcpy(rauth, hash.contents, AUTH_FIELD_SIZE);
|
|
Packit |
fd8b60 |
krb5_free_checksum_contents(ctx, &hash);
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Create a new packet. */
|
|
Packit |
fd8b60 |
static krad_packet *
|
|
Packit |
fd8b60 |
packet_new()
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krad_packet *pkt;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
pkt = calloc(1, sizeof(krad_packet));
|
|
Packit |
fd8b60 |
if (pkt == NULL)
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
pkt->pkt = make_data(pkt->buffer, sizeof(pkt->buffer));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return pkt;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Set the attrset object by decoding the packet. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
packet_set_attrset(krb5_context ctx, const char *secret, krad_packet *pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_data tmp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp = make_data(pkt_attr(pkt), pkt->pkt.length - OFFSET_ATTR);
|
|
Packit |
fd8b60 |
return kr_attrset_decode(ctx, &tmp, secret, pkt_auth(pkt), &pkt->attrset);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
ssize_t
|
|
Packit |
fd8b60 |
krad_packet_bytes_needed(const krb5_data *buffer)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
size_t len;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (buffer->length < OFFSET_AUTH)
|
|
Packit |
fd8b60 |
return OFFSET_AUTH - buffer->length;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
len = load_16_be(offset(buffer, OFFSET_LENGTH));
|
|
Packit |
fd8b60 |
if (len > KRAD_PACKET_SIZE_MAX)
|
|
Packit |
fd8b60 |
return -1;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (buffer->length > len) ? 0 : len - buffer->length;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
void
|
|
Packit |
fd8b60 |
krad_packet_free(krad_packet *pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (pkt)
|
|
Packit |
fd8b60 |
krad_attrset_free(pkt->attrset);
|
|
Packit |
fd8b60 |
free(pkt);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Create a new request packet. */
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
|
|
Packit |
fd8b60 |
const krad_attrset *set, krad_packet_iter_cb cb,
|
|
Packit |
fd8b60 |
void *data, krad_packet **request)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krad_packet *pkt;
|
|
Packit |
fd8b60 |
uchar id;
|
|
Packit |
fd8b60 |
size_t attrset_len;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
pkt = packet_new();
|
|
Packit |
fd8b60 |
if (pkt == NULL) {
|
|
Packit |
fd8b60 |
if (cb != NULL)
|
|
Packit |
fd8b60 |
(*cb)(data, TRUE);
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate the ID. */
|
|
Packit |
fd8b60 |
retval = id_generate(ctx, cb, data, &id;;
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
pkt_id_set(pkt, id);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate the authenticator. */
|
|
Packit |
fd8b60 |
retval = auth_generate_random(ctx, pkt_auth(pkt));
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Encode the attributes. */
|
|
Packit |
fd8b60 |
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
|
|
Packit Bot |
805b76 |
&attrset_len);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Set the code, ID and length. */
|
|
Packit |
fd8b60 |
pkt->pkt.length = attrset_len + OFFSET_ATTR;
|
|
Packit |
fd8b60 |
pkt_code_set(pkt, code);
|
|
Packit |
fd8b60 |
pkt_len_set(pkt, pkt->pkt.length);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Copy the attrset for future use. */
|
|
Packit |
fd8b60 |
retval = packet_set_attrset(ctx, secret, pkt);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*request = pkt;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error:
|
|
Packit |
fd8b60 |
free(pkt);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Create a new request packet. */
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
|
|
Packit |
fd8b60 |
const krad_attrset *set, const krad_packet *request,
|
|
Packit |
fd8b60 |
krad_packet **response)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krad_packet *pkt;
|
|
Packit |
fd8b60 |
size_t attrset_len;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
pkt = packet_new();
|
|
Packit |
fd8b60 |
if (pkt == NULL)
|
|
Packit |
fd8b60 |
return ENOMEM;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Encode the attributes. */
|
|
Packit |
fd8b60 |
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
|
|
Packit Bot |
805b76 |
&attrset_len);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Set the code, ID and length. */
|
|
Packit |
fd8b60 |
pkt->pkt.length = attrset_len + OFFSET_ATTR;
|
|
Packit |
fd8b60 |
pkt_code_set(pkt, code);
|
|
Packit |
fd8b60 |
pkt_id_set(pkt, pkt_id_get(request));
|
|
Packit |
fd8b60 |
pkt_len_set(pkt, pkt->pkt.length);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Generate the authenticator. */
|
|
Packit |
fd8b60 |
retval = auth_generate_response(ctx, secret, pkt, pkt_auth(request),
|
|
Packit |
fd8b60 |
pkt_auth(pkt));
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Copy the attrset for future use. */
|
|
Packit |
fd8b60 |
retval = packet_set_attrset(ctx, secret, pkt);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*response = pkt;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error:
|
|
Packit |
fd8b60 |
free(pkt);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Decode a packet. */
|
|
Packit |
fd8b60 |
static krb5_error_code
|
|
Packit |
fd8b60 |
decode_packet(krb5_context ctx, const char *secret, const krb5_data *buffer,
|
|
Packit |
fd8b60 |
krad_packet **pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
krad_packet *tmp;
|
|
Packit |
fd8b60 |
krb5_ui_2 len;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
tmp = packet_new();
|
|
Packit |
fd8b60 |
if (tmp == NULL) {
|
|
Packit |
fd8b60 |
retval = ENOMEM;
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Ensure a proper message length. */
|
|
Packit |
fd8b60 |
retval = (buffer->length < OFFSET_ATTR) ? EMSGSIZE : 0;
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
len = load_16_be(offset(buffer, OFFSET_LENGTH));
|
|
Packit |
fd8b60 |
retval = (len < OFFSET_ATTR) ? EBADMSG : 0;
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
retval = (len > buffer->length || len > tmp->pkt.length) ? EBADMSG : 0;
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Copy over the buffer. */
|
|
Packit |
fd8b60 |
tmp->pkt.length = len;
|
|
Packit |
fd8b60 |
memcpy(tmp->pkt.data, buffer->data, len);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Parse the packet to ensure it is well-formed. */
|
|
Packit |
fd8b60 |
retval = packet_set_attrset(ctx, secret, tmp);
|
|
Packit |
fd8b60 |
if (retval != 0)
|
|
Packit |
fd8b60 |
goto error;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*pkt = tmp;
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error:
|
|
Packit |
fd8b60 |
krad_packet_free(tmp);
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
krad_packet_decode_request(krb5_context ctx, const char *secret,
|
|
Packit |
fd8b60 |
const krb5_data *buffer, krad_packet_iter_cb cb,
|
|
Packit |
fd8b60 |
void *data, const krad_packet **duppkt,
|
|
Packit |
fd8b60 |
krad_packet **reqpkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
const krad_packet *tmp = NULL;
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = decode_packet(ctx, secret, buffer, reqpkt);
|
|
Packit |
fd8b60 |
if (cb != NULL && retval == 0) {
|
|
Packit |
fd8b60 |
for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
|
|
Packit |
fd8b60 |
if (pkt_id_get(*reqpkt) == pkt_id_get(tmp))
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (cb != NULL && (retval != 0 || tmp != NULL))
|
|
Packit |
fd8b60 |
(*cb)(data, TRUE);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*duppkt = tmp;
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krb5_error_code
|
|
Packit |
fd8b60 |
krad_packet_decode_response(krb5_context ctx, const char *secret,
|
|
Packit |
fd8b60 |
const krb5_data *buffer, krad_packet_iter_cb cb,
|
|
Packit |
fd8b60 |
void *data, const krad_packet **reqpkt,
|
|
Packit |
fd8b60 |
krad_packet **rsppkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
uchar auth[AUTH_FIELD_SIZE];
|
|
Packit |
fd8b60 |
const krad_packet *tmp = NULL;
|
|
Packit |
fd8b60 |
krb5_error_code retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
retval = decode_packet(ctx, secret, buffer, rsppkt);
|
|
Packit |
fd8b60 |
if (cb != NULL && retval == 0) {
|
|
Packit |
fd8b60 |
for (tmp = (*cb)(data, FALSE); tmp != NULL; tmp = (*cb)(data, FALSE)) {
|
|
Packit |
fd8b60 |
if (pkt_id_get(*rsppkt) != pkt_id_get(tmp))
|
|
Packit |
fd8b60 |
continue;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Response */
|
|
Packit |
fd8b60 |
retval = auth_generate_response(ctx, secret, *rsppkt,
|
|
Packit |
fd8b60 |
pkt_auth(tmp), auth);
|
|
Packit |
fd8b60 |
if (retval != 0) {
|
|
Packit |
fd8b60 |
krad_packet_free(*rsppkt);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* If the authenticator matches, then the response is valid. */
|
|
Packit |
fd8b60 |
if (memcmp(pkt_auth(*rsppkt), auth, sizeof(auth)) == 0)
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (cb != NULL && (retval != 0 || tmp != NULL))
|
|
Packit |
fd8b60 |
(*cb)(data, TRUE);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
*reqpkt = tmp;
|
|
Packit |
fd8b60 |
return retval;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
const krb5_data *
|
|
Packit |
fd8b60 |
krad_packet_encode(const krad_packet *pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return &pkt->pkt;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
krad_code
|
|
Packit |
fd8b60 |
krad_packet_get_code(const krad_packet *pkt)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
if (pkt == NULL)
|
|
Packit |
fd8b60 |
return 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return pkt_code_get(pkt);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
const krb5_data *
|
|
Packit |
fd8b60 |
krad_packet_get_attr(const krad_packet *pkt, krad_attr type, size_t indx)
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
return krad_attrset_get(pkt->attrset, type, indx);
|
|
Packit |
fd8b60 |
}
|