ypbind.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,033 行 · 第 1/2 页
C
1,033 行
#ifndef lintstatic char *sccsid = "@(#)ypbind.c 4.5 (ULTRIX) 3/1/91";#endif lint/**************************************************************** * * * Licensed to Digital Equipment Corporation, Maynard, MA * * Copyright 1985 Sun Microsystems, Inc. * * All rights reserved. * * * ****************************************************************//* * This constructs a list of servers by domains, * and keeps more-or-less up to dat track of * those server's reachability. *//* 02/06/89 jhw added ypbind -S security option *//* 04/14/89 jhw added SUN 4.0 code *//* 08/30/89 jhw backed out SUNs reserve port check *//* 12/14/89 jhw added nulling of client structs *//* 08/08/90 terry added ypbind -X initial bind option */ /* 01/24/91 terry bug fixes to ypbind_send_setdom() and *//* ypbind_set_binding() to match Sun's *//* code and fix the problem of ypbind not*//* working when no options are used. *//* 02/27/91 terry support new file descriptor handling */ #include <stdio.h>#include <errno.h>#include <signal.h>#include <sys/time.h>#include <sys/wait.h>#include <rpc/rpc.h>#include <sys/dir.h>#include <netdb.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <rpcsvc/yp_prot.h>#include <rpcsvc/ypv1_prot.h>#include <rpcsvc/ypclnt.h>/* * The domain struct is the data structure used by the yp binder to remember * mappings of domain to a server. The list of domains is pointed to by * known_domains. Domains are added when the yp binder gets binding requests * for domains which are not currently on the list. Once on the list, an * entry stays on the list forever. Bindings are initially made by means of * a broadcast method, using functions ypbind_broadcast_bind and * ypbind_broadcast_ack. This means of binding is re-done any time the domain * becomes unbound, which happens when a server doesn't respond to a ping. * current_domain is used to communicate among the various functions in this * module; it is set by ypbind_get_binding. * */struct domain { struct domain *dom_pnext; char dom_name[MAXNAMLEN + 1]; unsigned short dom_vers; /* YPVERS or YPOLDVERS */ bool dom_boundp; CLIENT *ping_clnt; struct in_addr dom_serv_addr; unsigned short int dom_serv_port; int dom_report_success; /* Controls msg to /dev/console*/ int dom_broadcaster_pid;};static int ping_sock = RPC_ANYSOCK;struct domain *known_domains = (struct domain *) NULL;struct domain *current_domain; /* Used by ypbind_broadcast_ack, set * by all callers of clnt_broadcast */struct domain *broadcast_domain; /* Set by ypbind_get_binding, used * by the mainline. */SVCXPRT *tcphandle;SVCXPRT *udphandle;#define BINDING_TRIES 3 /* Number of times we'll broadcast to * try to bind default domain. */#define PINGTOTTIM 20 /* Total seconds for ping timeout */#define PINGINTERTRY 10#define SETDOMINTERTRY 20#define SETDOMTOTTIM 60/*** udp timeout stuff *****/#define UDPINTER_TRY 5 /* Secs between tries for udp*/#define UDPTIMEOUT UDPINTER_TRY*3 /* Total timeout for udp */#define CALLINTER_TRY 10 /* Secs between callback tries*/#define CALLTIMEOUT CALLINTER_TRY*2 /* Total timeout for callback */struct timeval udp_intertry = { UDPINTER_TRY, 0};struct timeval udp_timeout = { UDPTIMEOUT, 0};struct timeval tcp_timeout = { 180, /* timeout for map enumeration (could be long) */ 0};#ifdef VERBOSEint silent = FALSE;#elseint silent = TRUE;#endifextern int errno;void dispatch();void ypbind_dispatch();void ypbind_olddispatch();void ypbind_get_binding();void ypbind_set_binding();void ypbind_send_setdom();struct domain *ypbind_point_to_domain();bool ypbind_broadcast_ack();void ypbind_ping();void ypbind_init_default();void broadcast_proc_exit();extern bool xdr_ypdomain_wrap_string();extern bool xdr_ypbind_resp();/******************************************************************************//* usage - ypbind -S domainname,server1[,server2,server3,server4] *//* The -S option allows the system administrator to startup ypbind *//* in a secure mode. The -S option locks this ypbind process into the *//* specified domainname and server. *//* It will not accept any other system as its server. *//* Consequently the secure option should only be used where either the *//* system itself is a server and you are setting it to itself or when a *//* very reliable server is available in your environment. *//******************************************************************************/char srvname[4][64];char srvaddr[4][64];char setdomain[64];struct hostent *hp;struct sockaddr_in sock[4];struct sockaddr_in *sin;struct sockaddr_in myaddr;int locked=0;int preflock= -1;int x_init_bind= 0; /* x_init_bind is set during the initial attempt */ /* to bind, if both the -S and -X options are used */main(argc, argv) int argc; char *argv[];{ int pid; int i,j,k,t; int readfds; char *pname; char *securarg; extern char *optarg; bool true; int exit_arg=0; /* exit_arg is set if the -X option is used */ int arg; /* * must be superuser to run */ if (geteuid() != 0){ (void) fprintf(stderr, "ypbind: must be super user\n"); (void) fflush(stderr); exit(1); } /* initialize my address reference */ get_myaddress(&myaddr); /* * unset any old YPBIND processes */ (void) pmap_unset(YPBINDPROG, YPBINDVERS); (void) pmap_unset(YPBINDPROG, YPBINDOLDVERS); /* * process security arguments */ while ((arg = getopt(argc, argv, "XS:")) != EOF) { switch (arg) { case 'X': /* Initial Bind Option */ exit_arg = TRUE; break;/******ULTRIX SECUREYP *******/ case 'S': /* specify secure domainname.server */ strcpy(&securarg, &optarg); for ( t=0,j=0,i=0,k=0;securarg[i] != '\0'; i++ ) { if(!locked) if(securarg[i] == ',') { setdomain[t]='\0'; setdomainname(setdomain,strlen(setdomain)); locked=1; } else setdomain[t++]=securarg[i]; else { if(securarg[i] == ',') { srvname[k++][j]='\0'; if(k > 3) { fprintf(stderr,"Maximum of four servers selectable\n"); exit(1); } j=0; } else srvname[k][j++]=securarg[i]; } } /* save number of servers in locked flag */ if(!locked) { fprintf(stderr,"Usage: ypbind -S domain,server,server\n Up to four servers.\n"); exit(1); } locked=k+1; srvname[k][j]='\0'; for (i=0;i<locked;i++) { bzero((caddr_t)&sock[i], sizeof (struct sockaddr_in)); sin = &sock[i]; sin->sin_family = AF_INET; sin->sin_port = 0; sin->sin_addr.s_addr = inet_addr(srvname[i]); if (sin->sin_addr.s_addr == -1) { hp=gethostbyname(srvname[i]); if (hp == NULL) { fprintf(stderr, "arp: %s: unknown host\n", srvname[i]); exit(1); } bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,sizeof sin->sin_addr); } /* show preference to the local server */ if(sin->sin_addr.s_addr == myaddr.sin_addr.s_addr) preflock=i; } break;/*******ULTRIX SECUREYP *******/ } } /* Initial Bind Option (-X) * * If the -X option is specified, YPbind will initially attempt * to bind to a server BEFORE backgrounding itself. If YPbind * fails to bind to a server after BINDING_TRIES attempts, YPbind * will exit. */ if (exit_arg) { /* Initial binding with -S option */ if (locked) { x_init_bind = TRUE; ypbind_locked (preflock,YPVERS); x_init_bind = FALSE; } /* Initial binding without -S option */ else { ypbind_init_default(); } /* Exit YPbind if the initial binding failed */ if (!(current_domain->dom_boundp)) { (void) fprintf (stderr,"ypbind exiting: cannot bind to server.\n"); (void) fflush (stderr); exit(1); } } if (silent) { pid = fork(); if (pid == -1) { (void) fprintf(stderr, "ypbind: fork failure.\n"); (void) fflush(stderr); abort(); } if (pid != 0) { /* * Gross hack for last minute fix for release 3.0 FCS. * Make sure our child is registered and running * before we exit; the real solution is to do the * registration BEFORE the fork, but for historical * reasons it was not done. This prevents racing * with other processes started by rc.local. */ for(;;) { if (pmap_getport(&myaddr, YPBINDPROG, YPBINDVERS, IPPROTO_UDP)) exit(0); sleep(2); } } for (t = 0; t < 20; t++) { (void) close(t); } (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2); t = open("/dev/tty", 2); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } } if ((int) signal(SIGCHLD, broadcast_proc_exit) == -1) { (void) fprintf(stderr, "ypbind: Can't catch broadcast process exit signal.\n"); (void) fflush(stderr); abort(); } if ((tcphandle = svctcp_create(RPC_ANYSOCK, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == NULL) { (void) fprintf(stderr, "ypbind: can't create tcp service.\n"); (void) fflush(stderr); abort(); } if (!svc_register(tcphandle, YPBINDPROG, YPBINDVERS, ypbind_dispatch, IPPROTO_TCP) ) { (void) fprintf(stderr, "ypbind: can't register tcp service.\n"); (void) fflush(stderr); abort(); } if ((udphandle = svcudp_bufcreate(RPC_ANYSOCK, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE)) == (SVCXPRT *) NULL) { (void) fprintf(stderr, "ypbind: can't create udp service.\n"); (void) fflush(stderr); abort(); } if (!svc_register(udphandle, YPBINDPROG, YPBINDVERS, ypbind_dispatch, IPPROTO_UDP) ) { (void) fprintf(stderr, "ypbind: can't register udp service.\n"); (void) fflush(stderr); abort(); } if (!svc_register(tcphandle, YPBINDPROG, YPBINDOLDVERS, ypbind_olddispatch, IPPROTO_TCP) ) { (void) fprintf(stderr, "ypbind: can't register tcp service.\n"); (void) fflush(stderr); abort(); } if (!svc_register(udphandle, YPBINDPROG, YPBINDOLDVERS, ypbind_olddispatch, IPPROTO_UDP) ) { (void) fprintf(stderr, "ypbind: can't register udp service.\n"); (void) fflush(stderr); abort(); } /* If we are running in locked mode lock up the domain and server */ if(locked) { ypbind_locked(preflock,YPVERS); (void) fprintf(stderr,"YPBIND is locked\n"); } for (;;) { readfds = svc_fds; errno = 0; switch ( (int) select(32, &readfds, NULL, NULL, NULL) ) { case -1: { if (errno != EINTR) { (void) fprintf (stderr, "ypbind: bad fds bits in main loop select mask.\n"); } break; } case 0: { (void) fprintf (stderr, "ypbind: invalid timeout in main loop select.\n"); break; } default: { svc_getreq (readfds); break; } } }}/* * ypbind_dispatch and ypbind_olddispatch are wrappers for dispatch which * remember which protocol the requestor is looking for. The theory is, * that since YPVERS and YPBINDVERS are defined in the same header file, if * a request comes in on the old binder protocol, the requestor is looking * for the old yp server. */voidypbind_dispatch(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ dispatch(rqstp, transp, (unsigned short) YPVERS);}voidypbind_olddispatch(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp;{ dispatch(rqstp, transp, (unsigned short) YPOLDVERS);}/* * This dispatches to binder action routines. */voiddispatch(rqstp, transp, vers) struct svc_req *rqstp; SVCXPRT *transp; unsigned short vers;{ switch (rqstp->rq_proc) { case YPBINDPROC_NULL: if (!svc_sendreply(transp, xdr_void, 0) ) { (void) fprintf(stderr, "ypbind: Can't reply to rpc call.\n"); } break; case YPBINDPROC_DOMAIN: ypbind_get_binding(rqstp, transp, vers); break; case YPBINDPROC_SETDOM: ypbind_set_binding(rqstp, transp, vers); break; default: svcerr_noproc(transp); break; }}/* * This is a Unix SIGCHILD handler which notices when a broadcaster child * process has exited, and retrieves the exit status. The broadcaster pid * is set to 0. If the broadcaster succeeded, dom_report_success will be * be set to -1. */voidbroadcast_proc_exit(){ int pid; union wait wait_status; register struct domain *pdom; pid = 0; for (;;) { pid = wait3(&wait_status, WNOHANG, NULL); if (pid == 0) { return; } else if (pid == -1) { return; } for (pdom = known_domains; pdom != (struct domain *)NULL; pdom = pdom->dom_pnext) { if (pdom->dom_broadcaster_pid == pid) { pdom->dom_broadcaster_pid = 0; if ((wait_status.w_termsig == 0) && (wait_status.w_retcode == 0)) pdom->dom_report_success = -1; } } }}/* * This returns the current binding for a passed domain. */voidypbind_get_binding(rqstp, transp, vers) struct svc_req *rqstp; register SVCXPRT *transp; unsigned short vers;{ char domain_name[YPMAXDOMAIN + 1]; char *pdomain_name = domain_name; char *pname;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?