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