/* * files.c Read config files into memory. * * Version: $Id: client.c,v 1.21 2003/02/19 15:19:57 cmiller Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2000 The FreeRADIUS server project * Copyright 2000 Miquel van Smoorenburg * Copyright 2000 Alan DeKok */ static const char rcsid[] = "$Id: client.c,v 1.21 2003/02/19 15:19:57 cmiller Exp $"; #include "autoconf.h" #include "libradius.h" #include #if HAVE_NETINET_IN_H # include #endif #include #include #include #include #include #include "radiusd.h" #include "conffile.h" /* * Free a RADCLIENT list. */ void clients_free(RADCLIENT *cl) { RADCLIENT *next; while(cl) { next = cl->next; free(cl); cl = next; } } /* * Read the clients file. */ int read_clients_file(const char *file) { FILE *fp; RADCLIENT *c; char buffer[256]; char hostnm[256]; char secret[256]; char shortnm[256]; uint32_t mask; int lineno = 0; char *p; clients_free(mainconfig.clients); mainconfig.clients = NULL; if ((fp = fopen(file, "r")) == NULL) { /* The clients file is no longer required. All configuration information is read from radiusd.conf and friends. If clients exists it will be used, but if it doesn't no harm done. */ return 0; } while(fgets(buffer, 256, fp) != NULL) { lineno++; if (!feof(fp) && (strchr(buffer, '\n') == NULL)) { radlog(L_ERR, "%s[%d]: line too long", file, lineno); return -1; } /* * Skip whitespace. */ p = buffer; while (*p && ((*p == ' ') || (*p == '\t'))) p++; /* * Skip comments and blank lines. */ if ((*p == '#') || (*p == '\n') || (*p == '\r')) continue; if (!getword(&p, hostnm, sizeof(hostnm)) || !getword(&p, secret, sizeof(secret))) { radlog(L_ERR, "%s[%d]: unexpected end of line", file, lineno); return -1; } (void)getword(&p, shortnm, sizeof(shortnm)); /* * Look for a mask in the hostname */ p = strchr(hostnm, '/'); mask = ~0; if (p) { int i, mask_length; *p = '\0'; p++; mask_length = atoi(p); if ((mask_length < 0) || (mask_length > 32)) { radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.", file, lineno, p); return -1; } mask = (1 << 31); for (i = 1; i < mask_length; i++) { mask |= (mask >> 1); } } /* * Double-check lengths to be sure they're sane */ if (strlen(hostnm) >= sizeof(c->longname)) { radlog(L_ERR, "%s[%d]: host name of length %d is greater than the allowed maximum of %d.", file, lineno, strlen(hostnm), sizeof(c->longname) - 1); return -1; } if (strlen(secret) >= sizeof(c->secret)) { radlog(L_ERR, "%s[%d]: secret of length %d is greater than the allowed maximum of %d.", file, lineno, strlen(secret), sizeof(c->secret) - 1); return -1; } if (strlen(shortnm) > sizeof(c->shortname)) { radlog(L_ERR, "%s[%d]: short name of length %d is greater than the allowed maximum of %d.", file, lineno, strlen(shortnm), sizeof(c->shortname) - 1); return -1; } /* * It should be OK now, let's create the buffer. */ c = rad_malloc(sizeof(RADCLIENT)); memset(c, 0, sizeof(*c)); c->ipaddr = ip_getaddr(hostnm); if (c->ipaddr == INADDR_NONE) { radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s", file, lineno, hostnm); return -1; } c->netmask = htonl(mask); c->ipaddr &= c->netmask; /* addr & mask are in network order */ strcpy((char *)c->secret, secret); strcpy(c->shortname, shortnm); /* * Only do DNS lookups for machines. Just print * the network as the long name. */ if ((~mask) == 0) { NAS *nas; ip_hostname(c->longname, sizeof(c->longname), c->ipaddr); /* * Pull information over from the NAS. */ nas = nas_find(c->ipaddr); if (nas) { /* * No short name in the 'clients' file, * try copying one over from the * 'naslist' file. */ if (c->shortname[0] == '\0') { strcpy(c->shortname, nas->shortname); } /* * Copy the nastype over, too. */ strcpy(c->nastype, nas->nastype); } } else { hostnm[strlen(hostnm)] = '/'; strNcpy(c->longname, hostnm, sizeof(c->longname)); } c->next = mainconfig.clients; mainconfig.clients = c; } fclose(fp); return 0; } /* * Find a client in the RADCLIENTS list. */ RADCLIENT *client_find(uint32_t ipaddr) { RADCLIENT *cl; RADCLIENT *match = NULL; for (cl = mainconfig.clients; cl; cl = cl->next) { if ((ipaddr & cl->netmask) == cl->ipaddr) { if ((!match) || (ntohl(cl->netmask) > ntohl(match->netmask))) { match = cl; } } } return match; } /* * Walk the RADCLIENT list displaying the clients. This function * is for debugging purposes. */ void client_walk(void) { RADCLIENT *cl; char host_ipaddr[16]; for (cl = mainconfig.clients; cl != NULL; cl = cl->next) radlog(L_ERR, "client: client_walk: %s\n", ip_ntoa(host_ipaddr, cl->ipaddr)); } /* * Find the name of a client (prefer short name). */ const char *client_name(uint32_t ipaddr) { /* We don't call this unless we should know about the client. */ RADCLIENT *cl; char host_ipaddr[16]; if ((cl = client_find(ipaddr)) != NULL) { if (cl->shortname[0]) return cl->shortname; else return cl->longname; } /* * this isn't normally reachable, but if a loggable event happens just * after a client list change and a HUP, then we may not know this * information any more. * * If you see lots of these, then there's something wrong. */ radlog(L_ERR, "Trying to look up name of unknown client %s.\n", ip_ntoa(host_ipaddr, ipaddr)); return "UNKNOWN-CLIENT"; }