radlib.c revision 1.1.1.1 1 1.1 manu /* $NetBSD: radlib.c,v 1.1.1.1 2005/02/19 23:56:34 manu Exp $ */
2 1.1 manu
3 1.1 manu /*-
4 1.1 manu * Copyright 1998 Juniper Networks, Inc.
5 1.1 manu * All rights reserved.
6 1.1 manu *
7 1.1 manu * Redistribution and use in source and binary forms, with or without
8 1.1 manu * modification, are permitted provided that the following conditions
9 1.1 manu * are met:
10 1.1 manu * 1. Redistributions of source code must retain the above copyright
11 1.1 manu * notice, this list of conditions and the following disclaimer.
12 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 manu * notice, this list of conditions and the following disclaimer in the
14 1.1 manu * documentation and/or other materials provided with the distribution.
15 1.1 manu *
16 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 manu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 manu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 manu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 manu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 manu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 manu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 manu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 manu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 manu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 manu * SUCH DAMAGE.
27 1.1 manu */
28 1.1 manu
29 1.1 manu #include <sys/cdefs.h>
30 1.1 manu #ifdef __FreeBSD__
31 1.1 manu __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libradius/radlib.c,v 1.12 2004/06/14 20:55:30 stefanf Exp $");
32 1.1 manu #else
33 1.1 manu __RCSID("$NetBSD: radlib.c,v 1.1.1.1 2005/02/19 23:56:34 manu Exp $");
34 1.1 manu #endif
35 1.1 manu
36 1.1 manu #include <sys/types.h>
37 1.1 manu #include <sys/socket.h>
38 1.1 manu #include <sys/time.h>
39 1.1 manu #include <netinet/in.h>
40 1.1 manu #include <arpa/inet.h>
41 1.1 manu #ifdef WITH_SSL
42 1.1 manu #include <openssl/hmac.h>
43 1.1 manu #include <openssl/md5.h>
44 1.1 manu #define MD5Init MD5_Init
45 1.1 manu #define MD5Update MD5_Update
46 1.1 manu #define MD5Final MD5_Final
47 1.1 manu #else
48 1.1 manu #define MD5_DIGEST_LENGTH 16
49 1.1 manu #include <md5.h>
50 1.1 manu #endif
51 1.1 manu
52 1.1 manu /* We need the MPPE_KEY_LEN define */
53 1.1 manu #ifdef __FreeBSD__
54 1.1 manu #include <netgraph/ng_mppc.h>
55 1.1 manu #else
56 1.1 manu #define MPPE_KEY_LEN 16
57 1.1 manu #endif
58 1.1 manu
59 1.1 manu #include <errno.h>
60 1.1 manu #include <netdb.h>
61 1.1 manu #include <stdarg.h>
62 1.1 manu #include <stddef.h>
63 1.1 manu #include <stdio.h>
64 1.1 manu #include <stdlib.h>
65 1.1 manu #include <string.h>
66 1.1 manu #include <unistd.h>
67 1.1 manu
68 1.1 manu #include "radlib_private.h"
69 1.1 manu #if !defined(__printflike)
70 1.1 manu #define __printflike(fmtarg, firstvararg) \
71 1.1 manu __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
72 1.1 manu #endif
73 1.1 manu
74 1.1 manu #ifdef __NetBSD__
75 1.1 manu #define srandomdev(x)
76 1.1 manu #define random arc4random
77 1.1 manu #endif
78 1.1 manu
79 1.1 manu static void clear_password(struct rad_handle *);
80 1.1 manu static void generr(struct rad_handle *, const char *, ...)
81 1.1 manu __printflike(2, 3);
82 1.1 manu static void insert_scrambled_password(struct rad_handle *, int);
83 1.1 manu static void insert_request_authenticator(struct rad_handle *, int);
84 1.1 manu static void insert_message_authenticator(struct rad_handle *, int);
85 1.1 manu static int is_valid_response(struct rad_handle *, int,
86 1.1 manu const struct sockaddr_in *);
87 1.1 manu static int put_password_attr(struct rad_handle *, int,
88 1.1 manu const void *, size_t);
89 1.1 manu static int put_raw_attr(struct rad_handle *, int,
90 1.1 manu const void *, size_t);
91 1.1 manu static int split(char *, char *[], int, char *, size_t);
92 1.1 manu
93 1.1 manu static void
94 1.1 manu clear_password(struct rad_handle *h)
95 1.1 manu {
96 1.1 manu if (h->pass_len != 0) {
97 1.1 manu memset(h->pass, 0, h->pass_len);
98 1.1 manu h->pass_len = 0;
99 1.1 manu }
100 1.1 manu h->pass_pos = 0;
101 1.1 manu }
102 1.1 manu
103 1.1 manu static void
104 1.1 manu generr(struct rad_handle *h, const char *format, ...)
105 1.1 manu {
106 1.1 manu va_list ap;
107 1.1 manu
108 1.1 manu va_start(ap, format);
109 1.1 manu vsnprintf(h->errmsg, ERRSIZE, format, ap);
110 1.1 manu va_end(ap);
111 1.1 manu }
112 1.1 manu
113 1.1 manu static void
114 1.1 manu insert_scrambled_password(struct rad_handle *h, int srv)
115 1.1 manu {
116 1.1 manu MD5_CTX ctx;
117 1.1 manu unsigned char md5[MD5_DIGEST_LENGTH];
118 1.1 manu const struct rad_server *srvp;
119 1.1 manu int padded_len;
120 1.1 manu int pos;
121 1.1 manu
122 1.1 manu srvp = &h->servers[srv];
123 1.1 manu padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf;
124 1.1 manu
125 1.1 manu memcpy(md5, &h->request[POS_AUTH], LEN_AUTH);
126 1.1 manu for (pos = 0; pos < padded_len; pos += 16) {
127 1.1 manu int i;
128 1.1 manu
129 1.1 manu /* Calculate the new scrambler */
130 1.1 manu MD5Init(&ctx);
131 1.1 manu MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
132 1.1 manu MD5Update(&ctx, md5, 16);
133 1.1 manu MD5Final(md5, &ctx);
134 1.1 manu
135 1.1 manu /*
136 1.1 manu * Mix in the current chunk of the password, and copy
137 1.1 manu * the result into the right place in the request. Also
138 1.1 manu * modify the scrambler in place, since we will use this
139 1.1 manu * in calculating the scrambler for next time.
140 1.1 manu */
141 1.1 manu for (i = 0; i < 16; i++)
142 1.1 manu h->request[h->pass_pos + pos + i] =
143 1.1 manu md5[i] ^= h->pass[pos + i];
144 1.1 manu }
145 1.1 manu }
146 1.1 manu
147 1.1 manu static void
148 1.1 manu insert_request_authenticator(struct rad_handle *h, int srv)
149 1.1 manu {
150 1.1 manu MD5_CTX ctx;
151 1.1 manu const struct rad_server *srvp;
152 1.1 manu
153 1.1 manu srvp = &h->servers[srv];
154 1.1 manu
155 1.1 manu /* Create the request authenticator */
156 1.1 manu MD5Init(&ctx);
157 1.1 manu MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
158 1.1 manu MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH);
159 1.1 manu MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS);
160 1.1 manu MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
161 1.1 manu MD5Final(&h->request[POS_AUTH], &ctx);
162 1.1 manu }
163 1.1 manu
164 1.1 manu static void
165 1.1 manu insert_message_authenticator(struct rad_handle *h, int srv)
166 1.1 manu {
167 1.1 manu #ifdef WITH_SSL
168 1.1 manu u_char md[EVP_MAX_MD_SIZE];
169 1.1 manu u_int md_len;
170 1.1 manu const struct rad_server *srvp;
171 1.1 manu HMAC_CTX ctx;
172 1.1 manu srvp = &h->servers[srv];
173 1.1 manu
174 1.1 manu if (h->authentic_pos != 0) {
175 1.1 manu HMAC_CTX_init(&ctx);
176 1.1 manu HMAC_Init(&ctx, srvp->secret, strlen(srvp->secret), EVP_md5());
177 1.1 manu HMAC_Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE);
178 1.1 manu HMAC_Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
179 1.1 manu HMAC_Update(&ctx, &h->request[POS_ATTRS],
180 1.1 manu h->req_len - POS_ATTRS);
181 1.1 manu HMAC_Final(&ctx, md, &md_len);
182 1.1 manu HMAC_CTX_cleanup(&ctx);
183 1.1 manu HMAC_cleanup(&ctx);
184 1.1 manu memcpy(&h->request[h->authentic_pos + 2], md, md_len);
185 1.1 manu }
186 1.1 manu #endif
187 1.1 manu }
188 1.1 manu
189 1.1 manu /*
190 1.1 manu * Return true if the current response is valid for a request to the
191 1.1 manu * specified server.
192 1.1 manu */
193 1.1 manu static int
194 1.1 manu is_valid_response(struct rad_handle *h, int srv,
195 1.1 manu const struct sockaddr_in *from)
196 1.1 manu {
197 1.1 manu MD5_CTX ctx;
198 1.1 manu unsigned char md5[MD5_DIGEST_LENGTH];
199 1.1 manu const struct rad_server *srvp;
200 1.1 manu int len;
201 1.1 manu #ifdef WITH_SSL
202 1.1 manu HMAC_CTX hctx;
203 1.1 manu u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE];
204 1.1 manu int pos, md_len;
205 1.1 manu #endif
206 1.1 manu
207 1.1 manu srvp = &h->servers[srv];
208 1.1 manu
209 1.1 manu /* Check the source address */
210 1.1 manu if (from->sin_family != srvp->addr.sin_family ||
211 1.1 manu from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr ||
212 1.1 manu from->sin_port != srvp->addr.sin_port)
213 1.1 manu return 0;
214 1.1 manu
215 1.1 manu /* Check the message length */
216 1.1 manu if (h->resp_len < POS_ATTRS)
217 1.1 manu return 0;
218 1.1 manu len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1];
219 1.1 manu if (len > h->resp_len)
220 1.1 manu return 0;
221 1.1 manu
222 1.1 manu /* Check the response authenticator */
223 1.1 manu MD5Init(&ctx);
224 1.1 manu MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE);
225 1.1 manu MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH);
226 1.1 manu MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS);
227 1.1 manu MD5Update(&ctx, srvp->secret, strlen(srvp->secret));
228 1.1 manu MD5Final(md5, &ctx);
229 1.1 manu if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0)
230 1.1 manu return 0;
231 1.1 manu
232 1.1 manu #ifdef WITH_SSL
233 1.1 manu /*
234 1.1 manu * For non accounting responses check the message authenticator,
235 1.1 manu * if any.
236 1.1 manu */
237 1.1 manu if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) {
238 1.1 manu
239 1.1 manu memcpy(resp, h->response, MSGSIZE);
240 1.1 manu pos = POS_ATTRS;
241 1.1 manu
242 1.1 manu /* Search and verify the Message-Authenticator */
243 1.1 manu while (pos < len - 2) {
244 1.1 manu
245 1.1 manu if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) {
246 1.1 manu /* zero fill the Message-Authenticator */
247 1.1 manu memset(&resp[pos + 2], 0, MD5_DIGEST_LENGTH);
248 1.1 manu
249 1.1 manu HMAC_CTX_init(&hctx);
250 1.1 manu HMAC_Init(&hctx, srvp->secret,
251 1.1 manu strlen(srvp->secret), EVP_md5());
252 1.1 manu HMAC_Update(&hctx, &h->response[POS_CODE],
253 1.1 manu POS_AUTH - POS_CODE);
254 1.1 manu HMAC_Update(&hctx, &h->request[POS_AUTH],
255 1.1 manu LEN_AUTH);
256 1.1 manu HMAC_Update(&hctx, &resp[POS_ATTRS],
257 1.1 manu h->resp_len - POS_ATTRS);
258 1.1 manu HMAC_Final(&hctx, md, &md_len);
259 1.1 manu HMAC_CTX_cleanup(&hctx);
260 1.1 manu HMAC_cleanup(&hctx);
261 1.1 manu if (memcmp(md, &h->response[pos + 2],
262 1.1 manu MD5_DIGEST_LENGTH) != 0)
263 1.1 manu return 0;
264 1.1 manu break;
265 1.1 manu }
266 1.1 manu pos += h->response[pos + 1];
267 1.1 manu }
268 1.1 manu }
269 1.1 manu #endif
270 1.1 manu return 1;
271 1.1 manu }
272 1.1 manu
273 1.1 manu static int
274 1.1 manu put_password_attr(struct rad_handle *h, int type, const void *value, size_t len)
275 1.1 manu {
276 1.1 manu int padded_len;
277 1.1 manu int pad_len;
278 1.1 manu
279 1.1 manu if (h->pass_pos != 0) {
280 1.1 manu generr(h, "Multiple User-Password attributes specified");
281 1.1 manu return -1;
282 1.1 manu }
283 1.1 manu if (len > PASSSIZE)
284 1.1 manu len = PASSSIZE;
285 1.1 manu padded_len = len == 0 ? 16 : (len+15) & ~0xf;
286 1.1 manu pad_len = padded_len - len;
287 1.1 manu
288 1.1 manu /*
289 1.1 manu * Put in a place-holder attribute containing all zeros, and
290 1.1 manu * remember where it is so we can fill it in later.
291 1.1 manu */
292 1.1 manu clear_password(h);
293 1.1 manu put_raw_attr(h, type, h->pass, padded_len);
294 1.1 manu h->pass_pos = h->req_len - padded_len;
295 1.1 manu
296 1.1 manu /* Save the cleartext password, padded as necessary */
297 1.1 manu memcpy(h->pass, value, len);
298 1.1 manu h->pass_len = len;
299 1.1 manu memset(h->pass + len, 0, pad_len);
300 1.1 manu return 0;
301 1.1 manu }
302 1.1 manu
303 1.1 manu static int
304 1.1 manu put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len)
305 1.1 manu {
306 1.1 manu if (len > 253) {
307 1.1 manu generr(h, "Attribute too long");
308 1.1 manu return -1;
309 1.1 manu }
310 1.1 manu if (h->req_len + 2 + len > MSGSIZE) {
311 1.1 manu generr(h, "Maximum message length exceeded");
312 1.1 manu return -1;
313 1.1 manu }
314 1.1 manu h->request[h->req_len++] = type;
315 1.1 manu h->request[h->req_len++] = len + 2;
316 1.1 manu memcpy(&h->request[h->req_len], value, len);
317 1.1 manu h->req_len += len;
318 1.1 manu return 0;
319 1.1 manu }
320 1.1 manu
321 1.1 manu int
322 1.1 manu rad_add_server(struct rad_handle *h, const char *host, int port,
323 1.1 manu const char *secret, int timeout, int tries)
324 1.1 manu {
325 1.1 manu struct rad_server *srvp;
326 1.1 manu
327 1.1 manu if (h->num_servers >= MAXSERVERS) {
328 1.1 manu generr(h, "Too many RADIUS servers specified");
329 1.1 manu return -1;
330 1.1 manu }
331 1.1 manu srvp = &h->servers[h->num_servers];
332 1.1 manu
333 1.1 manu memset(&srvp->addr, 0, sizeof srvp->addr);
334 1.1 manu srvp->addr.sin_len = sizeof srvp->addr;
335 1.1 manu srvp->addr.sin_family = AF_INET;
336 1.1 manu if (!inet_aton(host, &srvp->addr.sin_addr)) {
337 1.1 manu struct hostent *hent;
338 1.1 manu
339 1.1 manu if ((hent = gethostbyname(host)) == NULL) {
340 1.1 manu generr(h, "%s: host not found", host);
341 1.1 manu return -1;
342 1.1 manu }
343 1.1 manu memcpy(&srvp->addr.sin_addr, hent->h_addr,
344 1.1 manu sizeof srvp->addr.sin_addr);
345 1.1 manu }
346 1.1 manu if (port != 0)
347 1.1 manu srvp->addr.sin_port = htons((u_short)port);
348 1.1 manu else {
349 1.1 manu struct servent *sent;
350 1.1 manu
351 1.1 manu if (h->type == RADIUS_AUTH)
352 1.1 manu srvp->addr.sin_port =
353 1.1 manu (sent = getservbyname("radius", "udp")) != NULL ?
354 1.1 manu sent->s_port : htons(RADIUS_PORT);
355 1.1 manu else
356 1.1 manu srvp->addr.sin_port =
357 1.1 manu (sent = getservbyname("radacct", "udp")) != NULL ?
358 1.1 manu sent->s_port : htons(RADACCT_PORT);
359 1.1 manu }
360 1.1 manu if ((srvp->secret = strdup(secret)) == NULL) {
361 1.1 manu generr(h, "Out of memory");
362 1.1 manu return -1;
363 1.1 manu }
364 1.1 manu srvp->timeout = timeout;
365 1.1 manu srvp->max_tries = tries;
366 1.1 manu srvp->num_tries = 0;
367 1.1 manu h->num_servers++;
368 1.1 manu return 0;
369 1.1 manu }
370 1.1 manu
371 1.1 manu void
372 1.1 manu rad_close(struct rad_handle *h)
373 1.1 manu {
374 1.1 manu int srv;
375 1.1 manu
376 1.1 manu if (h->fd != -1)
377 1.1 manu close(h->fd);
378 1.1 manu for (srv = 0; srv < h->num_servers; srv++) {
379 1.1 manu memset(h->servers[srv].secret, 0,
380 1.1 manu strlen(h->servers[srv].secret));
381 1.1 manu free(h->servers[srv].secret);
382 1.1 manu }
383 1.1 manu clear_password(h);
384 1.1 manu free(h);
385 1.1 manu }
386 1.1 manu
387 1.1 manu int
388 1.1 manu rad_config(struct rad_handle *h, const char *path)
389 1.1 manu {
390 1.1 manu FILE *fp;
391 1.1 manu char buf[MAXCONFLINE];
392 1.1 manu int linenum;
393 1.1 manu int retval;
394 1.1 manu
395 1.1 manu if (path == NULL)
396 1.1 manu path = PATH_RADIUS_CONF;
397 1.1 manu if ((fp = fopen(path, "r")) == NULL) {
398 1.1 manu generr(h, "Cannot open \"%s\": %s", path, strerror(errno));
399 1.1 manu return -1;
400 1.1 manu }
401 1.1 manu retval = 0;
402 1.1 manu linenum = 0;
403 1.1 manu while (fgets(buf, sizeof buf, fp) != NULL) {
404 1.1 manu int len;
405 1.1 manu char *fields[5];
406 1.1 manu int nfields;
407 1.1 manu char msg[ERRSIZE];
408 1.1 manu char *type;
409 1.1 manu char *host, *res;
410 1.1 manu char *port_str;
411 1.1 manu char *secret;
412 1.1 manu char *timeout_str;
413 1.1 manu char *maxtries_str;
414 1.1 manu char *end;
415 1.1 manu char *wanttype;
416 1.1 manu unsigned long timeout;
417 1.1 manu unsigned long maxtries;
418 1.1 manu int port;
419 1.1 manu int i;
420 1.1 manu
421 1.1 manu linenum++;
422 1.1 manu len = strlen(buf);
423 1.1 manu /* We know len > 0, else fgets would have returned NULL. */
424 1.1 manu if (buf[len - 1] != '\n') {
425 1.1 manu if (len == sizeof buf - 1)
426 1.1 manu generr(h, "%s:%d: line too long", path,
427 1.1 manu linenum);
428 1.1 manu else
429 1.1 manu generr(h, "%s:%d: missing newline", path,
430 1.1 manu linenum);
431 1.1 manu retval = -1;
432 1.1 manu break;
433 1.1 manu }
434 1.1 manu buf[len - 1] = '\0';
435 1.1 manu
436 1.1 manu /* Extract the fields from the line. */
437 1.1 manu nfields = split(buf, fields, 5, msg, sizeof msg);
438 1.1 manu if (nfields == -1) {
439 1.1 manu generr(h, "%s:%d: %s", path, linenum, msg);
440 1.1 manu retval = -1;
441 1.1 manu break;
442 1.1 manu }
443 1.1 manu if (nfields == 0)
444 1.1 manu continue;
445 1.1 manu /*
446 1.1 manu * The first field should contain "auth" or "acct" for
447 1.1 manu * authentication or accounting, respectively. But older
448 1.1 manu * versions of the file didn't have that field. Default
449 1.1 manu * it to "auth" for backward compatibility.
450 1.1 manu */
451 1.1 manu if (strcmp(fields[0], "auth") != 0 &&
452 1.1 manu strcmp(fields[0], "acct") != 0) {
453 1.1 manu if (nfields >= 5) {
454 1.1 manu generr(h, "%s:%d: invalid service type", path,
455 1.1 manu linenum);
456 1.1 manu retval = -1;
457 1.1 manu break;
458 1.1 manu }
459 1.1 manu nfields++;
460 1.1 manu for (i = nfields; --i > 0; )
461 1.1 manu fields[i] = fields[i - 1];
462 1.1 manu fields[0] = "auth";
463 1.1 manu }
464 1.1 manu if (nfields < 3) {
465 1.1 manu generr(h, "%s:%d: missing shared secret", path,
466 1.1 manu linenum);
467 1.1 manu retval = -1;
468 1.1 manu break;
469 1.1 manu }
470 1.1 manu type = fields[0];
471 1.1 manu host = fields[1];
472 1.1 manu secret = fields[2];
473 1.1 manu timeout_str = fields[3];
474 1.1 manu maxtries_str = fields[4];
475 1.1 manu
476 1.1 manu /* Ignore the line if it is for the wrong service type. */
477 1.1 manu wanttype = h->type == RADIUS_AUTH ? "auth" : "acct";
478 1.1 manu if (strcmp(type, wanttype) != 0)
479 1.1 manu continue;
480 1.1 manu
481 1.1 manu /* Parse and validate the fields. */
482 1.1 manu res = host;
483 1.1 manu host = strsep(&res, ":");
484 1.1 manu port_str = strsep(&res, ":");
485 1.1 manu if (port_str != NULL) {
486 1.1 manu port = strtoul(port_str, &end, 10);
487 1.1 manu if (*end != '\0') {
488 1.1 manu generr(h, "%s:%d: invalid port", path,
489 1.1 manu linenum);
490 1.1 manu retval = -1;
491 1.1 manu break;
492 1.1 manu }
493 1.1 manu } else
494 1.1 manu port = 0;
495 1.1 manu if (timeout_str != NULL) {
496 1.1 manu timeout = strtoul(timeout_str, &end, 10);
497 1.1 manu if (*end != '\0') {
498 1.1 manu generr(h, "%s:%d: invalid timeout", path,
499 1.1 manu linenum);
500 1.1 manu retval = -1;
501 1.1 manu break;
502 1.1 manu }
503 1.1 manu } else
504 1.1 manu timeout = TIMEOUT;
505 1.1 manu if (maxtries_str != NULL) {
506 1.1 manu maxtries = strtoul(maxtries_str, &end, 10);
507 1.1 manu if (*end != '\0') {
508 1.1 manu generr(h, "%s:%d: invalid maxtries", path,
509 1.1 manu linenum);
510 1.1 manu retval = -1;
511 1.1 manu break;
512 1.1 manu }
513 1.1 manu } else
514 1.1 manu maxtries = MAXTRIES;
515 1.1 manu
516 1.1 manu if (rad_add_server(h, host, port, secret, timeout, maxtries) ==
517 1.1 manu -1) {
518 1.1 manu strcpy(msg, h->errmsg);
519 1.1 manu generr(h, "%s:%d: %s", path, linenum, msg);
520 1.1 manu retval = -1;
521 1.1 manu break;
522 1.1 manu }
523 1.1 manu }
524 1.1 manu /* Clear out the buffer to wipe a possible copy of a shared secret */
525 1.1 manu memset(buf, 0, sizeof buf);
526 1.1 manu fclose(fp);
527 1.1 manu return retval;
528 1.1 manu }
529 1.1 manu
530 1.1 manu /*
531 1.1 manu * rad_init_send_request() must have previously been called.
532 1.1 manu * Returns:
533 1.1 manu * 0 The application should select on *fd with a timeout of tv before
534 1.1 manu * calling rad_continue_send_request again.
535 1.1 manu * < 0 Failure
536 1.1 manu * > 0 Success
537 1.1 manu */
538 1.1 manu int
539 1.1 manu rad_continue_send_request(struct rad_handle *h, int selected, int *fd,
540 1.1 manu struct timeval *tv)
541 1.1 manu {
542 1.1 manu int n;
543 1.1 manu
544 1.1 manu if (selected) {
545 1.1 manu struct sockaddr_in from;
546 1.1 manu int fromlen;
547 1.1 manu
548 1.1 manu fromlen = sizeof from;
549 1.1 manu h->resp_len = recvfrom(h->fd, h->response,
550 1.1 manu MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
551 1.1 manu if (h->resp_len == -1) {
552 1.1 manu generr(h, "recvfrom: %s", strerror(errno));
553 1.1 manu return -1;
554 1.1 manu }
555 1.1 manu if (is_valid_response(h, h->srv, &from)) {
556 1.1 manu h->resp_len = h->response[POS_LENGTH] << 8 |
557 1.1 manu h->response[POS_LENGTH+1];
558 1.1 manu h->resp_pos = POS_ATTRS;
559 1.1 manu return h->response[POS_CODE];
560 1.1 manu }
561 1.1 manu }
562 1.1 manu
563 1.1 manu if (h->try == h->total_tries) {
564 1.1 manu generr(h, "No valid RADIUS responses received");
565 1.1 manu return -1;
566 1.1 manu }
567 1.1 manu
568 1.1 manu /*
569 1.1 manu * Scan round-robin to the next server that has some
570 1.1 manu * tries left. There is guaranteed to be one, or we
571 1.1 manu * would have exited this loop by now.
572 1.1 manu */
573 1.1 manu while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries)
574 1.1 manu if (++h->srv >= h->num_servers)
575 1.1 manu h->srv = 0;
576 1.1 manu
577 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST)
578 1.1 manu /* Insert the request authenticator into the request */
579 1.1 manu insert_request_authenticator(h, h->srv);
580 1.1 manu else
581 1.1 manu /* Insert the scrambled password into the request */
582 1.1 manu if (h->pass_pos != 0)
583 1.1 manu insert_scrambled_password(h, h->srv);
584 1.1 manu
585 1.1 manu insert_message_authenticator(h, h->srv);
586 1.1 manu
587 1.1 manu /* Send the request */
588 1.1 manu n = sendto(h->fd, h->request, h->req_len, 0,
589 1.1 manu (const struct sockaddr *)&h->servers[h->srv].addr,
590 1.1 manu sizeof h->servers[h->srv].addr);
591 1.1 manu if (n != h->req_len) {
592 1.1 manu if (n == -1)
593 1.1 manu generr(h, "sendto: %s", strerror(errno));
594 1.1 manu else
595 1.1 manu generr(h, "sendto: short write");
596 1.1 manu return -1;
597 1.1 manu }
598 1.1 manu
599 1.1 manu h->try++;
600 1.1 manu h->servers[h->srv].num_tries++;
601 1.1 manu tv->tv_sec = h->servers[h->srv].timeout;
602 1.1 manu tv->tv_usec = 0;
603 1.1 manu *fd = h->fd;
604 1.1 manu
605 1.1 manu return 0;
606 1.1 manu }
607 1.1 manu
608 1.1 manu int
609 1.1 manu rad_create_request(struct rad_handle *h, int code)
610 1.1 manu {
611 1.1 manu int i;
612 1.1 manu
613 1.1 manu h->request[POS_CODE] = code;
614 1.1 manu h->request[POS_IDENT] = ++h->ident;
615 1.1 manu /* Create a random authenticator */
616 1.1 manu for (i = 0; i < LEN_AUTH; i += 2) {
617 1.1 manu long r;
618 1.1 manu r = random();
619 1.1 manu h->request[POS_AUTH+i] = (u_char)r;
620 1.1 manu h->request[POS_AUTH+i+1] = (u_char)(r >> 8);
621 1.1 manu }
622 1.1 manu h->req_len = POS_ATTRS;
623 1.1 manu clear_password(h);
624 1.1 manu h->request_created = 1;
625 1.1 manu return 0;
626 1.1 manu }
627 1.1 manu
628 1.1 manu struct in_addr
629 1.1 manu rad_cvt_addr(const void *data)
630 1.1 manu {
631 1.1 manu struct in_addr value;
632 1.1 manu
633 1.1 manu memcpy(&value.s_addr, data, sizeof value.s_addr);
634 1.1 manu return value;
635 1.1 manu }
636 1.1 manu
637 1.1 manu u_int32_t
638 1.1 manu rad_cvt_int(const void *data)
639 1.1 manu {
640 1.1 manu u_int32_t value;
641 1.1 manu
642 1.1 manu memcpy(&value, data, sizeof value);
643 1.1 manu return ntohl(value);
644 1.1 manu }
645 1.1 manu
646 1.1 manu char *
647 1.1 manu rad_cvt_string(const void *data, size_t len)
648 1.1 manu {
649 1.1 manu char *s;
650 1.1 manu
651 1.1 manu s = malloc(len + 1);
652 1.1 manu if (s != NULL) {
653 1.1 manu memcpy(s, data, len);
654 1.1 manu s[len] = '\0';
655 1.1 manu }
656 1.1 manu return s;
657 1.1 manu }
658 1.1 manu
659 1.1 manu /*
660 1.1 manu * Returns the attribute type. If none are left, returns 0. On failure,
661 1.1 manu * returns -1.
662 1.1 manu */
663 1.1 manu int
664 1.1 manu rad_get_attr(struct rad_handle *h, const void **value, size_t *len)
665 1.1 manu {
666 1.1 manu int type;
667 1.1 manu
668 1.1 manu if (h->resp_pos >= h->resp_len)
669 1.1 manu return 0;
670 1.1 manu if (h->resp_pos + 2 > h->resp_len) {
671 1.1 manu generr(h, "Malformed attribute in response");
672 1.1 manu return -1;
673 1.1 manu }
674 1.1 manu type = h->response[h->resp_pos++];
675 1.1 manu *len = h->response[h->resp_pos++] - 2;
676 1.1 manu if (h->resp_pos + (int)*len > h->resp_len) {
677 1.1 manu generr(h, "Malformed attribute in response");
678 1.1 manu return -1;
679 1.1 manu }
680 1.1 manu *value = &h->response[h->resp_pos];
681 1.1 manu h->resp_pos += *len;
682 1.1 manu return type;
683 1.1 manu }
684 1.1 manu
685 1.1 manu /*
686 1.1 manu * Returns -1 on error, 0 to indicate no event and >0 for success
687 1.1 manu */
688 1.1 manu int
689 1.1 manu rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv)
690 1.1 manu {
691 1.1 manu int srv;
692 1.1 manu
693 1.1 manu /* Make sure we have a socket to use */
694 1.1 manu if (h->fd == -1) {
695 1.1 manu struct sockaddr_in saddr;
696 1.1 manu
697 1.1 manu if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
698 1.1 manu generr(h, "Cannot create socket: %s", strerror(errno));
699 1.1 manu return -1;
700 1.1 manu }
701 1.1 manu memset(&saddr, 0, sizeof saddr);
702 1.1 manu saddr.sin_len = sizeof saddr;
703 1.1 manu saddr.sin_family = AF_INET;
704 1.1 manu saddr.sin_addr.s_addr = INADDR_ANY;
705 1.1 manu saddr.sin_port = htons(0);
706 1.1 manu if (bind(h->fd, (const struct sockaddr *)&saddr,
707 1.1 manu sizeof saddr) == -1) {
708 1.1 manu generr(h, "bind: %s", strerror(errno));
709 1.1 manu close(h->fd);
710 1.1 manu h->fd = -1;
711 1.1 manu return -1;
712 1.1 manu }
713 1.1 manu }
714 1.1 manu
715 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
716 1.1 manu /* Make sure no password given */
717 1.1 manu if (h->pass_pos || h->chap_pass) {
718 1.1 manu generr(h, "User or Chap Password"
719 1.1 manu " in accounting request");
720 1.1 manu return -1;
721 1.1 manu }
722 1.1 manu } else {
723 1.1 manu if (h->eap_msg == 0) {
724 1.1 manu /* Make sure the user gave us a password */
725 1.1 manu if (h->pass_pos == 0 && !h->chap_pass) {
726 1.1 manu generr(h, "No User or Chap Password"
727 1.1 manu " attributes given");
728 1.1 manu return -1;
729 1.1 manu }
730 1.1 manu if (h->pass_pos != 0 && h->chap_pass) {
731 1.1 manu generr(h, "Both User and Chap Password"
732 1.1 manu " attributes given");
733 1.1 manu return -1;
734 1.1 manu }
735 1.1 manu }
736 1.1 manu }
737 1.1 manu
738 1.1 manu /* Fill in the length field in the message */
739 1.1 manu h->request[POS_LENGTH] = h->req_len >> 8;
740 1.1 manu h->request[POS_LENGTH+1] = h->req_len;
741 1.1 manu
742 1.1 manu /*
743 1.1 manu * Count the total number of tries we will make, and zero the
744 1.1 manu * counter for each server.
745 1.1 manu */
746 1.1 manu h->total_tries = 0;
747 1.1 manu for (srv = 0; srv < h->num_servers; srv++) {
748 1.1 manu h->total_tries += h->servers[srv].max_tries;
749 1.1 manu h->servers[srv].num_tries = 0;
750 1.1 manu }
751 1.1 manu if (h->total_tries == 0) {
752 1.1 manu generr(h, "No RADIUS servers specified");
753 1.1 manu return -1;
754 1.1 manu }
755 1.1 manu
756 1.1 manu h->try = h->srv = 0;
757 1.1 manu
758 1.1 manu return rad_continue_send_request(h, 0, fd, tv);
759 1.1 manu }
760 1.1 manu
761 1.1 manu /*
762 1.1 manu * Create and initialize a rad_handle structure, and return it to the
763 1.1 manu * caller. Can fail only if the necessary memory cannot be allocated.
764 1.1 manu * In that case, it returns NULL.
765 1.1 manu */
766 1.1 manu struct rad_handle *
767 1.1 manu rad_auth_open(void)
768 1.1 manu {
769 1.1 manu struct rad_handle *h;
770 1.1 manu
771 1.1 manu h = (struct rad_handle *)malloc(sizeof(struct rad_handle));
772 1.1 manu if (h != NULL) {
773 1.1 manu srandomdev();
774 1.1 manu h->fd = -1;
775 1.1 manu h->num_servers = 0;
776 1.1 manu h->ident = random();
777 1.1 manu h->errmsg[0] = '\0';
778 1.1 manu memset(h->pass, 0, sizeof h->pass);
779 1.1 manu h->pass_len = 0;
780 1.1 manu h->pass_pos = 0;
781 1.1 manu h->chap_pass = 0;
782 1.1 manu h->authentic_pos = 0;
783 1.1 manu h->type = RADIUS_AUTH;
784 1.1 manu h->request_created = 0;
785 1.1 manu h->eap_msg = 0;
786 1.1 manu }
787 1.1 manu return h;
788 1.1 manu }
789 1.1 manu
790 1.1 manu struct rad_handle *
791 1.1 manu rad_acct_open(void)
792 1.1 manu {
793 1.1 manu struct rad_handle *h;
794 1.1 manu
795 1.1 manu h = rad_open();
796 1.1 manu if (h != NULL)
797 1.1 manu h->type = RADIUS_ACCT;
798 1.1 manu return h;
799 1.1 manu }
800 1.1 manu
801 1.1 manu struct rad_handle *
802 1.1 manu rad_open(void)
803 1.1 manu {
804 1.1 manu return rad_auth_open();
805 1.1 manu }
806 1.1 manu
807 1.1 manu int
808 1.1 manu rad_put_addr(struct rad_handle *h, int type, struct in_addr addr)
809 1.1 manu {
810 1.1 manu return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr);
811 1.1 manu }
812 1.1 manu
813 1.1 manu int
814 1.1 manu rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len)
815 1.1 manu {
816 1.1 manu int result;
817 1.1 manu
818 1.1 manu if (!h->request_created) {
819 1.1 manu generr(h, "Please call rad_create_request()"
820 1.1 manu " before putting attributes");
821 1.1 manu return -1;
822 1.1 manu }
823 1.1 manu
824 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
825 1.1 manu if (type == RAD_EAP_MESSAGE) {
826 1.1 manu generr(h, "EAP-Message attribute is not valid"
827 1.1 manu " in accounting requests");
828 1.1 manu return -1;
829 1.1 manu }
830 1.1 manu }
831 1.1 manu
832 1.1 manu /*
833 1.1 manu * When proxying EAP Messages, the Message Authenticator
834 1.1 manu * MUST be present; see RFC 3579.
835 1.1 manu */
836 1.1 manu if (type == RAD_EAP_MESSAGE) {
837 1.1 manu if (rad_put_message_authentic(h) == -1)
838 1.1 manu return -1;
839 1.1 manu }
840 1.1 manu
841 1.1 manu if (type == RAD_USER_PASSWORD) {
842 1.1 manu result = put_password_attr(h, type, value, len);
843 1.1 manu } else if (type == RAD_MESSAGE_AUTHENTIC) {
844 1.1 manu result = rad_put_message_authentic(h);
845 1.1 manu } else {
846 1.1 manu result = put_raw_attr(h, type, value, len);
847 1.1 manu if (result == 0) {
848 1.1 manu if (type == RAD_CHAP_PASSWORD)
849 1.1 manu h->chap_pass = 1;
850 1.1 manu else if (type == RAD_EAP_MESSAGE)
851 1.1 manu h->eap_msg = 1;
852 1.1 manu }
853 1.1 manu }
854 1.1 manu
855 1.1 manu return result;
856 1.1 manu }
857 1.1 manu
858 1.1 manu int
859 1.1 manu rad_put_int(struct rad_handle *h, int type, u_int32_t value)
860 1.1 manu {
861 1.1 manu u_int32_t nvalue;
862 1.1 manu
863 1.1 manu nvalue = htonl(value);
864 1.1 manu return rad_put_attr(h, type, &nvalue, sizeof nvalue);
865 1.1 manu }
866 1.1 manu
867 1.1 manu int
868 1.1 manu rad_put_string(struct rad_handle *h, int type, const char *str)
869 1.1 manu {
870 1.1 manu return rad_put_attr(h, type, str, strlen(str));
871 1.1 manu }
872 1.1 manu
873 1.1 manu int
874 1.1 manu rad_put_message_authentic(struct rad_handle *h)
875 1.1 manu {
876 1.1 manu #ifdef WITH_SSL
877 1.1 manu u_char md_zero[MD5_DIGEST_LENGTH];
878 1.1 manu
879 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) {
880 1.1 manu generr(h, "Message-Authenticator is not valid"
881 1.1 manu " in accounting requests");
882 1.1 manu return -1;
883 1.1 manu }
884 1.1 manu
885 1.1 manu if (h->authentic_pos == 0) {
886 1.1 manu h->authentic_pos = h->req_len;
887 1.1 manu memset(md_zero, 0, sizeof(md_zero));
888 1.1 manu return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero,
889 1.1 manu sizeof(md_zero)));
890 1.1 manu }
891 1.1 manu return 0;
892 1.1 manu #else
893 1.1 manu generr(h, "Message Authenticator not supported,"
894 1.1 manu " please recompile libradius with SSL support");
895 1.1 manu return -1;
896 1.1 manu #endif
897 1.1 manu }
898 1.1 manu
899 1.1 manu /*
900 1.1 manu * Returns the response type code on success, or -1 on failure.
901 1.1 manu */
902 1.1 manu int
903 1.1 manu rad_send_request(struct rad_handle *h)
904 1.1 manu {
905 1.1 manu struct timeval timelimit;
906 1.1 manu struct timeval tv;
907 1.1 manu int fd;
908 1.1 manu int n;
909 1.1 manu
910 1.1 manu n = rad_init_send_request(h, &fd, &tv);
911 1.1 manu
912 1.1 manu if (n != 0)
913 1.1 manu return n;
914 1.1 manu
915 1.1 manu gettimeofday(&timelimit, NULL);
916 1.1 manu timeradd(&tv, &timelimit, &timelimit);
917 1.1 manu
918 1.1 manu for ( ; ; ) {
919 1.1 manu fd_set readfds;
920 1.1 manu
921 1.1 manu FD_ZERO(&readfds);
922 1.1 manu FD_SET(fd, &readfds);
923 1.1 manu
924 1.1 manu n = select(fd + 1, &readfds, NULL, NULL, &tv);
925 1.1 manu
926 1.1 manu if (n == -1) {
927 1.1 manu generr(h, "select: %s", strerror(errno));
928 1.1 manu return -1;
929 1.1 manu }
930 1.1 manu
931 1.1 manu if (!FD_ISSET(fd, &readfds)) {
932 1.1 manu /* Compute a new timeout */
933 1.1 manu gettimeofday(&tv, NULL);
934 1.1 manu timersub(&timelimit, &tv, &tv);
935 1.1 manu if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0))
936 1.1 manu /* Continue the select */
937 1.1 manu continue;
938 1.1 manu }
939 1.1 manu
940 1.1 manu n = rad_continue_send_request(h, n, &fd, &tv);
941 1.1 manu
942 1.1 manu if (n != 0)
943 1.1 manu return n;
944 1.1 manu
945 1.1 manu gettimeofday(&timelimit, NULL);
946 1.1 manu timeradd(&tv, &timelimit, &timelimit);
947 1.1 manu }
948 1.1 manu }
949 1.1 manu
950 1.1 manu const char *
951 1.1 manu rad_strerror(struct rad_handle *h)
952 1.1 manu {
953 1.1 manu return h->errmsg;
954 1.1 manu }
955 1.1 manu
956 1.1 manu /*
957 1.1 manu * Destructively split a string into fields separated by white space.
958 1.1 manu * `#' at the beginning of a field begins a comment that extends to the
959 1.1 manu * end of the string. Fields may be quoted with `"'. Inside quoted
960 1.1 manu * strings, the backslash escapes `\"' and `\\' are honored.
961 1.1 manu *
962 1.1 manu * Pointers to up to the first maxfields fields are stored in the fields
963 1.1 manu * array. Missing fields get NULL pointers.
964 1.1 manu *
965 1.1 manu * The return value is the actual number of fields parsed, and is always
966 1.1 manu * <= maxfields.
967 1.1 manu *
968 1.1 manu * On a syntax error, places a message in the msg string, and returns -1.
969 1.1 manu */
970 1.1 manu static int
971 1.1 manu split(char *str, char *fields[], int maxfields, char *msg, size_t msglen)
972 1.1 manu {
973 1.1 manu char *p;
974 1.1 manu int i;
975 1.1 manu static const char ws[] = " \t";
976 1.1 manu
977 1.1 manu for (i = 0; i < maxfields; i++)
978 1.1 manu fields[i] = NULL;
979 1.1 manu p = str;
980 1.1 manu i = 0;
981 1.1 manu while (*p != '\0') {
982 1.1 manu p += strspn(p, ws);
983 1.1 manu if (*p == '#' || *p == '\0')
984 1.1 manu break;
985 1.1 manu if (i >= maxfields) {
986 1.1 manu snprintf(msg, msglen, "line has too many fields");
987 1.1 manu return -1;
988 1.1 manu }
989 1.1 manu if (*p == '"') {
990 1.1 manu char *dst;
991 1.1 manu
992 1.1 manu dst = ++p;
993 1.1 manu fields[i] = dst;
994 1.1 manu while (*p != '"') {
995 1.1 manu if (*p == '\\') {
996 1.1 manu p++;
997 1.1 manu if (*p != '"' && *p != '\\' &&
998 1.1 manu *p != '\0') {
999 1.1 manu snprintf(msg, msglen,
1000 1.1 manu "invalid `\\' escape");
1001 1.1 manu return -1;
1002 1.1 manu }
1003 1.1 manu }
1004 1.1 manu if (*p == '\0') {
1005 1.1 manu snprintf(msg, msglen,
1006 1.1 manu "unterminated quoted string");
1007 1.1 manu return -1;
1008 1.1 manu }
1009 1.1 manu *dst++ = *p++;
1010 1.1 manu }
1011 1.1 manu *dst = '\0';
1012 1.1 manu p++;
1013 1.1 manu if (*fields[i] == '\0') {
1014 1.1 manu snprintf(msg, msglen,
1015 1.1 manu "empty quoted string not permitted");
1016 1.1 manu return -1;
1017 1.1 manu }
1018 1.1 manu if (*p != '\0' && strspn(p, ws) == 0) {
1019 1.1 manu snprintf(msg, msglen, "quoted string not"
1020 1.1 manu " followed by white space");
1021 1.1 manu return -1;
1022 1.1 manu }
1023 1.1 manu } else {
1024 1.1 manu fields[i] = p;
1025 1.1 manu p += strcspn(p, ws);
1026 1.1 manu if (*p != '\0')
1027 1.1 manu *p++ = '\0';
1028 1.1 manu }
1029 1.1 manu i++;
1030 1.1 manu }
1031 1.1 manu return i;
1032 1.1 manu }
1033 1.1 manu
1034 1.1 manu int
1035 1.1 manu rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len)
1036 1.1 manu {
1037 1.1 manu struct vendor_attribute *attr;
1038 1.1 manu
1039 1.1 manu attr = (struct vendor_attribute *)*data;
1040 1.1 manu *vendor = ntohl(attr->vendor_value);
1041 1.1 manu *data = attr->attrib_data;
1042 1.1 manu *len = attr->attrib_len - 2;
1043 1.1 manu
1044 1.1 manu return (attr->attrib_type);
1045 1.1 manu }
1046 1.1 manu
1047 1.1 manu int
1048 1.1 manu rad_put_vendor_addr(struct rad_handle *h, int vendor, int type,
1049 1.1 manu struct in_addr addr)
1050 1.1 manu {
1051 1.1 manu return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr,
1052 1.1 manu sizeof addr.s_addr));
1053 1.1 manu }
1054 1.1 manu
1055 1.1 manu int
1056 1.1 manu rad_put_vendor_attr(struct rad_handle *h, int vendor, int type,
1057 1.1 manu const void *value, size_t len)
1058 1.1 manu {
1059 1.1 manu struct vendor_attribute *attr;
1060 1.1 manu int res;
1061 1.1 manu
1062 1.1 manu if (!h->request_created) {
1063 1.1 manu generr(h, "Please call rad_create_request()"
1064 1.1 manu " before putting attributes");
1065 1.1 manu return -1;
1066 1.1 manu }
1067 1.1 manu
1068 1.1 manu if ((attr = malloc(len + 6)) == NULL) {
1069 1.1 manu generr(h, "malloc failure (%zu bytes)", len + 6);
1070 1.1 manu return -1;
1071 1.1 manu }
1072 1.1 manu
1073 1.1 manu attr->vendor_value = htonl(vendor);
1074 1.1 manu attr->attrib_type = type;
1075 1.1 manu attr->attrib_len = len + 2;
1076 1.1 manu memcpy(attr->attrib_data, value, len);
1077 1.1 manu
1078 1.1 manu res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6);
1079 1.1 manu free(attr);
1080 1.1 manu if (res == 0 && vendor == RAD_VENDOR_MICROSOFT
1081 1.1 manu && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE
1082 1.1 manu || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) {
1083 1.1 manu h->chap_pass = 1;
1084 1.1 manu }
1085 1.1 manu return (res);
1086 1.1 manu }
1087 1.1 manu
1088 1.1 manu int
1089 1.1 manu rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i)
1090 1.1 manu {
1091 1.1 manu u_int32_t value;
1092 1.1 manu
1093 1.1 manu value = htonl(i);
1094 1.1 manu return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value));
1095 1.1 manu }
1096 1.1 manu
1097 1.1 manu int
1098 1.1 manu rad_put_vendor_string(struct rad_handle *h, int vendor, int type,
1099 1.1 manu const char *str)
1100 1.1 manu {
1101 1.1 manu return (rad_put_vendor_attr(h, vendor, type, str, strlen(str)));
1102 1.1 manu }
1103 1.1 manu
1104 1.1 manu ssize_t
1105 1.1 manu rad_request_authenticator(struct rad_handle *h, char *buf, size_t len)
1106 1.1 manu {
1107 1.1 manu if (len < LEN_AUTH)
1108 1.1 manu return (-1);
1109 1.1 manu memcpy(buf, h->request + POS_AUTH, LEN_AUTH);
1110 1.1 manu if (len > LEN_AUTH)
1111 1.1 manu buf[LEN_AUTH] = '\0';
1112 1.1 manu return (LEN_AUTH);
1113 1.1 manu }
1114 1.1 manu
1115 1.1 manu u_char *
1116 1.1 manu rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen)
1117 1.1 manu {
1118 1.1 manu char R[LEN_AUTH];
1119 1.1 manu const char *S;
1120 1.1 manu int i, Ppos;
1121 1.1 manu MD5_CTX Context;
1122 1.1 manu u_char b[MD5_DIGEST_LENGTH], *C, *demangled;
1123 1.1 manu
1124 1.1 manu if ((mlen % 16 != 0) || mlen > 128) {
1125 1.1 manu generr(h, "Cannot interpret mangled data of length %lu",
1126 1.1 manu (u_long)mlen);
1127 1.1 manu return NULL;
1128 1.1 manu }
1129 1.1 manu
1130 1.1 manu C = (u_char *)mangled;
1131 1.1 manu
1132 1.1 manu /* We need the shared secret as Salt */
1133 1.1 manu S = rad_server_secret(h);
1134 1.1 manu
1135 1.1 manu /* We need the request authenticator */
1136 1.1 manu if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1137 1.1 manu generr(h, "Cannot obtain the RADIUS request authenticator");
1138 1.1 manu return NULL;
1139 1.1 manu }
1140 1.1 manu
1141 1.1 manu demangled = malloc(mlen);
1142 1.1 manu if (!demangled)
1143 1.1 manu return NULL;
1144 1.1 manu
1145 1.1 manu MD5Init(&Context);
1146 1.1 manu MD5Update(&Context, S, strlen(S));
1147 1.1 manu MD5Update(&Context, R, LEN_AUTH);
1148 1.1 manu MD5Final(b, &Context);
1149 1.1 manu Ppos = 0;
1150 1.1 manu while (mlen) {
1151 1.1 manu
1152 1.1 manu mlen -= 16;
1153 1.1 manu for (i = 0; i < 16; i++)
1154 1.1 manu demangled[Ppos++] = C[i] ^ b[i];
1155 1.1 manu
1156 1.1 manu if (mlen) {
1157 1.1 manu MD5Init(&Context);
1158 1.1 manu MD5Update(&Context, S, strlen(S));
1159 1.1 manu MD5Update(&Context, C, 16);
1160 1.1 manu MD5Final(b, &Context);
1161 1.1 manu }
1162 1.1 manu
1163 1.1 manu C += 16;
1164 1.1 manu }
1165 1.1 manu
1166 1.1 manu return demangled;
1167 1.1 manu }
1168 1.1 manu
1169 1.1 manu u_char *
1170 1.1 manu rad_demangle_mppe_key(struct rad_handle *h, const void *mangled,
1171 1.1 manu size_t mlen, size_t *len)
1172 1.1 manu {
1173 1.1 manu char R[LEN_AUTH]; /* variable names as per rfc2548 */
1174 1.1 manu const char *S;
1175 1.1 manu u_char b[MD5_DIGEST_LENGTH], *demangled;
1176 1.1 manu const u_char *A, *C;
1177 1.1 manu MD5_CTX Context;
1178 1.1 manu int Slen, i, Clen, Ppos;
1179 1.1 manu u_char *P;
1180 1.1 manu
1181 1.1 manu if (mlen % 16 != SALT_LEN) {
1182 1.1 manu generr(h, "Cannot interpret mangled data of length %lu",
1183 1.1 manu (u_long)mlen);
1184 1.1 manu return NULL;
1185 1.1 manu }
1186 1.1 manu
1187 1.1 manu /* We need the RADIUS Request-Authenticator */
1188 1.1 manu if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) {
1189 1.1 manu generr(h, "Cannot obtain the RADIUS request authenticator");
1190 1.1 manu return NULL;
1191 1.1 manu }
1192 1.1 manu
1193 1.1 manu A = (const u_char *)mangled; /* Salt comes first */
1194 1.1 manu C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */
1195 1.1 manu Clen = mlen - SALT_LEN;
1196 1.1 manu S = rad_server_secret(h); /* We need the RADIUS secret */
1197 1.1 manu Slen = strlen(S);
1198 1.1 manu P = alloca(Clen); /* We derive our plaintext */
1199 1.1 manu
1200 1.1 manu MD5Init(&Context);
1201 1.1 manu MD5Update(&Context, S, Slen);
1202 1.1 manu MD5Update(&Context, R, LEN_AUTH);
1203 1.1 manu MD5Update(&Context, A, SALT_LEN);
1204 1.1 manu MD5Final(b, &Context);
1205 1.1 manu Ppos = 0;
1206 1.1 manu
1207 1.1 manu while (Clen) {
1208 1.1 manu Clen -= 16;
1209 1.1 manu
1210 1.1 manu for (i = 0; i < 16; i++)
1211 1.1 manu P[Ppos++] = C[i] ^ b[i];
1212 1.1 manu
1213 1.1 manu if (Clen) {
1214 1.1 manu MD5Init(&Context);
1215 1.1 manu MD5Update(&Context, S, Slen);
1216 1.1 manu MD5Update(&Context, C, 16);
1217 1.1 manu MD5Final(b, &Context);
1218 1.1 manu }
1219 1.1 manu
1220 1.1 manu C += 16;
1221 1.1 manu }
1222 1.1 manu
1223 1.1 manu /*
1224 1.1 manu * The resulting plain text consists of a one-byte length, the text and
1225 1.1 manu * maybe some padding.
1226 1.1 manu */
1227 1.1 manu *len = *P;
1228 1.1 manu if (*len > mlen - 1) {
1229 1.1 manu generr(h, "Mangled data seems to be garbage %zu %zu",
1230 1.1 manu *len, mlen-1);
1231 1.1 manu return NULL;
1232 1.1 manu }
1233 1.1 manu
1234 1.1 manu if (*len > MPPE_KEY_LEN * 2) {
1235 1.1 manu generr(h, "Key to long (%zu) for me max. %d",
1236 1.1 manu *len, MPPE_KEY_LEN * 2);
1237 1.1 manu return NULL;
1238 1.1 manu }
1239 1.1 manu demangled = malloc(*len);
1240 1.1 manu if (!demangled)
1241 1.1 manu return NULL;
1242 1.1 manu
1243 1.1 manu memcpy(demangled, P + 1, *len);
1244 1.1 manu return demangled;
1245 1.1 manu }
1246 1.1 manu
1247 1.1 manu const char *
1248 1.1 manu rad_server_secret(struct rad_handle *h)
1249 1.1 manu {
1250 1.1 manu return (h->servers[h->srv].secret);
1251 1.1 manu }
1252