/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* lib/krad/t_packet.c - RADIUS packet test program */
/*
* 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 "t_daemon.h"
#define ACCEPT_PACKET 0
#define REJECT_PACKET 1
static krad_packet *packets[3];
static const krad_packet *
iterator(void *data, krb5_boolean cancel)
{
krad_packet *tmp;
int *i = data;
if (cancel || packets[*i] == NULL)
return NULL;
tmp = packets[*i];
*i += 1;
return tmp;
}
static krb5_error_code
make_packet(krb5_context ctx, const krb5_data *username,
const krb5_data *password, krad_packet **pkt)
{
krad_attrset *set = NULL;
krad_packet *tmp = NULL;
krb5_error_code retval;
const krb5_data *data;
int i = 0;
retval = krad_attrset_new(ctx, &set);
if (retval != 0)
goto out;
retval = krad_attrset_add(set, krad_attr_name2num("User-Name"), username);
if (retval != 0)
goto out;
retval = krad_attrset_add(set, krad_attr_name2num("User-Password"),
password);
if (retval != 0)
goto out;
retval = krad_packet_new_request(ctx, "foo",
krad_code_name2num("Access-Request"),
set, iterator, &i, &tmp);
if (retval != 0)
goto out;
data = krad_packet_get_attr(tmp, krad_attr_name2num("User-Name"), 0);
if (data == NULL) {
retval = ENOENT;
goto out;
}
if (data->length != username->length ||
memcmp(data->data, username->data, data->length) != 0) {
retval = EINVAL;
goto out;
}
*pkt = tmp;
tmp = NULL;
out:
krad_attrset_free(set);
krad_packet_free(tmp);
return retval;
}
static krb5_error_code
do_auth(krb5_context ctx, struct addrinfo *ai, const char *secret,
const krad_packet *rqst, krb5_boolean *auth)
{
const krad_packet *req = NULL;
char tmp[KRAD_PACKET_SIZE_MAX];
const krb5_data *request;
krad_packet *rsp = NULL;
krb5_error_code retval;
krb5_data response;
int sock = -1, i;
response = make_data(tmp, sizeof(tmp));
sock = socket(ai->ai_family, ai->ai_socktype, 0);
if (sock < 0) {
retval = errno;
goto out;
}
request = krad_packet_encode(rqst);
if (sendto(sock, request->data, request->length, 0, ai->ai_addr,
ai->ai_addrlen) < 0) {
retval = errno;
goto out;
}
i = recv(sock, response.data, sizeof(tmp), 0);
if (i < 0) {
retval = errno;
goto out;
}
response.length = i;
i = 0;
retval = krad_packet_decode_response(ctx, secret, &response, iterator, &i,
&req, &rsp);
if (retval != 0)
goto out;
if (req != rqst) {
retval = EBADMSG;
goto out;
}
*auth = krad_packet_get_code(rsp) == krad_code_name2num("Access-Accept");
out:
krad_packet_free(rsp);
if (sock >= 0)
close(sock);
return retval;
}
int
main(int argc, const char **argv)
{
struct addrinfo *ai = NULL, hints;
krb5_data username, password;
krb5_boolean auth = FALSE;
krb5_context ctx;
username = string2data("testUser");
if (!daemon_start(argc, argv)) {
fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n");
return 0;
}
noerror(krb5_init_context(&ctx));
password = string2data("accept");
noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET]));
password = string2data("reject");
noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET]));
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
noerror(gai_error_code(getaddrinfo("127.0.0.1", "radius", &hints, &ai)));
noerror(do_auth(ctx, ai, "foo", packets[ACCEPT_PACKET], &auth));
insist(auth == TRUE);
noerror(do_auth(ctx, ai, "foo", packets[REJECT_PACKET], &auth));
insist(auth == FALSE);
krad_packet_free(packets[ACCEPT_PACKET]);
krad_packet_free(packets[REJECT_PACKET]);
krb5_free_context(ctx);
freeaddrinfo(ai);
return 0;
}