xref: /freebsd/crypto/krb5/src/lib/krad/t_packet.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
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