ypbind.c revision 8474
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 318474Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.11 1995/05/11 00:16:54 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; 768091Swpaul CLIENT *client_handle; 771927Swollman long int dom_vers; 781927Swollman int dom_lockfd; 791927Swollman int dom_alive; 808091Swpaul int dom_broadcasting; 818091Swpaul int dom_default; 821927Swollman}; 831927Swollman 841927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp(); 851927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 861927Swollmanextern bool_t xdr_ypbind_setdom(); 871927Swollman 888091Swpaulvoid checkwork __P((void)); 898091Swpaulvoid *ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *)); 908091Swpaulbool_t *ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *)); 918091Swpaulvoid rpc_received __P((char *, struct sockaddr_in *, int )); 928091Swpaulvoid broadcast __P((struct _dom_binding *)); 938425Swpaulint ping __P((struct _dom_binding *)); 948091Swpaulvoid handle_children __P(( int )); 958425Swpaulvoid reaper __P((int)); 968425Swpaulvoid terminate __P((int)); 978091Swpaul 988091Swpaulstatic char *broad_domain; 991927Swollmanchar *domainname; 1001927Swollmanstruct _dom_binding *ypbindlist; 1011927Swollman 1021927Swollman#define YPSET_NO 0 1031927Swollman#define YPSET_LOCAL 1 1041927Swollman#define YPSET_ALL 2 1051927Swollmanint ypsetmode = YPSET_NO; 1066732Swpaulint ypsecuremode = 0; 1076732Swpaul 1088091Swpaul/* No more than MAX_CHILDREN child broadcasters at a time. */ 1098091Swpaul#define MAX_CHILDREN 5 1108425Swpaul/* No more than MAX_DOMAINS simultaneous domains */ 1118425Swpaul#define MAX_DOMAINS 200 1128425Swpaul#ifndef FAIL_THRESHOLD 1138425Swpaul#define FAIL_THRESHOLD 20 1148425Swpaul#endif 1158425Swpaul 1168425Swpaul#define KILLME_MAGIC 0xdeaddead 1178425Swpaul 1188091Swpaulint child_fds[FD_SETSIZE]; 1198091Swpaulstatic int fd[2]; 1208091Swpaulint children = 0; 1218425Swpaulint domains = 0; 1228474Swpaulint yplockfd; 1238091Swpaul 1241927SwollmanSVCXPRT *udptransp, *tcptransp; 1251927Swollman 1261927Swollmanvoid * 1271927Swollmanypbindproc_null_2(transp, argp, clnt) 1281927SwollmanSVCXPRT *transp; 1291927Swollmanvoid *argp; 1301927SwollmanCLIENT *clnt; 1311927Swollman{ 1321927Swollman static char res; 1331927Swollman 1341927Swollman bzero((char *)&res, sizeof(res)); 1351927Swollman return (void *)&res; 1361927Swollman} 1371927Swollman 1381927Swollmanstruct ypbind_resp * 1391927Swollmanypbindproc_domain_2(transp, argp, clnt) 1401927SwollmanSVCXPRT *transp; 1411927Swollmanchar *argp; 1421927SwollmanCLIENT *clnt; 1431927Swollman{ 1441927Swollman static struct ypbind_resp res; 1451927Swollman struct _dom_binding *ypdb; 1461927Swollman char path[MAXPATHLEN]; 1471927Swollman 1481927Swollman bzero((char *)&res, sizeof res); 1491927Swollman res.ypbind_status = YPBIND_FAIL_VAL; 1507982Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_NOSERV; 1511927Swollman 1521927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 1531927Swollman if( strcmp(ypdb->dom_domain, argp) == 0) 1541927Swollman break; 1551927Swollman 1561927Swollman if(ypdb==NULL) { 1578474Swpaul if (domains >= MAX_DOMAINS) { 1588425Swpaul syslog(LOG_WARNING, "domain limit (%d) exceeded", 1598425Swpaul MAX_DOMAINS); 1608425Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; 1618428Swpaul return &res; 1628425Swpaul } 1631927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 1648246Swpaul if (ypdb == NULL) { 1658246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 1668246Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; 1678428Swpaul return &res; 1688246Swpaul } 1691927Swollman bzero((char *)ypdb, sizeof *ypdb); 1701927Swollman strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 1711927Swollman ypdb->dom_vers = YPVERS; 1721927Swollman ypdb->dom_alive = 0; 1738091Swpaul ypdb->dom_default = 0; 1741927Swollman ypdb->dom_lockfd = -1; 1758425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 1768425Swpaul ypdb->dom_domain, ypdb->dom_vers); 1771927Swollman unlink(path); 1781927Swollman ypdb->dom_pnext = ypbindlist; 1791927Swollman ypbindlist = ypdb; 1808425Swpaul domains++; 1811927Swollman } 1821927Swollman 1838425Swpaul if (ping(ypdb)) 1847982Swpaul return &res; 1851927Swollman 1861927Swollman res.ypbind_status = YPBIND_SUCC_VAL; 1878246Swpaul res.ypbind_respbody.ypbind_error = 0; /* Success */ 1881927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 1891927Swollman ypdb->dom_server_addr.sin_addr.s_addr; 1901927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 1918091Swpaul ypdb->dom_server_addr.sin_port; 1921927Swollman /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 1931927Swollman inet_ntoa(ypdb->dom_server_addr.sin_addr), 1941927Swollman ntohs(ypdb->dom_server_addr.sin_port));*/ 1951927Swollman return &res; 1961927Swollman} 1971927Swollman 1981927Swollmanbool_t * 1991927Swollmanypbindproc_setdom_2(transp, argp, clnt) 2001927SwollmanSVCXPRT *transp; 2011927Swollmanstruct ypbind_setdom *argp; 2021927SwollmanCLIENT *clnt; 2031927Swollman{ 2041927Swollman struct sockaddr_in *fromsin, bindsin; 2053033Sdg static char res; 2061927Swollman 2071927Swollman bzero((char *)&res, sizeof(res)); 2081927Swollman fromsin = svc_getcaller(transp); 2091927Swollman 2101927Swollman switch(ypsetmode) { 2111927Swollman case YPSET_LOCAL: 2121927Swollman if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) 2131927Swollman return (void *)NULL; 2141927Swollman break; 2151927Swollman case YPSET_ALL: 2161927Swollman break; 2171927Swollman case YPSET_NO: 2181927Swollman default: 2191927Swollman return (void *)NULL; 2201927Swollman } 2211927Swollman 2221927Swollman if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) 2231927Swollman return (void *)&res; 2241927Swollman 2251927Swollman if(argp->ypsetdom_vers != YPVERS) 2261927Swollman return (void *)&res; 2271927Swollman 2281927Swollman bzero((char *)&bindsin, sizeof bindsin); 2291927Swollman bindsin.sin_family = AF_INET; 2301927Swollman bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 2311927Swollman bindsin.sin_port = argp->ypsetdom_port; 2321927Swollman rpc_received(argp->ypsetdom_domain, &bindsin, 1); 2331927Swollman 2341927Swollman res = 1; 2351927Swollman return (void *)&res; 2361927Swollman} 2371927Swollman 2381927Swollmanstatic void 2391927Swollmanypbindprog_2(rqstp, transp) 2401927Swollmanstruct svc_req *rqstp; 2411927Swollmanregister SVCXPRT *transp; 2421927Swollman{ 2431927Swollman union { 2441927Swollman char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 2451927Swollman struct ypbind_setdom ypbindproc_setdom_2_arg; 2461927Swollman } argument; 2471927Swollman struct authunix_parms *creds; 2481927Swollman char *result; 2491927Swollman bool_t (*xdr_argument)(), (*xdr_result)(); 2501927Swollman char *(*local)(); 2511927Swollman 2521927Swollman switch (rqstp->rq_proc) { 2531927Swollman case YPBINDPROC_NULL: 2541927Swollman xdr_argument = xdr_void; 2551927Swollman xdr_result = xdr_void; 2561927Swollman local = (char *(*)()) ypbindproc_null_2; 2571927Swollman break; 2581927Swollman 2591927Swollman case YPBINDPROC_DOMAIN: 2601927Swollman xdr_argument = xdr_domainname; 2611927Swollman xdr_result = xdr_ypbind_resp; 2621927Swollman local = (char *(*)()) ypbindproc_domain_2; 2631927Swollman break; 2641927Swollman 2651927Swollman case YPBINDPROC_SETDOM: 2661927Swollman switch(rqstp->rq_cred.oa_flavor) { 2671927Swollman case AUTH_UNIX: 2681927Swollman creds = (struct authunix_parms *)rqstp->rq_clntcred; 2691927Swollman if( creds->aup_uid != 0) { 2701927Swollman svcerr_auth(transp, AUTH_BADCRED); 2711927Swollman return; 2721927Swollman } 2731927Swollman break; 2741927Swollman default: 2751927Swollman svcerr_auth(transp, AUTH_TOOWEAK); 2761927Swollman return; 2771927Swollman } 2781927Swollman 2791927Swollman xdr_argument = xdr_ypbind_setdom; 2801927Swollman xdr_result = xdr_void; 2811927Swollman local = (char *(*)()) ypbindproc_setdom_2; 2821927Swollman break; 2831927Swollman 2841927Swollman default: 2851927Swollman svcerr_noproc(transp); 2861927Swollman return; 2871927Swollman } 2881927Swollman bzero((char *)&argument, sizeof(argument)); 2891927Swollman if (!svc_getargs(transp, xdr_argument, &argument)) { 2901927Swollman svcerr_decode(transp); 2911927Swollman return; 2921927Swollman } 2931927Swollman result = (*local)(transp, &argument, rqstp); 2941927Swollman if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 2951927Swollman svcerr_systemerr(transp); 2961927Swollman } 2971927Swollman return; 2981927Swollman} 2991927Swollman 3008091Swpaul/* Jack the reaper */ 3018091Swpaulvoid reaper(sig) 3028091Swpaulint sig; 3038091Swpaul{ 3048091Swpaul int st; 3058091Swpaul 3068091Swpaul wait3(&st, WNOHANG, NULL); 3078091Swpaul} 3088091Swpaul 3098425Swpaulvoid terminate(sig) 3108425Swpaulint sig; 3118425Swpaul{ 3128425Swpaul struct _dom_binding *ypdb; 3138425Swpaul char path[MAXPATHLEN]; 3148425Swpaul 3158425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 3168425Swpaul close(ypdb->dom_lockfd); 3178425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 3188425Swpaul ypdb->dom_domain, ypdb->dom_vers); 3198425Swpaul unlink(path); 3208425Swpaul } 3218474Swpaul close(yplockfd); 3228474Swpaul unlink(YPBINDLOCK); 3238425Swpaul pmap_unset(YPBINDPROG, YPBINDVERS); 3248425Swpaul exit(0); 3258425Swpaul} 3268425Swpaul 3278091Swpaulvoid 3281927Swollmanmain(argc, argv) 3298091Swpaulint argc; 3301927Swollmanchar **argv; 3311927Swollman{ 3321927Swollman char path[MAXPATHLEN]; 3331927Swollman struct timeval tv; 3341927Swollman fd_set fdsr; 3351927Swollman int i; 3368425Swpaul DIR *dird; 3378425Swpaul struct dirent *dirp; 3381927Swollman 3398474Swpaul /* Check that another ypbind isn't already running. */ 3408474Swpaul if ((yplockfd = (open(YPBINDLOCK, O_RDONLY|O_CREAT, 0444))) == -1) { 3418474Swpaul perror(YPBINDLOCK); 3428474Swpaul exit(1); 3438474Swpaul } 3448474Swpaul 3458474Swpaul if(flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) { 3468474Swpaul fprintf (stderr, "Another ypbind is already running. Aborting.\n"); 3478474Swpaul exit(1); 3488474Swpaul } 3498474Swpaul 3501927Swollman yp_get_default_domain(&domainname); 3511927Swollman if( domainname[0] == '\0') { 3521927Swollman fprintf(stderr, "domainname not set. Aborting.\n"); 3531927Swollman exit(1); 3541927Swollman } 3551927Swollman 3561927Swollman for(i=1; i<argc; i++) { 3571927Swollman if( strcmp("-ypset", argv[i]) == 0) 3581927Swollman ypsetmode = YPSET_ALL; 3591927Swollman else if (strcmp("-ypsetme", argv[i]) == 0) 3606732Swpaul ypsetmode = YPSET_LOCAL; 3616732Swpaul else if (strcmp("-s", argv[i]) == 0) 3626732Swpaul ypsecuremode++; 3631927Swollman } 3641927Swollman 3658425Swpaul /* blow away everything in BINDINGDIR (if it exists) */ 3661927Swollman 3678425Swpaul if ((dird = opendir(BINDINGDIR)) != NULL) { 3688425Swpaul char path[MAXPATHLEN]; 3698425Swpaul while ((dirp = readdir(dird)) != NULL) 3708425Swpaul if (strcmp(dirp->d_name, ".") && 3718425Swpaul strcmp(dirp->d_name, "..")) { 3728425Swpaul sprintf(path,"%s/%s",BINDINGDIR,dirp->d_name); 3738425Swpaul unlink(path); 3748425Swpaul } 3758425Swpaul closedir(dird); 3768425Swpaul } 3771927Swollman 3781927Swollman#ifdef DAEMON 3798425Swpaul if (daemon(0,0)) { 3801927Swollman perror("fork"); 3811927Swollman exit(1); 3821927Swollman } 3831927Swollman#endif 3841927Swollman 3851927Swollman pmap_unset(YPBINDPROG, YPBINDVERS); 3861927Swollman 3871927Swollman udptransp = svcudp_create(RPC_ANYSOCK); 3881927Swollman if (udptransp == NULL) { 3898425Swpaul fprintf(stderr, "cannot create udp service.\n"); 3901927Swollman exit(1); 3911927Swollman } 3921927Swollman if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 3931927Swollman IPPROTO_UDP)) { 3948425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp).\n"); 3951927Swollman exit(1); 3961927Swollman } 3971927Swollman 3981927Swollman tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 3991927Swollman if (tcptransp == NULL) { 4008425Swpaul fprintf(stderr, "cannot create tcp service.\n"); 4011927Swollman exit(1); 4021927Swollman } 4031927Swollman 4041927Swollman if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 4051927Swollman IPPROTO_TCP)) { 4068425Swpaul fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp).\n"); 4071927Swollman exit(1); 4081927Swollman } 4091927Swollman 4101927Swollman /* build initial domain binding, make it "unsuccessful" */ 4111927Swollman ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 4128246Swpaul if (ypbindlist == NULL) { 4138246Swpaul perror("malloc"); 4148246Swpaul exit(1); 4158246Swpaul } 4161927Swollman bzero((char *)ypbindlist, sizeof *ypbindlist); 4171927Swollman strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 4181927Swollman ypbindlist->dom_vers = YPVERS; 4191927Swollman ypbindlist->dom_alive = 0; 4201927Swollman ypbindlist->dom_lockfd = -1; 4218091Swpaul ypbindlist->client_handle = NULL; 4228091Swpaul ypbindlist->dom_default = 1; 4238425Swpaul domains++; 4241927Swollman 4258425Swpaul signal(SIGCHLD, reaper); 4268425Swpaul signal(SIGTERM, terminate); 4278425Swpaul 4288091Swpaul /* Initialize children fds. */ 4298091Swpaul for (i = 0; i < FD_SETSIZE; i++) 4308091Swpaul child_fds[i] = -1; 4318091Swpaul 4328246Swpaul openlog(argv[0], LOG_PID, LOG_DAEMON); 4336478Swpaul 4348425Swpaul /* Kick off the default domain */ 4358425Swpaul broadcast(ypbindlist); 4368425Swpaul 4371927Swollman while(1) { 4381927Swollman fdsr = svc_fdset; 4398091Swpaul 4408091Swpaul for (i = 0; i < FD_SETSIZE; i++) 4418091Swpaul if (child_fds[i] > 0 ) 4428091Swpaul FD_SET(child_fds[i], &fdsr); 4438091Swpaul 4448425Swpaul tv.tv_sec = 60; 4451927Swollman tv.tv_usec = 0; 4461927Swollman 4478091Swpaul switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 4481927Swollman case 0: 4491927Swollman checkwork(); 4501927Swollman break; 4511927Swollman case -1: 4528425Swpaul if (errno == EINTR) 4538425Swpaul continue; 4548425Swpaul else { 4558425Swpaul syslog(LOG_WARNING, "select: %s", strerror(errno)); 4568425Swpaul break; 4578425Swpaul } 4581927Swollman default: 4598091Swpaul for(i = 0; i < FD_SETSIZE; i++) { 4608091Swpaul if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) { 4618091Swpaul handle_children(child_fds[i]); 4628091Swpaul close(child_fds[i]); 4638091Swpaul FD_CLR(child_fds[i], &fdsr); 4648091Swpaul child_fds[i] = -1; 4658091Swpaul children--; 4668091Swpaul 4678091Swpaul } 4681927Swollman } 4691927Swollman svc_getreqset(&fdsr); 4701927Swollman break; 4711927Swollman } 4721927Swollman } 4731927Swollman} 4741927Swollman 4758091Swpaulvoid 4761927Swollmancheckwork() 4771927Swollman{ 4781927Swollman struct _dom_binding *ypdb; 4791927Swollman 4808425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 4818425Swpaul ping(ypdb); 4821927Swollman} 4831927Swollman 4848091Swpaul/* The clnt_broadcast() callback mechanism sucks. */ 4858091Swpaul 4868091Swpaul/* 4878091Swpaul * Receive results from broadcaster. Don't worry about passing 4888091Swpaul * bogus info to rpc_received() -- it can handle it. 4898091Swpaul */ 4908091Swpaulvoid handle_children(i) 4918091Swpaulint i; 4928091Swpaul{ 4938091Swpaul char buf[YPMAXDOMAIN + 1]; 4948091Swpaul struct sockaddr_in addr; 4958091Swpaul 4968091Swpaul if (read(i, &buf, sizeof(buf)) < 0) 4978246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 4988091Swpaul if (read(i, &addr, sizeof(struct sockaddr_in)) < 0) 4998246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 5008091Swpaul rpc_received((char *)&buf, &addr, 0); 5018091Swpaul} 5028091Swpaul 5038091Swpaul/* 5048091Swpaul * Send our dying words back to our parent before we perish. 5058091Swpaul */ 5068091Swpaulint 5078091Swpaultell_parent(dom, addr) 5081927Swollmanchar *dom; 5098091Swpaulstruct sockaddr_in *addr; 5101927Swollman{ 5118091Swpaul char buf[YPMAXDOMAIN + 1]; 5128091Swpaul struct timeval timeout; 5138091Swpaul fd_set fds; 5141927Swollman 5158091Swpaul timeout.tv_sec = 5; 5168091Swpaul timeout.tv_usec = 0; 5171927Swollman 5188091Swpaul sprintf (buf, "%s", broad_domain); 5198091Swpaul if (write(fd[1], &buf, sizeof(buf)) < 0) 5208091Swpaul return(1); 5211927Swollman 5228091Swpaul /* 5238091Swpaul * Stay in sync with parent: wait for it to read our first 5248091Swpaul * message before sending the second. 5258091Swpaul */ 5261927Swollman 5278091Swpaul FD_ZERO(&fds); 5288091Swpaul FD_SET(fd[1], &fds); 5298091Swpaul if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 5308091Swpaul return(1); 5318091Swpaul if (FD_ISSET(fd[1], &fds)) { 5328091Swpaul if (write(fd[1], addr, sizeof(struct sockaddr_in)) < 0) 5338091Swpaul return(1); 5348091Swpaul } else { 5358091Swpaul return(1); 5361927Swollman } 5371927Swollman 5388091Swpaul close(fd[1]); 5398091Swpaul return (0); 5408091Swpaul} 5411927Swollman 5428091Swpaulbool_t broadcast_result(out, addr) 5438091Swpaulbool_t *out; 5448091Swpaulstruct sockaddr_in *addr; 5458091Swpaul{ 5468091Swpaul if (tell_parent(&broad_domain, addr)) 5478091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 5488091Swpaul return TRUE; 5498091Swpaul} 5508091Swpaul 5518091Swpaul/* 5528091Swpaul * The right way to send RPC broadcasts. 5538091Swpaul * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 5548091Swpaul * blocks while waiting for replies, so we have to fork off seperate 5558091Swpaul * broadcaster processes that do the waiting and then transmit their 5568091Swpaul * results back to the parent for processing. We also have to remember 5578091Swpaul * to save the name of the domain we're trying to bind in a global 5588091Swpaul * variable since clnt_broadcast() provides no way to pass things to 5598091Swpaul * the 'eachresult' callback function. 5608091Swpaul */ 5618091Swpaulvoid 5628091Swpaulbroadcast(ypdb) 5638091Swpaulstruct _dom_binding *ypdb; 5648091Swpaul{ 5658091Swpaul bool_t out = FALSE; 5668091Swpaul enum clnt_stat stat; 5678091Swpaul int i; 5688091Swpaul 5698425Swpaul if (children > MAX_CHILDREN || ypdb->dom_broadcasting) 5708091Swpaul return; 5718091Swpaul 5728091Swpaul if (pipe(fd) < 0) { 5738091Swpaul syslog(LOG_WARNING, "pipe: %s",strerror(errno)); 5748091Swpaul return; 5751927Swollman } 5761927Swollman 5778425Swpaul if (ypdb->dom_vers = -1 && (long)ypdb->dom_server_addr.sin_addr.s_addr) 5788425Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain %s not responding", 5798425Swpaul inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 5808425Swpaul 5818425Swpaul broad_domain = ypdb->dom_domain; 5828425Swpaul ypdb->dom_broadcasting = 1; 5838425Swpaul flock(ypdb->dom_lockfd, LOCK_UN); 5848425Swpaul 5858091Swpaul switch(fork()) { 5868091Swpaul case 0: 5878091Swpaul close(fd[0]); 5888091Swpaul break; 5898091Swpaul case -1: 5908091Swpaul syslog(LOG_WARNING, "fork: %s", strerror(errno)); 5918091Swpaul close(fd[1]); 5928091Swpaul close(fd[0]); 5938091Swpaul return; 5948091Swpaul default: 5958091Swpaul for (i = 0; i < FD_SETSIZE; i++) { 5968091Swpaul if (child_fds[i] < 0) { 5978091Swpaul child_fds[i] = fd[0]; 5988091Swpaul break; 5991927Swollman } 6006478Swpaul } 6018091Swpaul close(fd[1]); 6028091Swpaul children++; 6038091Swpaul return; 6041927Swollman } 6056478Swpaul 6068091Swpaul close(ypdb->dom_lockfd); 6078091Swpaul stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 6088091Swpaul xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out, 6098091Swpaul broadcast_result); 6108091Swpaul 6118091Swpaul if (stat != RPC_SUCCESS) { 6128091Swpaul bzero((char *)&ypdb->dom_server_addr, 6138091Swpaul sizeof(struct sockaddr_in)); 6148425Swpaul if (!ypdb->dom_default) 6158425Swpaul ypdb->dom_server_addr.sin_addr.s_addr = KILLME_MAGIC; 6168091Swpaul if (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr)) 6178091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 6188091Swpaul } 6198091Swpaul exit(0); 6201927Swollman} 6211927Swollman 6228091Swpaul/* 6238091Swpaul * The right way to check if a server is alive. 6248091Swpaul * Attempt to get a client handle pointing to the server and send a 6258091Swpaul * YPPROC_DOMAIN_NONACK. If we don't get a response, we invalidate 6268425Swpaul * this binding entry and send out a broadcast to try to establish 6278425Swpaul * a new binding. Note that we treat non-default domains 6288091Swpaul * specially: once bound, we keep tabs on our server, but if it 6298091Swpaul * goes away and fails to respond after one round of broadcasting, we 6308091Swpaul * abandon it until a client specifically references it again. We make 6318091Swpaul * every effort to keep our default domain bound, however, since we 6328091Swpaul * need it to keep the system on its feet. 6338091Swpaul */ 6348091Swpaulint 6358425Swpaulping(ypdb) 6368091Swpaulstruct _dom_binding *ypdb; 6371927Swollman{ 6388091Swpaul bool_t out; 6398091Swpaul struct timeval interval, timeout; 6408091Swpaul enum clnt_stat stat; 6418091Swpaul int rpcsock = RPC_ANYSOCK; 6428091Swpaul time_t t; 6431927Swollman 6448091Swpaul interval.tv_sec = 5; 6458091Swpaul interval.tv_usec = 0; 6468091Swpaul timeout.tv_sec = FAIL_THRESHOLD; 6478091Swpaul timeout.tv_usec = 0; 6481927Swollman 6498091Swpaul if (ypdb->dom_broadcasting) 6508091Swpaul return(1); 6518091Swpaul 6528091Swpaul if (ypdb->client_handle == NULL) { 6538091Swpaul if ((ypdb->client_handle = clntudp_bufcreate( 6548091Swpaul &ypdb->dom_server_addr, YPPROG, YPVERS, 6558091Swpaul interval, &rpcsock, RPCSMALLMSGSIZE, 6568091Swpaul RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 6578091Swpaul /* Can't get a handle: we're dead. */ 6588091Swpaul ypdb->client_handle = NULL; 6598091Swpaul ypdb->dom_alive = 0; 6608091Swpaul ypdb->dom_vers = -1; 6618425Swpaul broadcast(ypdb); 6628091Swpaul return(1); 6638091Swpaul } 6641927Swollman } 6651927Swollman 6668091Swpaul if ((stat = clnt_call(ypdb->client_handle, YPPROC_DOMAIN_NONACK, 6678091Swpaul xdr_domainname, (char *)ypdb->dom_domain, 6688091Swpaul xdr_bool, (char *)&out, timeout)) != RPC_SUCCESS) { 6698091Swpaul ypdb->client_handle = NULL; 6708091Swpaul ypdb->dom_alive = 0; 6718091Swpaul ypdb->dom_vers = -1; 6728425Swpaul broadcast(ypdb); 6738091Swpaul return(1); 6748091Swpaul } 6751927Swollman 6768091Swpaul return(0); 6771927Swollman} 6781927Swollman 6798091Swpaulvoid rpc_received(dom, raddrp, force) 6801927Swollmanchar *dom; 6811927Swollmanstruct sockaddr_in *raddrp; 6821927Swollmanint force; 6831927Swollman{ 6848425Swpaul struct _dom_binding *ypdb, *prev = NULL; 6851927Swollman struct iovec iov[2]; 6861927Swollman struct ypbind_resp ybr; 6871927Swollman char path[MAXPATHLEN]; 6881927Swollman int fd; 6891927Swollman 6906732Swpaul /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 6916732Swpaul ntohs(raddrp->sin_port), dom);*/ 6921927Swollman 6931927Swollman if(dom==NULL) 6941927Swollman return; 6951927Swollman 6968425Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 6978091Swpaul if( strcmp(ypdb->dom_domain, dom) == 0) 6988091Swpaul break; 6998425Swpaul prev = ypdb; 7008425Swpaul } 7018091Swpaul 7026732Swpaul /* if in securemode, check originating port number */ 7036732Swpaul if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) { 7046732Swpaul syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 7056732Swpaul inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 7066732Swpaul dom); 7078246Swpaul if (ypdb != NULL) { 7088246Swpaul ypdb->dom_broadcasting = 0; 7098246Swpaul ypdb->dom_alive = 0; 7108246Swpaul } 7116732Swpaul return; 7126732Swpaul } 7136732Swpaul 7148246Swpaul if (raddrp->sin_addr.s_addr == (long)0) { 7158246Swpaul ypdb->dom_broadcasting = 0; 7168246Swpaul ypdb->dom_alive = 0; 7178425Swpaul broadcast(ypdb); 7188246Swpaul return; 7198246Swpaul } 7208246Swpaul 7218425Swpaul if (raddrp->sin_addr.s_addr == KILLME_MAGIC) { 7228425Swpaul if (prev == NULL) 7238425Swpaul ypbindlist = ypdb->dom_pnext; 7248425Swpaul else 7258425Swpaul prev->dom_pnext = ypdb->dom_pnext; 7268425Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 7278425Swpaul ypdb->dom_domain, YPVERS); /* XXX dom_vers can't */ 7288425Swpaul close(ypdb->dom_lockfd); /* be trusted here */ 7298425Swpaul unlink(path); 7308425Swpaul free(ypdb); 7318425Swpaul domains--; 7328425Swpaul return; 7338425Swpaul } 7348425Swpaul 7351927Swollman if(ypdb==NULL) { 7368246Swpaul if (force == 0) 7371927Swollman return; 7381927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 7398246Swpaul if (ypdb == NULL) { 7408246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 7418246Swpaul return; 7428246Swpaul } 7431927Swollman bzero((char *)ypdb, sizeof *ypdb); 7441927Swollman strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 7451927Swollman ypdb->dom_lockfd = -1; 7468091Swpaul ypdb->dom_default = 0; 7478246Swpaul ypdb->dom_alive = 0; 7488246Swpaul ypdb->dom_broadcasting = 0; 7491927Swollman ypdb->dom_pnext = ypbindlist; 7501927Swollman ypbindlist = ypdb; 7511927Swollman } 7521927Swollman 7538091Swpaul /* We've recovered from a crash: inform the world. */ 7548091Swpaul if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr) 7558425Swpaul syslog(LOG_WARNING, "NIS server [%s] for domain %s OK", 7568425Swpaul inet_ntoa(ypdb->dom_server_addr.sin_addr), ypdb->dom_domain); 7576478Swpaul 7581927Swollman bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 7591927Swollman sizeof ypdb->dom_server_addr); 7606478Swpaul 7611927Swollman ypdb->dom_vers = YPVERS; 7621927Swollman ypdb->dom_alive = 1; 7638091Swpaul ypdb->dom_broadcasting = 0; 7641927Swollman 7651927Swollman if(ypdb->dom_lockfd != -1) 7661927Swollman close(ypdb->dom_lockfd); 7671927Swollman 7688091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 7691927Swollman ypdb->dom_domain, ypdb->dom_vers); 7701927Swollman#ifdef O_SHLOCK 7717864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 7721927Swollman (void)mkdir(BINDINGDIR, 0755); 7737864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 7741927Swollman return; 7751927Swollman } 7761927Swollman#else 7777864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 7781927Swollman (void)mkdir(BINDINGDIR, 0755); 7797864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 7801927Swollman return; 7811927Swollman } 7821927Swollman flock(fd, LOCK_SH); 7831927Swollman#endif 7841927Swollman 7851927Swollman /* 7861927Swollman * ok, if BINDINGDIR exists, and we can create the binding file, 7871927Swollman * then write to it.. 7881927Swollman */ 7891927Swollman ypdb->dom_lockfd = fd; 7901927Swollman 7911927Swollman iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 7921927Swollman iov[0].iov_len = sizeof udptransp->xp_port; 7931927Swollman iov[1].iov_base = (caddr_t)&ybr; 7941927Swollman iov[1].iov_len = sizeof ybr; 7951927Swollman 7961927Swollman bzero(&ybr, sizeof ybr); 7971927Swollman ybr.ypbind_status = YPBIND_SUCC_VAL; 7981927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr; 7991927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 8001927Swollman 8011927Swollman if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 8028091Swpaul syslog(LOG_WARNING, "write: %s", strerror(errno)); 8031927Swollman close(ypdb->dom_lockfd); 8041927Swollman ypdb->dom_lockfd = -1; 8051927Swollman return; 8061927Swollman } 8071927Swollman} 808