📄 yp_bind.c
字号:
#if !defined(lint) && defined(SCCSIDS)static char sccsid[] = "@(#)yp_bind.c 1.1 92/07/30 Copyr 1990 Sun Micro";#endif#ifdef sun#define MAP_STUFF 1#endif#include <stdio.h>#include <errno.h>#include <fcntl.h>#include <sys/time.h>#include <rpc/rpc.h>#include <rpc/pmap_prot.h>#include <sys/socket.h>#include <sys/fcntl.h>#include <sys/file.h>#include <sys/syslog.h>#include "yp_prot.h"#include "ypv1_prot.h"#include "ypclnt.h"#define BFSIZE (YPMAXDOMAIN + 32) /* size of binding file *//* This should match the one in ypbind.c */#define CACHE_DIR "/var/yp/binding"extern int errno;extern int sleep();extern malloc_t malloc();extern char *strcpy();static void _yp_unbind();enum bind_status { BS_BAGIT, BS_RETRY, BS_OK};bool check_pmap_up();bool check_binder_up();enum bind_status talk2_pmap();enum bind_status talk2_binder();void talk2_server();enum bind_status get_binder_port();bool check_binding();void newborn();struct dom_binding *load_dom_binding();/* * Time parameters when talking to the ypbind and pmap processes */#define YPSLEEPTIME 5 /* Time to sleep between tries */unsigned int _ypsleeptime = YPSLEEPTIME;#define YPBIND_TIMEOUT 30 /* Total seconds for timeout */#define YPBIND_INTER_TRY 30 /* Seconds between tries */static struct timeval bind_intertry = { YPBIND_INTER_TRY, /* Seconds */ 0 /* Microseconds */ };static struct timeval bind_timeout = { YPBIND_TIMEOUT, /* Seconds */ 0 /* Microseconds */ };/* * Time parameters when talking to the ypserv process */#ifdef DEBUG#define YPTIMEOUT 120 /* Total seconds for timeout */#define YPINTER_TRY 60 /* Seconds between tries */#else#define YPTIMEOUT 90 /* Total seconds for timeout */#define YPINTER_TRY 5 /* Seconds between tries */#endif#define MAX_TRIES_FOR_NEW_YP 1 /* Number of times we'll try to get * a new YP server before we'll * settle for an old one. */static struct timeval ypserv_intertry = { YPINTER_TRY, /* Seconds */ 0 /* Microseconds */ };struct timeval _ypserv_timeout = { YPTIMEOUT, /* Seconds */ 0 /* Microseconds */ };static struct in_addr my_addr; /* Local internet addr */static struct dom_binding *bound_domains; /* List of bound domains */static char *default_domain;static char bfinvalid; /* Binding file invalid */static char *bfname;#ifdef MAP_STUFF#include <sys/mman.h>static u_short *binderfilemap; /* Mapped version of binder */#define MAP_LEN (2+sizeof(struct ypbind_resp)) /* just for current udp only*/#endifstatic int bf; /* Binding file fd *//* * binder_port holds what we believe to be the local port for ypbind. It is * set only by talk2_pmap. It is cleared (set to 0) by: * 1. talk2_pmap: always upon entry. * 2. check_binder_up if: * - It can't create a socket to speak to the binder. * - If it fails to bind to the port. * 3. talk2_binder if there are RPC errors when trying to use the port. */static unsigned long binder_port; /* Initialize to "no port" *//* * Attempts to locate a NIS server that serves a passed domain. If * one is found, an entry is created on the static list of domain-server pairs * pointed to by cell bound_domains, a udp path to the server is created and * the function returns 0. Otherwise, the function returns a defined errorcode * YPERR_xxxx. */int_yp_dobind(domain, binding) char *domain; struct dom_binding **binding; /* if result == 0, ptr to dom_binding */{return (_yp_dobind_soft(domain,binding, -1));}int_yp_dobind_soft(domain, binding,usertries) char *domain; struct dom_binding **binding; /* if result == 0, ptr to dom_binding */ int usertries;{ struct dom_binding *pdomb; /* Ptr to new domain binding */ struct sockaddr_in ypbinder; /* To talk with ypbinder */ char *pdomain; /* For xdr interface */ struct ypbind_resp ypbind_resp; /* Response from local ypbinder */ int vers; /* ypbind program version number */ int tries; /* Number of times we've tried with * the current protocol */ int gbtries; /* Number of times we've tried to * get the binder */ int status; u_short b_port; enum bind_status loopctl; bool bound; bool oldport = FALSE;#ifdef MAP_STUFF char tmpbfname[BFSIZE];#endif if ( (domain == NULL) ||(strlen(domain) == 0) ) { return (YPERR_BADARGS); } newborn(); if (bfname==0){ bfname=(char *)calloc(1,BFSIZE); } if (bfname==0){ bfinvalid=TRUE; } if (!bfinvalid) {#ifdef MAP_STUFF sprintf(tmpbfname,"%s/%s.%d",CACHE_DIR,domain,YPVERS); if (strcmp(bfname,tmpbfname)==0){ /*same name*/ if (binderfilemap){ binder_port = binderfilemap[0]; } } else { bfname[0]=0; if (binderfilemap){ munmap(binderfilemap,MAP_LEN); binderfilemap=0; } if ((bf = open(tmpbfname,O_RDONLY)) != -1) { if (flock(bf,LOCK_EX+LOCK_NB) == 0) { close(bf); bf = -1; /* Not valid if we would lock it */ } else { binderfilemap=(u_short *)mmap(bfname,MAP_LEN,PROT_READ,MAP_SHARED,bf,0); if ((int)binderfilemap == -1) binderfilemap=0; if (binderfilemap){ strcpy(bfname,tmpbfname); binder_port = binderfilemap[0]; close(bf); } else { close(bf); bf= -1; /*map failed*/ } } } }#else sprintf(bfname,"%s/%s.%d",CACHE_DIR,domain,YPVERS); if ((bf = open(bfname,O_RDONLY)) != -1) { if (flock(bf,LOCK_EX+LOCK_NB) == 0) { close(bf); bf = -1; /* Not valid if we would lock it */ } else { read(bf,&b_port,sizeof(u_short)); binder_port = b_port; close(bf); } }#endif } if (check_binding(domain, binding) ) return (0); /* We are bound */ /* * Use loopback address. */ my_addr.s_addr = INADDR_LOOPBACK; pdomain = domain; /* * Try to get the binder's port, using the current program version. * The version may be changed to the old version, deep in the bowels * of talk2_binder. */ for (bound = FALSE, vers = YPBINDVERS; !bound; ) { if (binder_port) { oldport = TRUE; } else { oldport = FALSE; /* * Get the binder's port. We'll loop as long as * get_binder_port returns BS_RETRY. */ for (gbtries=0,loopctl = BS_RETRY; loopctl != BS_OK;gbtries++ ) { if ((usertries>=0) && gbtries >=usertries) return (status); switch (loopctl = get_binder_port(vers, &status) ) { case BS_BAGIT: return (status); case BS_OK: break; } } } /* * See whether ypbind is up. If no, bag it if it's a * resource error, or if we are using a port we just got * from the port mapper. Otherwise loop around to try to * get a valid port. */ if (!check_binder_up(&ypbinder, &status)) { if (status == YPERR_RESRC) { return (status); } if (!oldport && status == YPERR_YPBIND) { return (status); } continue; } /* * At this point, we think we know how to talk to the * binder, and the binder is apparently alive. Until we * succeed in binding the domain, or we know we can't ever * bind the domain, we will try forever. This loops when * talk2_binder returns BS_RETRY, and terminates when * talk2_binder returns BS_BAGIT, or BS_OK. If binder_port * gets cleared, we will not execute this loop again, but * will go to the top of the enclosing loop to try to get * the binder's port again. It is never the case that both * talk2_binder returns BS_OK and that it clears the * binder_port. */ for (loopctl = BS_RETRY, tries = 1; binder_port && (loopctl != BS_OK); tries++) { switch (loopctl = talk2_binder(&ypbinder, &vers, tries, &pdomain, &ypbind_resp, &status) ) { case BS_BAGIT: return (status); case BS_OK: bound = TRUE; } if ((usertries>=0) && tries >=usertries) return (status); } } if ( (pdomb = load_dom_binding(&ypbind_resp, vers, domain, &status) ) == (struct dom_binding *) NULL) { return (status); } if (vers == YPBINDOLDVERS) { talk2_server(pdomb); } *binding = pdomb; /* Return ptr to the binding * entry */ return (0); /* This is the go path */}/* * This is a "wrapper" function for _yp_dobind_soft for vanilla user-level * functions which neither know nor care about struct dom_bindings. */intyp_bind(domain) char *domain;{ struct dom_binding *binding; return (_yp_dobind(domain, &binding) );}/* * This is a "wrapper" function for _yp_dobind_soft for vanilla user-level * functions which neither know nor care about struct dom_bindings. */intyp_softbind(domain,tries) char *domain; int tries;{ struct dom_binding *binding; return (_yp_dobind_soft(domain, &binding, tries) );}/* * Attempts to find a dom_binding in the list at bound_domains having the * domain name field equal to the passed domain name, and removes it if found. * The domain-server binding will not exist after the call to this function. * All resources associated with the binding will be freed. */voidyp_unbind (domain) char *domain;{_yp_unbind(domain, TRUE);}static void_yp_unbind (domain, invalidate) char *domain; bool_t invalidate; /*the binding file*/{ struct dom_binding *pdomb; struct dom_binding *ptrail = 0; struct sockaddr_in local_name; int local_name_len; if ( (domain == NULL) ||(strlen(domain) == 0) ) { return; } if (invalidate) bfinvalid = TRUE; /* Don't use binding file again */ for (pdomb = bound_domains; pdomb != NULL; ptrail = pdomb, pdomb = pdomb->dom_pnext) { if (strcmp(domain, pdomb->dom_domain) == 0) { /* * The act of destroying the rpc client closes * the associated socket. However, the fd * representing what we believe to be our socket may * really belong to someone else due to closes * followed by new opens. So let us be very careful! */ local_name_len = sizeof (local_name); if ((getsockname(pdomb->dom_socket, (struct sockaddr *) &local_name, &local_name_len) != 0) || (local_name.sin_family != AF_INET) || (local_name.sin_port != pdomb->dom_local_port) ) { int tmp, tobesaved; tmp = dup(tobesaved = pdomb->dom_socket); clnt_destroy(pdomb->dom_client); tobesaved = dup2(tmp, tobesaved); (void) close(tmp); } else { clnt_destroy(pdomb->dom_client); (void) close(pdomb->dom_socket); } if (pdomb == bound_domains) { bound_domains = pdomb->dom_pnext; } else { ptrail->dom_pnext = pdomb->dom_pnext; } free((char *) pdomb); break; } }}static char *_default_domain(){ char temp[256]; if (default_domain) return (default_domain); if (getdomainname(temp, sizeof(temp))) return (0); if (strlen(temp) > 0) { default_domain = (char *)malloc(strlen(temp)+1); if (default_domain == 0) return (0); strcpy(default_domain, temp); return (default_domain); } return (0);}/* * This is a wrapper for the system call getdomainname which returns a * ypclnt.h error code in the failure case. It also checks to see that * the domain name is non-null, knowing that the null string is going to * get rejected elsewhere in the NIS client package. */intyp_get_default_domain(domain) char **domain;{ if ((*domain = _default_domain()) != 0) return (0); return (YPERR_YPERR);}/* * This checks to see if this is a new process incarnation which has * inherited bindings from a parent, and unbinds the world if so. */static voidnewborn(){ static long int mypid; /* Cached to detect forks */ long int testpid; if ((testpid = getpid() ) != mypid) { mypid = testpid; while (bound_domains) { _yp_unbind(bound_domains->dom_domain, FALSE); /*do not unmap the file*/ } }}/* * This checks that the socket for a domain which has already been bound * hasn't been closed or changed under us. If it has, unbind the domain * without closing the socket, which may be in use by some higher level * code. This returns TRUE and points the binding parameter at the found * dom_binding if the binding is found and the socket looks OK, and FALSE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -