Branch data Line data Source code
1 : : /*
2 : : * RADIUS message processing
3 : : * Copyright (c) 2002-2009, 2011-2014, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "utils/includes.h"
10 : :
11 : : #include "utils/common.h"
12 : : #include "utils/wpabuf.h"
13 : : #include "crypto/md5.h"
14 : : #include "crypto/crypto.h"
15 : : #include "radius.h"
16 : :
17 : :
18 : : /**
19 : : * struct radius_msg - RADIUS message structure for new and parsed messages
20 : : */
21 : : struct radius_msg {
22 : : /**
23 : : * buf - Allocated buffer for RADIUS message
24 : : */
25 : : struct wpabuf *buf;
26 : :
27 : : /**
28 : : * hdr - Pointer to the RADIUS header in buf
29 : : */
30 : : struct radius_hdr *hdr;
31 : :
32 : : /**
33 : : * attr_pos - Array of indexes to attributes
34 : : *
35 : : * The values are number of bytes from buf to the beginning of
36 : : * struct radius_attr_hdr.
37 : : */
38 : : size_t *attr_pos;
39 : :
40 : : /**
41 : : * attr_size - Total size of the attribute pointer array
42 : : */
43 : : size_t attr_size;
44 : :
45 : : /**
46 : : * attr_used - Total number of attributes in the array
47 : : */
48 : : size_t attr_used;
49 : : };
50 : :
51 : :
52 : 10219 : struct radius_hdr * radius_msg_get_hdr(struct radius_msg *msg)
53 : : {
54 : 10219 : return msg->hdr;
55 : : }
56 : :
57 : :
58 : 2134 : struct wpabuf * radius_msg_get_buf(struct radius_msg *msg)
59 : : {
60 : 2134 : return msg->buf;
61 : : }
62 : :
63 : :
64 : : static struct radius_attr_hdr *
65 : 108892 : radius_get_attr_hdr(struct radius_msg *msg, int idx)
66 : : {
67 : 108892 : return (struct radius_attr_hdr *)
68 : 108892 : (wpabuf_mhead_u8(msg->buf) + msg->attr_pos[idx]);
69 : : }
70 : :
71 : :
72 : 2131 : static void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
73 : : {
74 : 2131 : msg->hdr->code = code;
75 : 2131 : msg->hdr->identifier = identifier;
76 : 2131 : }
77 : :
78 : :
79 : 4258 : static int radius_msg_initialize(struct radius_msg *msg)
80 : : {
81 : 4258 : msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
82 : : sizeof(*msg->attr_pos));
83 [ - + ]: 4258 : if (msg->attr_pos == NULL)
84 : 0 : return -1;
85 : :
86 : 4258 : msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
87 : 4258 : msg->attr_used = 0;
88 : :
89 : 4258 : return 0;
90 : : }
91 : :
92 : :
93 : : /**
94 : : * radius_msg_new - Create a new RADIUS message
95 : : * @code: Code for RADIUS header
96 : : * @identifier: Identifier for RADIUS header
97 : : * Returns: Context for RADIUS message or %NULL on failure
98 : : *
99 : : * The caller is responsible for freeing the returned data with
100 : : * radius_msg_free().
101 : : */
102 : 2131 : struct radius_msg * radius_msg_new(u8 code, u8 identifier)
103 : : {
104 : : struct radius_msg *msg;
105 : :
106 : 2131 : msg = os_zalloc(sizeof(*msg));
107 [ - + ]: 2131 : if (msg == NULL)
108 : 0 : return NULL;
109 : :
110 : 2131 : msg->buf = wpabuf_alloc(RADIUS_DEFAULT_MSG_SIZE);
111 [ - + ][ + - ]: 2131 : if (msg->buf == NULL || radius_msg_initialize(msg)) {
112 : 0 : radius_msg_free(msg);
113 : 0 : return NULL;
114 : : }
115 : 2131 : msg->hdr = wpabuf_put(msg->buf, sizeof(struct radius_hdr));
116 : :
117 : 2131 : radius_msg_set_hdr(msg, code, identifier);
118 : :
119 : 2131 : return msg;
120 : : }
121 : :
122 : :
123 : : /**
124 : : * radius_msg_free - Free a RADIUS message
125 : : * @msg: RADIUS message from radius_msg_new() or radius_msg_parse()
126 : : */
127 : 4905 : void radius_msg_free(struct radius_msg *msg)
128 : : {
129 [ + + ]: 4905 : if (msg == NULL)
130 : 4905 : return;
131 : :
132 : 4258 : wpabuf_free(msg->buf);
133 : 4258 : os_free(msg->attr_pos);
134 : 4258 : os_free(msg);
135 : : }
136 : :
137 : :
138 : 2141 : static const char *radius_code_string(u8 code)
139 : : {
140 [ + + + + : 2141 : switch (code) {
+ + - - -
+ + + + -
+ - ]
141 : 1049 : case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
142 : 170 : case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
143 : 21 : case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
144 : 8 : case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
145 : 8 : case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
146 : 858 : case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
147 : 0 : case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
148 : 0 : case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
149 : 0 : case RADIUS_CODE_RESERVED: return "Reserved";
150 : 14 : case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
151 : 4 : case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
152 : 7 : case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
153 : 1 : case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
154 : 0 : case RADIUS_CODE_COA_ACK: return "CoA-ACK";
155 : 1 : case RADIUS_CODE_COA_NAK: return "CoA-NAK";
156 : 2141 : default: return "?Unknown?";
157 : : }
158 : : }
159 : :
160 : :
161 : : struct radius_attr_type {
162 : : u8 type;
163 : : char *name;
164 : : enum {
165 : : RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
166 : : RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
167 : : } data_type;
168 : : };
169 : :
170 : : static struct radius_attr_type radius_attrs[] =
171 : : {
172 : : { RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
173 : : { RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
174 : : { RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
175 : : { RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
176 : : { RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
177 : : { RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
178 : : { RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
179 : : { RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
180 : : { RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
181 : : { RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
182 : : { RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
183 : : { RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
184 : : RADIUS_ATTR_INT32 },
185 : : { RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
186 : : RADIUS_ATTR_TEXT },
187 : : { RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
188 : : RADIUS_ATTR_TEXT },
189 : : { RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
190 : : { RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
191 : : { RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
192 : : RADIUS_ATTR_INT32 },
193 : : { RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
194 : : { RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
195 : : RADIUS_ATTR_INT32 },
196 : : { RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
197 : : RADIUS_ATTR_INT32 },
198 : : { RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
199 : : { RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
200 : : { RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
201 : : RADIUS_ATTR_INT32 },
202 : : { RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
203 : : RADIUS_ATTR_INT32 },
204 : : { RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
205 : : RADIUS_ATTR_INT32 },
206 : : { RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
207 : : RADIUS_ATTR_INT32 },
208 : : { RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
209 : : RADIUS_ATTR_TEXT },
210 : : { RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
211 : : { RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords",
212 : : RADIUS_ATTR_INT32 },
213 : : { RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
214 : : RADIUS_ATTR_INT32 },
215 : : { RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
216 : : RADIUS_ATTR_INT32 },
217 : : { RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
218 : : { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
219 : : { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
220 : : RADIUS_ATTR_HEXDUMP },
221 : : { RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
222 : : RADIUS_ATTR_UNDIST },
223 : : { RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
224 : : { RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
225 : : { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
226 : : RADIUS_ATTR_UNDIST },
227 : : { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
228 : : RADIUS_ATTR_HEXDUMP },
229 : : { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
230 : : RADIUS_ATTR_INT32 },
231 : : { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
232 : : RADIUS_ATTR_TEXT },
233 : : { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
234 : : { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
235 : : };
236 : : #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
237 : :
238 : :
239 : 17106 : static struct radius_attr_type *radius_get_attr_type(u8 type)
240 : : {
241 : : size_t i;
242 : :
243 [ + - ]: 355324 : for (i = 0; i < RADIUS_ATTRS; i++) {
244 [ + + ]: 355324 : if (type == radius_attrs[i].type)
245 : 17106 : return &radius_attrs[i];
246 : : }
247 : :
248 : 17106 : return NULL;
249 : : }
250 : :
251 : :
252 : 17106 : static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
253 : : {
254 : : struct radius_attr_type *attr;
255 : : int len;
256 : : unsigned char *pos;
257 : : char buf[1000];
258 : :
259 : 17106 : attr = radius_get_attr_type(hdr->type);
260 : :
261 [ + - ]: 17106 : wpa_printf(MSG_INFO, " Attribute %d (%s) length=%d",
262 : 34212 : hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
263 : :
264 [ - + ][ + - ]: 17106 : if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
265 : 17106 : return;
266 : :
267 : 17106 : len = hdr->length - sizeof(struct radius_attr_hdr);
268 : 17106 : pos = (unsigned char *) (hdr + 1);
269 : :
270 [ + + + + : 17106 : switch (attr->data_type) {
+ - ]
271 : : case RADIUS_ATTR_TEXT:
272 : 5900 : printf_encode(buf, sizeof(buf), pos, len);
273 : 5900 : wpa_printf(MSG_INFO, " Value: '%s'", buf);
274 : 5900 : break;
275 : :
276 : : case RADIUS_ATTR_IP:
277 [ + - ]: 18 : if (len == 4) {
278 : : struct in_addr addr;
279 : 18 : os_memcpy(&addr, pos, 4);
280 : 18 : wpa_printf(MSG_INFO, " Value: %s",
281 : : inet_ntoa(addr));
282 : : } else {
283 : 0 : wpa_printf(MSG_INFO, " Invalid IP address length %d",
284 : : len);
285 : : }
286 : 18 : break;
287 : :
288 : : #ifdef CONFIG_IPV6
289 : : case RADIUS_ATTR_IPV6:
290 [ + - ]: 7 : if (len == 16) {
291 : : const char *atxt;
292 : 7 : struct in6_addr *addr = (struct in6_addr *) pos;
293 : 7 : atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
294 [ + - ]: 7 : wpa_printf(MSG_INFO, " Value: %s",
295 : : atxt ? atxt : "?");
296 : : } else {
297 : 0 : wpa_printf(MSG_INFO, " Invalid IPv6 address length %d",
298 : : len);
299 : : }
300 : 7 : break;
301 : : #endif /* CONFIG_IPV6 */
302 : :
303 : : case RADIUS_ATTR_HEXDUMP:
304 : : case RADIUS_ATTR_UNDIST:
305 : 7954 : wpa_snprintf_hex(buf, sizeof(buf), pos, len);
306 : 7954 : wpa_printf(MSG_INFO, " Value: %s", buf);
307 : 7954 : break;
308 : :
309 : : case RADIUS_ATTR_INT32:
310 [ + - ]: 3227 : if (len == 4)
311 : 3227 : wpa_printf(MSG_INFO, " Value: %u",
312 : : WPA_GET_BE32(pos));
313 : : else
314 : 0 : wpa_printf(MSG_INFO, " Invalid INT32 length %d",
315 : : len);
316 : 3227 : break;
317 : :
318 : : default:
319 : 0 : break;
320 : : }
321 : : }
322 : :
323 : :
324 : 2141 : void radius_msg_dump(struct radius_msg *msg)
325 : : {
326 : : size_t i;
327 : :
328 : 2141 : wpa_printf(MSG_INFO, "RADIUS message: code=%d (%s) identifier=%d length=%d",
329 : 4282 : msg->hdr->code, radius_code_string(msg->hdr->code),
330 : 4282 : msg->hdr->identifier, be_to_host16(msg->hdr->length));
331 : :
332 [ + + ]: 19247 : for (i = 0; i < msg->attr_used; i++) {
333 : 17106 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
334 : 17106 : radius_msg_dump_attr(attr);
335 : : }
336 : 2141 : }
337 : :
338 : :
339 : 1050 : int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
340 : : size_t secret_len)
341 : : {
342 [ + - ]: 1050 : if (secret) {
343 : : u8 auth[MD5_MAC_LEN];
344 : : struct radius_attr_hdr *attr;
345 : :
346 : 1050 : os_memset(auth, 0, MD5_MAC_LEN);
347 : 1050 : attr = radius_msg_add_attr(msg,
348 : : RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
349 : : auth, MD5_MAC_LEN);
350 [ - + ]: 1050 : if (attr == NULL) {
351 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Could not add "
352 : : "Message-Authenticator");
353 : 0 : return -1;
354 : : }
355 : 1050 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
356 : 1050 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
357 : 1050 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
358 : : } else
359 : 0 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
360 : :
361 [ - + ]: 1050 : if (wpabuf_len(msg->buf) > 0xffff) {
362 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
363 : 0 : (unsigned long) wpabuf_len(msg->buf));
364 : 0 : return -1;
365 : : }
366 : 1050 : return 0;
367 : : }
368 : :
369 : :
370 : 1049 : int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
371 : : size_t secret_len, const u8 *req_authenticator)
372 : : {
373 : : u8 auth[MD5_MAC_LEN];
374 : : struct radius_attr_hdr *attr;
375 : : const u8 *addr[4];
376 : : size_t len[4];
377 : :
378 : 1049 : os_memset(auth, 0, MD5_MAC_LEN);
379 : 1049 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
380 : : auth, MD5_MAC_LEN);
381 [ - + ]: 1049 : if (attr == NULL) {
382 : 0 : wpa_printf(MSG_ERROR, "WARNING: Could not add Message-Authenticator");
383 : 0 : return -1;
384 : : }
385 : 1049 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
386 : 1049 : os_memcpy(msg->hdr->authenticator, req_authenticator,
387 : : sizeof(msg->hdr->authenticator));
388 : 1049 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
389 : 1049 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
390 : :
391 : : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
392 : 1049 : addr[0] = (u8 *) msg->hdr;
393 : 1049 : len[0] = 1 + 1 + 2;
394 : 1049 : addr[1] = req_authenticator;
395 : 1049 : len[1] = MD5_MAC_LEN;
396 : 1049 : addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
397 : 1049 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
398 : 1049 : addr[3] = secret;
399 : 1049 : len[3] = secret_len;
400 : 1049 : md5_vector(4, addr, len, msg->hdr->authenticator);
401 : :
402 [ - + ]: 1049 : if (wpabuf_len(msg->buf) > 0xffff) {
403 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
404 : 0 : (unsigned long) wpabuf_len(msg->buf));
405 : 0 : return -1;
406 : : }
407 : 1049 : return 0;
408 : : }
409 : :
410 : :
411 : 12 : int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
412 : : size_t secret_len,
413 : : const struct radius_hdr *req_hdr)
414 : : {
415 : : const u8 *addr[2];
416 : : size_t len[2];
417 : : u8 auth[MD5_MAC_LEN];
418 : : struct radius_attr_hdr *attr;
419 : :
420 : 12 : os_memset(auth, 0, MD5_MAC_LEN);
421 : 12 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
422 : : auth, MD5_MAC_LEN);
423 [ - + ]: 12 : if (attr == NULL) {
424 : 0 : wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
425 : 0 : return -1;
426 : : }
427 : :
428 : 12 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
429 : 12 : os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
430 : 12 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
431 : 12 : wpabuf_len(msg->buf), (u8 *) (attr + 1));
432 : :
433 : : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
434 : 12 : addr[0] = wpabuf_head_u8(msg->buf);
435 : 12 : len[0] = wpabuf_len(msg->buf);
436 : 12 : addr[1] = secret;
437 : 12 : len[1] = secret_len;
438 [ - + ]: 12 : if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
439 : 0 : return -1;
440 : :
441 [ - + ]: 12 : if (wpabuf_len(msg->buf) > 0xffff) {
442 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
443 : 0 : (unsigned long) wpabuf_len(msg->buf));
444 : 0 : return -1;
445 : : }
446 : 12 : return 0;
447 : : }
448 : :
449 : :
450 : 12 : void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
451 : : size_t secret_len)
452 : : {
453 : : const u8 *addr[2];
454 : : size_t len[2];
455 : :
456 : 12 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
457 : 12 : os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
458 : 12 : addr[0] = wpabuf_head(msg->buf);
459 : 12 : len[0] = wpabuf_len(msg->buf);
460 : 12 : addr[1] = secret;
461 : 12 : len[1] = secret_len;
462 : 12 : md5_vector(2, addr, len, msg->hdr->authenticator);
463 : :
464 [ - + ]: 12 : if (wpabuf_len(msg->buf) > 0xffff) {
465 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
466 : 0 : (unsigned long) wpabuf_len(msg->buf));
467 : : }
468 : 12 : }
469 : :
470 : :
471 : 8 : void radius_msg_finish_acct_resp(struct radius_msg *msg, const u8 *secret,
472 : : size_t secret_len, const u8 *req_authenticator)
473 : : {
474 : : const u8 *addr[2];
475 : : size_t len[2];
476 : :
477 : 8 : msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
478 : 8 : os_memcpy(msg->hdr->authenticator, req_authenticator, MD5_MAC_LEN);
479 : 8 : addr[0] = wpabuf_head(msg->buf);
480 : 8 : len[0] = wpabuf_len(msg->buf);
481 : 8 : addr[1] = secret;
482 : 8 : len[1] = secret_len;
483 : 8 : md5_vector(2, addr, len, msg->hdr->authenticator);
484 : :
485 [ - + ]: 8 : if (wpabuf_len(msg->buf) > 0xffff) {
486 : 0 : wpa_printf(MSG_WARNING, "RADIUS: Too long messages (%lu)",
487 : 0 : (unsigned long) wpabuf_len(msg->buf));
488 : : }
489 : 8 : }
490 : :
491 : :
492 : 8 : int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
493 : : size_t secret_len)
494 : : {
495 : : const u8 *addr[4];
496 : : size_t len[4];
497 : : u8 zero[MD5_MAC_LEN];
498 : : u8 hash[MD5_MAC_LEN];
499 : :
500 : 8 : os_memset(zero, 0, sizeof(zero));
501 : 8 : addr[0] = (u8 *) msg->hdr;
502 : 8 : len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
503 : 8 : addr[1] = zero;
504 : 8 : len[1] = MD5_MAC_LEN;
505 : 8 : addr[2] = (u8 *) (msg->hdr + 1);
506 : 8 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
507 : 8 : addr[3] = secret;
508 : 8 : len[3] = secret_len;
509 : 8 : md5_vector(4, addr, len, hash);
510 : 8 : return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
511 : : }
512 : :
513 : :
514 : 15 : int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
515 : : size_t secret_len)
516 : : {
517 : : const u8 *addr[4];
518 : : size_t len[4];
519 : : u8 zero[MD5_MAC_LEN];
520 : : u8 hash[MD5_MAC_LEN];
521 : : u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
522 : : u8 orig_authenticator[16];
523 : :
524 : 15 : struct radius_attr_hdr *attr = NULL, *tmp;
525 : : size_t i;
526 : :
527 : 15 : os_memset(zero, 0, sizeof(zero));
528 : 15 : addr[0] = (u8 *) msg->hdr;
529 : 15 : len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
530 : 15 : addr[1] = zero;
531 : 15 : len[1] = MD5_MAC_LEN;
532 : 15 : addr[2] = (u8 *) (msg->hdr + 1);
533 : 15 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
534 : 15 : addr[3] = secret;
535 : 15 : len[3] = secret_len;
536 : 15 : md5_vector(4, addr, len, hash);
537 [ + + ]: 15 : if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
538 : 1 : return 1;
539 : :
540 [ + + ]: 50 : for (i = 0; i < msg->attr_used; i++) {
541 : 36 : tmp = radius_get_attr_hdr(msg, i);
542 [ - + ]: 36 : if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
543 [ # # ]: 0 : if (attr != NULL) {
544 : 0 : wpa_printf(MSG_WARNING, "Multiple "
545 : : "Message-Authenticator attributes "
546 : : "in RADIUS message");
547 : 0 : return 1;
548 : : }
549 : 0 : attr = tmp;
550 : : }
551 : : }
552 : :
553 [ + - ]: 14 : if (attr == NULL) {
554 : : /* Message-Authenticator is MAY; not required */
555 : 14 : return 0;
556 : : }
557 : :
558 : 0 : os_memcpy(orig, attr + 1, MD5_MAC_LEN);
559 : 0 : os_memset(attr + 1, 0, MD5_MAC_LEN);
560 : 0 : os_memcpy(orig_authenticator, msg->hdr->authenticator,
561 : : sizeof(orig_authenticator));
562 : 0 : os_memset(msg->hdr->authenticator, 0,
563 : : sizeof(msg->hdr->authenticator));
564 : 0 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
565 : 0 : wpabuf_len(msg->buf), auth);
566 : 0 : os_memcpy(attr + 1, orig, MD5_MAC_LEN);
567 : 0 : os_memcpy(msg->hdr->authenticator, orig_authenticator,
568 : : sizeof(orig_authenticator));
569 : :
570 : 15 : return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
571 : : }
572 : :
573 : :
574 : 34193 : static int radius_msg_add_attr_to_array(struct radius_msg *msg,
575 : : struct radius_attr_hdr *attr)
576 : : {
577 [ + + ]: 34193 : if (msg->attr_used >= msg->attr_size) {
578 : : size_t *nattr_pos;
579 : 21 : int nlen = msg->attr_size * 2;
580 : :
581 : 21 : nattr_pos = os_realloc_array(msg->attr_pos, nlen,
582 : : sizeof(*msg->attr_pos));
583 [ - + ]: 21 : if (nattr_pos == NULL)
584 : 0 : return -1;
585 : :
586 : 21 : msg->attr_pos = nattr_pos;
587 : 21 : msg->attr_size = nlen;
588 : : }
589 : :
590 : 68386 : msg->attr_pos[msg->attr_used++] =
591 : 34193 : (unsigned char *) attr - wpabuf_head_u8(msg->buf);
592 : :
593 : 34193 : return 0;
594 : : }
595 : :
596 : :
597 : 17119 : struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
598 : : const u8 *data, size_t data_len)
599 : : {
600 : : size_t buf_needed;
601 : : struct radius_attr_hdr *attr;
602 : :
603 [ - + ]: 17119 : if (data_len > RADIUS_MAX_ATTR_LEN) {
604 : 0 : wpa_printf(MSG_ERROR, "radius_msg_add_attr: too long attribute (%lu bytes)",
605 : : (unsigned long) data_len);
606 : 0 : return NULL;
607 : : }
608 : :
609 : 17119 : buf_needed = sizeof(*attr) + data_len;
610 : :
611 [ + + ]: 17119 : if (wpabuf_tailroom(msg->buf) < buf_needed) {
612 : : /* allocate more space for message buffer */
613 [ - + ]: 518 : if (wpabuf_resize(&msg->buf, buf_needed) < 0)
614 : 0 : return NULL;
615 : 518 : msg->hdr = wpabuf_mhead(msg->buf);
616 : : }
617 : :
618 : 17119 : attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
619 : 17119 : attr->type = type;
620 : 17119 : attr->length = sizeof(*attr) + data_len;
621 : 17119 : wpabuf_put_data(msg->buf, data, data_len);
622 : :
623 [ - + ]: 17119 : if (radius_msg_add_attr_to_array(msg, attr))
624 : 0 : return NULL;
625 : :
626 : 17119 : return attr;
627 : : }
628 : :
629 : :
630 : : /**
631 : : * radius_msg_parse - Parse a RADIUS message
632 : : * @data: RADIUS message to be parsed
633 : : * @len: Length of data buffer in octets
634 : : * Returns: Parsed RADIUS message or %NULL on failure
635 : : *
636 : : * This parses a RADIUS message and makes a copy of its data. The caller is
637 : : * responsible for freeing the returned data with radius_msg_free().
638 : : */
639 : 2127 : struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
640 : : {
641 : : struct radius_msg *msg;
642 : : struct radius_hdr *hdr;
643 : : struct radius_attr_hdr *attr;
644 : : size_t msg_len;
645 : : unsigned char *pos, *end;
646 : :
647 [ + - ][ - + ]: 2127 : if (data == NULL || len < sizeof(*hdr))
648 : 0 : return NULL;
649 : :
650 : 2127 : hdr = (struct radius_hdr *) data;
651 : :
652 : 2127 : msg_len = be_to_host16(hdr->length);
653 [ + - ][ - + ]: 2127 : if (msg_len < sizeof(*hdr) || msg_len > len) {
654 : 0 : wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
655 : 0 : return NULL;
656 : : }
657 : :
658 [ - + ]: 2127 : if (msg_len < len) {
659 : 0 : wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
660 : : "RADIUS message", (unsigned long) len - msg_len);
661 : : }
662 : :
663 : 2127 : msg = os_zalloc(sizeof(*msg));
664 [ - + ]: 2127 : if (msg == NULL)
665 : 0 : return NULL;
666 : :
667 : 2127 : msg->buf = wpabuf_alloc_copy(data, msg_len);
668 [ - + ][ + - ]: 2127 : if (msg->buf == NULL || radius_msg_initialize(msg)) {
669 : 0 : radius_msg_free(msg);
670 : 0 : return NULL;
671 : : }
672 : 2127 : msg->hdr = wpabuf_mhead(msg->buf);
673 : :
674 : : /* parse attributes */
675 : 2127 : pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
676 : 2127 : end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
677 [ + + ]: 19201 : while (pos < end) {
678 [ - + ]: 17074 : if ((size_t) (end - pos) < sizeof(*attr))
679 : 0 : goto fail;
680 : :
681 : 17074 : attr = (struct radius_attr_hdr *) pos;
682 : :
683 [ + - ][ + - ]: 17074 : if (pos + attr->length > end || attr->length < sizeof(*attr))
684 : : goto fail;
685 : :
686 : : /* TODO: check that attr->length is suitable for attr->type */
687 : :
688 [ - + ]: 17074 : if (radius_msg_add_attr_to_array(msg, attr))
689 : 0 : goto fail;
690 : :
691 : 17074 : pos += attr->length;
692 : : }
693 : :
694 : 2127 : return msg;
695 : :
696 : : fail:
697 : 0 : radius_msg_free(msg);
698 : 2127 : return NULL;
699 : : }
700 : :
701 : :
702 : 2099 : int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
703 : : {
704 : 2099 : const u8 *pos = data;
705 : 2099 : size_t left = data_len;
706 : :
707 [ + + ]: 5009 : while (left > 0) {
708 : : int len;
709 [ + + ]: 2910 : if (left > RADIUS_MAX_ATTR_LEN)
710 : 811 : len = RADIUS_MAX_ATTR_LEN;
711 : : else
712 : 2099 : len = left;
713 : :
714 [ - + ]: 2910 : if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
715 : : pos, len))
716 : 0 : return 0;
717 : :
718 : 2910 : pos += len;
719 : 2910 : left -= len;
720 : : }
721 : :
722 : 2099 : return 1;
723 : : }
724 : :
725 : :
726 : 2114 : struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
727 : : {
728 : : struct wpabuf *eap;
729 : : size_t len, i;
730 : : struct radius_attr_hdr *attr;
731 : :
732 [ - + ]: 2114 : if (msg == NULL)
733 : 0 : return NULL;
734 : :
735 : 2114 : len = 0;
736 [ + + ]: 19264 : for (i = 0; i < msg->attr_used; i++) {
737 : 17150 : attr = radius_get_attr_hdr(msg, i);
738 [ + - ][ + + ]: 17150 : if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
739 : 2925 : attr->length > sizeof(struct radius_attr_hdr))
740 : 2925 : len += attr->length - sizeof(struct radius_attr_hdr);
741 : : }
742 : :
743 [ - + ]: 2114 : if (len == 0)
744 : 0 : return NULL;
745 : :
746 : 2114 : eap = wpabuf_alloc(len);
747 [ - + ]: 2114 : if (eap == NULL)
748 : 0 : return NULL;
749 : :
750 [ + + ]: 19264 : for (i = 0; i < msg->attr_used; i++) {
751 : 17150 : attr = radius_get_attr_hdr(msg, i);
752 [ + - ][ + + ]: 17150 : if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
753 : 2925 : attr->length > sizeof(struct radius_attr_hdr)) {
754 : 2925 : int flen = attr->length - sizeof(*attr);
755 : 2925 : wpabuf_put_data(eap, attr + 1, flen);
756 : : }
757 : : }
758 : :
759 : 2114 : return eap;
760 : : }
761 : :
762 : :
763 : 2098 : int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
764 : : size_t secret_len, const u8 *req_auth)
765 : : {
766 : : u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
767 : : u8 orig_authenticator[16];
768 : 2098 : struct radius_attr_hdr *attr = NULL, *tmp;
769 : : size_t i;
770 : :
771 [ + + ]: 19047 : for (i = 0; i < msg->attr_used; i++) {
772 : 16949 : tmp = radius_get_attr_hdr(msg, i);
773 [ + + ]: 16949 : if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
774 [ - + ]: 2098 : if (attr != NULL) {
775 : 0 : wpa_printf(MSG_INFO, "Multiple Message-Authenticator attributes in RADIUS message");
776 : 0 : return 1;
777 : : }
778 : 2098 : attr = tmp;
779 : : }
780 : : }
781 : :
782 [ - + ]: 2098 : if (attr == NULL) {
783 : 0 : wpa_printf(MSG_INFO, "No Message-Authenticator attribute found");
784 : 0 : return 1;
785 : : }
786 : :
787 : 2098 : os_memcpy(orig, attr + 1, MD5_MAC_LEN);
788 : 2098 : os_memset(attr + 1, 0, MD5_MAC_LEN);
789 [ + + ]: 2098 : if (req_auth) {
790 : 1049 : os_memcpy(orig_authenticator, msg->hdr->authenticator,
791 : : sizeof(orig_authenticator));
792 : 1049 : os_memcpy(msg->hdr->authenticator, req_auth,
793 : : sizeof(msg->hdr->authenticator));
794 : : }
795 : 2098 : hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
796 : 2098 : wpabuf_len(msg->buf), auth);
797 : 2098 : os_memcpy(attr + 1, orig, MD5_MAC_LEN);
798 [ + + ]: 2098 : if (req_auth) {
799 : 1049 : os_memcpy(msg->hdr->authenticator, orig_authenticator,
800 : : sizeof(orig_authenticator));
801 : : }
802 : :
803 [ - + ]: 2098 : if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
804 : 0 : wpa_printf(MSG_INFO, "Invalid Message-Authenticator!");
805 : 0 : return 1;
806 : : }
807 : :
808 : 2098 : return 0;
809 : : }
810 : :
811 : :
812 : 1055 : int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
813 : : size_t secret_len, struct radius_msg *sent_msg, int auth)
814 : : {
815 : : const u8 *addr[4];
816 : : size_t len[4];
817 : : u8 hash[MD5_MAC_LEN];
818 : :
819 [ - + ]: 1055 : if (sent_msg == NULL) {
820 : 0 : wpa_printf(MSG_INFO, "No matching Access-Request message found");
821 : 0 : return 1;
822 : : }
823 : :
824 [ + + - + ]: 2104 : if (auth &&
825 : 1049 : radius_msg_verify_msg_auth(msg, secret, secret_len,
826 : 1049 : sent_msg->hdr->authenticator)) {
827 : 0 : return 1;
828 : : }
829 : :
830 : : /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
831 : 1055 : addr[0] = (u8 *) msg->hdr;
832 : 1055 : len[0] = 1 + 1 + 2;
833 : 1055 : addr[1] = sent_msg->hdr->authenticator;
834 : 1055 : len[1] = MD5_MAC_LEN;
835 : 1055 : addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr);
836 : 1055 : len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
837 : 1055 : addr[3] = secret;
838 : 1055 : len[3] = secret_len;
839 : 1055 : md5_vector(4, addr, len, hash);
840 [ - + ]: 1055 : if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
841 : 0 : wpa_printf(MSG_INFO, "Response Authenticator invalid!");
842 : 0 : return 1;
843 : : }
844 : :
845 : 1055 : return 0;
846 : : }
847 : :
848 : :
849 : 1905 : int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
850 : : u8 type)
851 : : {
852 : : struct radius_attr_hdr *attr;
853 : : size_t i;
854 : 1905 : int count = 0;
855 : :
856 [ + + ]: 18126 : for (i = 0; i < src->attr_used; i++) {
857 : 16221 : attr = radius_get_attr_hdr(src, i);
858 [ + - ][ + + ]: 16221 : if (attr->type == type && attr->length >= sizeof(*attr)) {
859 [ - + ]: 856 : if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
860 : 856 : attr->length - sizeof(*attr)))
861 : 0 : return -1;
862 : 856 : count++;
863 : : }
864 : : }
865 : :
866 : 1905 : return count;
867 : : }
868 : :
869 : :
870 : : /* Create Request Authenticator. The value should be unique over the lifetime
871 : : * of the shared secret between authenticator and authentication server.
872 : : * Use one-way MD5 hash calculated from current timestamp and some data given
873 : : * by the caller. */
874 : 1062 : void radius_msg_make_authenticator(struct radius_msg *msg,
875 : : const u8 *data, size_t len)
876 : : {
877 : : struct os_time tv;
878 : : long int l;
879 : : const u8 *addr[3];
880 : : size_t elen[3];
881 : :
882 : 1062 : os_get_time(&tv);
883 : 1062 : l = os_random();
884 : 1062 : addr[0] = (u8 *) &tv;
885 : 1062 : elen[0] = sizeof(tv);
886 : 1062 : addr[1] = data;
887 : 1062 : elen[1] = len;
888 : 1062 : addr[2] = (u8 *) &l;
889 : 1062 : elen[2] = sizeof(l);
890 : 1062 : md5_vector(3, addr, elen, msg->hdr->authenticator);
891 : 1062 : }
892 : :
893 : :
894 : : /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
895 : : * Returns the Attribute payload and sets alen to indicate the length of the
896 : : * payload if a vendor attribute with subtype is found, otherwise returns NULL.
897 : : * The returned payload is allocated with os_malloc() and caller must free it
898 : : * by calling os_free().
899 : : */
900 : 340 : static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
901 : : u8 subtype, size_t *alen)
902 : : {
903 : : u8 *data, *pos;
904 : : size_t i, len;
905 : :
906 [ - + ]: 340 : if (msg == NULL)
907 : 0 : return NULL;
908 : :
909 [ + - ]: 850 : for (i = 0; i < msg->attr_used; i++) {
910 : 850 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
911 : : size_t left;
912 : : u32 vendor_id;
913 : : struct radius_attr_vendor *vhdr;
914 : :
915 [ - + ][ + + ]: 850 : if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
916 : 510 : attr->length < sizeof(*attr))
917 : 340 : continue;
918 : :
919 : 510 : left = attr->length - sizeof(*attr);
920 [ - + ]: 510 : if (left < 4)
921 : 0 : continue;
922 : :
923 : 510 : pos = (u8 *) (attr + 1);
924 : :
925 : 510 : os_memcpy(&vendor_id, pos, 4);
926 : 510 : pos += 4;
927 : 510 : left -= 4;
928 : :
929 [ - + ]: 510 : if (ntohl(vendor_id) != vendor)
930 : 0 : continue;
931 : :
932 [ + + ]: 680 : while (left >= sizeof(*vhdr)) {
933 : 510 : vhdr = (struct radius_attr_vendor *) pos;
934 [ + - ][ - + ]: 510 : if (vhdr->vendor_length > left ||
935 : 510 : vhdr->vendor_length < sizeof(*vhdr)) {
936 : 0 : left = 0;
937 : 0 : break;
938 : : }
939 [ + + ]: 510 : if (vhdr->vendor_type != subtype) {
940 : 170 : pos += vhdr->vendor_length;
941 : 170 : left -= vhdr->vendor_length;
942 : 170 : continue;
943 : : }
944 : :
945 : 340 : len = vhdr->vendor_length - sizeof(*vhdr);
946 : 340 : data = os_malloc(len);
947 [ - + ]: 340 : if (data == NULL)
948 : 0 : return NULL;
949 : 340 : os_memcpy(data, pos + sizeof(*vhdr), len);
950 [ + - ]: 340 : if (alen)
951 : 340 : *alen = len;
952 : 340 : return data;
953 : : }
954 : : }
955 : :
956 : 340 : return NULL;
957 : : }
958 : :
959 : :
960 : 340 : static u8 * decrypt_ms_key(const u8 *key, size_t len,
961 : : const u8 *req_authenticator,
962 : : const u8 *secret, size_t secret_len, size_t *reslen)
963 : : {
964 : : u8 *plain, *ppos, *res;
965 : : const u8 *pos;
966 : : size_t left, plen;
967 : : u8 hash[MD5_MAC_LEN];
968 : 340 : int i, first = 1;
969 : : const u8 *addr[3];
970 : : size_t elen[3];
971 : :
972 : : /* key: 16-bit salt followed by encrypted key info */
973 : :
974 [ - + ]: 340 : if (len < 2 + 16)
975 : 0 : return NULL;
976 : :
977 : 340 : pos = key + 2;
978 : 340 : left = len - 2;
979 [ - + ]: 340 : if (left % 16) {
980 : 0 : wpa_printf(MSG_INFO, "Invalid ms key len %lu",
981 : : (unsigned long) left);
982 : 0 : return NULL;
983 : : }
984 : :
985 : 340 : plen = left;
986 : 340 : ppos = plain = os_malloc(plen);
987 [ - + ]: 340 : if (plain == NULL)
988 : 0 : return NULL;
989 : 340 : plain[0] = 0;
990 : :
991 [ + + ]: 1360 : while (left > 0) {
992 : : /* b(1) = MD5(Secret + Request-Authenticator + Salt)
993 : : * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
994 : :
995 : 1020 : addr[0] = secret;
996 : 1020 : elen[0] = secret_len;
997 [ + + ]: 1020 : if (first) {
998 : 340 : addr[1] = req_authenticator;
999 : 340 : elen[1] = MD5_MAC_LEN;
1000 : 340 : addr[2] = key;
1001 : 340 : elen[2] = 2; /* Salt */
1002 : : } else {
1003 : 680 : addr[1] = pos - MD5_MAC_LEN;
1004 : 680 : elen[1] = MD5_MAC_LEN;
1005 : : }
1006 [ + + ]: 1020 : md5_vector(first ? 3 : 2, addr, elen, hash);
1007 : 1020 : first = 0;
1008 : :
1009 [ + + ]: 17340 : for (i = 0; i < MD5_MAC_LEN; i++)
1010 : 16320 : *ppos++ = *pos++ ^ hash[i];
1011 : 1020 : left -= MD5_MAC_LEN;
1012 : : }
1013 : :
1014 [ + - ][ - + ]: 340 : if (plain[0] == 0 || plain[0] > plen - 1) {
1015 : 0 : wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
1016 : 0 : os_free(plain);
1017 : 0 : return NULL;
1018 : : }
1019 : :
1020 : 340 : res = os_malloc(plain[0]);
1021 [ - + ]: 340 : if (res == NULL) {
1022 : 0 : os_free(plain);
1023 : 0 : return NULL;
1024 : : }
1025 : 340 : os_memcpy(res, plain + 1, plain[0]);
1026 [ + - ]: 340 : if (reslen)
1027 : 340 : *reslen = plain[0];
1028 : 340 : os_free(plain);
1029 : 340 : return res;
1030 : : }
1031 : :
1032 : :
1033 : 340 : static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
1034 : : const u8 *req_authenticator,
1035 : : const u8 *secret, size_t secret_len,
1036 : : u8 *ebuf, size_t *elen)
1037 : : {
1038 : 340 : int i, len, first = 1;
1039 : : u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
1040 : : const u8 *addr[3];
1041 : : size_t _len[3];
1042 : :
1043 : 340 : WPA_PUT_BE16(saltbuf, salt);
1044 : :
1045 : 340 : len = 1 + key_len;
1046 [ + - ]: 340 : if (len & 0x0f) {
1047 : 340 : len = (len & 0xf0) + 16;
1048 : : }
1049 : 340 : os_memset(ebuf, 0, len);
1050 : 340 : ebuf[0] = key_len;
1051 : 340 : os_memcpy(ebuf + 1, key, key_len);
1052 : :
1053 : 340 : *elen = len;
1054 : :
1055 : 340 : pos = ebuf;
1056 [ + + ]: 1360 : while (len > 0) {
1057 : : /* b(1) = MD5(Secret + Request-Authenticator + Salt)
1058 : : * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
1059 : 1020 : addr[0] = secret;
1060 : 1020 : _len[0] = secret_len;
1061 [ + + ]: 1020 : if (first) {
1062 : 340 : addr[1] = req_authenticator;
1063 : 340 : _len[1] = MD5_MAC_LEN;
1064 : 340 : addr[2] = saltbuf;
1065 : 340 : _len[2] = sizeof(saltbuf);
1066 : : } else {
1067 : 680 : addr[1] = pos - MD5_MAC_LEN;
1068 : 680 : _len[1] = MD5_MAC_LEN;
1069 : : }
1070 [ + + ]: 1020 : md5_vector(first ? 3 : 2, addr, _len, hash);
1071 : 1020 : first = 0;
1072 : :
1073 [ + + ]: 17340 : for (i = 0; i < MD5_MAC_LEN; i++)
1074 : 16320 : *pos++ ^= hash[i];
1075 : :
1076 : 1020 : len -= MD5_MAC_LEN;
1077 : : }
1078 : 340 : }
1079 : :
1080 : :
1081 : : struct radius_ms_mppe_keys *
1082 : 170 : radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1083 : : const u8 *secret, size_t secret_len)
1084 : : {
1085 : : u8 *key;
1086 : : size_t keylen;
1087 : : struct radius_ms_mppe_keys *keys;
1088 : :
1089 [ + - ][ - + ]: 170 : if (msg == NULL || sent_msg == NULL)
1090 : 0 : return NULL;
1091 : :
1092 : 170 : keys = os_zalloc(sizeof(*keys));
1093 [ - + ]: 170 : if (keys == NULL)
1094 : 0 : return NULL;
1095 : :
1096 : 170 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1097 : : RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
1098 : : &keylen);
1099 [ + - ]: 170 : if (key) {
1100 : 170 : keys->send = decrypt_ms_key(key, keylen,
1101 : 170 : sent_msg->hdr->authenticator,
1102 : : secret, secret_len,
1103 : : &keys->send_len);
1104 : 170 : os_free(key);
1105 : : }
1106 : :
1107 : 170 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
1108 : : RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
1109 : : &keylen);
1110 [ + - ]: 170 : if (key) {
1111 : 170 : keys->recv = decrypt_ms_key(key, keylen,
1112 : 170 : sent_msg->hdr->authenticator,
1113 : : secret, secret_len,
1114 : : &keys->recv_len);
1115 : 170 : os_free(key);
1116 : : }
1117 : :
1118 : 170 : return keys;
1119 : : }
1120 : :
1121 : :
1122 : : struct radius_ms_mppe_keys *
1123 : 0 : radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
1124 : : const u8 *secret, size_t secret_len)
1125 : : {
1126 : : u8 *key;
1127 : : size_t keylen;
1128 : : struct radius_ms_mppe_keys *keys;
1129 : :
1130 [ # # ][ # # ]: 0 : if (msg == NULL || sent_msg == NULL)
1131 : 0 : return NULL;
1132 : :
1133 : 0 : keys = os_zalloc(sizeof(*keys));
1134 [ # # ]: 0 : if (keys == NULL)
1135 : 0 : return NULL;
1136 : :
1137 : 0 : key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
1138 : : RADIUS_CISCO_AV_PAIR, &keylen);
1139 [ # # ][ # # ]: 0 : if (key && keylen == 51 &&
[ # # ]
1140 : 0 : os_memcmp(key, "leap:session-key=", 17) == 0) {
1141 : 0 : keys->recv = decrypt_ms_key(key + 17, keylen - 17,
1142 : 0 : sent_msg->hdr->authenticator,
1143 : : secret, secret_len,
1144 : : &keys->recv_len);
1145 : : }
1146 : 0 : os_free(key);
1147 : :
1148 : 0 : return keys;
1149 : : }
1150 : :
1151 : :
1152 : 170 : int radius_msg_add_mppe_keys(struct radius_msg *msg,
1153 : : const u8 *req_authenticator,
1154 : : const u8 *secret, size_t secret_len,
1155 : : const u8 *send_key, size_t send_key_len,
1156 : : const u8 *recv_key, size_t recv_key_len)
1157 : : {
1158 : : struct radius_attr_hdr *attr;
1159 : 170 : u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
1160 : : u8 *buf;
1161 : : struct radius_attr_vendor *vhdr;
1162 : : u8 *pos;
1163 : : size_t elen;
1164 : : int hlen;
1165 : : u16 salt;
1166 : :
1167 : 170 : hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
1168 : :
1169 : : /* MS-MPPE-Send-Key */
1170 : 170 : buf = os_malloc(hlen + send_key_len + 16);
1171 [ - + ]: 170 : if (buf == NULL) {
1172 : 0 : return 0;
1173 : : }
1174 : 170 : pos = buf;
1175 : 170 : os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1176 : 170 : pos += sizeof(vendor_id);
1177 : 170 : vhdr = (struct radius_attr_vendor *) pos;
1178 : 170 : vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
1179 : 170 : pos = (u8 *) (vhdr + 1);
1180 : 170 : salt = os_random() | 0x8000;
1181 : 170 : WPA_PUT_BE16(pos, salt);
1182 : 170 : pos += 2;
1183 : 170 : encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
1184 : : secret_len, pos, &elen);
1185 : 170 : vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1186 : :
1187 : 170 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1188 : : buf, hlen + elen);
1189 : 170 : os_free(buf);
1190 [ - + ]: 170 : if (attr == NULL) {
1191 : 0 : return 0;
1192 : : }
1193 : :
1194 : : /* MS-MPPE-Recv-Key */
1195 : 170 : buf = os_malloc(hlen + send_key_len + 16);
1196 [ - + ]: 170 : if (buf == NULL) {
1197 : 0 : return 0;
1198 : : }
1199 : 170 : pos = buf;
1200 : 170 : os_memcpy(pos, &vendor_id, sizeof(vendor_id));
1201 : 170 : pos += sizeof(vendor_id);
1202 : 170 : vhdr = (struct radius_attr_vendor *) pos;
1203 : 170 : vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
1204 : 170 : pos = (u8 *) (vhdr + 1);
1205 : 170 : salt ^= 1;
1206 : 170 : WPA_PUT_BE16(pos, salt);
1207 : 170 : pos += 2;
1208 : 170 : encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
1209 : : secret_len, pos, &elen);
1210 : 170 : vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
1211 : :
1212 : 170 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1213 : : buf, hlen + elen);
1214 : 170 : os_free(buf);
1215 [ - + ]: 170 : if (attr == NULL) {
1216 : 0 : return 0;
1217 : : }
1218 : :
1219 : 170 : return 1;
1220 : : }
1221 : :
1222 : :
1223 : 880 : int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data,
1224 : : size_t len)
1225 : : {
1226 : : struct radius_attr_hdr *attr;
1227 : : u8 *buf, *pos;
1228 : : size_t alen;
1229 : :
1230 : 880 : alen = 4 + 2 + len;
1231 : 880 : buf = os_malloc(alen);
1232 [ - + ]: 880 : if (buf == NULL)
1233 : 0 : return 0;
1234 : 880 : pos = buf;
1235 : 880 : WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA);
1236 : 880 : pos += 4;
1237 : 880 : *pos++ = subtype;
1238 : 880 : *pos++ = 2 + len;
1239 : 880 : os_memcpy(pos, data, len);
1240 : 880 : attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
1241 : : buf, alen);
1242 : 880 : os_free(buf);
1243 [ - + ]: 880 : if (attr == NULL)
1244 : 0 : return 0;
1245 : :
1246 : 880 : return 1;
1247 : : }
1248 : :
1249 : :
1250 : : /* Add User-Password attribute to a RADIUS message and encrypt it as specified
1251 : : * in RFC 2865, Chap. 5.2 */
1252 : : struct radius_attr_hdr *
1253 : 0 : radius_msg_add_attr_user_password(struct radius_msg *msg,
1254 : : const u8 *data, size_t data_len,
1255 : : const u8 *secret, size_t secret_len)
1256 : : {
1257 : : u8 buf[128];
1258 : : size_t padlen, i, buf_len, pos;
1259 : : const u8 *addr[2];
1260 : : size_t len[2];
1261 : : u8 hash[16];
1262 : :
1263 [ # # ]: 0 : if (data_len > 128)
1264 : 0 : return NULL;
1265 : :
1266 : 0 : os_memcpy(buf, data, data_len);
1267 : 0 : buf_len = data_len;
1268 : :
1269 : 0 : padlen = data_len % 16;
1270 [ # # ][ # # ]: 0 : if (padlen && data_len < sizeof(buf)) {
1271 : 0 : padlen = 16 - padlen;
1272 : 0 : os_memset(buf + data_len, 0, padlen);
1273 : 0 : buf_len += padlen;
1274 : : }
1275 : :
1276 : 0 : addr[0] = secret;
1277 : 0 : len[0] = secret_len;
1278 : 0 : addr[1] = msg->hdr->authenticator;
1279 : 0 : len[1] = 16;
1280 : 0 : md5_vector(2, addr, len, hash);
1281 : :
1282 [ # # ]: 0 : for (i = 0; i < 16; i++)
1283 : 0 : buf[i] ^= hash[i];
1284 : 0 : pos = 16;
1285 : :
1286 [ # # ]: 0 : while (pos < buf_len) {
1287 : 0 : addr[0] = secret;
1288 : 0 : len[0] = secret_len;
1289 : 0 : addr[1] = &buf[pos - 16];
1290 : 0 : len[1] = 16;
1291 : 0 : md5_vector(2, addr, len, hash);
1292 : :
1293 [ # # ]: 0 : for (i = 0; i < 16; i++)
1294 : 0 : buf[pos + i] ^= hash[i];
1295 : :
1296 : 0 : pos += 16;
1297 : : }
1298 : :
1299 : 0 : return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
1300 : : buf, buf_len);
1301 : : }
1302 : :
1303 : :
1304 : 3545 : int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
1305 : : {
1306 : 3545 : struct radius_attr_hdr *attr = NULL, *tmp;
1307 : : size_t i, dlen;
1308 : :
1309 [ + + ]: 22793 : for (i = 0; i < msg->attr_used; i++) {
1310 : 20331 : tmp = radius_get_attr_hdr(msg, i);
1311 [ + + ]: 20331 : if (tmp->type == type) {
1312 : 1083 : attr = tmp;
1313 : 1083 : break;
1314 : : }
1315 : : }
1316 : :
1317 [ + + ][ - + ]: 3545 : if (!attr || attr->length < sizeof(*attr))
1318 : 2462 : return -1;
1319 : :
1320 : 1083 : dlen = attr->length - sizeof(*attr);
1321 [ + + ]: 1083 : if (buf)
1322 : 1062 : os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
1323 : 3545 : return dlen;
1324 : : }
1325 : :
1326 : :
1327 : 917 : int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
1328 : : size_t *len, const u8 *start)
1329 : : {
1330 : : size_t i;
1331 : 917 : struct radius_attr_hdr *attr = NULL, *tmp;
1332 : :
1333 [ + + ]: 3617 : for (i = 0; i < msg->attr_used; i++) {
1334 : 3057 : tmp = radius_get_attr_hdr(msg, i);
1335 [ + + ][ + + ]: 3057 : if (tmp->type == type &&
1336 [ + + ]: 680 : (start == NULL || (u8 *) tmp > start)) {
1337 : 357 : attr = tmp;
1338 : 357 : break;
1339 : : }
1340 : : }
1341 : :
1342 [ + + ][ - + ]: 917 : if (!attr || attr->length < sizeof(*attr))
1343 : 560 : return -1;
1344 : :
1345 : 357 : *buf = (u8 *) (attr + 1);
1346 : 357 : *len = attr->length - sizeof(*attr);
1347 : 917 : return 0;
1348 : : }
1349 : :
1350 : :
1351 : 3 : int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
1352 : : {
1353 : : size_t i;
1354 : : int count;
1355 : :
1356 [ + + ]: 15 : for (count = 0, i = 0; i < msg->attr_used; i++) {
1357 : 12 : struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
1358 [ # # ][ - + ]: 12 : if (attr->type == type &&
1359 : 0 : attr->length >= sizeof(struct radius_attr_hdr) + min_len)
1360 : 0 : count++;
1361 : : }
1362 : :
1363 : 3 : return count;
1364 : : }
1365 : :
1366 : :
1367 : : struct radius_tunnel_attrs {
1368 : : int tag_used;
1369 : : int type; /* Tunnel-Type */
1370 : : int medium_type; /* Tunnel-Medium-Type */
1371 : : int vlanid;
1372 : : };
1373 : :
1374 : :
1375 : : /**
1376 : : * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
1377 : : * @msg: RADIUS message
1378 : : * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
1379 : : */
1380 : 0 : int radius_msg_get_vlanid(struct radius_msg *msg)
1381 : : {
1382 : : struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
1383 : : size_t i;
1384 : 0 : struct radius_attr_hdr *attr = NULL;
1385 : : const u8 *data;
1386 : : char buf[10];
1387 : : size_t dlen;
1388 : :
1389 : 0 : os_memset(&tunnel, 0, sizeof(tunnel));
1390 : :
1391 [ # # ]: 0 : for (i = 0; i < msg->attr_used; i++) {
1392 : 0 : attr = radius_get_attr_hdr(msg, i);
1393 [ # # ]: 0 : if (attr->length < sizeof(*attr))
1394 : 0 : return -1;
1395 : 0 : data = (const u8 *) (attr + 1);
1396 : 0 : dlen = attr->length - sizeof(*attr);
1397 [ # # ]: 0 : if (attr->length < 3)
1398 : 0 : continue;
1399 [ # # ]: 0 : if (data[0] >= RADIUS_TUNNEL_TAGS)
1400 : 0 : tun = &tunnel[0];
1401 : : else
1402 : 0 : tun = &tunnel[data[0]];
1403 : :
1404 [ # # # # ]: 0 : switch (attr->type) {
1405 : : case RADIUS_ATTR_TUNNEL_TYPE:
1406 [ # # ]: 0 : if (attr->length != 6)
1407 : 0 : break;
1408 : 0 : tun->tag_used++;
1409 : 0 : tun->type = WPA_GET_BE24(data + 1);
1410 : 0 : break;
1411 : : case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
1412 [ # # ]: 0 : if (attr->length != 6)
1413 : 0 : break;
1414 : 0 : tun->tag_used++;
1415 : 0 : tun->medium_type = WPA_GET_BE24(data + 1);
1416 : 0 : break;
1417 : : case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
1418 [ # # ]: 0 : if (data[0] < RADIUS_TUNNEL_TAGS) {
1419 : 0 : data++;
1420 : 0 : dlen--;
1421 : : }
1422 [ # # ]: 0 : if (dlen >= sizeof(buf))
1423 : 0 : break;
1424 : 0 : os_memcpy(buf, data, dlen);
1425 : 0 : buf[dlen] = '\0';
1426 : 0 : tun->tag_used++;
1427 : 0 : tun->vlanid = atoi(buf);
1428 : 0 : break;
1429 : : }
1430 : : }
1431 : :
1432 [ # # ]: 0 : for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
1433 : 0 : tun = &tunnel[i];
1434 [ # # ][ # # ]: 0 : if (tun->tag_used &&
1435 [ # # ]: 0 : tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
1436 [ # # ]: 0 : tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
1437 : 0 : tun->vlanid > 0)
1438 : 0 : return tun->vlanid;
1439 : : }
1440 : :
1441 : 0 : return -1;
1442 : : }
1443 : :
1444 : :
1445 : : /**
1446 : : * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
1447 : : * @msg: Received RADIUS message
1448 : : * @keylen: Length of returned password
1449 : : * @secret: RADIUS shared secret
1450 : : * @secret_len: Length of secret
1451 : : * @sent_msg: Sent RADIUS message
1452 : : * @n: Number of password attribute to return (starting with 0)
1453 : : * Returns: Pointer to n-th password (free with os_free) or %NULL
1454 : : */
1455 : 0 : char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
1456 : : const u8 *secret, size_t secret_len,
1457 : : struct radius_msg *sent_msg, size_t n)
1458 : : {
1459 : 0 : u8 *buf = NULL;
1460 : : size_t buflen;
1461 : : const u8 *salt;
1462 : : u8 *str;
1463 : : const u8 *addr[3];
1464 : : size_t len[3];
1465 : : u8 hash[16];
1466 : : u8 *pos;
1467 : 0 : size_t i, j = 0;
1468 : : struct radius_attr_hdr *attr;
1469 : : const u8 *data;
1470 : : size_t dlen;
1471 : 0 : const u8 *fdata = NULL; /* points to found item */
1472 : 0 : size_t fdlen = -1;
1473 : 0 : char *ret = NULL;
1474 : :
1475 : : /* find n-th valid Tunnel-Password attribute */
1476 [ # # ]: 0 : for (i = 0; i < msg->attr_used; i++) {
1477 : 0 : attr = radius_get_attr_hdr(msg, i);
1478 [ # # ][ # # ]: 0 : if (attr == NULL ||
1479 : 0 : attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
1480 : 0 : continue;
1481 : : }
1482 [ # # ]: 0 : if (attr->length <= 5)
1483 : 0 : continue;
1484 : 0 : data = (const u8 *) (attr + 1);
1485 : 0 : dlen = attr->length - sizeof(*attr);
1486 [ # # ][ # # ]: 0 : if (dlen <= 3 || dlen % 16 != 3)
1487 : 0 : continue;
1488 : 0 : j++;
1489 [ # # ]: 0 : if (j <= n)
1490 : 0 : continue;
1491 : :
1492 : 0 : fdata = data;
1493 : 0 : fdlen = dlen;
1494 : 0 : break;
1495 : : }
1496 [ # # ]: 0 : if (fdata == NULL)
1497 : 0 : goto out;
1498 : :
1499 : : /* alloc writable memory for decryption */
1500 : 0 : buf = os_malloc(fdlen);
1501 [ # # ]: 0 : if (buf == NULL)
1502 : 0 : goto out;
1503 : 0 : os_memcpy(buf, fdata, fdlen);
1504 : 0 : buflen = fdlen;
1505 : :
1506 : : /* init pointers */
1507 : 0 : salt = buf + 1;
1508 : 0 : str = buf + 3;
1509 : :
1510 : : /* decrypt blocks */
1511 : 0 : pos = buf + buflen - 16; /* last block */
1512 [ # # ]: 0 : while (pos >= str + 16) { /* all but the first block */
1513 : 0 : addr[0] = secret;
1514 : 0 : len[0] = secret_len;
1515 : 0 : addr[1] = pos - 16;
1516 : 0 : len[1] = 16;
1517 : 0 : md5_vector(2, addr, len, hash);
1518 : :
1519 [ # # ]: 0 : for (i = 0; i < 16; i++)
1520 : 0 : pos[i] ^= hash[i];
1521 : :
1522 : 0 : pos -= 16;
1523 : : }
1524 : :
1525 : : /* decrypt first block */
1526 [ # # ]: 0 : if (str != pos)
1527 : 0 : goto out;
1528 : 0 : addr[0] = secret;
1529 : 0 : len[0] = secret_len;
1530 : 0 : addr[1] = sent_msg->hdr->authenticator;
1531 : 0 : len[1] = 16;
1532 : 0 : addr[2] = salt;
1533 : 0 : len[2] = 2;
1534 : 0 : md5_vector(3, addr, len, hash);
1535 : :
1536 [ # # ]: 0 : for (i = 0; i < 16; i++)
1537 : 0 : pos[i] ^= hash[i];
1538 : :
1539 : : /* derive plaintext length from first subfield */
1540 : 0 : *keylen = (unsigned char) str[0];
1541 [ # # ]: 0 : if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
1542 : : /* decryption error - invalid key length */
1543 : 0 : goto out;
1544 : : }
1545 [ # # ]: 0 : if (*keylen == 0) {
1546 : : /* empty password */
1547 : 0 : goto out;
1548 : : }
1549 : :
1550 : : /* copy passphrase into new buffer */
1551 : 0 : ret = os_malloc(*keylen);
1552 [ # # ]: 0 : if (ret)
1553 : 0 : os_memcpy(ret, str + 1, *keylen);
1554 : :
1555 : : out:
1556 : : /* return new buffer */
1557 : 0 : os_free(buf);
1558 : 0 : return ret;
1559 : : }
1560 : :
1561 : :
1562 : 422 : void radius_free_class(struct radius_class_data *c)
1563 : : {
1564 : : size_t i;
1565 [ - + ]: 422 : if (c == NULL)
1566 : 422 : return;
1567 [ - + ]: 422 : for (i = 0; i < c->count; i++)
1568 : 0 : os_free(c->attr[i].data);
1569 : 422 : os_free(c->attr);
1570 : 422 : c->attr = NULL;
1571 : 422 : c->count = 0;
1572 : : }
1573 : :
1574 : :
1575 : 178 : int radius_copy_class(struct radius_class_data *dst,
1576 : : const struct radius_class_data *src)
1577 : : {
1578 : : size_t i;
1579 : :
1580 [ + - ]: 178 : if (src->attr == NULL)
1581 : 178 : return 0;
1582 : :
1583 : 0 : dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
1584 [ # # ]: 0 : if (dst->attr == NULL)
1585 : 0 : return -1;
1586 : :
1587 : 0 : dst->count = 0;
1588 : :
1589 [ # # ]: 0 : for (i = 0; i < src->count; i++) {
1590 : 0 : dst->attr[i].data = os_malloc(src->attr[i].len);
1591 [ # # ]: 0 : if (dst->attr[i].data == NULL)
1592 : 0 : break;
1593 : 0 : dst->count++;
1594 : 0 : os_memcpy(dst->attr[i].data, src->attr[i].data,
1595 : : src->attr[i].len);
1596 : 0 : dst->attr[i].len = src->attr[i].len;
1597 : : }
1598 : :
1599 : 178 : return 0;
1600 : : }
1601 : :
1602 : :
1603 : 11 : u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
1604 : : {
1605 : : size_t i, j;
1606 : : struct radius_attr_hdr *attr;
1607 : :
1608 [ + + ]: 40 : for (i = 0; i < msg->attr_used; i++) {
1609 : 30 : attr = radius_get_attr_hdr(msg, i);
1610 : :
1611 [ + + ]: 132 : for (j = 0; attrs[j]; j++) {
1612 [ + + ]: 131 : if (attr->type == attrs[j])
1613 : 29 : break;
1614 : : }
1615 : :
1616 [ + + ]: 30 : if (attrs[j] == 0)
1617 : 1 : return attr->type; /* unlisted attr */
1618 : : }
1619 : :
1620 : 11 : return 0;
1621 : : }
|