1/*
2*
3* radrealms.c
4*
5* A pppd plugin which is stacked on top of radius.so.  This plugin
6* allows selection of alternate set of servers based on the user's realm.
7*
8* Author: Ben McKeegan  ben@netservers.co.uk
9*
10* Copyright (C) 2002 Netservers
11*
12* This plugin may be distributed according to the terms of the GNU
13* General Public License, version 2 or (at your option) any later version.
14*
15*/
16
17static char const RCSID[] =
18    "$Id: radrealms.c,v 1.2 2004/11/14 07:26:26 paulus Exp $";
19
20#include "pppd.h"
21#include "radiusclient.h"
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25
26char pppd_version[] = VERSION;
27
28char radrealms_config[MAXPATHLEN] = "/etc/radiusclient/realms";
29
30static option_t Options[] = {
31    { "realms-config-file", o_string, &radrealms_config },
32    { NULL }
33};
34
35extern void (*radius_pre_auth_hook)(char const *user,
36				    SERVER **authserver,
37				    SERVER **acctserver);
38
39static void
40lookup_realm(char const *user,
41	     SERVER **authserver,
42	     SERVER **acctserver)
43{
44    char *realm;
45    FILE *fd;
46    SERVER *accts, *auths, *s;
47    char buffer[512], *p;
48    int line = 0;
49
50    auths = (SERVER *) malloc(sizeof(SERVER));
51    auths->max = 0;
52    accts = (SERVER *) malloc(sizeof(SERVER));
53    accts->max = 0;
54
55    realm = strrchr(user, '@');
56
57    if (realm) {
58	info("Looking up servers for realm '%s'", realm);
59    } else {
60	info("Looking up servers for DEFAULT realm");
61    }
62    if (realm) {
63	if (*(++realm) == '\0') {
64	    realm = NULL;
65	}
66    }
67
68    if ((fd = fopen(radrealms_config, "r")) == NULL) {
69	option_error("cannot open %s", radrealms_config);
70	return;
71    }
72    info("Reading %s", radrealms_config);
73
74    while ((fgets(buffer, sizeof(buffer), fd) != NULL)) {
75	line++;
76
77	if ((*buffer == '\n') || (*buffer == '#') || (*buffer == '\0'))
78	    continue;
79
80	buffer[strlen(buffer)-1] = '\0';
81
82	p = strtok(buffer, "\t ");
83
84	if (p == NULL || (strcmp(p, "authserver") !=0
85	    && strcmp(p, "acctserver"))) {
86	    fclose(fd);
87	    option_error("%s: invalid line %d: %s", radrealms_config,
88			 line, buffer);
89	    return;
90	}
91	info("Parsing '%s' entry:", p);
92	s = auths;
93	if (p[1] == 'c') {
94	    s = accts;
95	}
96	if (s->max >= SERVER_MAX)
97	    continue;
98
99	if ((p = strtok(NULL, "\t ")) == NULL) {
100	    fclose(fd);
101	    option_error("%s: realm name missing on line %d: %s",
102			 radrealms_config, line, buffer);
103	    return;
104	}
105
106	if ((realm != NULL && strcmp(p, realm) == 0) ||
107	    (realm == NULL && strcmp(p, "DEFAULT") == 0) ) {
108	    info(" - Matched realm %s", p);
109	    if ((p = strtok(NULL, ":")) == NULL) {
110		fclose(fd);
111		option_error("%s: server address missing on line %d: %s",
112			     radrealms_config, line, buffer);
113		return;
114	    }
115	    s->name[s->max] = strdup(p);
116	    info(" - Address is '%s'",p);
117	    if ((p = strtok(NULL, "\t ")) == NULL) {
118		fclose(fd);
119		option_error("%s: server port missing on line %d:  %s",
120			     radrealms_config, line, buffer);
121		return;
122	    }
123	    s->port[s->max] = atoi(p);
124	    info(" - Port is '%d'", s->port[s->max]);
125	    s->max++;
126	} else
127	    info(" - Skipping realm '%s'", p);
128    }
129    fclose(fd);
130
131    if (accts->max)
132	*acctserver = accts;
133
134    if (auths->max)
135	*authserver = auths;
136
137    return;
138}
139
140void
141plugin_init(void)
142{
143    radius_pre_auth_hook = lookup_realm;
144
145    add_options(Options);
146    info("RADIUS Realms plugin initialized.");
147}
148