yp_access.c revision 16044
1116742Ssam/* 2116904Ssam * Copyright (c) 1995 3186904Ssam * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 4116742Ssam * 5116742Ssam * Redistribution and use in source and binary forms, with or without 6116742Ssam * modification, are permitted provided that the following conditions 7116742Ssam * are met: 8116742Ssam * 1. Redistributions of source code must retain the above copyright 9116742Ssam * notice, this list of conditions and the following disclaimer. 10116742Ssam * 2. Redistributions in binary form must reproduce the above copyright 11116742Ssam * notice, this list of conditions and the following disclaimer in the 12116742Ssam * documentation and/or other materials provided with the distribution. 13116742Ssam * 3. All advertising materials mentioning features or use of this software 14116742Ssam * must display the following acknowledgement: 15116904Ssam * This product includes software developed by Bill Paul. 16116904Ssam * 4. Neither the name of the author nor the names of any co-contributors 17116904Ssam * may be used to endorse or promote products derived from this software 18116904Ssam * without specific prior written permission. 19116904Ssam * 20116904Ssam * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21116904Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22116904Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23116904Ssam * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE 24116904Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25116904Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26116742Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27116742Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28116742Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29116742Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30116742Ssam * SUCH DAMAGE. 31116742Ssam * 32116742Ssam */ 33116742Ssam 34138568Ssam#include <stdlib.h> 35138568Ssam#include <rpc/rpc.h> 36138568Ssam#include <rpcsvc/yp.h> 37116742Ssam#include <rpcsvc/yppasswd.h> 38138568Ssam#include <sys/types.h> 39161146Ssam#include <limits.h> 40138568Ssam#include <db.h> 41138568Ssam#include <sys/socket.h> 42170530Ssam#include <netinet/in.h> 43170530Ssam#include <arpa/inet.h> 44170530Ssam#include <sys/stat.h> 45170530Ssam#include <sys/fcntl.h> 46170530Ssam#include <paths.h> 47170530Ssam#include <errno.h> 48170530Ssam#include <sys/param.h> 49170530Ssam#include "yp_extern.h" 50138568Ssam#ifdef TCP_WRAPPER 51170530Ssam#include "tcpd.h" 52170530Ssam#endif 53170530Ssam 54170530Ssam#ifndef lint 55170530Ssamstatic const char rcsid[] = "$Id: yp_access.c,v 1.7 1996/04/28 04:38:47 wpaul Exp $"; 56170530Ssam#endif 57170530Ssam 58170530Ssamextern int debug; 59170530Ssam 60170530Ssam /* NIS v1 */ 61170530Ssamchar *yp_procs[] = { "ypoldproc_null", 62170530Ssam "ypoldproc_domain", 63173273Ssam "ypoldproc_domain_nonack", 64138568Ssam "ypoldproc_match", 65170530Ssam "ypoldproc_first", 66170530Ssam "ypoldproc_next", 67193239Ssam "ypoldproc_poll", 68170530Ssam "ypoldproc_push", 69170530Ssam "ypoldproc_get", 70170530Ssam "badproc1", /* placeholder */ 71170530Ssam "badproc2", /* placeholder */ 72138568Ssam "badproc3", /* placeholder */ 73170530Ssam 74170530Ssam /* NIS v2 */ 75138568Ssam "ypproc_null" , 76170530Ssam "ypproc_domain", 77138568Ssam "ypproc_domain_nonack", 78138568Ssam "ypproc_match", 79170530Ssam "ypproc_first", 80170530Ssam "ypproc_next", 81170530Ssam "ypproc_xfr", 82170530Ssam "ypproc_clear", 83170530Ssam "ypproc_all", 84170530Ssam "ypproc_master", 85170530Ssam "ypproc_order", 86170530Ssam "ypproc_maplist" 87193239Ssam }; 88138568Ssam 89138568Ssam 90138568Ssam#ifdef TCP_WRAPPER 91138568Ssamvoid load_securenets() 92138568Ssam{ 93121180Ssam} 94170530Ssam#else 95170530Ssamstruct securenet { 96170530Ssam struct in_addr net; 97170530Ssam struct in_addr mask; 98170530Ssam struct securenet *next; 99170530Ssam}; 100170530Ssam 101170530Ssamstruct securenet *securenets; 102170530Ssam 103170530Ssam#define LINEBUFSZ 1024 104170530Ssam 105170530Ssam/* 106193239Ssam * Read /var/yp/securenets file and initialize the securenets 107170530Ssam * list. If the file doesn't exist, we set up a dummy entry that 108170530Ssam * allows all hosts to connect. 109170530Ssam */ 110170530Ssamvoid load_securenets() 111170530Ssam{ 112170530Ssam FILE *fp; 113170530Ssam char path[MAXPATHLEN + 2]; 114170530Ssam char linebuf[1024 + 2]; 115170530Ssam struct securenet *tmp; 116170530Ssam 117170530Ssam /* 118170530Ssam * If securenets is not NULL, we are being called to reload 119170530Ssam * the list; free the existing list before re-reading the 120170530Ssam * securenets file. 121170530Ssam */ 122170530Ssam while(securenets) { 123170530Ssam tmp = securenets->next; 124170530Ssam free(securenets); 125170530Ssam securenets = tmp; 126170530Ssam } 127170530Ssam 128170530Ssam snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir); 129170530Ssam 130170530Ssam if ((fp = fopen(path, "r")) == NULL) { 131170530Ssam if (errno == ENOENT) { 132170530Ssam securenets = (struct securenet *)malloc(sizeof(struct securenet)); 133170530Ssam securenets->net.s_addr = INADDR_ANY; 134170530Ssam securenets->mask.s_addr = INADDR_ANY; 135170530Ssam securenets->next = NULL; 136170530Ssam return; 137170530Ssam } else { 138170530Ssam yp_error("fopen(%s) failed: %s", path, strerror(errno)); 139170530Ssam exit(1); 140170530Ssam } 141170530Ssam } 142170530Ssam 143170530Ssam securenets = NULL; 144170530Ssam 145170530Ssam while(fgets(linebuf, LINEBUFSZ, fp)) { 146170530Ssam char addr1[20], addr2[20]; 147170530Ssam 148170530Ssam if (linebuf[0] == '#') 149170530Ssam continue; 150170530Ssam if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) { 151170530Ssam yp_error("badly formatted securenets entry: %s", 152170530Ssam linebuf); 153170530Ssam continue; 154170530Ssam } 155170530Ssam 156170530Ssam tmp = (struct securenet *)malloc(sizeof(struct securenet)); 157170530Ssam 158170530Ssam if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) { 159170530Ssam yp_error("badly formatted securenets entry: %s", addr1); 160170530Ssam free(tmp); 161170530Ssam continue; 162170530Ssam } 163170530Ssam 164170530Ssam if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) { 165170530Ssam yp_error("badly formatted securenets entry: %s", addr2); 166170530Ssam free(tmp); 167170530Ssam continue; 168170530Ssam } 169170530Ssam 170170530Ssam tmp->next = securenets; 171170530Ssam securenets = tmp; 172170530Ssam } 173170530Ssam 174170530Ssam fclose(fp); 175170530Ssam 176170530Ssam} 177170530Ssam#endif 178170530Ssam 179170530Ssam/* 180170530Ssam * Access control functions. 181170530Ssam * 182170530Ssam * yp_access() checks the mapname and client host address and watches for 183170530Ssam * the following things: 184170530Ssam * 185170530Ssam * - If the client is referencing one of the master.passwd.* maps, it must 186170530Ssam * be using a privileged port to make its RPC to us. If it is, then we can 187170530Ssam * assume that the caller is root and allow the RPC to succeed. If it 188170530Ssam * isn't access is denied. 189170530Ssam * 190170530Ssam * - The client's IP address is checked against the securenets rules. 191170530Ssam * There are two kinds of securenets support: the built-in support, 192173273Ssam * which is very simple and depends on the presence of a 193170530Ssam * /var/yp/securenets file, and tcp-wrapper support, which requires 194170530Ssam * Wietse Venema's libwrap.a and tcpd.h. (Since the tcp-wrapper 195170530Ssam * package does not ship with FreeBSD, we use the built-in support 196170530Ssam * by default. Users can recompile the server with the tcp-wrapper library 197173273Ssam * if they already have it installed and want to use hosts.allow and 198173273Ssam * hosts.deny to control access instead of having a seperate securenets 199173273Ssam * file.) 200173273Ssam * 201178354Ssam * If no /var/yp/securenets file is present, the host access checks 202178354Ssam * are bypassed and all hosts are allowed to connect. 203173273Ssam * 204173273Ssam * The yp_validdomain() function checks the domain specified by the caller 205173273Ssam * to make sure it's actually served by this server. This is more a sanity 206173273Ssam * check than an a security check, but this seems to be the best place for 207173273Ssam * it. 208173273Ssam */ 209173273Ssam 210173273Ssamint yp_access(map, rqstp) 211173273Ssam const char *map; 212182829Ssam const struct svc_req *rqstp; 213173273Ssam{ 214173273Ssam struct sockaddr_in *rqhost; 215173273Ssam int status = 0; 216178354Ssam static unsigned long oldaddr = 0; 217178354Ssam#ifndef TCP_WRAPPER 218178354Ssam struct securenet *tmp; 219178354Ssam#endif 220178354Ssam char *yp_procedure = NULL; 221186904Ssam 222190579Ssam yp_procedure = rqstp->rq_prog == YPPASSWDPROG ? "yppasswdprog_update" : 223193239Ssam yp_procs[rqstp->rq_proc + (12 * (rqstp->rq_vers - 1))]; 224193239Ssam 225193239Ssam rqhost = svc_getcaller(rqstp->rq_xprt); 226195618Srpaulo 227195618Srpaulo if (debug) { 228195618Srpaulo yp_error("Procedure %s called from %s:%d", yp_procedure, 229195618Srpaulo inet_ntoa(rqhost->sin_addr), 230195618Srpaulo ntohs(rqhost->sin_port)); 231195618Srpaulo if (map != NULL) 232195618Srpaulo yp_error("Client is referencing map \"%s\".", map); 233195618Srpaulo } 234195618Srpaulo 235195618Srpaulo /* Check the map name if one was supplied. */ 236195618Srpaulo if (map != NULL) { 237195618Srpaulo if ((strstr(map, "master.passwd.") || 238195784Srpaulo rqstp->rq_proc == YPPROC_XFR) && 239195784Srpaulo ntohs(rqhost->sin_port) > 1023) { 240195784Srpaulo yp_error("Access to %s denied -- client not privileged", map); 241195784Srpaulo return(1); 242195757Ssam } 243195908Srpaulo } 244232244Sadrian 245234018Sadrian#ifdef TCP_WRAPPER 246234018Sadrian status = hosts_ctl(progname, STRING_UNKNOWN, 247234018Sadrian inet_ntoa(rqhost->sin_addr), ""); 248234018Sadrian#else 249234018Sadrian tmp = securenets; 250121180Ssam while(tmp) { 251121180Ssam if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr) 252138568Ssam | tmp->net.s_addr) == rqhost->sin_addr.s_addr) { 253138568Ssam status = 1; 254138568Ssam break; 255138568Ssam } 256138568Ssam tmp = tmp->next; 257138568Ssam } 258138568Ssam#endif 259138568Ssam 260138568Ssam if (!status) { 261138568Ssam if (rqhost->sin_addr.s_addr != oldaddr) { 262138568Ssam yp_error("connect from %s:%d to procedure %s refused", 263138568Ssam inet_ntoa(rqhost->sin_addr), 264138568Ssam ntohs(rqhost->sin_port), 265138568Ssam yp_procedure); 266138568Ssam oldaddr = rqhost->sin_addr.s_addr; 267173273Ssam } 268138568Ssam return(1); 269138568Ssam } 270170530Ssam return(0); 271170530Ssam 272170530Ssam} 273170530Ssam 274170530Ssamint yp_validdomain(domain) 275138568Ssam const char *domain; 276138568Ssam{ 277170530Ssam struct stat statbuf; 278170530Ssam char dompath[MAXPATHLEN + 2]; 279170530Ssam 280170530Ssam if (domain == NULL || strstr(domain, "binding") || 281138568Ssam !strcmp(domain, ".") || !strcmp(domain, "..") || 282138568Ssam strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN) 283138568Ssam return(1); 284138568Ssam 285138568Ssam snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain); 286138568Ssam 287138568Ssam if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode)) 288170530Ssam return(1); 289170530Ssam 290138568Ssam 291138568Ssam return(0); 292138568Ssam} 293138568Ssam