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 *
iterator(void * data,krb5_boolean cancel)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
make_packet(krb5_context ctx,const krb5_data * username,const krb5_data * password,krad_packet ** pkt)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_USER_NAME, username);
74 if (retval != 0)
75 goto out;
76
77 retval = krad_attrset_add(set, KRAD_ATTR_USER_PASSWORD,
78 password);
79 if (retval != 0)
80 goto out;
81
82 retval = krad_attrset_add(set, KRAD_ATTR_NAS_IDENTIFIER, &nas_id);
83 if (retval != 0)
84 goto out;
85
86 retval = krad_packet_new_request(ctx, "foo", KRAD_CODE_ACCESS_REQUEST,
87 set, iterator, &i, &tmp);
88 if (retval != 0)
89 goto out;
90
91 data = krad_packet_get_attr(tmp, KRAD_ATTR_USER_NAME, 0);
92 if (data == NULL) {
93 retval = ENOENT;
94 goto out;
95 }
96
97 if (data->length != username->length ||
98 memcmp(data->data, username->data, data->length) != 0) {
99 retval = EINVAL;
100 goto out;
101 }
102
103 *pkt = tmp;
104 tmp = NULL;
105
106 out:
107 krad_attrset_free(set);
108 krad_packet_free(tmp);
109 return retval;
110 }
111
112 static krb5_error_code
do_auth(krb5_context ctx,struct addrinfo * ai,const char * secret,const krad_packet * rqst,krb5_boolean * auth)113 do_auth(krb5_context ctx, struct addrinfo *ai, const char *secret,
114 const krad_packet *rqst, krb5_boolean *auth)
115 {
116 const krad_packet *req = NULL;
117 char tmp[KRAD_PACKET_SIZE_MAX];
118 const krb5_data *request;
119 krad_packet *rsp = NULL;
120 krb5_error_code retval;
121 krb5_data response;
122 int sock = -1, i;
123
124 response = make_data(tmp, sizeof(tmp));
125
126 sock = socket(ai->ai_family, ai->ai_socktype, 0);
127 if (sock < 0) {
128 retval = errno;
129 goto out;
130 }
131
132 request = krad_packet_encode(rqst);
133 if (sendto(sock, request->data, request->length, 0, ai->ai_addr,
134 ai->ai_addrlen) < 0) {
135 retval = errno;
136 goto out;
137 }
138
139 i = recv(sock, response.data, sizeof(tmp), 0);
140 if (i < 0) {
141 retval = errno;
142 goto out;
143 }
144 response.length = i;
145
146 i = 0;
147 retval = krad_packet_decode_response(ctx, secret, &response, iterator, &i,
148 &req, &rsp);
149 if (retval != 0)
150 goto out;
151
152 if (req != rqst) {
153 retval = EBADMSG;
154 goto out;
155 }
156
157 *auth = krad_packet_get_code(rsp) == KRAD_CODE_ACCESS_ACCEPT;
158
159 out:
160 krad_packet_free(rsp);
161 if (sock >= 0)
162 close(sock);
163 return retval;
164 }
165
166 int
main(int argc,const char ** argv)167 main(int argc, const char **argv)
168 {
169 struct addrinfo *ai = NULL, hints;
170 krb5_data username, password;
171 krb5_boolean auth = FALSE;
172 krb5_context ctx;
173 const krad_packet *dupreq;
174 const krb5_data *encpkt;
175 krad_packet *decreq;
176
177 username = string2data("testUser");
178
179 if (!daemon_start(argc, argv)) {
180 fprintf(stderr, "Unable to start pyrad daemon, skipping test...\n");
181 return 0;
182 }
183
184 noerror(krb5_init_context(&ctx));
185
186 password = string2data("accept");
187 noerror(make_packet(ctx, &username, &password, &packets[ACCEPT_PACKET]));
188 encpkt = krad_packet_encode(packets[ACCEPT_PACKET]);
189 noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
190 &dupreq, &decreq));
191 krad_packet_free(decreq);
192
193 password = string2data("reject");
194 noerror(make_packet(ctx, &username, &password, &packets[REJECT_PACKET]));
195 encpkt = krad_packet_encode(packets[REJECT_PACKET]);
196 noerror(krad_packet_decode_request(ctx, "foo", encpkt, NULL, NULL,
197 &dupreq, &decreq));
198 krad_packet_free(decreq);
199
200 memset(&hints, 0, sizeof(hints));
201 hints.ai_family = AF_INET;
202 hints.ai_socktype = SOCK_DGRAM;
203 noerror(gai_error_code(getaddrinfo("127.0.0.1", "radius", &hints, &ai)));
204
205 noerror(do_auth(ctx, ai, "foo", packets[ACCEPT_PACKET], &auth));
206 insist(auth == TRUE);
207
208 noerror(do_auth(ctx, ai, "foo", packets[REJECT_PACKET], &auth));
209 insist(auth == FALSE);
210
211 krad_packet_free(packets[ACCEPT_PACKET]);
212 krad_packet_free(packets[REJECT_PACKET]);
213 krb5_free_context(ctx);
214 freeaddrinfo(ai);
215 return 0;
216 }
217