The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: a35c2a766439df8db2f02e2755c7a57ec5cbaf3c $
19 *
20 * @file protocols/tacacs/encode.c
21 * @brief Low-Level TACACS+ encode functions
22 *
23 * @copyright 2017 The FreeRADIUS server project
24 * @copyright 2017 Network RADIUS SAS (legal@networkradius.com)
25 */
26#include <freeradius-devel/util/net.h>
27#include <freeradius-devel/util/md5.h>
28#include <freeradius-devel/util/struct.h>
29
30#include "tacacs.h"
31#include "attrs.h"
32
34static bool instantiated = false;
35
37
40 { .out = &dict_tacacs, .proto = "tacacs" },
41
42 { NULL }
43};
44
71
79
82 { .out = &attr_tacacs_accounting_flags, .name = "Accounting-Flags", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
83 { .out = &attr_tacacs_accounting_status, .name = "Accounting-Status", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
84 { .out = &attr_tacacs_action, .name = "Action", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
85 { .out = &attr_tacacs_authentication_flags, .name = "Authentication-Flags", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
86 { .out = &attr_tacacs_authentication_continue_flags, .name = "Authentication-Continue-Flags", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
87 { .out = &attr_tacacs_authentication_method, .name = "Authentication-Method", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
88 { .out = &attr_tacacs_authentication_service, .name = "Authentication-Service", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
89 { .out = &attr_tacacs_authentication_status, .name = "Authentication-Status", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
90 { .out = &attr_tacacs_authentication_type, .name = "Authentication-Type", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
91 { .out = &attr_tacacs_authorization_status, .name = "Authorization-Status", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
92 { .out = &attr_tacacs_argument_list, .name = "Argument-List", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
93 { .out = &attr_tacacs_client_port, .name = "Client-Port", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
94 { .out = &attr_tacacs_data, .name = "Data", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
95 { .out = &attr_tacacs_flags, .name = "Packet.Flags", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
96 { .out = &attr_tacacs_length, .name = "Packet.Length", .type = FR_TYPE_UINT32, .dict = &dict_tacacs },
97 { .out = &attr_tacacs_packet, .name = "Packet", .type = FR_TYPE_STRUCT, .dict = &dict_tacacs },
98 { .out = &attr_tacacs_packet_body_type, .name = "Packet-Body-Type", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
99 { .out = &attr_tacacs_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_tacacs },
100 { .out = &attr_tacacs_privilege_level, .name = "Privilege-Level", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
101 { .out = &attr_tacacs_remote_address, .name = "Remote-Address", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
102 { .out = &attr_tacacs_sequence_number, .name = "Packet.Sequence-Number", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
103 { .out = &attr_tacacs_server_message, .name = "Server-Message", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
104 { .out = &attr_tacacs_session_id, .name = "Packet.Session-Id", .type = FR_TYPE_UINT32, .dict = &dict_tacacs },
105 { .out = &attr_tacacs_user_message, .name = "User-Message", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
106 { .out = &attr_tacacs_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
107 { .out = &attr_tacacs_version_major, .name = "Packet.Version-Major", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
108 { .out = &attr_tacacs_version_minor, .name = "Packet.Version-Minor", .type = FR_TYPE_UINT8, .dict = &dict_tacacs },
109
110 { .out = &attr_tacacs_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
111 { .out = &attr_tacacs_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_tacacs },
112 { .out = &attr_tacacs_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
113 { .out = &attr_tacacs_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
114 { .out = &attr_tacacs_mschap_response, .name = "MS-CHAP-Response", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
115 { .out = &attr_tacacs_mschap2_response, .name = "MS-CHAP2-Response", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
116 { .out = &attr_tacacs_mschap_challenge, .name = "MS-CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_tacacs },
117 { NULL }
118};
119
121 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_START] = "Authentication-Start",
122 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_PASS] = "Authentication-Pass",
123 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_FAIL] = "Authentication-Fail",
124 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETDATA] = "Authentication-GetData",
125 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETUSER] = "Authentication-GetUser",
126 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_GETPASS] = "Authentication-GetPass",
127 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_RESTART] = "Authentication-Restart",
128 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_ERROR] = "Authentication-Error",
129
130 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE] = "Authentication-Continue",
131 [FR_PACKET_TYPE_VALUE_AUTHENTICATION_CONTINUE_ABORT] = "Authentication-Continue-Abort",
132
133 [FR_PACKET_TYPE_VALUE_AUTHORIZATION_REQUEST] = "Authorization-Request",
134 [FR_PACKET_TYPE_VALUE_AUTHORIZATION_PASS_ADD] = "Authorization-Pass-Add",
135 [FR_PACKET_TYPE_VALUE_AUTHORIZATION_PASS_REPLACE] = "Authorization-Pass-Replace",
136 [FR_PACKET_TYPE_VALUE_AUTHORIZATION_FAIL] = "Authorization-Fail",
137 [FR_PACKET_TYPE_VALUE_AUTHORIZATION_ERROR] = "Authorization-Error",
138
139 [FR_PACKET_TYPE_VALUE_ACCOUNTING_REQUEST] = "Accounting-Request",
140 [FR_PACKET_TYPE_VALUE_ACCOUNTING_SUCCESS] = "Accounting-Success",
141 [FR_PACKET_TYPE_VALUE_ACCOUNTING_ERROR] = "Accounting-Error",
142};
143
144
145/** XOR the body based on the secret key.
146 *
147 * This function encrypts (or decrypts) TACACS+ packets, and sets the "encrypted" flag.
148 */
149int fr_tacacs_body_xor(fr_tacacs_packet_t const *pkt, uint8_t *body, size_t body_len, char const *secret, size_t secret_len)
150{
152 uint8_t *buf, *end;
153 int pad_offset;
154
155 /*
156 * Do some basic sanity checks.
157 */
158 if (!secret_len) {
159 fr_strerror_const("Failed to encrypt/decrept the packet, as the secret has zero length.");
160 return -1;
161 }
162
163 pad_offset = sizeof(pkt->hdr.session_id) + secret_len + sizeof(pkt->hdr.version) + sizeof(pkt->hdr.seq_no);
164
165 /* MD5_1 = MD5{session_id, key, version, seq_no} */
166 /* MD5_n = MD5{session_id, key, version, seq_no, MD5_n-1} */
167 buf = talloc_array(NULL, uint8_t, pad_offset + MD5_DIGEST_LENGTH);
168 if (!buf) return -1;
169
170 memcpy(&buf[0], &pkt->hdr.session_id, sizeof(pkt->hdr.session_id));
171 memcpy(&buf[sizeof(pkt->hdr.session_id)], secret, secret_len);
172 memcpy(&buf[sizeof(pkt->hdr.session_id) + secret_len], &pkt->hdr.version, sizeof(pkt->hdr.version));
173 memcpy(&buf[sizeof(pkt->hdr.session_id) + secret_len + sizeof(pkt->hdr.version)], &pkt->hdr.seq_no, sizeof(pkt->hdr.seq_no));
174
175 fr_md5_calc(pad, buf, pad_offset);
176
177 end = body + body_len;
178 while (body < end) {
179 size_t i;
180
181 for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
182 *body ^= pad[i];
183
184 if (++body == end) goto done;
185 }
186
187 memcpy(&buf[pad_offset], pad, MD5_DIGEST_LENGTH);
188 fr_md5_calc(pad, buf, pad_offset + MD5_DIGEST_LENGTH);
189 }
190
191done:
192 talloc_free(buf);
193
194 return 0;
195}
196
197/**
198 * Return how long a TACACS+ packet is
199 *
200 * Note that we only look at the 12 byte packet header. We don't
201 * (yet) do validation on authentication / authorization /
202 * accounting headers. The packet may still be determined later
203 * to be invalid.
204 *
205 * @param buffer to check
206 * @param buffer_len length of the buffer
207 * @return
208 * >0 size of the TACACS+ packet. We want. MAY be larger than "buffer_len"
209 * <=0 error, packet should be discarded.
210 */
211ssize_t fr_tacacs_length(uint8_t const *buffer, size_t buffer_len)
212{
213 fr_tacacs_packet_t const *pkt = (fr_tacacs_packet_t const *) buffer;
214 size_t length, want;
215
216 /*
217 * Check that we have a full TACACS+ header before
218 * decoding anything.
219 */
220 if (buffer_len < sizeof(pkt->hdr)) {
221 return sizeof(pkt->hdr);
222 }
223
224 /*
225 * TACACS major / minor version MUST be 12.0 or 12.1
226 */
227 if (!((buffer[0] == 0xc0) || (buffer[0] == 0xc1))) {
228 fr_strerror_printf("Unsupported TACACS+ version %02x", buffer[0]);
229 return -1;
230 }
231
232 /*
233 * There's no reason to accept 64K TACACS+ packets.
234 */
235 if ((buffer[8] != 0) || (buffer[9] != 0)) {
236 fr_strerror_const("Packet is too large. Our limit is 64K");
237 return -1;
238 }
239
240 /*
241 * There are only 3 types of packets which are supported.
242 */
243 if (!((pkt->hdr.type == FR_TAC_PLUS_AUTHEN) ||
244 (pkt->hdr.type == FR_TAC_PLUS_AUTHOR) ||
245 (pkt->hdr.type == FR_TAC_PLUS_ACCT))) {
246 fr_strerror_printf("Unknown packet type %d", pkt->hdr.type);
247 return -1;
248 }
249
250 length = sizeof(pkt->hdr) + ntohl(pkt->hdr.length);
251
252 if (buffer_len < length) return length;
253
254 /*
255 * We want at least the headers for the various packet
256 * types. Note that we do NOT check the lengths in the
257 * headers against buffer / buffer_len. That process is
258 * complex and error-prone. It's best to leave it in one
259 * place: fr_tacacs_decode().
260 */
261 switch (pkt->hdr.type) {
262 default:
263 fr_assert(0); /* should have been caught above */
264 return -1;
265
268 want = sizeof(pkt->hdr) + sizeof(pkt->authen_start);
269
270 } else if (packet_is_authen_continue(pkt)) {
271 want = sizeof(pkt->hdr) + sizeof(pkt->authen_cont);
272
273 } else {
275 want = sizeof(pkt->hdr) + sizeof(pkt->authen_reply);
276 }
277 break;
278
280 if (packet_is_author_request(pkt)) {
281 want = sizeof(pkt->hdr) + sizeof(pkt->author_req);
282 } else {
284 want = sizeof(pkt->hdr) + sizeof(pkt->author_reply);
285 }
286 break;
287
288 case FR_TAC_PLUS_ACCT:
289 if (packet_is_acct_request(pkt)) {
290 want = sizeof(pkt->hdr) + sizeof(pkt->acct_req);
291 } else {
293 want = sizeof(pkt->hdr) + sizeof(pkt->acct_reply);
294 }
295 break;
296 }
297
298 if (want > length) {
299 fr_strerror_printf("Packet is too small. Want %zu, got %zu", want, length);
300 return -1;
301 }
302
303 return length;
304}
305
306static void print_hex(fr_log_t const *log, char const *file, int line, char const *prefix, uint8_t const *data, size_t datalen)
307{
308 if (!datalen) return;
309
310 fr_log_hex(log, L_DBG, file, line, data, datalen, "%s", prefix);
311}
312
313static void print_ascii(fr_log_t const *log, char const *file, int line, char const *prefix, uint8_t const *data, size_t datalen)
314{
315 uint8_t const *p;
316
317 if (!datalen) return;
318
319 if (datalen > 80) {
320 hex:
321 print_hex(log, file, line, prefix, data, datalen);
322 return;
323 }
324
325 for (p = data; p < (data + datalen); p++) {
326 if ((*p < 0x20) || (*p > 0x80)) goto hex;
327 }
328
329 fr_log(log, L_DBG, file, line, "%s %.*s", prefix, (int) datalen, (char const *) data);
330}
331
332#define CHECK(_length) do { \
333 size_t plen = _length; \
334 if ((size_t) (end - p) < plen) { \
335 fr_log_hex(log, L_DBG, file, line, p, end - p, "%s", " TRUNCATED "); \
336 return; \
337 } \
338 data = p; \
339 data_len = plen; \
340 p += plen; \
341 } while (0)
342
343#undef ASCII
344#define ASCII(_prefix, _field) do { \
345 CHECK(_field); \
346 print_ascii(log, file, line, _prefix, data, data_len); \
347 } while (0)
348
349#undef HEXIT
350#define HEXIT(_prefix, _field) do { \
351 CHECK(_field); \
352 print_hex(log, file, line, _prefix, data, data_len); \
353 } while (0)
354
355#define PRINT(_fmt, ...) fr_log(log, L_DBG, file, line, _fmt, ## __VA_ARGS__)
356
357static void print_args(fr_log_t const *log, char const *file, int line, size_t arg_cnt, uint8_t const *argv, uint8_t const *start, uint8_t const *end)
358{
359 size_t i, data_len;
360 uint8_t const *p;
361 uint8_t const *data;
362 char prefix[64];
363
364 if (argv + arg_cnt > end) {
365 PRINT(" ARG cnt overflows packet");
366 return;
367 }
368
369 p = start;
370 for (i = 0; i < arg_cnt; i++) {
371 if (p == end) {
372 PRINT(" ARG[%zu] is at EOF", i);
373 return;
374 }
375
376 if ((end - p) < argv[i]) {
377 PRINT(" ARG[%zu] overflows packet", i);
378 print_hex(log, file, line, " ", p, end - p);
379 return;
380 }
381
382 snprintf(prefix, sizeof(prefix), " arg[%zu] ", i);
383 prefix[21] = '\0';
384
385 ASCII(prefix, argv[i]);
386 }
387}
388
389void _fr_tacacs_packet_log_hex(fr_log_t const *log, fr_tacacs_packet_t const *packet, size_t packet_len, char const *file, int line)
390{
391 size_t length, data_len;
392 uint8_t const *p = (uint8_t const *) packet;
393 uint8_t const *hdr, *end, *args;
394 uint8_t const *data;
395
396 end = ((uint8_t const *) packet) + packet_len;
397
398 if (packet_len < 12) {
399 print_hex(log, file, line, "header ", p, packet_len);
400 return;
401 }
402
403 /*
404 * It has to be at least 12 bytes long.
405 */
406 PRINT(" major %d", (p[0] & 0xf0) >> 4);
407 PRINT(" minor %d", (p[0] & 0x0f));
408
409 PRINT(" type %02x", p[1]);
410 PRINT(" seq_no %02x", p[2]);
411 PRINT(" flags %02x", p[3]);
412
413 PRINT(" sessid %08x", fr_nbo_to_uint32(p + 4));
414 PRINT(" length %08x", fr_nbo_to_uint32(p + 8));
415
416 PRINT(" body");
417 length = fr_nbo_to_uint32(p + 8);
418
419 if ((p[3] & 0x01) == 0) {
420 PRINT(" ... encrypted ...");
421 return;
422 }
423
424 if (length > 65535) {
425 PRINT(" TOO LARGE");
426 return;
427 }
428
429 p += 12;
430 hdr = p;
431
432 if ((p + length) != end) {
433 PRINT("length field does not match input packet length %08lx", packet_len - 12);
434 return;
435 }
436
437#define REQUIRE(_length) do { \
438 size_t plen = _length; \
439 if ((size_t) (end - hdr) < plen) { \
440 print_hex(log, file, line, " TRUNCATED ", hdr, end - hdr); \
441 return; \
442 } \
443 p = hdr + plen; \
444 } while (0)
445
446 switch (packet->hdr.type) {
447 default:
448 print_hex(log, file, line, " data ", p, length);
449 return;
450
452 if (packet_is_authen_start_request(packet)) {
453 PRINT(" authentication-start");
454
455 REQUIRE(8);
456
457 PRINT(" action %02x", hdr[0]);
458 PRINT(" priv_lvl %02x", hdr[1]);
459 PRINT(" authen_type %02x", hdr[2]);
460 PRINT(" authen_service %02x", hdr[3]);
461 PRINT(" user_len %02x", hdr[4]);
462 PRINT(" port_len %02x", hdr[5]);
463 PRINT(" rem_addr_len %02x", hdr[6]);
464 PRINT(" data_len %02x", hdr[7]);
465
466 ASCII(" user ", hdr[4]);
467 ASCII(" port ", hdr[5]);
468 ASCII(" rem_addr ", hdr[6]);
469 HEXIT(" data ", hdr[7]); /* common auth flows */
470
471 } else if (packet_is_authen_continue(packet)) {
472 PRINT(" authentication-continue");
473
474 REQUIRE(5);
475
476 PRINT(" user_msg_len %04x", fr_nbo_to_uint16(hdr));
477 PRINT(" data_len %04x", fr_nbo_to_uint16(hdr + 2));
478 PRINT(" flags %02x", hdr[4]);
479
480 ASCII(" user_msg ", fr_nbo_to_uint16(hdr));
481 HEXIT(" data ", fr_nbo_to_uint16(hdr + 2));
482
483 } else {
485
486 PRINT(" authentication-reply");
487
488 REQUIRE(6);
489
490 PRINT(" status %02x", hdr[0]);
491 PRINT(" flags %02x", hdr[1]);
492 PRINT(" server_msg_len %04x", fr_nbo_to_uint16(hdr + 2));
493 PRINT(" data_len %04x", fr_nbo_to_uint16(hdr + 4));
494
495 ASCII(" server_msg ", fr_nbo_to_uint16(hdr + 2));
496 HEXIT(" data ", fr_nbo_to_uint16(hdr + 4));
497 }
498 break;
499
501 if (packet_is_author_request(packet)) {
502 PRINT(" authorization-request");
503 REQUIRE(8);
504
505 PRINT(" auth_method %02x", hdr[0]);
506 PRINT(" priv_lvl %02x", hdr[1]);
507 PRINT(" authen_type %02x", hdr[2]);
508 PRINT(" authen_service %02x", hdr[3]);
509 PRINT(" user_len %02x", hdr[4]);
510 PRINT(" port_len %02x", hdr[5]);
511 PRINT(" rem_addr_len %02x", hdr[6]);
512 PRINT(" arg_cnt %02x", hdr[7]);
513 args = p;
514
515 HEXIT(" argc ", hdr[7]);
516 ASCII(" user ", hdr[4]);
517 ASCII(" port ", hdr[5]);
518 ASCII(" rem_addr ", hdr[6]);
519
520 print_args(log, file, line, hdr[7], args, p, end);
521
522 } else {
523 PRINT(" authorization-reply");
524
526
527 REQUIRE(6);
528
529 PRINT(" status %02x", hdr[0]);
530 PRINT(" arg_cnt %02x", hdr[1]);
531 PRINT(" server_msg_len %04x", fr_nbo_to_uint16(hdr + 2));
532 PRINT(" data_len %04x", fr_nbo_to_uint16(hdr + 4));
533 args = p;
534
535 HEXIT(" argc ", hdr[1]);
536 ASCII(" server_msg ", fr_nbo_to_uint16(hdr + 2));
537 ASCII(" data ", fr_nbo_to_uint16(hdr + 4));
538
539 print_args(log, file, line, hdr[1], args, p, end);
540 }
541 break;
542
543 case FR_TAC_PLUS_ACCT:
544 if (packet_is_acct_request(packet)) {
545 PRINT(" accounting-request");
546
547 REQUIRE(9);
548
549 PRINT(" flags %02x", hdr[0]);
550 PRINT(" auth_method %02x", hdr[1]);
551 PRINT(" priv_lvl %02x", hdr[2]);
552 PRINT(" authen_type %02x", hdr[3]);
553 PRINT(" authen_service %02x", hdr[4]);
554 PRINT(" user_len %02x", hdr[5]);
555 PRINT(" port_len %02x", hdr[6]);
556 PRINT(" rem_addr_len %02x", hdr[7]);
557 PRINT(" arg_cnt %02x", hdr[8]);
558 args = p;
559
560 HEXIT(" argc ", hdr[8]);
561 ASCII(" user ", hdr[5]);
562 ASCII(" port ", hdr[6]);
563 ASCII(" rem_addr ", hdr[7]);
564
565 print_args(log, file, line, hdr[8], args, p, end);
566 } else {
567 PRINT(" accounting-reply");
569
570 PRINT(" authentication-reply");
571
572 REQUIRE(5);
573
574 PRINT(" server_msg_len %04x", fr_nbo_to_uint16(hdr));
575 PRINT(" data_len %04x", fr_nbo_to_uint16(hdr + 2));
576 PRINT(" status %02x", hdr[0]);
577
578 ASCII(" server_msg ", fr_nbo_to_uint16(hdr));
579 HEXIT(" data ", fr_nbo_to_uint16(hdr + 2));
580 }
581 break;
582 }
583
584 fr_assert(p == end);
585}
586
588{
589 if (instance_count > 0) {
591 return 0;
592 }
593
595
597 fail:
599 return -1;
600 }
601
604 goto fail;
605 }
606
607 instantiated = true;
608 return 0;
609}
610
612{
613 if (!instantiated) return;
614
616
617 if (--instance_count > 0) return;
618
620 instantiated = false;
621}
622
624{
625 fr_dict_attr_flags_t *flags = &da->flags;
626
627 /*
628 * No arrays in TACACS+
629 */
630 if (flags->array) {
631 fr_strerror_const("Attributes with flag 'array' cannot be used in TACACS+");
632 return false;
633 }
634
635 if ((strcmp(da->name, "Packet") == 0) &&
636 (da->depth == 1)) {
637 if (da->type != FR_TYPE_STRUCT) {
638 fr_strerror_const("The top 'Packet' attribute must of type 'struct'");
639 return false;
640 }
641
642 return true;
643 }
644
645 /*
646 * The top-level Packet is a STRUCT which contains
647 * MEMBERs with defined values.
648 */
649 if (!flags->name_only && (da->parent->type != FR_TYPE_STRUCT)) {
650 fr_strerror_const("Attributes in TACACS+ cannot have assigned values. Use DEFINE, not ATTRIBUTE");
651 return false;
652 }
653
654 switch (da->type) {
656 case FR_TYPE_INTERNAL:
657 fr_strerror_printf("Attributes of type '%s' cannot be used in TACACS+", fr_type_to_str(da->type));
658 return false;
659
660 default:
661 break;
662 }
663
664 return true;
665}
666
669 .name = "tacacs",
670 .default_type_size = 4,
671 .default_type_length = 4,
672 .attr = {
673 .valid = attr_valid,
674 },
675
676 .init = fr_tacacs_global_init,
677 .free = fr_tacacs_global_free,
678};
static int const char char buffer[256]
Definition acutest.h:576
int const char * file
Definition acutest.h:702
va_list args
Definition acutest.h:770
int const char int line
Definition acutest.h:702
unsigned int name_only
this attribute should always be referred to by name.
Definition dict.h:101
#define fr_dict_autofree(_to_free)
Definition dict.h:892
unsigned int array
Pack multiples into 1 attr.
Definition dict.h:91
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:287
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:300
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4227
#define fr_dict_autoload(_to_load)
Definition dict.h:889
char const * name
name of this protocol
Definition dict.h:448
Specifies an attribute which must be present for the module to function.
Definition dict.h:286
Values of the encryption flags.
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:299
Protocol-specific callbacks in libfreeradius-PROTOCOL.
Definition dict.h:447
static uint32_t instance_count
Definition base.c:44
talloc_free(reap)
void fr_log_hex(fr_log_t const *log, fr_log_type_t type, char const *file, int line, uint8_t const *data, size_t data_len, char const *line_prefix_fmt,...)
Print out hex block.
Definition log.c:778
void fr_log(fr_log_t const *log, fr_log_type_t type, char const *file, int line, char const *fmt,...)
Send a server log message to its destination.
Definition log.c:577
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
#define MD5_DIGEST_LENGTH
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_OCTETS
Raw octets.
unsigned int uint32_t
long int ssize_t
void fr_md5_calc(uint8_t out[static MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen)
Perform a single digest operation on a single input buffer.
unsigned char uint8_t
static uint16_t fr_nbo_to_uint16(uint8_t const data[static sizeof(uint16_t)])
Read an unsigned 16bit integer from wire format (big endian)
Definition nbo.h:146
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
Definition nbo.h:167
static fr_dict_attr_t const * attr_tacacs_authentication_flags
Definition base.c:56
static fr_dict_attr_t const * attr_tacacs_user_message
Definition base.c:73
static fr_dict_t const * dict_tacacs
Definition base.c:39
static fr_dict_attr_t const * attr_tacacs_session_id
Definition base.c:70
static fr_dict_attr_t const * attr_tacacs_server_message
Definition base.c:69
static fr_dict_attr_t const * attr_tacacs_privilege_level
Definition base.c:67
static fr_dict_attr_t const * attr_tacacs_authentication_type
Definition base.c:57
static fr_dict_attr_t const * attr_tacacs_accounting_status
Definition base.c:62
static fr_dict_attr_t const * attr_tacacs_authentication_service
Definition base.c:58
static fr_dict_attr_t const * attr_tacacs_authentication_status
Definition base.c:59
static fr_dict_attr_t const * attr_tacacs_client_port
Definition base.c:65
static fr_dict_attr_t const * attr_tacacs_remote_address
Definition base.c:68
static fr_dict_attr_t const * attr_tacacs_action
Definition base.c:54
static fr_dict_attr_t const * attr_tacacs_sequence_number
Definition base.c:71
static fr_dict_attr_t const * attr_tacacs_authorization_status
Definition base.c:61
static fr_dict_attr_t const * attr_tacacs_accounting_flags
Definition base.c:63
static fr_dict_attr_t const * attr_tacacs_data
Definition base.c:66
static bool instantiated
Definition base.c:34
static bool attr_valid(fr_dict_attr_t *da)
Definition base.c:448
int fr_tacacs_body_xor(fr_tacacs_packet_t const *pkt, uint8_t *body, size_t body_len, char const *secret, size_t secret_len)
XOR the body based on the secret key.
Definition base.c:149
fr_dict_attr_t const * attr_tacacs_length
Definition base.c:59
void _fr_tacacs_packet_log_hex(fr_log_t const *log, fr_tacacs_packet_t const *packet, size_t packet_len, char const *file, int line)
Definition base.c:389
fr_dict_attr_autoload_t libfreeradius_tacacs_dict_attr[]
Definition base.c:81
ssize_t fr_tacacs_length(uint8_t const *buffer, size_t buffer_len)
Definition base.c:211
fr_dict_attr_t const * attr_tacacs_authentication_continue_flags
Definition base.c:49
char const * fr_tacacs_packet_names[FR_TACACS_CODE_MAX]
Definition base.c:120
static void print_args(fr_log_t const *log, char const *file, int line, size_t arg_cnt, uint8_t const *argv, uint8_t const *start, uint8_t const *end)
Definition base.c:357
void fr_tacacs_global_free(void)
Definition base.c:611
static void print_hex(fr_log_t const *log, char const *file, int line, char const *prefix, uint8_t const *data, size_t datalen)
Definition base.c:306
fr_dict_attr_t const * attr_tacacs_argument_list
Definition base.c:55
fr_dict_attr_t const * attr_tacacs_chap_challenge
Definition base.c:75
int fr_tacacs_global_init(void)
Definition base.c:587
fr_dict_attr_t const * attr_tacacs_user_password
Definition base.c:73
#define PRINT(_fmt,...)
Definition base.c:355
fr_dict_attr_t const * attr_tacacs_version_major
Definition base.c:69
#define HEXIT(_prefix, _field)
Definition base.c:350
fr_dict_autoload_t libfreeradius_tacacs_dict[]
Definition base.c:39
fr_dict_attr_t const * attr_tacacs_mschap_challenge
Definition base.c:78
fr_dict_protocol_t libfreeradius_tacacs_dict_protocol
Definition base.c:668
fr_dict_attr_t const * attr_tacacs_mschap_response
Definition base.c:76
static void print_ascii(fr_log_t const *log, char const *file, int line, char const *prefix, uint8_t const *data, size_t datalen)
Definition base.c:313
fr_dict_attr_t const * attr_tacacs_version_minor
Definition base.c:70
fr_dict_attr_t const * attr_tacacs_mschap2_response
Definition base.c:77
#define REQUIRE(_length)
fr_dict_attr_t const * attr_tacacs_chap_password
Definition base.c:74
fr_dict_attr_t const * attr_tacacs_packet
Definition base.c:60
fr_dict_attr_t const * attr_tacacs_packet_body_type
Definition base.c:61
#define ASCII(_prefix, _field)
Definition base.c:344
fr_dict_attr_t const * attr_tacacs_authentication_method
Definition base.c:50
fr_dict_attr_t const * attr_tacacs_user_name
Definition base.c:72
fr_dict_attr_t const * attr_tacacs_flags
Definition base.c:58
fr_dict_attr_t const * attr_tacacs_packet_type
Definition base.c:62
VQP attributes.
#define fr_assert(_expr)
Definition rad_assert.h:38
static char * secret
static bool done
Definition radclient.c:81
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
Definition log.h:96
#define packet_is_authen_reply(p)
Definition tacacs.h:51
#define packet_is_authen_continue(p)
Definition tacacs.h:50
#define packet_is_acct_reply(p)
Definition tacacs.h:57
@ FR_TAC_PLUS_ACCT
Definition tacacs.h:67
@ FR_TAC_PLUS_AUTHEN
Definition tacacs.h:65
@ FR_TAC_PLUS_AUTHOR
Definition tacacs.h:66
#define packet_is_author_request(p)
Definition tacacs.h:53
#define packet_is_acct_request(p)
Definition tacacs.h:56
#define packet_is_authen_start_request(p)
3.4.
Definition tacacs.h:49
fr_tacacs_packet_hdr_t hdr
Definition tacacs.h:277
fr_tacacs_type_t type
Definition tacacs.h:97
@ FR_TACACS_CODE_MAX
Definition tacacs.h:317
#define packet_is_author_reply(p)
Definition tacacs.h:54
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define fr_strerror_const(_msg)
Definition strerror.h:223
#define FR_TYPE_STRUCTURAL_EXCEPT_GROUP
Definition types.h:316
#define FR_TYPE_INTERNAL
Definition types.h:320
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition types.h:455
static fr_slen_t data
Definition value.h:1293