/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #define ACCFILE "/var/yp/securenets" #define MAXLINE 128 typedef union { struct in_addr in4; struct in6_addr in6; } inaddr_t; struct seclist { sa_family_t af; inaddr_t mask; inaddr_t net; struct seclist *next; }; static int string2inaddr(char *, sa_family_t *, inaddr_t *); static int addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask, inaddr_t *caddr); static struct seclist *slist; static int nofile = 0; void get_secure_nets(char *daemon_name) { FILE *fp; char strung[MAXLINE], nmask[MAXLINE], net[MAXLINE]; inaddr_t maskin, netin; sa_family_t maskaf, netaf; struct seclist *tmp1, *tmp2; int items = 0, line = 0; if (fp = fopen(ACCFILE, "r")) { tmp1 = (struct seclist *) malloc(sizeof (struct seclist)); slist = tmp2 = tmp1; while (fgets(strung, MAXLINE, fp)) { line++; if (strung[strlen(strung) - 1] != '\n') { syslog(LOG_ERR|LOG_DAEMON, "%s: %s line %d: too long\n", daemon_name, ACCFILE, line); exit(1); } if (strung[0] != '#') { items++; if (sscanf(strung, "%46s%46s", nmask, net) < 2) { syslog(LOG_ERR|LOG_DAEMON, "%s: %s line %d: missing fields\n", daemon_name, ACCFILE, line); exit(1); } netaf = AF_UNSPEC; if (! string2inaddr(net, &netaf, &netin)) { syslog(LOG_ERR|LOG_DAEMON, "%s: %s line %d: error in address\n", daemon_name, ACCFILE, line); exit(1); } maskaf = netaf; if (! string2inaddr(nmask, &maskaf, &maskin) || maskaf != netaf) { syslog(LOG_ERR|LOG_DAEMON, "%s: %s line %d: error in netmask\n", daemon_name, ACCFILE, line); exit(1); } if (! addrequal(netaf, &netin, &maskin, &netin)) { syslog(LOG_ERR|LOG_DAEMON, "%s: %s line %d: netmask does not match network\n", daemon_name, ACCFILE, line); exit(1); } tmp1->af = netaf; tmp1->mask = maskin; tmp1->net = netin; tmp1->next = (struct seclist *) malloc(sizeof (struct seclist)); tmp2 = tmp1; tmp1 = tmp1->next; } } tmp2->next = NULL; /* if nothing to process, set nofile flag and free up memory */ if (items == 0) { free(slist); nofile = 1; } } else { syslog(LOG_WARNING|LOG_DAEMON, "%s: no %s file\n", daemon_name, ACCFILE); nofile = 1; } } int check_secure_net_ti(struct netbuf *caller, char *ypname) { struct seclist *tmp; sa_family_t af; inaddr_t addr; char buf[INET6_ADDRSTRLEN]; if (nofile) return (1); af = ((struct sockaddr_storage *)caller->buf)->ss_family; if (af == AF_INET) { addr.in4 = ((struct sockaddr_in *)caller->buf)->sin_addr; } else if (af == AF_INET6) { addr.in6 = ((struct sockaddr_in6 *)caller->buf)->sin6_addr; } else { return (1); } tmp = slist; while (tmp != NULL) { if (af == tmp->af && addrequal(af, &tmp->net, &tmp->mask, &addr)) { return (1); } tmp = tmp->next; } syslog(LOG_ERR|LOG_DAEMON, "%s: access denied for %s\n", ypname, inet_ntop(af, (af == AF_INET6) ? (void *)&addr.in6 : (void *)&addr.in4, buf, sizeof (buf))); return (0); } static int string2inaddr(char *string, sa_family_t *af, inaddr_t *addr) { sa_family_t stringaf = AF_UNSPEC; stringaf = (strchr(string, ':') != 0) ? AF_INET6 : AF_INET; if (*af != AF_UNSPEC && strcmp(string, "host") == 0) { if (*af == AF_INET) { string = "255.255.255.255"; stringaf = AF_INET; } else if (*af == AF_INET6) { string = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"; stringaf = AF_INET6; } } *af = stringaf; if (inet_pton(*af, string, (*af == AF_INET6) ? (void *)&addr->in6 : (void *)&addr->in4) != 1) { return (0); } return (1); } static int addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask, inaddr_t *caddr) { if (af == AF_INET6) { int i; for (i = 0; i < sizeof (laddr->in6.s6_addr); i++) { if ((caddr->in6.s6_addr[i] & mask->in6.s6_addr[i]) != laddr->in6.s6_addr[i]) return (0); } return (1); } else if (af == AF_INET) { return ((caddr->in4.s_addr & mask->in4.s_addr) == laddr->in4.s_addr); } else { return (0); } } static void print_inaddr(char *string, sa_family_t af, inaddr_t *addr) { char buf[INET6_ADDRSTRLEN]; printf("%s %s %s\n", string, (af == AF_INET6)?"AF_INET6":"AF_INET", inet_ntop(af, (af == AF_INET6) ? (void *)&addr->in6 : (void *)&addr->in4, buf, sizeof (buf))); }