xref: /titanic_51/usr/src/lib/passwdutil/switch_utils.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <nsswitch.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <string.h>
34*7c478bd9Sstevel@tonic-gate #include <syslog.h>
35*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
39*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
40*7c478bd9Sstevel@tonic-gate #include <nsswitch.h>
41*7c478bd9Sstevel@tonic-gate #include <pwd.h>
42*7c478bd9Sstevel@tonic-gate #include <shadow.h>
43*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include "passwdutil.h"
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static struct passwd *nisplus_getpw_from_master(const char *, char *);
48*7c478bd9Sstevel@tonic-gate static struct spwd *nisplus_getsp_from_master(const char *, char *);
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * name_to_int(rep)
52*7c478bd9Sstevel@tonic-gate  *
53*7c478bd9Sstevel@tonic-gate  * Translate the repository to a bitmask.
54*7c478bd9Sstevel@tonic-gate  * if we don't recognise the repository name, we return REP_ERANGE
55*7c478bd9Sstevel@tonic-gate  */
56*7c478bd9Sstevel@tonic-gate int
57*7c478bd9Sstevel@tonic-gate name_to_int(char *rep_name)
58*7c478bd9Sstevel@tonic-gate {
59*7c478bd9Sstevel@tonic-gate 	int result = REP_ERANGE;
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate 	if (strcmp(rep_name, "files") == 0)
62*7c478bd9Sstevel@tonic-gate 		result = REP_FILES;
63*7c478bd9Sstevel@tonic-gate 	else if (strcmp(rep_name, "nis") == 0)
64*7c478bd9Sstevel@tonic-gate 		result = REP_NIS;
65*7c478bd9Sstevel@tonic-gate 	else if (strcmp(rep_name, "nisplus") == 0)
66*7c478bd9Sstevel@tonic-gate 		result = REP_NISPLUS;
67*7c478bd9Sstevel@tonic-gate 	else if (strcmp(rep_name, "ldap") == 0)
68*7c478bd9Sstevel@tonic-gate 		result = REP_LDAP;
69*7c478bd9Sstevel@tonic-gate 	else if (strcmp(rep_name, "compat") == 0) {
70*7c478bd9Sstevel@tonic-gate 		struct __nsw_switchconfig *cfg;
71*7c478bd9Sstevel@tonic-gate 		enum   __nsw_parse_err pserr;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 		cfg = __nsw_getconfig("passwd_compat", &pserr);
74*7c478bd9Sstevel@tonic-gate 		if (cfg == NULL) {
75*7c478bd9Sstevel@tonic-gate 			result = REP_FILES | REP_NIS;
76*7c478bd9Sstevel@tonic-gate 		} else {
77*7c478bd9Sstevel@tonic-gate 			if (strcmp(cfg->lookups->service_name, "nisplus") == 0)
78*7c478bd9Sstevel@tonic-gate 				result = REP_FILES | REP_NISPLUS;
79*7c478bd9Sstevel@tonic-gate 			else if (strcmp(cfg->lookups->service_name, "ldap") ==
80*7c478bd9Sstevel@tonic-gate 			    0)
81*7c478bd9Sstevel@tonic-gate 				result = REP_FILES | REP_LDAP;
82*7c478bd9Sstevel@tonic-gate 			else
83*7c478bd9Sstevel@tonic-gate 				result = REP_ERANGE;
84*7c478bd9Sstevel@tonic-gate 			__nsw_freeconfig(cfg);
85*7c478bd9Sstevel@tonic-gate 		}
86*7c478bd9Sstevel@tonic-gate 	}
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	return (result);
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate /*
92*7c478bd9Sstevel@tonic-gate  * Figure out which repository we use in compat mode.
93*7c478bd9Sstevel@tonic-gate  */
94*7c478bd9Sstevel@tonic-gate int
95*7c478bd9Sstevel@tonic-gate get_compat_mode(void)
96*7c478bd9Sstevel@tonic-gate {
97*7c478bd9Sstevel@tonic-gate 	struct __nsw_switchconfig *cfg;
98*7c478bd9Sstevel@tonic-gate 	enum   __nsw_parse_err pserr;
99*7c478bd9Sstevel@tonic-gate 	int result = REP_COMPAT_NIS;
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	if ((cfg = __nsw_getconfig("passwd_compat", &pserr)) != NULL) {
102*7c478bd9Sstevel@tonic-gate 		if (strcmp(cfg->lookups->service_name, "nisplus") == 0)
103*7c478bd9Sstevel@tonic-gate 			result = REP_COMPAT_NISPLUS;
104*7c478bd9Sstevel@tonic-gate 		else if (strcmp(cfg->lookups->service_name, "ldap") == 0)
105*7c478bd9Sstevel@tonic-gate 			result = REP_COMPAT_LDAP;
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 	__nsw_freeconfig(cfg);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	return (result);
110*7c478bd9Sstevel@tonic-gate }
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /*
113*7c478bd9Sstevel@tonic-gate  * get_ns(rep, accesstype)
114*7c478bd9Sstevel@tonic-gate  *
115*7c478bd9Sstevel@tonic-gate  * returns a bitmask of repositories to use based on either
116*7c478bd9Sstevel@tonic-gate  *   1. the repository that is given as argument
117*7c478bd9Sstevel@tonic-gate  *   2. the nsswitch.conf file
118*7c478bd9Sstevel@tonic-gate  *   3. the type of access requested
119*7c478bd9Sstevel@tonic-gate  *
120*7c478bd9Sstevel@tonic-gate  * "accesstype" indicates whether we are reading from or writing to the
121*7c478bd9Sstevel@tonic-gate  * repository. We need to know this since "compat" will translate into
122*7c478bd9Sstevel@tonic-gate  * REP_NSS (the nss-switch) for READ access (needed to decode
123*7c478bd9Sstevel@tonic-gate  * the black-magic '+' entries) but it translates into a bitmask
124*7c478bd9Sstevel@tonic-gate  * on WRITE access.
125*7c478bd9Sstevel@tonic-gate  *
126*7c478bd9Sstevel@tonic-gate  * If we detect read-access in compat mode, we augment the result
127*7c478bd9Sstevel@tonic-gate  * with one of REP_COMPAT_{NIS,NISPLUS,LDAP}. We need this in order to
128*7c478bd9Sstevel@tonic-gate  * implement ATTR_REP_NAME in nss_getpwnam.
129*7c478bd9Sstevel@tonic-gate  *
130*7c478bd9Sstevel@tonic-gate  * A return value of REP_NOREP indicates an error.
131*7c478bd9Sstevel@tonic-gate  */
132*7c478bd9Sstevel@tonic-gate int
133*7c478bd9Sstevel@tonic-gate get_ns(pwu_repository_t *rep, int accesstype)
134*7c478bd9Sstevel@tonic-gate {
135*7c478bd9Sstevel@tonic-gate 	struct __nsw_switchconfig *conf = NULL;
136*7c478bd9Sstevel@tonic-gate 	enum __nsw_parse_err pserr;
137*7c478bd9Sstevel@tonic-gate 	struct __nsw_lookup *lkp;
138*7c478bd9Sstevel@tonic-gate 	struct __nsw_lookup *lkp2;
139*7c478bd9Sstevel@tonic-gate 	int result = REP_NOREP;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	if (rep != PWU_DEFAULT_REP) {
142*7c478bd9Sstevel@tonic-gate 		result = name_to_int(rep->type);
143*7c478bd9Sstevel@tonic-gate 		return (result);
144*7c478bd9Sstevel@tonic-gate 	}
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	conf = __nsw_getconfig("passwd", &pserr);
147*7c478bd9Sstevel@tonic-gate 	if (conf == NULL) {
148*7c478bd9Sstevel@tonic-gate 		/*
149*7c478bd9Sstevel@tonic-gate 		 * No config found. The user didn't supply a repository,
150*7c478bd9Sstevel@tonic-gate 		 * so we try to change the password in the default
151*7c478bd9Sstevel@tonic-gate 		 * repositories (files and nis) even though we cannot
152*7c478bd9Sstevel@tonic-gate 		 * find the name service switch entry. (Backward compat)
153*7c478bd9Sstevel@tonic-gate 		 */
154*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "passwdutil.so: nameservice switch entry for "
155*7c478bd9Sstevel@tonic-gate 				"passwd not found.");
156*7c478bd9Sstevel@tonic-gate 		result = REP_FILES | REP_NIS;
157*7c478bd9Sstevel@tonic-gate 		return (result);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	lkp = conf->lookups;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/*
163*7c478bd9Sstevel@tonic-gate 	 * Supported nsswitch.conf can have a maximum of 2 repositories.
164*7c478bd9Sstevel@tonic-gate 	 * If we encounter an unsupported nsswitch.conf, we return REP_NSS
165*7c478bd9Sstevel@tonic-gate 	 * to fall back to the nsswitch backend.
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	if (conf->num_lookups == 1) {
168*7c478bd9Sstevel@tonic-gate 		/* files or compat */
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 		if (strcmp(lkp->service_name, "files") == 0) {
171*7c478bd9Sstevel@tonic-gate 			result = name_to_int(lkp->service_name);
172*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(lkp->service_name, "compat") == 0) {
173*7c478bd9Sstevel@tonic-gate 			if (accesstype == PWU_READ)
174*7c478bd9Sstevel@tonic-gate 				result = REP_NSS | get_compat_mode();
175*7c478bd9Sstevel@tonic-gate 			else
176*7c478bd9Sstevel@tonic-gate 				result = name_to_int(lkp->service_name);
177*7c478bd9Sstevel@tonic-gate 		} else
178*7c478bd9Sstevel@tonic-gate 			result = REP_NSS;
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	} else if (conf->num_lookups == 2) {
181*7c478bd9Sstevel@tonic-gate 		lkp2 = lkp->next;
182*7c478bd9Sstevel@tonic-gate 		if (strcmp(lkp->service_name, "files") == 0) {
183*7c478bd9Sstevel@tonic-gate 			result = REP_FILES;
184*7c478bd9Sstevel@tonic-gate 			if (strcmp(lkp2->service_name, "ldap") == 0)
185*7c478bd9Sstevel@tonic-gate 				result |= REP_LDAP;
186*7c478bd9Sstevel@tonic-gate 			else if (strcmp(lkp2->service_name, "nis") == 0)
187*7c478bd9Sstevel@tonic-gate 				result |= REP_NIS;
188*7c478bd9Sstevel@tonic-gate 			else if (strcmp(lkp2->service_name, "nisplus") == 0)
189*7c478bd9Sstevel@tonic-gate 				result |= REP_NISPLUS;
190*7c478bd9Sstevel@tonic-gate 			else
191*7c478bd9Sstevel@tonic-gate 				result = REP_NSS;
192*7c478bd9Sstevel@tonic-gate 		} else {
193*7c478bd9Sstevel@tonic-gate 			result = REP_NSS;
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 	} else {
196*7c478bd9Sstevel@tonic-gate 		result = REP_NSS;
197*7c478bd9Sstevel@tonic-gate 	}
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	__nsw_freeconfig(conf);
200*7c478bd9Sstevel@tonic-gate 	return (result);
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate static void
204*7c478bd9Sstevel@tonic-gate nss_ldap_passwd(p)
205*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_PASSWD;
208*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
209*7c478bd9Sstevel@tonic-gate 	p->default_config = "ldap";
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate static void
213*7c478bd9Sstevel@tonic-gate nss_ldap_shadow(p)
214*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_SHADOW;
217*7c478bd9Sstevel@tonic-gate 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
218*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
219*7c478bd9Sstevel@tonic-gate 	p->default_config = "ldap";
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS
224*7c478bd9Sstevel@tonic-gate static void
225*7c478bd9Sstevel@tonic-gate nss_nis_passwd(p)
226*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_PASSWD;
229*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
230*7c478bd9Sstevel@tonic-gate 	p->default_config = "nis";
231*7c478bd9Sstevel@tonic-gate }
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate static void
234*7c478bd9Sstevel@tonic-gate nss_nis_shadow(p)
235*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_SHADOW;
238*7c478bd9Sstevel@tonic-gate 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
239*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
240*7c478bd9Sstevel@tonic-gate 	p->default_config = "nis";
241*7c478bd9Sstevel@tonic-gate }
242*7c478bd9Sstevel@tonic-gate #endif /* PAM_NIS */
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate static void
246*7c478bd9Sstevel@tonic-gate nss_nisplus_passwd(p)
247*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
248*7c478bd9Sstevel@tonic-gate {
249*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_PASSWD;
250*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
251*7c478bd9Sstevel@tonic-gate 	p->default_config = "nisplus";
252*7c478bd9Sstevel@tonic-gate }
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate static void
255*7c478bd9Sstevel@tonic-gate nss_nisplus_shadow(p)
256*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_SHADOW;
259*7c478bd9Sstevel@tonic-gate 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
260*7c478bd9Sstevel@tonic-gate 	p->flags |= NSS_USE_DEFAULT_CONFIG;
261*7c478bd9Sstevel@tonic-gate 	p->default_config = "nisplus";
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate static char *
266*7c478bd9Sstevel@tonic-gate gettok(nextpp)
267*7c478bd9Sstevel@tonic-gate 	char	**nextpp;
268*7c478bd9Sstevel@tonic-gate {
269*7c478bd9Sstevel@tonic-gate 	char	*p = *nextpp;
270*7c478bd9Sstevel@tonic-gate 	char	*q = p;
271*7c478bd9Sstevel@tonic-gate 	char	c;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
274*7c478bd9Sstevel@tonic-gate 		return (0);
275*7c478bd9Sstevel@tonic-gate 	}
276*7c478bd9Sstevel@tonic-gate 	while ((c = *q) != '\0' && c != ':') {
277*7c478bd9Sstevel@tonic-gate 		q++;
278*7c478bd9Sstevel@tonic-gate 	}
279*7c478bd9Sstevel@tonic-gate 	if (c == '\0') {
280*7c478bd9Sstevel@tonic-gate 		*nextpp = 0;
281*7c478bd9Sstevel@tonic-gate 	} else {
282*7c478bd9Sstevel@tonic-gate 		*q++ = '\0';
283*7c478bd9Sstevel@tonic-gate 		*nextpp = q;
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 	return (p);
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
290*7c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
291*7c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
292*7c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
293*7c478bd9Sstevel@tonic-gate  */
294*7c478bd9Sstevel@tonic-gate static int
295*7c478bd9Sstevel@tonic-gate str2passwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
296*7c478bd9Sstevel@tonic-gate {
297*7c478bd9Sstevel@tonic-gate 	struct passwd	*passwd	= (struct passwd *)ent;
298*7c478bd9Sstevel@tonic-gate 	char		*p, *next;
299*7c478bd9Sstevel@tonic-gate 	int		black_magic;	/* "+" or "-" entry */
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	if (lenstr + 1 > buflen) {
302*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 	/*
305*7c478bd9Sstevel@tonic-gate 	 * We copy the input string into the output buffer and
306*7c478bd9Sstevel@tonic-gate 	 * operate on it in place.
307*7c478bd9Sstevel@tonic-gate 	 */
308*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, instr, lenstr);
309*7c478bd9Sstevel@tonic-gate 	buffer[lenstr] = '\0';
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	next = buffer;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	passwd->pw_name = p = gettok(&next);		/* username */
314*7c478bd9Sstevel@tonic-gate 	if (*p == '\0') {
315*7c478bd9Sstevel@tonic-gate 		/* Empty username;  not allowed */
316*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 	black_magic = (*p == '+' || *p == '-');
319*7c478bd9Sstevel@tonic-gate 	if (black_magic) {
320*7c478bd9Sstevel@tonic-gate 		passwd->pw_uid	= UID_NOBODY;
321*7c478bd9Sstevel@tonic-gate 		passwd->pw_gid	= GID_NOBODY;
322*7c478bd9Sstevel@tonic-gate 		/*
323*7c478bd9Sstevel@tonic-gate 		 * pwconv tests pw_passwd and pw_age == NULL
324*7c478bd9Sstevel@tonic-gate 		 */
325*7c478bd9Sstevel@tonic-gate 		passwd->pw_passwd = "";
326*7c478bd9Sstevel@tonic-gate 		passwd->pw_age	= "";
327*7c478bd9Sstevel@tonic-gate 		/*
328*7c478bd9Sstevel@tonic-gate 		 * the rest of the passwd entry is "optional"
329*7c478bd9Sstevel@tonic-gate 		 */
330*7c478bd9Sstevel@tonic-gate 		passwd->pw_comment = "";
331*7c478bd9Sstevel@tonic-gate 		passwd->pw_gecos = "";
332*7c478bd9Sstevel@tonic-gate 		passwd->pw_dir	= "";
333*7c478bd9Sstevel@tonic-gate 		passwd->pw_shell = "";
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	passwd->pw_passwd = p = gettok(&next);		/* password */
337*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
338*7c478bd9Sstevel@tonic-gate 		if (black_magic)
339*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
340*7c478bd9Sstevel@tonic-gate 		else
341*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 	for (; *p != '\0'; p++) {			/* age */
344*7c478bd9Sstevel@tonic-gate 		if (*p == ',') {
345*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
346*7c478bd9Sstevel@tonic-gate 			break;
347*7c478bd9Sstevel@tonic-gate 		}
348*7c478bd9Sstevel@tonic-gate 	}
349*7c478bd9Sstevel@tonic-gate 	passwd->pw_age = p;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	p = next;					/* uid */
352*7c478bd9Sstevel@tonic-gate 	if (p == 0 || *p == '\0') {
353*7c478bd9Sstevel@tonic-gate 		if (black_magic)
354*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
355*7c478bd9Sstevel@tonic-gate 		else
356*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
357*7c478bd9Sstevel@tonic-gate 	}
358*7c478bd9Sstevel@tonic-gate 	if (!black_magic) {
359*7c478bd9Sstevel@tonic-gate 		passwd->pw_uid = strtol(p, &next, 10);
360*7c478bd9Sstevel@tonic-gate 		if (next == p) {
361*7c478bd9Sstevel@tonic-gate 			/* uid field should be nonempty */
362*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 		/*
365*7c478bd9Sstevel@tonic-gate 		 * The old code (in 2.0 thru 2.5) would check
366*7c478bd9Sstevel@tonic-gate 		 * for the uid being negative, or being greater
367*7c478bd9Sstevel@tonic-gate 		 * than 60001 (the rfs limit).  If it met either of
368*7c478bd9Sstevel@tonic-gate 		 * these conditions, the uid was translated to 60001.
369*7c478bd9Sstevel@tonic-gate 		 *
370*7c478bd9Sstevel@tonic-gate 		 * Now we just check for negative uids; anything else
371*7c478bd9Sstevel@tonic-gate 		 * is administrative policy
372*7c478bd9Sstevel@tonic-gate 		 */
373*7c478bd9Sstevel@tonic-gate 		if (passwd->pw_uid < 0)
374*7c478bd9Sstevel@tonic-gate 			passwd->pw_uid = UID_NOBODY;
375*7c478bd9Sstevel@tonic-gate 	}
376*7c478bd9Sstevel@tonic-gate 	if (*next++ != ':') {
377*7c478bd9Sstevel@tonic-gate 		if (black_magic)
378*7c478bd9Sstevel@tonic-gate 			p = gettok(&next);
379*7c478bd9Sstevel@tonic-gate 		else
380*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
381*7c478bd9Sstevel@tonic-gate 	}
382*7c478bd9Sstevel@tonic-gate 	p = next;					/* gid */
383*7c478bd9Sstevel@tonic-gate 	if (p == 0 || *p == '\0') {
384*7c478bd9Sstevel@tonic-gate 		if (black_magic)
385*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
386*7c478bd9Sstevel@tonic-gate 		else
387*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
388*7c478bd9Sstevel@tonic-gate 	}
389*7c478bd9Sstevel@tonic-gate 	if (!black_magic) {
390*7c478bd9Sstevel@tonic-gate 		passwd->pw_gid = strtol(p, &next, 10);
391*7c478bd9Sstevel@tonic-gate 		if (next == p) {
392*7c478bd9Sstevel@tonic-gate 			/* gid field should be nonempty */
393*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 		/*
396*7c478bd9Sstevel@tonic-gate 		 * gid should be non-negative; anything else
397*7c478bd9Sstevel@tonic-gate 		 * is administrative policy.
398*7c478bd9Sstevel@tonic-gate 		 */
399*7c478bd9Sstevel@tonic-gate 		if (passwd->pw_gid < 0)
400*7c478bd9Sstevel@tonic-gate 			passwd->pw_gid = GID_NOBODY;
401*7c478bd9Sstevel@tonic-gate 	}
402*7c478bd9Sstevel@tonic-gate 	if (*next++ != ':') {
403*7c478bd9Sstevel@tonic-gate 		if (black_magic)
404*7c478bd9Sstevel@tonic-gate 			p = gettok(&next);
405*7c478bd9Sstevel@tonic-gate 		else
406*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	passwd->pw_gecos = passwd->pw_comment = p = gettok(&next);
410*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
411*7c478bd9Sstevel@tonic-gate 		if (black_magic)
412*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
413*7c478bd9Sstevel@tonic-gate 		else
414*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	passwd->pw_dir = p = gettok(&next);
418*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
419*7c478bd9Sstevel@tonic-gate 		if (black_magic)
420*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
421*7c478bd9Sstevel@tonic-gate 		else
422*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	passwd->pw_shell = p = gettok(&next);
426*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
427*7c478bd9Sstevel@tonic-gate 		if (black_magic)
428*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
429*7c478bd9Sstevel@tonic-gate 		else
430*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	/* Better not be any more fields... */
434*7c478bd9Sstevel@tonic-gate 	if (next == 0) {
435*7c478bd9Sstevel@tonic-gate 		/* Successfully parsed and stored */
436*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_SUCCESS);
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_PARSE);
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate typedef const char *constp;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate /*
444*7c478bd9Sstevel@tonic-gate  * Return value 1 means success and more input, 0 means error or no more
445*7c478bd9Sstevel@tonic-gate  */
446*7c478bd9Sstevel@tonic-gate static int
447*7c478bd9Sstevel@tonic-gate getfield(nextp, limit, uns, valp)
448*7c478bd9Sstevel@tonic-gate 	constp		*nextp;
449*7c478bd9Sstevel@tonic-gate 	constp		limit;
450*7c478bd9Sstevel@tonic-gate 	int		uns;
451*7c478bd9Sstevel@tonic-gate 	void		*valp;
452*7c478bd9Sstevel@tonic-gate {
453*7c478bd9Sstevel@tonic-gate 	constp		p = *nextp;
454*7c478bd9Sstevel@tonic-gate 	char		*endfield;
455*7c478bd9Sstevel@tonic-gate 	char		numbuf[12];  /* Holds -2^31 and trailing ':' */
456*7c478bd9Sstevel@tonic-gate 	int		len;
457*7c478bd9Sstevel@tonic-gate 	long		x;
458*7c478bd9Sstevel@tonic-gate 	unsigned long	ux;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	if (p == 0 || p >= limit) {
461*7c478bd9Sstevel@tonic-gate 		return (0);
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 	if (*p == ':') {
464*7c478bd9Sstevel@tonic-gate 		p++;
465*7c478bd9Sstevel@tonic-gate 		*nextp = p;
466*7c478bd9Sstevel@tonic-gate 		return (p < limit);
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 	if ((len = limit - p) > sizeof (numbuf) - 1) {
469*7c478bd9Sstevel@tonic-gate 		len = sizeof (numbuf) - 1;
470*7c478bd9Sstevel@tonic-gate 	}
471*7c478bd9Sstevel@tonic-gate 	/*
472*7c478bd9Sstevel@tonic-gate 	 * We want to use strtol() and we have a readonly non-zero-terminated
473*7c478bd9Sstevel@tonic-gate 	 *   string, so first we copy and terminate the interesting bit.
474*7c478bd9Sstevel@tonic-gate 	 *   Ugh.  (It's convenient to terminate with a colon rather than \0).
475*7c478bd9Sstevel@tonic-gate 	 */
476*7c478bd9Sstevel@tonic-gate 	if ((endfield = memccpy(numbuf, p, ':', len)) == 0) {
477*7c478bd9Sstevel@tonic-gate 		if (len != limit - p) {
478*7c478bd9Sstevel@tonic-gate 			/* Error -- field is too big to be a legit number */
479*7c478bd9Sstevel@tonic-gate 			return (0);
480*7c478bd9Sstevel@tonic-gate 		}
481*7c478bd9Sstevel@tonic-gate 		numbuf[len] = ':';
482*7c478bd9Sstevel@tonic-gate 		p = limit;
483*7c478bd9Sstevel@tonic-gate 	} else {
484*7c478bd9Sstevel@tonic-gate 		p += (endfield - numbuf);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	if (uns) {
487*7c478bd9Sstevel@tonic-gate 		ux = strtoul(numbuf, &endfield, 10);
488*7c478bd9Sstevel@tonic-gate 		if (*endfield != ':') {
489*7c478bd9Sstevel@tonic-gate 			/* Error -- expected <integer><colon> */
490*7c478bd9Sstevel@tonic-gate 			return (0);
491*7c478bd9Sstevel@tonic-gate 		}
492*7c478bd9Sstevel@tonic-gate 		*((unsigned int *)valp) = (unsigned int)ux;
493*7c478bd9Sstevel@tonic-gate 	} else {
494*7c478bd9Sstevel@tonic-gate 		x = strtol(numbuf, &endfield, 10);
495*7c478bd9Sstevel@tonic-gate 		if (*endfield != ':') {
496*7c478bd9Sstevel@tonic-gate 			/* Error -- expected <integer><colon> */
497*7c478bd9Sstevel@tonic-gate 			return (0);
498*7c478bd9Sstevel@tonic-gate 		}
499*7c478bd9Sstevel@tonic-gate 		*((int *)valp) = (int)x;
500*7c478bd9Sstevel@tonic-gate 	}
501*7c478bd9Sstevel@tonic-gate 	*nextp = p;
502*7c478bd9Sstevel@tonic-gate 	return (p < limit);
503*7c478bd9Sstevel@tonic-gate }
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate /*
506*7c478bd9Sstevel@tonic-gate  *  str2spwd() -- convert a string to a shadow passwd entry.  The parser is
507*7c478bd9Sstevel@tonic-gate  *	more liberal than the passwd or group parsers;  since it's legitimate
508*7c478bd9Sstevel@tonic-gate  *	for almost all the fields here to be blank, the parser lets one omit
509*7c478bd9Sstevel@tonic-gate  *	any number of blank fields at the end of the entry.  The acceptable
510*7c478bd9Sstevel@tonic-gate  *	forms for '+' and '-' entries are the same as those for normal entries.
511*7c478bd9Sstevel@tonic-gate  *  === Is this likely to do more harm than good?
512*7c478bd9Sstevel@tonic-gate  *
513*7c478bd9Sstevel@tonic-gate  * Return values: 0 = success, 1 = parse error, 2 = erange ...
514*7c478bd9Sstevel@tonic-gate  * The structure pointer passed in is a structure in the caller's space
515*7c478bd9Sstevel@tonic-gate  * wherein the field pointers would be set to areas in the buffer if
516*7c478bd9Sstevel@tonic-gate  * need be. instring and buffer should be separate areas.
517*7c478bd9Sstevel@tonic-gate  */
518*7c478bd9Sstevel@tonic-gate int
519*7c478bd9Sstevel@tonic-gate str2spwd(instr, lenstr, ent, buffer, buflen)
520*7c478bd9Sstevel@tonic-gate 	const char	*instr;
521*7c478bd9Sstevel@tonic-gate 	int		lenstr;
522*7c478bd9Sstevel@tonic-gate 	void	*ent; /* really (struct spwd *) */
523*7c478bd9Sstevel@tonic-gate 	char	*buffer;
524*7c478bd9Sstevel@tonic-gate 	int	buflen;
525*7c478bd9Sstevel@tonic-gate {
526*7c478bd9Sstevel@tonic-gate 	struct spwd	*shadow	= (struct spwd *)ent;
527*7c478bd9Sstevel@tonic-gate 	const char	*p = instr, *limit;
528*7c478bd9Sstevel@tonic-gate 	char		*bufp;
529*7c478bd9Sstevel@tonic-gate 	int	lencopy, black_magic;
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	limit = p + lenstr;
532*7c478bd9Sstevel@tonic-gate 	if ((p = memchr(instr, ':', lenstr)) == 0 ||
533*7c478bd9Sstevel@tonic-gate 		++p >= limit ||
534*7c478bd9Sstevel@tonic-gate 		(p = memchr(p, ':', limit - p)) == 0) {
535*7c478bd9Sstevel@tonic-gate 		lencopy = lenstr;
536*7c478bd9Sstevel@tonic-gate 		p = 0;
537*7c478bd9Sstevel@tonic-gate 	} else {
538*7c478bd9Sstevel@tonic-gate 		lencopy = p - instr;
539*7c478bd9Sstevel@tonic-gate 		p++;
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 	if (lencopy + 1 > buflen) {
542*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_ERANGE);
543*7c478bd9Sstevel@tonic-gate 	}
544*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, instr, lencopy);
545*7c478bd9Sstevel@tonic-gate 	buffer[lencopy] = 0;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	black_magic = (*instr == '+' || *instr == '-');
548*7c478bd9Sstevel@tonic-gate 	shadow->sp_namp = bufp = buffer;
549*7c478bd9Sstevel@tonic-gate 	shadow->sp_pwdp	= 0;
550*7c478bd9Sstevel@tonic-gate 	shadow->sp_lstchg = -1;
551*7c478bd9Sstevel@tonic-gate 	shadow->sp_min	= -1;
552*7c478bd9Sstevel@tonic-gate 	shadow->sp_max	= -1;
553*7c478bd9Sstevel@tonic-gate 	shadow->sp_warn	= -1;
554*7c478bd9Sstevel@tonic-gate 	shadow->sp_inact = -1;
555*7c478bd9Sstevel@tonic-gate 	shadow->sp_expire = -1;
556*7c478bd9Sstevel@tonic-gate 	shadow->sp_flag	= 0;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 	if ((bufp = strchr(bufp, ':')) == 0) {
559*7c478bd9Sstevel@tonic-gate 		if (black_magic)
560*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
561*7c478bd9Sstevel@tonic-gate 		else
562*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_PARSE);
563*7c478bd9Sstevel@tonic-gate 	}
564*7c478bd9Sstevel@tonic-gate 	*bufp++ = '\0';
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	shadow->sp_pwdp = bufp;
567*7c478bd9Sstevel@tonic-gate 	if (instr == 0) {
568*7c478bd9Sstevel@tonic-gate 		if ((bufp = strchr(bufp, ':')) == 0) {
569*7c478bd9Sstevel@tonic-gate 			if (black_magic)
570*7c478bd9Sstevel@tonic-gate 				return (NSS_STR_PARSE_SUCCESS);
571*7c478bd9Sstevel@tonic-gate 			else
572*7c478bd9Sstevel@tonic-gate 				return (NSS_STR_PARSE_PARSE);
573*7c478bd9Sstevel@tonic-gate 		}
574*7c478bd9Sstevel@tonic-gate 		*bufp++ = '\0';
575*7c478bd9Sstevel@tonic-gate 		p = bufp;
576*7c478bd9Sstevel@tonic-gate 	} /* else p was set when we copied name and passwd into the buffer */
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_lstchg))
579*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
580*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_min))
581*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
582*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_max))
583*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
584*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_warn))
585*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
586*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_inact))
587*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
588*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &shadow->sp_expire))
589*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
590*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 1, &shadow->sp_flag))
591*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_SUCCESS);
592*7c478bd9Sstevel@tonic-gate 	if (p != limit) {
593*7c478bd9Sstevel@tonic-gate 		/* Syntax error -- garbage at end of line */
594*7c478bd9Sstevel@tonic-gate 		return (NSS_STR_PARSE_PARSE);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 	return (NSS_STR_PARSE_SUCCESS);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *buffer;
600*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate #define	GETBUF()	\
603*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_ALLOC(&buffer, sizeof (struct passwd), NSS_BUFLEN_PASSWD)
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate #pragma fini(endutilpwent)
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate static void
608*7c478bd9Sstevel@tonic-gate endutilpwent(void)
609*7c478bd9Sstevel@tonic-gate {
610*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_FREE(&buffer);
611*7c478bd9Sstevel@tonic-gate 	nss_delete(&db_root);
612*7c478bd9Sstevel@tonic-gate }
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate struct passwd *
615*7c478bd9Sstevel@tonic-gate getpwnam_from(const char *name, pwu_repository_t *rep, int reptype)
616*7c478bd9Sstevel@tonic-gate {
617*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t  *b = GETBUF();
618*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	if (b == 0)
621*7c478bd9Sstevel@tonic-gate 		return (0);
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd);
624*7c478bd9Sstevel@tonic-gate 	arg.key.name = name;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	switch (reptype) {
627*7c478bd9Sstevel@tonic-gate 	case REP_LDAP:
628*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_ldap_passwd,
629*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYNAME, &arg);
630*7c478bd9Sstevel@tonic-gate 		break;
631*7c478bd9Sstevel@tonic-gate 	case REP_NISPLUS:
632*7c478bd9Sstevel@tonic-gate 		if (rep && rep->scope)
633*7c478bd9Sstevel@tonic-gate 			return (nisplus_getpw_from_master(name, rep->scope));
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_nisplus_passwd,
636*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYNAME, &arg);
637*7c478bd9Sstevel@tonic-gate 		break;
638*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS
639*7c478bd9Sstevel@tonic-gate 	case REP_NIS:
640*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_nis_passwd,
641*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYNAME, &arg);
642*7c478bd9Sstevel@tonic-gate 		break;
643*7c478bd9Sstevel@tonic-gate #endif
644*7c478bd9Sstevel@tonic-gate 	default:
645*7c478bd9Sstevel@tonic-gate 		return (NULL);
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	return (struct passwd *)NSS_XbyY_FINI(&arg);
649*7c478bd9Sstevel@tonic-gate }
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
652*7c478bd9Sstevel@tonic-gate struct passwd *
653*7c478bd9Sstevel@tonic-gate getpwuid_from(uid_t uid, pwu_repository_t *rep, int reptype)
654*7c478bd9Sstevel@tonic-gate {
655*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t  *b = GETBUF();
656*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	if (b == 0)
659*7c478bd9Sstevel@tonic-gate 		return (0);
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2passwd);
662*7c478bd9Sstevel@tonic-gate 	arg.key.uid = uid;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	switch (reptype) {
665*7c478bd9Sstevel@tonic-gate 	case REP_LDAP:
666*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_ldap_passwd,
667*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYUID, &arg);
668*7c478bd9Sstevel@tonic-gate 		break;
669*7c478bd9Sstevel@tonic-gate 	case REP_NISPLUS:
670*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_nisplus_passwd,
671*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYUID, &arg);
672*7c478bd9Sstevel@tonic-gate 		break;
673*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS
674*7c478bd9Sstevel@tonic-gate 	case REP_NIS:
675*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&db_root, nss_nis_passwd,
676*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_PASSWD_BYUID, &arg);
677*7c478bd9Sstevel@tonic-gate 		break;
678*7c478bd9Sstevel@tonic-gate #endif
679*7c478bd9Sstevel@tonic-gate 	default:
680*7c478bd9Sstevel@tonic-gate 		return (NULL);
681*7c478bd9Sstevel@tonic-gate 	}
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	return (struct passwd *)NSS_XbyY_FINI(&arg);
684*7c478bd9Sstevel@tonic-gate }
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *spbuf;
687*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(spdb_root);
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate #define	GETSPBUF()	\
690*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_ALLOC(&spbuf, sizeof (struct spwd), NSS_BUFLEN_SHADOW)
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate #pragma fini(endutilspent)
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate static void
695*7c478bd9Sstevel@tonic-gate endutilspent(void)
696*7c478bd9Sstevel@tonic-gate {
697*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_FREE(&spbuf);
698*7c478bd9Sstevel@tonic-gate 	nss_delete(&spdb_root);
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate struct spwd *
702*7c478bd9Sstevel@tonic-gate getspnam_from(const char *name, pwu_repository_t *rep, int reptype)
703*7c478bd9Sstevel@tonic-gate {
704*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t  *b = GETSPBUF();
705*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	if (b == 0)
708*7c478bd9Sstevel@tonic-gate 		return (0);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, b->result, b->buffer, b->buflen, str2spwd);
711*7c478bd9Sstevel@tonic-gate 	arg.key.name = name;
712*7c478bd9Sstevel@tonic-gate 	switch (reptype) {
713*7c478bd9Sstevel@tonic-gate 	case REP_LDAP:
714*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&spdb_root, nss_ldap_shadow,
715*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_SHADOW_BYNAME, &arg);
716*7c478bd9Sstevel@tonic-gate 		break;
717*7c478bd9Sstevel@tonic-gate 	case REP_NISPLUS:
718*7c478bd9Sstevel@tonic-gate 		if (rep && rep->scope)
719*7c478bd9Sstevel@tonic-gate 			return (nisplus_getsp_from_master(name, rep->scope));
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&spdb_root, nss_nisplus_shadow,
722*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_SHADOW_BYNAME, &arg);
723*7c478bd9Sstevel@tonic-gate 		break;
724*7c478bd9Sstevel@tonic-gate #ifdef PAM_NIS
725*7c478bd9Sstevel@tonic-gate 	case REP_NIS:
726*7c478bd9Sstevel@tonic-gate 		(void) nss_search(&spdb_root, nss_nis_shadow,
727*7c478bd9Sstevel@tonic-gate 		    NSS_DBOP_SHADOW_BYNAME, &arg);
728*7c478bd9Sstevel@tonic-gate 		break;
729*7c478bd9Sstevel@tonic-gate #endif
730*7c478bd9Sstevel@tonic-gate 	default:
731*7c478bd9Sstevel@tonic-gate 		return (NULL);
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate 	return (struct spwd *)NSS_XbyY_FINI(&arg);
734*7c478bd9Sstevel@tonic-gate }
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate static nis_result *
738*7c478bd9Sstevel@tonic-gate nisplus_match(const char *name, char *domain, char *buf, int len)
739*7c478bd9Sstevel@tonic-gate {
740*7c478bd9Sstevel@tonic-gate 	int n;
741*7c478bd9Sstevel@tonic-gate 	int flags;
742*7c478bd9Sstevel@tonic-gate 	nis_result *res;
743*7c478bd9Sstevel@tonic-gate 	nis_object *object;
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	n = snprintf(buf, len, "[name=%s],passwd.org_dir.%s", name, domain);
746*7c478bd9Sstevel@tonic-gate 	if (n >= len) {
747*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "nisplus_match: name too long");
748*7c478bd9Sstevel@tonic-gate 		return (NULL);
749*7c478bd9Sstevel@tonic-gate 	}
750*7c478bd9Sstevel@tonic-gate 	if (buf[n-1] != '.') {
751*7c478bd9Sstevel@tonic-gate 		if (n == len-1) {
752*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "nisplus_match: name too long");
753*7c478bd9Sstevel@tonic-gate 			return (NULL);
754*7c478bd9Sstevel@tonic-gate 		}
755*7c478bd9Sstevel@tonic-gate 		buf[n++] = '.';
756*7c478bd9Sstevel@tonic-gate 		buf[n] = '\0';
757*7c478bd9Sstevel@tonic-gate 	}
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	flags = USE_DGRAM | FOLLOW_LINKS | FOLLOW_PATH | MASTER_ONLY;
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	res = nis_list(buf, flags, NULL, NULL);
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	if (res == NULL) {
764*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "nisplus_match: nis_list returned NULL");
765*7c478bd9Sstevel@tonic-gate 		return (NULL);
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (NIS_RES_STATUS(res) != NIS_SUCCESS || NIS_RES_NUMOBJ(res) != 1) {
769*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "nisplus_match: match failed: %s",
770*7c478bd9Sstevel@tonic-gate 		    nis_sperrno(NIS_RES_STATUS(res)));
771*7c478bd9Sstevel@tonic-gate 		nis_freeresult(res);
772*7c478bd9Sstevel@tonic-gate 		return (NULL);
773*7c478bd9Sstevel@tonic-gate 	}
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	object = NIS_RES_OBJECT(res);
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	if (object->EN_data.en_cols.en_cols_len < 8) {
778*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "nisplus_match: "
779*7c478bd9Sstevel@tonic-gate 		    "not a valid passwd table entry for user %s", name);
780*7c478bd9Sstevel@tonic-gate 		nis_freeresult(res);
781*7c478bd9Sstevel@tonic-gate 		return (NULL);
782*7c478bd9Sstevel@tonic-gate 	}
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	return (res);
785*7c478bd9Sstevel@tonic-gate }
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate #define	SAFE_STRDUP(dst, idx) \
788*7c478bd9Sstevel@tonic-gate 	if ((idx) <= 3 && ENTRY_VAL(nret, (idx)) == NULL) { \
789*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, \
790*7c478bd9Sstevel@tonic-gate 		    "passwdutil: missing field from password entry"); \
791*7c478bd9Sstevel@tonic-gate 		goto error; \
792*7c478bd9Sstevel@tonic-gate 	} \
793*7c478bd9Sstevel@tonic-gate 	len = ENTRY_LEN(nret, (idx)); \
794*7c478bd9Sstevel@tonic-gate 	(dst) = malloc(len+1); \
795*7c478bd9Sstevel@tonic-gate 	if ((dst) == NULL) { \
796*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "passwdutil: out of memory"); \
797*7c478bd9Sstevel@tonic-gate 		goto error; \
798*7c478bd9Sstevel@tonic-gate 	} \
799*7c478bd9Sstevel@tonic-gate 	(dst)[len] = '\0'; \
800*7c478bd9Sstevel@tonic-gate 	(void) strncpy((dst), \
801*7c478bd9Sstevel@tonic-gate 	    ENTRY_VAL(nret, (idx)) ? ENTRY_VAL(nret, (idx)) : "", \
802*7c478bd9Sstevel@tonic-gate 	    len);
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate static struct passwd *
807*7c478bd9Sstevel@tonic-gate nisplus_getpw_from_master(const char *name, char *domain)
808*7c478bd9Sstevel@tonic-gate {
809*7c478bd9Sstevel@tonic-gate 	char lookup[NIS_MAXNAMELEN+1];
810*7c478bd9Sstevel@tonic-gate 	nis_result *res;
811*7c478bd9Sstevel@tonic-gate 	nis_object *nret;
812*7c478bd9Sstevel@tonic-gate 	int len;
813*7c478bd9Sstevel@tonic-gate 	char *p;
814*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if ((pw = calloc(1, sizeof (*pw))) == NULL)
817*7c478bd9Sstevel@tonic-gate 		return (NULL);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	res = nisplus_match(name, domain, lookup, sizeof (lookup));
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	if (res == NULL)
822*7c478bd9Sstevel@tonic-gate 		return (NULL);
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	nret = NIS_RES_OBJECT(res);
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(pw->pw_name, 0);
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 	if ((pw->pw_passwd = strdup("x")) == NULL) {
829*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "passwdutil: out of memory");
830*7c478bd9Sstevel@tonic-gate 		goto error;
831*7c478bd9Sstevel@tonic-gate 	}
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(p, 2);
834*7c478bd9Sstevel@tonic-gate 	pw->pw_uid = atoi(p);
835*7c478bd9Sstevel@tonic-gate 	free(p);
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(p, 3);
838*7c478bd9Sstevel@tonic-gate 	pw->pw_gid = atoi(p);
839*7c478bd9Sstevel@tonic-gate 	free(p);
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	pw->pw_age = NULL;
842*7c478bd9Sstevel@tonic-gate 	pw->pw_comment = NULL;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/
845*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(pw->pw_gecos, 4);
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/
848*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(pw->pw_dir, 5);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate /*CONSTANTCONDITION*/
851*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(pw->pw_shell, 6);
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	nis_freeresult(res);
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	return (pw);
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate error:
858*7c478bd9Sstevel@tonic-gate 	nis_freeresult(res);
859*7c478bd9Sstevel@tonic-gate 	if (pw->pw_name)
860*7c478bd9Sstevel@tonic-gate 		free(pw->pw_name);
861*7c478bd9Sstevel@tonic-gate 	if (pw->pw_passwd)
862*7c478bd9Sstevel@tonic-gate 		free(pw->pw_passwd);
863*7c478bd9Sstevel@tonic-gate 	if (pw->pw_gecos)
864*7c478bd9Sstevel@tonic-gate 		free(pw->pw_gecos);
865*7c478bd9Sstevel@tonic-gate 	if (pw->pw_dir)
866*7c478bd9Sstevel@tonic-gate 		free(pw->pw_dir);
867*7c478bd9Sstevel@tonic-gate 	if (pw->pw_shell)
868*7c478bd9Sstevel@tonic-gate 		free(pw->pw_shell);
869*7c478bd9Sstevel@tonic-gate 	free(pw);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	return (NULL);
872*7c478bd9Sstevel@tonic-gate }
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate /*
875*7c478bd9Sstevel@tonic-gate  * struct spwd * nisplus_getsp_from_master()
876*7c478bd9Sstevel@tonic-gate  *
877*7c478bd9Sstevel@tonic-gate  * Get the shadow structure from a NIS+ master.
878*7c478bd9Sstevel@tonic-gate  * This routine normally runs with EUID==0. This can cause trouble
879*7c478bd9Sstevel@tonic-gate  * if the NIS+ tables are locked down so that only the owner can
880*7c478bd9Sstevel@tonic-gate  * access the encrypted password. If we detect that scenario, we switch
881*7c478bd9Sstevel@tonic-gate  * EUID to the owner of the record and refetch it.
882*7c478bd9Sstevel@tonic-gate  */
883*7c478bd9Sstevel@tonic-gate static struct spwd *
884*7c478bd9Sstevel@tonic-gate nisplus_getsp_from_master(const char *name, char *domain)
885*7c478bd9Sstevel@tonic-gate {
886*7c478bd9Sstevel@tonic-gate 	char lookup[NIS_MAXNAMELEN+1];
887*7c478bd9Sstevel@tonic-gate 	nis_result *res = NULL;
888*7c478bd9Sstevel@tonic-gate 	nis_object *nret = NULL;
889*7c478bd9Sstevel@tonic-gate 	int len;
890*7c478bd9Sstevel@tonic-gate 	struct spwd *spw;
891*7c478bd9Sstevel@tonic-gate 	char *shadow = NULL;
892*7c478bd9Sstevel@tonic-gate 	const char *p = NULL;
893*7c478bd9Sstevel@tonic-gate 	const char *limit;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	res = nisplus_match(name, domain, lookup, sizeof (lookup));
896*7c478bd9Sstevel@tonic-gate 	if (res == NULL)
897*7c478bd9Sstevel@tonic-gate 		return (NULL);
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	nret = NIS_RES_OBJECT(res);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
902*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(shadow, 7);
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate 	/*
905*7c478bd9Sstevel@tonic-gate 	 * If we got "*NP*" as password, try again with EUID set to
906*7c478bd9Sstevel@tonic-gate 	 * the UID of the record-owner.
907*7c478bd9Sstevel@tonic-gate 	 */
908*7c478bd9Sstevel@tonic-gate 	if (strncmp(shadow, "*NP*", 4) == 0) {
909*7c478bd9Sstevel@tonic-gate 		char *p;
910*7c478bd9Sstevel@tonic-gate 		uid_t owner_uid;
911*7c478bd9Sstevel@tonic-gate 		uid_t euid = geteuid();
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 		SAFE_STRDUP(p, 2);	/* record-owner field */
914*7c478bd9Sstevel@tonic-gate 		owner_uid = atoi(p);
915*7c478bd9Sstevel@tonic-gate 		free(p);
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 		if (owner_uid != euid) {
918*7c478bd9Sstevel@tonic-gate 			/* re-obtain entry using owners EUID */
919*7c478bd9Sstevel@tonic-gate 			free(shadow);
920*7c478bd9Sstevel@tonic-gate 			nis_freeresult(res);
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 			(void) seteuid(owner_uid);
923*7c478bd9Sstevel@tonic-gate 			res = nisplus_match(name, domain, lookup,
924*7c478bd9Sstevel@tonic-gate 			    sizeof (lookup));
925*7c478bd9Sstevel@tonic-gate 			(void) seteuid(euid);
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 			if (res == NULL)
928*7c478bd9Sstevel@tonic-gate 				return (NULL);
929*7c478bd9Sstevel@tonic-gate 			nret = NIS_RES_OBJECT(res);
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 			/*CONSTANTCONDITION*/
932*7c478bd9Sstevel@tonic-gate 			SAFE_STRDUP(shadow, 7);
933*7c478bd9Sstevel@tonic-gate 		}
934*7c478bd9Sstevel@tonic-gate 	}
935*7c478bd9Sstevel@tonic-gate 
936*7c478bd9Sstevel@tonic-gate 	if ((spw = calloc(1, sizeof (*spw))) == NULL) {
937*7c478bd9Sstevel@tonic-gate 		nis_freeresult(res);
938*7c478bd9Sstevel@tonic-gate 		return (NULL);
939*7c478bd9Sstevel@tonic-gate 	}
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(spw->sp_namp, 0);
942*7c478bd9Sstevel@tonic-gate 	SAFE_STRDUP(spw->sp_pwdp, 1);
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	nis_freeresult(res);
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	limit = shadow + strlen(shadow) + 1;
947*7c478bd9Sstevel@tonic-gate 	p = shadow;
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	spw->sp_lstchg = -1;
950*7c478bd9Sstevel@tonic-gate 	spw->sp_min	= -1;
951*7c478bd9Sstevel@tonic-gate 	spw->sp_max	= -1;
952*7c478bd9Sstevel@tonic-gate 	spw->sp_warn	= -1;
953*7c478bd9Sstevel@tonic-gate 	spw->sp_inact = -1;
954*7c478bd9Sstevel@tonic-gate 	spw->sp_expire = -1;
955*7c478bd9Sstevel@tonic-gate 	spw->sp_flag	= 0;
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_lstchg))
958*7c478bd9Sstevel@tonic-gate 		goto out;
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_min))
961*7c478bd9Sstevel@tonic-gate 		goto out;
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_max))
964*7c478bd9Sstevel@tonic-gate 		goto out;
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_warn))
967*7c478bd9Sstevel@tonic-gate 		goto out;
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_inact))
970*7c478bd9Sstevel@tonic-gate 		goto out;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 0, &spw->sp_expire))
973*7c478bd9Sstevel@tonic-gate 		goto out;
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate 	if (!getfield(&p, limit, 1, &spw->sp_flag))
976*7c478bd9Sstevel@tonic-gate 		goto out;
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	if (p != limit) {
979*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "passwdutil: garbage at end of record");
980*7c478bd9Sstevel@tonic-gate 		goto error;
981*7c478bd9Sstevel@tonic-gate 	}
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate out:
984*7c478bd9Sstevel@tonic-gate 	free(shadow);
985*7c478bd9Sstevel@tonic-gate 	return (spw);
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate error:
988*7c478bd9Sstevel@tonic-gate 	if (spw->sp_namp)
989*7c478bd9Sstevel@tonic-gate 		free(spw->sp_namp);
990*7c478bd9Sstevel@tonic-gate 	if (spw->sp_pwdp)
991*7c478bd9Sstevel@tonic-gate 		free(spw->sp_pwdp);
992*7c478bd9Sstevel@tonic-gate 	free(spw);
993*7c478bd9Sstevel@tonic-gate 	if (shadow)
994*7c478bd9Sstevel@tonic-gate 		free(shadow);
995*7c478bd9Sstevel@tonic-gate 	return (NULL);
996*7c478bd9Sstevel@tonic-gate }
997