1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/socket.h> 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <malloc.h> 36 #include <syslog.h> 37 #include <sys/tiuser.h> 38 39 #define ACCFILE "/var/yp/securenets" 40 #define MAXLINE 128 41 42 typedef union { 43 struct in_addr in4; 44 struct in6_addr in6; 45 } inaddr_t; 46 47 struct seclist { 48 sa_family_t af; 49 inaddr_t mask; 50 inaddr_t net; 51 struct seclist *next; 52 }; 53 54 static int string2inaddr(char *, sa_family_t *, inaddr_t *); 55 static int addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask, 56 inaddr_t *caddr); 57 58 static struct seclist *slist; 59 static int nofile = 0; 60 61 void 62 get_secure_nets(char *daemon_name) 63 { 64 FILE *fp; 65 char strung[MAXLINE], nmask[MAXLINE], net[MAXLINE]; 66 inaddr_t maskin, netin; 67 sa_family_t maskaf, netaf; 68 struct seclist *tmp1, *tmp2; 69 int items = 0, line = 0; 70 if (fp = fopen(ACCFILE, "r")) { 71 tmp1 = (struct seclist *) malloc(sizeof (struct seclist)); 72 slist = tmp2 = tmp1; 73 while (fgets(strung, MAXLINE, fp)) { 74 line++; 75 if (strung[strlen(strung) - 1] != '\n') { 76 syslog(LOG_ERR|LOG_DAEMON, 77 "%s: %s line %d: too long\n", 78 daemon_name, ACCFILE, line); 79 exit(1); 80 } 81 if (strung[0] != '#') { 82 items++; 83 if (sscanf(strung, 84 "%46s%46s", nmask, net) < 2) { 85 86 syslog(LOG_ERR|LOG_DAEMON, 87 "%s: %s line %d: missing fields\n", 88 daemon_name, ACCFILE, line); 89 exit(1); 90 } 91 netaf = AF_UNSPEC; 92 if (! string2inaddr(net, &netaf, &netin)) { 93 syslog(LOG_ERR|LOG_DAEMON, 94 "%s: %s line %d: error in address\n", 95 daemon_name, ACCFILE, line); 96 exit(1); 97 } 98 maskaf = netaf; 99 if (! string2inaddr(nmask, &maskaf, &maskin) || 100 maskaf != netaf) { 101 syslog(LOG_ERR|LOG_DAEMON, 102 "%s: %s line %d: error in netmask\n", 103 daemon_name, ACCFILE, line); 104 exit(1); 105 } 106 if (! addrequal(netaf, &netin, &maskin, 107 &netin)) { 108 syslog(LOG_ERR|LOG_DAEMON, 109 "%s: %s line %d: netmask does not match network\n", 110 daemon_name, ACCFILE, line); 111 exit(1); 112 } 113 114 tmp1->af = netaf; 115 tmp1->mask = maskin; 116 tmp1->net = netin; 117 tmp1->next = (struct seclist *) 118 malloc(sizeof (struct seclist)); 119 tmp2 = tmp1; 120 tmp1 = tmp1->next; 121 } 122 } 123 tmp2->next = NULL; 124 /* if nothing to process, set nofile flag and free up memory */ 125 if (items == 0) { 126 free(slist); 127 nofile = 1; 128 } 129 } else { 130 syslog(LOG_WARNING|LOG_DAEMON, "%s: no %s file\n", 131 daemon_name, ACCFILE); 132 nofile = 1; 133 } 134 } 135 136 int 137 check_secure_net_ti(struct netbuf *caller, char *ypname) { 138 struct seclist *tmp; 139 sa_family_t af; 140 inaddr_t addr; 141 char buf[INET6_ADDRSTRLEN]; 142 143 if (nofile) 144 return (1); 145 146 af = ((struct sockaddr_storage *)caller->buf)->ss_family; 147 if (af == AF_INET) { 148 addr.in4 = ((struct sockaddr_in *)caller->buf)->sin_addr; 149 } else if (af == AF_INET6) { 150 addr.in6 = ((struct sockaddr_in6 *)caller->buf)->sin6_addr; 151 } else { 152 return (1); 153 } 154 155 tmp = slist; 156 while (tmp != NULL) { 157 if (af == tmp->af && 158 addrequal(af, &tmp->net, &tmp->mask, &addr)) { 159 return (1); 160 } 161 tmp = tmp->next; 162 } 163 syslog(LOG_ERR|LOG_DAEMON, "%s: access denied for %s\n", 164 ypname, inet_ntop(af, 165 (af == AF_INET6) ? (void *)&addr.in6 : 166 (void *)&addr.in4, buf, sizeof (buf))); 167 168 return (0); 169 } 170 171 172 static int 173 string2inaddr(char *string, sa_family_t *af, inaddr_t *addr) { 174 175 sa_family_t stringaf = AF_UNSPEC; 176 177 stringaf = (strchr(string, ':') != 0) ? AF_INET6 : AF_INET; 178 179 if (*af != AF_UNSPEC && strcmp(string, "host") == 0) { 180 if (*af == AF_INET) { 181 string = "255.255.255.255"; 182 stringaf = AF_INET; 183 } else if (*af == AF_INET6) { 184 string = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"; 185 stringaf = AF_INET6; 186 } 187 } 188 189 *af = stringaf; 190 if (inet_pton(*af, string, (*af == AF_INET6) ? (void *)&addr->in6 : 191 (void *)&addr->in4) != 1) { 192 return (0); 193 } 194 195 return (1); 196 } 197 198 199 static int 200 addrequal(sa_family_t af, inaddr_t *laddr, inaddr_t *mask, inaddr_t *caddr) { 201 202 if (af == AF_INET6) { 203 int i; 204 for (i = 0; i < sizeof (laddr->in6.s6_addr); i++) { 205 if ((caddr->in6.s6_addr[i] & mask->in6.s6_addr[i]) != 206 laddr->in6.s6_addr[i]) 207 return (0); 208 } 209 return (1); 210 } else if (af == AF_INET) { 211 return ((caddr->in4.s_addr & mask->in4.s_addr) == 212 laddr->in4.s_addr); 213 } else { 214 return (0); 215 } 216 } 217 218 219 static void 220 print_inaddr(char *string, sa_family_t af, inaddr_t *addr) { 221 222 char buf[INET6_ADDRSTRLEN]; 223 224 printf("%s %s %s\n", 225 string, (af == AF_INET6)?"AF_INET6":"AF_INET", 226 inet_ntop(af, (af == AF_INET6) ? (void *)&addr->in6 : 227 (void *)&addr->in4, buf, sizeof (buf))); 228 } 229