Home | History | Annotate | Download | only in gen
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * This module contains the subroutines used by the server to manipulate
     31  * objects and names.
     32  */
     33 #include "mt.h"
     34 #include <pwd.h>
     35 #include <grp.h>
     36 #include <syslog.h>
     37 #include <stdio.h>
     38 #include <string.h>
     39 #include <ctype.h>
     40 #include <stdlib.h>
     41 #include <unistd.h>
     42 #include <sys/time.h>
     43 #include <sys/fcntl.h>
     44 #include <netinet/in.h>
     45 #include <rpc/rpc.h>	/* Must be ahead of rpcb_clnt.h */
     46 #include <rpc/svc.h>
     47 #include <tiuser.h>
     48 #include <netconfig.h>
     49 #include <netdir.h>
     50 #include <rpc/rpcb_clnt.h>
     51 #include <rpc/pmap_clnt.h>
     52 #include <rpcsvc/nis.h>
     53 #include <rpcsvc/nis_dhext.h>
     54 #include "nis_clnt.h"
     55 #include <sys/systeminfo.h>
     56 #include "nis_local.h"
     57 #include <nsswitch.h>
     58 
     59 #define	MAXIPRINT	(11)	/* max length of printed integer */
     60 static char    *PKTABLE	  = "cred.org_dir";
     61 #define	PKTABLE_LEN	12
     62 /*
     63  * send and receive buffer size used for clnt_tli_create if not specified.
     64  * This is only used for "UDP" connection.
     65  * This limit can be changed from the application if this value is too
     66  * small for the application.  To use the maximum value for the transport,
     67  * set this value to 0.
     68  */
     69 int __nisipbufsize = 8192;
     70 
     71 /* Error result returned by nis_make_error() when malloc fails */
     72 const nis_result	__nomem_nis_result = {NIS_NOMEMORY, {0, 0}, {0, 0},
     73 						0, 0, 0, 0};
     74 
     75 extern int __readColdStartFile();
     76 
     77 /*
     78  * Static function prototypes.
     79  */
     80 static struct local_names *__get_local_names(void);
     81 static char *__map_addr(struct netconfig *, char *, rpcprog_t, rpcvers_t);
     82 
     83 CLIENT * nis_make_rpchandle_uaddr(nis_server *,
     84 		int, rpcprog_t, rpcvers_t, uint_t, int, int, char *);
     85 
     86 #define	COMMA	','	/* Avoid cstyle bug */
     87 
     88 /* __nis_data_directory is READ ONLY, so no locking is needed    */
     89 /* Note: We make it static, so external caller can not access it */
     90 /*	i.e we make sure it stay read only			*/
     91 static char	__nis_data_directory[1024] = {"/var/nis/"};
     92 
     93 /* These macros make the code easier to read */
     94 
     95 #ifdef NOTIME
     96 #define	__start_clock(n)
     97 #define	__stop_clock(n)		n
     98 #else
     99 static struct timeval clocks[MAXCLOCKS];
    100 
    101 #define	LOOP_UADDR "127.0.0.1.0.0"
    102 
    103 /*
    104  * __start_clock()
    105  *
    106  * This function will start the "stopwatch" on the function calls.
    107  * It uses an array of time vals to keep track of the time. The
    108  * sister call __stop_clock() will return the number of microseconds
    109  * since the clock was started. This allows for keeping statistics
    110  * on the NIS calls and tuning the service. If the clock in question
    111  * is not "stopped" this function returns an error.
    112  */
    113 int
    114 __start_clock(
    115 	int	clk)	/* The clock we want to start */
    116 {
    117 	if ((clk >= MAXCLOCKS) || (clk < 0) || (clocks[clk].tv_sec))
    118 		return (FALSE);
    119 
    120 	(void) gettimeofday(&clocks[clk], NULL);
    121 	return (TRUE);
    122 }
    123 
    124 uint32_t
    125 __stop_clock(int clk)
    126 {
    127 	struct timeval 		now;
    128 	uint32_t		secs, micros;
    129 
    130 	if ((clk >= MAXCLOCKS) || (clk < 0) || (!clocks[clk].tv_sec))
    131 		return (0);
    132 	(void) gettimeofday(&now, NULL);
    133 	secs = (int)(now.tv_sec - clocks[clk].tv_sec);
    134 	if (now.tv_usec < clocks[clk].tv_usec) {
    135 		micros = (int)((now.tv_usec + 1000000) - clocks[clk].tv_usec);
    136 		secs--; /* adjusted 'cuz we added a second above */
    137 	} else {
    138 		micros = (int)(now.tv_usec - clocks[clk].tv_usec);
    139 	}
    140 	micros = micros + (secs * 1000000); /* All micros now */
    141 	clocks[clk].tv_sec = 0; /* Stop the clock. */
    142 	return (micros);
    143 }
    144 #endif /* no time */
    145 
    146 /*
    147  * nis_dir_cmp() -- the results can be read as:
    148  * 	"Name 'n1' is a $result than name 'n2'"
    149  */
    150 name_pos
    151 nis_dir_cmp(
    152 	nis_name	n1,
    153 	nis_name	n2)	/* See if these are the same domain */
    154 {
    155 	size_t		l1, l2;
    156 	name_pos	result;
    157 
    158 	if ((n1 == NULL) || (n2 == NULL))
    159 		return (BAD_NAME);
    160 
    161 	l1 = strlen(n1);
    162 	l2 = strlen(n2);
    163 
    164 	/* In this routine we're lenient and don't require a trailing '.' */
    165 	/*   so we need to ignore it if it does appear.			  */
    166 	/* ==== That's what the previous version did so this one does	  */
    167 	/*   too, but why?  Is this inconsistent with rest of system?	  */
    168 	if (l1 != 0 && n1[l1 - 1] == '.') {
    169 		--l1;
    170 	}
    171 	if (l2 != 0 && n2[l2 - 1] == '.') {
    172 		--l2;
    173 	}
    174 
    175 	if (l1 > l2) {
    176 		result = LOWER_NAME;
    177 	} else if (l1 == l2) {
    178 		result = SAME_NAME;
    179 	} else /* (l1 < l2); swap l1/l2 and n1/n2 */ {
    180 		nis_name	ntmp;
    181 		size_t		ltmp;
    182 		ntmp = n1; n1 = n2; n2 = ntmp;
    183 		ltmp = l1; l1 = l2; l2 = ltmp;
    184 
    185 		result = HIGHER_NAME;
    186 	}
    187 
    188 	/* Now l1 >= l2 in all cases */
    189 	if (l2 == 0) {
    190 		/* Special case for n2 == "." or "" */
    191 		return (result);
    192 	}
    193 	if (l1 > l2) {
    194 		n1 += l1 - l2;
    195 		if (n1[-1] != '.') {
    196 			return (NOT_SEQUENTIAL);
    197 		}
    198 	}
    199 	if (strncasecmp(n1, n2, l2) == 0) {
    200 		return (result);
    201 	}
    202 	return (NOT_SEQUENTIAL);
    203 }
    204 
    205 #define	LN_BUFSIZE	(size_t)1024
    206 
    207 struct principal_list {
    208 	uid_t uid;
    209 	char principal[LN_BUFSIZE];
    210 	struct principal_list *next;
    211 };
    212 
    213 
    214 struct local_names {
    215 	char domain[LN_BUFSIZE];
    216 	char host[LN_BUFSIZE];
    217 	char *rpcdomain;
    218 	struct principal_list *principal_map;
    219 	char group[LN_BUFSIZE];
    220 };
    221 
    222 static mutex_t ln_lock = DEFAULTMUTEX; /* lock level 2 */
    223 static struct local_names *ln = NULL;
    224 static struct local_names *__get_local_names1();
    225 
    226 static struct local_names *
    227 __get_local_names(void)
    228 {
    229 	struct local_names *names;
    230 
    231 	sig_mutex_lock(&ln_lock);
    232 	names = __get_local_names1();
    233 	sig_mutex_unlock(&ln_lock);
    234 	return (names);
    235 }
    236 
    237 static char *
    238 get_nis_domain(void)
    239 {
    240 	directory_obj dobj;
    241 	enum __nsw_parse_err pserr;
    242 	struct __nsw_switchconfig *conf;
    243 	static int checked_domain = 0;
    244 	static char *nisdomain = 0;
    245 
    246 	if (!checked_domain) {
    247 		checked_domain = 1;
    248 		/*
    249 		 * Check that nisplus is first in nsswitch.conf for publickey.
    250 		 */
    251 		conf = __nsw_getconfig("publickey", &pserr);
    252 		if (conf == NULL)
    253 			return (NULL);
    254 		if (conf->num_lookups <= 0)
    255 			return (NULL);
    256 		if (strcasecmp(conf->lookups[0].service_name, "nisplus") != 0)
    257 			return (NULL);
    258 
    259 		/*
    260 		 * Read cold-start file to determine directory where
    261 		 * the machine's credentials are stored.
    262 		 */
    263 		if (!__readColdStartFile(&dobj))
    264 			return (NULL);
    265 		nisdomain = strdup(dobj.do_name);
    266 		xdr_free((xdrproc_t)xdr_directory_obj, (char *)&dobj);
    267 	}
    268 
    269 	return (nisdomain);
    270 }
    271 
    272 static struct local_names *
    273 __get_local_names1(void)
    274 {
    275 	char		*t;
    276 
    277 	if (ln != NULL) {
    278 		/* Second and subsequent calls go this way */
    279 		return (ln);
    280 	}
    281 	/* First call goes this way */
    282 	ln = calloc(1, sizeof (*ln));
    283 	if (ln == NULL) {
    284 		syslog(LOG_ERR, "__get_local_names: Out of heap.");
    285 		return (NULL);
    286 	}
    287 	ln->principal_map = NULL;
    288 
    289 	if (sysinfo(SI_SRPC_DOMAIN, ln->domain, LN_BUFSIZE) < 0)
    290 		return (ln);
    291 	/* If no dot exists, add one. */
    292 	if (ln->domain[strlen(ln->domain)-1] != '.')
    293 		(void) strcat(ln->domain, ".");
    294 	if (sysinfo(SI_HOSTNAME, ln->host, LN_BUFSIZE) < 0)
    295 		return (ln);
    296 
    297 	/*
    298 	 * Check for fully qualified hostname.  If it's a fully qualified
    299 	 * hostname, strip off the domain part.  We always use the local
    300 	 * domainname for the host principal name.
    301 	 */
    302 	t = strchr(ln->host, '.');
    303 	if (t)
    304 		*t = 0;
    305 	if (ln->domain[0] != '.')
    306 		(void) strcat(ln->host, ".");
    307 	if ((ln->rpcdomain = get_nis_domain()) != NULL) {
    308 		(void) strcat(ln->host, ln->rpcdomain);
    309 	} else {
    310 		ln->rpcdomain = strdup(ln->domain);
    311 		(void) strcat(ln->host, ln->domain);
    312 	}
    313 
    314 	t = getenv("NIS_GROUP");
    315 	if (t == NULL) {
    316 		ln->group[0] = '\0';
    317 	} else {
    318 		size_t maxlen = LN_BUFSIZE-1;	/* max chars to copy */
    319 		char *temp;			/* temp marker */
    320 
    321 		/*
    322 		 * Copy <= maximum characters from NIS_GROUP; strncpy()
    323 		 * doesn't terminate, so we do that manually. #1223323
    324 		 * Also check to see if it's "".  If it's the null string,
    325 		 * we return because we don't want to add ".domain".
    326 		 */
    327 		(void) strncpy(ln->group, t, maxlen);
    328 		if (strcmp(ln->group, "") == 0) {
    329 			return (ln);
    330 		}
    331 		ln->group[maxlen] = '\0';
    332 
    333 		/* Is the group name somewhat fully-qualified? */
    334 		temp = strrchr(ln->group, '.');
    335 
    336 		/* If not, we need to add ".domain" to the group */
    337 		if ((temp == NULL) || (temp[1] != '\0')) {
    338 
    339 			/* truncate to make room for ".domain" */
    340 			ln->group[maxlen - (strlen(ln->domain)+1)] = '\0';
    341 
    342 			/* concat '.' if domain doesn't already have it */
    343 			if (ln->domain[0] != '.') {
    344 				(void) strcat(ln->group, ".");
    345 			}
    346 			(void) strcat(ln->group, ln->domain);
    347 		}
    348 	}
    349 	return (ln);
    350 }
    351 
    352 /*
    353  * nis_local_group()
    354  *
    355  * Return's the group name of the current user.
    356  */
    357 nis_name
    358 nis_local_group(void)
    359 {
    360 	struct local_names	*ln = __get_local_names();
    361 
    362 	/* LOCK NOTE: Warning, after initialization, "ln" is expected	 */
    363 	/* to stay constant, So no need to lock here. If this assumption */
    364 	/* is changed, this code must be protected.			 */
    365 	if (!ln)
    366 		return (NULL);
    367 	return (ln->group);
    368 }
    369 
    370 /*
    371  * __nis_nextsep_of()
    372  *
    373  * This internal funtion will accept a pointer to a NIS name string and
    374  * return a pointer to the next separator occurring in it (it will point
    375  * just past the first label).  It allows for labels to be "quoted" to
    376  * prevent the the dot character within them to be interpreted as a
    377  * separator, also the quote character itself can be quoted by using
    378  * it twice.  If the the name contains only one label and no trailing
    379  * dot character, a pointer to the terminating NULL is returned.
    380  */
    381 nis_name
    382 __nis_nextsep_of(char *s)
    383 {
    384 	char	*d;
    385 	int	in_quotes = FALSE,
    386 		quote_quote = FALSE;
    387 
    388 	if (!s)
    389 		return (NULL);
    390 
    391 	for (d = s; (in_quotes && (*d != '\0')) ||
    392 	    (!in_quotes && (*d != '.') && (*d != '\0')); d++) {
    393 		if (quote_quote && in_quotes && (*d != '"')) {
    394 			quote_quote = FALSE;
    395 			in_quotes = FALSE;
    396 			if (*d == '.')
    397 				break;
    398 		} else if (quote_quote && in_quotes && (*d == '"')) {
    399 			quote_quote = FALSE;
    400 		} else if (quote_quote && (*d != '"')) {
    401 			quote_quote = FALSE;
    402 			in_quotes = TRUE;
    403 		} else if (quote_quote && (*d == '"')) {
    404 			quote_quote = FALSE;
    405 		} else if (in_quotes && (*d == '"')) {
    406 			quote_quote = TRUE;
    407 		} else if (!in_quotes && (*d == '"')) {
    408 			quote_quote = TRUE;
    409 		}
    410 	}
    411 
    412 	if (quote_quote || in_quotes) {
    413 		syslog(LOG_DEBUG, "__nis_nextsep_of: "
    414 		    "Mismatched quotes in %s", s);
    415 	}
    416 
    417 	return (d);
    418 }
    419 
    420 /*
    421  * nis_domain_of()
    422  *
    423  * This internal funtion will accept a pointer to a NIS name string and
    424  * return a pointer to the "domain" part of it.
    425  *
    426  * ==== We don't need nis_domain_of_r(), but should we provide one for
    427  *	uniformity?
    428  */
    429 nis_name
    430 nis_domain_of(char *s)
    431 {
    432 	char	*d;
    433 
    434 	d = __nis_nextsep_of(s);
    435 	if (d == NULL)
    436 		return (NULL);
    437 	if (*d == '.')
    438 		d++;
    439 	if (*d == '\0')	/* Don't return a zero length string */
    440 		return ("."); /* return root domain instead */
    441 	return (d);
    442 }
    443 
    444 
    445 /*
    446  * nis_leaf_of()
    447  *
    448  * Returns the first label of a name. (other half of __domain_of)
    449  */
    450 nis_name
    451 nis_leaf_of_r(
    452 	const nis_name	s,
    453 	char		*buf,
    454 	size_t		bufsize)
    455 {
    456 	size_t		nchars;
    457 	const char	*d = __nis_nextsep_of((char *)s);
    458 
    459 	if (d == 0) {
    460 		return (0);
    461 	}
    462 	nchars = d - s;
    463 	if (bufsize < nchars + 1) {
    464 		return (0);
    465 	}
    466 	(void) strncpy(buf, s, nchars);
    467 	buf[nchars] = '\0';
    468 	return (buf);
    469 }
    470 
    471 static pthread_key_t buf_key = PTHREAD_ONCE_KEY_NP;
    472 static char buf_main[LN_BUFSIZE];
    473 
    474 nis_name
    475 nis_leaf_of(char *s)
    476 {
    477 	char *buf = thr_main()? buf_main :
    478 		thr_get_storage(&buf_key, LN_BUFSIZE, free);
    479 
    480 	if (buf == NULL)
    481 		return (NULL);
    482 	return (nis_leaf_of_r(s, buf,  LN_BUFSIZE));
    483 }
    484 
    485 /*
    486  * nis_name_of()
    487  * This internal function will remove from the NIS name, the domain
    488  * name of the current server, this will leave the unique part in
    489  * the name this becomes the "internal" version of the name. If this
    490  * function returns NULL then the name we were given to resolve is
    491  * bad somehow.
    492  * NB: Uses static storage and this is a no-no with threads. XXX
    493  */
    494 
    495 nis_name
    496 nis_name_of_r(
    497 	char	*s,	/* string with the name in it. */
    498 	char		*buf,
    499 	size_t		bufsize)
    500 {
    501 	char			*d;
    502 	struct local_names 	*ln = __get_local_names();
    503 	size_t			dl, sl;
    504 	name_pos		p;
    505 
    506 #ifdef lint
    507 	bufsize = bufsize;
    508 #endif /* lint */
    509 	if ((!s) || (!ln))
    510 		return (NULL);		/* No string, this can't continue */
    511 
    512 	d  = &(ln->domain[0]);
    513 	dl = strlen(ln->domain); 	/* _always dot terminated_   */
    514 
    515 	sl = strlen(s);
    516 	if (sl >= bufsize || (s[sl-1] != '.' && sl >= bufsize-1))
    517 		return (NULL);
    518 	(void) strcpy(buf, s);		/* Make a private copy of 's'   */
    519 	if (buf[sl-1] != '.') {	/* Add a dot if necessary.  */
    520 		(void) strcat(buf, ".");
    521 		sl++;
    522 	}
    523 
    524 	if (dl == 1) {			/* We're the '.' directory   */
    525 		buf[sl-1] = '\0';	/* Lose the 'dot'	  */
    526 		return (buf);
    527 	}
    528 
    529 	p = nis_dir_cmp(buf, d);
    530 
    531 	/* 's' is above 'd' in the tree */
    532 	if ((p == HIGHER_NAME) || (p == NOT_SEQUENTIAL) || (p == SAME_NAME))
    533 		return (NULL);
    534 
    535 	/* Insert a NUL where the domain name starts in the string */
    536 	buf[(sl - dl) - 1] = '\0';
    537 
    538 	/* Don't return a zero length name */
    539 	if (buf[0] == '\0')
    540 		return (NULL);
    541 
    542 	return (buf);
    543 }
    544 
    545 nis_name
    546 nis_name_of(
    547 	char	*s)	/* string with the name in it. */
    548 {
    549 	char *buf = thr_main()? buf_main :
    550 		thr_get_storage(&buf_key, LN_BUFSIZE, free);
    551 
    552 	if (!buf)
    553 		return (NULL);
    554 	return (nis_name_of_r(s, buf,  LN_BUFSIZE));
    555 }
    556 
    557 
    558 
    559 /*
    560  * nis_local_directory()
    561  *
    562  * Return a pointer to a string with the local directory name in it.
    563  */
    564 nis_name
    565 nis_local_directory(void)
    566 {
    567 	struct local_names	*ln = __get_local_names();
    568 
    569 	/* LOCK NOTE: Warning, after initialization, "ln" is expected	 */
    570 	/* to stay constant, So no need to lock here. If this assumption */
    571 	/* is changed, this code must be protected.			 */
    572 	if (ln == NULL)
    573 		return (NULL);
    574 	return (ln->domain);
    575 }
    576 
    577 /*
    578  * __nis_rpc_domain()
    579  *
    580  * Return a pointer to a string with the rpc domain name in it.
    581  */
    582 nis_name
    583 __nis_rpc_domain()
    584 {
    585 	struct local_names	*ln = __get_local_names();
    586 
    587 	/* LOCK NOTE: Warning, after initialization, "ln" is expected	 */
    588 	/* to stay constant, So no need to lock here. If this assumption */
    589 	/* is changed, this code must be protected.			 */
    590 	if (ln == NULL)
    591 		return (NULL);
    592 	return (ln->rpcdomain);
    593 }
    594 
    595 /*
    596  * nis_getprincipal:
    597  *   Return the prinicipal name of the given uid in string supplied.
    598  *   Returns status obtained from nis+.
    599  *
    600  * Look up the LOCAL mapping in the local cred table. Note that if the
    601  * server calls this, then the version of nis_list that will
    602  * will be bound here is the 'safe' one in the server code.
    603  *
    604  * The USE_DGRAM + NO_AUTHINFO is required to prevent a
    605  * recursion through the getnetname() interface which is
    606  * called by authseccreate_pk and authdes_pk_create().
    607  *
    608  * NOTE that if you really want to get the nis+ principal name,
    609  * you should not use this call.  You should do something similar
    610  * but use an authenticated handle.
    611  */
    612 
    613 
    614 int
    615 __nis_principal(char *principal_name, uid_t uid, char *directory)
    616 {
    617 	nis_result	*res;
    618 	char		buf[NIS_MAXNAMELEN];
    619 	int		status;
    620 
    621 	if ((strlen(directory)+MAXIPRINT+PKTABLE_LEN+32) >
    622 		(size_t)NIS_MAXNAMELEN) {
    623 		return (NIS_BADNAME);
    624 	}
    625 
    626 	(void) snprintf(buf, sizeof (buf),
    627 		"[auth_name=%d,auth_type=LOCAL],%s.%s",
    628 		(int)uid, PKTABLE, directory);
    629 
    630 	if (buf[strlen(buf)-1] != '.')
    631 		(void) strcat(buf, ".");
    632 
    633 	res = nis_list(buf,
    634 			USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
    635 			NULL, NULL);
    636 	status = res->status;
    637 	if (status == NIS_SUCCESS || status == NIS_S_SUCCESS) {
    638 		if (res->objects.objects_len > 1) {
    639 			/*
    640 			 * More than one principal with same uid?
    641 			 * something wrong with cred table. Should be unique
    642 			 * Warn user and continue.
    643 			 */
    644 			syslog(LOG_ERR,
    645 		"nis_principal: LOCAL entry for %d in directory %s not unique",
    646 				uid, directory);
    647 		}
    648 		(void) strcpy(principal_name,
    649 			ENTRY_VAL(res->objects.objects_val, 0));
    650 	}
    651 	nis_freeresult(res);
    652 
    653 	return (status);
    654 }
    655 
    656 /*
    657  * nis_local_principal()
    658  * Generate the principal name for this user by looking it up its LOCAL
    659  * entry in the cred table of the local direectory.
    660  * Does not use an authenticated call (to prevent recursion because
    661  * this is called by user2netname).
    662  *
    663  * NOTE: the principal strings returned by nis_local_principal are
    664  * never changed and never freed, so there is no need to copy them.
    665  * Also note that nis_local_principal can return NULL.
    666  */
    667 nis_name
    668 nis_local_principal(void)
    669 {
    670 	struct local_names *ln = __get_local_names();
    671 	uid_t		uid;
    672 	int 		status;
    673 	char		*dirname;
    674 	static mutex_t local_principal_lock = DEFAULTMUTEX;
    675 	struct principal_list *p;
    676 
    677 	if (ln == NULL)
    678 		return (NULL);
    679 
    680 	sig_mutex_lock(&local_principal_lock);
    681 	uid = geteuid();
    682 	p = ln->principal_map;
    683 	while (p) {
    684 		if (p->uid == uid) {
    685 			ASSERT(*(p->principal) != 0);
    686 			sig_mutex_unlock(&local_principal_lock);
    687 			return (p->principal);
    688 		}
    689 		p = p->next;
    690 	}
    691 	if (uid == 0) {
    692 		sig_mutex_unlock(&local_principal_lock);
    693 		return (ln->host);
    694 	}
    695 	p = calloc(1, sizeof (*p));
    696 	if (p == NULL)
    697 		return (NULL);
    698 	if (!ln->principal_map) {
    699 		ln->principal_map = p;
    700 	}
    701 	dirname = nis_local_directory();
    702 	if ((dirname == NULL) || (dirname[0] == NULL)) {
    703 		(void) strcpy(p->principal, "nobody");
    704 		p->uid = uid;
    705 		sig_mutex_unlock(&local_principal_lock);
    706 		return (p->principal);
    707 	}
    708 	switch (status = __nis_principal(p->principal, uid, dirname)) {
    709 	case NIS_SUCCESS:
    710 	case NIS_S_SUCCESS:
    711 		break;
    712 	case NIS_NOTFOUND:
    713 	case NIS_PARTIAL:
    714 	case NIS_NOSUCHNAME:
    715 	case NIS_NOSUCHTABLE:
    716 		(void) strcpy(p->principal, "nobody");
    717 		break;
    718 	default:
    719 		/*
    720 		 * XXX We should return 'nobody', but
    721 		 * should we be remembering 'nobody' as our
    722 		 * principal name here?  Some errors might be
    723 		 * transient.
    724 		 */
    725 		syslog(LOG_ERR,
    726 			"nis_local_principal: %s",
    727 			nis_sperrno(status));
    728 		(void) strcpy(p->principal, "nobody");
    729 	}
    730 	p->uid = uid;
    731 	sig_mutex_unlock(&local_principal_lock);
    732 	return (p->principal);
    733 }
    734 
    735 /*
    736  * nis_local_host()
    737  * Generate the principal name for this host, "hostname"+"domainname"
    738  * unless the hostname already has "dots" in its name.
    739  */
    740 nis_name
    741 nis_local_host(void)
    742 {
    743 	struct local_names	*ln = __get_local_names();
    744 
    745 	/* LOCK NOTE: Warning, after initialization, "ln" is expected	 */
    746 	/* to stay constant, So no need to lock here. If this assumption */
    747 	/* is changed, this code must be protected.			 */
    748 	if (ln == NULL)
    749 		return (NULL);
    750 
    751 	return (ln->host);
    752 }
    753 
    754 /*
    755  * nis_destroy_object()
    756  * This function takes a pointer to a NIS object and deallocates it. This
    757  * is the inverse of __clone_object below. It must be able to correctly
    758  * deallocate partially allocated objects because __clone_object will call
    759  * it if it runs out of memory and has to abort. Everything is freed,
    760  * INCLUDING the pointer that is passed.
    761  */
    762 void
    763 nis_destroy_object(nis_object *obj)	/* The object to clone */
    764 {
    765 	if (obj == 0)
    766 		return;
    767 	xdr_free(xdr_nis_object, (char *)obj);
    768 	free(obj);
    769 } /* nis_destroy_object */
    770 
    771 static void
    772 destroy_nis_sdata(void *p)
    773 {
    774 	struct nis_sdata	*ns = p;
    775 
    776 	if (ns->buf != 0)
    777 		free(ns->buf);
    778 	free(ns);
    779 }
    780 
    781 /* XXX Why are these static ? */
    782 /* static XDR in_xdrs, out_xdrs; */
    783 
    784 
    785 /*
    786  * __clone_object_r()
    787  * This function takes a pointer to a NIS object and clones it. This
    788  * duplicate object is now available for use in the local context.
    789  */
    790 nis_object *
    791 nis_clone_object_r(
    792 	nis_object	*obj,	/* The object to clone */
    793 	nis_object	*dest,	/* Use this pointer if non-null */
    794 	struct nis_sdata *clone_buf_ptr)
    795 {
    796 	nis_object	*result; /* The clone itself */
    797 	int		status; /* a counter variable */
    798 	XDR		in_xdrs, out_xdrs;
    799 
    800 	if (!nis_get_static_storage(clone_buf_ptr, 1,
    801 					    xdr_sizeof(xdr_nis_object, obj)))
    802 		return (NULL);
    803 
    804 	(void) memset(&in_xdrs, 0, sizeof (in_xdrs));
    805 	(void) memset(&out_xdrs, 0, sizeof (out_xdrs));
    806 	xdrmem_create(&in_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size,
    807 			XDR_ENCODE);
    808 	xdrmem_create(&out_xdrs, clone_buf_ptr->buf, clone_buf_ptr->size,
    809 			XDR_DECODE);
    810 
    811 	/* Allocate a basic NIS object structure */
    812 	if (dest) {
    813 		(void) memset(dest, 0, sizeof (nis_object));
    814 		result = dest;
    815 	} else
    816 		result = calloc(1, sizeof (nis_object));
    817 
    818 	if (result == NULL)
    819 		return (NULL);
    820 
    821 	/* Encode our object into the clone buffer */
    822 	(void) xdr_setpos(&in_xdrs, 0);
    823 	status = xdr_nis_object(&in_xdrs, obj);
    824 	if (status == FALSE)
    825 		return (NULL);
    826 
    827 	/* Now decode the buffer into our result pointer ... */
    828 	(void) xdr_setpos(&out_xdrs, 0);
    829 	status = xdr_nis_object(&out_xdrs, result);
    830 	if (status == FALSE)
    831 		return (NULL);
    832 
    833 	/* presto changeo, a new object */
    834 	return (result);
    835 } /* __clone_object_r */
    836 
    837 
    838 nis_object *
    839 nis_clone_object(
    840 	nis_object	*obj,	/* The object to clone */
    841 	nis_object	*dest)	/* Use this pointer if non-null */
    842 {
    843 	static pthread_key_t clone_buf_key = PTHREAD_ONCE_KEY_NP;
    844 	static struct nis_sdata clone_buf_main;
    845 	struct nis_sdata *clone_buf_ptr;
    846 
    847 	clone_buf_ptr = thr_main()? &clone_buf_main :
    848 		thr_get_storage(&clone_buf_key, sizeof (struct nis_sdata),
    849 		    destroy_nis_sdata);
    850 	return (nis_clone_object_r(obj, dest, clone_buf_ptr));
    851 } /* __clone_object */
    852 
    853 
    854 /*
    855  * __break_name() converts a NIS name into it's components, returns an
    856  * array of char pointers pointing to the components and INVERTS there
    857  * order so that they are root first, then down. The list is terminated
    858  * with a null pointer. Returned memory can be freed by freeing the last
    859  * pointer in the list and the pointer returned.
    860  */
    861 char	**
    862 __break_name(
    863 	nis_name	name,
    864 	int		*levels)
    865 {
    866 	char	**pieces;	/* pointer to the pieces */
    867 	char	*s;		/* Temporary */
    868 	char	*data;		/* actual data and first piece pointer. */
    869 	int	components;	/* Number of estimated components */
    870 	size_t	namelen;	/* Length of the original name. */
    871 	int 	i;
    872 
    873 	/* First check to see that name is not NULL */
    874 	if (!name)
    875 		return (NULL);
    876 	if ((namelen = strlen(name)) == 0)
    877 		return (NULL);	/* Null string */
    878 
    879 	namelen = strlen(name);
    880 
    881 	data = strdup(name);
    882 	if (!data)
    883 		return (NULL);	/* No memory! */
    884 
    885 	/* Kill the optional trailing dot */
    886 	if (*(data+namelen-1) == '.') {
    887 		*(data+namelen-1) = '\0';
    888 		namelen--;
    889 	}
    890 	s = data;
    891 	components = 1;
    892 	while (*s != '\0') {
    893 		if (*s == '.') {
    894 			*s = '\0';
    895 			components++;
    896 			s++;
    897 		} else if (*s == '"') {
    898 			if (*(s+1) == '"') { /* escaped quote */
    899 				s += 2;
    900 			} else {
    901 				/* skip quoted string */
    902 				s++;
    903 				while ((*s != '"') && (*s != '\0'))
    904 					s++;
    905 				if (*s == '"') {
    906 					s++;
    907 				}
    908 			}
    909 		} else {
    910 			s++;
    911 		}
    912 	}
    913 	pieces = calloc(components+1, sizeof (char *));
    914 	if (!pieces) {
    915 		free(data);
    916 		return (NULL);
    917 	}
    918 
    919 	/* store in pieces in inverted order */
    920 	for (i = (components-1), s = data; i > -1; i--) {
    921 		*(pieces+i) = s;
    922 		while (*s != '\0')
    923 			s++;
    924 		s++;
    925 	}
    926 	*(pieces+components) = NULL;
    927 	*levels = components;
    928 
    929 	return (pieces);
    930 }
    931 
    932 void
    933 __free_break_name(char **components, int levels)
    934 {
    935 	free(components[levels-1]);
    936 	free(components);
    937 }
    938 
    939 int
    940 __name_distance(
    941 	char	**targ,	/* The target name */
    942 	char	**test) /* the test name */
    943 {
    944 	int	distance = 0;
    945 
    946 	/* Don't count common components */
    947 	while ((*targ && *test) && (strcasecmp(*targ, *test) == 0)) {
    948 		targ++;
    949 		test++;
    950 	}
    951 
    952 	/* count off the legs of each name */
    953 	while (*test != NULL) {
    954 		test++;
    955 		distance++;
    956 	}
    957 
    958 	while (*targ != NULL) {
    959 		targ++;
    960 		distance++;
    961 	}
    962 
    963 	return (distance);
    964 }
    965 
    966 int
    967 __dir_same(char **test, char **targ)
    968 {
    969 	/* skip common components */
    970 	while ((*targ && *test) && (strcasecmp(*targ, *test) == 0)) {
    971 		targ++;
    972 		test++;
    973 	}
    974 
    975 	return (*test == NULL && *targ == NULL);
    976 }
    977 
    978 void
    979 __broken_name_print(char **name, int levels)
    980 {
    981 	int i;
    982 
    983 	for (i = levels-1; i >= 0; --i)
    984 		(void) printf("%s.", name[i]);
    985 }
    986 
    987 
    988 /*
    989  * For returning errors in a NIS result structure
    990  */
    991 nis_result *
    992 nis_make_error(
    993 	nis_error	err,
    994 	uint32_t	aticks,	/* Profile information for client */
    995 	uint32_t	cticks,
    996 	uint32_t	dticks,
    997 	uint32_t	zticks)
    998 {
    999 	nis_result	*nres;
   1000 
   1001 	nres = malloc(sizeof (nis_result));
   1002 	if (!nres)
   1003 		return ((nis_result *)&__nomem_nis_result);
   1004 	(void) memset(nres, 0, sizeof (nis_result));
   1005 	nres->status = err;
   1006 	nres->aticks = aticks;
   1007 	nres->zticks = zticks;
   1008 	nres->dticks = dticks;
   1009 	nres->cticks = cticks;
   1010 	return (nres);
   1011 }
   1012 
   1013 #define	ZVAL zattr_val.zattr_val_val
   1014 #define	ZLEN zattr_val.zattr_val_len
   1015 
   1016 /*
   1017  * __cvt2attr()
   1018  *
   1019  * This function converts a search criteria of the form :
   1020  *	[ <key>=<value>, <key>=<value>, ... ]
   1021  * Into an array of nis_attr structures.
   1022  */
   1023 
   1024 nis_attr *
   1025 __cvt2attr(
   1026 	int	*na, 		/* Number of attributes 	*/
   1027 	char	**attrs) 	/* Strings associated with them */
   1028 
   1029 {
   1030 	int		i;
   1031 	nis_attr	*zattrs;
   1032 	char		*s;
   1033 
   1034 	zattrs = calloc(*na, sizeof (nis_attr));
   1035 	if (!zattrs)
   1036 		return (NULL);
   1037 
   1038 	for (i = 0; i < *na; i++) {
   1039 		zattrs[i].zattr_ndx = *(attrs+i);
   1040 		for (s = zattrs[i].zattr_ndx; *s != '\0'; s++) {
   1041 			if (*s == '=') {
   1042 				*s = '\0';
   1043 				s++;
   1044 				zattrs[i].ZVAL = s;
   1045 				zattrs[i].ZLEN = (uint_t)strlen(s) + 1;
   1046 				break;
   1047 			} else if (*s == '"') {
   1048 				/* advance s to matching quote */
   1049 				s++;
   1050 				while ((*s != '"') && (*s != '\0'))
   1051 					s++;
   1052 				if (*s == '\0') {
   1053 					/* unterminated quote */
   1054 					free(zattrs);
   1055 					return (NULL);
   1056 				}
   1057 			}
   1058 		}
   1059 		/*
   1060 		 * POLICY : Missing value for an index name is an
   1061 		 *	    error. The other alternative is the missing
   1062 		 *	    value means "is present" unfortunately there
   1063 		 *	    is no standard "is present" indicator in the
   1064 		 *	    existing databases.
   1065 		 * ANSWER : Always return an error.
   1066 		 */
   1067 		if (!zattrs[i].ZVAL) {
   1068 			free(zattrs);
   1069 			return (NULL);
   1070 		}
   1071 	}
   1072 	return (zattrs);
   1073 }
   1074 
   1075 /*
   1076  * nis_free_request()
   1077  *
   1078  * Free memory associated with a constructed list request.
   1079  */
   1080 void
   1081 nis_free_request(ib_request *req)
   1082 {
   1083 	if (req->ibr_srch.ibr_srch_len) {
   1084 		/* free the string memory */
   1085 		free(req->ibr_srch.ibr_srch_val[0].zattr_ndx);
   1086 		/* free the nis_attr array */
   1087 		free(req->ibr_srch.ibr_srch_val);
   1088 	}
   1089 
   1090 	if (req->ibr_name)
   1091 		free(req->ibr_name);
   1092 }
   1093 
   1094 /*
   1095  * nis_get_request()
   1096  *
   1097  * This function takes a NIS name, and converts it into an ib_request
   1098  * structure. The request can then be used in a call to the nis service
   1099  * functions. If the name wasn't parseable it returns an appropriate
   1100  * error. This function ends up allocating an array of nis_attr structures
   1101  * and a duplicate of the name string passed. To free this memory you
   1102  * can call nis_free_request(), or you can simply free the first nis_attr
   1103  * zattr_ndx pointer (the string memory) and the nis_attr pointer which
   1104  * is the array.
   1105  */
   1106 nis_error
   1107 nis_get_request(
   1108 	nis_name	name,		/* search criteria + Table name	*/
   1109 	nis_object	*obj,		/* Object for (rem/modify/add)	*/
   1110 	netobj		*cookie,	/* Pointer to a cookie		*/
   1111 	ib_request	*req)		/* Request structure to fill in */
   1112 {
   1113 	char	*s, *t; 		/* Some string pointer temps */
   1114 	char	*p;			/* temp var */
   1115 	char	**attr;			/* Intermediate attributes */
   1116 	int	i;			/* Counter variable */
   1117 	char		*data;		/* pointer to malloc'd string */
   1118 	int		zn = 0;		/* Count of attributes		*/
   1119 	size_t datalen;			/* length of malloc'd data	*/
   1120 	char		namebuf[NIS_MAXNAMELEN];
   1121 
   1122 	uchar_t		within_attr_val;
   1123 				/*
   1124 				 * a boolean to indicate the current parse
   1125 				 * location is within the attribute value
   1126 				 * - so that we can stop deleting white
   1127 				 * space within an attribute value
   1128 				 */
   1129 
   1130 	(void) memset(req, 0, sizeof (ib_request));
   1131 
   1132 	/*
   1133 	 * if we're passed an object but no name, use the name from
   1134 	 * the object instead.
   1135 	 */
   1136 	if (obj && !name) {
   1137 		if ((strlen(obj->zo_name)+strlen(obj->zo_domain)+2) >
   1138 			sizeof (namebuf)) {
   1139 			return (NIS_BADNAME);
   1140 		}
   1141 		(void) snprintf(namebuf, sizeof (namebuf),
   1142 					"%s.%s", obj->zo_name, obj->zo_domain);
   1143 		name = namebuf;
   1144 	}
   1145 	if (!name || (name[0] == '\0'))
   1146 		return (NIS_BADNAME);
   1147 
   1148 	s = name;
   1149 
   1150 	/* Move to the start of the components */
   1151 	while (isspace(*s))
   1152 		s++;
   1153 
   1154 	if (*s == '[') {
   1155 
   1156 		s++; /* Point past the opening bracket */
   1157 
   1158 		datalen = strlen(s);
   1159 		data = calloc(1, datalen+1);
   1160 		if (!data)
   1161 			return (NIS_NOMEMORY);
   1162 
   1163 		t = data; /* Point to the databuffer */
   1164 		while ((*s != '\0') && (*s != ']')) {
   1165 			while (isspace(*s)) {
   1166 				s++;
   1167 			}
   1168 			/* Check to see if we finished off the string */
   1169 			if ((*s == '\0') || (*s == ']'))
   1170 				break;
   1171 
   1172 			/* If *s == comma its a null criteria */
   1173 			if (*s == COMMA) {
   1174 				s++;
   1175 				continue;
   1176 			}
   1177 			/* Not a space and not a comma, process an attr */
   1178 			zn++;
   1179 			within_attr_val = 0; /* not within attr_val right now */
   1180 			while ((*s != COMMA) && (*s != ']') && (*s != '\0')) {
   1181 				if (*s == '"') {
   1182 					if (*(s+1) == '"') { /* escaped quote */
   1183 						*t++ = *s; /* copy one quote */
   1184 						s += 2;
   1185 					} else {
   1186 						/* skip quoted string */
   1187 						s++;
   1188 						while ((*s != '"') &&
   1189 							(*s != '\0'))
   1190 							*t++ = *s++;
   1191 						if (*s == '"') {
   1192 							s++;
   1193 						}
   1194 					}
   1195 				} else if (*s == '=') {
   1196 					*t++ = *s++;
   1197 					within_attr_val = 1;
   1198 				} else if (isspace(*s) && !within_attr_val) {
   1199 					s++;
   1200 				} else
   1201 					*t++ = *s++;
   1202 			}
   1203 			*t++ = '\0'; /* terminate the attribute */
   1204 			if (*s == COMMA)
   1205 				s++;
   1206 		}
   1207 		if (*s == '\0') {
   1208 			free(data);
   1209 			return (NIS_BADATTRIBUTE);
   1210 		}
   1211 
   1212 		/* It wasn't a '\0' so it must be the closing bracket. */
   1213 		s++;
   1214 		/* Skip any intervening white space and "comma" */
   1215 		while (isspace(*s) || (*s == COMMA)) {
   1216 			s++;
   1217 		}
   1218 		/* Copy the name into our malloc'd buffer */
   1219 		(void) strcpy(t, s);
   1220 
   1221 		/*
   1222 		 * If we found any attributes we process them, the
   1223 		 * data string at this point is completely nulled
   1224 		 * out except for attribute data. We recover this
   1225 		 * data by scanning the string (we know how long it
   1226 		 * is) and saving to each chunk of non-null data.
   1227 		 */
   1228 		if (zn) {
   1229 			/* Save this as the table name */
   1230 			req->ibr_name = strdup(t);
   1231 			attr = calloc(zn+1, sizeof (char *));
   1232 			if (!attr) {
   1233 				free(data);
   1234 				free(req->ibr_name);
   1235 				req->ibr_name = 0;
   1236 				return (NIS_NOMEMORY);
   1237 			}
   1238 
   1239 			/* store in pieces in attr array */
   1240 			for (i = 0, s = data; i < zn; i++) {
   1241 				*(attr+i) = s;
   1242 				/* Advance s past this component */
   1243 				while (*s != '\0')
   1244 					s++;
   1245 				s++;
   1246 			}
   1247 			*(attr+zn) = NULL;
   1248 		} else {
   1249 			free(data);
   1250 			req->ibr_name = strdup(s);
   1251 		}
   1252 	} else {
   1253 		/* Null search criteria */
   1254 		req->ibr_name = strdup(s);
   1255 		data = NULL;
   1256 	}
   1257 
   1258 	if (zn) {
   1259 		req->ibr_srch.ibr_srch_len = zn;
   1260 		req->ibr_srch.ibr_srch_val = __cvt2attr(&zn, attr);
   1261 		free(attr); /* don't need this any more */
   1262 		if (!(req->ibr_srch.ibr_srch_val)) {
   1263 			req->ibr_srch.ibr_srch_len = 0;
   1264 			free(req->ibr_name);
   1265 			req->ibr_name = 0;
   1266 			free(data);
   1267 			return (NIS_BADATTRIBUTE);
   1268 		}
   1269 	}
   1270 
   1271 	/* check for correct quotes in ibr_name (but leave them in) */
   1272 	for (p = req->ibr_name; *p; p++) {
   1273 		if (*p == '"') {
   1274 			/* advance p to the matching quote */
   1275 			p++;
   1276 			while (*p != '"' && *p != '\0') {
   1277 				p++;
   1278 			}
   1279 			if (*p == '\0') {
   1280 				req->ibr_srch.ibr_srch_len = 0;
   1281 				free(req->ibr_name);
   1282 				req->ibr_name = 0;
   1283 				free(data);
   1284 				return (NIS_BADNAME);
   1285 			}
   1286 		}
   1287 	}
   1288 
   1289 	if (obj) {
   1290 		req->ibr_obj.ibr_obj_len = 1;
   1291 		req->ibr_obj.ibr_obj_val = obj;
   1292 	}
   1293 	if (cookie) {
   1294 		req->ibr_cookie = *cookie;
   1295 	}
   1296 	return (NIS_SUCCESS);
   1297 }
   1298 
   1299 /* Various subroutines used by the server code */
   1300 nis_object *
   1301 nis_read_obj(char *f)	/* name of the object to read */
   1302 {
   1303 	FILE	*rootfile;
   1304 	int	status;	/* Status of the XDR decoding */
   1305 	XDR	xdrs;	/* An xdr stream handle */
   1306 	nis_object	*res;
   1307 
   1308 	res = calloc(1, sizeof (nis_object));
   1309 	if (!res)
   1310 		return (NULL);
   1311 
   1312 	rootfile = fopen(f, "rF");
   1313 	if (rootfile == NULL) {
   1314 		/* This is ok if we are the root of roots. */
   1315 		free(res);
   1316 		return (NULL);
   1317 	}
   1318 	/* Now read in the object */
   1319 	xdrstdio_create(&xdrs, rootfile, XDR_DECODE);
   1320 	status = xdr_nis_object(&xdrs, res);
   1321 	xdr_destroy(&xdrs);
   1322 	(void) fclose(rootfile);
   1323 	if (!status) {
   1324 		syslog(LOG_ERR, "Object file %s is corrupt!", f);
   1325 		xdr_free(xdr_nis_object, (char *)res);
   1326 		free(res);
   1327 		return (NULL);
   1328 	}
   1329 	return (res);
   1330 }
   1331 
   1332 int
   1333 nis_write_obj(
   1334 	char	*f,	/* name of the object to read */
   1335 	nis_object *o)	/* The object to write */
   1336 {
   1337 	FILE	*rootfile;
   1338 	int	status;	/* Status of the XDR decoding */
   1339 	XDR	xdrs;	/* An xdr stream handle */
   1340 
   1341 	rootfile = fopen(f, "wF");
   1342 	if (rootfile == NULL) {
   1343 		return (0);
   1344 	}
   1345 	/* Now encode the object */
   1346 	xdrstdio_create(&xdrs, rootfile, XDR_ENCODE);
   1347 	status = xdr_nis_object(&xdrs, o);
   1348 	xdr_destroy(&xdrs);
   1349 	(void) fclose(rootfile);
   1350 	return (status);
   1351 }
   1352 
   1353 /*
   1354  * nis_make_rpchandle()
   1355  *
   1356  * This is a generic version of clnt_creat() for NIS. It localizes
   1357  * _all_ of the changes needed to port to TLI RPC into this one
   1358  * section of code.
   1359  */
   1360 
   1361 /*
   1362  * Transport INDEPENDENT RPC code. This code assumes you
   1363  * are using the new RPC/tli code and will build
   1364  * a ping handle on top of a datagram transport.
   1365  */
   1366 
   1367 /*
   1368  * __map_addr()
   1369  *
   1370  * This is our internal function that replaces rpcb_getaddr(). We
   1371  * build our own to prevent calling netdir_getbyname() which could
   1372  * recurse to the nameservice.
   1373  */
   1374 static char *
   1375 __map_addr(
   1376 	struct netconfig	*nc,		/* Our transport	*/
   1377 	char			*uaddr,		/* RPCBIND address */
   1378 	rpcprog_t		prog,		/* Name service Prog */
   1379 	rpcvers_t		ver)
   1380 {
   1381 	CLIENT *client;
   1382 	RPCB 		parms;		/* Parameters for RPC binder	  */
   1383 	enum clnt_stat	clnt_st;	/* Result from the rpc call	  */
   1384 	char 		*ua = NULL;	/* Universal address of service	  */
   1385 	char		*res = NULL;	/* Our result to the parent	  */
   1386 	struct timeval	tv;		/* Timeout for our rpcb call	  */
   1387 	int		ilen, olen;	/* buffer length for clnt_tli_create */
   1388 
   1389 	/*
   1390 	 * If using "udp", use __nisipbufsize if inbuf and outbuf are set to 0.
   1391 	 */
   1392 	if (strcmp(NC_UDP, nc->nc_proto) == 0) {
   1393 			/* for udp only */
   1394 		ilen = olen = __nisipbufsize;
   1395 	} else {
   1396 		ilen = olen = 0;
   1397 	}
   1398 	client = __nis_clnt_create(RPC_ANYFD, nc, uaddr, 0, 0,
   1399 					RPCBPROG, RPCBVERS, ilen, olen);
   1400 	if (!client)
   1401 		return (NULL);
   1402 
   1403 	(void) clnt_control(client, CLSET_FD_CLOSE, NULL);
   1404 
   1405 	/*
   1406 	 * Now make the call to get the NIS service address.
   1407 	 * We set the retry timeout to 3 seconds so that we
   1408 	 * will retry a few times.  Retries should be rare
   1409 	 * because we are usually only called when we know
   1410 	 * a server is available.
   1411 	 */
   1412 	tv.tv_sec = 3;
   1413 	tv.tv_usec = 0;
   1414 	(void) clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&tv);
   1415 
   1416 	tv.tv_sec = 10;
   1417 	tv.tv_usec = 0;
   1418 	parms.r_prog = prog;
   1419 	parms.r_vers = ver;
   1420 	parms.r_netid = nc->nc_netid;	/* not needed */
   1421 	parms.r_addr = "";	/* not needed; just for xdring */
   1422 	parms.r_owner = "";	/* not needed; just for xdring */
   1423 	clnt_st = clnt_call(client, RPCBPROC_GETADDR, xdr_rpcb, (char *)&parms,
   1424 					    xdr_wrapstring, (char *)&ua, tv);
   1425 
   1426 	if (clnt_st == RPC_SUCCESS) {
   1427 		clnt_destroy(client);
   1428 		if (*ua == '\0') {
   1429 			free(ua);
   1430 			return (NULL);
   1431 		}
   1432 		res = strdup(ua);
   1433 		xdr_free(xdr_wrapstring, (char *)&ua);
   1434 		return (res);
   1435 	} else if (((clnt_st == RPC_PROGVERSMISMATCH) ||
   1436 			(clnt_st == RPC_PROGUNAVAIL)) &&
   1437 			(strcmp(nc->nc_protofmly, NC_INET) == 0)) {
   1438 		/*
   1439 		 * version 3 not available. Try version 2
   1440 		 * The assumption here is that the netbuf
   1441 		 * is arranged in the sockaddr_in
   1442 		 * style for IP cases.
   1443 		 *
   1444 		 * Note:	If the remote host doesn't support version 3,
   1445 		 *		we assume it doesn't know IPv6 either.
   1446 		 */
   1447 		ushort_t 		port;
   1448 		struct sockaddr_in	*sa;
   1449 		struct netbuf 		remote;
   1450 		int			protocol;
   1451 		char			buf[32];
   1452 
   1453 		(void) clnt_control(client, CLGET_SVC_ADDR, (char *)&remote);
   1454 		/* LINTED pointer cast */
   1455 		sa = (struct sockaddr_in *)(remote.buf);
   1456 		protocol = strcmp(nc->nc_proto, NC_TCP) ?
   1457 				IPPROTO_UDP : IPPROTO_TCP;
   1458 		port = (ushort_t)pmap_getport(sa, prog, ver, protocol);
   1459 
   1460 		if (port != 0) {
   1461 			port = htons(port);
   1462 			(void) sprintf(buf, "%d.%d.%d.%d.%d.%d",
   1463 				(sa->sin_addr.s_addr >> 24) & 0xff,
   1464 				(sa->sin_addr.s_addr >> 16) & 0xff,
   1465 				(sa->sin_addr.s_addr >>  8) & 0xff,
   1466 				(sa->sin_addr.s_addr) & 0xff,
   1467 				(port >> 8) & 0xff,
   1468 				port & 0xff);
   1469 			res = strdup(buf);
   1470 		} else
   1471 			res = NULL;
   1472 		clnt_destroy(client);
   1473 		return (res);
   1474 	}
   1475 	if (clnt_st == RPC_TIMEDOUT)
   1476 		syslog(LOG_ERR, "NIS+ server not responding");
   1477 	else
   1478 		syslog(LOG_ERR, "NIS+ server could not be contacted: %s",
   1479 					clnt_sperrno(clnt_st));
   1480 	clnt_destroy(client);
   1481 	return (NULL);
   1482 }
   1483 
   1484 char *
   1485 __nis_get_server_address(struct netconfig *nc, endpoint *ep)
   1486 {
   1487 	return (__map_addr(nc, ep->uaddr, NIS_PROG, NIS_VERSION));
   1488 }
   1489 
   1490 #define	MAX_EP (20)
   1491 
   1492 int
   1493 __nis_get_callback_addresses(endpoint *ep, endpoint **ret_eps)
   1494 {
   1495 	int i;
   1496 	int n;
   1497 	int st;
   1498 	int nep = 0;
   1499 	endpoint *eps;
   1500 	struct nd_hostserv hs;
   1501 	struct nd_addrlist *addrs;
   1502 	struct nd_mergearg ma;
   1503 	void *lh;
   1504 	void *nch;
   1505 	struct netconfig *nc;
   1506 
   1507 	eps = malloc(MAX_EP * sizeof (endpoint));
   1508 	if (eps == 0)
   1509 		return (0);
   1510 
   1511 	hs.h_host = HOST_SELF;
   1512 	hs.h_serv = "rpcbind";	/* as good as any */
   1513 
   1514 	lh = __inet_get_local_interfaces();
   1515 
   1516 	nch = setnetconfig();
   1517 	while ((nc = getnetconfig(nch)) != NULL) {
   1518 		if (strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
   1519 			continue;
   1520 		if (nc->nc_semantics != NC_TPI_COTS &&
   1521 		    nc->nc_semantics != NC_TPI_COTS_ORD)
   1522 			continue;
   1523 		st = netdir_getbyname(nc, &hs, &addrs);
   1524 		if (st != 0)
   1525 			continue;
   1526 
   1527 		/*
   1528 		 *  The netdir_merge code does not work very well
   1529 		 *  for inet if the client and server are not
   1530 		 *  on the same network.  Instead, we try each local
   1531 		 *  address.
   1532 		 *
   1533 		 *  For other protocol families and for servers on a
   1534 		 *  local network, we use the regular merge code.
   1535 		 */
   1536 
   1537 		if (strcmp(nc->nc_protofmly, NC_INET) == 0 &&
   1538 		    !__inet_uaddr_is_local(lh, nc, ep->uaddr)) {
   1539 			n = __inet_address_count(lh);
   1540 			for (i = 0; i < n; i++) {
   1541 				if (nep >= MAX_EP) {
   1542 					syslog(LOG_INFO,
   1543 		"__nis_get_callback_addresses: too many endpoints");
   1544 					goto full;
   1545 				}
   1546 				eps[nep].uaddr = __inet_get_uaddr(lh, nc, i);
   1547 				if (eps[nep].uaddr == 0)
   1548 					continue;
   1549 				if (strcmp(eps[nep].uaddr, LOOP_UADDR) == 0) {
   1550 					free(eps[nep].uaddr);
   1551 					continue;
   1552 				}
   1553 				__nis_netconfig2ep(nc, &(eps[nep]));
   1554 				nep++;
   1555 			}
   1556 		} else {
   1557 			ma.s_uaddr = ep->uaddr;
   1558 			ma.c_uaddr = taddr2uaddr(nc, addrs->n_addrs);
   1559 			ma.m_uaddr = 0;
   1560 			(void) netdir_options(nc, ND_MERGEADDR, 0, (void *)&ma);
   1561 			free(ma.s_uaddr);
   1562 			free(ma.c_uaddr);
   1563 
   1564 			if (nep >= MAX_EP) {
   1565 					syslog(LOG_INFO,
   1566 		"__nis_get_callback_addresses: too many endpoints");
   1567 				goto full;
   1568 			}
   1569 			eps[nep].uaddr = ma.m_uaddr;
   1570 			__nis_netconfig2ep(nc, &(eps[nep]));
   1571 			nep++;
   1572 		}
   1573 		netdir_free((void *)addrs, ND_ADDRLIST);
   1574 	}
   1575 
   1576 full:
   1577 	(void) endnetconfig(nch);
   1578 	__inet_free_local_interfaces(lh);
   1579 
   1580 	*ret_eps = eps;
   1581 	return (nep);
   1582 }
   1583 
   1584 /*
   1585  * Try to create a RPC GSS security context (flavor RPCSEC_GSS).
   1586  * Returns auth handle on success, else NULL.  Set flag 'try_auth_des'
   1587  * to TRUE if the AUTH_DES compat line is found in the security conf file
   1588  * or no valid mech entries are found in the conf file.
   1589  */
   1590 static AUTH *
   1591 create_rpcgss_secctx(
   1592 	CLIENT		*clnt,		/* out */
   1593 	nis_server	*srv,
   1594 	char 		*gss_svc,
   1595 	bool_t		*try_auth_des)	/* out */
   1596 {
   1597 	mechanism_t		**mechs;	/* list of mechanisms	*/
   1598 
   1599 	*try_auth_des = FALSE;
   1600 	if (mechs = __nis_get_mechanisms(TRUE)) {
   1601 		mechanism_t **mpp;
   1602 		char svc_name[NIS_MAXNAMELEN+1] = {0};
   1603 
   1604 		/* Check RPC GSS service name buf size. */
   1605 		if ((strlen(gss_svc ? gss_svc : NIS_SVCNAME_NISD) + 1
   1606 			+ strlen(srv->name) + 1) > sizeof (svc_name)) {
   1607 			syslog(LOG_ERR,
   1608 		"nis_make_rpchandle_gss_svc: RPC GSS service name too long");
   1609 			__nis_release_mechanisms(mechs);
   1610 			return (NULL);
   1611 		}
   1612 
   1613 		/* RPC GSS service names are of the form svc (at) host.dom */
   1614 		(void) snprintf(svc_name, sizeof (svc_name),
   1615 				"%s@%s", gss_svc ? gss_svc : NIS_SVCNAME_NISD,
   1616 				srv->name);
   1617 
   1618 		/*
   1619 		 * Loop thru all the available mech entries until an
   1620 		 * RPC GSS security context is established or until
   1621 		 * the AUTH_DES compat entry is found.
   1622 		 */
   1623 		for (mpp = mechs; *mpp; mpp++) {
   1624 			mechanism_t *mp = *mpp;
   1625 
   1626 			if (AUTH_DES_COMPAT_CHK(mp)) {
   1627 				__nis_release_mechanisms(mechs);
   1628 				*try_auth_des = TRUE;
   1629 				return (NULL);
   1630 			}
   1631 
   1632 			if (!VALID_MECH_ENTRY(mp)) {
   1633 				syslog(LOG_ERR,
   1634 					"%s: invalid mechanism entry name '%s'",
   1635 					NIS_SEC_CF_PATHNAME,
   1636 					mp->mechname ? mp->mechname : "NULL");
   1637 				continue;
   1638 			}
   1639 
   1640 			/*
   1641 			 * If the mechanism is of the public key crypto
   1642 			 * technology variety, let's make sure the server's
   1643 			 * public key exists and the clients secret key is set
   1644 			 * before going thru the expense of a RPC GSS security
   1645 			 * context creation attempt.
   1646 			 */
   1647 			if (MECH_PK_TECH(mp) &&
   1648 				((srv->key_type == NIS_PK_DHEXT &&
   1649 					!__nis_dhext_extract_pkey(&(srv->pkey),
   1650 					mp->keylen,  mp->algtype)) ||
   1651 					!key_secretkey_is_set_g(mp->keylen,
   1652 							mp->algtype))) {
   1653 #ifdef DHEXT_DEBUG
   1654 					(void) fprintf(stderr,
   1655 "nis_make_rpchandle_gss_svc: srv keytype = %d: No keys, skip mech '%s' ...\n",
   1656 							srv->key_type,
   1657 							mp->alias);
   1658 #endif
   1659 					continue;
   1660 			}
   1661 
   1662 			clnt->cl_auth = rpc_gss_seccreate(clnt, svc_name,
   1663 						mp->mechname, mp->secserv,
   1664 						mp->qop, NULL, NULL);
   1665 			if (clnt->cl_auth) {
   1666 				__nis_release_mechanisms(mechs);
   1667 				return (clnt->cl_auth); /* we're in bizness */
   1668 #ifdef DHEXT_DEBUG
   1669 			} else {
   1670 				rpc_gss_error_t	err;
   1671 
   1672 				rpc_gss_get_error(&err);
   1673 				(void) fprintf(stderr,
   1674 "nis_make_rpchandle_gss_svc: RPCGSS_SecCreat fail: gerr = %d serr = %d\n",
   1675 					err.rpc_gss_error, err.system_error);
   1676 #endif /* DHEXT_DEBUG */
   1677 			}
   1678 		}
   1679 		__nis_release_mechanisms(mechs);
   1680 	} else {
   1681 		/* no valid mechs, fallback to AUTH_DES */
   1682 		*try_auth_des = TRUE;
   1683 	}
   1684 
   1685 	return (NULL);
   1686 }
   1687 
   1688 
   1689 CLIENT *
   1690 nis_make_rpchandle(
   1691 	nis_server	*srv,	/* NIS Server description 		*/
   1692 	int		cback,	/* Boolean indicating callback address	*/
   1693 	rpcprog_t	prog,	/* Program number			*/
   1694 	rpcvers_t	ver,	/* Version				*/
   1695 	uint_t		flags,	/* Flags, {VC, DG, AUTH}  		*/
   1696 	int		inbuf,	/* Preferred buffer sizes 		*/
   1697 	int		outbuf)	/* for input and output   		*/
   1698 {
   1699 	return (nis_make_rpchandle_uaddr(srv, cback, prog, ver, flags,
   1700 			inbuf, outbuf, 0));
   1701 }
   1702 
   1703 CLIENT *
   1704 nis_make_rpchandle_uaddr(
   1705 	nis_server	*srv,	/* NIS Server description 		*/
   1706 	int		cback,	/* Boolean indicating callback address	*/
   1707 	rpcprog_t	prog,	/* Program number			*/
   1708 	rpcvers_t	ver,	/* Version				*/
   1709 	uint_t		flags,	/* Flags, {VC, DG, AUTH}  		*/
   1710 	int		inbuf,	/* Preferred buffer sizes 		*/
   1711 	int		outbuf,	/* for input and output   		*/
   1712 	char		*uaddr)	/* optional address of server		*/
   1713 {
   1714 	return (nis_make_rpchandle_gss_svc(srv, cback, prog, ver, flags,
   1715 			inbuf, outbuf, uaddr, NULL));
   1716 }
   1717 
   1718 extern int __can_use_af(sa_family_t af);
   1719 
   1720 CLIENT *
   1721 __nis_clnt_create(int fd, struct netconfig *nc, char *uaddr,
   1722 			struct netbuf *addr, int domapaddr,
   1723 			int prog, int ver, int inbuf, int outbuf) {
   1724 
   1725 	char		*svc_addr;
   1726 	CLIENT		*clnt;
   1727 	int		freeaddr = 0;
   1728 
   1729 	/* Sanity check */
   1730 	if (nc == 0 || (addr == 0 && uaddr == 0)) {
   1731 		return (0);
   1732 	}
   1733 
   1734 	/*
   1735 	 * Check if we have a useable interface for this address family.
   1736 	 * This check properly belongs in RPC (or even further down),
   1737 	 * but until they provide it, we roll our own.
   1738 	 */
   1739 	if (__can_use_af((strcmp(nc->nc_protofmly, NC_INET6) == 0) ?
   1740 			AF_INET6 : AF_INET) == 0) {
   1741 		return (0);
   1742 	}
   1743 
   1744 	if (domapaddr) {
   1745 		svc_addr = __map_addr(nc, uaddr, prog, ver);
   1746 		if (svc_addr == 0)
   1747 			return (0);
   1748 		addr = uaddr2taddr(nc, svc_addr);
   1749 		freeaddr = 1;
   1750 		free(svc_addr);
   1751 	} else if (addr == 0) {
   1752 		addr = uaddr2taddr(nc, uaddr);
   1753 		freeaddr = 1;
   1754 	}
   1755 
   1756 	if (addr == 0) {
   1757 		return (0);
   1758 	}
   1759 
   1760 	clnt = clnt_tli_create(fd, nc, addr, prog, ver, outbuf, inbuf);
   1761 
   1762 	if (clnt) {
   1763 		if (clnt_control(clnt, CLGET_FD, (char *)&fd))
   1764 			/* make it "close on exec" */
   1765 			(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
   1766 		(void) clnt_control(clnt, CLSET_FD_CLOSE, NULL);
   1767 	}
   1768 
   1769 	if (freeaddr)
   1770 		netdir_free(addr, ND_ADDR);
   1771 
   1772 	return (clnt);
   1773 }
   1774 
   1775 
   1776 typedef struct {
   1777 	endpoint		*ep;
   1778 	struct netconfig	*nc;
   1779 } alt_ep_t;
   1780 
   1781 /*
   1782  * Construct an rpc handle.
   1783  *
   1784  * If the gss_svc arg is NULL, then default to "nisd" (rpc.nisd).
   1785  */
   1786 static CLIENT *
   1787 nis_make_rpchandle_gss_svc_ext(
   1788 	nis_server	*srv,	  /* NIS Server description 		*/
   1789 	int		cback,	  /* Boolean indicating callback address */
   1790 	rpcprog_t	prog,	  /* Program number			*/
   1791 	rpcvers_t	ver,	  /* Version				*/
   1792 	uint_t		flags,	  /* Flags, {VC, DG, AUTH}  		*/
   1793 	int		inbuf,	  /* Preferred buffer sizes 		*/
   1794 	int		outbuf,	  /* for input and output   		*/
   1795 	char		*uaddr,	  /* optional address of server		*/
   1796 	char		*gss_svc, /* RPC GSS service name		*/
   1797 	int		use_realid) /* 1: Use REAL id, 0: use Eff. ids	*/
   1798 {
   1799 	CLIENT			*clnt = 0;	/* Client handle 	*/
   1800 	void			*nc_handle;	/* Netconfig "state"	*/
   1801 	struct netconfig	*nc;		/* Various handles	*/
   1802 	endpoint		*ep;		/* useful endpoints	*/
   1803 	int			epl, i;		/* counters		*/
   1804 	int			uid, gid;	/* Effective uid/gid	*/
   1805 	char			netname[MAXNETNAMELEN+1]; /* our netname */
   1806 	char			*hexkey = NULL; /* hex public key for DHEXT */
   1807 	netobj			xpkey = { NULL, 0};
   1808 	bool_t			try_auth_des;
   1809 	alt_ep_t		*altep = 0;
   1810 
   1811 
   1812 	nc_handle = (void *) setnetconfig();
   1813 	if (!nc_handle)
   1814 		return (NULL);
   1815 
   1816 	ep = srv->ep.ep_val;
   1817 	epl = srv->ep.ep_len;
   1818 
   1819 	if (uaddr) {
   1820 
   1821 		char	*fmly = (strchr(uaddr, ':') == 0) ? NC_INET : NC_INET6;
   1822 
   1823 		while ((nc = getnetconfig(nc_handle)) != NULL) {
   1824 			/* Is it a visible transport ? */
   1825 			if ((nc->nc_flag & NC_VISIBLE) == 0)
   1826 				continue;
   1827 			/* Does the protocol family match the uaddr ? */
   1828 			if (strcmp(nc->nc_protofmly, fmly) != 0)
   1829 				continue;
   1830 			for (i = 0; i < epl; i++) {
   1831 				if (__nis_netconfig_matches_ep(nc, &ep[i])) {
   1832 					break;
   1833 				}
   1834 			}
   1835 			/* Did we find a matching endpoint ? */
   1836 			if (i < epl)
   1837 				break;
   1838 		}
   1839 		if (nc == 0) {
   1840 			syslog(LOG_ERR,
   1841 	"nis_make_rpchandle: can't find netconfig entry for %s, %s",
   1842 				uaddr, fmly);
   1843 			return (0);
   1844 		}
   1845 
   1846 		clnt = __nis_clnt_create(RPC_ANYFD, nc, uaddr, 0, 0, prog, ver,
   1847 					inbuf, outbuf);
   1848 
   1849 	} else {
   1850 
   1851 		altep = calloc(epl, sizeof (*altep));
   1852 
   1853 		/*
   1854 		 * The transport policies :
   1855 		 * Selected transport must be visible.
   1856 		 * Must have requested or better semantics.
   1857 		 * Must be correct protocol.
   1858 		 */
   1859 		while ((nc = getnetconfig(nc_handle)) != 0) {
   1860 
   1861 			/* Is it a visible transport ? */
   1862 			if ((nc->nc_flag & NC_VISIBLE) == 0)
   1863 				continue;
   1864 
   1865 			/* If we asked for a virtual circuit, is it ? */
   1866 			if (((flags & ZMH_VC) != 0) &&
   1867 			    (nc->nc_semantics != NC_TPI_COTS) &&
   1868 			    (nc->nc_semantics != NC_TPI_COTS_ORD))
   1869 				continue;
   1870 
   1871 			/* Check to see is we talk this protofmly, protocol */
   1872 			for (i = 0; i < epl; i++) {
   1873 				if (__nis_netconfig_matches_ep(nc, &(ep[i])))
   1874 					break;
   1875 			}
   1876 
   1877 			/* Was it one of our transports ? */
   1878 			if (i == epl)
   1879 				continue;	/* No */
   1880 
   1881 			/*
   1882 			 * If it is one of our supported transports, but isn't
   1883 			 * a datagram and we want a datagram, keep looking but
   1884 			 * remember this one as a possibility.
   1885 			 */
   1886 			if (((flags & ZMH_DG) != 0) &&
   1887 				(nc->nc_semantics != NC_TPI_CLTS) &&
   1888 					altep != 0) {
   1889 				altep[i].nc = nc;
   1890 				altep[i].ep = &ep[i]; /* This endpoint */
   1891 				continue;
   1892 			}
   1893 
   1894 			/* We've got a candidate; see if it works */
   1895 			clnt = __nis_clnt_create(RPC_ANYFD, nc, ep[i].uaddr, 0,
   1896 						(cback == 0), prog, ver, inbuf,
   1897 						outbuf);
   1898 
   1899 			if (clnt != 0)
   1900 				break;
   1901 		}
   1902 
   1903 		if (altep != 0 && (!(flags & ZMH_NOFALLBACK))) {
   1904 			/* If primary choices failed, try the alternates */
   1905 			for (i = 0; clnt == 0 && i < epl; i++) {
   1906 				if (altep[i].ep == 0)
   1907 					continue;
   1908 				clnt = __nis_clnt_create(RPC_ANYFD,
   1909 					altep[i].nc, altep[i].ep->uaddr, 0,
   1910 					(cback == 0), prog, ver, inbuf,
   1911 					outbuf);
   1912 			}
   1913 			free(altep);
   1914 		}
   1915 
   1916 	}
   1917 
   1918 	/* Done with the netconfig handle regardless */
   1919 	(void) endnetconfig(nc_handle);
   1920 
   1921 	/* If we still don't have a client handle, we're sunk */
   1922 	if (clnt == 0) {
   1923 		return (0);
   1924 	}
   1925 
   1926 	/*
   1927 	 * No auth requested or it's a callback (which is not authenticated),
   1928 	 * so we're done.
   1929 	 */
   1930 	if (!(flags & ZMH_AUTH) || cback)
   1931 		return (clnt);
   1932 
   1933 	/*
   1934 	 * Setup authentication.  Try the RPCSEC_GSS flavor first, then
   1935 	 * fallback to AUTH_DES (if requested) and, if need be, AUTH_SYS.
   1936 	 */
   1937 	if (create_rpcgss_secctx(clnt, srv, gss_svc, &try_auth_des))
   1938 		return (clnt);
   1939 
   1940 	if (!try_auth_des)
   1941 		/* XXXX what's the meaning of going into a switch stmt??? */
   1942 		goto auth_sys;
   1943 
   1944 	switch (srv->key_type) {
   1945 	case NIS_PK_DHEXT :
   1946 		/*
   1947 		 * We're doing AUTH_DES, but the server might
   1948 		 * have multiple keys so let's get the 192-0 one.
   1949 		 */
   1950 		if ((hexkey = __nis_dhext_extract_pkey(&(srv->pkey),
   1951 							192, 0)) == NULL)
   1952 			goto auth_sys;
   1953 		xpkey.n_len = strlen(hexkey) + 1;
   1954 		xpkey.n_bytes = hexkey;
   1955 		/*FALLTHROUGH*/
   1956 	case NIS_PK_DH :
   1957 		(void) host2netname(netname, srv->name, NULL);
   1958 		clnt->cl_auth = (AUTH *)authdes_pk_seccreate(netname,
   1959 					xpkey.n_len ? &xpkey : &(srv->pkey),
   1960 					15, NULL, NULL, srv);
   1961 		if (xpkey.n_len)
   1962 			free(xpkey.n_bytes);
   1963 		if (clnt->cl_auth)
   1964 			break;
   1965 		/*FALLTHROUGH*/
   1966 	case NIS_PK_NONE :
   1967 auth_sys:
   1968 	uid = use_realid ? getuid() : geteuid();
   1969 	gid = use_realid ? getgid() : getegid();
   1970 
   1971 	clnt->cl_auth = authsys_create(nis_local_host(), uid, gid, 0, NULL);
   1972 	if (clnt->cl_auth)
   1973 		break;
   1974 	/*FALLTHROUGH*/
   1975 	default :
   1976 		clnt->cl_auth = authnone_create();
   1977 		if (clnt->cl_auth)
   1978 			break;
   1979 		syslog(LOG_CRIT,
   1980 			"nis_make_rpchandle_uaddr: cannot create cred.");
   1981 		abort();
   1982 		break;
   1983 	}
   1984 
   1985 	if (clnt->cl_auth)
   1986 		return (clnt);
   1987 
   1988 	clnt_destroy(clnt);
   1989 	return (NULL);
   1990 }
   1991 
   1992 CLIENT *
   1993 nis_make_rpchandle_gss_svc(nis_server *srv, int cback, rpcprog_t prog,
   1994     rpcvers_t ver, uint_t flags, int inbuf, int outbuf, char *uaddr,
   1995     char *gss_svc)
   1996 {
   1997 	return (nis_make_rpchandle_gss_svc_ext(srv, cback, prog, ver, flags,
   1998 	    inbuf, outbuf, uaddr, gss_svc, 0));
   1999 }
   2000 
   2001 CLIENT *
   2002 nis_make_rpchandle_gss_svc_ruid(nis_server *srv, int cback, rpcprog_t prog,
   2003     rpcvers_t ver, uint_t flags, int inbuf, int outbuf, char *uaddr,
   2004     char *gss_svc)
   2005 {
   2006 	return (nis_make_rpchandle_gss_svc_ext(srv, cback, prog, ver, flags,
   2007 	    inbuf, outbuf, uaddr, gss_svc, 1));
   2008 }
   2009 
   2010 static mutex_t __nis_ss_used_lock = DEFAULTMUTEX; /* lock level 3 */
   2011 int	__nis_ss_used = 0;
   2012 
   2013 /*
   2014  * nis_get_static_storage()
   2015  *
   2016  * This function is used by various functions in their effort to minimize the
   2017  * hassles of memory management in an RPC daemon. Because the service doesn't
   2018  * implement any hard limits, this function allows people to get automatically
   2019  * growing buffers that meet their storage requirements. It returns the
   2020  * pointer in the nis_sdata structure.
   2021  *
   2022  */
   2023 void *
   2024 nis_get_static_storage(
   2025 	struct nis_sdata 	*bs, 	/* User buffer structure */
   2026 	uint_t			el,	/* Sizeof elements	 */
   2027 	uint_t			nel)	/* Number of elements	 */
   2028 {
   2029 	uint_t	sz;
   2030 
   2031 	sz = nel * el;
   2032 	if (!bs)
   2033 		return (NULL);
   2034 
   2035 	if (!bs->buf) {
   2036 		bs->buf = malloc(sz);
   2037 		if (!bs->buf)
   2038 			return (NULL);
   2039 		bs->size = sz;
   2040 		sig_mutex_lock(&__nis_ss_used_lock);
   2041 		__nis_ss_used += sz;
   2042 		sig_mutex_unlock(&__nis_ss_used_lock);
   2043 	} else if (bs->size < sz) {
   2044 		int 	size_delta;
   2045 
   2046 		free(bs->buf);
   2047 		size_delta = - (bs->size);
   2048 		bs->buf = malloc(sz);
   2049 
   2050 		/* check the result of malloc() first	*/
   2051 		/* then update the statistic.		*/
   2052 		if (!bs->buf)
   2053 			return (NULL);
   2054 		bs->size = sz;
   2055 		size_delta += sz;
   2056 		sig_mutex_lock(&__nis_ss_used_lock);
   2057 		__nis_ss_used += size_delta;
   2058 		sig_mutex_unlock(&__nis_ss_used_lock);
   2059 	}
   2060 
   2061 	(void) memset(bs->buf, 0, sz); /* SYSV version of bzero() */
   2062 	return (bs->buf);
   2063 }
   2064 
   2065 char *
   2066 nis_old_data_r(
   2067 	char	*s,
   2068 	struct nis_sdata	*bs_ptr)
   2069 {
   2070 	char			*buf;
   2071 	char			temp[1024];
   2072 	size_t			len = 0;
   2073 
   2074 	buf = (char *)nis_get_static_storage(bs_ptr, 1, 1024);
   2075 
   2076 	if (!buf)
   2077 		return (NULL);
   2078 
   2079 	/*
   2080 	 * this saving of 's' is because the routines that call nis_data()
   2081 	 * are not very careful about what they pass in.  Sometimes what they
   2082 	 * pass in are 'static' returned from some of the routines called
   2083 	 * below nis_leaf_of(),  nis_local_host() and so on.
   2084 	 */
   2085 	if (s) {
   2086 		len = strlen(s) + 1;
   2087 		if (len >= sizeof (temp))
   2088 			return (NULL);
   2089 		(void) snprintf(temp, sizeof (temp), "/%s", s);
   2090 	}
   2091 	if (len + strlen(__nis_data_directory) +
   2092 		strlen(nis_leaf_of(nis_local_host())) >= bs_ptr->size)
   2093 		return (NULL);
   2094 	(void) strcpy(buf, __nis_data_directory);
   2095 	(void) strcat(buf, nis_leaf_of(nis_local_host()));
   2096 	if (s)
   2097 		(void) strcat(buf, temp);
   2098 
   2099 	for (s = buf; *s; s++) {
   2100 		if (isupper(*s))
   2101 			*s = tolower(*s);
   2102 	}
   2103 
   2104 	return (buf);
   2105 }
   2106 
   2107 char *
   2108 nis_old_data(char *s)
   2109 {
   2110 	static pthread_key_t 	bs_key = PTHREAD_ONCE_KEY_NP;
   2111 	static struct nis_sdata	bs_main;
   2112 	struct nis_sdata	*bs_ptr;
   2113 
   2114 	bs_ptr = thr_main()? &bs_main :
   2115 		thr_get_storage(&bs_key, sizeof (struct nis_sdata),
   2116 		    destroy_nis_sdata);
   2117 	return (nis_old_data_r(s, bs_ptr));
   2118 }
   2119 
   2120 
   2121 char *
   2122 nis_data_r(char *s, struct nis_sdata *bs_ptr)
   2123 {
   2124 	char			*buf;
   2125 	char			temp[1024];
   2126 	size_t			len = 0;
   2127 
   2128 	buf = (char *)nis_get_static_storage(bs_ptr, 1, 1024);
   2129 
   2130 	if (!buf)
   2131 		return (NULL);
   2132 
   2133 	/*
   2134 	 * this saving of 's' is because the routines that call nis_data()
   2135 	 * are not very careful about what they pass in.  Sometimes what they
   2136 	 * pass in are 'static' returned from some of the routines called
   2137 	 * below nis_leaf_of(),  nis_local_host() and so on.
   2138 	 */
   2139 	if (s) {
   2140 		len = strlen(s) + 1;
   2141 		if (len >= sizeof (temp))
   2142 			return (NULL);
   2143 		(void) snprintf(temp, sizeof (temp), "/%s", s);
   2144 	}
   2145 	if (len + strlen(__nis_data_directory) +
   2146 		strlen(NIS_DIR) >= bs_ptr->size)
   2147 		return (NULL);
   2148 	(void) strcpy(buf, __nis_data_directory);
   2149 	(void) strcat(buf, NIS_DIR);
   2150 	if (s)
   2151 		(void) strcat(buf, temp);
   2152 
   2153 	for (s = buf; *s; s++) {
   2154 		if (isupper(*s))
   2155 			*s = tolower(*s);
   2156 	}
   2157 
   2158 	return (buf);
   2159 }
   2160 
   2161 char *
   2162 nis_data(char *s)
   2163 {
   2164 	static pthread_key_t 	bs_key = PTHREAD_ONCE_KEY_NP;
   2165 	static struct nis_sdata	bs_main;
   2166 	struct nis_sdata	*bs_ptr;
   2167 
   2168 	bs_ptr = thr_main()? &bs_main :
   2169 		thr_get_storage(&bs_key, sizeof (struct nis_sdata),
   2170 		    destroy_nis_sdata);
   2171 	return (nis_data_r(s, bs_ptr));
   2172 }
   2173 
   2174 /*
   2175  * Return the directory name of the root_domain of the caller's NIS+
   2176  * domain.
   2177  *
   2178  * This routine is a temporary implementation and should be
   2179  * provided as part of the the NIS+ project.  See RFE:  1103216
   2180  * Required for root replication.
   2181  *
   2182  * XXX MT safing: local_root_lock protects the local_root structure.
   2183  *
   2184  * It tries to determine the root domain
   2185  * name by "walking" the path up the NIS+ directory tree, starting
   2186  * at nis_local_directory() until a NIS_NOSUCHNAME or NIS_NOTFOUND error
   2187  * is obtained.  Returns 0 on fatal errors obtained before this point,
   2188  * or if it exhausts the domain name without ever obtaining one of
   2189  * of these errors.
   2190  */
   2191 
   2192 static nis_name local_root = 0;
   2193 static mutex_t local_root_lock = DEFAULTMUTEX;
   2194 
   2195 nis_name
   2196 __nis_local_root(void)
   2197 {
   2198 	char *dir;
   2199 	int found_root = 0;
   2200 	int try_count = 0;
   2201 	int fatal_error = 0;
   2202 	char *prev_testdir;
   2203 	char *testdir;
   2204 
   2205 	sig_mutex_lock(&local_root_lock);
   2206 	if (local_root) {
   2207 		sig_mutex_unlock(&local_root_lock);
   2208 		return (local_root);
   2209 	}
   2210 	local_root = calloc(1, LN_BUFSIZE);
   2211 
   2212 	if (!local_root) {
   2213 		sig_mutex_unlock(&local_root_lock);
   2214 		return (0);
   2215 	}
   2216 	/*  walk up NIS+ tree till we find the root. */
   2217 	dir = strdup(__nis_rpc_domain());
   2218 	prev_testdir = dir;
   2219 	testdir = nis_domain_of(prev_testdir);
   2220 
   2221 	while (testdir && !found_root && !fatal_error) {
   2222 	    /* try lookup */
   2223 	    nis_result* nis_ret = nis_lookup(testdir, 0);
   2224 	    /* handle return status */
   2225 	    switch (nis_ret->status) {
   2226 	    case NIS_SUCCESS:
   2227 	    case NIS_S_SUCCESS:
   2228 		try_count = 0;
   2229 		prev_testdir = testdir;
   2230 		testdir = nis_domain_of(prev_testdir);
   2231 		break;
   2232 	    case NIS_NOSUCHNAME:
   2233 	    case NIS_NOTFOUND:
   2234 	    case NIS_NOT_ME:
   2235 	    case NIS_FOREIGNNS:
   2236 		found_root = 1;
   2237 		break;
   2238 	    case NIS_TRYAGAIN:
   2239 	    case NIS_CACHEEXPIRED:
   2240 		/* sleep 1 second and try same name again, up to 10 times */
   2241 		/* REMIND: This is arbitrary! BAD! */
   2242 		(void) sleep(1);
   2243 		fatal_error = (try_count++ > 9);
   2244 		break;
   2245 	    case NIS_NAMEUNREACHABLE:
   2246 	    case NIS_SYSTEMERROR:
   2247 	    case NIS_RPCERROR:
   2248 	    case NIS_NOMEMORY:
   2249 	    default:
   2250 		fatal_error = 1;
   2251 		break;
   2252 	    }
   2253 	    if (nis_ret) nis_freeresult(nis_ret);
   2254 	}
   2255 
   2256 	if (!found_root) {
   2257 		free(dir);
   2258 		sig_mutex_unlock(&local_root_lock);
   2259 		return (0);
   2260 	}
   2261 	(void) strcpy(local_root, prev_testdir);
   2262 	free(dir);
   2263 	sig_mutex_unlock(&local_root_lock);
   2264 	return (local_root);
   2265 }
   2266 
   2267 extern	void __pkey_cache_add(char *, char *, keylen_t, algtype_t);
   2268 extern	int bin2hex(int, unsigned char *, char *);
   2269 
   2270 /*
   2271  * __nis_cache_server_pkeys
   2272  *
   2273  * Add the public keys for the servers of the directory object to the
   2274  * per-process public key cache.
   2275  */
   2276 void
   2277 __nis_cache_server_pkeys(directory_obj *dir) {
   2278 
   2279 	int		i;
   2280 	nis_server	*srv;
   2281 	char		netname[MAXNETNAMELEN+1];
   2282 	char		pkey[MAX_NETOBJ_SZ+1];
   2283 	extdhkey_t	*key;
   2284 	uint_t		s;
   2285 
   2286 	if (dir == NULL)
   2287 		return;
   2288 
   2289 	for (i = 0; i < dir->do_servers.do_servers_len; i++) {
   2290 
   2291 		srv = &(dir->do_servers.do_servers_val[i]);
   2292 
   2293 		switch (srv->key_type) {
   2294 		case NIS_PK_DH:
   2295 			if (srv->pkey.n_len < sizeof (pkey) &&
   2296 				host2netname(netname, srv->name, NULL)) {
   2297 				(void) memcpy(pkey, srv->pkey.n_bytes,
   2298 					srv->pkey.n_len);
   2299 				pkey[srv->pkey.n_len] = '\0';
   2300 				__pkey_cache_add(netname, pkey, 192, 0);
   2301 			}
   2302 			break;
   2303 		case NIS_PK_DHEXT:
   2304 			if (!host2netname(netname, srv->name, NULL))
   2305 				break;
   2306 			for (s = 0; s < srv->pkey.n_len; ) {
   2307 				keylen_t	k, kpadlen;
   2308 				algtype_t	a;
   2309 				/* LINTED pointer cast */
   2310 				key = (extdhkey_t *)&(srv->pkey.n_bytes[s]);
   2311 				k = ntohs(key->keylen);
   2312 				if (k == 0)
   2313 					break;
   2314 				kpadlen = ((((k+7)/8)+3)/4)*4;
   2315 				a = ntohs(key->algtype);
   2316 				if (kpadlen <= sizeof (pkey)) {
   2317 					(void) bin2hex((k+7)/8, key->key, pkey);
   2318 					__pkey_cache_add(netname, pkey, k, a);
   2319 				}
   2320 				s += 2*sizeof (ushort_t) + kpadlen;
   2321 			}
   2322 			break;
   2323 		default:
   2324 			break;
   2325 		}
   2326 
   2327 	}
   2328 }
   2329