1/* 2 * $Id: config.c,v 1.1.1.1 2008/10/15 03:30:50 james26_jang Exp $ 3 * 4 * Copyright (C) 1995,1996,1997 Lars Fenneberg 5 * 6 * Copyright 1992 Livingston Enterprises, Inc. 7 * 8 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan 9 * and Merit Network, Inc. All Rights Reserved 10 * 11 * See the file COPYRIGHT for the respective terms and conditions. 12 * If the file is missing contact me at lf@elemental.net 13 * and I'll send you a copy. 14 * 15 */ 16 17#include <config.h> 18#include <includes.h> 19#include <radiusclient.h> 20#include <options.h> 21 22static int test_config(char *); 23 24/* 25 * Function: find_option 26 * 27 * Purpose: find an option in the option list 28 * 29 * Returns: pointer to option on success, NULL otherwise 30 */ 31 32static OPTION *find_option(char *optname, unsigned int type) 33{ 34 int i; 35 36 /* there're so few options that a binary search seems not necessary */ 37 for (i = 0; i < num_options; i++) { 38 if (!strcmp(config_options[i].name, optname) && 39 (config_options[i].type & type)) 40 return &config_options[i]; 41 } 42 43 return NULL; 44} 45 46/* 47 * Function: set_option_... 48 * 49 * Purpose: set a specific option doing type conversions 50 * 51 * Returns: 0 on success, -1 on failure 52 */ 53 54static int set_option_str(char *filename, int line, OPTION *option, char *p) 55{ 56 if (p) 57 option->val = (void *) strdup(p); 58 else 59 option->val = NULL; 60 61 return 0; 62} 63 64static int set_option_int(char *filename, int line, OPTION *option, char *p) 65{ 66 int *iptr; 67 68 if (p == NULL) { 69 rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line); 70 return (-1); 71 } 72 73 if ((iptr = (int *) malloc(sizeof(iptr))) == NULL) { 74 rc_log(LOG_CRIT, "read_config: out of memory"); 75 return (-1); 76 } 77 78 *iptr = atoi(p); 79 option->val = (void *) iptr; 80 81 return 0; 82} 83 84static int set_option_srv(char *filename, int line, OPTION *option, char *p) 85{ 86 SERVER *serv; 87 char *q; 88 struct servent *svp; 89 int i; 90 91 if (p == NULL) { 92 rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line); 93 return (-1); 94 } 95 96 serv = (SERVER *) option->val; 97 98 for (i = 0; i < serv->max; i++) { 99 free(serv->name[i]); 100 } 101 serv->max = 0; 102 103 while ((p = strtok(p, ", \t")) != NULL) { 104 105 if ((q = strchr(p,':')) != NULL) { 106 *q = '\0'; 107 q++; 108 serv->port[serv->max] = atoi(q); 109 } else { 110 if (!strcmp(option->name,"authserver")) 111 if ((svp = getservbyname ("radius", "udp")) == NULL) 112 serv->port[serv->max] = PW_AUTH_UDP_PORT; 113 else 114 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port); 115 else if (!strcmp(option->name, "acctserver")) 116 if ((svp = getservbyname ("radacct", "udp")) == NULL) 117 serv->port[serv->max] = PW_ACCT_UDP_PORT; 118 else 119 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port); 120 else { 121 rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name); 122 return (-1); 123 } 124 } 125 126 serv->name[serv->max++] = strdup(p); 127 128 p = NULL; 129 } 130 131 return 0; 132} 133 134static int set_option_auo(char *filename, int line, OPTION *option, char *p) 135{ 136 int *iptr; 137 138 if (p == NULL) { 139 rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line); 140 return (-1); 141 } 142 143 if ((iptr = (int *) malloc(sizeof(iptr))) == NULL) { 144 rc_log(LOG_CRIT, "read_config: out of memory"); 145 return (-1); 146 } 147 148 *iptr = 0; 149 p = strtok(p, ", \t"); 150 151 if (!strncmp(p, "local", 5)) 152 *iptr = AUTH_LOCAL_FST; 153 else if (!strncmp(p, "radius", 6)) 154 *iptr = AUTH_RADIUS_FST; 155 else { 156 rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p); 157 return (-1); 158 } 159 160 p = strtok(NULL, ", \t"); 161 162 if (p && (*p != '\0')) { 163 if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p, "local")) 164 *iptr = (*iptr) | AUTH_LOCAL_SND; 165 else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p, "radius")) 166 *iptr = (*iptr) | AUTH_RADIUS_SND; 167 else { 168 rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p); 169 return (-1); 170 } 171 } 172 173 option->val = (void *) iptr; 174 175 return 0; 176} 177 178 179/* 180 * Function: rc_read_config 181 * 182 * Purpose: read the global config file 183 * 184 * Returns: 0 on success, -1 when failure 185 */ 186 187int rc_read_config(char *filename) 188{ 189 FILE *configfd; 190 char buffer[512], *p; 191 OPTION *option; 192 int line, pos; 193 194 if ((configfd = fopen(filename,"r")) == NULL) 195 { 196 rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno)); 197 return (-1); 198 } 199 200 line = 0; 201 while ((fgets(buffer, sizeof(buffer), configfd) != NULL)) 202 { 203 line++; 204 p = buffer; 205 206 if ((*p == '\n') || (*p == '#') || (*p == '\0')) 207 continue; 208 209 p[strlen(p)-1] = '\0'; 210 211 212 if ((pos = strcspn(p, "\t ")) == 0) { 213 rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p); 214 return (-1); 215 } 216 217 p[pos] = '\0'; 218 219 if ((option = find_option(p, OT_ANY)) == NULL) { 220 rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p); 221 return (-1); 222 } 223 224 if (option->status != ST_UNDEF) { 225 rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p); 226 return (-1); 227 } 228 229 p += pos+1; 230 while (isspace(*p)) 231 p++; 232 233 switch (option->type) { 234 case OT_STR: 235 if (set_option_str(filename, line, option, p) < 0) 236 return (-1); 237 break; 238 case OT_INT: 239 if (set_option_int(filename, line, option, p) < 0) 240 return (-1); 241 break; 242 case OT_SRV: 243 if (set_option_srv(filename, line, option, p) < 0) 244 return (-1); 245 break; 246 case OT_AUO: 247 if (set_option_auo(filename, line, option, p) < 0) 248 return (-1); 249 break; 250 default: 251 rc_log(LOG_CRIT, "rc_read_config: impossible case branch!"); 252 abort(); 253 } 254 } 255 fclose(configfd); 256 257 return test_config(filename); 258} 259 260/* 261 * Function: rc_conf_str, rc_conf_int, rc_conf_src 262 * 263 * Purpose: get the value of a config option 264 * 265 * Returns: config option value 266 */ 267 268char *rc_conf_str(char *optname) 269{ 270 OPTION *option; 271 272 option = find_option(optname, OT_STR); 273 274 if (option != NULL) { 275 return (char *)option->val; 276 } else { 277 rc_log(LOG_CRIT, "rc_conf_str: unkown config option requested: %s", optname); 278 abort(); 279 } 280} 281 282int rc_conf_int(char *optname) 283{ 284 OPTION *option; 285 286 option = find_option(optname, OT_INT|OT_AUO); 287 288 if (option != NULL) { 289 return *((int *)option->val); 290 } else { 291 rc_log(LOG_CRIT, "rc_conf_int: unkown config option requested: %s", optname); 292 abort(); 293 } 294} 295 296SERVER *rc_conf_srv(char *optname) 297{ 298 OPTION *option; 299 300 option = find_option(optname, OT_SRV); 301 302 if (option != NULL) { 303 return (SERVER *)option->val; 304 } else { 305 rc_log(LOG_CRIT, "rc_conf_srv: unkown config option requested: %s", optname); 306 abort(); 307 } 308} 309 310/* 311 * Function: test_config 312 * 313 * Purpose: test the configuration the user supplied 314 * 315 * Returns: 0 on success, -1 when failure 316 */ 317 318static int test_config(char *filename) 319{ 320#if 0 321 struct stat st; 322 char *file; 323#endif 324 325 if (!(rc_conf_srv("authserver")->max)) 326 { 327 rc_log(LOG_ERR,"%s: no authserver specified", filename); 328 return (-1); 329 } 330 if (!(rc_conf_srv("acctserver")->max)) 331 { 332 rc_log(LOG_ERR,"%s: no acctserver specified", filename); 333 return (-1); 334 } 335 if (!rc_conf_str("servers")) 336 { 337 rc_log(LOG_ERR,"%s: no servers file specified", filename); 338 return (-1); 339 } 340 if (!rc_conf_str("dictionary")) 341 { 342 rc_log(LOG_ERR,"%s: no dictionary specified", filename); 343 return (-1); 344 } 345 346 if (rc_conf_int("radius_timeout") <= 0) 347 { 348 rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename); 349 return (-1); 350 } 351 if (rc_conf_int("radius_retries") <= 0) 352 { 353 rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename); 354 return (-1); 355 } 356 357#if 0 358 file = rc_conf_str("login_local"); 359 if (stat(file, &st) == 0) 360 { 361 if (!S_ISREG(st.st_mode)) { 362 rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); 363 return (-1); 364 } 365 } else { 366 rc_log(LOG_ERR,"%s: file not found: %s", filename, file); 367 return (-1); 368 } 369 file = rc_conf_str("login_radius"); 370 if (stat(file, &st) == 0) 371 { 372 if (!S_ISREG(st.st_mode)) { 373 rc_log(LOG_ERR,"%s: not a regular file: %s", filename, file); 374 return (-1); 375 } 376 } else { 377 rc_log(LOG_ERR,"%s: file not found: %s", filename, file); 378 return (-1); 379 } 380#endif 381 382 if (rc_conf_int("login_tries") <= 0) 383 { 384 rc_log(LOG_ERR,"%s: login_tries <= 0 is illegal", filename); 385 return (-1); 386 } 387 if (rc_conf_str("seqfile") == NULL) 388 { 389 rc_log(LOG_ERR,"%s: seqfile not specified", filename); 390 return (-1); 391 } 392 if (rc_conf_int("login_timeout") <= 0) 393 { 394 rc_log(LOG_ERR,"%s: login_timeout <= 0 is illegal", filename); 395 return (-1); 396 } 397 if (rc_conf_str("mapfile") == NULL) 398 { 399 rc_log(LOG_ERR,"%s: mapfile not specified", filename); 400 return (-1); 401 } 402 if (rc_conf_str("nologin") == NULL) 403 { 404 rc_log(LOG_ERR,"%s: nologin not specified", filename); 405 return (-1); 406 } 407 408 return 0; 409} 410 411/* 412 * Function: rc_find_match 413 * 414 * Purpose: see if ip_addr is one of the ip addresses of hostname 415 * 416 * Returns: 0 on success, -1 when failure 417 * 418 */ 419 420static int find_match (UINT4 *ip_addr, char *hostname) 421{ 422 UINT4 addr; 423 char **paddr; 424 struct hostent *hp; 425 426 if (rc_good_ipaddr (hostname) == 0) 427 { 428 if (*ip_addr == ntohl(inet_addr (hostname))) 429 { 430 return (0); 431 } 432 } 433 else 434 { 435 if ((hp = gethostbyname (hostname)) == (struct hostent *) NULL) 436 { 437 return (-1); 438 } 439 for (paddr = hp->h_addr_list; *paddr; paddr++) 440 { 441 addr = ** (UINT4 **) paddr; 442 if (ntohl(addr) == *ip_addr) 443 { 444 return (0); 445 } 446 } 447 } 448 return (-1); 449} 450 451/* 452 * Function: rc_find_server 453 * 454 * Purpose: search a server in the servers file 455 * 456 * Returns: 0 on success, -1 on failure 457 * 458 */ 459 460int rc_find_server (char *server_name, UINT4 *ip_addr, char *secret) 461{ 462 UINT4 myipaddr = 0; 463 int len; 464 int result; 465 FILE *clientfd; 466 char *h; 467 char *s; 468 char *host2; 469 char buffer[128]; 470 char hostnm[AUTH_ID_LEN + 1]; 471 472 /* Get the IP address of the authentication server */ 473 if ((*ip_addr = rc_get_ipaddr (server_name)) == (UINT4) 0) 474 return (-1); 475 476 if ((clientfd = fopen (rc_conf_str("servers"), "r")) == (FILE *) NULL) 477 { 478 rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str("servers")); 479 return (-1); 480 } 481 482 myipaddr = rc_own_ipaddress(); 483 484 result = 0; 485 while (fgets (buffer, sizeof (buffer), clientfd) != (char *) NULL) 486 { 487 if (*buffer == '#') 488 continue; 489 490 if ((h = strtok (buffer, " \t\n")) == NULL) /* first hostname */ 491 continue; 492 493 memset (hostnm, '\0', AUTH_ID_LEN); 494 len = strlen (h); 495 if (len > AUTH_ID_LEN) 496 { 497 len = AUTH_ID_LEN; 498 } 499 strncpy (hostnm, h, (size_t) len); 500 hostnm[AUTH_ID_LEN] = '\0'; 501 502 if ((s = strtok (NULL, " \t\n")) == NULL) /* and secret field */ 503 continue; 504 505 memset (secret, '\0', MAX_SECRET_LENGTH); 506 len = strlen (s); 507 if (len > MAX_SECRET_LENGTH) 508 { 509 len = MAX_SECRET_LENGTH; 510 } 511 strncpy (secret, s, (size_t) len); 512 secret[MAX_SECRET_LENGTH] = '\0'; 513 514 if (!strchr (hostnm, '/')) /* If single name form */ 515 { 516 if (find_match (ip_addr, hostnm) == 0) 517 { 518 result++; 519 break; 520 } 521 } 522 else /* <name1>/<name2> "paired" form */ 523 { 524 strtok (hostnm, "/"); 525 if (find_match (&myipaddr, hostnm) == 0) 526 { /* If we're the 1st name, target is 2nd */ 527 host2 = strtok (NULL, " "); 528 if (find_match (ip_addr, host2) == 0) 529 { 530 result++; 531 break; 532 } 533 } 534 else /* If we were 2nd name, target is 1st name */ 535 { 536 if (find_match (ip_addr, hostnm) == 0) 537 { 538 result++; 539 break; 540 } 541 } 542 } 543 } 544 fclose (clientfd); 545 if (result == 0) 546 { 547 memset (buffer, '\0', sizeof (buffer)); 548 memset (secret, '\0', sizeof (secret)); 549 rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s", 550 server_name, rc_conf_str("servers")); 551 return (-1); 552 } 553 return 0; 554} 555