ypbind.c revision 8246
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 318246Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.8 1995/04/26 19:03:14 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 686478Swpaul/* 698091Swpaul * Ping the server once every PING_INTERVAL seconds to make sure it's 708091Swpaul * still there. 716478Swpaul */ 728091Swpaul#ifndef PING_INTERVAL 738091Swpaul#define PING_INTERVAL 60 748091Swpaul#endif 756478Swpaul#ifndef FAIL_THRESHOLD 766478Swpaul#define FAIL_THRESHOLD 20 776478Swpaul#endif 786478Swpaul 791927Swollmanstruct _dom_binding { 801927Swollman struct _dom_binding *dom_pnext; 811927Swollman char dom_domain[YPMAXDOMAIN + 1]; 821927Swollman struct sockaddr_in dom_server_addr; 838091Swpaul CLIENT *client_handle; 841927Swollman long int dom_vers; 851927Swollman int dom_lockfd; 861927Swollman int dom_alive; 878091Swpaul int dom_broadcasting; 888091Swpaul int dom_default; 898091Swpaul time_t dom_check; 901927Swollman}; 911927Swollman 921927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp(); 931927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 941927Swollmanextern bool_t xdr_ypbind_setdom(); 951927Swollman 968091Swpaulvoid checkwork __P((void)); 978091Swpaulvoid *ypbindproc_null_2 __P((SVCXPRT *, void *, CLIENT *)); 988091Swpaulbool_t *ypbindproc_setdom_2 __P((SVCXPRT *, struct ypbind_setdom *, CLIENT *)); 998091Swpaulvoid rpc_received __P((char *, struct sockaddr_in *, int )); 1008091Swpaulvoid broadcast __P((struct _dom_binding *)); 1018091Swpaulint ping __P((struct _dom_binding *, int)); 1028091Swpaulvoid handle_children __P(( int )); 1038091Swpaul 1048091Swpaulstatic char *broad_domain; 1051927Swollmanchar *domainname; 1061927Swollmanstruct _dom_binding *ypbindlist; 1071927Swollman 1081927Swollman#define YPSET_NO 0 1091927Swollman#define YPSET_LOCAL 1 1101927Swollman#define YPSET_ALL 2 1111927Swollmanint ypsetmode = YPSET_NO; 1126732Swpaulint ypsecuremode = 0; 1136732Swpaul 1148091Swpaul/* No more than MAX_CHILDREN child broadcasters at a time. */ 1158091Swpaul#define MAX_CHILDREN 5 1168091Swpaulint child_fds[FD_SETSIZE]; 1178091Swpaulstatic int fd[2]; 1188091Swpaulint children = 0; 1198091Swpaul 1201927SwollmanSVCXPRT *udptransp, *tcptransp; 1211927Swollman 1221927Swollmanvoid * 1231927Swollmanypbindproc_null_2(transp, argp, clnt) 1241927SwollmanSVCXPRT *transp; 1251927Swollmanvoid *argp; 1261927SwollmanCLIENT *clnt; 1271927Swollman{ 1281927Swollman static char res; 1291927Swollman 1301927Swollman bzero((char *)&res, sizeof(res)); 1311927Swollman return (void *)&res; 1321927Swollman} 1331927Swollman 1341927Swollmanstruct ypbind_resp * 1351927Swollmanypbindproc_domain_2(transp, argp, clnt) 1361927SwollmanSVCXPRT *transp; 1371927Swollmanchar *argp; 1381927SwollmanCLIENT *clnt; 1391927Swollman{ 1401927Swollman static struct ypbind_resp res; 1411927Swollman struct _dom_binding *ypdb; 1421927Swollman char path[MAXPATHLEN]; 1431927Swollman 1441927Swollman bzero((char *)&res, sizeof res); 1451927Swollman res.ypbind_status = YPBIND_FAIL_VAL; 1467982Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_NOSERV; 1471927Swollman 1481927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 1491927Swollman if( strcmp(ypdb->dom_domain, argp) == 0) 1501927Swollman break; 1511927Swollman 1521927Swollman if(ypdb==NULL) { 1531927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 1548246Swpaul if (ypdb == NULL) { 1558246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 1568246Swpaul res.ypbind_respbody.ypbind_error = YPBIND_ERR_RESC; 1578246Swpaul return; 1588246Swpaul } 1591927Swollman bzero((char *)ypdb, sizeof *ypdb); 1601927Swollman strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 1611927Swollman ypdb->dom_vers = YPVERS; 1621927Swollman ypdb->dom_alive = 0; 1638091Swpaul ypdb->dom_default = 0; 1641927Swollman ypdb->dom_lockfd = -1; 1658091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 1661927Swollman unlink(path); 1671927Swollman ypdb->dom_pnext = ypbindlist; 1681927Swollman ypbindlist = ypdb; 1697982Swpaul return &res; 1701927Swollman } 1711927Swollman 1721927Swollman if(ypdb->dom_alive==0) 1737982Swpaul return &res; 1741927Swollman 1758091Swpaul if (ping(ypdb, 1)) 1768091Swpaul return &res; 1771927Swollman 1781927Swollman res.ypbind_status = YPBIND_SUCC_VAL; 1798246Swpaul res.ypbind_respbody.ypbind_error = 0; /* Success */ 1801927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 1811927Swollman ypdb->dom_server_addr.sin_addr.s_addr; 1821927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 1838091Swpaul ypdb->dom_server_addr.sin_port; 1841927Swollman /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 1851927Swollman inet_ntoa(ypdb->dom_server_addr.sin_addr), 1861927Swollman ntohs(ypdb->dom_server_addr.sin_port));*/ 1871927Swollman return &res; 1881927Swollman} 1891927Swollman 1901927Swollmanbool_t * 1911927Swollmanypbindproc_setdom_2(transp, argp, clnt) 1921927SwollmanSVCXPRT *transp; 1931927Swollmanstruct ypbind_setdom *argp; 1941927SwollmanCLIENT *clnt; 1951927Swollman{ 1961927Swollman struct sockaddr_in *fromsin, bindsin; 1973033Sdg static char res; 1981927Swollman 1991927Swollman bzero((char *)&res, sizeof(res)); 2001927Swollman fromsin = svc_getcaller(transp); 2011927Swollman 2021927Swollman switch(ypsetmode) { 2031927Swollman case YPSET_LOCAL: 2041927Swollman if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) 2051927Swollman return (void *)NULL; 2061927Swollman break; 2071927Swollman case YPSET_ALL: 2081927Swollman break; 2091927Swollman case YPSET_NO: 2101927Swollman default: 2111927Swollman return (void *)NULL; 2121927Swollman } 2131927Swollman 2141927Swollman if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) 2151927Swollman return (void *)&res; 2161927Swollman 2171927Swollman if(argp->ypsetdom_vers != YPVERS) 2181927Swollman return (void *)&res; 2191927Swollman 2201927Swollman bzero((char *)&bindsin, sizeof bindsin); 2211927Swollman bindsin.sin_family = AF_INET; 2221927Swollman bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 2231927Swollman bindsin.sin_port = argp->ypsetdom_port; 2241927Swollman rpc_received(argp->ypsetdom_domain, &bindsin, 1); 2251927Swollman 2261927Swollman res = 1; 2271927Swollman return (void *)&res; 2281927Swollman} 2291927Swollman 2301927Swollmanstatic void 2311927Swollmanypbindprog_2(rqstp, transp) 2321927Swollmanstruct svc_req *rqstp; 2331927Swollmanregister SVCXPRT *transp; 2341927Swollman{ 2351927Swollman union { 2361927Swollman char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 2371927Swollman struct ypbind_setdom ypbindproc_setdom_2_arg; 2381927Swollman } argument; 2391927Swollman struct authunix_parms *creds; 2401927Swollman char *result; 2411927Swollman bool_t (*xdr_argument)(), (*xdr_result)(); 2421927Swollman char *(*local)(); 2431927Swollman 2441927Swollman switch (rqstp->rq_proc) { 2451927Swollman case YPBINDPROC_NULL: 2461927Swollman xdr_argument = xdr_void; 2471927Swollman xdr_result = xdr_void; 2481927Swollman local = (char *(*)()) ypbindproc_null_2; 2491927Swollman break; 2501927Swollman 2511927Swollman case YPBINDPROC_DOMAIN: 2521927Swollman xdr_argument = xdr_domainname; 2531927Swollman xdr_result = xdr_ypbind_resp; 2541927Swollman local = (char *(*)()) ypbindproc_domain_2; 2551927Swollman break; 2561927Swollman 2571927Swollman case YPBINDPROC_SETDOM: 2581927Swollman switch(rqstp->rq_cred.oa_flavor) { 2591927Swollman case AUTH_UNIX: 2601927Swollman creds = (struct authunix_parms *)rqstp->rq_clntcred; 2611927Swollman if( creds->aup_uid != 0) { 2621927Swollman svcerr_auth(transp, AUTH_BADCRED); 2631927Swollman return; 2641927Swollman } 2651927Swollman break; 2661927Swollman default: 2671927Swollman svcerr_auth(transp, AUTH_TOOWEAK); 2681927Swollman return; 2691927Swollman } 2701927Swollman 2711927Swollman xdr_argument = xdr_ypbind_setdom; 2721927Swollman xdr_result = xdr_void; 2731927Swollman local = (char *(*)()) ypbindproc_setdom_2; 2741927Swollman break; 2751927Swollman 2761927Swollman default: 2771927Swollman svcerr_noproc(transp); 2781927Swollman return; 2791927Swollman } 2801927Swollman bzero((char *)&argument, sizeof(argument)); 2811927Swollman if (!svc_getargs(transp, xdr_argument, &argument)) { 2821927Swollman svcerr_decode(transp); 2831927Swollman return; 2841927Swollman } 2851927Swollman result = (*local)(transp, &argument, rqstp); 2861927Swollman if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 2871927Swollman svcerr_systemerr(transp); 2881927Swollman } 2891927Swollman return; 2901927Swollman} 2911927Swollman 2928091Swpaul/* Jack the reaper */ 2938091Swpaulvoid reaper(sig) 2948091Swpaulint sig; 2958091Swpaul{ 2968091Swpaul int st; 2978091Swpaul 2988091Swpaul wait3(&st, WNOHANG, NULL); 2998091Swpaul} 3008091Swpaul 3018091Swpaulvoid 3021927Swollmanmain(argc, argv) 3038091Swpaulint argc; 3041927Swollmanchar **argv; 3051927Swollman{ 3061927Swollman char path[MAXPATHLEN]; 3071927Swollman struct timeval tv; 3081927Swollman fd_set fdsr; 3091927Swollman int i; 3101927Swollman 3111927Swollman yp_get_default_domain(&domainname); 3121927Swollman if( domainname[0] == '\0') { 3131927Swollman fprintf(stderr, "domainname not set. Aborting.\n"); 3141927Swollman exit(1); 3151927Swollman } 3161927Swollman 3171927Swollman for(i=1; i<argc; i++) { 3181927Swollman if( strcmp("-ypset", argv[i]) == 0) 3191927Swollman ypsetmode = YPSET_ALL; 3201927Swollman else if (strcmp("-ypsetme", argv[i]) == 0) 3216732Swpaul ypsetmode = YPSET_LOCAL; 3226732Swpaul else if (strcmp("-s", argv[i]) == 0) 3236732Swpaul ypsecuremode++; 3241927Swollman } 3251927Swollman 3261927Swollman /* blow away everything in BINDINGDIR */ 3271927Swollman 3281927Swollman 3291927Swollman 3301927Swollman#ifdef DAEMON 3311927Swollman switch(fork()) { 3321927Swollman case 0: 3331927Swollman break; 3341927Swollman case -1: 3351927Swollman perror("fork"); 3361927Swollman exit(1); 3371927Swollman default: 3381927Swollman exit(0); 3391927Swollman } 3401927Swollman setsid(); 3411927Swollman#endif 3421927Swollman 3431927Swollman pmap_unset(YPBINDPROG, YPBINDVERS); 3441927Swollman 3451927Swollman udptransp = svcudp_create(RPC_ANYSOCK); 3461927Swollman if (udptransp == NULL) { 3471927Swollman fprintf(stderr, "cannot create udp service."); 3481927Swollman exit(1); 3491927Swollman } 3501927Swollman if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 3511927Swollman IPPROTO_UDP)) { 3521927Swollman fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp)."); 3531927Swollman exit(1); 3541927Swollman } 3551927Swollman 3561927Swollman tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 3571927Swollman if (tcptransp == NULL) { 3581927Swollman fprintf(stderr, "cannot create tcp service."); 3591927Swollman exit(1); 3601927Swollman } 3611927Swollman 3621927Swollman if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 3631927Swollman IPPROTO_TCP)) { 3641927Swollman fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 3651927Swollman exit(1); 3661927Swollman } 3671927Swollman 3681927Swollman /* build initial domain binding, make it "unsuccessful" */ 3691927Swollman ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 3708246Swpaul if (ypbindlist == NULL) { 3718246Swpaul perror("malloc"); 3728246Swpaul exit(1); 3738246Swpaul } 3741927Swollman bzero((char *)ypbindlist, sizeof *ypbindlist); 3751927Swollman strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 3761927Swollman ypbindlist->dom_vers = YPVERS; 3771927Swollman ypbindlist->dom_alive = 0; 3781927Swollman ypbindlist->dom_lockfd = -1; 3798091Swpaul ypbindlist->client_handle = NULL; 3808091Swpaul ypbindlist->dom_default = 1; 3818091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, ypbindlist->dom_domain, 3821927Swollman ypbindlist->dom_vers); 3831927Swollman (void)unlink(path); 3841927Swollman 3858091Swpaul /* Initialize children fds. */ 3868091Swpaul for (i = 0; i < FD_SETSIZE; i++) 3878091Swpaul child_fds[i] = -1; 3888091Swpaul 3898246Swpaul openlog(argv[0], LOG_PID, LOG_DAEMON); 3906478Swpaul 3911927Swollman while(1) { 3921927Swollman fdsr = svc_fdset; 3938091Swpaul 3948091Swpaul for (i = 0; i < FD_SETSIZE; i++) 3958091Swpaul if (child_fds[i] > 0 ) 3968091Swpaul FD_SET(child_fds[i], &fdsr); 3978091Swpaul 3981927Swollman tv.tv_sec = 1; 3991927Swollman tv.tv_usec = 0; 4001927Swollman 4018091Swpaul switch(select(_rpc_dtablesize(), &fdsr, NULL, NULL, &tv)) { 4021927Swollman case 0: 4031927Swollman checkwork(); 4048091Swpaul reaper(); 4051927Swollman break; 4061927Swollman case -1: 4078246Swpaul syslog(LOG_WARNING, "select: %s", strerror(errno)); 4081927Swollman break; 4091927Swollman default: 4108091Swpaul for(i = 0; i < FD_SETSIZE; i++) { 4118091Swpaul if (child_fds[i] > 0 && FD_ISSET(child_fds[i],&fdsr)) { 4128091Swpaul handle_children(child_fds[i]); 4138091Swpaul close(child_fds[i]); 4148091Swpaul FD_CLR(child_fds[i], &fdsr); 4158091Swpaul child_fds[i] = -1; 4168091Swpaul children--; 4178091Swpaul 4188091Swpaul } 4191927Swollman } 4201927Swollman svc_getreqset(&fdsr); 4211927Swollman break; 4221927Swollman } 4231927Swollman } 4241927Swollman} 4251927Swollman 4268091Swpaulvoid 4271927Swollmancheckwork() 4281927Swollman{ 4291927Swollman struct _dom_binding *ypdb; 4301927Swollman time_t t; 4311927Swollman 4328091Swpaul time(&t); 4331927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 4348091Swpaul if (!ypdb->dom_alive && !ypdb->dom_broadcasting) { 4358091Swpaul if (!ypdb->dom_default) 4368091Swpaul ypdb->dom_alive = 1; 4378091Swpaul ypdb->dom_broadcasting = 1; 4388091Swpaul broadcast(ypdb); 4391927Swollman } 4408091Swpaul if (ypdb->dom_alive && ypdb->dom_check < t) 4418091Swpaul ping(ypdb, 0); 4421927Swollman } 4431927Swollman} 4441927Swollman 4458091Swpaul/* The clnt_broadcast() callback mechanism sucks. */ 4468091Swpaul 4478091Swpaul/* 4488091Swpaul * Receive results from broadcaster. Don't worry about passing 4498091Swpaul * bogus info to rpc_received() -- it can handle it. 4508091Swpaul */ 4518091Swpaulvoid handle_children(i) 4528091Swpaulint i; 4538091Swpaul{ 4548091Swpaul char buf[YPMAXDOMAIN + 1]; 4558091Swpaul struct sockaddr_in addr; 4568091Swpaul 4578091Swpaul if (read(i, &buf, sizeof(buf)) < 0) 4588246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 4598091Swpaul if (read(i, &addr, sizeof(struct sockaddr_in)) < 0) 4608246Swpaul syslog(LOG_WARNING, "could not read from child: %s", strerror(errno)); 4618091Swpaul rpc_received((char *)&buf, &addr, 0); 4628091Swpaul} 4638091Swpaul 4648091Swpaul/* 4658091Swpaul * Send our dying words back to our parent before we perish. 4668091Swpaul */ 4678091Swpaulint 4688091Swpaultell_parent(dom, addr) 4691927Swollmanchar *dom; 4708091Swpaulstruct sockaddr_in *addr; 4711927Swollman{ 4728091Swpaul char buf[YPMAXDOMAIN + 1]; 4738091Swpaul struct timeval timeout; 4748091Swpaul fd_set fds; 4751927Swollman 4768091Swpaul timeout.tv_sec = 5; 4778091Swpaul timeout.tv_usec = 0; 4781927Swollman 4798091Swpaul sprintf (buf, "%s", broad_domain); 4808091Swpaul if (write(fd[1], &buf, sizeof(buf)) < 0) 4818091Swpaul return(1); 4821927Swollman 4838091Swpaul /* 4848091Swpaul * Stay in sync with parent: wait for it to read our first 4858091Swpaul * message before sending the second. 4868091Swpaul */ 4871927Swollman 4888091Swpaul FD_ZERO(&fds); 4898091Swpaul FD_SET(fd[1], &fds); 4908091Swpaul if (select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == -1) 4918091Swpaul return(1); 4928091Swpaul if (FD_ISSET(fd[1], &fds)) { 4938091Swpaul if (write(fd[1], addr, sizeof(struct sockaddr_in)) < 0) 4948091Swpaul return(1); 4958091Swpaul } else { 4968091Swpaul return(1); 4971927Swollman } 4981927Swollman 4998091Swpaul close(fd[1]); 5008091Swpaul return (0); 5018091Swpaul} 5021927Swollman 5038091Swpaulbool_t broadcast_result(out, addr) 5048091Swpaulbool_t *out; 5058091Swpaulstruct sockaddr_in *addr; 5068091Swpaul{ 5078091Swpaul if (tell_parent(&broad_domain, addr)) 5088091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 5098091Swpaul return TRUE; 5108091Swpaul} 5118091Swpaul 5128091Swpaul/* 5138091Swpaul * The right way to send RPC broadcasts. 5148091Swpaul * Use the clnt_broadcast() RPC service. Unfortunately, clnt_broadcast() 5158091Swpaul * blocks while waiting for replies, so we have to fork off seperate 5168091Swpaul * broadcaster processes that do the waiting and then transmit their 5178091Swpaul * results back to the parent for processing. We also have to remember 5188091Swpaul * to save the name of the domain we're trying to bind in a global 5198091Swpaul * variable since clnt_broadcast() provides no way to pass things to 5208091Swpaul * the 'eachresult' callback function. 5218091Swpaul */ 5228091Swpaulvoid 5238091Swpaulbroadcast(ypdb) 5248091Swpaulstruct _dom_binding *ypdb; 5258091Swpaul{ 5268091Swpaul bool_t out = FALSE; 5278091Swpaul enum clnt_stat stat; 5288091Swpaul int i; 5298091Swpaul 5308091Swpaul if (children > MAX_CHILDREN) 5318091Swpaul return; 5328091Swpaul 5338091Swpaul broad_domain = ypdb->dom_domain; 5348091Swpaul 5358091Swpaul if (pipe(fd) < 0) { 5368091Swpaul syslog(LOG_WARNING, "pipe: %s",strerror(errno)); 5378091Swpaul return; 5381927Swollman } 5391927Swollman 5408091Swpaul switch(fork()) { 5418091Swpaul case 0: 5428091Swpaul close(fd[0]); 5438091Swpaul break; 5448091Swpaul case -1: 5458091Swpaul syslog(LOG_WARNING, "fork: %s", strerror(errno)); 5468091Swpaul close(fd[1]); 5478091Swpaul close(fd[0]); 5488091Swpaul return; 5498091Swpaul default: 5508091Swpaul for (i = 0; i < FD_SETSIZE; i++) { 5518091Swpaul if (child_fds[i] < 0) { 5528091Swpaul child_fds[i] = fd[0]; 5538091Swpaul break; 5541927Swollman } 5556478Swpaul } 5568091Swpaul close(fd[1]); 5578091Swpaul children++; 5588091Swpaul return; 5591927Swollman } 5606478Swpaul 5618091Swpaul close(ypdb->dom_lockfd); 5628091Swpaul stat = clnt_broadcast(YPPROG, YPVERS, YPPROC_DOMAIN_NONACK, 5638091Swpaul xdr_domainname, (char *)ypdb->dom_domain, xdr_bool, (char *)&out, 5648091Swpaul broadcast_result); 5658091Swpaul 5668091Swpaul if (stat != RPC_SUCCESS) { 5678091Swpaul syslog(LOG_WARNING, "NIS server for domain %s not responding", 5688091Swpaul ypdb->dom_domain); 5698091Swpaul bzero((char *)&ypdb->dom_server_addr, 5708091Swpaul sizeof(struct sockaddr_in)); 5718091Swpaul if (tell_parent(&ypdb->dom_domain, &ypdb->dom_server_addr)) 5728091Swpaul syslog(LOG_WARNING, "lost connection to parent"); 5738091Swpaul } 5748091Swpaul exit(0); 5751927Swollman} 5761927Swollman 5778091Swpaul/* 5788091Swpaul * The right way to check if a server is alive. 5798091Swpaul * Attempt to get a client handle pointing to the server and send a 5808091Swpaul * YPPROC_DOMAIN_NONACK. If we don't get a response, we invalidate 5818091Swpaul * this binding entry, which will cause checkwork() to dispatch a 5828091Swpaul * broadcaster process. Note that we treat non-default domains 5838091Swpaul * specially: once bound, we keep tabs on our server, but if it 5848091Swpaul * goes away and fails to respond after one round of broadcasting, we 5858091Swpaul * abandon it until a client specifically references it again. We make 5868091Swpaul * every effort to keep our default domain bound, however, since we 5878091Swpaul * need it to keep the system on its feet. 5888091Swpaul */ 5898091Swpaulint 5908091Swpaulping(ypdb, force) 5918091Swpaulstruct _dom_binding *ypdb; 5928091Swpaulint force; 5931927Swollman{ 5948091Swpaul bool_t out; 5958091Swpaul struct timeval interval, timeout; 5968091Swpaul enum clnt_stat stat; 5978091Swpaul int rpcsock = RPC_ANYSOCK; 5988091Swpaul time_t t; 5991927Swollman 6008091Swpaul interval.tv_sec = 5; 6018091Swpaul interval.tv_usec = 0; 6028091Swpaul timeout.tv_sec = FAIL_THRESHOLD; 6038091Swpaul timeout.tv_usec = 0; 6041927Swollman 6058091Swpaul if (ypdb->dom_broadcasting) 6068091Swpaul return(1); 6078091Swpaul 6088091Swpaul if (!ypdb->dom_default && ypdb->dom_vers == -1 && !force) 6098091Swpaul return(1); 6108091Swpaul 6118091Swpaul if (ypdb->client_handle == NULL) { 6128091Swpaul if ((ypdb->client_handle = clntudp_bufcreate( 6138091Swpaul &ypdb->dom_server_addr, YPPROG, YPVERS, 6148091Swpaul interval, &rpcsock, RPCSMALLMSGSIZE, 6158091Swpaul RPCSMALLMSGSIZE)) == (CLIENT *)NULL) { 6168091Swpaul /* Can't get a handle: we're dead. */ 6178091Swpaul ypdb->client_handle = NULL; 6188091Swpaul ypdb->dom_alive = 0; 6198091Swpaul ypdb->dom_vers = -1; 6208091Swpaul flock(ypdb->dom_lockfd, LOCK_UN); 6218091Swpaul return(1); 6228091Swpaul } 6231927Swollman } 6241927Swollman 6258091Swpaul if ((stat = clnt_call(ypdb->client_handle, YPPROC_DOMAIN_NONACK, 6268091Swpaul xdr_domainname, (char *)ypdb->dom_domain, 6278091Swpaul xdr_bool, (char *)&out, timeout)) != RPC_SUCCESS) { 6288091Swpaul ypdb->client_handle = NULL; 6298091Swpaul ypdb->dom_alive = 0; 6308091Swpaul ypdb->dom_vers = -1; 6318091Swpaul flock(ypdb->dom_lockfd, LOCK_UN); 6328091Swpaul return(1); 6338091Swpaul } 6341927Swollman /* 6358091Swpaul * We pinged successfully. Reset the timer. 6361927Swollman */ 6378091Swpaul time(&t); 6388091Swpaul ypdb->dom_check = t + PING_INTERVAL; 6391927Swollman 6408091Swpaul return(0); 6411927Swollman} 6421927Swollman 6438091Swpaulvoid rpc_received(dom, raddrp, force) 6441927Swollmanchar *dom; 6451927Swollmanstruct sockaddr_in *raddrp; 6461927Swollmanint force; 6471927Swollman{ 6481927Swollman struct _dom_binding *ypdb; 6491927Swollman struct iovec iov[2]; 6501927Swollman struct ypbind_resp ybr; 6511927Swollman char path[MAXPATHLEN]; 6521927Swollman int fd; 6531927Swollman 6546732Swpaul /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 6556732Swpaul ntohs(raddrp->sin_port), dom);*/ 6561927Swollman 6571927Swollman if(dom==NULL) 6581927Swollman return; 6591927Swollman 6608091Swpaul for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 6618091Swpaul if( strcmp(ypdb->dom_domain, dom) == 0) 6628091Swpaul break; 6638091Swpaul 6646732Swpaul /* if in securemode, check originating port number */ 6656732Swpaul if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) { 6666732Swpaul syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 6676732Swpaul inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 6686732Swpaul dom); 6698246Swpaul if (ypdb != NULL) { 6708246Swpaul ypdb->dom_broadcasting = 0; 6718246Swpaul ypdb->dom_alive = 0; 6728246Swpaul } 6736732Swpaul return; 6746732Swpaul } 6756732Swpaul 6768246Swpaul if (raddrp->sin_addr.s_addr == (long)0) { 6778246Swpaul ypdb->dom_broadcasting = 0; 6788246Swpaul ypdb->dom_alive = 0; 6798246Swpaul return; 6808246Swpaul } 6818246Swpaul 6821927Swollman if(ypdb==NULL) { 6838246Swpaul if (force == 0) 6841927Swollman return; 6851927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 6868246Swpaul if (ypdb == NULL) { 6878246Swpaul syslog(LOG_WARNING, "malloc: %s", strerror(errno)); 6888246Swpaul return; 6898246Swpaul } 6901927Swollman bzero((char *)ypdb, sizeof *ypdb); 6911927Swollman strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 6921927Swollman ypdb->dom_lockfd = -1; 6938091Swpaul ypdb->dom_default = 0; 6948246Swpaul ypdb->dom_alive = 0; 6958246Swpaul ypdb->dom_broadcasting = 0; 6961927Swollman ypdb->dom_pnext = ypbindlist; 6971927Swollman ypbindlist = ypdb; 6981927Swollman } 6991927Swollman 7008091Swpaul /* We've recovered from a crash: inform the world. */ 7018091Swpaul if (ypdb->dom_vers = -1 && ypdb->dom_server_addr.sin_addr.s_addr) 7028091Swpaul syslog(LOG_WARNING, "NIS server for domain %s OK", 7038091Swpaul ypdb->dom_domain); 7046478Swpaul 7051927Swollman bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 7061927Swollman sizeof ypdb->dom_server_addr); 7076478Swpaul 7081927Swollman ypdb->dom_vers = YPVERS; 7091927Swollman ypdb->dom_alive = 1; 7108091Swpaul ypdb->dom_broadcasting = 0; 7111927Swollman 7121927Swollman if(ypdb->dom_lockfd != -1) 7131927Swollman close(ypdb->dom_lockfd); 7141927Swollman 7158091Swpaul sprintf(path, "%s/%s.%ld", BINDINGDIR, 7161927Swollman ypdb->dom_domain, ypdb->dom_vers); 7171927Swollman#ifdef O_SHLOCK 7187864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 7191927Swollman (void)mkdir(BINDINGDIR, 0755); 7207864Swpaul if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 7211927Swollman return; 7221927Swollman } 7231927Swollman#else 7247864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 7251927Swollman (void)mkdir(BINDINGDIR, 0755); 7267864Swpaul if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 7271927Swollman return; 7281927Swollman } 7291927Swollman flock(fd, LOCK_SH); 7301927Swollman#endif 7311927Swollman 7321927Swollman /* 7331927Swollman * ok, if BINDINGDIR exists, and we can create the binding file, 7341927Swollman * then write to it.. 7351927Swollman */ 7361927Swollman ypdb->dom_lockfd = fd; 7371927Swollman 7381927Swollman iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 7391927Swollman iov[0].iov_len = sizeof udptransp->xp_port; 7401927Swollman iov[1].iov_base = (caddr_t)&ybr; 7411927Swollman iov[1].iov_len = sizeof ybr; 7421927Swollman 7431927Swollman bzero(&ybr, sizeof ybr); 7441927Swollman ybr.ypbind_status = YPBIND_SUCC_VAL; 7451927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr; 7461927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 7471927Swollman 7481927Swollman if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 7498091Swpaul syslog(LOG_WARNING, "write: %s", strerror(errno)); 7501927Swollman close(ypdb->dom_lockfd); 7511927Swollman ypdb->dom_lockfd = -1; 7521927Swollman return; 7531927Swollman } 7541927Swollman} 755