1 /* $OpenBSD: parse.y,v 1.12 2019/04/01 11:05:41 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 5 * Copyright (c) 2001 Markus Friedl. All rights reserved. 6 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 7 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 %{ 23 #include <sys/types.h> 24 #include <sys/queue.h> 25 #include <sys/socket.h> 26 27 #include <ctype.h> 28 #include <errno.h> 29 #include <limits.h> 30 #include <netdb.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <syslog.h> 34 35 #include "radiusd.h" 36 #include "radiusd_local.h" 37 #include "log.h" 38 39 static struct radiusd *conf; 40 static struct radiusd_authentication authen; 41 static struct radiusd_client client; 42 43 static struct radiusd_module *find_module (const char *); 44 static void free_str_l (void *); 45 static struct radiusd_module_ref *create_module_ref (const char *); 46 static void radiusd_authentication_init (struct radiusd_authentication *); 47 static void radiusd_client_init (struct radiusd_client *); 48 49 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 50 static struct file { 51 TAILQ_ENTRY(file) entry; 52 FILE *stream; 53 char *name; 54 int lineno; 55 int errors; 56 } *file, *topfile; 57 struct file *pushfile(const char *); 58 int popfile(void); 59 int yyparse(void); 60 int yylex(void); 61 int yyerror(const char *, ...) 62 __attribute__((__format__ (printf, 1, 2))) 63 __attribute__((__nonnull__ (1))); 64 int kw_cmp(const void *, const void *); 65 int lookup(char *); 66 int lgetc(int); 67 int lungetc(int); 68 int findeol(void); 69 70 typedef struct { 71 union { 72 int64_t number; 73 char *string; 74 struct radiusd_listen listen; 75 int yesno; 76 struct { 77 char **v; 78 int c; 79 } str_l; 80 struct { 81 int af; 82 struct radiusd_addr addr; 83 struct radiusd_addr mask; 84 } prefix; 85 } v; 86 int lineno; 87 } YYSTYPE; 88 89 %} 90 91 %token INCLUDE LISTEN ON PORT CLIENT SECRET LOAD MODULE MSGAUTH_REQUIRED 92 %token AUTHENTICATE AUTHENTICATE_BY DECORATE_BY SET 93 %token ERROR YES NO 94 %token <v.string> STRING 95 %token <v.number> NUMBER 96 %type <v.number> optport 97 %type <v.listen> listen_addr 98 %type <v.str_l> str_l 99 %type <v.prefix> prefix 100 %type <v.yesno> yesno 101 %type <v.string> strnum 102 %% 103 104 grammar : /* empty */ 105 | grammar '\n' 106 | grammar include '\n' 107 | grammar listen '\n' 108 | grammar client '\n' 109 | grammar module '\n' 110 | grammar authenticate '\n' 111 | grammar error '\n' 112 ; 113 114 include : INCLUDE STRING { 115 struct file *nfile; 116 117 if ((nfile = pushfile($2)) == NULL) { 118 yyerror("failed to include file %s", $2); 119 free($2); 120 YYERROR; 121 } 122 free($2); 123 124 file = nfile; 125 lungetc('\n'); 126 nfile->lineno--; 127 } 128 ; 129 listen : LISTEN ON listen_addr { 130 struct radiusd_listen *n; 131 132 if ((n = malloc(sizeof(struct radiusd_listen))) 133 == NULL) { 134 outofmemory: 135 yyerror("Out of memory: %s", strerror(errno)); 136 YYERROR; 137 } 138 *n = $3; 139 TAILQ_INSERT_TAIL(&conf->listen, n, next); 140 } 141 listen_addr : STRING optport { 142 int gai_errno; 143 struct addrinfo hints, *res; 144 145 memset(&hints, 0, sizeof(hints)); 146 hints.ai_family = PF_UNSPEC; 147 hints.ai_socktype = SOCK_DGRAM; 148 hints.ai_flags = AI_PASSIVE; 149 hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; 150 151 if ((gai_errno = 152 getaddrinfo($1, NULL, &hints, &res)) != 0 || 153 res->ai_addrlen > sizeof($$.addr)) { 154 yyerror("Could not parse the address: %s: %s", 155 $1, gai_strerror(gai_errno)); 156 free($1); 157 YYERROR; 158 } 159 free($1); 160 $$.stype = res->ai_socktype; 161 $$.sproto = res->ai_protocol; 162 memcpy(&$$.addr, res->ai_addr, res->ai_addrlen); 163 $$.addr.ipv4.sin_port = ($2 == 0)? 164 htons(RADIUS_DEFAULT_PORT) : htons($2); 165 freeaddrinfo(res); 166 } 167 optport : { $$ = 0; } 168 | PORT NUMBER { $$ = $2; } 169 ; 170 client : CLIENT prefix optnl clientopts_b { 171 struct radiusd_client *client0; 172 173 if (client.secret[0] == '\0') { 174 yyerror("secret is required for client"); 175 YYERROR; 176 } 177 178 client0 = calloc(1, sizeof(struct radiusd_client)); 179 if (client0 == NULL) 180 goto outofmemory; 181 strlcpy(client0->secret, client.secret, 182 sizeof(client0->secret)); 183 client0->msgauth_required = client.msgauth_required; 184 client0->af = $2.af; 185 client0->addr = $2.addr; 186 client0->mask = $2.mask; 187 TAILQ_INSERT_TAIL(&conf->client, client0, next); 188 radiusd_client_init(&client); 189 } 190 191 clientopts_b : '{' optnl_l clientopts_l optnl_l '}' 192 | '{' optnl_l '}' /* allow empty block */ 193 ; 194 195 clientopts_l : clientopts_l nl clientopts 196 | clientopts 197 ; 198 199 clientopts : SECRET STRING { 200 if (strlcpy(client.secret, $2, sizeof(client.secret)) 201 >= sizeof(client.secret)) { 202 yyerror("secret is too long"); 203 YYERROR; 204 } 205 } 206 | MSGAUTH_REQUIRED yesno { 207 client.msgauth_required = $2; 208 } 209 ; 210 211 prefix : STRING '/' NUMBER { 212 int gai_errno, q, r; 213 struct addrinfo hints, *res; 214 215 memset(&hints, 0, sizeof(hints)); 216 hints.ai_family = PF_UNSPEC; 217 hints.ai_socktype = SOCK_DGRAM; /* dummy */ 218 hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; 219 220 if ((gai_errno = getaddrinfo($1, NULL, &hints, &res)) 221 != 0) { 222 yyerror("Could not parse the address: %s: %s", 223 $1, gai_strerror(gai_errno)); 224 free($1); 225 YYERROR; 226 } 227 free($1); 228 q = $3 >> 3; 229 r = $3 & 7; 230 switch (res->ai_family) { 231 case AF_INET: 232 if ($3 < 0 || 32 < $3) { 233 yyerror("mask len %lld is out of range", 234 (long long)$3); 235 YYERROR; 236 } 237 $$.addr.addr.ipv4 = ((struct sockaddr_in *) 238 res->ai_addr)->sin_addr; 239 $$.mask.addr.ipv4.s_addr = htonl((uint32_t) 240 ((0xffffffffffULL) << (32 - $3))); 241 break; 242 case AF_INET6: 243 if ($3 < 0 || 128 < $3) { 244 yyerror("mask len %lld is out of range", 245 (long long)$3); 246 YYERROR; 247 } 248 $$.addr.addr.ipv6 = ((struct sockaddr_in6 *) 249 res->ai_addr)->sin6_addr; 250 memset(&$$.mask.addr.ipv6, 0, 251 sizeof($$.mask.addr.ipv6)); 252 if (q > 0) 253 memset(&$$.mask.addr.ipv6, 0xff, q); 254 if (r > 0) 255 *((u_char *)&$$.mask.addr.ipv6 + q) = 256 (0xff00 >> r) & 0xff; 257 break; 258 } 259 $$.af = res->ai_family; 260 freeaddrinfo(res); 261 } 262 ; 263 module : MODULE LOAD STRING STRING { 264 struct radiusd_module *module; 265 if ((module = radiusd_module_load(conf, $4, $3)) 266 == NULL) { 267 free($3); 268 free($4); 269 YYERROR; 270 } 271 free($3); 272 free($4); 273 TAILQ_INSERT_TAIL(&conf->module, module, next); 274 } 275 | MODULE SET STRING STRING str_l { 276 struct radiusd_module *module; 277 278 module = find_module($3); 279 if (module == NULL) { 280 yyerror("module `%s' is not found", $3); 281 setstrerr: 282 free($3); 283 free($4); 284 free_str_l(&$5); 285 YYERROR; 286 } 287 if ($4[0] == '_') { 288 yyerror("setting `%s' is not allowed", $4); 289 goto setstrerr; 290 } 291 if (radiusd_module_set(module, $4, $5.c, $5.v)) { 292 yyerror("syntax error by module `%s'", $3); 293 goto setstrerr; 294 } 295 free($3); 296 free($4); 297 free_str_l(&$5); 298 } 299 ; 300 authenticate : AUTHENTICATE str_l optnl authopts_b { 301 struct radiusd_authentication *a; 302 303 if ((a = calloc(1, 304 sizeof(struct radiusd_authentication))) == NULL) { 305 free_str_l(&$2); 306 goto outofmemory; 307 } 308 a->auth = authen.auth; 309 a->deco = authen.deco; 310 a->username = $2.v; 311 312 TAILQ_INSERT_TAIL(&conf->authen, a, next); 313 radiusd_authentication_init(&authen); 314 } 315 ; 316 317 authopts_b : '{' optnl_l authopts_l optnl_l '}' 318 | '{' optnl_l '}' /* empty options */ 319 ; 320 321 authopts_l : authopts_l nl authopts 322 | authopts 323 ; 324 325 authopts : AUTHENTICATE_BY STRING { 326 struct radiusd_module_ref *modref; 327 328 modref = create_module_ref($2); 329 free($2); 330 if (modref == NULL) 331 YYERROR; 332 authen.auth = modref; 333 } 334 /* XXX decoration doesn't work for this moment. */ 335 | DECORATE_BY str_l { 336 int i; 337 struct radiusd_module_ref *modref; 338 339 for (i = 0; i < $2.c; i++) { 340 if ((modref = create_module_ref($2.v[i])) 341 == NULL) { 342 free_str_l(&$2); 343 YYERROR; 344 } 345 TAILQ_INSERT_TAIL(&authen.deco, modref, next); 346 } 347 free_str_l(&$2); 348 } 349 ; 350 str_l : str_l strnum { 351 int i; 352 char **v; 353 if ((v = calloc(sizeof(char **), $$.c + 2)) == NULL) 354 goto outofmemory; 355 for (i = 0; i < $$.c; i++) 356 v[i] = $$.v[i]; 357 v[i++] = $2; 358 v[i] = NULL; 359 $$.c++; 360 free($$.v); 361 $$.v = v; 362 } 363 | strnum { 364 if (($$.v = calloc(sizeof(char **), 2)) == NULL) 365 goto outofmemory; 366 $$.v[0] = $1; 367 $$.v[1] = NULL; 368 $$.c = 1; 369 } 370 ; 371 strnum : STRING { $$ = $1; } 372 | NUMBER { 373 /* Treat number as a string */ 374 asprintf(&($$), "%jd", (intmax_t)$1); 375 if ($$ == NULL) 376 goto outofmemory; 377 } 378 ; 379 optnl : 380 | '\n' 381 ; 382 nl : '\n' optnl /* one new line or more */ 383 ; 384 optnl_l : 385 | '\n' optnl_l 386 ; 387 yesno : YES { $$ = true; } 388 | NO { $$ = false; } 389 ; 390 %% 391 392 struct keywords { 393 const char *k_name; 394 int k_val; 395 }; 396 397 int 398 yyerror(const char *fmt, ...) 399 { 400 va_list ap; 401 char *msg; 402 403 file->errors++; 404 va_start(ap, fmt); 405 if (vasprintf(&msg, fmt, ap) == -1) 406 fatalx("yyerror vasprintf"); 407 va_end(ap); 408 logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); 409 free(msg); 410 return (0); 411 } 412 413 int 414 kw_cmp(const void *k, const void *e) 415 { 416 return (strcmp(k, ((const struct keywords *)e)->k_name)); 417 } 418 419 int 420 lookup(char *s) 421 { 422 /* this has to be sorted always */ 423 static const struct keywords keywords[] = { 424 { "authenticate", AUTHENTICATE}, 425 { "authenticate-by", AUTHENTICATE_BY}, 426 { "client", CLIENT}, 427 { "decorate-by", DECORATE_BY}, 428 { "include", INCLUDE}, 429 { "listen", LISTEN}, 430 { "load", LOAD}, 431 { "module", MODULE}, 432 { "msgauth-required", MSGAUTH_REQUIRED}, 433 { "no", NO}, 434 { "on", ON}, 435 { "port", PORT}, 436 { "secret", SECRET}, 437 { "set", SET}, 438 { "yes", YES}, 439 }; 440 const struct keywords *p; 441 442 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 443 sizeof(keywords[0]), kw_cmp); 444 445 if (p) 446 return (p->k_val); 447 else 448 return (STRING); 449 } 450 451 #define MAXPUSHBACK 128 452 453 u_char *parsebuf; 454 int parseindex; 455 u_char pushback_buffer[MAXPUSHBACK]; 456 int pushback_index = 0; 457 458 int 459 lgetc(int quotec) 460 { 461 int c, next; 462 463 if (parsebuf) { 464 /* Read character from the parsebuffer instead of input. */ 465 if (parseindex >= 0) { 466 c = parsebuf[parseindex++]; 467 if (c != '\0') 468 return (c); 469 parsebuf = NULL; 470 } else 471 parseindex++; 472 } 473 474 if (pushback_index) 475 return (pushback_buffer[--pushback_index]); 476 477 if (quotec) { 478 if ((c = getc(file->stream)) == EOF) { 479 yyerror("reached end of file while parsing " 480 "quoted string"); 481 if (file == topfile || popfile() == EOF) 482 return (EOF); 483 return (quotec); 484 } 485 return (c); 486 } 487 488 while ((c = getc(file->stream)) == '\\') { 489 next = getc(file->stream); 490 if (next != '\n') { 491 c = next; 492 break; 493 } 494 yylval.lineno = file->lineno; 495 file->lineno++; 496 } 497 498 while (c == EOF) { 499 if (file == topfile || popfile() == EOF) 500 return (EOF); 501 c = getc(file->stream); 502 } 503 return (c); 504 } 505 506 int 507 lungetc(int c) 508 { 509 if (c == EOF) 510 return (EOF); 511 if (parsebuf) { 512 parseindex--; 513 if (parseindex >= 0) 514 return (c); 515 } 516 if (pushback_index < MAXPUSHBACK-1) 517 return (pushback_buffer[pushback_index++] = c); 518 else 519 return (EOF); 520 } 521 522 int 523 findeol(void) 524 { 525 int c; 526 527 parsebuf = NULL; 528 529 /* skip to either EOF or the first real EOL */ 530 while (1) { 531 if (pushback_index) 532 c = pushback_buffer[--pushback_index]; 533 else 534 c = lgetc(0); 535 if (c == '\n') { 536 file->lineno++; 537 break; 538 } 539 if (c == EOF) 540 break; 541 } 542 return (ERROR); 543 } 544 545 int 546 yylex(void) 547 { 548 u_char buf[8096]; 549 u_char *p; 550 int quotec, next, c; 551 int token; 552 553 p = buf; 554 while ((c = lgetc(0)) == ' ' || c == '\t') 555 ; /* nothing */ 556 557 yylval.lineno = file->lineno; 558 if (c == '#') 559 while ((c = lgetc(0)) != '\n' && c != EOF) 560 ; /* nothing */ 561 562 switch (c) { 563 case '\'': 564 case '"': 565 quotec = c; 566 while (1) { 567 if ((c = lgetc(quotec)) == EOF) 568 return (0); 569 if (c == '\n') { 570 file->lineno++; 571 continue; 572 } else if (c == '\\') { 573 if ((next = lgetc(quotec)) == EOF) 574 return (0); 575 if (next == quotec || next == ' ' || 576 next == '\t') 577 c = next; 578 else if (next == '\n') { 579 file->lineno++; 580 continue; 581 } else 582 lungetc(next); 583 } else if (c == quotec) { 584 *p = '\0'; 585 break; 586 } else if (c == '\0') { 587 yyerror("syntax error"); 588 return (findeol()); 589 } 590 if (p + 1 >= buf + sizeof(buf) - 1) { 591 yyerror("string too long"); 592 return (findeol()); 593 } 594 *p++ = c; 595 } 596 yylval.v.string = strdup(buf); 597 if (yylval.v.string == NULL) 598 fatal("yylex: strdup"); 599 return (STRING); 600 } 601 602 #define allowed_to_end_number(x) \ 603 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 604 605 if (c == '-' || isdigit(c)) { 606 do { 607 *p++ = c; 608 if ((size_t)(p-buf) >= sizeof(buf)) { 609 yyerror("string too long"); 610 return (findeol()); 611 } 612 } while ((c = lgetc(0)) != EOF && isdigit(c)); 613 lungetc(c); 614 if (p == buf + 1 && buf[0] == '-') 615 goto nodigits; 616 if (c == EOF || allowed_to_end_number(c)) { 617 const char *errstr = NULL; 618 619 *p = '\0'; 620 yylval.v.number = strtonum(buf, LLONG_MIN, 621 LLONG_MAX, &errstr); 622 if (errstr) { 623 yyerror("\"%s\" invalid number: %s", 624 buf, errstr); 625 return (findeol()); 626 } 627 return (NUMBER); 628 } else { 629 nodigits: 630 while (p > buf + 1) 631 lungetc(*--p); 632 c = *--p; 633 if (c == '-') 634 return (c); 635 } 636 } 637 638 #define allowed_in_string(x) \ 639 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 640 x != '{' && x != '}' && x != '<' && x != '>' && \ 641 x != '!' && x != '=' && x != '/' && x != '#' && \ 642 x != ',')) 643 644 if (isalnum(c) || c == ':' || c == '_' || c == '*') { 645 do { 646 *p++ = c; 647 if ((size_t)(p-buf) >= sizeof(buf)) { 648 yyerror("string too long"); 649 return (findeol()); 650 } 651 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 652 lungetc(c); 653 *p = '\0'; 654 if ((token = lookup(buf)) == STRING) 655 if ((yylval.v.string = strdup(buf)) == NULL) 656 fatal("yylex: strdup"); 657 return (token); 658 } 659 if (c == '\n') { 660 yylval.lineno = file->lineno; 661 file->lineno++; 662 } 663 if (c == EOF) 664 return (0); 665 return (c); 666 } 667 668 struct file * 669 pushfile(const char *name) 670 { 671 struct file *nfile; 672 673 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 674 log_warn("%s", __func__); 675 return (NULL); 676 } 677 if ((nfile->name = strdup(name)) == NULL) { 678 log_warn("%s", __func__); 679 free(nfile); 680 return (NULL); 681 } 682 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 683 log_warn("%s: %s", __func__, nfile->name); 684 free(nfile->name); 685 free(nfile); 686 return (NULL); 687 } 688 nfile->lineno = 1; 689 TAILQ_INSERT_TAIL(&files, nfile, entry); 690 return (nfile); 691 } 692 693 int 694 popfile(void) 695 { 696 struct file *prev; 697 698 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 699 prev->errors += file->errors; 700 701 TAILQ_REMOVE(&files, file, entry); 702 fclose(file->stream); 703 free(file->name); 704 free(file); 705 file = prev; 706 return (file ? 0 : EOF); 707 } 708 709 int 710 parse_config(const char *filename, struct radiusd *radiusd) 711 { 712 int errors = 0; 713 struct radiusd_listen *l; 714 struct radiusd_module_ref *m, *mt; 715 716 conf = radiusd; 717 radiusd_conf_init(conf); 718 radiusd_authentication_init(&authen); 719 radiusd_client_init(&client); 720 authen.auth = NULL; 721 722 if ((file = pushfile(filename)) == NULL) { 723 errors++; 724 goto out; 725 } 726 topfile = file; 727 728 yyparse(); 729 errors = file->errors; 730 popfile(); 731 732 if (TAILQ_EMPTY(&conf->listen)) { 733 if ((l = malloc(sizeof(struct radiusd_listen))) == NULL) { 734 log_warn("Out of memory"); 735 return (-1); 736 } 737 l->stype = SOCK_DGRAM; 738 l->sproto = IPPROTO_UDP; 739 l->addr.ipv4.sin_family = AF_INET; 740 l->addr.ipv4.sin_len = sizeof(struct sockaddr_in); 741 l->addr.ipv4.sin_addr.s_addr = htonl(0x7F000001L); 742 l->addr.ipv4.sin_port = htons(RADIUS_DEFAULT_PORT); 743 TAILQ_INSERT_TAIL(&conf->listen, l, next); 744 } 745 TAILQ_FOREACH(l, &conf->listen, next) { 746 l->sock = -1; 747 } 748 if (authen.auth != NULL) 749 free(authen.auth); 750 TAILQ_FOREACH_SAFE(m, &authen.deco, next, mt) { 751 TAILQ_REMOVE(&authen.deco, m, next); 752 free(m); 753 } 754 out: 755 conf = NULL; 756 return (errors ? -1 : 0); 757 } 758 759 static struct radiusd_module * 760 find_module(const char *name) 761 { 762 struct radiusd_module *module; 763 764 TAILQ_FOREACH(module, &conf->module, next) { 765 if (strcmp(name, module->name) == 0) 766 return (module); 767 } 768 769 return (NULL); 770 } 771 772 static void 773 free_str_l(void *str_l0) 774 { 775 int i; 776 struct { 777 char **v; 778 int c; 779 } *str_l = str_l0; 780 781 for (i = 0; i < str_l->c; i++) 782 free(str_l->v[i]); 783 free(str_l->v); 784 } 785 786 static struct radiusd_module_ref * 787 create_module_ref(const char *modulename) 788 { 789 struct radiusd_module *module; 790 struct radiusd_module_ref *modref; 791 792 if ((module = find_module(modulename)) == NULL) { 793 yyerror("module `%s' is not found", modulename); 794 return (NULL); 795 } 796 if ((modref = calloc(1, sizeof(struct radiusd_module_ref))) == NULL) { 797 yyerror("Out of memory: %s", strerror(errno)); 798 return (NULL); 799 } 800 modref->module = module; 801 802 return (modref); 803 } 804 805 static void 806 radiusd_authentication_init(struct radiusd_authentication *auth) 807 { 808 memset(auth, 0, sizeof(struct radiusd_authentication)); 809 TAILQ_INIT(&auth->deco); 810 } 811 812 static void 813 radiusd_client_init(struct radiusd_client *clnt) 814 { 815 memset(clnt, 0, sizeof(struct radiusd_client)); 816 clnt->msgauth_required = true; 817 } 818