Home | History | Annotate | Download | only in passwdutil
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <nsswitch.h>
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <string.h>
     32 #include <syslog.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 
     36 #include "ns_sldap.h"
     37 #include <nss_dbdefs.h>
     38 #include <nsswitch.h>
     39 #include <pwd.h>
     40 #include <shadow.h>
     41 #include <rpcsvc/nis.h>
     42 
     43 #include "passwdutil.h"
     44 
     45 /*
     46  * name_to_int(rep)
     47  *
     48  * Translate the repository to a bitmask.
     49  * if we don't recognise the repository name, we return REP_ERANGE
     50  */
     51 int
     52 name_to_int(char *rep_name)
     53 {
     54 	int result = REP_ERANGE;
     55 
     56 	if (strcmp(rep_name, "files") == 0)
     57 		result = REP_FILES;
     58 	else if (strcmp(rep_name, "nis") == 0)
     59 		result = REP_NIS;
     60 	else if (strcmp(rep_name, "ldap") == 0)
     61 		result = REP_LDAP;
     62 	else if (strcmp(rep_name, "compat") == 0) {
     63 		struct __nsw_switchconfig *cfg;
     64 		enum   __nsw_parse_err pserr;
     65 
     66 		cfg = __nsw_getconfig("passwd_compat", &pserr);
     67 		if (cfg == NULL) {
     68 			result = REP_FILES | REP_NIS;
     69 		} else {
     70 			if (strcmp(cfg->lookups->service_name, "ldap") == 0)
     71 				result = REP_FILES | REP_LDAP;
     72 			else
     73 				result = REP_ERANGE;
     74 			(void) __nsw_freeconfig(cfg);
     75 		}
     76 	}
     77 
     78 	return (result);
     79 }
     80 
     81 /*
     82  * Figure out which repository we use in compat mode.
     83  */
     84 int
     85 get_compat_mode(void)
     86 {
     87 	struct __nsw_switchconfig *cfg;
     88 	enum   __nsw_parse_err pserr;
     89 	int result = REP_COMPAT_NIS;
     90 
     91 	if ((cfg = __nsw_getconfig("passwd_compat", &pserr)) != NULL) {
     92 		if (strcmp(cfg->lookups->service_name, "ldap") == 0)
     93 			result = REP_COMPAT_LDAP;
     94 	}
     95 	(void) __nsw_freeconfig(cfg);
     96 
     97 	return (result);
     98 }
     99 
    100 /*
    101  * get_ns(rep, accesstype)
    102  *
    103  * returns a bitmask of repositories to use based on either
    104  *   1. the repository that is given as argument
    105  *   2. the nsswitch.conf file
    106  *   3. the type of access requested
    107  *
    108  * "accesstype" indicates whether we are reading from or writing to the
    109  * repository. We need to know this since "compat" will translate into
    110  * REP_NSS (the nss-switch) for READ access (needed to decode
    111  * the black-magic '+' entries) but it translates into a bitmask
    112  * on WRITE access.
    113  *
    114  * If we detect read-access in compat mode, we augment the result
    115  * with one of REP_COMPAT_{NIS,LDAP}. We need this in order to
    116  * implement ATTR_REP_NAME in nss_getpwnam.
    117  *
    118  * A return value of REP_NOREP indicates an error.
    119  */
    120 int
    121 get_ns(pwu_repository_t *rep, int accesstype)
    122 {
    123 	struct __nsw_switchconfig *conf = NULL;
    124 	enum __nsw_parse_err pserr;
    125 	struct __nsw_lookup *lkp;
    126 	struct __nsw_lookup *lkp2;
    127 	struct __nsw_lookup *lkp3;
    128 	struct __nsw_lookup *lkpn;
    129 	int result = REP_NOREP;
    130 
    131 	if (rep != PWU_DEFAULT_REP) {
    132 		result = name_to_int(rep->type);
    133 		return (result);
    134 	}
    135 
    136 	conf = __nsw_getconfig("passwd", &pserr);
    137 	if (conf == NULL) {
    138 		/*
    139 		 * No config found. The user didn't supply a repository,
    140 		 * so we try to change the password in the default
    141 		 * repositories (files and nis) even though we cannot
    142 		 * find the name service switch entry. (Backward compat)
    143 		 */
    144 		syslog(LOG_ERR, "passwdutil.so: nameservice switch entry for "
    145 		    "passwd not found.");
    146 		result = REP_FILES | REP_NIS;
    147 		return (result);
    148 	}
    149 
    150 	lkp = conf->lookups;
    151 
    152 	/*
    153 	 * Supported nsswitch.conf can have a maximum of 3 repositories.
    154 	 * If we encounter an unsupported nsswitch.conf, we return REP_NSS
    155 	 * to fall back to the nsswitch backend.
    156 	 *
    157 	 * Note that specifying 'ad' in the configuration is acceptable
    158 	 * though changing AD users' passwords through passwd(1) is not.
    159 	 * Therefore "ad" will be silently ignored.
    160 	 */
    161 	if (conf->num_lookups == 1) {
    162 		/* files or compat */
    163 
    164 		if (strcmp(lkp->service_name, "files") == 0) {
    165 			result = name_to_int(lkp->service_name);
    166 		} else if (strcmp(lkp->service_name, "compat") == 0) {
    167 			if (accesstype == PWU_READ)
    168 				result = REP_NSS | get_compat_mode();
    169 			else
    170 				result = name_to_int(lkp->service_name);
    171 		} else
    172 			result = REP_NSS;
    173 
    174 	} else if (conf->num_lookups == 2) {
    175 		lkp2 = lkp->next;
    176 		if (strcmp(lkp->service_name, "files") == 0) {
    177 			result = REP_FILES;
    178 			if (strcmp(lkp2->service_name, "ldap") == 0)
    179 				result |= REP_LDAP;
    180 			else if (strcmp(lkp2->service_name, "nis") == 0)
    181 				result |= REP_NIS;
    182 			else if (strcmp(lkp2->service_name, "ad") != 0)
    183 				result = REP_NSS;
    184 			/* AD is ignored */
    185 		} else {
    186 			result = REP_NSS;
    187 		}
    188 	} else if (conf->num_lookups == 3) {
    189 		/*
    190 		 * Valid configurations with 3 repositories are:
    191 		 *   files ad [nis | ldap ] OR
    192 		 *   files [nis | ldap ] ad
    193 		 */
    194 		lkp2 = lkp->next;
    195 		lkp3 = lkp2->next;
    196 		if (strcmp(lkp2->service_name, "ad") == 0)
    197 			lkpn = lkp3;
    198 		else if (strcmp(lkp3->service_name, "ad") == 0)
    199 			lkpn = lkp2;
    200 		else
    201 			lkpn = NULL;
    202 		if (strcmp(lkp->service_name, "files") == 0 &&
    203 		    lkpn != NULL) {
    204 			result = REP_FILES;
    205 			if (strcmp(lkpn->service_name, "ldap") == 0)
    206 				result |= REP_LDAP;
    207 			else if (strcmp(lkpn->service_name, "nis") == 0)
    208 				result |= REP_NIS;
    209 			else
    210 				result = REP_NSS;
    211 		} else {
    212 			result = REP_NSS;
    213 		}
    214 	} else {
    215 		result = REP_NSS;
    216 	}
    217 
    218 	(void) __nsw_freeconfig(conf);
    219 	return (result);
    220 }
    221 
    222 static void
    223 nss_ldap_passwd(p)
    224 	nss_db_params_t	*p;
    225 {
    226 	p->name = NSS_DBNAM_PASSWD;
    227 	p->flags |= NSS_USE_DEFAULT_CONFIG;
    228 	p->default_config = "ldap";
    229 }
    230 
    231 static void
    232 nss_ldap_shadow(p)
    233 	nss_db_params_t	*p;
    234 {
    235 	p->name = NSS_DBNAM_SHADOW;
    236 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
    237 	p->flags |= NSS_USE_DEFAULT_CONFIG;
    238 	p->default_config = "ldap";
    239 }
    240 
    241 
    242 #ifdef PAM_NIS
    243 static void
    244 nss_nis_passwd(p)
    245 	nss_db_params_t	*p;
    246 {
    247 	p->name = NSS_DBNAM_PASSWD;
    248 	p->flags |= NSS_USE_DEFAULT_CONFIG;
    249 	p->default_config = "nis";
    250 }
    251 
    252 static void
    253 nss_nis_shadow(p)
    254 	nss_db_params_t	*p;
    255 {
    256 	p->name = NSS_DBNAM_SHADOW;
    257 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
    258 	p->flags |= NSS_USE_DEFAULT_CONFIG;
    259 	p->default_config = "nis";
    260 }
    261 #endif /* PAM_NIS */
    262 
    263 static char *
    264 gettok(nextpp)
    265 	char	**nextpp;
    266 {
    267 	char	*p = *nextpp;
    268 	char	*q = p;
    269 	char	c;
    270 
    271 	if (p == 0) {
    272 		return (0);
    273 	}
    274 	while ((c = *q) != '\0' && c != ':') {
    275 		q++;
    276 	}
    277 	if (c == '\0') {
    278 		*nextpp = 0;
    279 	} else {
    280 		*q++ = '\0';
    281 		*nextpp = q;
    282 	}
    283 	return (p);
    284 }
    285 
    286 /*
    287  * Return values: 0 = success, 1 = parse error, 2 = erange ...
    288  * The structure pointer passed in is a structure in the caller's space
    289  * wherein the field pointers would be set to areas in the buffer if
    290  * need be. instring and buffer should be separate areas.
    291  */
    292 static int
    293 str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
    294 {
    295 	struct passwd	*passwd	= (struct passwd *)ent;
    296 	char		*p, *next;
    297 	int		black_magic;	/* "+" or "-" entry */
    298 
    299 	if (lenstr + 1 > buflen) {
    300 		return (NSS_STR_PARSE_ERANGE);
    301 	}
    302 	/*
    303 	 * We copy the input string into the output buffer and
    304 	 * operate on it in place.
    305 	 */
    306 	(void) memcpy(buffer, instr, lenstr);
    307 	buffer[lenstr] = '\0';
    308 
    309 	next = buffer;
    310 
    311 	passwd->pw_name = p = gettok(&next);		/* username */
    312 	if (*p == '\0') {
    313 		/* Empty username;  not allowed */
    314 		return (NSS_STR_PARSE_PARSE);
    315 	}
    316 	black_magic = (*p == '+' || *p == '-');
    317 	if (black_magic) {
    318 		passwd->pw_uid	= UID_NOBODY;
    319 		passwd->pw_gid	= GID_NOBODY;
    320 		/*
    321 		 * pwconv tests pw_passwd and pw_age == NULL
    322 		 */
    323 		passwd->pw_passwd = "";
    324 		passwd->pw_age	= "";
    325 		/*
    326 		 * the rest of the passwd entry is "optional"
    327 		 */
    328 		passwd->pw_comment = "";
    329 		passwd->pw_gecos = "";
    330 		passwd->pw_dir	= "";
    331 		passwd->pw_shell = "";
    332 	}
    333 
    334 	passwd->pw_passwd = p = gettok(&next);		/* password */
    335 	if (p == 0) {
    336 		if (black_magic)
    337 			return (NSS_STR_PARSE_SUCCESS);
    338 		else
    339 			return (NSS_STR_PARSE_PARSE);
    340 	}
    341 	for (; *p != '\0'; p++) {			/* age */
    342 		if (*p == ',') {
    343 			*p++ = '\0';
    344 			break;
    345 		}
    346 	}
    347 	passwd->pw_age = p;
    348 
    349 	p = next;					/* uid */
    350 	if (p == 0 || *p == '\0') {
    351 		if (black_magic)
    352 			return (NSS_STR_PARSE_SUCCESS);
    353 		else
    354 			return (NSS_STR_PARSE_PARSE);
    355 	}
    356 	if (!black_magic) {
    357 		passwd->pw_uid = strtol(p, &next, 10);
    358 		if (next == p) {
    359 			/* uid field should be nonempty */
    360 			return (NSS_STR_PARSE_PARSE);
    361 		}
    362 		/*
    363 		 * The old code (in 2.0 thru 2.5) would check
    364 		 * for the uid being negative, or being greater
    365 		 * than 60001 (the rfs limit).  If it met either of
    366 		 * these conditions, the uid was translated to 60001.
    367 		 *
    368 		 * Now we just check for ephemeral uids; anything else
    369 		 * is administrative policy
    370 		 */
    371 		if (passwd->pw_uid > MAXUID)
    372 			passwd->pw_uid = UID_NOBODY;
    373 	}
    374 	if (*next++ != ':') {
    375 		if (black_magic)
    376 			p = gettok(&next);
    377 		else
    378 			return (NSS_STR_PARSE_PARSE);
    379 	}
    380 	p = next;					/* gid */
    381 	if (p == 0 || *p == '\0') {
    382 		if (black_magic)
    383 			return (NSS_STR_PARSE_SUCCESS);
    384 		else
    385 			return (NSS_STR_PARSE_PARSE);
    386 	}
    387 	if (!black_magic) {
    388 		passwd->pw_gid = strtol(p, &next, 10);
    389 		if (next == p) {
    390 			/* gid field should be nonempty */
    391 			return (NSS_STR_PARSE_PARSE);
    392 		}
    393 		/*
    394 		 * gid should be non-negative; anything else
    395 		 * is administrative policy.
    396 		 */
    397 		if (passwd->pw_gid > MAXUID)
    398 			passwd->pw_gid = GID_NOBODY;
    399 	}
    400 	if (*next++ != ':') {
    401 		if (black_magic)
    402 			p = gettok(&next);
    403 		else
    404 			return (NSS_STR_PARSE_PARSE);
    405 	}
    406 
    407 	passwd->pw_gecos = passwd->pw_comment = p = gettok(&next);
    408 	if (p == 0) {
    409 		if (black_magic)
    410 			return (NSS_STR_PARSE_SUCCESS);
    411 		else
    412 			return (NSS_STR_PARSE_PARSE);
    413 	}
    414 
    415 	passwd->pw_dir = p = gettok(&next);
    416 	if (p == 0) {
    417 		if (black_magic)
    418 			return (NSS_STR_PARSE_SUCCESS);
    419 		else
    420 			return (NSS_STR_PARSE_PARSE);
    421 	}
    422 
    423 	passwd->pw_shell = p = gettok(&next);
    424 	if (p == 0) {
    425 		if (black_magic)
    426 			return (NSS_STR_PARSE_SUCCESS);
    427 		else
    428 			return (NSS_STR_PARSE_PARSE);
    429 	}
    430 
    431 	/* Better not be any more fields... */
    432 	if (next == 0) {
    433 		/* Successfully parsed and stored */
    434 		return (NSS_STR_PARSE_SUCCESS);
    435 	}
    436 	return (NSS_STR_PARSE_PARSE);
    437 }
    438 
    439 typedef const char *constp;
    440 
    441 /*
    442  * Return value 1 means success and more input, 0 means error or no more
    443  */
    444 static int
    445 getfield(nextp, limit, uns, valp)
    446 	constp		*nextp;
    447 	constp		limit;
    448 	int		uns;
    449 	void		*valp;
    450 {
    451 	constp		p = *nextp;
    452 	char		*endfield;
    453 	char		numbuf[12];  /* Holds -2^31 and trailing ':' */
    454 	int		len;
    455 	long		x;
    456 	unsigned long	ux;
    457 
    458 	if (p == 0 || p >= limit) {
    459 		return (0);
    460 	}
    461 	if (*p == ':') {
    462 		p++;
    463 		*nextp = p;
    464 		return (p < limit);
    465 	}
    466 	if ((len = limit - p) > sizeof (numbuf) - 1) {
    467 		len = sizeof (numbuf) - 1;
    468 	}
    469 	/*
    470 	 * We want to use strtol() and we have a readonly non-zero-terminated
    471 	 *   string, so first we copy and terminate the interesting bit.
    472 	 *   Ugh.  (It's convenient to terminate with a colon rather than \0).
    473 	 */
    474 	if ((endfield = memccpy(numbuf, p, ':', len)) == 0) {
    475 		if (len != limit - p) {
    476 			/* Error -- field is too big to be a legit number */
    477 			return (0);
    478 		}
    479 		numbuf[len] = ':';
    480 		p = limit;
    481 	} else {
    482 		p += (endfield - numbuf);
    483 	}
    484 	if (uns) {
    485 		ux = strtoul(numbuf, &endfield, 10);
    486 		if (*endfield != ':') {
    487 			/* Error -- expected <integer><colon> */
    488 			return (0);
    489 		}
    490 		*((unsigned int *)valp) = (unsigned int)ux;
    491 	} else {
    492 		x = strtol(numbuf, &endfield, 10);
    493 		if (*endfield != ':') {
    494 			/* Error -- expected <integer><colon> */
    495 			return (0);
    496 		}
    497 		*((int *)valp) = (int)x;
    498 	}
    499 	*nextp = p;
    500 	return (p < limit);
    501 }
    502 
    503 /*
    504  *  str2spwd() -- convert a string to a shadow passwd entry.  The parser is
    505  *	more liberal than the passwd or group parsers;  since it's legitimate
    506  *	for almost all the fields here to be blank, the parser lets one omit
    507  *	any number of blank fields at the end of the entry.  The acceptable
    508  *	forms for '+' and '-' entries are the same as those for normal entries.
    509  *  === Is this likely to do more harm than good?
    510  *
    511  * Return values: 0 = success, 1 = parse error, 2 = erange ...
    512  * The structure pointer passed in is a structure in the caller's space
    513  * wherein the field pointers would be set to areas in the buffer if
    514  * need be. instring and buffer should be separate areas.
    515  */
    516 int
    517 str2spwd(instr, lenstr, ent, buffer, buflen)
    518 	const char	*instr;
    519 	int		lenstr;
    520 	void	*ent; /* really (struct spwd *) */
    521 	char	*buffer;
    522 	int	buflen;
    523 {
    524 	struct spwd	*shadow	= (struct spwd *)ent;
    525 	const char	*p = instr, *limit;
    526 	char		*bufp;
    527 	int	lencopy, black_magic;
    528 
    529 	limit = p + lenstr;
    530 	if ((p = memchr(instr, ':', lenstr)) == 0 ||
    531 		++p >= limit ||
    532 		(p = memchr(p, ':', limit - p)) == 0) {
    533 		lencopy = lenstr;
    534 		p = 0;
    535 	} else {
    536 		lencopy = p - instr;
    537 		p++;
    538 	}
    539 	if (lencopy + 1 > buflen) {
    540 		return (NSS_STR_PARSE_ERANGE);
    541 	}
    542 	(void) memcpy(buffer, instr, lencopy);
    543 	buffer[lencopy] = 0;
    544 
    545 	black_magic = (*instr == '+' || *instr == '-');
    546 	shadow->sp_namp = bufp = buffer;
    547 	shadow->sp_pwdp	= 0;
    548 	shadow->sp_lstchg = -1;
    549 	shadow->sp_min	= -1;
    550 	shadow->sp_max	= -1;
    551 	shadow->sp_warn	= -1;
    552 	shadow->sp_inact = -1;
    553 	shadow->sp_expire = -1;
    554 	shadow->sp_flag	= 0;
    555 
    556 	if ((bufp = strchr(bufp, ':')) == 0) {
    557 		if (black_magic)
    558 			return (NSS_STR_PARSE_SUCCESS);
    559 		else
    560 			return (NSS_STR_PARSE_PARSE);
    561 	}
    562 	*bufp++ = '\0';
    563 
    564 	shadow->sp_pwdp = bufp;
    565 	if (instr == 0) {
    566 		if ((bufp = strchr(bufp, ':')) == 0) {
    567 			if (black_magic)
    568 				return (NSS_STR_PARSE_SUCCESS);
    569 			else
    570 				return (NSS_STR_PARSE_PARSE);
    571 		}
    572 		*bufp++ = '\0';
    573 		p = bufp;
    574 	} /* else p was set when we copied name and passwd into the buffer */
    575 
    576 	if (!getfield(&p, limit, 0, &shadow->sp_lstchg))
    577 			return (NSS_STR_PARSE_SUCCESS);
    578 	if (!getfield(&p, limit, 0, &shadow->sp_min))
    579 			return (NSS_STR_PARSE_SUCCESS);
    580 	if (!getfield(&p, limit, 0, &shadow->sp_max))
    581 			return (NSS_STR_PARSE_SUCCESS);
    582 	if (!getfield(&p, limit, 0, &shadow->sp_warn))
    583 			return (NSS_STR_PARSE_SUCCESS);
    584 	if (!getfield(&p, limit, 0, &shadow->sp_inact))
    585 			return (NSS_STR_PARSE_SUCCESS);
    586 	if (!getfield(&p, limit, 0, &shadow->sp_expire))
    587 			return (NSS_STR_PARSE_SUCCESS);
    588 	if (!getfield(&p, limit, 1, &shadow->sp_flag))
    589 			return (NSS_STR_PARSE_SUCCESS);
    590 	if (p != limit) {
    591 		/* Syntax error -- garbage at end of line */
    592 		return (NSS_STR_PARSE_PARSE);
    593 	}
    594 	return (NSS_STR_PARSE_SUCCESS);
    595 }
    596 
    597 static nss_XbyY_buf_t *buffer;
    598 static DEFINE_NSS_DB_ROOT(db_root);
    599 
    600 #define	GETBUF()	\
    601 	NSS_XbyY_ALLOC(&buffer, sizeof (struct passwd), NSS_BUFLEN_PASSWD)
    602 
    603 #pragma fini(endutilpwent)
    604 
    605 static void
    606 endutilpwent(void)
    607 {
    608 	NSS_XbyY_FREE(&buffer);
    609 	nss_delete(&db_root);
    610 }
    611 
    612 /*ARGSUSED*/
    613 struct passwd *
    614 getpwnam_from(const char *name, pwu_repository_t *rep, int reptype)
    615 {
    616 	nss_XbyY_buf_t  *b = GETBUF();
    617 	nss_XbyY_args_t arg;
    618 
    619 	if (b == 0)
    620 		return (0);
    621 
    622 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd);
    623 	arg.key.name = name;
    624 
    625 	switch (reptype) {
    626 	case REP_LDAP:
    627 		(void) nss_search(&db_root, nss_ldap_passwd,
    628 		    NSS_DBOP_PASSWD_BYNAME, &arg);
    629 		break;
    630 #ifdef PAM_NIS
    631 	case REP_NIS:
    632 		(void) nss_search(&db_root, nss_nis_passwd,
    633 		    NSS_DBOP_PASSWD_BYNAME, &arg);
    634 		break;
    635 #endif
    636 	default:
    637 		return (NULL);
    638 	}
    639 
    640 	return (struct passwd *)NSS_XbyY_FINI(&arg);
    641 }
    642 
    643 /*ARGSUSED*/
    644 struct passwd *
    645 getpwuid_from(uid_t uid, pwu_repository_t *rep, int reptype)
    646 {
    647 	nss_XbyY_buf_t  *b = GETBUF();
    648 	nss_XbyY_args_t arg;
    649 
    650 	if (b == 0)
    651 		return (0);
    652 
    653 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd);
    654 	arg.key.uid = uid;
    655 
    656 	switch (reptype) {
    657 	case REP_LDAP:
    658 		(void) nss_search(&db_root, nss_ldap_passwd,
    659 		    NSS_DBOP_PASSWD_BYUID, &arg);
    660 		break;
    661 #ifdef PAM_NIS
    662 	case REP_NIS:
    663 		(void) nss_search(&db_root, nss_nis_passwd,
    664 		    NSS_DBOP_PASSWD_BYUID, &arg);
    665 		break;
    666 #endif
    667 	default:
    668 		return (NULL);
    669 	}
    670 
    671 	return (struct passwd *)NSS_XbyY_FINI(&arg);
    672 }
    673 
    674 static nss_XbyY_buf_t *spbuf;
    675 static DEFINE_NSS_DB_ROOT(spdb_root);
    676 
    677 #define	GETSPBUF()	\
    678 	NSS_XbyY_ALLOC(&spbuf, sizeof (struct spwd), NSS_BUFLEN_SHADOW)
    679 
    680 #pragma fini(endutilspent)
    681 
    682 static void
    683 endutilspent(void)
    684 {
    685 	NSS_XbyY_FREE(&spbuf);
    686 	nss_delete(&spdb_root);
    687 }
    688 
    689 /*ARGSUSED*/
    690 struct spwd *
    691 getspnam_from(const char *name, pwu_repository_t *rep, int reptype)
    692 {
    693 	nss_XbyY_buf_t  *b = GETSPBUF();
    694 	nss_XbyY_args_t arg;
    695 
    696 	if (b == 0)
    697 		return (0);
    698 
    699 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2spwd);
    700 	arg.key.name = name;
    701 	switch (reptype) {
    702 	case REP_LDAP:
    703 		(void) nss_search(&spdb_root, nss_ldap_shadow,
    704 		    NSS_DBOP_SHADOW_BYNAME, &arg);
    705 		break;
    706 #ifdef PAM_NIS
    707 	case REP_NIS:
    708 		(void) nss_search(&spdb_root, nss_nis_shadow,
    709 		    NSS_DBOP_SHADOW_BYNAME, &arg);
    710 		break;
    711 #endif
    712 	default:
    713 		return (NULL);
    714 	}
    715 	return (struct spwd *)NSS_XbyY_FINI(&arg);
    716 }
    717