ypbind.c revision 226690
133965Sjdp/* 2130561Sobrien * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 3218822Sdim * All rights reserved. 433965Sjdp * 533965Sjdp * Redistribution and use in source and binary forms, with or without 633965Sjdp * modification, are permitted provided that the following conditions 7104834Sobrien * are met: 833965Sjdp * 1. Redistributions of source code must retain the above copyright 9104834Sobrien * notice, this list of conditions and the following disclaimer. 10104834Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11104834Sobrien * notice, this list of conditions and the following disclaimer in the 12104834Sobrien * documentation and/or other materials provided with the distribution. 1333965Sjdp * 3. The name of the author may not be used to endorse or promote 14104834Sobrien * products derived from this software without specific prior written 15104834Sobrien * permission. 16104834Sobrien * 17104834Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 1833965Sjdp * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19104834Sobrien * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20104834Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21218822Sdim * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2233965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23218822Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2433965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2533965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2633965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2733965Sjdp * SUCH DAMAGE. 2833965Sjdp */ 2933965Sjdp 3033965Sjdp#include <sys/cdefs.h> 3133965Sjdp__FBSDID("$FreeBSD: head/usr.sbin/ypbind/ypbind.c 226690 2011-10-24 14:35:31Z glebius $"); 3233965Sjdp 3333965Sjdp#include <sys/param.h> 3433965Sjdp#include <sys/types.h> 3533965Sjdp#include <sys/wait.h> 3633965Sjdp#include <sys/ioctl.h> 3733965Sjdp#include <sys/mman.h> 3833965Sjdp#include <sys/signal.h> 3933965Sjdp#include <sys/socket.h> 4033965Sjdp#include <sys/file.h> 4133965Sjdp#include <sys/fcntl.h> 4233965Sjdp#include <sys/stat.h> 4333965Sjdp#include <sys/uio.h> 4433965Sjdp#include <ctype.h> 4533965Sjdp#include <dirent.h> 46218822Sdim#include <err.h> 4733965Sjdp#include <errno.h> 48218822Sdim#include <netdb.h> 49218822Sdim#include <signal.h> 50218822Sdim#include <stdio.h> 5133965Sjdp#include <stdlib.h> 5233965Sjdp#include <string.h> 5360484Sobrien#include <syslog.h> 5460484Sobrien#include <unistd.h> 55218822Sdim#include <rpc/rpc.h> 56218822Sdim#include <rpc/xdr.h> 57218822Sdim#include <net/if.h> 58218822Sdim#include <netinet/in.h> 59218822Sdim#include <arpa/inet.h> 60218822Sdim#include <rpc/pmap_clnt.h> 61218822Sdim#include <rpc/pmap_prot.h> 62218822Sdim#include <rpc/pmap_rmt.h> 63218822Sdim#include <rpc/rpc_com.h> 64218822Sdim#include <rpcsvc/yp.h> 6578828Sobrien#include <rpcsvc/ypclnt.h> 6678828Sobrien#include "yp_ping.h" 6778828Sobrien 6878828Sobrien#ifndef BINDINGDIR 6978828Sobrien#define BINDINGDIR "/var/yp/binding" 7078828Sobrien#endif 71218822Sdim 72218822Sdim#ifndef YPBINDLOCK 7378828Sobrien#define YPBINDLOCK "/var/run/ypbind.lock" 7478828Sobrien#endif 7578828Sobrien 76218822Sdimstruct _dom_binding { 7778828Sobrien struct _dom_binding *dom_pnext; 78218822Sdim char dom_domain[YPMAXDOMAIN + 1]; 79218822Sdim struct sockaddr_in dom_server_addr; 80218822Sdim long int dom_vers; 8160484Sobrien int dom_lockfd; 8233965Sjdp int dom_alive; 8333965Sjdp int dom_broadcast_pid; 8433965Sjdp int dom_pipe_fds[2]; 85130561Sobrien int dom_default; 86218822Sdim}; 8733965Sjdp 8889857Sobrien#define READFD ypdb->dom_pipe_fds[0] 89104834Sobrien#define WRITEFD ypdb->dom_pipe_fds[1] 90218822Sdim#define BROADFD broad_domain->dom_pipe_fds[1] 9133965Sjdp 92130561Sobrienextern bool_t xdr_domainname(), xdr_ypbind_resp(); 9333965Sjdpextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 94130561Sobrienextern bool_t xdr_ypbind_setdom(); 9533965Sjdp 9633965Sjdpvoid checkwork(void); 9733965Sjdpvoid *ypbindproc_null_2_yp(SVCXPRT *, void *, CLIENT *); 9833965Sjdpvoid *ypbindproc_setdom_2_yp(SVCXPRT *, struct ypbind_setdom *, CLIENT *); 9933965Sjdpvoid rpc_received(char *, struct sockaddr_in *, int); 100218822Sdimvoid broadcast(struct _dom_binding *); 101218822Sdimint ping(struct _dom_binding *); 10233965Sjdpint tell_parent(char *, struct sockaddr_in *); 10333965Sjdpvoid handle_children(struct _dom_binding *); 10433965Sjdpvoid reaper(int); 10533965Sjdpvoid terminate(int); 10633965Sjdpvoid yp_restricted_mode(char *); 107104834Sobrienint verify(struct in_addr); 10833965Sjdp 10933965Sjdpchar *domain_name; 11033965Sjdpstruct _dom_binding *ypbindlist; 11133965Sjdpstatic struct _dom_binding *broad_domain; 11233965Sjdp 11333965Sjdp#define YPSET_NO 0 114218822Sdim#define YPSET_LOCAL 1 11533965Sjdp#define YPSET_ALL 2 11633965Sjdpint ypsetmode = YPSET_NO; 11733965Sjdpint ypsecuremode = 0; 11833965Sjdpint ppid; 11933965Sjdp 12033965Sjdp#define NOT_RESPONDING_HYSTERESIS 10 12133965Sjdpstatic int not_responding_count = 0; 12233965Sjdp 12333965Sjdp/* 12433965Sjdp * Special restricted mode variables: when in restricted mode, only the 12533965Sjdp * specified restricted_domain will be bound, and only the servers listed 12633965Sjdp * in restricted_addrs will be used for binding. 12733965Sjdp */ 12833965Sjdp#define RESTRICTED_SERVERS 10 12933965Sjdpint yp_restricted = 0; 13033965Sjdpint yp_manycast = 0; 13133965Sjdpstruct in_addr restricted_addrs[RESTRICTED_SERVERS]; 13233965Sjdp 13333965Sjdp/* No more than MAX_CHILDREN child broadcasters at a time. */ 13433965Sjdp#ifndef MAX_CHILDREN 13533965Sjdp#define MAX_CHILDREN 5 13633965Sjdp#endif 137218822Sdim/* No more than MAX_DOMAINS simultaneous domains */ 13833965Sjdp#ifndef MAX_DOMAINS 13933965Sjdp#define MAX_DOMAINS 200 14033965Sjdp#endif 14133965Sjdp/* RPC timeout value */ 142130561Sobrien#ifndef FAIL_THRESHOLD 143218822Sdim#define FAIL_THRESHOLD 20 14433965Sjdp#endif 145218822Sdim 146218822Sdim/* Number of times to fish for a response froma particular set of hosts */ 147218822Sdim#ifndef MAX_RETRIES 148218822Sdim#define MAX_RETRIES 30 149218822Sdim#endif 150218822Sdim 151218822Sdimint retries = 0; 152218822Sdimint children = 0; 153218822Sdimint domains = 0; 154218822Sdimint yplockfd; 155218822Sdimfd_set fdsr; 156218822Sdim 157218822SdimSVCXPRT *udptransp, *tcptransp; 158218822Sdim 159218822Sdimvoid * 160218822Sdimypbindproc_null_2_yp(SVCXPRT *transp, void *argp, CLIENT *clnt) 161218822Sdim{ 162218822Sdim static char res; 163218822Sdim 164218822Sdim bzero(&res, sizeof(res)); 165218822Sdim return &res; 166218822Sdim} 167218822Sdim 168218822Sdimstruct ypbind_resp * 16933965Sjdpypbindproc_domain_2_yp(SVCXPRT *transp, domainname *argp, CLIENT *clnt) 17033965Sjdp{ 171218822Sdim static struct ypbind_resp res; 172218822Sdim struct _dom_binding *ypdb; 173218822Sdim char path[MAXPATHLEN]; 174218822Sdim 175218822Sdim bzero(&res, sizeof res); 176218822Sdim res.ypbind_status = YPBIND_FAIL_VAL; 17733965Sjdp res.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV; 178218822Sdim 17933965Sjdp if (strchr(*argp, '/')) { 18033965Sjdp syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ 18133965Sjdprejecting.", *argp); 18233965Sjdp return(&res); 183218822Sdim } 18433965Sjdp 18533965Sjdp for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 18633965Sjdp if (strcmp(ypdb->dom_domain, *argp) == 0) 18733965Sjdp break; 18833965Sjdp } 18933965Sjdp 19033965Sjdp if (ypdb == NULL) { 191130561Sobrien if (yp_restricted) { 192218822Sdim syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", *argp); 19333965Sjdp return (&res); 194218822Sdim } 19533965Sjdp 19633965Sjdp if (domains >= MAX_DOMAINS) { 19733965Sjdp syslog(LOG_WARNING, "domain limit (%d) exceeded", 19833965Sjdp MAX_DOMAINS); 19933965Sjdp res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 20033965Sjdp return (&res); 20133965Sjdp } 20233965Sjdp ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 20333965Sjdp if (ypdb == NULL) { 204130561Sobrien syslog(LOG_WARNING, "malloc: %m"); 20533965Sjdp res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 20633965Sjdp return (&res); 20733965Sjdp } 20833965Sjdp bzero(ypdb, sizeof *ypdb); 209104834Sobrien strncpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain); 21033965Sjdp ypdb->dom_vers = YPVERS; 211130561Sobrien ypdb->dom_alive = 0; 21233965Sjdp ypdb->dom_default = 0; 21333965Sjdp ypdb->dom_lockfd = -1; 21433965Sjdp sprintf(path, "%s/%s.%ld", BINDINGDIR, 21533965Sjdp ypdb->dom_domain, ypdb->dom_vers); 216104834Sobrien unlink(path); 21733965Sjdp ypdb->dom_pnext = ypbindlist; 218130561Sobrien ypbindlist = ypdb; 21933965Sjdp domains++; 22033965Sjdp } 22133965Sjdp 22233965Sjdp if (ping(ypdb)) { 22333965Sjdp return (&res); 22433965Sjdp } 22533965Sjdp 22633965Sjdp res.ypbind_status = YPBIND_SUCC_VAL; 22733965Sjdp res.ypbind_resp_u.ypbind_error = 0; /* Success */ 22833965Sjdp *(u_int32_t *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr = 22933965Sjdp ypdb->dom_server_addr.sin_addr.s_addr; 23033965Sjdp *(u_short *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port = 23133965Sjdp ypdb->dom_server_addr.sin_port; 23233965Sjdp /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 23333965Sjdp inet_ntoa(ypdb->dom_server_addr.sin_addr), 23433965Sjdp ntohs(ypdb->dom_server_addr.sin_port));*/ 23533965Sjdp return (&res); 23633965Sjdp} 23733965Sjdp 23833965Sjdpvoid * 239218822Sdimypbindproc_setdom_2_yp(SVCXPRT *transp, ypbind_setdom *argp, CLIENT *clnt) 24033965Sjdp{ 24133965Sjdp struct sockaddr_in *fromsin, bindsin; 24233965Sjdp static char *result = NULL; 24333965Sjdp 24433965Sjdp if (strchr(argp->ypsetdom_domain, '/')) { 24533965Sjdp syslog(LOG_WARNING, "Domain name '%s' has embedded slash -- \ 24633965Sjdprejecting.", argp->ypsetdom_domain); 24733965Sjdp return(NULL); 24833965Sjdp } 24933965Sjdp fromsin = svc_getcaller(transp); 250130561Sobrien 25133965Sjdp switch (ypsetmode) { 25233965Sjdp case YPSET_LOCAL: 25333965Sjdp if (fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 25433965Sjdp svcerr_noprog(transp); 255130561Sobrien return(NULL); 25633965Sjdp } 25733965Sjdp break; 25833965Sjdp case YPSET_ALL: 25933965Sjdp break; 260130561Sobrien case YPSET_NO: 26133965Sjdp default: 26233965Sjdp svcerr_noprog(transp); 26333965Sjdp return(NULL); 26433965Sjdp } 26533965Sjdp 26633965Sjdp if (ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 26733965Sjdp svcerr_noprog(transp); 26833965Sjdp return(NULL); 26933965Sjdp } 27033965Sjdp 27133965Sjdp if (argp->ypsetdom_vers != YPVERS) { 27233965Sjdp svcerr_noprog(transp); 27333965Sjdp return(NULL); 27433965Sjdp } 27533965Sjdp 27633965Sjdp bzero(&bindsin, sizeof bindsin); 27733965Sjdp bindsin.sin_family = AF_INET; 27833965Sjdp bindsin.sin_addr.s_addr = *(u_int32_t *)argp->ypsetdom_binding.ypbind_binding_addr; 27933965Sjdp bindsin.sin_port = *(u_short *)argp->ypsetdom_binding.ypbind_binding_port; 280218822Sdim rpc_received(argp->ypsetdom_domain, &bindsin, 1); 28133965Sjdp 282218822Sdim return((void *) &result); 283218822Sdim} 284218822Sdim 285218822Sdimvoid 286218822Sdimypbindprog_2(struct svc_req *rqstp, register SVCXPRT *transp) 287218822Sdim{ 288218822Sdim union { 289218822Sdim domainname ypbindproc_domain_2_arg; 290218822Sdim struct ypbind_setdom ypbindproc_setdom_2_arg; 291218822Sdim } argument; 292218822Sdim struct authunix_parms *creds; 293218822Sdim char *result; 294218822Sdim bool_t (*xdr_argument)(), (*xdr_result)(); 295218822Sdim char *(*local)(); 296218822Sdim 297218822Sdim switch (rqstp->rq_proc) { 298218822Sdim case YPBINDPROC_NULL: 299218822Sdim xdr_argument = xdr_void; 300218822Sdim xdr_result = xdr_void; 301218822Sdim local = (char *(*)()) ypbindproc_null_2_yp; 302218822Sdim break; 303218822Sdim 304218822Sdim case YPBINDPROC_DOMAIN: 305218822Sdim xdr_argument = xdr_domainname; 306218822Sdim xdr_result = xdr_ypbind_resp; 307218822Sdim local = (char *(*)()) ypbindproc_domain_2_yp; 308218822Sdim break; 309218822Sdim 310218822Sdim case YPBINDPROC_SETDOM: 311218822Sdim switch (rqstp->rq_cred.oa_flavor) { 312218822Sdim case AUTH_UNIX: 313218822Sdim creds = (struct authunix_parms *)rqstp->rq_clntcred; 314218822Sdim if (creds->aup_uid != 0) { 31533965Sjdp svcerr_auth(transp, AUTH_BADCRED); 316218822Sdim return; 317218822Sdim } 318218822Sdim break; 319218822Sdim default: 320218822Sdim svcerr_auth(transp, AUTH_TOOWEAK); 321218822Sdim return; 32233965Sjdp } 323218822Sdim 32433965Sjdp xdr_argument = xdr_ypbind_setdom; 325218822Sdim xdr_result = xdr_void; 326218822Sdim local = (char *(*)()) ypbindproc_setdom_2_yp; 327218822Sdim break; 328218822Sdim 329218822Sdim default: 330218822Sdim svcerr_noproc(transp); 331218822Sdim return; 332218822Sdim } 333218822Sdim bzero(&argument, sizeof(argument)); 334218822Sdim if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 335218822Sdim svcerr_decode(transp); 336218822Sdim return; 337218822Sdim } 338218822Sdim result = (*local)(transp, &argument, rqstp); 339218822Sdim if (result != NULL && 34033965Sjdp !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 34133965Sjdp svcerr_systemerr(transp); 34233965Sjdp } 34333965Sjdp return; 34433965Sjdp} 34533965Sjdp 34633965Sjdp/* Jack the reaper */ 34733965Sjdpvoid 34833965Sjdpreaper(int sig) 34933965Sjdp{ 350130561Sobrien int st; 351218822Sdim 352218822Sdim while (wait3(&st, WNOHANG, NULL) > 0) 353218822Sdim children--; 354218822Sdim} 355218822Sdim 35633965Sjdpvoid 357218822Sdimterminate(int sig) 35833965Sjdp{ 35989857Sobrien struct _dom_binding *ypdb; 36033965Sjdp char path[MAXPATHLEN]; 36133965Sjdp 36233965Sjdp if (ppid != getpid()) 36333965Sjdp exit(0); 36433965Sjdp 36533965Sjdp for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 36633965Sjdp close(ypdb->dom_lockfd); 36733965Sjdp if (ypdb->dom_broadcast_pid) 36833965Sjdp kill(ypdb->dom_broadcast_pid, SIGINT); 36933965Sjdp sprintf(path, "%s/%s.%ld", BINDINGDIR, 37033965Sjdp ypdb->dom_domain, ypdb->dom_vers); 37133965Sjdp unlink(path); 37233965Sjdp } 37333965Sjdp close(yplockfd); 37433965Sjdp unlink(YPBINDLOCK); 37533965Sjdp pmap_unset(YPBINDPROG, YPBINDVERS); 37633965Sjdp exit(0); 37733965Sjdp} 37833965Sjdp 37933965Sjdpint 38033965Sjdpmain(int argc, char *argv[]) 38133965Sjdp{ 38233965Sjdp struct timeval tv; 38333965Sjdp int i; 38433965Sjdp DIR *dird; 38533965Sjdp struct dirent *dirp; 38633965Sjdp struct _dom_binding *ypdb, *next; 38733965Sjdp 38833965Sjdp /* Check that another ypbind isn't already running. */ 38933965Sjdp if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) 39033965Sjdp err(1, "%s", YPBINDLOCK); 39133965Sjdp 39233965Sjdp if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) 39333965Sjdp errx(1, "another ypbind is already running. Aborting"); 39433965Sjdp 39533965Sjdp /* XXX domainname will be overriden if we use restricted mode */ 39633965Sjdp yp_get_default_domain(&domain_name); 39733965Sjdp if (domain_name[0] == '\0') 39833965Sjdp errx(1, "domainname not set. Aborting"); 39933965Sjdp 40033965Sjdp for (i = 1; i<argc; i++) { 40189857Sobrien if (strcmp("-ypset", argv[i]) == 0) 40233965Sjdp ypsetmode = YPSET_ALL; 40389857Sobrien else if (strcmp("-ypsetme", argv[i]) == 0) 40433965Sjdp ypsetmode = YPSET_LOCAL; 40533965Sjdp else if (strcmp("-s", argv[i]) == 0) 40633965Sjdp ypsecuremode++; 40789857Sobrien else if (strcmp("-S", argv[i]) == 0 && argc > i) 40833965Sjdp yp_restricted_mode(argv[++i]); 40989857Sobrien else if (strcmp("-m", argv[i]) == 0) 41033965Sjdp yp_manycast++; 41189857Sobrien else 41233965Sjdp errx(1, "unknown option: %s", argv[i]); 41389857Sobrien } 414130561Sobrien 41533965Sjdp /* blow away everything in BINDINGDIR (if it exists) */ 41633965Sjdp 41733965Sjdp if ((dird = opendir(BINDINGDIR)) != NULL) { 41833965Sjdp char path[MAXPATHLEN]; 419130561Sobrien while ((dirp = readdir(dird)) != NULL) 420218822Sdim if (strcmp(dirp->d_name, ".") && 42133965Sjdp strcmp(dirp->d_name, "..")) { 42233965Sjdp sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); 42333965Sjdp unlink(path); 424218822Sdim } 42533965Sjdp closedir(dird); 42633965Sjdp } 42733965Sjdp 42877298Sobrien#ifdef DAEMON 42933965Sjdp if (daemon(0,0)) 430130561Sobrien err(1, "fork"); 43133965Sjdp#endif 43233965Sjdp 43333965Sjdp pmap_unset(YPBINDPROG, YPBINDVERS); 43433965Sjdp 43533965Sjdp udptransp = svcudp_create(RPC_ANYSOCK); 436130561Sobrien if (udptransp == NULL) 43733965Sjdp errx(1, "cannot create udp service"); 43833965Sjdp if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 43933965Sjdp IPPROTO_UDP)) 44033965Sjdp errx(1, "unable to register (YPBINDPROG, YPBINDVERS, udp)"); 44133965Sjdp 44233965Sjdp tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 44333965Sjdp if (tcptransp == NULL) 44433965Sjdp errx(1, "cannot create tcp service"); 44533965Sjdp 44633965Sjdp if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 447130561Sobrien IPPROTO_TCP)) 44833965Sjdp errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)"); 44933965Sjdp 45033965Sjdp /* build initial domain binding, make it "unsuccessful" */ 451218822Sdim ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 45233965Sjdp if (ypbindlist == NULL) 45333965Sjdp errx(1, "malloc"); 45433965Sjdp bzero(ypbindlist, sizeof *ypbindlist); 45589857Sobrien strncpy(ypbindlist->dom_domain, domain_name, sizeof ypbindlist->dom_domain); 45689857Sobrien ypbindlist->dom_vers = YPVERS; 45733965Sjdp ypbindlist->dom_alive = 0; 45833965Sjdp ypbindlist->dom_lockfd = -1; 45933965Sjdp ypbindlist->dom_default = 1; 46033965Sjdp domains++; 46133965Sjdp 46233965Sjdp signal(SIGCHLD, reaper); 46333965Sjdp signal(SIGTERM, terminate); 46433965Sjdp 46533965Sjdp ppid = getpid(); /* Remember who we are. */ 46633965Sjdp 46733965Sjdp openlog(argv[0], LOG_PID, LOG_DAEMON); 46833965Sjdp 46933965Sjdp if (madvise(NULL, 0, MADV_PROTECT) != 0) 47033965Sjdp syslog(LOG_WARNING, "madvise(): %m"); 47133965Sjdp 47233965Sjdp /* Kick off the default domain */ 473130561Sobrien broadcast(ypbindlist); 47433965Sjdp 47533965Sjdp while (1) { 47633965Sjdp fdsr = svc_fdset; 477130561Sobrien 47833965Sjdp tv.tv_sec = 60; 47933965Sjdp tv.tv_usec = 0; 48033965Sjdp 48133965Sjdp switch (select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 48233965Sjdp case 0: 48333965Sjdp checkwork(); 484130561Sobrien break; 485218822Sdim case -1: 486218822Sdim if (errno != EINTR) 487218822Sdim syslog(LOG_WARNING, "select: %m"); 48833965Sjdp break; 48933965Sjdp default: 49033965Sjdp for (ypdb = ypbindlist; ypdb; ypdb = next) { 49133965Sjdp next = ypdb->dom_pnext; 49233965Sjdp if (READFD > 0 && FD_ISSET(READFD, &fdsr)) { 493218822Sdim handle_children(ypdb); 49433965Sjdp if (children == (MAX_CHILDREN - 1)) 49533965Sjdp checkwork(); 49633965Sjdp } 49733965Sjdp } 49833965Sjdp svc_getreqset(&fdsr); 49933965Sjdp break; 50089857Sobrien } 50189857Sobrien } 50233965Sjdp 50333965Sjdp /* NOTREACHED */ 50433965Sjdp exit(1); 50533965Sjdp} 50633965Sjdp 507218822Sdimvoid 508130561Sobriencheckwork(void) 50933965Sjdp{ 51033965Sjdp struct _dom_binding *ypdb; 51133965Sjdp 512130561Sobrien for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) 51333965Sjdp ping(ypdb); 51433965Sjdp} 51533965Sjdp 516130561Sobrien/* The clnt_broadcast() callback mechanism sucks. */ 51733965Sjdp 51833965Sjdp/* 51933965Sjdp * Receive results from broadcaster. Don't worry about passing 52033965Sjdp * bogus info to rpc_received() -- it can handle it. Note that we 52133965Sjdp * must be sure to invalidate the dom_pipe_fds descriptors here: 52233965Sjdp * since descriptors can be re-used, we have to make sure we 52333965Sjdp * don't mistake one of the RPC descriptors for one of the pipes. 52433965Sjdp * What's weird is that forgetting to invalidate the pipe descriptors 52533965Sjdp * doesn't always result in an error (otherwise I would have caught 52633965Sjdp * the mistake much sooner), even though logically it should. 52733965Sjdp */ 52833965Sjdpvoid 52933965Sjdphandle_children(struct _dom_binding *ypdb) 53033965Sjdp{ 53133965Sjdp char buf[YPMAXDOMAIN + 1]; 53233965Sjdp struct sockaddr_in addr; 53333965Sjdp int d = 0, a = 0; 53433965Sjdp struct _dom_binding *y, *prev = NULL; 53533965Sjdp char path[MAXPATHLEN]; 53633965Sjdp 53733965Sjdp if ((d = read(READFD, &buf, sizeof(buf))) <= 0) 53833965Sjdp syslog(LOG_WARNING, "could not read from child: %m"); 53933965Sjdp 540104834Sobrien if ((a = read(READFD, &addr, sizeof(struct sockaddr_in))) < 0) 541218822Sdim syslog(LOG_WARNING, "could not read from child: %m"); 542104834Sobrien 54333965Sjdp close(READFD); 54433965Sjdp FD_CLR(READFD, &fdsr); 54533965Sjdp FD_CLR(READFD, &svc_fdset); 54633965Sjdp READFD = WRITEFD = -1; 54733965Sjdp if (d > 0 && a > 0) 54833965Sjdp rpc_received(buf, &addr, 0); 54933965Sjdp else { 55033965Sjdp for (y = ypbindlist; y; y = y->dom_pnext) { 55133965Sjdp if (y == ypdb) 55233965Sjdp break; 55333965Sjdp prev = y; 55433965Sjdp } 55533965Sjdp switch (ypdb->dom_default) { 556130561Sobrien case 0: 55733965Sjdp if (prev == NULL) 558218822Sdim ypbindlist = y->dom_pnext; 55933965Sjdp else 560130561Sobrien prev->dom_pnext = y->dom_pnext; 56189857Sobrien sprintf(path, "%s/%s.%ld", BINDINGDIR, 56289857Sobrien ypdb->dom_domain, YPVERS); 56389857Sobrien close(ypdb->dom_lockfd); 56489857Sobrien unlink(path); 56589857Sobrien free(ypdb); 56633965Sjdp domains--; 56733965Sjdp return; 568130561Sobrien case 1: 56933965Sjdp ypdb->dom_broadcast_pid = 0; 57033965Sjdp ypdb->dom_alive = 0; 57133965Sjdp broadcast(ypdb); 57233965Sjdp return; 57333965Sjdp default: 574218822Sdim break; 575218822Sdim } 576218822Sdim } 577218822Sdim 578218822Sdim return; 579218822Sdim} 58033965Sjdp 581104834Sobrien/* 58233965Sjdp * Send our dying words back to our parent before we perish. 583218822Sdim */ 584218822Sdimint 585218822Sdimtell_parent(char *dom, struct sockaddr_in *addr) 586218822Sdim{ 58733965Sjdp char buf[YPMAXDOMAIN + 1]; 58833965Sjdp struct timeval timeout; 58933965Sjdp fd_set fds; 590218822Sdim 591218822Sdim timeout.tv_sec = 5; 592218822Sdim timeout.tv_usec = 0; 59333965Sjdp 59433965Sjdp sprintf(buf, "%s", broad_domain->dom_domain); 59533965Sjdp if (write(BROADFD, &buf, sizeof(buf)) < 0) 59633965Sjdp return(1); 59733965Sjdp 59833965Sjdp /* 59933965Sjdp * Stay in sync with parent: wait for it to read our first 60033965Sjdp * message before sending the second. 60133965Sjdp */ 60233965Sjdp 60389857Sobrien FD_ZERO(&fds); 60489857Sobrien FD_SET(BROADFD, &fds); 605218822Sdim if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 60633965Sjdp return(1); 607130561Sobrien if (FD_ISSET(BROADFD, &fds)) { 60833965Sjdp if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0) 60933965Sjdp return(1); 61033965Sjdp } else { 61133965Sjdp return(1); 61233965Sjdp } 613218822Sdim 61433965Sjdp close(BROADFD); 615130561Sobrien return (0); 61633965Sjdp} 61733965Sjdp 61833965Sjdpbool_t broadcast_result(out, addr) 61933965Sjdpbool_t *out; 62033965Sjdpstruct sockaddr_in *addr; 62133965Sjdp{ 62233965Sjdp if (retries >= MAX_RETRIES) { 62333965Sjdp bzero(addr, sizeof(struct sockaddr_in)); 62433965Sjdp if (tell_parent(broad_domain->dom_domain, addr)) 62533965Sjdp syslog(LOG_WARNING, "lost connection to parent"); 62633965Sjdp return (TRUE); 62733965Sjdp } 62833965Sjdp 62933965Sjdp if (yp_restricted && verify(addr->sin_addr)) { 63033965Sjdp retries++; 63133965Sjdp syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr)); 63233965Sjdp return (FALSE); 633218822Sdim } else { 63433965Sjdp if (tell_parent(broad_domain->dom_domain, addr)) 63533965Sjdp syslog(LOG_WARNING, "lost connection to parent"); 63689857Sobrien return (TRUE); 63733965Sjdp } 638218822Sdim} 639218822Sdim 640218822Sdim/* 641218822Sdim * The right way to send RPC broadcasts. 642218822Sdim * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 643130561Sobrien * blocks while waiting for replies, so we have to fork off separate 64433965Sjdp * broadcaster processes that do the waiting and then transmit their 64533965Sjdp * results back to the parent for processing. We also have to remember 64633965Sjdp * to save the name of the domain we're trying to bind in a global 64733965Sjdp * variable since clnt_broadcast() provides no way to pass things to 64833965Sjdp * the 'eachresult' callback function. 64933965Sjdp */ 65033965Sjdpvoid 651130561Sobrienbroadcast(struct _dom_binding *ypdb) 652218822Sdim{ 653218822Sdim bool_t out = FALSE; 654218822Sdim enum clnt_stat stat; 655218822Sdim 656218822Sdim if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid) 65733965Sjdp return; 65833965Sjdp 65933965Sjdp if (pipe(ypdb->dom_pipe_fds) < 0) { 66033965Sjdp syslog(LOG_WARNING, "pipe: %m"); 66133965Sjdp return; 66233965Sjdp } 66333965Sjdp 66433965Sjdp if (ypdb->dom_vers == -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) { 66533965Sjdp if (not_responding_count++ >= NOT_RESPONDING_HYSTERESIS) { 66633965Sjdp not_responding_count = NOT_RESPONDING_HYSTERESIS; 66733965Sjdp syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding", 66833965Sjdp inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 66933965Sjdp } 67033965Sjdp } 67133965Sjdp 67233965Sjdp broad_domain = ypdb; 67333965Sjdp flock(ypdb->dom_lockfd, LOCK_UN); 67433965Sjdp 67533965Sjdp switch ((ypdb->dom_broadcast_pid = fork())) { 676130561Sobrien case 0: 67733965Sjdp close(READFD); 67833965Sjdp signal(SIGCHLD, SIG_DFL); 67933965Sjdp signal(SIGTERM, SIG_DFL); 68033965Sjdp break; 681130561Sobrien case -1: 68233965Sjdp syslog(LOG_WARNING, "fork: %m"); 68333965Sjdp close(READFD); 68433965Sjdp close(WRITEFD); 68533965Sjdp return; 68633965Sjdp default: 68733965Sjdp close(WRITEFD); 68833965Sjdp FD_SET(READFD, &svc_fdset); 68933965Sjdp children++; 69033965Sjdp return; 69133965Sjdp } 69233965Sjdp 69333965Sjdp /* Release all locks before doing anything else. */ 69433965Sjdp while (ypbindlist) { 69533965Sjdp close(ypbindlist->dom_lockfd); 69633965Sjdp ypbindlist = ypbindlist->dom_pnext; 69733965Sjdp } 69833965Sjdp close(yplockfd); 69933965Sjdp 70033965Sjdp /* 70133965Sjdp * Special 'many-cast' behavior. If we're in restricted mode, 702104834Sobrien * we have a list of possible server addresses to try. What 703104834Sobrien * we can do is transmit to each ypserv's YPPROC_DOMAIN_NONACK 704104834Sobrien * procedure and time the replies. Whoever replies fastest 705104834Sobrien * gets to be our server. Note that this is not a broadcast 70633965Sjdp * operation: we transmit uni-cast datagrams only. 70733965Sjdp */ 70833965Sjdp if (yp_restricted && yp_manycast) { 70933965Sjdp short port; 71033965Sjdp int i; 71133965Sjdp struct sockaddr_in sin; 71233965Sjdp 71333965Sjdp i = __yp_ping(restricted_addrs, yp_restricted, 71433965Sjdp ypdb->dom_domain, &port); 71533965Sjdp if (i == -1) { 716218822Sdim bzero(&ypdb->dom_server_addr, 71733965Sjdp sizeof(struct sockaddr_in)); 71833965Sjdp if (tell_parent(ypdb->dom_domain, 71933965Sjdp &ypdb->dom_server_addr)) 720218822Sdim syslog(LOG_WARNING, "lost connection to parent"); 72133965Sjdp } else { 72233965Sjdp bzero(&sin, sizeof(struct sockaddr_in)); 72333965Sjdp bcopy(&restricted_addrs[i], 724218822Sdim &sin.sin_addr, sizeof(struct in_addr)); 72533965Sjdp sin.sin_family = AF_INET; 72633965Sjdp sin.sin_port = port; 72733965Sjdp if (tell_parent(broad_domain->dom_domain, &sin)) 72833965Sjdp syslog(LOG_WARNING, 72933965Sjdp "lost connection to parent"); 73033965Sjdp } 73133965Sjdp _exit(0); 73233965Sjdp } 73333965Sjdp 73433965Sjdp retries = 0; 73533965Sjdp 73633965Sjdp { 73733965Sjdp char *ptr; 73833965Sjdp 73933965Sjdp ptr = ypdb->dom_domain; 74033965Sjdp stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 74133965Sjdp (xdrproc_t)xdr_domainname, &ptr, 74233965Sjdp (xdrproc_t)xdr_bool, &out, 74333965Sjdp (resultproc_t)broadcast_result); 74433965Sjdp } 74533965Sjdp 74633965Sjdp if (stat != RPC_SUCCESS) { 74733965Sjdp bzero(&ypdb->dom_server_addr, 74833965Sjdp sizeof(struct sockaddr_in)); 74933965Sjdp if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr)) 75033965Sjdp syslog(LOG_WARNING, "lost connection to parent"); 75133965Sjdp } 75233965Sjdp 75333965Sjdp _exit(0); 75433965Sjdp} 75533965Sjdp 75633965Sjdp/* 75733965Sjdp * The right way to check if a server is alive. 75833965Sjdp * Attempt to get a client handle pointing to the server and send a 75933965Sjdp * YPPROC_DOMAIN. If we can't get a handle or we get a reply of FALSE, 76033965Sjdp * we invalidate this binding entry and send out a broadcast to try to 76133965Sjdp * establish a new binding. Note that we treat non-default domains 76233965Sjdp * specially: once bound, we keep tabs on our server, but if it 76333965Sjdp * goes away and fails to respond after one round of broadcasting, we 76433965Sjdp * abandon it until a client specifically references it again. We make 76533965Sjdp * every effort to keep our default domain bound, however, since we 76633965Sjdp * need it to keep the system on its feet. 76733965Sjdp */ 76833965Sjdpint 76933965Sjdpping(struct _dom_binding *ypdb) 77033965Sjdp{ 77133965Sjdp bool_t out; 77233965Sjdp struct timeval interval, timeout; 77333965Sjdp enum clnt_stat stat; 77433965Sjdp int rpcsock = RPC_ANYSOCK; 77533965Sjdp CLIENT *client_handle; 77633965Sjdp 77733965Sjdp interval.tv_sec = FAIL_THRESHOLD; 77833965Sjdp interval.tv_usec = 0; 77933965Sjdp timeout.tv_sec = FAIL_THRESHOLD; 78033965Sjdp timeout.tv_usec = 0; 78133965Sjdp 78233965Sjdp if (ypdb->dom_broadcast_pid) 78333965Sjdp return(1); 78433965Sjdp 78533965Sjdp if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr, 78633965Sjdp YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE, 78733965Sjdp RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 78833965Sjdp /* Can't get a handle: we're dead. */ 78933965Sjdp ypdb->dom_alive = 0; 79033965Sjdp ypdb->dom_vers = -1; 79133965Sjdp broadcast(ypdb); 79233965Sjdp return(1); 79333965Sjdp } 79433965Sjdp 79533965Sjdp { 79633965Sjdp char *ptr; 79733965Sjdp 79833965Sjdp ptr = ypdb->dom_domain; 79933965Sjdp 80033965Sjdp stat = clnt_call(client_handle, YPPROC_DOMAIN, 80133965Sjdp (xdrproc_t)xdr_domainname, &ptr, 80233965Sjdp (xdrproc_t)xdr_bool, &out, timeout); 80333965Sjdp if (stat != RPC_SUCCESS || out == FALSE) { 80433965Sjdp ypdb->dom_alive = 0; 80533965Sjdp ypdb->dom_vers = -1; 80633965Sjdp clnt_destroy(client_handle); 80733965Sjdp broadcast(ypdb); 80833965Sjdp return(1); 80933965Sjdp } 81033965Sjdp } 81133965Sjdp 81233965Sjdp clnt_destroy(client_handle); 81333965Sjdp return(0); 81433965Sjdp} 81533965Sjdp 81633965Sjdpvoid 81733965Sjdprpc_received(char *dom, struct sockaddr_in *raddrp, int force) 81833965Sjdp{ 81933965Sjdp struct _dom_binding *ypdb, *prev = NULL; 82033965Sjdp struct iovec iov[2]; 82133965Sjdp struct ypbind_resp ybr; 82233965Sjdp char path[MAXPATHLEN]; 82333965Sjdp int fd; 82433965Sjdp 82533965Sjdp /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 82633965Sjdp ntohs(raddrp->sin_port), dom);*/ 82733965Sjdp 82833965Sjdp if (dom == NULL) 82933965Sjdp return; 830218822Sdim 831218822Sdim for (ypdb = ypbindlist; ypdb; ypdb = ypdb->dom_pnext) { 83233965Sjdp if (strcmp(ypdb->dom_domain, dom) == 0) 83333965Sjdp break; 83433965Sjdp prev = ypdb; 835130561Sobrien } 83633965Sjdp 83733965Sjdp if (ypdb && force) { 83833965Sjdp if (ypdb->dom_broadcast_pid) { 83933965Sjdp kill(ypdb->dom_broadcast_pid, SIGINT); 840130561Sobrien close(READFD); 841218822Sdim FD_CLR(READFD, &fdsr); 84233965Sjdp FD_CLR(READFD, &svc_fdset); 84333965Sjdp READFD = WRITEFD = -1; 84433965Sjdp } 84533965Sjdp } 84633965Sjdp 84733965Sjdp /* if in secure mode, check originating port number */ 848218822Sdim if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) { 84933965Sjdp syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 850218822Sdim inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 85133965Sjdp dom); 85233965Sjdp if (ypdb != NULL) { 85333965Sjdp ypdb->dom_broadcast_pid = 0; 85433965Sjdp ypdb->dom_alive = 0; 85533965Sjdp } 85633965Sjdp return; 85733965Sjdp } 85833965Sjdp 85933965Sjdp if (raddrp->sin_addr.s_addr == (long)0) { 86033965Sjdp switch (ypdb->dom_default) { 86133965Sjdp case 0: 862130561Sobrien if (prev == NULL) 86333965Sjdp ypbindlist = ypdb->dom_pnext; 86433965Sjdp else 865218822Sdim prev->dom_pnext = ypdb->dom_pnext; 86633965Sjdp sprintf(path, "%s/%s.%ld", BINDINGDIR, 867130561Sobrien ypdb->dom_domain, YPVERS); 86833965Sjdp close(ypdb->dom_lockfd); 869130561Sobrien unlink(path); 87033965Sjdp free(ypdb); 87189857Sobrien domains--; 87289857Sobrien return; 873218822Sdim case 1: 87433965Sjdp ypdb->dom_broadcast_pid = 0; 875130561Sobrien ypdb->dom_alive = 0; 87633965Sjdp broadcast(ypdb); 87733965Sjdp return; 87833965Sjdp default: 87933965Sjdp break; 88033965Sjdp } 88133965Sjdp } 88233965Sjdp 88333965Sjdp if (ypdb == NULL) { 88433965Sjdp if (force == 0) 88533965Sjdp return; 886218822Sdim ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 88733965Sjdp if (ypdb == NULL) { 88833965Sjdp syslog(LOG_WARNING, "malloc: %m"); 88933965Sjdp return; 89033965Sjdp } 89133965Sjdp bzero(ypdb, sizeof *ypdb); 892130561Sobrien strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 89333965Sjdp ypdb->dom_lockfd = -1; 89433965Sjdp ypdb->dom_default = 0; 89533965Sjdp ypdb->dom_pnext = ypbindlist; 89633965Sjdp ypbindlist = ypdb; 89733965Sjdp } 89833965Sjdp 899130561Sobrien /* We've recovered from a crash: inform the world. */ 900218822Sdim if (ypdb->dom_vers == -1 && ypdb->dom_server_addr.sin_addr.s_addr) { 90133965Sjdp if (not_responding_count >= NOT_RESPONDING_HYSTERESIS) { 90233965Sjdp not_responding_count = 0; 90333965Sjdp syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK", 90433965Sjdp inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); 90533965Sjdp } 90633965Sjdp } 90733965Sjdp 90833965Sjdp bcopy(raddrp, &ypdb->dom_server_addr, 90933965Sjdp sizeof ypdb->dom_server_addr); 91033965Sjdp 91133965Sjdp ypdb->dom_vers = YPVERS; 91233965Sjdp ypdb->dom_alive = 1; 91333965Sjdp ypdb->dom_broadcast_pid = 0; 91433965Sjdp 91533965Sjdp if (ypdb->dom_lockfd != -1) 91633965Sjdp close(ypdb->dom_lockfd); 91733965Sjdp 91833965Sjdp sprintf(path, "%s/%s.%ld", BINDINGDIR, 91933965Sjdp ypdb->dom_domain, ypdb->dom_vers); 92033965Sjdp#ifdef O_SHLOCK 921218822Sdim if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 92233965Sjdp (void)mkdir(BINDINGDIR, 0755); 92333965Sjdp if ((fd = open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 92433965Sjdp return; 92533965Sjdp } 92633965Sjdp#else 927130561Sobrien if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 92833965Sjdp (void)mkdir(BINDINGDIR, 0755); 929130561Sobrien if ((fd = open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 930218822Sdim return; 93133965Sjdp } 93233965Sjdp flock(fd, LOCK_SH); 93333965Sjdp#endif 93433965Sjdp 93533965Sjdp /* 936130561Sobrien * ok, if BINDINGDIR exists, and we can create the binding file, 93733965Sjdp * then write to it.. 93833965Sjdp */ 93933965Sjdp ypdb->dom_lockfd = fd; 94033965Sjdp 94133965Sjdp iov[0].iov_base = (char *)&(udptransp->xp_port); 942218822Sdim iov[0].iov_len = sizeof udptransp->xp_port; 94333965Sjdp iov[1].iov_base = (char *)&ybr; 944218822Sdim iov[1].iov_len = sizeof ybr; 94533965Sjdp 94633965Sjdp bzero(&ybr, sizeof ybr); 94733965Sjdp ybr.ypbind_status = YPBIND_SUCC_VAL; 94833965Sjdp *(u_int32_t *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr.s_addr; 94933965Sjdp *(u_short *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 95033965Sjdp 95133965Sjdp if (writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 95233965Sjdp syslog(LOG_WARNING, "write: %m"); 95333965Sjdp close(ypdb->dom_lockfd); 95433965Sjdp ypdb->dom_lockfd = -1; 95533965Sjdp return; 95633965Sjdp } 957218822Sdim} 95833965Sjdp 95933965Sjdp/* 96033965Sjdp * Check address against list of allowed servers. Return 0 if okay, 96133965Sjdp * 1 if not matched. 96233965Sjdp */ 963104834Sobrienint 96433965Sjdpverify(struct in_addr addr) 96533965Sjdp{ 96633965Sjdp int i; 96733965Sjdp 96833965Sjdp for (i = 0; i < RESTRICTED_SERVERS; i++) 96933965Sjdp if (!bcmp(&addr, &restricted_addrs[i], sizeof(struct in_addr))) 97033965Sjdp return(0); 97133965Sjdp 97233965Sjdp return(1); 97333965Sjdp} 974218822Sdim 97533965Sjdp/* 97633965Sjdp * Try to set restricted mode. We default to normal mode if we can't 97733965Sjdp * resolve the specified hostnames. 97833965Sjdp */ 97933965Sjdpvoid 98033965Sjdpyp_restricted_mode(char *args) 98133965Sjdp{ 98233965Sjdp struct hostent *h; 98333965Sjdp int i = 0; 98433965Sjdp char *s; 985218822Sdim 986218822Sdim /* Find the restricted domain. */ 987218822Sdim if ((s = strsep(&args, ",")) == NULL) 988218822Sdim return; 989218822Sdim domain_name = s; 990218822Sdim 99133965Sjdp /* Get the addresses of the servers. */ 99233965Sjdp while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) { 99333965Sjdp if ((h = gethostbyname(s)) == NULL) 99433965Sjdp return; 99533965Sjdp bcopy (h->h_addr_list[0], &restricted_addrs[i], 99633965Sjdp sizeof(struct in_addr)); 99733965Sjdp i++; 99877298Sobrien } 99933965Sjdp 100033965Sjdp /* ypset and ypsetme not allowed with restricted mode */ 100133965Sjdp ypsetmode = YPSET_NO; 100233965Sjdp 100333965Sjdp yp_restricted = i; 100433965Sjdp return; 100533965Sjdp} 100633965Sjdp