ypbind.c revision 21539
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 3121539Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.19 1996/12/30 15:31:26 peter 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> 6112862Swpaul#include <rpcsvc/yp.h> 6212862Swpaulstruct dom_binding{}; 631927Swollman#include <rpcsvc/ypclnt.h> 641927Swollman 651927Swollman#ifndef BINDINGDIR 661927Swollman#define BINDINGDIR "/var/yp/binding" 671927Swollman#endif 681927Swollman 698474Swpaul#ifndef YPBINDLOCK 708474Swpaul#define YPBINDLOCK "/var/run/ypbind.lock" 718474Swpaul#endif 728474Swpaul 731927Swollmanstruct _dom_binding { 741927Swollman struct _dom_binding *dom_pnext; 751927Swollman char dom_domain[YPMAXDOMAIN + 1]; 761927Swollman struct sockaddr_in dom_server_addr; 771927Swollman long int dom_vers; 781927Swollman int dom_lockfd; 791927Swollman int dom_alive; 808755Swpaul int dom_broadcast_pid; 818755Swpaul int dom_pipe_fds[2]; 828091Swpaul int dom_default; 831927Swollman}; 841927Swollman 858755Swpaul#define READFD ypdb->dom_pipe_fds[0] 868755Swpaul#define WRITEFD ypdb->dom_pipe_fds[1] 878755Swpaul#define BROADFD broad_domain->dom_pipe_fds[1] 888755Swpaul 891927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp(); 901927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 911927Swollmanextern bool_t xdr_ypbind_setdom(); 921927Swollman 938091Swpaulvoid checkwork __P((void)); 948091Swpaulvoid *ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *)); 958755Swpaulvoid *ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *)); 968091Swpaulvoid rpc_received __P((char *, struct sockaddr_in *, int )); 978091Swpaulvoid broadcast __P((struct _dom_binding *)); 988425Swpaulint ping __P((struct _dom_binding *)); 998755Swpaulint tell_parent __P((char *, struct sockaddr_in *)); 1008853Swpaulvoid handle_children __P(( struct _dom_binding * )); 1018425Swpaulvoid reaper __P((int)); 1028425Swpaulvoid terminate __P((int)); 1039600Swpaulvoid yp_restricted_mode __P((char *)); 1049600Swpaulint verify __P((struct in_addr)); 1058091Swpaul 10612862Swpaulchar *domain_name; 1071927Swollmanstruct _dom_binding *ypbindlist; 1088755Swpaulstatic struct _dom_binding *broad_domain; 1091927Swollman 1101927Swollman#define YPSET_NO 0 1111927Swollman#define YPSET_LOCAL 1 1121927Swollman#define YPSET_ALL 2 1131927Swollmanint ypsetmode = YPSET_NO; 1146732Swpaulint ypsecuremode = 0; 1156732Swpaul 1169600Swpaul/* 1179600Swpaul * Special restricted mode variables: when in restricted mode, only the 1189600Swpaul * specified restricted_domain will be bound, and only the servers listed 1199600Swpaul * in restricted_addrs will be used for binding. 1209600Swpaul */ 1219600Swpaul#define RESTRICTED_SERVERS 10 1229600Swpaulint yp_restricted = 0; 1239600Swpaulstruct in_addr restricted_addrs[RESTRICTED_SERVERS]; 1249600Swpaul 1258091Swpaul/* No more than MAX_CHILDREN child broadcasters at a time. */ 1268755Swpaul#ifndef MAX_CHILDREN 1278091Swpaul#define MAX_CHILDREN 5 1288755Swpaul#endif 1298425Swpaul/* No more than MAX_DOMAINS simultaneous domains */ 1308755Swpaul#ifndef MAX_DOMAINS 1318425Swpaul#define MAX_DOMAINS 200 1328755Swpaul#endif 1338755Swpaul/* RPC timeout value */ 1348425Swpaul#ifndef FAIL_THRESHOLD 13521539Swpaul#define FAIL_THRESHOLD 20 1368425Swpaul#endif 1378425Swpaul 1389600Swpaul/* Number of times to fish for a response froma particular set of hosts */ 1399600Swpaul#ifndef MAX_RETRIES 1409600Swpaul#define MAX_RETRIES 30 1419600Swpaul#endif 1429600Swpaul 1439600Swpaulint retries = 0; 1448091Swpaulint children = 0; 1458425Swpaulint domains = 0; 1468474Swpaulint yplockfd; 1478755Swpaulfd_set fdsr; 1488091Swpaul 1491927SwollmanSVCXPRT *udptransp, *tcptransp; 1501927Swollman 1511927Swollmanvoid * 1521927Swollmanypbindproc_null_2(transp, argp, clnt) 1531927SwollmanSVCXPRT *transp; 1541927Swollmanvoid *argp; 1551927SwollmanCLIENT *clnt; 1561927Swollman{ 1571927Swollman static char res; 1581927Swollman 1591927Swollman bzero((char *)&res, sizeof(res)); 1601927Swollman return (void *)&res; 1611927Swollman} 1621927Swollman 1631927Swollmanstruct ypbind_resp * 1641927Swollmanypbindproc_domain_2(transp, argp, clnt) 1651927SwollmanSVCXPRT *transp; 16612862Swpauldomainname *argp; 1671927SwollmanCLIENT *clnt; 1681927Swollman{ 1691927Swollman static struct ypbind_resp res; 1701927Swollman struct _dom_binding *ypdb; 1711927Swollman char path[MAXPATHLEN]; 1721927Swollman 1731927Swollman bzero((char *)&res, sizeof res); 1741927Swollman res.ypbind_status = YPBIND_FAIL_VAL; 17512862Swpaul res.ypbind_resp_u.ypbind_error = YPBIND_ERR_NOSERV; 1761927Swollman 1778755Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 17812862Swpaul if( strcmp(ypdb->dom_domain, *argp) == 0) 1791927Swollman break; 1808755Swpaul } 1811927Swollman 1821927Swollman if(ypdb==NULL) { 1839600Swpaul if (yp_restricted) { 18412862Swpaul syslog(LOG_NOTICE, "Running in restricted mode -- request to bind domain \"%s\" rejected.\n", *argp); 1859600Swpaul return &res; 1869600Swpaul } 1879600Swpaul 1888474Swpaul if (domains >= MAX_DOMAINS) { 1898425Swpaul syslog(LOG_WARNING, "domain limit (%d) exceeded", 1908425Swpaul MAX_DOMAINS); 19112862Swpaul res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 1928428Swpaul return &res; 1938425Swpaul } 1941927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 1958857Srgrimes if (ypdb == NULL) { 19621539Swpaul syslog(LOG_WARNING, "malloc: %m"); 19712862Swpaul res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC; 1988428Swpaul return &res; 1998246Swpaul } 2001927Swollman bzero((char *)ypdb, sizeof *ypdb); 20112862Swpaul strncpy(ypdb->dom_domain, *argp, sizeof ypdb->dom_domain); 2021927Swollman ypdb->dom_vers = YPVERS; 2031927Swollman ypdb->dom_alive = 0; 2048091Swpaul ypdb->dom_default = 0; 2051927Swollman ypdb->dom_lockfd = -1; 2068425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 2078425Swpaul ypdb->dom_domain, ypdb->dom_vers); 2081927Swollman unlink(path); 2091927Swollman ypdb->dom_pnext = ypbindlist; 2101927Swollman ypbindlist = ypdb; 2118425Swpaul domains++; 2121927Swollman } 2131927Swollman 2148755Swpaul if (ping(ypdb)) { 2157982Swpaul return &res; 2168755Swpaul } 2171927Swollman 2181927Swollman res.ypbind_status = YPBIND_SUCC_VAL; 21912862Swpaul res.ypbind_resp_u.ypbind_error = 0; /* Success */ 22012862Swpaul *(u_long *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr = 2211927Swollman ypdb->dom_server_addr.sin_addr.s_addr; 22212862Swpaul *(u_short *)&res.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port = 2238091Swpaul ypdb->dom_server_addr.sin_port; 2241927Swollman /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 2251927Swollman inet_ntoa(ypdb->dom_server_addr.sin_addr), 2261927Swollman ntohs(ypdb->dom_server_addr.sin_port));*/ 2271927Swollman return &res; 2281927Swollman} 2291927Swollman 2308755Swpaulvoid * 2311927Swollmanypbindproc_setdom_2(transp, argp, clnt) 2321927SwollmanSVCXPRT *transp; 23312862Swpaulypbind_setdom *argp; 2341927SwollmanCLIENT *clnt; 2351927Swollman{ 2361927Swollman struct sockaddr_in *fromsin, bindsin; 2371927Swollman 2381927Swollman fromsin = svc_getcaller(transp); 2391927Swollman 2401927Swollman switch(ypsetmode) { 2411927Swollman case YPSET_LOCAL: 2428755Swpaul if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { 2438755Swpaul svcerr_noprog(transp); 2448755Swpaul return; 2458755Swpaul } 2461927Swollman break; 2471927Swollman case YPSET_ALL: 2481927Swollman break; 2491927Swollman case YPSET_NO: 2501927Swollman default: 2518755Swpaul svcerr_noprog(transp); 2528755Swpaul return; 2531927Swollman } 2541927Swollman 2558755Swpaul if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) { 2568755Swpaul svcerr_noprog(transp); 2578755Swpaul return; 2588755Swpaul } 2591927Swollman 2608755Swpaul if(argp->ypsetdom_vers != YPVERS) { 2618755Swpaul svcerr_noprog(transp); 2628755Swpaul return; 2638755Swpaul } 2641927Swollman 2651927Swollman bzero((char *)&bindsin, sizeof bindsin); 2661927Swollman bindsin.sin_family = AF_INET; 26712862Swpaul bindsin.sin_addr.s_addr = *(u_long *)argp->ypsetdom_binding.ypbind_binding_addr; 26812862Swpaul bindsin.sin_port = *(u_short *)argp->ypsetdom_binding.ypbind_binding_port; 2691927Swollman rpc_received(argp->ypsetdom_domain, &bindsin, 1); 2701927Swollman 2718755Swpaul return; 2721927Swollman} 2731927Swollman 2741927Swollmanstatic void 2751927Swollmanypbindprog_2(rqstp, transp) 2761927Swollmanstruct svc_req *rqstp; 2771927Swollmanregister SVCXPRT *transp; 2781927Swollman{ 2791927Swollman union { 28012862Swpaul domainname ypbindproc_domain_2_arg; 2811927Swollman struct ypbind_setdom ypbindproc_setdom_2_arg; 2821927Swollman } argument; 2831927Swollman struct authunix_parms *creds; 2841927Swollman char *result; 2851927Swollman bool_t (*xdr_argument)(), (*xdr_result)(); 2861927Swollman char *(*local)(); 2871927Swollman 2881927Swollman switch (rqstp->rq_proc) { 2891927Swollman case YPBINDPROC_NULL: 2901927Swollman xdr_argument = xdr_void; 2911927Swollman xdr_result = xdr_void; 2921927Swollman local = (char *(*)()) ypbindproc_null_2; 2931927Swollman break; 2941927Swollman 2951927Swollman case YPBINDPROC_DOMAIN: 2961927Swollman xdr_argument = xdr_domainname; 2971927Swollman xdr_result = xdr_ypbind_resp; 2981927Swollman local = (char *(*)()) ypbindproc_domain_2; 2991927Swollman break; 3001927Swollman 3011927Swollman case YPBINDPROC_SETDOM: 3021927Swollman switch(rqstp->rq_cred.oa_flavor) { 3031927Swollman case AUTH_UNIX: 3041927Swollman creds = (struct authunix_parms *)rqstp->rq_clntcred; 3051927Swollman if( creds->aup_uid != 0) { 3061927Swollman svcerr_auth(transp, AUTH_BADCRED); 3071927Swollman return; 3081927Swollman } 3091927Swollman break; 3101927Swollman default: 3111927Swollman svcerr_auth(transp, AUTH_TOOWEAK); 3121927Swollman return; 3131927Swollman } 3141927Swollman 3151927Swollman xdr_argument = xdr_ypbind_setdom; 3161927Swollman xdr_result = xdr_void; 3171927Swollman local = (char *(*)()) ypbindproc_setdom_2; 3181927Swollman break; 3191927Swollman 3201927Swollman default: 3211927Swollman svcerr_noproc(transp); 3221927Swollman return; 3231927Swollman } 3241927Swollman bzero((char *)&argument, sizeof(argument)); 32521096Speter if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 3261927Swollman svcerr_decode(transp); 3271927Swollman return; 3281927Swollman } 3291927Swollman result = (*local)(transp, &argument, rqstp); 3301927Swollman if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 3311927Swollman svcerr_systemerr(transp); 3321927Swollman } 3331927Swollman return; 3341927Swollman} 3351927Swollman 3368091Swpaul/* Jack the reaper */ 3378091Swpaulvoid reaper(sig) 3388091Swpaulint sig; 3398091Swpaul{ 3408091Swpaul int st; 3418091Swpaul 3429532Swpaul while(wait3(&st, WNOHANG, NULL) > 0) 3439532Swpaul children--; 3448091Swpaul} 3458091Swpaul 3468425Swpaulvoid terminate(sig) 3478425Swpaulint sig; 3488425Swpaul{ 3498425Swpaul struct _dom_binding *ypdb; 3508425Swpaul char path[MAXPATHLEN]; 3518425Swpaul 3528425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 3538425Swpaul close(ypdb->dom_lockfd); 3548755Swpaul if (ypdb->dom_broadcast_pid) 3558755Swpaul kill(ypdb->dom_broadcast_pid, SIGINT); 3568425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 3578425Swpaul ypdb->dom_domain, ypdb->dom_vers); 3588425Swpaul unlink(path); 3598425Swpaul } 3608474Swpaul close(yplockfd); 3618474Swpaul unlink(YPBINDLOCK); 3628425Swpaul pmap_unset(YPBINDPROG, YPBINDVERS); 3638425Swpaul exit(0); 3648425Swpaul} 3658857Srgrimes 3668091Swpaulvoid 3671927Swollmanmain(argc, argv) 3688091Swpaulint argc; 3691927Swollmanchar **argv; 3701927Swollman{ 3711927Swollman char path[MAXPATHLEN]; 3721927Swollman struct timeval tv; 3731927Swollman int i; 3748425Swpaul DIR *dird; 3758425Swpaul struct dirent *dirp; 3768755Swpaul struct _dom_binding *ypdb; 3771927Swollman 3788474Swpaul /* Check that another ypbind isn't already running. */ 3798474Swpaul if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) { 3808474Swpaul perror(YPBINDLOCK); 3818474Swpaul exit(1); 3828474Swpaul } 3838474Swpaul 3848474Swpaul if(flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { 3858474Swpaul fprintf (stderr, "Another ypbind is already running. Aborting.\n"); 3868474Swpaul exit(1); 3878474Swpaul } 3888474Swpaul 3899600Swpaul /* XXX domainname will be overriden if we use restricted mode */ 39012862Swpaul yp_get_default_domain(&domain_name); 39112862Swpaul if( domain_name[0] == '\0') { 3921927Swollman fprintf(stderr, "domainname not set. Aborting.\n"); 3931927Swollman exit(1); 3941927Swollman } 3951927Swollman 3961927Swollman for(i=1; i<argc; i++) { 3971927Swollman if( strcmp("-ypset", argv[i]) == 0) 3981927Swollman ypsetmode = YPSET_ALL; 3991927Swollman else if (strcmp("-ypsetme", argv[i]) == 0) 4006732Swpaul ypsetmode = YPSET_LOCAL; 4016732Swpaul else if (strcmp("-s", argv[i]) == 0) 4026732Swpaul ypsecuremode++; 4039600Swpaul else if (strcmp("-S", argv[i]) == 0 && argc > i) 4049600Swpaul yp_restricted_mode(argv[i+1]); 4051927Swollman } 4061927Swollman 4078425Swpaul /* blow away everything in BINDINGDIR (if it exists) */ 4081927Swollman 4098425Swpaul if ((dird = opendir(BINDINGDIR)) != NULL) { 4108425Swpaul char path[MAXPATHLEN]; 4118425Swpaul while ((dirp = readdir(dird)) != NULL) 4128425Swpaul if (strcmp(dirp->d_name, ".") && 4138425Swpaul strcmp(dirp->d_name, "..")) { 4148425Swpaul sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); 4158425Swpaul unlink(path); 4168425Swpaul } 4178425Swpaul closedir(dird); 4188425Swpaul } 4191927Swollman 4201927Swollman#ifdef DAEMON 4218425Swpaul if (daemon(0,0)) { 4221927Swollman perror("fork"); 4231927Swollman exit(1); 4241927Swollman } 4251927Swollman#endif 4261927Swollman 4271927Swollman pmap_unset(YPBINDPROG, YPBINDVERS); 4281927Swollman 4291927Swollman udptransp = svcudp_create(RPC_ANYSOCK); 4301927Swollman if (udptransp == NULL) { 4318425Swpaul fprintf(stderr, "cannot create udp service.\n"); 4321927Swollman exit(1); 4331927Swollman } 4341927Swollman if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 4351927Swollman IPPROTO_UDP)) { 4368425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).\n"); 4371927Swollman exit(1); 4381927Swollman } 4391927Swollman 4401927Swollman tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 4411927Swollman if (tcptransp == NULL) { 4428425Swpaul fprintf(stderr, "cannot create tcp service.\n"); 4431927Swollman exit(1); 4441927Swollman } 4451927Swollman 4461927Swollman if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 4471927Swollman IPPROTO_TCP)) { 4488425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).\n"); 4491927Swollman exit(1); 4501927Swollman } 4511927Swollman 4521927Swollman /* build initial domain binding, make it "unsuccessful" */ 4531927Swollman ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 4548246Swpaul if (ypbindlist == NULL) { 4558246Swpaul perror("malloc"); 4568246Swpaul exit(1); 4578246Swpaul } 4581927Swollman bzero((char *)ypbindlist, sizeof *ypbindlist); 45912862Swpaul strncpy(ypbindlist->dom_domain, domain_name, sizeof ypbindlist->dom_domain); 4601927Swollman ypbindlist->dom_vers = YPVERS; 4611927Swollman ypbindlist->dom_alive = 0; 4621927Swollman ypbindlist->dom_lockfd = -1; 4638091Swpaul ypbindlist->dom_default = 1; 4648425Swpaul domains++; 4651927Swollman 4668425Swpaul signal(SIGCHLD, reaper); 4678425Swpaul signal(SIGTERM, terminate); 4688425Swpaul 4698246Swpaul openlog(argv[0], LOG_PID, LOG_DAEMON); 4706478Swpaul 4718425Swpaul /* Kick off the default domain */ 4728425Swpaul broadcast(ypbindlist); 4738425Swpaul 4741927Swollman while(1) { 4751927Swollman fdsr = svc_fdset; 4768091Swpaul 4778425Swpaul tv.tv_sec = 60; 4781927Swollman tv.tv_usec = 0; 4791927Swollman 4808091Swpaul switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 4811927Swollman case 0: 4821927Swollman checkwork(); 4831927Swollman break; 4841927Swollman case -1: 4858755Swpaul if (errno != EINTR) 48621539Swpaul syslog(LOG_WARNING, "select: %m"); 4878755Swpaul break; 4881927Swollman default: 4898755Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 4908755Swpaul if (READFD > 0 && FD_ISSET(READFD, &fdsr)) { 4918853Swpaul handle_children(ypdb); 4928755Swpaul if (children == (MAX_CHILDREN - 1)) 4938755Swpaul checkwork(); 4948091Swpaul } 4951927Swollman } 4961927Swollman svc_getreqset(&fdsr); 4971927Swollman break; 4981927Swollman } 4991927Swollman } 5001927Swollman} 5011927Swollman 5028091Swpaulvoid 5031927Swollmancheckwork() 5041927Swollman{ 5051927Swollman struct _dom_binding *ypdb; 5061927Swollman 5078425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 5088425Swpaul ping(ypdb); 5091927Swollman} 5101927Swollman 5118091Swpaul/* The clnt_broadcast() callback mechanism sucks. */ 5128091Swpaul 5138091Swpaul/* 5148091Swpaul * Receive results from broadcaster. Don't worry about passing 5158853Swpaul * bogus info to rpc_received() -- it can handle it. Note that we 5168853Swpaul * must be sure to invalidate the dom_pipe_fds descriptors here: 5178853Swpaul * since descriptors can be re-used, we have to make sure we 5188853Swpaul * don't mistake one of the RPC descriptors for one of the pipes. 5198853Swpaul * What's weird is that forgetting to invalidate the pipe descriptors 5208853Swpaul * doesn't always result in an error (otherwise I would have caught 5218853Swpaul * the mistake much sooner), even though logically it should. 5228091Swpaul */ 5238853Swpaulvoid handle_children(ypdb) 5248853Swpaulstruct _dom_binding *ypdb; 5258091Swpaul{ 5268091Swpaul char buf[YPMAXDOMAIN + 1]; 5278091Swpaul struct sockaddr_in addr; 52821539Swpaul int d = 0, a = 0; 52921539Swpaul struct _dom_binding *y, *prev = NULL; 53021539Swpaul char path[MAXPATHLEN]; 5318091Swpaul 53221539Swpaul if ((d = read(READFD, &buf, sizeof(buf))) <= 0) 53321539Swpaul syslog(LOG_WARNING, "could not read from child: %m"); 5348755Swpaul 53521539Swpaul if ((a = read(READFD, &addr, sizeof(struct sockaddr_in))) < 0) 53621539Swpaul syslog(LOG_WARNING, "could not read from child: %m"); 53721539Swpaul 5388853Swpaul close(READFD); 5398853Swpaul FD_CLR(READFD, &fdsr); 5408853Swpaul FD_CLR(READFD, &svc_fdset); 5418853Swpaul READFD = WRITEFD = -1; 54221539Swpaul if (d > 0 && a > 0) 54321539Swpaul rpc_received((char *)&buf, &addr, 0); 54421539Swpaul else { 54521539Swpaul for(y=ypbindlist; y; y=y->dom_pnext) { 54621539Swpaul if (y == ypdb) 54721539Swpaul break; 54821539Swpaul prev = y; 54921539Swpaul } 55021539Swpaul switch(ypdb->dom_default) { 55121539Swpaul case 0: 55221539Swpaul if (prev == NULL) 55321539Swpaul ypbindlist = y->dom_pnext; 55421539Swpaul else 55521539Swpaul prev->dom_pnext = y->dom_pnext; 55621539Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 55721539Swpaul ypdb->dom_domain, YPVERS); 55821539Swpaul close(ypdb->dom_lockfd); 55921539Swpaul unlink(path); 56021539Swpaul free(ypdb); 56121539Swpaul domains--; 56221539Swpaul return; 56321539Swpaul case 1: 56421539Swpaul ypdb->dom_broadcast_pid = 0; 56521539Swpaul ypdb->dom_alive = 0; 56621539Swpaul broadcast(ypdb); 56721539Swpaul return; 56821539Swpaul default: 56921539Swpaul break; 57021539Swpaul } 57121539Swpaul } 57221539Swpaul 57321539Swpaul return; 5748091Swpaul} 5758091Swpaul 5768091Swpaul/* 5778091Swpaul * Send our dying words back to our parent before we perish. 5788091Swpaul */ 5798091Swpaulint 5808091Swpaultell_parent(dom, addr) 5811927Swollmanchar *dom; 5828091Swpaulstruct sockaddr_in *addr; 5831927Swollman{ 5848091Swpaul char buf[YPMAXDOMAIN + 1]; 5858091Swpaul struct timeval timeout; 5868091Swpaul fd_set fds; 5871927Swollman 5888091Swpaul timeout.tv_sec = 5; 5898091Swpaul timeout.tv_usec = 0; 5901927Swollman 5918755Swpaul sprintf(buf, "%s", broad_domain->dom_domain); 5928755Swpaul if (write(BROADFD, &buf, sizeof(buf)) < 0) 5938091Swpaul return(1); 5941927Swollman 5958091Swpaul /* 5968091Swpaul * Stay in sync with parent: wait for it to read our first 5978091Swpaul * message before sending the second. 5988091Swpaul */ 5991927Swollman 6008091Swpaul FD_ZERO(&fds); 6018755Swpaul FD_SET(BROADFD, &fds); 6028091Swpaul if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 6038091Swpaul return(1); 6048755Swpaul if (FD_ISSET(BROADFD, &fds)) { 6058755Swpaul if (write(BROADFD, addr, sizeof(struct sockaddr_in)) < 0) 6068091Swpaul return(1); 6078091Swpaul } else { 6088091Swpaul return(1); 6091927Swollman } 6101927Swollman 6118755Swpaul close(BROADFD); 6128091Swpaul return (0); 6138091Swpaul} 6141927Swollman 6158091Swpaulbool_t broadcast_result(out, addr) 6168091Swpaulbool_t *out; 6178091Swpaulstruct sockaddr_in *addr; 6188091Swpaul{ 6199600Swpaul if (retries >= MAX_RETRIES) { 6209600Swpaul bzero((char *)addr, sizeof(struct sockaddr_in)); 6219600Swpaul if (tell_parent(broad_domain->dom_domain, addr)) 6229600Swpaul syslog(LOG_WARNING, "lost connection to parent"); 6239600Swpaul return TRUE; 6249600Swpaul } 6259600Swpaul 6269600Swpaul if (yp_restricted && verify(addr->sin_addr)) { 6279600Swpaul retries++; 6289600Swpaul syslog(LOG_NOTICE, "NIS server at %s not in restricted mode access list -- rejecting.\n",inet_ntoa(addr->sin_addr)); 6299600Swpaul return FALSE; 6309600Swpaul } else { 6319600Swpaul if (tell_parent(broad_domain->dom_domain, addr)) 6329600Swpaul syslog(LOG_WARNING, "lost connection to parent"); 6339600Swpaul return TRUE; 6349600Swpaul } 6358091Swpaul} 6368091Swpaul 6378091Swpaul/* 6388091Swpaul * The right way to send RPC broadcasts. 6398091Swpaul * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 6408091Swpaul * blocks while waiting for replies, so we have to fork off seperate 6418091Swpaul * broadcaster processes that do the waiting and then transmit their 6428091Swpaul * results back to the parent for processing. We also have to remember 6438091Swpaul * to save the name of the domain we're trying to bind in a global 6448091Swpaul * variable since clnt_broadcast() provides no way to pass things to 6458091Swpaul * the 'eachresult' callback function. 6468091Swpaul */ 6478091Swpaulvoid 6488091Swpaulbroadcast(ypdb) 6498091Swpaulstruct _dom_binding *ypdb; 6508091Swpaul{ 6518091Swpaul bool_t out = FALSE; 6528091Swpaul enum clnt_stat stat; 6538091Swpaul 6548755Swpaul if (children >= MAX_CHILDREN || ypdb->dom_broadcast_pid) 6558091Swpaul return; 6568091Swpaul 6578755Swpaul if (pipe(ypdb->dom_pipe_fds) < 0) { 65821539Swpaul syslog(LOG_WARNING, "pipe: %m"); 6598091Swpaul return; 6601927Swollman } 6611927Swollman 6628425Swpaul if (ypdb->dom_vers = -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) 6638755Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" not responding", 6648425Swpaul inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 6658425Swpaul 6668755Swpaul broad_domain = ypdb; 6678425Swpaul flock(ypdb->dom_lockfd, LOCK_UN); 6688425Swpaul 6698755Swpaul switch((ypdb->dom_broadcast_pid = fork())) { 6708091Swpaul case 0: 6718755Swpaul close(READFD); 67221539Swpaul signal(SIGCHLD, SIG_DFL); 67321539Swpaul signal(SIGTERM, SIG_DFL); 6748091Swpaul break; 6758091Swpaul case -1: 67621539Swpaul syslog(LOG_WARNING, "fork: %m"); 6778755Swpaul close(READFD); 6788755Swpaul close(WRITEFD); 6798091Swpaul return; 6808091Swpaul default: 6818755Swpaul close(WRITEFD); 6828755Swpaul FD_SET(READFD, &svc_fdset); 6838091Swpaul children++; 6848091Swpaul return; 6851927Swollman } 6866478Swpaul 6878755Swpaul /* Release all locks before doing anything else. */ 6888755Swpaul while(ypbindlist) { 6898755Swpaul close(ypbindlist->dom_lockfd); 6908755Swpaul ypbindlist = ypbindlist->dom_pnext; 6918755Swpaul } 6928755Swpaul close(yplockfd); 6938755Swpaul 6949600Swpaul retries = 0; 6959600Swpaul 69612862Swpaul { 69712862Swpaul char *ptr; 6988091Swpaul 69912862Swpaul ptr = (char *)&ypdb->dom_domain; 70012862Swpaul stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 70112862Swpaul xdr_domainname, (char *)&ptr, xdr_bool, (char *)&out, 70212862Swpaul broadcast_result); 70312862Swpaul } 70412862Swpaul 7058091Swpaul if (stat != RPC_SUCCESS) { 7068091Swpaul bzero((char *)&ypdb->dom_server_addr, 7078091Swpaul sizeof(struct sockaddr_in)); 7088755Swpaul if (tell_parent(ypdb->dom_domain, &ypdb->dom_server_addr)) 7098091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 7108091Swpaul } 7118755Swpaul 7128091Swpaul exit(0); 7131927Swollman} 7141927Swollman 7158091Swpaul/* 7168091Swpaul * The right way to check if a server is alive. 7178091Swpaul * Attempt to get a client handle pointing to the server and send a 7188755Swpaul * YPPROC_DOMAIN. If we can't get a handle or we get a reply of FALSE, 7198755Swpaul * we invalidate this binding entry and send out a broadcast to try to 7208755Swpaul * establish a new binding. Note that we treat non-default domains 7218091Swpaul * specially: once bound, we keep tabs on our server, but if it 7228091Swpaul * goes away and fails to respond after one round of broadcasting, we 7238091Swpaul * abandon it until a client specifically references it again. We make 7248091Swpaul * every effort to keep our default domain bound, however, since we 7258091Swpaul * need it to keep the system on its feet. 7268091Swpaul */ 7278091Swpaulint 7288425Swpaulping(ypdb) 7298091Swpaulstruct _dom_binding *ypdb; 7301927Swollman{ 7318091Swpaul bool_t out; 7328091Swpaul struct timeval interval, timeout; 7338091Swpaul enum clnt_stat stat; 7348091Swpaul int rpcsock = RPC_ANYSOCK; 7358755Swpaul CLIENT *client_handle; 7368091Swpaul time_t t; 7371927Swollman 7388755Swpaul interval.tv_sec = FAIL_THRESHOLD; 7398091Swpaul interval.tv_usec = 0; 7408091Swpaul timeout.tv_sec = FAIL_THRESHOLD; 7418091Swpaul timeout.tv_usec = 0; 7421927Swollman 7438755Swpaul if (ypdb->dom_broadcast_pid) 7448091Swpaul return(1); 7458091Swpaul 7468755Swpaul if ((client_handle = clntudp_bufcreate(&ypdb->dom_server_addr, 7478755Swpaul YPPROG, YPVERS, interval, &rpcsock, RPCSMALLMSGSIZE, 7488755Swpaul RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 7498755Swpaul /* Can't get a handle: we're dead. */ 7508755Swpaul ypdb->dom_alive = 0; 7518755Swpaul ypdb->dom_vers = -1; 7528755Swpaul broadcast(ypdb); 7538755Swpaul return(1); 7541927Swollman } 7551927Swollman 75612862Swpaul { 75712862Swpaul char *ptr; 75812862Swpaul 75912862Swpaul ptr = (char *)&ypdb->dom_domain; 76012862Swpaul 76112862Swpaul if ((stat = clnt_call(client_handle, YPPROC_DOMAIN, 76212862Swpaul xdr_domainname, (char *)&ptr, xdr_bool, (char *)&out, 76312862Swpaul timeout)) != RPC_SUCCESS || out == FALSE) { 76412862Swpaul ypdb->dom_alive = 0; 76512862Swpaul ypdb->dom_vers = -1; 76612862Swpaul clnt_destroy(client_handle); 76712862Swpaul broadcast(ypdb); 76812862Swpaul return(1); 76912862Swpaul } 7708091Swpaul } 7711927Swollman 7728755Swpaul clnt_destroy(client_handle); 7738091Swpaul return(0); 7741927Swollman} 7751927Swollman 7768091Swpaulvoid rpc_received(dom, raddrp, force) 7771927Swollmanchar *dom; 7781927Swollmanstruct sockaddr_in *raddrp; 7791927Swollmanint force; 7801927Swollman{ 7818425Swpaul struct _dom_binding *ypdb, *prev = NULL; 7821927Swollman struct iovec iov[2]; 7831927Swollman struct ypbind_resp ybr; 7841927Swollman char path[MAXPATHLEN]; 7851927Swollman int fd; 7861927Swollman 7876732Swpaul /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 7886732Swpaul ntohs(raddrp->sin_port), dom);*/ 7891927Swollman 7901927Swollman if(dom==NULL) 7911927Swollman return; 7921927Swollman 7938425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 7948091Swpaul if( strcmp(ypdb->dom_domain, dom) == 0) 7958091Swpaul break; 7968425Swpaul prev = ypdb; 7978425Swpaul } 7988091Swpaul 7998755Swpaul if (ypdb && force) { 8008755Swpaul if (ypdb->dom_broadcast_pid) { 8018755Swpaul kill(ypdb->dom_broadcast_pid, SIGINT); 8028755Swpaul close(READFD); 8038853Swpaul FD_CLR(READFD, &fdsr); 8048853Swpaul FD_CLR(READFD, &svc_fdset); 8058853Swpaul READFD = WRITEFD = -1; 8068755Swpaul } 8078755Swpaul } 8088755Swpaul 8099600Swpaul /* if in secure mode, check originating port number */ 8109600Swpaul if ((ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED))) { 8116732Swpaul syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 8126732Swpaul inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 8136732Swpaul dom); 8148246Swpaul if (ypdb != NULL) { 8158755Swpaul ypdb->dom_broadcast_pid = 0; 8168246Swpaul ypdb->dom_alive = 0; 8178246Swpaul } 8186732Swpaul return; 8196732Swpaul } 8206732Swpaul 8218246Swpaul if (raddrp->sin_addr.s_addr == (long)0) { 8228755Swpaul switch(ypdb->dom_default) { 8238755Swpaul case 0: 8248755Swpaul if (prev == NULL) 8258755Swpaul ypbindlist = ypdb->dom_pnext; 8268755Swpaul else 8278755Swpaul prev->dom_pnext = ypdb->dom_pnext; 8288755Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 8298755Swpaul ypdb->dom_domain, YPVERS); 8308755Swpaul close(ypdb->dom_lockfd); 8318755Swpaul unlink(path); 8328755Swpaul free(ypdb); 8338755Swpaul domains--; 8348755Swpaul return; 8358755Swpaul case 1: 8368755Swpaul ypdb->dom_broadcast_pid = 0; 8378755Swpaul ypdb->dom_alive = 0; 8388755Swpaul broadcast(ypdb); 8398755Swpaul return; 8408755Swpaul default: 8418755Swpaul break; 8428755Swpaul } 8438246Swpaul } 8448246Swpaul 8451927Swollman if(ypdb==NULL) { 8468246Swpaul if (force == 0) 8471927Swollman return; 8481927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 8498857Srgrimes if (ypdb == NULL) { 85021539Swpaul syslog(LOG_WARNING, "malloc: %m"); 8518246Swpaul return; 8528246Swpaul } 8531927Swollman bzero((char *)ypdb, sizeof *ypdb); 8541927Swollman strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 8551927Swollman ypdb->dom_lockfd = -1; 8568091Swpaul ypdb->dom_default = 0; 8571927Swollman ypdb->dom_pnext = ypbindlist; 8581927Swollman ypbindlist = ypdb; 8591927Swollman } 8601927Swollman 8618091Swpaul /* We've recovered from a crash: inform the world. */ 8628091Swpaul if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr) 8638755Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain \"%s\" OK", 8648755Swpaul inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); 8656478Swpaul 8661927Swollman bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 8671927Swollman sizeof ypdb->dom_server_addr); 8686478Swpaul 8691927Swollman ypdb->dom_vers = YPVERS; 8701927Swollman ypdb->dom_alive = 1; 8718755Swpaul ypdb->dom_broadcast_pid = 0; 8721927Swollman 8731927Swollman if(ypdb->dom_lockfd != -1) 8741927Swollman close(ypdb->dom_lockfd); 8751927Swollman 8768091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 8771927Swollman ypdb->dom_domain, ypdb->dom_vers); 8781927Swollman#ifdef O_SHLOCK 8797864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 8801927Swollman (void)mkdir(BINDINGDIR, 0755); 8817864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 8821927Swollman return; 8831927Swollman } 8841927Swollman#else 8857864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 8861927Swollman (void)mkdir(BINDINGDIR, 0755); 8877864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 8881927Swollman return; 8891927Swollman } 8901927Swollman flock(fd, LOCK_SH); 8911927Swollman#endif 8921927Swollman 8931927Swollman /* 8941927Swollman * ok, if BINDINGDIR exists, and we can create the binding file, 8951927Swollman * then write to it.. 8961927Swollman */ 8971927Swollman ypdb->dom_lockfd = fd; 8981927Swollman 8991927Swollman iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 9001927Swollman iov[0].iov_len = sizeof udptransp->xp_port; 9011927Swollman iov[1].iov_base = (caddr_t)&ybr; 9021927Swollman iov[1].iov_len = sizeof ybr; 9031927Swollman 9041927Swollman bzero(&ybr, sizeof ybr); 9051927Swollman ybr.ypbind_status = YPBIND_SUCC_VAL; 90612862Swpaul *(u_long *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr.s_addr; 90712862Swpaul *(u_short *)&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 9081927Swollman 9091927Swollman if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 91021539Swpaul syslog(LOG_WARNING, "write: %m"); 9111927Swollman close(ypdb->dom_lockfd); 9121927Swollman ypdb->dom_lockfd = -1; 9131927Swollman return; 9141927Swollman } 9151927Swollman} 9169600Swpaul 9179600Swpaul/* 9189600Swpaul * Check address against list of allowed servers. Return 0 if okay, 9199600Swpaul * 1 if not matched. 9209600Swpaul */ 9219600Swpaulint 9229600Swpaulverify(addr) 9239600Swpaulstruct in_addr addr; 9249600Swpaul{ 9259600Swpaul int i; 9269600Swpaul 9279600Swpaul for (i = 0; i < RESTRICTED_SERVERS; i++) 9289600Swpaul if (!bcmp((char *)&addr, (char *)&restricted_addrs[i], 9299600Swpaul sizeof(struct in_addr))) 9309600Swpaul return(0); 9319600Swpaul 9329600Swpaul return(1); 9339600Swpaul} 9349600Swpaul 9359600Swpaul/* 9369600Swpaul * Try to set restricted mode. We default to normal mode if we can't 9379600Swpaul * resolve the specified hostnames. 9389600Swpaul */ 9399600Swpaulvoid 9409600Swpaulyp_restricted_mode(args) 9419600Swpaulchar *args; 9429600Swpaul{ 9439600Swpaul struct hostent *h; 9449600Swpaul int i = 0; 9459600Swpaul char *s; 9469600Swpaul 9479600Swpaul /* Find the restricted domain. */ 9489600Swpaul if ((s = strsep(&args, ",")) == NULL) 9499600Swpaul return; 95012862Swpaul domain_name = s; 9519600Swpaul 9529600Swpaul /* Get the addresses of the servers. */ 9539600Swpaul while ((s = strsep(&args, ",")) != NULL && i < RESTRICTED_SERVERS) { 9549600Swpaul if ((h = gethostbyname(s)) == NULL) 9559600Swpaul return; 9569600Swpaul bcopy ((char *)h->h_addr_list[0], (char *)&restricted_addrs[i], 9579600Swpaul sizeof(struct in_addr)); 9589600Swpaul i++; 9599600Swpaul } 9609600Swpaul 9619600Swpaul /* ypset and ypsetme not allowed with restricted mode */ 9629600Swpaul ypsetmode = YPSET_NO; 9639600Swpaul 9649600Swpaul yp_restricted = 1; 9659600Swpaul return; 9669600Swpaul} 967