ypbind.c revision 6732
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 316732Swpaulstatic char rcsid[] = "$Id: ypbind.c,v 1.3 1995/02/16 01:21:44 wpaul Exp $"; 321927Swollman#endif 331927Swollman 341927Swollman#include <sys/param.h> 351927Swollman#include <sys/types.h> 361927Swollman#include <sys/ioctl.h> 371927Swollman#include <sys/signal.h> 381927Swollman#include <sys/socket.h> 391927Swollman#include <sys/file.h> 401927Swollman#include <sys/fcntl.h> 411927Swollman#include <sys/uio.h> 426478Swpaul#include <syslog.h> 431927Swollman#include <stdio.h> 441927Swollman#include <errno.h> 451927Swollman#include <ctype.h> 461927Swollman#include <dirent.h> 471927Swollman#include <netdb.h> 481927Swollman#include <string.h> 491927Swollman#include <rpc/rpc.h> 501927Swollman#include <rpc/xdr.h> 511927Swollman#include <net/if.h> 526732Swpaul#include <netinet/in.h> 531927Swollman#include <arpa/inet.h> 541927Swollman#include <rpc/pmap_clnt.h> 551927Swollman#include <rpc/pmap_prot.h> 561927Swollman#include <rpc/pmap_rmt.h> 571927Swollman#include <unistd.h> 581927Swollman#include <rpcsvc/yp_prot.h> 591927Swollman#include <rpcsvc/ypclnt.h> 601927Swollman 611927Swollman#ifndef BINDINGDIR 621927Swollman#define BINDINGDIR "/var/yp/binding" 631927Swollman#endif 641927Swollman 656478Swpaul/* 666478Swpaul * Number of seconds to wait before for ping replies before we 676478Swpaul * decide that our server is dead. 686478Swpaul */ 696478Swpaul#ifndef FAIL_THRESHOLD 706478Swpaul#define FAIL_THRESHOLD 20 716478Swpaul#endif 726478Swpaul 731927Swollmanstruct _dom_binding { 741927Swollman struct _dom_binding *dom_pnext; 751927Swollman char dom_domain[YPMAXDOMAIN + 1]; 761927Swollman struct sockaddr_in dom_server_addr; 771927Swollman unsigned short int dom_server_port; 781927Swollman int dom_socket; 791927Swollman CLIENT *dom_client; 801927Swollman long int dom_vers; 811927Swollman time_t dom_check_t; 821927Swollman int dom_lockfd; 831927Swollman int dom_alive; 846478Swpaul int dom_answered; 856478Swpaul int dom_interval; 861927Swollman}; 871927Swollman 881927Swollmanextern bool_t xdr_domainname(), xdr_ypbind_resp(); 891927Swollmanextern bool_t xdr_ypreq_key(), xdr_ypresp_val(); 901927Swollmanextern bool_t xdr_ypbind_setdom(); 911927Swollman 921927Swollmanchar *domainname; 931927Swollman 941927Swollmanstruct _dom_binding *ypbindlist; 951927Swollmanint check; 961927Swollman 971927Swollman#define YPSET_NO 0 981927Swollman#define YPSET_LOCAL 1 991927Swollman#define YPSET_ALL 2 1001927Swollmanint ypsetmode = YPSET_NO; 1011927Swollman 1026732Swpaulint ypsecuremode = 0; 1036732Swpaul 1041927Swollmanint rpcsock; 1051927Swollmanstruct rmtcallargs rmtca; 1061927Swollmanstruct rmtcallres rmtcr; 1071927Swollmanchar rmtcr_outval; 1081927Swollmanu_long rmtcr_port; 1091927SwollmanSVCXPRT *udptransp, *tcptransp; 1101927Swollman 1111927Swollmanvoid * 1121927Swollmanypbindproc_null_2(transp, argp, clnt) 1131927SwollmanSVCXPRT *transp; 1141927Swollmanvoid *argp; 1151927SwollmanCLIENT *clnt; 1161927Swollman{ 1171927Swollman static char res; 1181927Swollman 1191927Swollman bzero((char *)&res, sizeof(res)); 1201927Swollman return (void *)&res; 1211927Swollman} 1221927Swollman 1231927Swollmanstruct ypbind_resp * 1241927Swollmanypbindproc_domain_2(transp, argp, clnt) 1251927SwollmanSVCXPRT *transp; 1261927Swollmanchar *argp; 1271927SwollmanCLIENT *clnt; 1281927Swollman{ 1291927Swollman static struct ypbind_resp res; 1301927Swollman struct _dom_binding *ypdb; 1311927Swollman char path[MAXPATHLEN]; 1321927Swollman 1331927Swollman bzero((char *)&res, sizeof res); 1341927Swollman res.ypbind_status = YPBIND_FAIL_VAL; 1351927Swollman 1361927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 1371927Swollman if( strcmp(ypdb->dom_domain, argp) == 0) 1381927Swollman break; 1391927Swollman 1401927Swollman if(ypdb==NULL) { 1411927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 1421927Swollman bzero((char *)ypdb, sizeof *ypdb); 1431927Swollman strncpy(ypdb->dom_domain, argp, sizeof ypdb->dom_domain); 1441927Swollman ypdb->dom_vers = YPVERS; 1451927Swollman ypdb->dom_alive = 0; 1461927Swollman ypdb->dom_lockfd = -1; 1471927Swollman sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 1481927Swollman unlink(path); 1491927Swollman ypdb->dom_pnext = ypbindlist; 1501927Swollman ypbindlist = ypdb; 1511927Swollman return NULL; 1521927Swollman } 1531927Swollman 1541927Swollman if(ypdb->dom_alive==0) 1551927Swollman return NULL; 1561927Swollman 1571927Swollman#if 0 1581927Swollman delta = ypdb->dom_check_t - ypdb->dom_ask_t; 1591927Swollman if( !(ypdb->dom_ask_t==0 || delta > 5)) { 1601927Swollman ypdb->dom_ask_t = time(NULL); 1611927Swollman /* 1621927Swollman * Hmm. More than 2 requests in 5 seconds have indicated that my 1631927Swollman * binding is possibly incorrect. Ok, make myself unalive, and 1641927Swollman * find out what the actual state is. 1651927Swollman */ 1661927Swollman if(ypdb->dom_lockfd!=-1) 1671927Swollman close(ypdb->dom_lockfd); 1681927Swollman ypdb->dom_lockfd = -1; 1691927Swollman ypdb->dom_alive = 0; 1701927Swollman ypdb->dom_lockfd = -1; 1711927Swollman sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers); 1721927Swollman unlink(path); 1731927Swollman return NULL; 1741927Swollman } 1751927Swollman#endif 1761927Swollman 1771927Swollmananswer: 1781927Swollman res.ypbind_status = YPBIND_SUCC_VAL; 1791927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr.s_addr = 1801927Swollman ypdb->dom_server_addr.sin_addr.s_addr; 1811927Swollman res.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = 1821927Swollman ypdb->dom_server_port; 1831927Swollman /*printf("domain %s at %s/%d\n", ypdb->dom_domain, 1841927Swollman inet_ntoa(ypdb->dom_server_addr.sin_addr), 1851927Swollman ntohs(ypdb->dom_server_addr.sin_port));*/ 1861927Swollman return &res; 1871927Swollman} 1881927Swollman 1891927Swollmanbool_t * 1901927Swollmanypbindproc_setdom_2(transp, argp, clnt) 1911927SwollmanSVCXPRT *transp; 1921927Swollmanstruct ypbind_setdom *argp; 1931927SwollmanCLIENT *clnt; 1941927Swollman{ 1951927Swollman struct sockaddr_in *fromsin, bindsin; 1963033Sdg static char res; 1971927Swollman 1981927Swollman bzero((char *)&res, sizeof(res)); 1991927Swollman fromsin = svc_getcaller(transp); 2001927Swollman 2011927Swollman switch(ypsetmode) { 2021927Swollman case YPSET_LOCAL: 2031927Swollman if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) 2041927Swollman return (void *)NULL; 2051927Swollman break; 2061927Swollman case YPSET_ALL: 2071927Swollman break; 2081927Swollman case YPSET_NO: 2091927Swollman default: 2101927Swollman return (void *)NULL; 2111927Swollman } 2121927Swollman 2131927Swollman if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED) 2141927Swollman return (void *)&res; 2151927Swollman 2161927Swollman if(argp->ypsetdom_vers != YPVERS) 2171927Swollman return (void *)&res; 2181927Swollman 2191927Swollman bzero((char *)&bindsin, sizeof bindsin); 2201927Swollman bindsin.sin_family = AF_INET; 2211927Swollman bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr; 2221927Swollman bindsin.sin_port = argp->ypsetdom_port; 2231927Swollman rpc_received(argp->ypsetdom_domain, &bindsin, 1); 2241927Swollman 2251927Swollman res = 1; 2261927Swollman return (void *)&res; 2271927Swollman} 2281927Swollman 2291927Swollmanstatic void 2301927Swollmanypbindprog_2(rqstp, transp) 2311927Swollmanstruct svc_req *rqstp; 2321927Swollmanregister SVCXPRT *transp; 2331927Swollman{ 2341927Swollman union { 2351927Swollman char ypbindproc_domain_2_arg[MAXHOSTNAMELEN]; 2361927Swollman struct ypbind_setdom ypbindproc_setdom_2_arg; 2371927Swollman } argument; 2381927Swollman struct authunix_parms *creds; 2391927Swollman char *result; 2401927Swollman bool_t (*xdr_argument)(), (*xdr_result)(); 2411927Swollman char *(*local)(); 2421927Swollman 2431927Swollman switch (rqstp->rq_proc) { 2441927Swollman case YPBINDPROC_NULL: 2451927Swollman xdr_argument = xdr_void; 2461927Swollman xdr_result = xdr_void; 2471927Swollman local = (char *(*)()) ypbindproc_null_2; 2481927Swollman break; 2491927Swollman 2501927Swollman case YPBINDPROC_DOMAIN: 2511927Swollman xdr_argument = xdr_domainname; 2521927Swollman xdr_result = xdr_ypbind_resp; 2531927Swollman local = (char *(*)()) ypbindproc_domain_2; 2541927Swollman break; 2551927Swollman 2561927Swollman case YPBINDPROC_SETDOM: 2571927Swollman switch(rqstp->rq_cred.oa_flavor) { 2581927Swollman case AUTH_UNIX: 2591927Swollman creds = (struct authunix_parms *)rqstp->rq_clntcred; 2601927Swollman if( creds->aup_uid != 0) { 2611927Swollman svcerr_auth(transp, AUTH_BADCRED); 2621927Swollman return; 2631927Swollman } 2641927Swollman break; 2651927Swollman default: 2661927Swollman svcerr_auth(transp, AUTH_TOOWEAK); 2671927Swollman return; 2681927Swollman } 2691927Swollman 2701927Swollman xdr_argument = xdr_ypbind_setdom; 2711927Swollman xdr_result = xdr_void; 2721927Swollman local = (char *(*)()) ypbindproc_setdom_2; 2731927Swollman break; 2741927Swollman 2751927Swollman default: 2761927Swollman svcerr_noproc(transp); 2771927Swollman return; 2781927Swollman } 2791927Swollman bzero((char *)&argument, sizeof(argument)); 2801927Swollman if (!svc_getargs(transp, xdr_argument, &argument)) { 2811927Swollman svcerr_decode(transp); 2821927Swollman return; 2831927Swollman } 2841927Swollman result = (*local)(transp, &argument, rqstp); 2851927Swollman if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 2861927Swollman svcerr_systemerr(transp); 2871927Swollman } 2881927Swollman return; 2891927Swollman} 2901927Swollman 2911927Swollmanmain(argc, argv) 2921927Swollmanchar **argv; 2931927Swollman{ 2941927Swollman char path[MAXPATHLEN]; 2951927Swollman struct timeval tv; 2961927Swollman fd_set fdsr; 2971927Swollman int width; 2981927Swollman int i; 2991927Swollman 3001927Swollman yp_get_default_domain(&domainname); 3011927Swollman if( domainname[0] == '\0') { 3021927Swollman fprintf(stderr, "domainname not set. Aborting.\n"); 3031927Swollman exit(1); 3041927Swollman } 3051927Swollman 3061927Swollman for(i=1; i<argc; i++) { 3071927Swollman if( strcmp("-ypset", argv[i]) == 0) 3081927Swollman ypsetmode = YPSET_ALL; 3091927Swollman else if (strcmp("-ypsetme", argv[i]) == 0) 3106732Swpaul ypsetmode = YPSET_LOCAL; 3116732Swpaul else if (strcmp("-s", argv[i]) == 0) 3126732Swpaul ypsecuremode++; 3131927Swollman } 3141927Swollman 3151927Swollman /* blow away everything in BINDINGDIR */ 3161927Swollman 3171927Swollman 3181927Swollman 3191927Swollman#ifdef DAEMON 3201927Swollman switch(fork()) { 3211927Swollman case 0: 3221927Swollman break; 3231927Swollman case -1: 3241927Swollman perror("fork"); 3251927Swollman exit(1); 3261927Swollman default: 3271927Swollman exit(0); 3281927Swollman } 3291927Swollman setsid(); 3301927Swollman#endif 3311927Swollman 3321927Swollman pmap_unset(YPBINDPROG, YPBINDVERS); 3331927Swollman 3341927Swollman udptransp = svcudp_create(RPC_ANYSOCK); 3351927Swollman if (udptransp == NULL) { 3361927Swollman fprintf(stderr, "cannot create udp service."); 3371927Swollman exit(1); 3381927Swollman } 3391927Swollman if (!svc_register(udptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 3401927Swollman IPPROTO_UDP)) { 3411927Swollman fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, udp)."); 3421927Swollman exit(1); 3431927Swollman } 3441927Swollman 3451927Swollman tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0); 3461927Swollman if (tcptransp == NULL) { 3471927Swollman fprintf(stderr, "cannot create tcp service."); 3481927Swollman exit(1); 3491927Swollman } 3501927Swollman 3511927Swollman if (!svc_register(tcptransp, YPBINDPROG, YPBINDVERS, ypbindprog_2, 3521927Swollman IPPROTO_TCP)) { 3531927Swollman fprintf(stderr, "unable to register (YPBINDPROG, YPBINDVERS, tcp)."); 3541927Swollman exit(1); 3551927Swollman } 3561927Swollman 3571927Swollman if( (rpcsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 3581927Swollman perror("socket"); 3591927Swollman return -1; 3601927Swollman } 3611927Swollman 3621927Swollman fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY); 3631927Swollman i = 1; 3641927Swollman setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i)); 3651927Swollman rmtca.prog = YPPROG; 3661927Swollman rmtca.vers = YPVERS; 3671927Swollman rmtca.proc = YPPROC_DOMAIN_NONACK; 3681927Swollman rmtca.xdr_args = NULL; /* set at call time */ 3691927Swollman rmtca.args_ptr = NULL; /* set at call time */ 3701927Swollman rmtcr.port_ptr = &rmtcr_port; 3711927Swollman rmtcr.xdr_results = xdr_bool; 3721927Swollman rmtcr.results_ptr = (caddr_t)&rmtcr_outval; 3731927Swollman 3741927Swollman /* build initial domain binding, make it "unsuccessful" */ 3751927Swollman ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist); 3761927Swollman bzero((char *)ypbindlist, sizeof *ypbindlist); 3771927Swollman strncpy(ypbindlist->dom_domain, domainname, sizeof ypbindlist->dom_domain); 3781927Swollman ypbindlist->dom_vers = YPVERS; 3796478Swpaul ypbindlist->dom_interval = 0; 3801927Swollman ypbindlist->dom_alive = 0; 3816478Swpaul ypbindlist->dom_answered = 0; 3821927Swollman ypbindlist->dom_lockfd = -1; 3836478Swpaul ypbindlist->dom_check_t = time(NULL) + ypbindlist->dom_interval; 3841927Swollman sprintf(path, "%s/%s.%d", BINDINGDIR, ypbindlist->dom_domain, 3851927Swollman ypbindlist->dom_vers); 3861927Swollman (void)unlink(path); 3871927Swollman 3886478Swpaul openlog(argv[0], LOG_PID, LOG_AUTH); 3891927Swollman width = getdtablesize(); 3906478Swpaul 3911927Swollman while(1) { 3921927Swollman fdsr = svc_fdset; 3931927Swollman FD_SET(rpcsock, &fdsr); 3941927Swollman tv.tv_sec = 1; 3951927Swollman tv.tv_usec = 0; 3961927Swollman 3971927Swollman switch(select(width, &fdsr, NULL, NULL, &tv)) { 3981927Swollman case 0: 3991927Swollman checkwork(); 4001927Swollman break; 4011927Swollman case -1: 4021927Swollman perror("select\n"); 4031927Swollman break; 4041927Swollman default: 4051927Swollman if(FD_ISSET(rpcsock, &fdsr)) { 4061927Swollman FD_CLR(rpcsock, &fdsr); 4071927Swollman handle_replies(); 4081927Swollman } 4091927Swollman svc_getreqset(&fdsr); 4101927Swollman break; 4111927Swollman } 4121927Swollman } 4131927Swollman} 4141927Swollman 4151927Swollman/* 4161927Swollman * change to do something like this: 4171927Swollman * 4181927Swollman * STATE TIME ACTION NEWTIME NEWSTATE 4191927Swollman * no binding t==* broadcast t=2 no binding 4201927Swollman * binding t==60 check server t=10 binding 4211927Swollman * binding t=10 broadcast t=2 no binding 4221927Swollman */ 4236478Swpaul 4246478Swpaul/* 4256478Swpaul * The above comment makes no sense whatsoever. This is what should 4266478Swpaul * be happening: 4276478Swpaul * 4286478Swpaul * - If we have any servers in our binding list marked alive, ping 4296478Swpaul * them _and them alone_ only once every 60 seconds to make sure 4306478Swpaul * they haven't crapped out on us (i.e. bother only the servers 4316478Swpaul * we know about: *DON'T* continually bother everybody with broadcast 4326478Swpaul * packets every 5 seconds like we used to). 4336478Swpaul * - If they don't respond within FAIL_THRESHOLD seconds after the ping, 4346478Swpaul * they're toast: mark them unalive and start to scream and shout. 4356478Swpaul * - If we don't have any servers marked alive, then we're in desperate 4366478Swpaul * trouble and we need to broadcast a cry for help every 5 seconds 4376478Swpaul * until somebody answers us. 4386478Swpaul */ 4396478Swpaul 4401927Swollmancheckwork() 4411927Swollman{ 4421927Swollman struct _dom_binding *ypdb; 4431927Swollman time_t t; 4441927Swollman 4451927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) { 4466478Swpaul time(&t); 4476478Swpaul if (ypdb->dom_check_t < t) { 4486478Swpaul broadcast(ypdb->dom_domain, 4496478Swpaul ypdb->dom_server_addr, ypdb->dom_alive); 4506478Swpaul ypdb->dom_check_t = t + ypdb->dom_interval; 4516478Swpaul ypdb->dom_answered = 0; 4526478Swpaul } else 4536478Swpaul if (!ypdb->dom_answered && ypdb->dom_alive && 4546478Swpaul ypdb->dom_check_t < (t + FAIL_THRESHOLD)) { 4556732Swpaul ypdb->dom_check_t = ypdb->dom_alive = 4566478Swpaul ypdb->dom_vers = 0; 4576478Swpaul ypdb->dom_interval = 5; 4586732Swpaul syslog (LOG_NOTICE, 4596732Swpaul "NIS server [%s] for domain %s not responding.", 4606732Swpaul inet_ntoa(ypdb->dom_server_addr.sin_addr), 4616732Swpaul ypdb->dom_domain); 4621927Swollman } 4631927Swollman } 4641927Swollman} 4651927Swollman 4666478Swpaulbroadcast(dom, saddr, direct) 4671927Swollmanchar *dom; 4686478Swpaulstruct sockaddr_in saddr; 4696478Swpaulint direct; 4701927Swollman{ 4711927Swollman struct rpc_msg rpcmsg; 4721927Swollman char buf[1400], inbuf[8192]; 4731927Swollman enum clnt_stat st; 4741927Swollman struct timeval tv; 4751927Swollman int outlen, i, sock, len; 4761927Swollman struct sockaddr_in bsin; 4771927Swollman struct ifconf ifc; 4781927Swollman struct ifreq ifreq, *ifr; 4791927Swollman struct in_addr in; 4801927Swollman AUTH *rpcua; 4811927Swollman XDR rpcxdr; 4821927Swollman 4831927Swollman rmtca.xdr_args = xdr_domainname; 4841927Swollman rmtca.args_ptr = dom; 4851927Swollman 4861927Swollman bzero((char *)&bsin, sizeof bsin); 4871927Swollman bsin.sin_family = AF_INET; 4881927Swollman bsin.sin_port = htons(PMAPPORT); 4891927Swollman 4901927Swollman bzero((char *)&rpcxdr, sizeof rpcxdr); 4911927Swollman bzero((char *)&rpcmsg, sizeof rpcmsg); 4921927Swollman 4931927Swollman rpcua = authunix_create_default(); 4941927Swollman if( rpcua == (AUTH *)NULL) { 4951927Swollman /*printf("cannot get unix auth\n");*/ 4961927Swollman return RPC_SYSTEMERROR; 4971927Swollman } 4981927Swollman rpcmsg.rm_direction = CALL; 4991927Swollman rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 5001927Swollman rpcmsg.rm_call.cb_prog = PMAPPROG; 5011927Swollman rpcmsg.rm_call.cb_vers = PMAPVERS; 5021927Swollman rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT; 5031927Swollman rpcmsg.rm_call.cb_cred = rpcua->ah_cred; 5041927Swollman rpcmsg.rm_call.cb_verf = rpcua->ah_verf; 5051927Swollman 5061927Swollman gettimeofday(&tv, (struct timezone *)0); 5071927Swollman rpcmsg.rm_xid = (int)dom; 5081927Swollman tv.tv_usec = 0; 5091927Swollman xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE); 5101927Swollman if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) { 5111927Swollman st = RPC_CANTENCODEARGS; 5121927Swollman AUTH_DESTROY(rpcua); 5131927Swollman return st; 5141927Swollman } 5151927Swollman if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) { 5161927Swollman st = RPC_CANTENCODEARGS; 5171927Swollman AUTH_DESTROY(rpcua); 5181927Swollman return st; 5191927Swollman } 5201927Swollman outlen = (int)xdr_getpos(&rpcxdr); 5211927Swollman xdr_destroy(&rpcxdr); 5221927Swollman if(outlen<1) { 5231927Swollman AUTH_DESTROY(rpcua); 5241927Swollman return st; 5251927Swollman } 5261927Swollman AUTH_DESTROY(rpcua); 5271927Swollman 5281927Swollman /* find all networks and send the RPC packet out them all */ 5291927Swollman if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 5301927Swollman perror("socket"); 5311927Swollman return -1; 5321927Swollman } 5331927Swollman 5346478Swpaul /* 5356478Swpaul * It's impolite to blast broadcast packets all over the place 5366478Swpaul * when we don't really have to. 5376478Swpaul */ 5386478Swpaul if (!direct) { 5396478Swpaul ifc.ifc_len = sizeof inbuf; 5406478Swpaul ifc.ifc_buf = inbuf; 5416478Swpaul if( ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 5426478Swpaul close(sock); 5436478Swpaul perror("ioctl(SIOCGIFCONF)"); 5446478Swpaul return -1; 5456478Swpaul } 5466478Swpaul ifr = ifc.ifc_req; 5476478Swpaul ifreq.ifr_name[0] = '\0'; 5486478Swpaul for(i=0; i<ifc.ifc_len; i+=len, ifr=(struct ifreq *)((caddr_t)ifr+len)) { 5491927Swollman#if defined(BSD) && BSD >= 199103 5506478Swpaul len = sizeof ifr->ifr_name + ifr->ifr_addr.sa_len; 5511927Swollman#else 5526478Swpaul len = sizeof ifc.ifc_len / sizeof(struct ifreq); 5531927Swollman#endif 5546478Swpaul ifreq = *ifr; 5556478Swpaul if( ifreq.ifr_addr.sa_family != AF_INET) 5561927Swollman continue; 5576478Swpaul if( ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) { 5586478Swpaul perror("ioctl(SIOCGIFFLAGS)"); 5596478Swpaul continue; 5601927Swollman } 5616478Swpaul if( (ifreq.ifr_flags & IFF_UP) == 0) 5621927Swollman continue; 5631927Swollman 5646478Swpaul ifreq.ifr_flags &= (IFF_LOOPBACK | IFF_BROADCAST); 5656478Swpaul if( ifreq.ifr_flags==IFF_BROADCAST ) { 5666478Swpaul if( ioctl(sock, SIOCGIFBRDADDR, &ifreq) < 0 ) { 5676478Swpaul perror("ioctl(SIOCGIFBRDADDR)"); 5686478Swpaul continue; 5696478Swpaul } 5706478Swpaul } else if( ifreq.ifr_flags==IFF_LOOPBACK ) { 5716478Swpaul if( ioctl(sock, SIOCGIFADDR, &ifreq) < 0 ) { 5726478Swpaul perror("ioctl(SIOCGIFADDR)"); 5736478Swpaul continue; 5746478Swpaul } 5756478Swpaul } else 5766478Swpaul continue; 5776478Swpaul in = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; 5786478Swpaul bsin.sin_addr = in; 5796478Swpaul if( sendto(rpcsock, buf, outlen, 0, 5806478Swpaul (struct sockaddr *)&bsin, sizeof bsin) < 0 ) 5816478Swpaul perror("sendto"); 5826478Swpaul } 5836478Swpaul } else { 5846478Swpaul in = ((struct sockaddr_in *)&saddr)->sin_addr; 5851927Swollman bsin.sin_addr = in; 5861927Swollman if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin, 5871927Swollman sizeof bsin) < 0 ) 5881927Swollman perror("sendto"); 5891927Swollman } 5906478Swpaul 5911927Swollman close(sock); 5921927Swollman return 0; 5931927Swollman} 5941927Swollman 5951927Swollman/*enum clnt_stat*/ 5961927Swollmanhandle_replies() 5971927Swollman{ 5981927Swollman char buf[1400]; 5991927Swollman int fromlen, inlen; 6001927Swollman struct sockaddr_in raddr; 6011927Swollman struct rpc_msg msg; 6021927Swollman XDR xdr; 6031927Swollman 6041927Swollmanrecv_again: 6051927Swollman bzero((char *)&xdr, sizeof(xdr)); 6061927Swollman bzero((char *)&msg, sizeof(msg)); 6071927Swollman msg.acpted_rply.ar_verf = _null_auth; 6081927Swollman msg.acpted_rply.ar_results.where = (caddr_t)&rmtcr; 6091927Swollman msg.acpted_rply.ar_results.proc = xdr_rmtcallres; 6101927Swollman 6111927Swollmantry_again: 6121927Swollman fromlen = sizeof (struct sockaddr); 6131927Swollman inlen = recvfrom(rpcsock, buf, sizeof buf, 0, 6141927Swollman (struct sockaddr *)&raddr, &fromlen); 6151927Swollman if(inlen<0) { 6161927Swollman if(errno==EINTR) 6171927Swollman goto try_again; 6181927Swollman return RPC_CANTRECV; 6191927Swollman } 6201927Swollman if(inlen<sizeof(u_long)) 6211927Swollman goto recv_again; 6221927Swollman 6231927Swollman /* 6241927Swollman * see if reply transaction id matches sent id. 6251927Swollman * If so, decode the results. 6261927Swollman */ 6271927Swollman xdrmem_create(&xdr, buf, (u_int)inlen, XDR_DECODE); 6281927Swollman if( xdr_replymsg(&xdr, &msg)) { 6291927Swollman if( (msg.rm_reply.rp_stat == MSG_ACCEPTED) && 6301927Swollman (msg.acpted_rply.ar_stat == SUCCESS)) { 6311927Swollman raddr.sin_port = htons((u_short)rmtcr_port); 6321927Swollman rpc_received(msg.rm_xid, &raddr, 0); 6331927Swollman } 6341927Swollman } 6351927Swollman xdr.x_op = XDR_FREE; 6361927Swollman msg.acpted_rply.ar_results.proc = xdr_void; 6371927Swollman xdr_destroy(&xdr); 6381927Swollman 6391927Swollman return RPC_SUCCESS; 6401927Swollman} 6411927Swollman 6421927Swollman/* 6431927Swollman * LOOPBACK IS MORE IMPORTANT: PUT IN HACK 6441927Swollman */ 6451927Swollmanrpc_received(dom, raddrp, force) 6461927Swollmanchar *dom; 6471927Swollmanstruct sockaddr_in *raddrp; 6481927Swollmanint force; 6491927Swollman{ 6501927Swollman struct _dom_binding *ypdb; 6511927Swollman struct iovec iov[2]; 6521927Swollman struct ypbind_resp ybr; 6531927Swollman char path[MAXPATHLEN]; 6541927Swollman int fd; 6551927Swollman 6566732Swpaul /*printf("returned from %s/%d about %s\n", inet_ntoa(raddrp->sin_addr), 6576732Swpaul ntohs(raddrp->sin_port), dom);*/ 6581927Swollman 6591927Swollman if(dom==NULL) 6601927Swollman return; 6611927Swollman 6626732Swpaul /* if in securemode, check originating port number */ 6636732Swpaul if (ypsecuremode && (ntohs(raddrp->sin_port) >= IPPORT_RESERVED)) { 6646732Swpaul syslog(LOG_WARNING, "Rejected NIS server on [%s/%d] for domain %s.", 6656732Swpaul inet_ntoa(raddrp->sin_addr), ntohs(raddrp->sin_port), 6666732Swpaul dom); 6676732Swpaul return; 6686732Swpaul } 6696732Swpaul 6701927Swollman for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) 6711927Swollman if( strcmp(ypdb->dom_domain, dom) == 0) 6721927Swollman break; 6731927Swollman 6741927Swollman if(ypdb==NULL) { 6751927Swollman if(force==0) 6761927Swollman return; 6771927Swollman ypdb = (struct _dom_binding *)malloc(sizeof *ypdb); 6781927Swollman bzero((char *)ypdb, sizeof *ypdb); 6791927Swollman strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain); 6801927Swollman ypdb->dom_lockfd = -1; 6811927Swollman ypdb->dom_pnext = ypbindlist; 6821927Swollman ypbindlist = ypdb; 6831927Swollman } 6841927Swollman 6856478Swpaul /* soft update, alive, less than FAIL_THRESHOLD seconds old */ 6866478Swpaul if(ypdb->dom_alive==1 && (force==0 || ypdb->dom_answered == 0) 6876732Swpaul && (ypdb->dom_check_t - FAIL_THRESHOLD) > time(NULL) 6886732Swpaul && (ypdb->dom_server_addr.sin_port == raddrp->sin_port)) { 6896478Swpaul ypdb->dom_answered = 1; 6906478Swpaul ypdb->dom_interval = 60; 6911927Swollman return; 6926478Swpaul } 6931927Swollman 6946478Swpaul /* 6956478Swpaul * We've recovered from a crash: inform the world. 6966478Swpaul */ 6976478Swpaul if (ypdb->dom_vers == 0) 6986478Swpaul syslog(LOG_NOTICE, "NIS server [%s] for domain %s OK.", 6996732Swpaul inet_ntoa(raddrp->sin_addr), ypdb->dom_domain); 7006478Swpaul 7011927Swollman bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr, 7021927Swollman sizeof ypdb->dom_server_addr); 7036478Swpaul 7041927Swollman ypdb->dom_vers = YPVERS; 7051927Swollman ypdb->dom_alive = 1; 7066478Swpaul ypdb->dom_answered = 1; 7076478Swpaul ypdb->dom_interval = 60; 7086478Swpaul ypdb->dom_check_t = time(NULL) + ypdb->dom_interval; 7091927Swollman 7101927Swollman if(ypdb->dom_lockfd != -1) 7111927Swollman close(ypdb->dom_lockfd); 7121927Swollman 7131927Swollman sprintf(path, "%s/%s.%d", BINDINGDIR, 7141927Swollman ypdb->dom_domain, ypdb->dom_vers); 7151927Swollman#ifdef O_SHLOCK 7161927Swollman if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) { 7171927Swollman (void)mkdir(BINDINGDIR, 0755); 7181927Swollman if( (fd=open(path, O_CREAT|O_SHLOCK|O_RDWR|O_TRUNC, 0644)) == -1) 7191927Swollman return; 7201927Swollman } 7211927Swollman#else 7221927Swollman if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) { 7231927Swollman (void)mkdir(BINDINGDIR, 0755); 7241927Swollman if( (fd=open(path, O_CREAT|O_RDWR|O_TRUNC, 0644)) == -1) 7251927Swollman return; 7261927Swollman } 7271927Swollman flock(fd, LOCK_SH); 7281927Swollman#endif 7291927Swollman 7301927Swollman /* 7311927Swollman * ok, if BINDINGDIR exists, and we can create the binding file, 7321927Swollman * then write to it.. 7331927Swollman */ 7341927Swollman ypdb->dom_lockfd = fd; 7351927Swollman 7361927Swollman iov[0].iov_base = (caddr_t)&(udptransp->xp_port); 7371927Swollman iov[0].iov_len = sizeof udptransp->xp_port; 7381927Swollman iov[1].iov_base = (caddr_t)&ybr; 7391927Swollman iov[1].iov_len = sizeof ybr; 7401927Swollman 7411927Swollman bzero(&ybr, sizeof ybr); 7421927Swollman ybr.ypbind_status = YPBIND_SUCC_VAL; 7431927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_addr = raddrp->sin_addr; 7441927Swollman ybr.ypbind_respbody.ypbind_bindinfo.ypbind_binding_port = raddrp->sin_port; 7451927Swollman 7461927Swollman if( writev(ypdb->dom_lockfd, iov, 2) != iov[0].iov_len + iov[1].iov_len) { 7471927Swollman perror("write"); 7481927Swollman close(ypdb->dom_lockfd); 7491927Swollman ypdb->dom_lockfd = -1; 7501927Swollman return; 7511927Swollman } 7521927Swollman} 753