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 + -
显示快捷键?