1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* lib/krad/t_packet.c - RADIUS packet test program */ 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 "t_daemon.h" 31 32 #define ACCEPT_PACKET 0 33 #define REJECT_PACKET 1 34 35 static krad_packet *packets[3]; 36 37 static const krad_packet * 38 iterator(void *data, krb5_boolean cancel) 39 { 40 krad_packet *tmp; 41 int *i = data; 42 43 if (cancel || packets[*i] == NULL) 44 return NULL; 45 46 tmp = packets[*i]; 47 *i += 1; 48 return tmp; 49 } 50 51 static krb5_error_code 52 make_packet(krb5_context ctx, const krb5_data *username, 53 const krb5_data *password, krad_packet **pkt) 54 { 55 krad_attrset *set = NULL; 56 krad_packet *tmp = NULL; 57 krb5_error_code retval; 58 const krb5_data *data; 59 int i = 0; 60 krb5_data nas_id; 61 62 nas_id = string2data("12345678901234567890123456789012345678901234567890" 63 "12345678901234567890123456789012345678901234567890" 64 "12345678901234567890123456789012345678901234567890" 65 "12345678901234567890123456789012345678901234567890" 66 "12345678901234567890123456789012345678901234567890" 67 "123"); 68 69 retval = krad_attrset_new(ctx, &set); 70 if (retval != 0) 71 goto out; 72 73 retval = krad_attrset_add(set, krad_attr_name2num("User-Name"), username); 74 if (retval != 0) 75 goto out; 76 77 retval = krad_attrset_add(set, krad_attr_name2num("User-Password"), 78 password); 79 if (retval != 0) 80 goto out; 81 82 retval = krad_attrset_add(set, krad_attr_name2num("NAS-Identifier"), 83 &nas_id); 84 if (retval != 0) 85 goto out; 86 87 retval = krad_packet_new_request(ctx, "foo", 88 krad_code_name2num("Access-Request"), 89 set, iterator, &i, &tmp); 90 if (retval != 0) 91 goto out; 92 93 data = krad_packet_get_attr(tmp, krad_attr_name2num("User-Name"), 0); 94 if (data == NULL) { 95 retval = ENOENT; 96 goto out; 97 } 98 99 if (data->length != username->length || 100 memcmp(data->data, username->data, data->length) != 0) { 101 retval = EINVAL; 102 goto out; 103 } 104 105 *pkt = tmp; 106 tmp = NULL; 107 108 out: 109 krad_attrset_free(set); 110 krad_packet_free(tmp); 111 return retval; 112 } 113 114 static krb5_error_code 115 do_auth(krb5_context ctx, struct addrinfo *ai, const char *secret, 116 const krad_packet *rqst, krb5_boolean *auth) 117 { 118 const krad_packet *req = NULL; 119 char tmp[KRAD_PACKET_SIZE_MAX]; 120 const krb5_data *request; 121 krad_packet *rsp = NULL; 122 krb5_error_code retval; 123 krb5_data response; 124 int sock = -1, i; 125 126 response = make_data(tmp, sizeof(tmp)); 127 128 sock = socket(ai->ai_family, ai->ai_socktype, 0); 129 if (sock < 0) { 130 retval = errno; 131 goto out; 132 } 133 134 request = krad_packet_encode(rqst); 135 if (sendto(sock, request->data, request->length, 0, ai->ai_addr, 136 ai->ai_addrlen) < 0) { 137 retval = errno; 138 goto out; 139 } 140 141 i = recv(sock, response.data, sizeof(tmp), 0); 142 if (i < 0) { 143 retval = errno; 144 goto out; 145 } 146 response.length = i; 147 148 i = 0; 149 retval = krad_packet_decode_response(ctx, secret, &response, iterator, &i, 150 &req, &rsp); 151 if (retval != 0) 152 goto out; 153 154 if (req != rqst) { 155 retval = EBADMSG; 156 goto out; 157 } 158 159 *auth = krad_packet_get_code(rsp) == krad_code_name2num("Access-Accept"); 160 161 out: 162 krad_packet_free(rsp); 163 if (sock >= 0) 164 close(sock); 165 return retval; 166 } 167 168 int 169 main(int argc, const char **argv) 170 { 171 struct addrinfo *ai = NULL, hints; 172 krb5_data username, password; 173 krb5_boolean auth = FALSE; 174 krb5_context ctx; 175 176 username = string2data("testUser"); 177 178 if (!daemon_start(argc, argv)) { 179 fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n"); 180 return 0; 181 } 182 183 noerror(krb5_init_context(&ctx)); 184 185 password = string2data("accept"); 186 noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET])); 187 188 password = string2data("reject"); 189 noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET])); 190 191 memset(&hints, 0, sizeof(hints)); 192 hints.ai_family = AF_INET; 193 hints.ai_socktype = SOCK_DGRAM; 194 noerror(gai_error_code(getaddrinfo("127.0.0.1", "radius", &hints, &ai))); 195 196 noerror(do_auth(ctx, ai, "foo", packets[ACCEPT_PACKET], &auth)); 197 insist(auth == TRUE); 198 199 noerror(do_auth(ctx, ai, "foo", packets[REJECT_PACKET], &auth)); 200 insist(auth == FALSE); 201 202 krad_packet_free(packets[ACCEPT_PACKET]); 203 krad_packet_free(packets[REJECT_PACKET]); 204 krb5_free_context(ctx); 205 freeaddrinfo(ai); 206 return 0; 207 } 208