ypbind.c revision 9600
11927Swollman/* 21927Swollman * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> 31927Swollman * All rights reserved. 41927Swollman * 51927Swollman * Redistribution and use in source and binary forms, with or without 61927Swollman * modification, are permitted provided that the following conditions 71927Swollman * are met: 81927Swollman * 1. Redistributions of source code must retain the above copyright 91927Swollman * notice, this list of conditions and the following disclaimer. 101927Swollman * 2. Redistributions in binary form must reproduce the above copyright 111927Swollman * notice, this list of conditions and the following disclaimer in the 121927Swollman * documentation and/or other materials provided with the distribution. 131927Swollman * 3. The name of the author may not be used to endorse or promote 141927Swollman * products derived from this software without specific prior written 151927Swollman * permission. 161927Swollman * 171927Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 181927Swollman * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 191927Swollman * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201927Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 211927Swollman * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221927Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231927Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241927Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251927Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261927Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271927Swollman * SUCH DAMAGE. 281927Swollman */ 291927Swollman 301927Swollman#ifndef LINT 319600Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.16 1995/07/15 23:27:27 wpaul Exp $"; 321927Swollman#endif 331927Swollman 341927Swollman#include <sys/param.h> 351927Swollman#include <sys/types.h> 368091Swpaul#include <sys/wait.h> 371927Swollman#include <sys/ioctl.h> 381927Swollman#include <sys/signal.h> 391927Swollman#include <sys/socket.h> 401927Swollman#include <sys/file.h> 411927Swollman#include <sys/fcntl.h> 428091Swpaul#include <sys/stat.h> 431927Swollman#include <sys/uio.h> 446478Swpaul#include <syslog.h> 451927Swollman#include <stdio.h> 461927Swollman#include <errno.h> 471927Swollman#include <ctype.h> 481927Swollman#include <dirent.h> 491927Swollman#include <netdb.h> 501927Swollman#include <string.h> 511927Swollman#include <rpc/rpc.h> 521927Swollman#include <rpc/xdr.h> 531927Swollman#include <net/if.h> 546732Swpaul#include <netinet/in.h> 551927Swollman#include <arpa/inet.h> 561927Swollman#include <rpc/pmap_clnt.h> 571927Swollman#include <rpc/pmap_prot.h> 581927Swollman#include <rpc/pmap_rmt.h> 591927Swollman#include <unistd.h> 608091Swpaul#include <stdlib.h> 611927Swollman#include <rpcsvc/yp_prot.h> 621927Swollman#include <rpcsvc/ypclnt.h> 631927Swollman 641927Swollman#ifndef BINDINGDIR 651927Swollman#define BINDINGDIR "/var/yp/binding" 661927Swollman#endif 671927Swollman 688474Swpaul#ifndef YPBINDLOCK 698474Swpaul#define YPBINDLOCK "/var/run/ypbind.lock" 708474Swpaul#endif 718474Swpaul 721927Swollmanstruct _dom_binding { 731927Swollman struct _dom_binding *dom_pnext; 741927Swollman char dom_domain[YPMAXDOMAIN + 1]; 751927Swollman struct sockaddr_in dom_server_addr; 761927Swollman long int dom_vers; 771927Swollman int dom_lockfd; 781927Swollman int dom_alive; 798755Swpaul int dom_broadcast_pid; 808755Swpaul int dom_pipe_fds[2]; 818091Swpaul int dom_default; 821927Swollman}; 831927Swollman 848755Swpaul#define READFD ypdb->dom_pipe_fds[0] 858755Swpaul#define WRITEFD ypdb->dom_pipe_fds[1] 868755Swpaul#define BROADFD broad_domain->dom_pipe_fds[1] 878755Swpaul 881927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp(); 891927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 901927Swollmanextern bool_t xdr_ypbind_setdom(); 911927Swollman 928091Swpaulvoid checkwork __P((void)); 938091Swpaulvoid *ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *)); 948755Swpaulvoid *ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *)); 958091Swpaulvoid rpc_received __P((char *, struct sockaddr_in *, int )); 968091Swpaulvoid broadcast __P((struct _dom_binding *)); 978425Swpaulint ping __P((struct _dom_binding *)); 988755Swpaulint tell_parent __P((char *, struct sockaddr_in *)); 998853Swpaulvoid handle_children __P(( struct _dom_binding * )); 1008425Swpaulvoid reaper __P((int)); 1018425Swpaulvoid terminate __P((int)); 1029600Swpaulvoid yp_restricted_mode __P((char *)); 1039600Swpaulint verify __P((struct in_addr)); 1048091Swpaul 1051927Swollmanchar *domainname; 1061927Swollmanstruct _dom_binding *ypbindlist; 1078755Swpaulstatic struct _dom_binding *broad_domain; 1081927Swollman 1091927Swollman#define YPSET_NO 0 1101927Swollman#define YPSET_LOCAL 1 1111927Swollman#define YPSET_ALL 2 1121927Swollmanint ypsetmode = YPSET_NO; 1136732Swpaulint ypsecuremode = 0; 1146732Swpaul 1159600Swpaul/* 1169600Swpaul * Special restricted mode variables: when in restricted mode, only the 1179600Swpaul * specified restricted_domain will be bound, and only the servers listed 1189600Swpaul * in restricted_addrs will be used for binding. 1199600Swpaul */ 1209600Swpaul#define RESTRICTED_SERVERS 10 1219600Swpaulint yp_restricted = 0; 1229600Swpaulstruct in_addr restricted_addrs[RESTRICTED_SERVERS]; 1239600Swpaul 1248091Swpaul/* No more than MAX_CHILDREN child broadcasters at a time. */ 1258755Swpaul#ifndef MAX_CHILDREN 1268091Swpaul#define MAX_CHILDREN 5 1278755Swpaul#endif 1288425Swpaul/* No more than MAX_DOMAINS simultaneous domains */ 1298755Swpaul#ifndef MAX_DOMAINS 1308425Swpaul#define MAX_DOMAINS 200 1318755Swpaul#endif 1328755Swpaul/* RPC timeout value */ 1338425Swpaul#ifndef FAIL_THRESHOLD 1348755Swpaul#define FAIL_THRESHOLD 10 1358425Swpaul#endif 1368425Swpaul 1379600Swpaul/* Number of times to fish for a response froma particular set of hosts */ 1389600Swpaul#ifndef MAX_RETRIES 1399600Swpaul#define MAX_RETRIES 30 1409600Swpaul#endif 1419600Swpaul 1429600Swpaulint retries = 0; 1438091Swpaulint children = 0; 1448425Swpaulint domains = 0; 1458474Swpaulint yplockfd; 1468755Swpaulfd_set fdsr; 1478091Swpaul 1481927SwollmanSVCXPRT *udptransp, *tcptransp; 1491927Swollman 1501927Swollmanvoid * 1511927Swollmanypbindproc_null_2(transp, argp, clnt) 1521927SwollmanSVCXPRT *transp; 1531927Swollmanvoid *argp; 1541927SwollmanCLIENT *clnt; 1551927Swollman{ 1561927Swollman static char res; 1571927Swollman 1581927Swollman bzero((char *)&res, sizeof(res)); 1591927Swollman return (void *)&res; 1601927Swollman} 1611927Swollman 1621927Swollmanstruct ypbind_resp * 1631927Swollmanypbindproc_domain_2(transp, argp, clnt) 1641927SwollmanSVCXPRT *transp; 1651927Swollmanchar *argp; 1661927SwollmanCLIENT *clnt; 1671927Swollman{ 1681927Swollman static struct ypbind_resp res; 1691927Swollman struct _dom_binding *ypdb; 1701927Swollman char path[MAXPATHLEN]; 1711927Swollman 1721927Swollman bzero((char *)&res, sizeof res); 1731927Swollman res.ypbind_status = YPBIND_FAIL_VAL; 1747982Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_NOSERV; 1751927Swollman 1768755Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 1771927Swollman if( strcmp(ypdb->dom_domain, argp) == 0) 1781927Swollman break; 1798755Swpaul } 1801927Swollman 1811927Swollman if(ypdb==NULL) { 1829600Swpaul if (yp_restricted) { 1839600Swpaul syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", argp); 1849600Swpaul return &res; 1859600Swpaul } 1869600Swpaul 1878474Swpaul if (domains >= MAX_DOMAINS) { 1888425Swpaul syslog(LOG_WARNING, "domain limit (%d) exceeded", 1898425Swpaul MAX_DOMAINS); 1908425Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; 1918428Swpaul return &res; 1928425Swpaul } 1931927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 1948857Srgrimes if (ypdb == NULL) { 1958246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 1968246Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; 1978428Swpaul return &res; 1988246Swpaul } 1991927Swollman bzero((char *)ypdb, sizeof *ypdb); 2001927Swollman strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 2011927Swollman ypdb->dom_vers = YPVERS; 2021927Swollman ypdb->dom_alive = 0; 2038091Swpaul ypdb->dom_default = 0; 2041927Swollman ypdb->dom_lockfd = -1; 2058425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 2068425Swpaul ypdb->dom_domain, ypdb->dom_vers); 2071927Swollman unlink(path); 2081927Swollman ypdb->dom_pnext = ypbindlist; 2091927Swollman ypbindlist = ypdb; 2108425Swpaul domains++; 2111927Swollman } 2121927Swollman 2138755Swpaul if (ping(ypdb)) { 2147982Swpaul return &res; 2158755Swpaul } 2161927Swollman 2171927Swollman res.ypbind_status = YPBIND_SUCC_VAL; 2188246Swpaul res.ypbind_respbody.ypbind_error = 0; /* Success */ 2191927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 2201927Swollman ypdb->dom_server_addr.sin_addr.s_addr; 2211927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 2228091Swpaul ypdb->dom_server_addr.sin_port; 2231927Swollman /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 2241927Swollman inet_ntoa(ypdb->dom_server_addr.sin_addr), 2251927Swollman ntohs(ypdb->dom_server_addr.sin_port));*/ 2261927Swollman return &res; 2271927Swollman} 2281927Swollman 2298755Swpaulvoid * 2301927Swollmanypbindproc_setdom_2(transp, argp, clnt) 2311927SwollmanSVCXPRT *transp; 2321927Swollmanstruct ypbind_setdom *argp; 2331927SwollmanCLIENT *clnt; 2341927Swollman{ 2351927Swollman struct sockaddr_in *fromsin, bindsin; 2361927Swollman 2371927Swollman fromsin = svc_getcaller(transp); 2381927Swollman 2391927Swollman switch(ypsetmode) { 2401927Swollman case YPSET_LOCAL: 2418755Swpaul if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 2428755Swpaul svcerr_noprog(transp); 2438755Swpaul return; 2448755Swpaul } 2451927Swollman break; 2461927Swollman case YPSET_ALL: 2471927Swollman break; 2481927Swollman case YPSET_NO: 2491927Swollman default: 2508755Swpaul svcerr_noprog(transp); 2518755Swpaul return; 2521927Swollman } 2531927Swollman 2548755Swpaul if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 2558755Swpaul svcerr_noprog(transp); 2568755Swpaul return; 2578755Swpaul } 2581927Swollman 2598755Swpaul if(argp->ypsetdom_vers != YPVERS) { 2608755Swpaul svcerr_noprog(transp); 2618755Swpaul return; 2628755Swpaul } 2631927Swollman 2641927Swollman bzero((char *)&bindsin, sizeof bindsin); 2651927Swollman bindsin.sin_family = AF_INET; 2661927Swollman bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 2671927Swollman bindsin.sin_port = argp->ypsetdom_port; 2681927Swollman rpc_received(argp->ypsetdom_domain, &bindsin, 1); 2691927Swollman 2708755Swpaul return; 2711927Swollman} 2721927Swollman 2731927Swollmanstatic void 2741927Swollmanypbindprog_2(rqstp, transp) 2751927Swollmanstruct svc_req *rqstp; 2761927Swollmanregister SVCXPRT *transp; 2771927Swollman{ 2781927Swollman union { 2791927Swollman char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 2801927Swollman struct ypbind_setdom ypbindproc_setdom_2_arg; 2811927Swollman } argument; 2821927Swollman struct authunix_parms *creds; 2831927Swollman char *result; 2841927Swollman bool_t (*xdr_argument)(), (*xdr_result)(); 2851927Swollman char *(*local)(); 2861927Swollman 2871927Swollman switch (rqstp->rq_proc) { 2881927Swollman case YPBINDPROC_NULL: 2891927Swollman xdr_argument = xdr_void; 2901927Swollman xdr_result = xdr_void; 2911927Swollman local = (char *(*)()) ypbindproc_null_2; 2921927Swollman break; 2931927Swollman 2941927Swollman case YPBINDPROC_DOMAIN: 2951927Swollman xdr_argument = xdr_domainname; 2961927Swollman xdr_result = xdr_ypbind_resp; 2971927Swollman local = (char *(*)()) ypbindproc_domain_2; 2981927Swollman break; 2991927Swollman 3001927Swollman case YPBINDPROC_SETDOM: 3011927Swollman switch(rqstp->rq_cred.oa_flavor) { 3021927Swollman case AUTH_UNIX: 3031927Swollman creds = (struct authunix_parms *)rqstp->rq_clntcred; 3041927Swollman if( creds->aup_uid != 0) { 3051927Swollman svcerr_auth(transp, AUTH_BADCRED); 3061927Swollman return; 3071927Swollman } 3081927Swollman break; 3091927Swollman default: 3101927Swollman svcerr_auth(transp, AUTH_TOOWEAK); 3111927Swollman return; 3121927Swollman } 3131927Swollman 3141927Swollman xdr_argument = xdr_ypbind_setdom; 3151927Swollman xdr_result = xdr_void; 3161927Swollman local = (char *(*)()) ypbindproc_setdom_2; 3171927Swollman break; 3181927Swollman 3191927Swollman default: 3201927Swollman svcerr_noproc(transp); 3211927Swollman return; 3221927Swollman } 3231927Swollman bzero((char *)&argument, sizeof(argument)); 3241927Swollman if (!svc_getargs(transp, xdr_argument, &argument)) { 3251927Swollman svcerr_decode(transp); 3261927Swollman return; 3271927Swollman } 3281927Swollman result = (*local)(transp, &argument, rqstp); 3291927Swollman if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 3301927Swollman svcerr_systemerr(transp); 3311927Swollman } 3321927Swollman return; 3331927Swollman} 3341927Swollman 3358091Swpaul/* Jack the reaper */ 3368091Swpaulvoid reaper(sig) 3378091Swpaulint sig; 3388091Swpaul{ 3398091Swpaul int st; 3408091Swpaul 3419532Swpaul while(wait3(&st, WNOHANG, NULL) > 0) 3429532Swpaul children--; 3438091Swpaul} 3448091Swpaul 3458425Swpaulvoid terminate(sig) 3468425Swpaulint sig; 3478425Swpaul{ 3488425Swpaul struct _dom_binding *ypdb; 3498425Swpaul char path[MAXPATHLEN]; 3508425Swpaul 3518425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 3528425Swpaul close(ypdb->dom_lockfd); 3538755Swpaul if (ypdb->dom_broadcast_pid) 3548755Swpaul kill(ypdb->dom_broadcast_pid, SIGINT); 3558425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 3568425Swpaul ypdb->dom_domain, ypdb->dom_vers); 3578425Swpaul unlink(path); 3588425Swpaul } 3598474Swpaul close(yplockfd); 3608474Swpaul unlink(YPBINDLOCK); 3618425Swpaul pmap_unset(YPBINDPROG, YPBINDVERS); 3628425Swpaul exit(0); 3638425Swpaul} 3648857Srgrimes 3658091Swpaulvoid 3661927Swollmanmain(argc, argv) 3678091Swpaulint argc; 3681927Swollmanchar **argv; 3691927Swollman{ 3701927Swollman char path[MAXPATHLEN]; 3711927Swollman struct timeval tv; 3721927Swollman int i; 3738425Swpaul DIR *dird; 3748425Swpaul struct dirent *dirp; 3758755Swpaul struct _dom_binding *ypdb; 3761927Swollman 3778474Swpaul /* Check that another ypbind isn't already running. */ 3788474Swpaul if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) { 3798474Swpaul perror(YPBINDLOCK); 3808474Swpaul exit(1); 3818474Swpaul } 3828474Swpaul 3838474Swpaul if(flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { 3848474Swpaul fprintf (stderr, "Another ypbind is already running. Aborting.\n"); 3858474Swpaul exit(1); 3868474Swpaul } 3878474Swpaul 3889600Swpaul /* XXX domainname will be overriden if we use restricted mode */ 3891927Swollman yp_get_default_domain(&domainname); 3901927Swollman if( domainname[0] == '\0') { 3911927Swollman fprintf(stderr, "domainname not set. Aborting.\n"); 3921927Swollman exit(1); 3931927Swollman } 3941927Swollman 3951927Swollman for(i=1; i<argc; i++) { 3961927Swollman if( strcmp("-ypset", argv[i]) == 0) 3971927Swollman ypsetmode = YPSET_ALL; 3981927Swollman else if (strcmp("-ypsetme", argv[i]) == 0) 3996732Swpaul ypsetmode = YPSET_LOCAL; 4006732Swpaul else if (strcmp("-s", argv[i]) == 0) 4016732Swpaul ypsecuremode++; 4029600Swpaul else if (strcmp("-S", argv[i]) == 0 && argc > i) 4039600Swpaul yp_restricted_mode(argv[i+1]); 4041927Swollman } 4051927Swollman 4068425Swpaul /* blow away everything in BINDINGDIR (if it exists) */ 4071927Swollman 4088425Swpaul if ((dird = opendir(BINDINGDIR)) != NULL) { 4098425Swpaul char path[MAXPATHLEN]; 4108425Swpaul while ((dirp = readdir(dird)) != NULL) 4118425Swpaul if (strcmp(dirp->d_name, ".") && 4128425Swpaul strcmp(dirp->d_name, "..")) { 4138425Swpaul sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); 4148425Swpaul unlink(path); 4158425Swpaul } 4168425Swpaul closedir(dird); 4178425Swpaul } 4181927Swollman 4191927Swollman#ifdef DAEMON 4208425Swpaul if (daemon(0,0)) { 4211927Swollman perror("fork"); 4221927Swollman exit(1); 4231927Swollman } 4241927Swollman#endif 4251927Swollman 4261927Swollman pmap_unset(YPBINDPROG, YPBINDVERS); 4271927Swollman 4281927Swollman udptransp = svcudp_create(RPC_ANYSOCK); 4291927Swollman if (udptransp == NULL) { 4308425Swpaul fprintf(stderr, "cannot create udp service.\n"); 4311927Swollman exit(1); 4321927Swollman } 4331927Swollman if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 4341927Swollman IPPROTO_UDP)) { 4358425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).\n"); 4361927Swollman exit(1); 4371927Swollman } 4381927Swollman 4391927Swollman tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 4401927Swollman if (tcptransp == NULL) { 4418425Swpaul fprintf(stderr, "cannot create tcp service.\n"); 4421927Swollman exit(1); 4431927Swollman } 4441927Swollman 4451927Swollman if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 4461927Swollman IPPROTO_TCP)) { 4478425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).\n"); 4481927Swollman exit(1); 4491927Swollman } 4501927Swollman 4511927Swollman /* build initial domain binding, make it "unsuccessful" */ 4521927Swollman ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 4538246Swpaul if (ypbindlist == NULL) { 4548246Swpaul perror("malloc"); 4558246Swpaul exit(1); 4568246Swpaul } 4571927Swollman bzero((char *)ypbindlist, sizeof *ypbindlist); 4581927Swollman strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 4591927Swollman ypbindlist->dom_vers = YPVERS; 4601927Swollman ypbindlist->dom_alive = 0; 4611927Swollman ypbindlist->dom_lockfd = -1; 4628091Swpaul ypbindlist->dom_default = 1; 4638425Swpaul domains++; 4641927Swollman 4658425Swpaul signal(SIGCHLD, reaper); 4668425Swpaul signal(SIGTERM, terminate); 4678425Swpaul 4688246Swpaul openlog(argv[0], LOG_PID, LOG_DAEMON); 4696478Swpaul 4708425Swpaul /* Kick off the default domain */ 4718425Swpaul broadcast(ypbindlist); 4728425Swpaul 4731927Swollman while(1) { 4741927Swollman fdsr = svc_fdset; 4758091Swpaul 4768425Swpaul tv.tv_sec = 60; 4771927Swollman tv.tv_usec = 0; 4781927Swollman 4798091Swpaul switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 4801927Swollman case 0: 4811927Swollman checkwork(); 4821927Swollman break; 4831927Swollman case -1: 4848755Swpaul if (errno != EINTR) 4858425Swpaul syslog(LOG_WARNING, "select: %s", strerror(errno)); 4868755Swpaul break; 4871927Swollman default: 4888755Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 4898755Swpaul if (READFD > 0 && FD_ISSET(READFD, &fdsr)) { 4908853Swpaul handle_children(ypdb); 4918755Swpaul if (children == (MAX_CHILDREN - 1)) 4928755Swpaul checkwork(); 4938091Swpaul } 4941927Swollman } 4951927Swollman svc_getreqset(&fdsr); 4961927Swollman break; 4971927Swollman } 4981927Swollman } 4991927Swollman} 5001927Swollman 5018091Swpaulvoid 5021927Swollmancheckwork() 5031927Swollman{ 5041927Swollman struct _dom_binding *ypdb; 5051927Swollman 5068425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 5078425Swpaul ping(ypdb); 5081927Swollman} 5091927Swollman 5108091Swpaul/* The clnt_broadcast() callback mechanism sucks. */ 5118091Swpaul 5128091Swpaul/* 5138091Swpaul * Receive results from broadcaster. Don't worry about passing 5148853Swpaul * bogus info to rpc_received() -- it can handle it. Note that we 5158853Swpaul * must be sure to invalidate the dom_pipe_fds descriptors here: 5168853Swpaul * since descriptors can be re-used, we have to make sure we 5178853Swpaul * don't mistake one of the RPC descriptors for one of the pipes. 5188853Swpaul * What's weird is that forgetting to invalidate the pipe descriptors 5198853Swpaul * doesn't always result in an error (otherwise I would have caught 5208853Swpaul * the mistake much sooner), even though logically it should. 5218091Swpaul */ 5228853Swpaulvoid handle_children(ypdb) 5238853Swpaulstruct _dom_binding *ypdb; 5248091Swpaul{ 5258091Swpaul char buf[YPMAXDOMAIN + 1]; 5268091Swpaul struct sockaddr_in addr; 5278091Swpaul 5288853Swpaul if (read(READFD, &buf, sizeof(buf)) < 0) 5298246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 5308853Swpaul if (read(READFD, &addr, sizeof(struct sockaddr_in)) < 0) 5318246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 5328755Swpaul 5338853Swpaul close(READFD); 5348853Swpaul FD_CLR(READFD, &fdsr); 5358853Swpaul FD_CLR(READFD, &svc_fdset); 5368853Swpaul READFD = WRITEFD = -1; 5378091Swpaul rpc_received((char *)&buf, &addr, 0); 5388091Swpaul} 5398091Swpaul 5408091Swpaul/* 5418091Swpaul * Send our dying words back to our parent before we perish. 5428091Swpaul */ 5438091Swpaulint 5448091Swpaultell_parent(dom, addr) 5451927Swollmanchar *dom; 5468091Swpaulstruct sockaddr_in *addr; 5471927Swollman{ 5488091Swpaul char buf[YPMAXDOMAIN + 1]; 5498091Swpaul struct timeval timeout; 5508091Swpaul fd_set fds; 5511927Swollman 5528091Swpaul timeout.tv_sec = 5; 5538091Swpaul timeout.tv_usec = 0; 5541927Swollman 5558755Swpaul sprintf(buf, "%s", broad_domain->dom_domain); 5568755Swpaul if (write(BROADFD, &buf, sizeof(buf)) < 0) 5578091Swpaul return(1); 5581927Swollman 5598091Swpaul /* 5608091Swpaul * Stay in sync with parent: wait for it to read our first 5618091Swpaul * message before sending the second. 5628091Swpaul */ 5631927Swollman 5648091Swpaul FD_ZERO(&fds); 5658755Swpaul FD_SET(BROADFD, &fds); 5668091Swpaul if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 5678091Swpaul return(1); 5688755Swpaul if (FD_ISSET(BROADFD, &fds)) { 5698755Swpaul if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0) 5708091Swpaul return(1); 5718091Swpaul } else { 5728091Swpaul return(1); 5731927Swollman } 5741927Swollman 5758755Swpaul close(BROADFD); 5768091Swpaul return (0); 5778091Swpaul} 5781927Swollman 5798091Swpaulbool_t broadcast_result(out, addr) 5808091Swpaulbool_t *out; 5818091Swpaulstruct sockaddr_in *addr; 5828091Swpaul{ 5839600Swpaul if (retries >= MAX_RETRIES) { 5849600Swpaul bzero((char *)addr, sizeof(struct sockaddr_in)); 5859600Swpaul if (tell_parent(broad_domain->dom_domain, addr)) 5869600Swpaul syslog(LOG_WARNING, "lost connection to parent"); 5879600Swpaul return TRUE; 5889600Swpaul } 5899600Swpaul 5909600Swpaul if (yp_restricted && verify(addr->sin_addr)) { 5919600Swpaul retries++; 5929600Swpaul syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr)); 5939600Swpaul return FALSE; 5949600Swpaul } else { 5959600Swpaul if (tell_parent(broad_domain->dom_domain, addr)) 5969600Swpaul syslog(LOG_WARNING, "lost connection to parent"); 5979600Swpaul return TRUE; 5989600Swpaul } 5998091Swpaul} 6008091Swpaul 6018091Swpaul/* 6028091Swpaul * The right way to send RPC broadcasts. 6038091Swpaul * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 6048091Swpaul * blocks while waiting for replies, so we have to fork off seperate 6058091Swpaul * broadcaster processes that do the waiting and then transmit their 6068091Swpaul * results back to the parent for processing. We also have to remember 6078091Swpaul * to save the name of the domain we're trying to bind in a global 6088091Swpaul * variable since clnt_broadcast() provides no way to pass things to 6098091Swpaul * the 'eachresult' callback function. 6108091Swpaul */ 6118091Swpaulvoid 6128091Swpaulbroadcast(ypdb) 6138091Swpaulstruct _dom_binding *ypdb; 6148091Swpaul{ 6158091Swpaul bool_t out = FALSE; 6168091Swpaul enum clnt_stat stat; 6178091Swpaul 6188755Swpaul if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid) 6198091Swpaul return; 6208091Swpaul 6218755Swpaul if (pipe(ypdb->dom_pipe_fds) < 0) { 6228091Swpaul syslog(LOG_WARNING, "pipe: %s",strerror(errno)); 6238091Swpaul return; 6241927Swollman } 6251927Swollman 6268425Swpaul if (ypdb->dom_vers = -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) 6278755Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding", 6288425Swpaul inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 6298425Swpaul 6308755Swpaul broad_domain = ypdb; 6318425Swpaul flock(ypdb->dom_lockfd, LOCK_UN); 6328425Swpaul 6338755Swpaul switch((ypdb->dom_broadcast_pid = fork())) { 6348091Swpaul case 0: 6358755Swpaul close(READFD); 6368091Swpaul break; 6378091Swpaul case -1: 6388091Swpaul syslog(LOG_WARNING, "fork: %s", strerror(errno)); 6398755Swpaul close(READFD); 6408755Swpaul close(WRITEFD); 6418091Swpaul return; 6428091Swpaul default: 6438755Swpaul close(WRITEFD); 6448755Swpaul FD_SET(READFD, &svc_fdset); 6458091Swpaul children++; 6468091Swpaul return; 6471927Swollman } 6486478Swpaul 6498755Swpaul /* Release all locks before doing anything else. */ 6508755Swpaul while(ypbindlist) { 6518755Swpaul close(ypbindlist->dom_lockfd); 6528755Swpaul ypbindlist = ypbindlist->dom_pnext; 6538755Swpaul } 6548755Swpaul close(yplockfd); 6558755Swpaul 6569600Swpaul retries = 0; 6579600Swpaul 6588091Swpaul stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 6598091Swpaul xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out, 6608091Swpaul broadcast_result); 6618091Swpaul 6628091Swpaul if (stat != RPC_SUCCESS) { 6638091Swpaul bzero((char *)&ypdb->dom_server_addr, 6648091Swpaul sizeof(struct sockaddr_in)); 6658755Swpaul if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr)) 6668091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 6678091Swpaul } 6688755Swpaul 6698091Swpaul exit(0); 6701927Swollman} 6711927Swollman 6728091Swpaul/* 6738091Swpaul * The right way to check if a server is alive. 6748091Swpaul * Attempt to get a client handle pointing to the server and send a 6758755Swpaul * YPPROC_DOMAIN. If we can't get a handle or we get a reply of FALSE, 6768755Swpaul * we invalidate this binding entry and send out a broadcast to try to 6778755Swpaul * establish a new binding. Note that we treat non-default domains 6788091Swpaul * specially: once bound, we keep tabs on our server, but if it 6798091Swpaul * goes away and fails to respond after one round of broadcasting, we 6808091Swpaul * abandon it until a client specifically references it again. We make 6818091Swpaul * every effort to keep our default domain bound, however, since we 6828091Swpaul * need it to keep the system on its feet. 6838091Swpaul */ 6848091Swpaulint 6858425Swpaulping(ypdb) 6868091Swpaulstruct _dom_binding *ypdb; 6871927Swollman{ 6888091Swpaul bool_t out; 6898091Swpaul struct timeval interval, timeout; 6908091Swpaul enum clnt_stat stat; 6918091Swpaul int rpcsock = RPC_ANYSOCK; 6928755Swpaul CLIENT *client_handle; 6938091Swpaul time_t t; 6941927Swollman 6958755Swpaul interval.tv_sec = FAIL_THRESHOLD; 6968091Swpaul interval.tv_usec = 0; 6978091Swpaul timeout.tv_sec = FAIL_THRESHOLD; 6988091Swpaul timeout.tv_usec = 0; 6991927Swollman 7008755Swpaul if (ypdb->dom_broadcast_pid) 7018091Swpaul return(1); 7028091Swpaul 7038755Swpaul if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr, 7048755Swpaul YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE, 7058755Swpaul RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 7068755Swpaul /* Can't get a handle: we're dead. */ 7078755Swpaul ypdb->dom_alive = 0; 7088755Swpaul ypdb->dom_vers = -1; 7098755Swpaul broadcast(ypdb); 7108755Swpaul return(1); 7111927Swollman } 7121927Swollman 7138755Swpaul if ((stat = clnt_call(client_handle, YPPROC_DOMAIN, 7148755Swpaul xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, 7158755Swpaul (char *)&out, timeout)) != RPC_SUCCESS || out == FALSE) { 7168091Swpaul ypdb->dom_alive = 0; 7178091Swpaul ypdb->dom_vers = -1; 7188755Swpaul clnt_destroy(client_handle); 7198425Swpaul broadcast(ypdb); 7208091Swpaul return(1); 7218091Swpaul } 7221927Swollman 7238755Swpaul clnt_destroy(client_handle); 7248091Swpaul return(0); 7251927Swollman} 7261927Swollman 7278091Swpaulvoid rpc_received(dom, raddrp, force) 7281927Swollmanchar *dom; 7291927Swollmanstruct sockaddr_in *raddrp; 7301927Swollmanint force; 7311927Swollman{ 7328425Swpaul struct _dom_binding *ypdb, *prev = NULL; 7331927Swollman struct iovec iov[2]; 7341927Swollman struct ypbind_resp ybr; 7351927Swollman char path[MAXPATHLEN]; 7361927Swollman int fd; 7371927Swollman 7386732Swpaul /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 7396732Swpaul ntohs(raddrp->sin_port), dom);*/ 7401927Swollman 7411927Swollman if(dom==NULL) 7421927Swollman return; 7431927Swollman 7448425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 7458091Swpaul if( strcmp(ypdb->dom_domain, dom) == 0) 7468091Swpaul break; 7478425Swpaul prev = ypdb; 7488425Swpaul } 7498091Swpaul 7508755Swpaul if (ypdb && force) { 7518755Swpaul if (ypdb->dom_broadcast_pid) { 7528755Swpaul kill(ypdb->dom_broadcast_pid, SIGINT); 7538755Swpaul close(READFD); 7548853Swpaul FD_CLR(READFD, &fdsr); 7558853Swpaul FD_CLR(READFD, &svc_fdset); 7568853Swpaul READFD = WRITEFD = -1; 7578755Swpaul } 7588755Swpaul } 7598755Swpaul 7609600Swpaul /* if in secure mode, check originating port number */ 7619600Swpaul if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) { 7626732Swpaul syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 7636732Swpaul inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 7646732Swpaul dom); 7658246Swpaul if (ypdb != NULL) { 7668755Swpaul ypdb->dom_broadcast_pid = 0; 7678246Swpaul ypdb->dom_alive = 0; 7688246Swpaul } 7696732Swpaul return; 7706732Swpaul } 7716732Swpaul 7728246Swpaul if (raddrp->sin_addr.s_addr == (long)0) { 7738755Swpaul switch(ypdb->dom_default) { 7748755Swpaul case 0: 7758755Swpaul if (prev == NULL) 7768755Swpaul ypbindlist = ypdb->dom_pnext; 7778755Swpaul else 7788755Swpaul prev->dom_pnext = ypdb->dom_pnext; 7798755Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 7808755Swpaul ypdb->dom_domain, YPVERS); 7818755Swpaul close(ypdb->dom_lockfd); 7828755Swpaul unlink(path); 7838755Swpaul free(ypdb); 7848755Swpaul domains--; 7858755Swpaul return; 7868755Swpaul case 1: 7878755Swpaul ypdb->dom_broadcast_pid = 0; 7888755Swpaul ypdb->dom_alive = 0; 7898755Swpaul broadcast(ypdb); 7908755Swpaul return; 7918755Swpaul default: 7928755Swpaul break; 7938755Swpaul } 7948246Swpaul } 7958246Swpaul 7961927Swollman if(ypdb==NULL) { 7978246Swpaul if (force == 0) 7981927Swollman return; 7991927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 8008857Srgrimes if (ypdb == NULL) { 8018246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 8028246Swpaul return; 8038246Swpaul } 8041927Swollman bzero((char *)ypdb, sizeof *ypdb); 8051927Swollman strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 8061927Swollman ypdb->dom_lockfd = -1; 8078091Swpaul ypdb->dom_default = 0; 8081927Swollman ypdb->dom_pnext = ypbindlist; 8091927Swollman ypbindlist = ypdb; 8101927Swollman } 8111927Swollman 8128091Swpaul /* We've recovered from a crash: inform the world. */ 8138091Swpaul if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr) 8148755Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK", 8158755Swpaul inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); 8166478Swpaul 8171927Swollman bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 8181927Swollman sizeof ypdb->dom_server_addr); 8196478Swpaul 8201927Swollman ypdb->dom_vers = YPVERS; 8211927Swollman ypdb->dom_alive = 1; 8228755Swpaul ypdb->dom_broadcast_pid = 0; 8231927Swollman 8241927Swollman if(ypdb->dom_lockfd != -1) 8251927Swollman close(ypdb->dom_lockfd); 8261927Swollman 8278091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 8281927Swollman ypdb->dom_domain, ypdb->dom_vers); 8291927Swollman#ifdef O_SHLOCK 8307864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 8311927Swollman (void)mkdir(BINDINGDIR, 0755); 8327864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 8331927Swollman return; 8341927Swollman } 8351927Swollman#else 8367864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 8371927Swollman (void)mkdir(BINDINGDIR, 0755); 8387864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 8391927Swollman return; 8401927Swollman } 8411927Swollman flock(fd, LOCK_SH); 8421927Swollman#endif 8431927Swollman 8441927Swollman /* 8451927Swollman * ok, if BINDINGDIR exists, and we can create the binding file, 8461927Swollman * then write to it.. 8471927Swollman */ 8481927Swollman ypdb->dom_lockfd = fd; 8491927Swollman 8501927Swollman iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 8511927Swollman iov[0].iov_len = sizeof udptransp->xp_port; 8521927Swollman iov[1].iov_base = (caddr_t)&ybr; 8531927Swollman iov[1].iov_len = sizeof ybr; 8541927Swollman 8551927Swollman bzero(&ybr, sizeof ybr); 8561927Swollman ybr.ypbind_status = YPBIND_SUCC_VAL; 8571927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr; 8581927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 8591927Swollman 8601927Swollman if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 8618091Swpaul syslog(LOG_WARNING, "write: %s", strerror(errno)); 8621927Swollman close(ypdb->dom_lockfd); 8631927Swollman ypdb->dom_lockfd = -1; 8641927Swollman return; 8651927Swollman } 8661927Swollman} 8679600Swpaul 8689600Swpaul/* 8699600Swpaul * Check address against list of allowed servers. Return 0 if okay, 8709600Swpaul * 1 if not matched. 8719600Swpaul */ 8729600Swpaulint 8739600Swpaulverify(addr) 8749600Swpaulstruct in_addr addr; 8759600Swpaul{ 8769600Swpaul int i; 8779600Swpaul 8789600Swpaul for (i = 0; i < RESTRICTED_SERVERS; i++) 8799600Swpaul if (!bcmp((char *)&addr, (char *)&restricted_addrs[i], 8809600Swpaul sizeof(struct in_addr))) 8819600Swpaul return(0); 8829600Swpaul 8839600Swpaul return(1); 8849600Swpaul} 8859600Swpaul 8869600Swpaul/* 8879600Swpaul * Try to set restricted mode. We default to normal mode if we can't 8889600Swpaul * resolve the specified hostnames. 8899600Swpaul */ 8909600Swpaulvoid 8919600Swpaulyp_restricted_mode(args) 8929600Swpaulchar *args; 8939600Swpaul{ 8949600Swpaul struct hostent *h; 8959600Swpaul int i = 0; 8969600Swpaul char *s; 8979600Swpaul 8989600Swpaul /* Find the restricted domain. */ 8999600Swpaul if ((s = strsep(&args, ",")) == NULL) 9009600Swpaul return; 9019600Swpaul domainname = s; 9029600Swpaul 9039600Swpaul /* Get the addresses of the servers. */ 9049600Swpaul while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) { 9059600Swpaul if ((h = gethostbyname(s)) == NULL) 9069600Swpaul return; 9079600Swpaul bcopy ((char *)h->h_addr_list[0], (char *)&restricted_addrs[i], 9089600Swpaul sizeof(struct in_addr)); 9099600Swpaul i++; 9109600Swpaul } 9119600Swpaul 9129600Swpaul /* ypset and ypsetme not allowed with restricted mode */ 9139600Swpaul ypsetmode = YPSET_NO; 9149600Swpaul 9159600Swpaul yp_restricted = 1; 9169600Swpaul return; 9179600Swpaul} 918