yp_access.c revision 14302
1/* 2 * Copyright (c) 1995 3 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34#include <stdlib.h> 35#include <rpc/rpc.h> 36#include <rpcsvc/yp.h> 37#include <rpcsvc/yppasswd.h> 38#include <sys/types.h> 39#include <sys/socket.h> 40#include <netinet/in.h> 41#include <arpa/inet.h> 42#include <sys/stat.h> 43#include <paths.h> 44#include <errno.h> 45#include <sys/param.h> 46#include "yp_extern.h" 47#ifdef TCP_WRAPPER 48#include "tcpd.h" 49#endif 50 51#ifndef lint 52static const char rcsid[] = "$Id: yp_access.c,v 1.5 1996/02/26 02:34:23 wpaul Exp $"; 53#endif 54 55extern int debug; 56 57 /* NIS v1 */ 58char *yp_procs[] = { "ypoldproc_null", 59 "ypoldproc_domain", 60 "ypoldproc_domain_nonack", 61 "ypoldproc_match", 62 "ypoldproc_first", 63 "ypoldproc_next", 64 "ypoldproc_poll", 65 "ypoldproc_push", 66 "ypoldproc_get", 67 "badproc1", /* placeholder */ 68 "badproc2", /* placeholder */ 69 "badproc3", /* placeholder */ 70 71 /* NIS v2 */ 72 "ypproc_null" , 73 "ypproc_domain", 74 "ypproc_domain_nonack", 75 "ypproc_match", 76 "ypproc_first", 77 "ypproc_next", 78 "ypproc_xfr", 79 "ypproc_clear", 80 "ypproc_all", 81 "ypproc_master", 82 "ypproc_order", 83 "ypproc_maplist" 84 }; 85 86 87#ifdef TCP_WRAPPER 88void load_securenets() 89{ 90} 91#else 92struct securenet { 93 struct in_addr net; 94 struct in_addr mask; 95 struct securenet *next; 96}; 97 98struct securenet *securenets; 99 100#define LINEBUFSZ 1024 101 102/* 103 * Read /var/yp/securenets file and initialize the securenets 104 * list. If the file doesn't exist, we set up a dummy entry that 105 * allows all hosts to connect. 106 */ 107void load_securenets() 108{ 109 FILE *fp; 110 char path[MAXPATHLEN + 2]; 111 char linebuf[1024 + 2]; 112 struct securenet *tmp; 113 114 /* 115 * If securenets is not NULL, we are being called to reload 116 * the list; free the existing list before re-reading the 117 * securenets file. 118 */ 119 if (securenets != NULL) { 120 while(securenets) { 121 tmp = securenets->next; 122 free(securenets); 123 securenets = tmp; 124 } 125 } 126 127 snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir); 128 129 if ((fp = fopen(path, "r")) == NULL) { 130 if (errno == ENOENT) { 131 securenets = (struct securenet *)malloc(sizeof(struct securenet)); 132 securenets->net.s_addr = INADDR_ANY; 133 securenets->mask.s_addr = INADDR_ANY; 134 securenets->next = NULL; 135 return; 136 } else { 137 yp_error("fopen(%s) failed: %s", path, strerror(errno)); 138 exit(1); 139 } 140 } 141 142 securenets = NULL; 143 144 while(fgets(linebuf, LINEBUFSZ, fp)) { 145 char addr1[20], addr2[20]; 146 147 if (linebuf[0] == '#') 148 continue; 149 if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) { 150 yp_error("badly formatted securenets entry: %s", 151 linebuf); 152 continue; 153 } 154 155 tmp = (struct securenet *)malloc(sizeof(struct securenet)); 156 157 if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) { 158 yp_error("badly formatted securenets entry: %s", addr1); 159 free(tmp); 160 continue; 161 } 162 163 if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) { 164 yp_error("badly formatted securenets entry: %s", addr2); 165 free(tmp); 166 continue; 167 } 168 169 tmp->next = securenets; 170 securenets = tmp; 171 } 172 173 fclose(fp); 174 175} 176#endif 177 178/* 179 * Access control functions. 180 * 181 * yp_access() checks the mapname and client host address and watches for 182 * the following things: 183 * 184 * - If the client is referencing one of the master.passwd.* maps, it must 185 * be using a privileged port to make its RPC to us. If it is, then we can 186 * assume that the caller is root and allow the RPC to succeed. If it 187 * isn't access is denied. 188 * 189 * - The client's IP address is checked against the securenets rules. 190 * There are two kinds of securenets support: the built-in support, 191 * which is very simple and depends on the presense of a 192 * /var/yp/securenets file, and tcp-wrapper support, which requires 193 * Wietse Venema's libwrap.a and tcpd.h. (Since the tcp-wrapper 194 * package does not ship with FreeBSD, we use the built-in support 195 * by default. Users can recompile the server the tcp-wrapper library 196 * if they already have it installed and want to use hosts.allow and 197 * hosts.deny to control access instead od having a seperate securenets 198 * file.) 199 * 200 * If no /var/yp/securenets file is present, the host access checks 201 * are bypassed and all hosts are allowed to connect. 202 * 203 * The yp_validdomain() functions checks the domain specified by the caller 204 * to make sure it's actually served by this server. This is more a sanity 205 * check than an a security check, but this seems to be the best place for 206 * it. 207 */ 208 209int yp_access(map, rqstp) 210 const char *map; 211 const struct svc_req *rqstp; 212{ 213 struct sockaddr_in *rqhost; 214 int status = 0; 215 unsigned long oldaddr; 216#ifndef TCP_WRAPPER 217 struct securenet *tmp; 218#endif 219 char *yp_procedure = NULL; 220 221 yp_procedure = rqstp->rq_prog == YPPASSWDPROG ? "yppasswdprog_update" : 222 yp_procs[rqstp->rq_proc + (12 * (rqstp->rq_vers - 1))]; 223 224 rqhost = svc_getcaller(rqstp->rq_xprt); 225 226 if (debug) { 227 yp_error("Procedure %s called from %s:%d", yp_procedure, 228 inet_ntoa(rqhost->sin_addr), 229 ntohs(rqhost->sin_port)); 230 if (map != NULL) 231 yp_error("Client is referencing map \"%s\".", map); 232 } 233 234 /* Check the map name if one was supplied. */ 235 if (map != NULL) { 236 if ((strstr(map, "master.passwd.") || 237 rqstp->rq_proc == YPPROC_XFR) && 238 ntohs(rqhost->sin_port) > 1023) { 239 yp_error("Access to %s denied -- client not privileged", map); 240 return(1); 241 } 242 } 243 244#ifdef TCP_WRAPPER 245 status = hosts_ctl(progname, STRING_UNKNOWN, 246 inet_ntoa(rqhost->sin_addr), ""); 247#else 248 tmp = securenets; 249 while(tmp) { 250 if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr) 251 | tmp->net.s_addr) == rqhost->sin_addr.s_addr) { 252 status = 1; 253 break; 254 } 255 tmp = tmp->next; 256 } 257#endif 258 259 if (!status) { 260 if (rqhost->sin_addr.s_addr != oldaddr) { 261 yp_error("connect from %s:%d to procedure %s refused", 262 inet_ntoa(rqhost->sin_addr), 263 ntohs(rqhost->sin_port), 264 yp_procedure); 265 oldaddr = rqhost->sin_addr.s_addr; 266 } 267 return(1); 268 } 269 return(0); 270 271} 272 273int yp_validdomain(domain) 274 const char *domain; 275{ 276 struct stat statbuf; 277 char dompath[MAXPATHLEN + 2]; 278 279 if (domain == NULL || strstr(domain, "binding") || 280 !strcmp(domain, ".") || !strcmp(domain, "..") || 281 strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN) 282 return(1); 283 284 snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain); 285 286 if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode)) 287 return(1); 288 289 return(0); 290} 291