yp_access.c revision 14240
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 <rpc/rpc.h> 35#include <rpcsvc/yp.h> 36#include <rpcsvc/yppasswd.h> 37#include <sys/types.h> 38#include <sys/socket.h> 39#include <netinet/in.h> 40#include <arpa/inet.h> 41#include <sys/stat.h> 42#include <paths.h> 43#include <errno.h> 44#include <sys/param.h> 45#include "yp_extern.h" 46#ifdef TCP_WRAPPER 47#include "tcpd.h" 48#endif 49 50#ifndef lint 51static const char rcsid[] = "$Id$"; 52#endif 53 54extern int debug; 55 56char *yp_procs[] = { "ypproc_null" , 57 "ypproc_domain", 58 "ypproc_domain_nonack", 59 "ypproc_match", 60 "ypproc_first", 61 "ypproc_next", 62 "ypproc_xfr", 63 "ypproc_clear", 64 "ypproc_all", 65 "ypproc_master", 66 "ypproc_order", 67 "ypproc_maplist" 68 }; 69 70#ifdef TCP_WRAPPER 71void load_securenets() 72{ 73} 74#else 75struct securenet { 76 struct in_addr net; 77 struct in_addr mask; 78 struct securenet *next; 79}; 80 81struct securenet *securenets; 82 83#define LINEBUFSZ 1024 84 85/* 86 * Read /var/yp/securenets file and initialize the securenets 87 * list. If the file doesn't exist, we set up a dummy entry that 88 * allows all hosts to connect. 89 */ 90void load_securenets() 91{ 92 FILE *fp; 93 char path[MAXPATHLEN + 2]; 94 char linebuf[1024 + 2]; 95 struct securenet *tmp; 96 97 /* 98 * If securenets is not NULL, we are being called to reload 99 * the list; free the existing list before re-reading the 100 * securenets file. 101 */ 102 if (securenets != NULL) { 103 while(securenets) { 104 tmp = securenets->next; 105 free(securenets->net); 106 free(securenets->mask); 107 free(securenets); 108 securenets = tmp; 109 } 110 } 111 112 snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir); 113 114 if ((fp = fopen(path, "r")) == NULL) { 115 if (errno == ENOENT) { 116 securenets = (struct securenet *)malloc(sizeof(struct securenet)); 117 securenets->net.s_addr = INADDR_ANY; 118 securenets->mask.s_addr = INADDR_BROADCAST; 119 securenets->next = NULL; 120 return; 121 } else { 122 yp_error("fopen(%s) failed: %s", path, strerror(errno)); 123 exit(1); 124 } 125 } 126 127 securenets = NULL; 128 129 while(fgets(linebuf, LINEBUFSZ, fp)) { 130 char addr1[20], addr2[20]; 131 132 if (linebuf[0] == '#') 133 continue; 134 if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) { 135 yp_error("badly formatted securenets entry: %s", 136 linebuf); 137 continue; 138 } 139 140 tmp = (struct securenet *)malloc(sizeof(struct securenet)); 141 142 if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) { 143 yp_error("badly formatted securenets entry: %s", addr1); 144 free(tmp); 145 continue; 146 } 147 148 if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) { 149 yp_error("badly formatted securenets entry: %s", addr2); 150 free(tmp); 151 continue; 152 } 153 154 tmp->next = securenets; 155 securenets = tmp; 156 } 157 158 fclose(fp); 159 160} 161#endif 162 163/* 164 * Access control functions. 165 * 166 * yp_access() checks the mapname and client host address and watches for 167 * the following things: 168 * 169 * - If the client is referencing one of the master.passwd.* maps, it must 170 * be using a privileged port to make its RPC to us. If it is, then we can 171 * assume that the caller is root and allow the RPC to succeed. If it 172 * isn't access is denied. 173 * 174 * - The client's IP address is checked against the securenets rules. 175 * There are two kinds of securenets support: the built-in support, 176 * which is very simple and depends on the presense of a 177 * /var/yp/securenets file, and tcp-wrapper support, which requires 178 * Wietse Venema's libwrap.a and tcpd.h. (Since the tcp-wrapper 179 * package does not ship with FreeBSD, we use the built-in support 180 * by default. Users can recompile the server the tcp-wrapper library 181 * if they already have it installed and want to use hosts.allow and 182 * hosts.deny to control access instead od having a seperate securenets 183 * file.) 184 * 185 * If no /var/yp/securenets file is present, the host access checks 186 * are bypassed and all hosts are allowed to connect. 187 * 188 * The yp_validdomain() functions checks the domain specified by the caller 189 * to make sure it's actually served by this server. This is more a sanity 190 * check than an a security check, but this seems to be the best place for 191 * it. 192 */ 193 194int yp_access(map, rqstp) 195 const char *map; 196 const struct svc_req *rqstp; 197{ 198 struct sockaddr_in *rqhost; 199 int status = 0; 200 unsigned long oldaddr; 201#ifndef TCP_WRAPPER 202 struct securenet *tmp; 203#endif 204 205 rqhost = svc_getcaller(rqstp->rq_xprt); 206 207 if (debug) { 208 yp_error("Procedure %s called from %s:%d", 209 /* Hack to allow rpc.yppasswdd to use this routine */ 210 rqstp->rq_prog == YPPASSWDPROG ? 211 "yppasswdproc_update" : 212 yp_procs[rqstp->rq_proc], inet_ntoa(rqhost->sin_addr), 213 ntohs(rqhost->sin_port)); 214 if (map != NULL) 215 yp_error("Client is referencing map \"%s\".", map); 216 } 217 218 /* Check the map name if one was supplied. */ 219 if (map != NULL) { 220 if ((strstr(map, "master.passwd.") || 221 rqstp->rq_proc == YPPROC_XFR) && 222 ntohs(rqhost->sin_port) > 1023) { 223 yp_error("Access to %s denied -- client not privileged", map); 224 return(1); 225 } 226 } 227 228#ifdef TCP_WRAPPER 229 status = hosts_ctl(progname, STRING_UNKNOWN, 230 inet_ntoa(rqhost->sin_addr), ""); 231#else 232 tmp = securenets; 233 while(tmp) { 234 if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr) 235 | tmp->net.s_addr) == rqhost->sin_addr.s_addr) { 236 status = 1; 237 break; 238 } 239 tmp = tmp->next; 240 } 241#endif 242 243 if (!status) { 244 if (rqhost->sin_addr.s_addr != oldaddr) { 245 yp_error("connect from %s:%d to procedure %s refused", 246 inet_ntoa(rqhost->sin_addr), 247 ntohs(rqhost->sin_port), 248 rqstp->rq_prog == YPPASSWDPROG ? 249 "yppasswdproc_update" : 250 yp_procs[rqstp->rq_proc]); 251 oldaddr = rqhost->sin_addr.s_addr; 252 } 253 return(1); 254 } 255 return(0); 256 257} 258 259int yp_validdomain(domain) 260 const char *domain; 261{ 262 struct stat statbuf; 263 char dompath[MAXPATHLEN + 2]; 264 265 if (domain == NULL || strstr(domain, "binding") || 266 !strcmp(domain, ".") || !strcmp(domain, "..") || 267 strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN) 268 return(1); 269 270 snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain); 271 272 if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode)) 273 return(1); 274 275 return(0); 276} 277