xref: /illumos-gate/usr/src/lib/libnisdb/yptol/shim_changepasswd.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
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 2003 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 /*
30*7c478bd9Sstevel@tonic-gate  * DESCRIPTION: This is the N2L equivalent of changepasswd.c. The traditional
31*7c478bd9Sstevel@tonic-gate  *		version modifies the NIS source files and then initiates a
32*7c478bd9Sstevel@tonic-gate  *		ypmake to make the maps and push them.
33*7c478bd9Sstevel@tonic-gate  *
34*7c478bd9Sstevel@tonic-gate  *		For N2L there are no source files and the policy is that the
35*7c478bd9Sstevel@tonic-gate  *		definitive information is that contained in the DIT. Old
36*7c478bd9Sstevel@tonic-gate  *		information is read from LDAP. Assuming	this authenticates, and
37*7c478bd9Sstevel@tonic-gate  *		the change is acceptable, this information is modified and
38*7c478bd9Sstevel@tonic-gate  *		written back to LDAP.
39*7c478bd9Sstevel@tonic-gate  *
40*7c478bd9Sstevel@tonic-gate  *		Related map entries are then found and 	updated finally
41*7c478bd9Sstevel@tonic-gate  *		yppushes of the changed maps are initiated. Since the
42*7c478bd9Sstevel@tonic-gate  *		definitive information has already correctly been updated the
43*7c478bd9Sstevel@tonic-gate  *		code is tolerant of some errors during this operation.
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  *		What was previously in the maps is irrelevant.
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  *		Some less than perfect code (like inline constants for
48*7c478bd9Sstevel@tonic-gate  *		return values and a few globals) is retained from the original.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
53*7c478bd9Sstevel@tonic-gate #include <ctype.h>
54*7c478bd9Sstevel@tonic-gate #include <unistd.h>
55*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
56*7c478bd9Sstevel@tonic-gate #include <string.h>
57*7c478bd9Sstevel@tonic-gate #include <stdio.h>
58*7c478bd9Sstevel@tonic-gate #include <errno.h>
59*7c478bd9Sstevel@tonic-gate #include <syslog.h>
60*7c478bd9Sstevel@tonic-gate #include <pwd.h>
61*7c478bd9Sstevel@tonic-gate #include <signal.h>
62*7c478bd9Sstevel@tonic-gate #include <crypt.h>
63*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
64*7c478bd9Sstevel@tonic-gate #include <rpcsvc/yppasswd.h>
65*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
66*7c478bd9Sstevel@tonic-gate #include <shadow.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #include <ndbm.h>
69*7c478bd9Sstevel@tonic-gate /* DO NOT INCLUDE SHIM_HOOKS.H */
70*7c478bd9Sstevel@tonic-gate #include "shim.h"
71*7c478bd9Sstevel@tonic-gate #include "yptol.h"
72*7c478bd9Sstevel@tonic-gate #include "../ldap_util.h"
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /* Constants */
75*7c478bd9Sstevel@tonic-gate #define	CRYPTPWSIZE CRYPT_MAXCIPHERTEXTLEN
76*7c478bd9Sstevel@tonic-gate #define	STRSIZE 100
77*7c478bd9Sstevel@tonic-gate #define	FINGERSIZE (4 * STRSIZE - 4)
78*7c478bd9Sstevel@tonic-gate #define	SHELLSIZE (STRSIZE - 2)
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate #define	UTUSERLEN (sizeof (((struct utmpx *)0)->ut_user))
81*7c478bd9Sstevel@tonic-gate #define	COLON_CHAR ':'
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate /*
84*7c478bd9Sstevel@tonic-gate  * Path to DBM files. This is only required for N2L mode. Traditional mode
85*7c478bd9Sstevel@tonic-gate  * works with the source files and uses the NIS Makefile to generate the maps.
86*7c478bd9Sstevel@tonic-gate  * Seems to be hard coded in the rest of NIS so same is done here.
87*7c478bd9Sstevel@tonic-gate  */
88*7c478bd9Sstevel@tonic-gate #define	YPDBPATH "/var/yp"
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate /* Names of password and adjunct mappings. Used to access DIT */
91*7c478bd9Sstevel@tonic-gate #define	BYNAME ".byname"
92*7c478bd9Sstevel@tonic-gate #define	BYUID ".byuid"
93*7c478bd9Sstevel@tonic-gate #define	BYGID ".bygid"
94*7c478bd9Sstevel@tonic-gate #define	PASSWD_MAPPING "passwd" BYNAME
95*7c478bd9Sstevel@tonic-gate #define	PASSWD_ADJUNCT_MAPPING "passwd.adjunct" BYNAME
96*7c478bd9Sstevel@tonic-gate #define	AGEING_MAPPING "ageing" BYNAME
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /* Bitmasks used in list of fields to change */
99*7c478bd9Sstevel@tonic-gate #define	CNG_PASSWD 	0x0001
100*7c478bd9Sstevel@tonic-gate #define	CNG_SH		0x0002
101*7c478bd9Sstevel@tonic-gate #define	CNG_GECOS	0x0004
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /* Globals :-( */
104*7c478bd9Sstevel@tonic-gate extern int single, nogecos, noshell, nopw, mflag;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate /*
107*7c478bd9Sstevel@tonic-gate  * Structure for containing the information is currently in the DIT. This is
108*7c478bd9Sstevel@tonic-gate  * similar to the passwd structure defined in getpwent(3C) apart from.
109*7c478bd9Sstevel@tonic-gate  *
110*7c478bd9Sstevel@tonic-gate  * 1. Since GID and UID are never changed they are not converted to integers.
111*7c478bd9Sstevel@tonic-gate  * 2. There are extra fields to hold adjunct information.
112*7c478bd9Sstevel@tonic-gate  * 3. There are extra fields to hold widely used information.
113*7c478bd9Sstevel@tonic-gate  */
114*7c478bd9Sstevel@tonic-gate struct passwd_entry {
115*7c478bd9Sstevel@tonic-gate 	char 	*pw_name;
116*7c478bd9Sstevel@tonic-gate 	char 	*pw_passwd;
117*7c478bd9Sstevel@tonic-gate 	char	*pw_uid;
118*7c478bd9Sstevel@tonic-gate 	char	*pw_gid;
119*7c478bd9Sstevel@tonic-gate 	char	*pw_gecos;
120*7c478bd9Sstevel@tonic-gate 	char	*pw_dir;
121*7c478bd9Sstevel@tonic-gate 	char	*pw_shell;
122*7c478bd9Sstevel@tonic-gate 	char	*adjunct_tail;	/* Tail of adjunct entry (opaque) */
123*7c478bd9Sstevel@tonic-gate 	bool_t	adjunct;	/* Flag indicating if DIT has adjunct info */
124*7c478bd9Sstevel@tonic-gate 	char	*pwd_str;	/* New password string */
125*7c478bd9Sstevel@tonic-gate 	char	*adjunct_str;	/* New adjunct string */
126*7c478bd9Sstevel@tonic-gate };
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate /* Prototypes */
129*7c478bd9Sstevel@tonic-gate extern bool_t validloginshell(char *sh, char *arg, int);
130*7c478bd9Sstevel@tonic-gate extern int    validstr(char *str, size_t size);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate suc_code write_shadow_info(char *, struct spwd *);
133*7c478bd9Sstevel@tonic-gate int put_new_info(struct passwd_entry *, char *);
134*7c478bd9Sstevel@tonic-gate char *create_pwd_str(struct passwd_entry *, bool_t);
135*7c478bd9Sstevel@tonic-gate int proc_domain(struct yppasswd *, bool_t, char *);
136*7c478bd9Sstevel@tonic-gate int proc_request(struct yppasswd *, struct passwd_entry *, bool_t, char *);
137*7c478bd9Sstevel@tonic-gate int modify_ent(struct yppasswd *, struct passwd_entry *t, bool_t, char *);
138*7c478bd9Sstevel@tonic-gate int get_change_list(struct yppasswd *, struct passwd_entry *);
139*7c478bd9Sstevel@tonic-gate struct passwd_entry *get_old_info(char *, char *);
140*7c478bd9Sstevel@tonic-gate static char *get_next_token(char *, char **, char *);
141*7c478bd9Sstevel@tonic-gate void free_pwd_entry(struct passwd_entry *);
142*7c478bd9Sstevel@tonic-gate struct spwd *get_old_shadow(char *, char *);
143*7c478bd9Sstevel@tonic-gate suc_code decode_shadow_entry(datum *, struct spwd *);
144*7c478bd9Sstevel@tonic-gate void free_shadow_entry(struct spwd *);
145*7c478bd9Sstevel@tonic-gate int proc_maps(char *, struct passwd_entry *);
146*7c478bd9Sstevel@tonic-gate int proc_map_list(char **, char *, struct passwd_entry *, bool_t);
147*7c478bd9Sstevel@tonic-gate int update_single_map(char *, struct passwd_entry *, bool_t);
148*7c478bd9Sstevel@tonic-gate bool_t strend(char *s1, char *s2);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate /*
151*7c478bd9Sstevel@tonic-gate  * FUNCTION:	shim_changepasswd()
152*7c478bd9Sstevel@tonic-gate  *
153*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	N2L version of changepasswd(). When this is called 'useshadow'
154*7c478bd9Sstevel@tonic-gate  *		etc. will have been set up but are meaningless. We work out
155*7c478bd9Sstevel@tonic-gate  *		what to change based on information from the DIT.
156*7c478bd9Sstevel@tonic-gate  *
157*7c478bd9Sstevel@tonic-gate  * INPUTS:	Identical to changepasswd()
158*7c478bd9Sstevel@tonic-gate  *
159*7c478bd9Sstevel@tonic-gate  * OUTPUTS:	Identical to changepasswd()
160*7c478bd9Sstevel@tonic-gate  */
161*7c478bd9Sstevel@tonic-gate void
162*7c478bd9Sstevel@tonic-gate shim_changepasswd(SVCXPRT *transp)
163*7c478bd9Sstevel@tonic-gate {
164*7c478bd9Sstevel@tonic-gate 	struct yppasswd yppwd;
165*7c478bd9Sstevel@tonic-gate 	bool_t	root_on_master = FALSE;
166*7c478bd9Sstevel@tonic-gate 	char domain[MAXNETNAMELEN+1];
167*7c478bd9Sstevel@tonic-gate 	char **domain_list;
168*7c478bd9Sstevel@tonic-gate 	int dom_count, i;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	int	ret, ans = 2;	/* Answer codes */
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	/* Clean out yppwd ... maybe we don't trust RPC */
173*7c478bd9Sstevel@tonic-gate 	memset(&yppwd, 0, sizeof (struct yppasswd));
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	/* Get the RPC args */
176*7c478bd9Sstevel@tonic-gate 	if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) {
177*7c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
178*7c478bd9Sstevel@tonic-gate 		return;
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	/* Perform basic validation */
182*7c478bd9Sstevel@tonic-gate 	if ((!validstr(yppwd.newpw.pw_passwd, CRYPTPWSIZE)) ||
183*7c478bd9Sstevel@tonic-gate 		(!validstr(yppwd.newpw.pw_name, UTUSERLEN)) ||
184*7c478bd9Sstevel@tonic-gate 		(!validstr(yppwd.newpw.pw_gecos, FINGERSIZE)) ||
185*7c478bd9Sstevel@tonic-gate 		(!validstr(yppwd.newpw.pw_shell, SHELLSIZE))) {
186*7c478bd9Sstevel@tonic-gate 		svcerr_decode(transp);
187*7c478bd9Sstevel@tonic-gate 		return;
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	/*
191*7c478bd9Sstevel@tonic-gate 	 * Special case: root on the master server can change other
192*7c478bd9Sstevel@tonic-gate 	 * users' passwords without first entering the old password.
193*7c478bd9Sstevel@tonic-gate 	 * We need to ensure that this is indeed root on the master
194*7c478bd9Sstevel@tonic-gate 	 * server. (bug 1253949)
195*7c478bd9Sstevel@tonic-gate 	 */
196*7c478bd9Sstevel@tonic-gate 	if (strcmp(transp->xp_netid, "ticlts") == 0) {
197*7c478bd9Sstevel@tonic-gate 		svc_local_cred_t cred;
198*7c478bd9Sstevel@tonic-gate 		if (!svc_get_local_cred(transp, &cred)) {
199*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
200*7c478bd9Sstevel@tonic-gate 					"Couldn't get local user credentials");
201*7c478bd9Sstevel@tonic-gate 		} else if (cred.ruid == 0)
202*7c478bd9Sstevel@tonic-gate 			root_on_master = TRUE;
203*7c478bd9Sstevel@tonic-gate 	}
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 	/*
206*7c478bd9Sstevel@tonic-gate 	 * Get the domain name. This is tricky because a N2L server may be
207*7c478bd9Sstevel@tonic-gate 	 * handling multiple domains. There is nothing in the request to
208*7c478bd9Sstevel@tonic-gate 	 * indicate which one we are trying to change a passwd for. First
209*7c478bd9Sstevel@tonic-gate 	 * we try to get a list of password related domains from the mapping
210*7c478bd9Sstevel@tonic-gate 	 * file.
211*7c478bd9Sstevel@tonic-gate 	 */
212*7c478bd9Sstevel@tonic-gate 	if (0 != (dom_count = get_mapping_domain_list(&domain_list))) {
213*7c478bd9Sstevel@tonic-gate 		/* Got a domain list ... process all the domains */
214*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < dom_count; i ++) {
215*7c478bd9Sstevel@tonic-gate 			ret = proc_domain(&yppwd, root_on_master,
216*7c478bd9Sstevel@tonic-gate 								domain_list[i]);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 			/* If one has worked don't care if others fail */
219*7c478bd9Sstevel@tonic-gate 			if (0 != ans)
220*7c478bd9Sstevel@tonic-gate 				ans = ret;
221*7c478bd9Sstevel@tonic-gate 		}
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate 	else
224*7c478bd9Sstevel@tonic-gate 	{
225*7c478bd9Sstevel@tonic-gate 		/*
226*7c478bd9Sstevel@tonic-gate 		 * There was no domain list in the mapping file. The
227*7c478bd9Sstevel@tonic-gate 		 * traditional version of this code calls ypmake which picks
228*7c478bd9Sstevel@tonic-gate 		 * up the domain returned by getdomainname(). Fall back to the
229*7c478bd9Sstevel@tonic-gate 		 * same mechanism.
230*7c478bd9Sstevel@tonic-gate 		 */
231*7c478bd9Sstevel@tonic-gate 		if (0 > getdomainname(domain, MAXNETNAMELEN+1)) {
232*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
233*7c478bd9Sstevel@tonic-gate 					"Could not get any domain info");
234*7c478bd9Sstevel@tonic-gate 		} else {
235*7c478bd9Sstevel@tonic-gate 			/* Got one domain ... process it. */
236*7c478bd9Sstevel@tonic-gate 			ans = proc_domain(&yppwd, root_on_master, domain);
237*7c478bd9Sstevel@tonic-gate 		}
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	/* Send reply packet */
241*7c478bd9Sstevel@tonic-gate 	if (!svc_sendreply(transp, xdr_int, (char *)&ans))
242*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
243*7c478bd9Sstevel@tonic-gate 						"could not reply to RPC call");
244*7c478bd9Sstevel@tonic-gate }
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate /*
247*7c478bd9Sstevel@tonic-gate  * FUNCTION : 	proc_domain()
248*7c478bd9Sstevel@tonic-gate  *
249*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Process a request for one domain
250*7c478bd9Sstevel@tonic-gate  *
251*7c478bd9Sstevel@tonic-gate  * GIVEN :	Pointer to the request.
252*7c478bd9Sstevel@tonic-gate  *		Root on master flag
253*7c478bd9Sstevel@tonic-gate  *		Domain
254*7c478bd9Sstevel@tonic-gate  *
255*7c478bd9Sstevel@tonic-gate  * OUTPUTS :	Answer code for reply
256*7c478bd9Sstevel@tonic-gate  */
257*7c478bd9Sstevel@tonic-gate int
258*7c478bd9Sstevel@tonic-gate proc_domain(struct yppasswd *yppwd, bool_t root_on_master, char *domain)
259*7c478bd9Sstevel@tonic-gate {
260*7c478bd9Sstevel@tonic-gate 	struct passwd_entry *old_pwd;
261*7c478bd9Sstevel@tonic-gate 	char	*p;
262*7c478bd9Sstevel@tonic-gate 	int ans = 2;
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 	/* security hole fix from original source */
265*7c478bd9Sstevel@tonic-gate 	for (p = yppwd->newpw.pw_name; (*p != '\0'); p++)
266*7c478bd9Sstevel@tonic-gate 		if ((*p == ':') || !(isprint(*p)))
267*7c478bd9Sstevel@tonic-gate 			*p = '$';	/* you lose buckwheat */
268*7c478bd9Sstevel@tonic-gate 	for (p = yppwd->newpw.pw_passwd; (*p != '\0'); p++)
269*7c478bd9Sstevel@tonic-gate 		if ((*p == ':') || !(isprint(*p)))
270*7c478bd9Sstevel@tonic-gate 			*p = '$';	/* you lose buckwheat */
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	/* Get old info from DIT for this domain */
273*7c478bd9Sstevel@tonic-gate 	old_pwd = get_old_info(yppwd->newpw.pw_name, domain);
274*7c478bd9Sstevel@tonic-gate 	if (NULL ==  old_pwd) {
275*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
276*7c478bd9Sstevel@tonic-gate 				"Could not get old information for %s in "
277*7c478bd9Sstevel@tonic-gate 				"domain %s", yppwd->newpw.pw_name, domain);
278*7c478bd9Sstevel@tonic-gate 		return (ans);
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	/* Have a request that can be replied to */
282*7c478bd9Sstevel@tonic-gate 	ans = proc_request(yppwd, old_pwd, root_on_master, domain);
283*7c478bd9Sstevel@tonic-gate 	free_pwd_entry(old_pwd);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	return (ans);
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * FUNCTION :	proc_request()
290*7c478bd9Sstevel@tonic-gate  *
291*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Process a request
292*7c478bd9Sstevel@tonic-gate  *
293*7c478bd9Sstevel@tonic-gate  * GIVEN :	Pointer to the request.
294*7c478bd9Sstevel@tonic-gate  *		Pointer to old information from LDAP
295*7c478bd9Sstevel@tonic-gate  *		Root on master flag
296*7c478bd9Sstevel@tonic-gate  *		Domain
297*7c478bd9Sstevel@tonic-gate  *
298*7c478bd9Sstevel@tonic-gate  * OUTPUTS :	Answer code for reply
299*7c478bd9Sstevel@tonic-gate  */
300*7c478bd9Sstevel@tonic-gate int
301*7c478bd9Sstevel@tonic-gate proc_request(struct yppasswd *yppwd, struct passwd_entry *old_pwd,
302*7c478bd9Sstevel@tonic-gate 					bool_t root_on_master, char *domain)
303*7c478bd9Sstevel@tonic-gate {
304*7c478bd9Sstevel@tonic-gate 	struct sigaction sa, osa1, osa2, osa3;
305*7c478bd9Sstevel@tonic-gate 	int	ans;
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	/* Authenticate */
308*7c478bd9Sstevel@tonic-gate 	if ((0 != strcmp(crypt(yppwd->oldpass, old_pwd->pw_passwd),
309*7c478bd9Sstevel@tonic-gate 				old_pwd->pw_passwd)) && !root_on_master) {
310*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_NOTICE, "Passwd incorrect %s",
311*7c478bd9Sstevel@tonic-gate 						yppwd->newpw.pw_name);
312*7c478bd9Sstevel@tonic-gate 		return (7);
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	/* Work out what we have to change and change it */
316*7c478bd9Sstevel@tonic-gate 	ans = modify_ent(yppwd, old_pwd, root_on_master, domain);
317*7c478bd9Sstevel@tonic-gate 	if (0 != ans)
318*7c478bd9Sstevel@tonic-gate 		return (ans);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	/*
321*7c478bd9Sstevel@tonic-gate 	 * Generate passwd and adjunct map entries. This creates extra
322*7c478bd9Sstevel@tonic-gate 	 * malloced strings in old_pwd. These will be freed when
323*7c478bd9Sstevel@tonic-gate 	 * free_pwd_entry() is called to free up the rest of the structure.
324*7c478bd9Sstevel@tonic-gate 	 */
325*7c478bd9Sstevel@tonic-gate 	old_pwd->pwd_str = create_pwd_str(old_pwd, FALSE);
326*7c478bd9Sstevel@tonic-gate 	if (NULL == old_pwd->pwd_str) {
327*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
328*7c478bd9Sstevel@tonic-gate 					"Could not create passwd entry");
329*7c478bd9Sstevel@tonic-gate 		return (2);
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 	if (old_pwd->adjunct) {
332*7c478bd9Sstevel@tonic-gate 		old_pwd->adjunct_str = create_pwd_str(old_pwd, TRUE);
333*7c478bd9Sstevel@tonic-gate 		if (NULL == old_pwd->adjunct_str) {
334*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
335*7c478bd9Sstevel@tonic-gate 					"Could not create adjunct entry");
336*7c478bd9Sstevel@tonic-gate 			return (2);
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 	} else {
339*7c478bd9Sstevel@tonic-gate 		old_pwd->adjunct_str = NULL;
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	/* Put the information back to DIT */
343*7c478bd9Sstevel@tonic-gate 	ans = put_new_info(old_pwd, domain);
344*7c478bd9Sstevel@tonic-gate 	if (0 != ans) {
345*7c478bd9Sstevel@tonic-gate 		return (ans);
346*7c478bd9Sstevel@tonic-gate 	}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	/* Are going to be forking pushes, set up signals */
349*7c478bd9Sstevel@tonic-gate 	memset(&sa, 0, sizeof (struct sigaction));
350*7c478bd9Sstevel@tonic-gate 	sa.sa_handler = SIG_IGN;
351*7c478bd9Sstevel@tonic-gate 	sigaction(SIGTSTP, &sa, (struct sigaction *)0);
352*7c478bd9Sstevel@tonic-gate 	sigaction(SIGHUP,  &sa, &osa1);
353*7c478bd9Sstevel@tonic-gate 	sigaction(SIGINT,  &sa, &osa2);
354*7c478bd9Sstevel@tonic-gate 	sigaction(SIGQUIT, &sa, &osa3);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	/* Update and push all the maps */
357*7c478bd9Sstevel@tonic-gate 	ans = proc_maps(domain, old_pwd);
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 	/* Tidy up signals */
360*7c478bd9Sstevel@tonic-gate 	sigaction(SIGHUP,  &osa1, (struct sigaction *)0);
361*7c478bd9Sstevel@tonic-gate 	sigaction(SIGINT,  &osa2, (struct sigaction *)0);
362*7c478bd9Sstevel@tonic-gate 	sigaction(SIGQUIT, &osa3, (struct sigaction *)0);
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 	return (ans);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * FUNCTION:	proc_maps()
369*7c478bd9Sstevel@tonic-gate  *
370*7c478bd9Sstevel@tonic-gate  * DESCRIPTION: Gets all the map lists and processes them.
371*7c478bd9Sstevel@tonic-gate  *
372*7c478bd9Sstevel@tonic-gate  * INPUTS:	Domain name
373*7c478bd9Sstevel@tonic-gate  *		New info to write into maps
374*7c478bd9Sstevel@tonic-gate  *
375*7c478bd9Sstevel@tonic-gate  * OUTPUT :	Answer code
376*7c478bd9Sstevel@tonic-gate  */
377*7c478bd9Sstevel@tonic-gate int
378*7c478bd9Sstevel@tonic-gate proc_maps(char *domain, struct passwd_entry *pwd)
379*7c478bd9Sstevel@tonic-gate {
380*7c478bd9Sstevel@tonic-gate 	char	**map_list; 	/* Array of passwd or adjunct maps */
381*7c478bd9Sstevel@tonic-gate 	int	ans = 0;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/* Get list of passwd maps from mapping file */
384*7c478bd9Sstevel@tonic-gate 	map_list = get_passwd_list(FALSE, domain);
385*7c478bd9Sstevel@tonic-gate 	if (map_list != NULL) {
386*7c478bd9Sstevel@tonic-gate 		/* Process list of passwd maps */
387*7c478bd9Sstevel@tonic-gate 		ans = proc_map_list(map_list, domain, pwd, FALSE);
388*7c478bd9Sstevel@tonic-gate 		free_passwd_list(map_list);
389*7c478bd9Sstevel@tonic-gate 		if (0 != ans)
390*7c478bd9Sstevel@tonic-gate 			return (ans);
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	/*
394*7c478bd9Sstevel@tonic-gate 	 * If we get here either there were no passwd maps or there were
395*7c478bd9Sstevel@tonic-gate 	 * some and they were processed successfully. Either case is good
396*7c478bd9Sstevel@tonic-gate 	 * continue and process passwd.adjunct maps.
397*7c478bd9Sstevel@tonic-gate 	 */
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	/* Get list of adjunct maps from mapping file */
400*7c478bd9Sstevel@tonic-gate 	map_list = get_passwd_list(TRUE, domain);
401*7c478bd9Sstevel@tonic-gate 	if (map_list != NULL) {
402*7c478bd9Sstevel@tonic-gate 		/*
403*7c478bd9Sstevel@tonic-gate 		 * Process list of adjunct maps. If the required information
404*7c478bd9Sstevel@tonic-gate 		 * is not present in LDAP then the updates attempts will log
405*7c478bd9Sstevel@tonic-gate 		 * an error. No need to make the check here
406*7c478bd9Sstevel@tonic-gate 		 */
407*7c478bd9Sstevel@tonic-gate 		ans = proc_map_list(map_list, domain, pwd, TRUE);
408*7c478bd9Sstevel@tonic-gate 		free_passwd_list(map_list);
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	return (ans);
412*7c478bd9Sstevel@tonic-gate }
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate /*
415*7c478bd9Sstevel@tonic-gate  * FUNCTION:	proc_map_list()
416*7c478bd9Sstevel@tonic-gate  *
417*7c478bd9Sstevel@tonic-gate  * DESCRIPTION: Finds entries in one list of map that need to be updated.
418*7c478bd9Sstevel@tonic-gate  *		updates them and writes them back.
419*7c478bd9Sstevel@tonic-gate  *
420*7c478bd9Sstevel@tonic-gate  * INPUTS:	Null terminated list of maps to process.
421*7c478bd9Sstevel@tonic-gate  *		Domain name
422*7c478bd9Sstevel@tonic-gate  *		Information to write (including user name)
423*7c478bd9Sstevel@tonic-gate  *		Flag indicating if this is the adjunct list
424*7c478bd9Sstevel@tonic-gate  *
425*7c478bd9Sstevel@tonic-gate  * OUTPUTS:	An error code
426*7c478bd9Sstevel@tonic-gate  */
427*7c478bd9Sstevel@tonic-gate int
428*7c478bd9Sstevel@tonic-gate proc_map_list(char **map_list, char *domain,
429*7c478bd9Sstevel@tonic-gate 				struct passwd_entry *pwd, bool_t adjunct_flag)
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate 	char 	*myself = "proc_map_list";
432*7c478bd9Sstevel@tonic-gate 	char	*map_name;
433*7c478bd9Sstevel@tonic-gate 	char	cmdbuf[BUFSIZ];
434*7c478bd9Sstevel@tonic-gate 	int	map_name_len = 0;
435*7c478bd9Sstevel@tonic-gate 	int	index, ans = 0;
436*7c478bd9Sstevel@tonic-gate 	int	res;
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	/* If this is a adjunct list check LDAP had some adjunct info */
439*7c478bd9Sstevel@tonic-gate 	if ((adjunct_flag) && (!pwd->adjunct)) {
440*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
441*7c478bd9Sstevel@tonic-gate 			"Have adjunct map list but no adjunct data in DIT");
442*7c478bd9Sstevel@tonic-gate 		/* Not a disaster */
443*7c478bd9Sstevel@tonic-gate 		return (0);
444*7c478bd9Sstevel@tonic-gate 	}
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	/* Allocate enough buffer to take longest map name */
447*7c478bd9Sstevel@tonic-gate 	for (index = 0; map_list[index] != NULL; index ++)
448*7c478bd9Sstevel@tonic-gate 		if (map_name_len < strlen(map_list[index]))
449*7c478bd9Sstevel@tonic-gate 			map_name_len = strlen(map_list[index]);
450*7c478bd9Sstevel@tonic-gate 	map_name_len += strlen(YPDBPATH);
451*7c478bd9Sstevel@tonic-gate 	map_name_len += strlen(NTOL_PREFIX);
452*7c478bd9Sstevel@tonic-gate 	map_name_len += strlen(domain);
453*7c478bd9Sstevel@tonic-gate 	map_name_len += 3;
454*7c478bd9Sstevel@tonic-gate 	if (NULL == (map_name = am(myself, map_name_len))) {
455*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc map name");
456*7c478bd9Sstevel@tonic-gate 		return (2);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	/* For all maps in list */
460*7c478bd9Sstevel@tonic-gate 	for (index = 0; map_list[index] != NULL; index ++) {
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 		/* Generate full map name */
463*7c478bd9Sstevel@tonic-gate 		strcpy(map_name, YPDBPATH);
464*7c478bd9Sstevel@tonic-gate 		add_separator(map_name);
465*7c478bd9Sstevel@tonic-gate 		strcat(map_name, domain);
466*7c478bd9Sstevel@tonic-gate 		add_separator(map_name);
467*7c478bd9Sstevel@tonic-gate 		strcat(map_name, NTOL_PREFIX);
468*7c478bd9Sstevel@tonic-gate 		strcat(map_name, map_list[index]);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		if (0 != (ans = update_single_map(map_name, pwd, adjunct_flag)))
471*7c478bd9Sstevel@tonic-gate 			break;
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	/* Done with full map path */
475*7c478bd9Sstevel@tonic-gate 	sfree(map_name);
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	/*
478*7c478bd9Sstevel@tonic-gate 	 * If (ans != 0) then one more maps have failed. LDAP has however been
479*7c478bd9Sstevel@tonic-gate 	 * updates. This is the definitive source for information there is no
480*7c478bd9Sstevel@tonic-gate 	 * need to unwind. (This was probably due to maps that were already
481*7c478bd9Sstevel@tonic-gate 	 * corrupt).
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/*
485*7c478bd9Sstevel@tonic-gate 	 * If it all worked fork off push operations for the maps. Since we
486*7c478bd9Sstevel@tonic-gate 	 * want the map to end up with it's traditional name on the slave send
487*7c478bd9Sstevel@tonic-gate 	 * the name without its LDAP_ prefix. The slave will call ypxfrd
488*7c478bd9Sstevel@tonic-gate 	 * which, since it is running in N2L mode, will put the prefix back on
489*7c478bd9Sstevel@tonic-gate 	 * before reading the file.
490*7c478bd9Sstevel@tonic-gate 	 */
491*7c478bd9Sstevel@tonic-gate 	if (mflag && (0 == ans)) {
492*7c478bd9Sstevel@tonic-gate 		for (index = 0; (map_name = map_list[index]) != NULL;
493*7c478bd9Sstevel@tonic-gate 								index ++) {
494*7c478bd9Sstevel@tonic-gate 			if (fork() == 0) {
495*7c478bd9Sstevel@tonic-gate 				/*
496*7c478bd9Sstevel@tonic-gate 				 * Define full path to yppush. Probably also
497*7c478bd9Sstevel@tonic-gate 				 * best for security.
498*7c478bd9Sstevel@tonic-gate 				 */
499*7c478bd9Sstevel@tonic-gate 				strcpy(cmdbuf, "/usr/lib/netsvc/yp/yppush ");
500*7c478bd9Sstevel@tonic-gate 				strcat(cmdbuf, map_name);
501*7c478bd9Sstevel@tonic-gate 				if (0 > system(cmdbuf))
502*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
503*7c478bd9Sstevel@tonic-gate 						"Could not initiate yppush");
504*7c478bd9Sstevel@tonic-gate 				exit(0);
505*7c478bd9Sstevel@tonic-gate 			}
506*7c478bd9Sstevel@tonic-gate 		}
507*7c478bd9Sstevel@tonic-gate 	}
508*7c478bd9Sstevel@tonic-gate 	return (ans);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate /*
512*7c478bd9Sstevel@tonic-gate  * FUNCTION :	update_single_map()
513*7c478bd9Sstevel@tonic-gate  *
514*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Updates one map. This is messy because we want to lock the map
515*7c478bd9Sstevel@tonic-gate  *		to prevent other processes from updating it at the same time.
516*7c478bd9Sstevel@tonic-gate  *		This mandates that we open it using the shim. When we
517*7c478bd9Sstevel@tonic-gate  *		write to it however we DO NOT want to write through to LDAP
518*7c478bd9Sstevel@tonic-gate  *		i.e. do not want to use the shim.
519*7c478bd9Sstevel@tonic-gate  *
520*7c478bd9Sstevel@tonic-gate  *		Solution : Do not include shim_hooks.h but call the shim
521*7c478bd9Sstevel@tonic-gate  *		versions of dbm_functions explicitly where needed.
522*7c478bd9Sstevel@tonic-gate  *
523*7c478bd9Sstevel@tonic-gate  * INPUT :	Full name of map
524*7c478bd9Sstevel@tonic-gate  *		Information to write (including user name)
525*7c478bd9Sstevel@tonic-gate  *		Flag indicating if this is an adjunct map.
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * OUTPUT :	Answer code
528*7c478bd9Sstevel@tonic-gate  *
529*7c478bd9Sstevel@tonic-gate  */
530*7c478bd9Sstevel@tonic-gate int
531*7c478bd9Sstevel@tonic-gate update_single_map(char *map_name, struct passwd_entry *pwd, bool_t adjunct_flag)
532*7c478bd9Sstevel@tonic-gate {
533*7c478bd9Sstevel@tonic-gate 	DBM	*map;
534*7c478bd9Sstevel@tonic-gate 	int	res;
535*7c478bd9Sstevel@tonic-gate 	datum	data, key;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	/* Set up data */
538*7c478bd9Sstevel@tonic-gate 	if (adjunct_flag)
539*7c478bd9Sstevel@tonic-gate 		data.dptr = pwd->adjunct_str;
540*7c478bd9Sstevel@tonic-gate 	else
541*7c478bd9Sstevel@tonic-gate 		data.dptr = pwd->pwd_str;
542*7c478bd9Sstevel@tonic-gate 	data.dsize = strlen(data.dptr);
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	/* Set up key dependent on which type of map this is */
545*7c478bd9Sstevel@tonic-gate 	key.dptr = NULL;
546*7c478bd9Sstevel@tonic-gate 	if (strend(map_name, BYNAME))
547*7c478bd9Sstevel@tonic-gate 		key.dptr = pwd->pw_name;
548*7c478bd9Sstevel@tonic-gate 	if (strend(map_name, BYUID))
549*7c478bd9Sstevel@tonic-gate 		key.dptr = pwd->pw_uid;
550*7c478bd9Sstevel@tonic-gate 	if (strend(map_name, BYGID))
551*7c478bd9Sstevel@tonic-gate 		key.dptr = pwd->pw_gid;
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	if (NULL == key.dptr) {
554*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
555*7c478bd9Sstevel@tonic-gate 					"Unrecognized map type %s", map_name);
556*7c478bd9Sstevel@tonic-gate 		return (0);		/* Next map */
557*7c478bd9Sstevel@tonic-gate 	}
558*7c478bd9Sstevel@tonic-gate 	key.dsize = strlen(key.dptr);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	/* Open the map */
561*7c478bd9Sstevel@tonic-gate 	map = shim_dbm_open(map_name, O_RDWR, 0600);
562*7c478bd9Sstevel@tonic-gate 	if (NULL == map) {
563*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not open %s", map_name);
564*7c478bd9Sstevel@tonic-gate 		return (0);		/* Next map */
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	/* Lock map for update. Painful and may block but have to do it */
568*7c478bd9Sstevel@tonic-gate 	if (SUCCESS != lock_map_update((map_ctrl *)map)) {
569*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
570*7c478bd9Sstevel@tonic-gate 				"Could not lock map %s for update", map_name);
571*7c478bd9Sstevel@tonic-gate 		shim_dbm_close(map);
572*7c478bd9Sstevel@tonic-gate 		return (2);
573*7c478bd9Sstevel@tonic-gate 	}
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	/* Do the update use simple DBM operation */
576*7c478bd9Sstevel@tonic-gate 	res = dbm_store(((map_ctrl *)map)->entries, key, data, DBM_REPLACE);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/* update entry TTL. If we fail not a problem will just timeout early */
579*7c478bd9Sstevel@tonic-gate 	update_entry_ttl((map_ctrl *)map, &key, TTL_RAND);
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	/*
582*7c478bd9Sstevel@tonic-gate 	 * Map has been modified so update YP_LAST_MODIFIED. In the vanilla
583*7c478bd9Sstevel@tonic-gate 	 * NIS case this would have been done by the ypmake done after updating
584*7c478bd9Sstevel@tonic-gate 	 * the passwd source file. If this fails not a great problem the map
585*7c478bd9Sstevel@tonic-gate 	 */
586*7c478bd9Sstevel@tonic-gate 	if (FAILURE == update_timestamp(((map_ctrl *)map)->entries)) {
587*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not update "
588*7c478bd9Sstevel@tonic-gate 			"YP_LAST_MODIFIED %s will not be pushed this time",
589*7c478bd9Sstevel@tonic-gate 			map_name);
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 	/*
593*7c478bd9Sstevel@tonic-gate 	 * Possibly should hold the lock until after push is complete
594*7c478bd9Sstevel@tonic-gate 	 * but this could deadlock if client is slow and ypxfrd also
595*7c478bd9Sstevel@tonic-gate 	 * decides to do an update.
596*7c478bd9Sstevel@tonic-gate 	 */
597*7c478bd9Sstevel@tonic-gate 	unlock_map_update((map_ctrl *)map);
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	/* Close the map */
600*7c478bd9Sstevel@tonic-gate 	shim_dbm_close(map);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if (0 != res) {
603*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
604*7c478bd9Sstevel@tonic-gate 					"Could not update map %s", map_name);
605*7c478bd9Sstevel@tonic-gate 		return (2);
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	return (0);
609*7c478bd9Sstevel@tonic-gate }
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate /*
612*7c478bd9Sstevel@tonic-gate  * FUNCTION :	strend()
613*7c478bd9Sstevel@tonic-gate  *
614*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Determines if one string ends with another.
615*7c478bd9Sstevel@tonic-gate  */
616*7c478bd9Sstevel@tonic-gate bool_t
617*7c478bd9Sstevel@tonic-gate strend(char *s1, char *s2)
618*7c478bd9Sstevel@tonic-gate {
619*7c478bd9Sstevel@tonic-gate 	int len_dif;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	len_dif = strlen(s1) - strlen(s2);
622*7c478bd9Sstevel@tonic-gate 	if (0 > len_dif)
623*7c478bd9Sstevel@tonic-gate 		return (FALSE);
624*7c478bd9Sstevel@tonic-gate 	if (0 == strcmp(s1 + len_dif, s2))
625*7c478bd9Sstevel@tonic-gate 		return (TRUE);
626*7c478bd9Sstevel@tonic-gate 	return (FALSE);
627*7c478bd9Sstevel@tonic-gate }
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate /*
630*7c478bd9Sstevel@tonic-gate  * FUNCTION:	modify_ent()
631*7c478bd9Sstevel@tonic-gate  *
632*7c478bd9Sstevel@tonic-gate  * DESCRIPTION: Modify an entry to reflect a request.
633*7c478bd9Sstevel@tonic-gate  *
634*7c478bd9Sstevel@tonic-gate  * INPUT:	Pointer to the request.
635*7c478bd9Sstevel@tonic-gate  *		Pointer to the entry to modify.
636*7c478bd9Sstevel@tonic-gate  *		Flag indication if we are root on master
637*7c478bd9Sstevel@tonic-gate  *		Domain
638*7c478bd9Sstevel@tonic-gate  *
639*7c478bd9Sstevel@tonic-gate  * OUTPUT:	Error code
640*7c478bd9Sstevel@tonic-gate  */
641*7c478bd9Sstevel@tonic-gate int
642*7c478bd9Sstevel@tonic-gate modify_ent(struct yppasswd *yppwd, struct passwd_entry *old_ent,
643*7c478bd9Sstevel@tonic-gate 					bool_t root_on_master, char *domain)
644*7c478bd9Sstevel@tonic-gate {
645*7c478bd9Sstevel@tonic-gate 	int change_list;
646*7c478bd9Sstevel@tonic-gate 	struct spwd *shadow;
647*7c478bd9Sstevel@tonic-gate 	time_t now;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	/* Get list of changes */
650*7c478bd9Sstevel@tonic-gate 	change_list = get_change_list(yppwd, old_ent);
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 	if (!change_list) {
653*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_NOTICE,
654*7c478bd9Sstevel@tonic-gate 				"No change for %s", yppwd->newpw.pw_name);
655*7c478bd9Sstevel@tonic-gate 		return (3);
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	/* Check that the shell we have been given is acceptable. */
659*7c478bd9Sstevel@tonic-gate 	if ((change_list & CNG_SH) && (!validloginshell(old_ent->pw_shell,
660*7c478bd9Sstevel@tonic-gate 					yppwd->newpw.pw_shell, root_on_master)))
661*7c478bd9Sstevel@tonic-gate 		return (2);
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	/*
664*7c478bd9Sstevel@tonic-gate 	 * If changing the password do any aging checks.
665*7c478bd9Sstevel@tonic-gate 	 * Since there are no shadow maps this is done by accessing
666*7c478bd9Sstevel@tonic-gate 	 * attributes in the DIT via the mapping system.
667*7c478bd9Sstevel@tonic-gate 	 */
668*7c478bd9Sstevel@tonic-gate 	if (change_list & CNG_PASSWD) {
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		/* Try to get shadow information */
671*7c478bd9Sstevel@tonic-gate 		shadow = get_old_shadow(yppwd->newpw.pw_name, domain);
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 		/* If there is shadow information make password aging checks */
674*7c478bd9Sstevel@tonic-gate 		if (NULL != shadow) {
675*7c478bd9Sstevel@tonic-gate 			now = DAY_NOW;
676*7c478bd9Sstevel@tonic-gate 			/* password aging - bug for bug compatibility */
677*7c478bd9Sstevel@tonic-gate 			if (shadow->sp_max != -1) {
678*7c478bd9Sstevel@tonic-gate 				if (now < shadow->sp_lstchg + shadow->sp_min) {
679*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
680*7c478bd9Sstevel@tonic-gate 					"Sorry: < %ld days since "
681*7c478bd9Sstevel@tonic-gate 					"the last change", shadow->sp_min);
682*7c478bd9Sstevel@tonic-gate 					free_shadow_entry(shadow);
683*7c478bd9Sstevel@tonic-gate 					return (2);
684*7c478bd9Sstevel@tonic-gate 				}
685*7c478bd9Sstevel@tonic-gate 		}
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 			/* Update time of change */
688*7c478bd9Sstevel@tonic-gate 			shadow->sp_lstchg = now;
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 			/* Write it back */
691*7c478bd9Sstevel@tonic-gate 			write_shadow_info(domain, shadow);
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 			free_shadow_entry(shadow);
694*7c478bd9Sstevel@tonic-gate 		}
695*7c478bd9Sstevel@tonic-gate 	}
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	/* Make changes to old entity */
698*7c478bd9Sstevel@tonic-gate 	if (change_list & CNG_GECOS) {
699*7c478bd9Sstevel@tonic-gate 		if (NULL != old_ent->pw_gecos)
700*7c478bd9Sstevel@tonic-gate 			sfree(old_ent->pw_gecos);
701*7c478bd9Sstevel@tonic-gate 		old_ent->pw_gecos = strdup(yppwd->newpw.pw_gecos);
702*7c478bd9Sstevel@tonic-gate 		if (NULL == old_ent->pw_gecos) {
703*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate gecos");
704*7c478bd9Sstevel@tonic-gate 			return (2);
705*7c478bd9Sstevel@tonic-gate 		}
706*7c478bd9Sstevel@tonic-gate 	}
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	if (change_list & CNG_SH) {
709*7c478bd9Sstevel@tonic-gate 		if (NULL != old_ent->pw_shell)
710*7c478bd9Sstevel@tonic-gate 			sfree(old_ent->pw_shell);
711*7c478bd9Sstevel@tonic-gate 		old_ent->pw_shell = strdup(yppwd->newpw.pw_shell);
712*7c478bd9Sstevel@tonic-gate 		if (NULL == old_ent->pw_shell) {
713*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate shell");
714*7c478bd9Sstevel@tonic-gate 			return (2);
715*7c478bd9Sstevel@tonic-gate 		}
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	if (change_list & CNG_PASSWD) {
719*7c478bd9Sstevel@tonic-gate 		if (NULL != old_ent->pw_passwd)
720*7c478bd9Sstevel@tonic-gate 			sfree(old_ent->pw_passwd);
721*7c478bd9Sstevel@tonic-gate 		old_ent->pw_passwd = strdup(yppwd->newpw.pw_passwd);
722*7c478bd9Sstevel@tonic-gate 		if (NULL == old_ent->pw_passwd) {
723*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate passwd");
724*7c478bd9Sstevel@tonic-gate 			return (2);
725*7c478bd9Sstevel@tonic-gate 		}
726*7c478bd9Sstevel@tonic-gate 	}
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	return (0);
729*7c478bd9Sstevel@tonic-gate }
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate /*
732*7c478bd9Sstevel@tonic-gate  * FUNCTION :	get_change_list()
733*7c478bd9Sstevel@tonic-gate  *
734*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Works out what we have to change.
735*7c478bd9Sstevel@tonic-gate  *
736*7c478bd9Sstevel@tonic-gate  * INPUTS :	Request.
737*7c478bd9Sstevel@tonic-gate  *		Structure containing current state of entry
738*7c478bd9Sstevel@tonic-gate  *
739*7c478bd9Sstevel@tonic-gate  * OUTPUTS :	A bitmask signaling what to change. (Implemented in this
740*7c478bd9Sstevel@tonic-gate  *		way to make it easy to pass between functions).
741*7c478bd9Sstevel@tonic-gate  */
742*7c478bd9Sstevel@tonic-gate int
743*7c478bd9Sstevel@tonic-gate get_change_list(struct yppasswd *yppwd, struct passwd_entry *old_ent)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	int list = 0;
746*7c478bd9Sstevel@tonic-gate 	char *p;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	p = yppwd->newpw.pw_passwd;
749*7c478bd9Sstevel@tonic-gate 	if ((!nopw) &&
750*7c478bd9Sstevel@tonic-gate 		p && *p &&
751*7c478bd9Sstevel@tonic-gate 		!(*p++ == '#' && *p++ == '#' &&
752*7c478bd9Sstevel@tonic-gate 		(strcmp(p, old_ent->pw_name) == 0)) &&
753*7c478bd9Sstevel@tonic-gate 		(strcmp(crypt(old_ent->pw_passwd,
754*7c478bd9Sstevel@tonic-gate 			yppwd->newpw.pw_passwd), yppwd->newpw.pw_passwd) != 0))
755*7c478bd9Sstevel@tonic-gate 		list |= CNG_PASSWD;
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	if ((NULL != old_ent->pw_shell) &&
758*7c478bd9Sstevel@tonic-gate 		(!noshell) &&
759*7c478bd9Sstevel@tonic-gate 		(strcmp(old_ent->pw_shell, yppwd->newpw.pw_shell) != 0)) {
760*7c478bd9Sstevel@tonic-gate 		if (single)
761*7c478bd9Sstevel@tonic-gate 			list = 0;
762*7c478bd9Sstevel@tonic-gate 		list |= CNG_SH;
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 	if ((NULL != old_ent->pw_gecos) &&
766*7c478bd9Sstevel@tonic-gate 		(!nogecos) &&
767*7c478bd9Sstevel@tonic-gate 		(strcmp(old_ent->pw_gecos, yppwd->newpw.pw_gecos) != 0)) {
768*7c478bd9Sstevel@tonic-gate 		if (single)
769*7c478bd9Sstevel@tonic-gate 			list = 0;
770*7c478bd9Sstevel@tonic-gate 		list |= CNG_GECOS;
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	return (list);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate /*
777*7c478bd9Sstevel@tonic-gate  * FUNCTION :	decode_pwd_entry()
778*7c478bd9Sstevel@tonic-gate  *
779*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Pulls apart a password entry. Because the password entry has
780*7c478bd9Sstevel@tonic-gate  *		come from the mapping system it can be assumed to be correctly
781*7c478bd9Sstevel@tonic-gate  *		formatted and relatively simple parsing can be done.
782*7c478bd9Sstevel@tonic-gate  *
783*7c478bd9Sstevel@tonic-gate  *		Substrings are put into malloced memory. Caller to free.
784*7c478bd9Sstevel@tonic-gate  *
785*7c478bd9Sstevel@tonic-gate  *		For adjunct files most of it is left empty.
786*7c478bd9Sstevel@tonic-gate  *
787*7c478bd9Sstevel@tonic-gate  *		It would be nice to use getpwent and friends for this work but
788*7c478bd9Sstevel@tonic-gate  *		these only seem to exist for files and it seems excessive to
789*7c478bd9Sstevel@tonic-gate  *		create a temporary file for this operation.
790*7c478bd9Sstevel@tonic-gate  *
791*7c478bd9Sstevel@tonic-gate  * INPUTS:	Pointer to datum containing password string.
792*7c478bd9Sstevel@tonic-gate  *		Pointer to structure in which to return results
793*7c478bd9Sstevel@tonic-gate  *		Flag indicating if we are decoding passwd or passwd.adjunct
794*7c478bd9Sstevel@tonic-gate  *
795*7c478bd9Sstevel@tonic-gate  * OUTPUTS:	SUCCESS = Decoded successfully
796*7c478bd9Sstevel@tonic-gate  *		FAILURE = Not decoded successfully. Caller to tidy up.
797*7c478bd9Sstevel@tonic-gate  */
798*7c478bd9Sstevel@tonic-gate suc_code
799*7c478bd9Sstevel@tonic-gate decode_pwd_entry(datum *data, struct passwd_entry *pwd, bool_t adjunct)
800*7c478bd9Sstevel@tonic-gate {
801*7c478bd9Sstevel@tonic-gate 	char *myself = "decode_pwd_entry";
802*7c478bd9Sstevel@tonic-gate 	char *p, *str_end, *temp;
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	/* Work out last location in string */
805*7c478bd9Sstevel@tonic-gate 	str_end = data->dptr + data->dsize;
806*7c478bd9Sstevel@tonic-gate 
807*7c478bd9Sstevel@tonic-gate 	/* Name */
808*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(data->dptr, &temp, str_end)))
809*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
810*7c478bd9Sstevel@tonic-gate 	if (adjunct) {
811*7c478bd9Sstevel@tonic-gate 		/* If we found an adjunct version this is the one to use */
812*7c478bd9Sstevel@tonic-gate 		if (NULL != pwd->pw_name)
813*7c478bd9Sstevel@tonic-gate 			sfree(pwd->pw_name);
814*7c478bd9Sstevel@tonic-gate 	}
815*7c478bd9Sstevel@tonic-gate 	pwd->pw_name = temp;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	/* Password */
818*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
819*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
820*7c478bd9Sstevel@tonic-gate 	if (adjunct) {
821*7c478bd9Sstevel@tonic-gate 		/* If we found an adjunct version this is the one to use */
822*7c478bd9Sstevel@tonic-gate 		if (NULL != pwd->pw_passwd)
823*7c478bd9Sstevel@tonic-gate 			sfree(pwd->pw_passwd);
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 	pwd->pw_passwd = temp;
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	if (adjunct) {
828*7c478bd9Sstevel@tonic-gate 		/* Store adjunct information in opaque string */
829*7c478bd9Sstevel@tonic-gate 		pwd->adjunct_tail = am(myself, str_end - p + 1);
830*7c478bd9Sstevel@tonic-gate 		if (NULL == pwd->adjunct_tail)
831*7c478bd9Sstevel@tonic-gate 			return (FAILURE);
832*7c478bd9Sstevel@tonic-gate 		strncpy(pwd->adjunct_tail, p, str_end - p);
833*7c478bd9Sstevel@tonic-gate 		pwd->adjunct_tail[str_end - p] = '\0';
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 		/* Remember that LDAP contained adjunct data */
836*7c478bd9Sstevel@tonic-gate 		pwd->adjunct = TRUE;
837*7c478bd9Sstevel@tonic-gate 		return (SUCCESS);
838*7c478bd9Sstevel@tonic-gate 	}
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	/* If we get here not adjunct. Decode rest of passwd */
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	/* UID */
843*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &(pwd->pw_uid), str_end)))
844*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	/* GID */
847*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &(pwd->pw_gid), str_end)))
848*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 	/* Gecos */
851*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &(pwd->pw_gecos), str_end)))
852*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	/* Home dir */
855*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &(pwd->pw_dir), str_end)))
856*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 	/* Shell may not be present so don't check return */
859*7c478bd9Sstevel@tonic-gate 	get_next_token(p, &(pwd->pw_shell), str_end);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	if (NULL == pwd->pw_shell)
862*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
865*7c478bd9Sstevel@tonic-gate }
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate /*
868*7c478bd9Sstevel@tonic-gate  * FUNCTION :	get_next_token()
869*7c478bd9Sstevel@tonic-gate  *
870*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Gets the next token from a string upto the next colon or the
871*7c478bd9Sstevel@tonic-gate  *		end of the string. The duplicates this token into malloced
872*7c478bd9Sstevel@tonic-gate  *		memory removing any spaces.
873*7c478bd9Sstevel@tonic-gate  *
874*7c478bd9Sstevel@tonic-gate  * INPUTS :	String to search for token. NOT NULL TERMINATED
875*7c478bd9Sstevel@tonic-gate  *		Location to return result (NULL if result not required)
876*7c478bd9Sstevel@tonic-gate  *		Last location in string
877*7c478bd9Sstevel@tonic-gate  *
878*7c478bd9Sstevel@tonic-gate  * OUTPUT :	Pointer into the string immediately after the token.
879*7c478bd9Sstevel@tonic-gate  *		NULL if end of string reached or error.
880*7c478bd9Sstevel@tonic-gate  */
881*7c478bd9Sstevel@tonic-gate static char *
882*7c478bd9Sstevel@tonic-gate get_next_token(char *str, char **op, char *str_end)
883*7c478bd9Sstevel@tonic-gate {
884*7c478bd9Sstevel@tonic-gate 	char *myself = "get_next_token";
885*7c478bd9Sstevel@tonic-gate 	char *p, *tok_start, *tok_end;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	p = str;
888*7c478bd9Sstevel@tonic-gate 	/* Skip leading whitespace */
889*7c478bd9Sstevel@tonic-gate 	while (' ' == *p)
890*7c478bd9Sstevel@tonic-gate 		p++;
891*7c478bd9Sstevel@tonic-gate 	tok_start = p;
892*7c478bd9Sstevel@tonic-gate 	tok_end = p;
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 	while ((str_end + 1 != p) && (COLON_CHAR != *p)) {
895*7c478bd9Sstevel@tonic-gate 		if (' ' != *p)
896*7c478bd9Sstevel@tonic-gate 			tok_end = p;
897*7c478bd9Sstevel@tonic-gate 		p++;
898*7c478bd9Sstevel@tonic-gate 	}
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 	/* Required string is now between start and end */
901*7c478bd9Sstevel@tonic-gate 	if (NULL != op) {
902*7c478bd9Sstevel@tonic-gate 		*op = am(myself, tok_end - tok_start + 2);
903*7c478bd9Sstevel@tonic-gate 		if (NULL == *op) {
904*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOMEM, LOG_ERR,
905*7c478bd9Sstevel@tonic-gate 					"Could not alloc memory for token");
906*7c478bd9Sstevel@tonic-gate 			return (NULL);
907*7c478bd9Sstevel@tonic-gate 		}
908*7c478bd9Sstevel@tonic-gate 		strncpy(*op, tok_start, tok_end - tok_start + 1);
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 		/* Terminate token */
911*7c478bd9Sstevel@tonic-gate 		(*op)[tok_end - tok_start + 1] = '\0';
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 	}
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 	/* Check if we reached the end of the input string */
916*7c478bd9Sstevel@tonic-gate 	if ('\0' == *p)
917*7c478bd9Sstevel@tonic-gate 		return (NULL);
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 	/* There is some more */
920*7c478bd9Sstevel@tonic-gate 	p++;
921*7c478bd9Sstevel@tonic-gate 	return (p);
922*7c478bd9Sstevel@tonic-gate }
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate /*
925*7c478bd9Sstevel@tonic-gate  * FUNCTION :	free_pwd_entry()
926*7c478bd9Sstevel@tonic-gate  *
927*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Frees up a pwd_entry structure and its contents.
928*7c478bd9Sstevel@tonic-gate  *
929*7c478bd9Sstevel@tonic-gate  * INPUTS:	Pointer to the structure to free.
930*7c478bd9Sstevel@tonic-gate  *
931*7c478bd9Sstevel@tonic-gate  * OUTPUT:	Nothing
932*7c478bd9Sstevel@tonic-gate  */
933*7c478bd9Sstevel@tonic-gate void
934*7c478bd9Sstevel@tonic-gate free_pwd_entry(struct passwd_entry *pwd)
935*7c478bd9Sstevel@tonic-gate {
936*7c478bd9Sstevel@tonic-gate 	/* Free up strings */
937*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pw_name)
938*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pw_name);
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pw_passwd)
941*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pw_passwd);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pw_gecos)
944*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pw_gecos);
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pw_shell)
947*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pw_shell);
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pw_dir)
950*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pw_dir);
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->adjunct_tail)
953*7c478bd9Sstevel@tonic-gate 		sfree(pwd->adjunct_tail);
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->pwd_str)
956*7c478bd9Sstevel@tonic-gate 		sfree(pwd->pwd_str);
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if (NULL != pwd->adjunct_str)
959*7c478bd9Sstevel@tonic-gate 		sfree(pwd->adjunct_str);
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate 	/* Free up structure */
962*7c478bd9Sstevel@tonic-gate 	sfree(pwd);
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate /*
966*7c478bd9Sstevel@tonic-gate  * FUNCTION :	create_pwd_str()
967*7c478bd9Sstevel@tonic-gate  *
968*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Builds up a new password entity string from a passwd structure.
969*7c478bd9Sstevel@tonic-gate  *
970*7c478bd9Sstevel@tonic-gate  * INPUTS :	Structure containing password details
971*7c478bd9Sstevel@tonic-gate  *		Flag indicating if we should create an adjunct or passwd string.
972*7c478bd9Sstevel@tonic-gate  *
973*7c478bd9Sstevel@tonic-gate  * OUTPUTS :	String in malloced memory (to be freed by caller).
974*7c478bd9Sstevel@tonic-gate  *		NULL on failure.
975*7c478bd9Sstevel@tonic-gate  */
976*7c478bd9Sstevel@tonic-gate char *
977*7c478bd9Sstevel@tonic-gate create_pwd_str(struct passwd_entry *pwd, bool_t adjunct)
978*7c478bd9Sstevel@tonic-gate {
979*7c478bd9Sstevel@tonic-gate 	char *myself = "create_pwd_str";
980*7c478bd9Sstevel@tonic-gate 	char *s;
981*7c478bd9Sstevel@tonic-gate 	int len;
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	/* Separator string so we can strcat separator onto things */
984*7c478bd9Sstevel@tonic-gate 	char sep_str[2] = {COLON_CHAR, '\0'};
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 	/* Work out the size */
987*7c478bd9Sstevel@tonic-gate 	len = strlen(pwd->pw_name) + 1;
988*7c478bd9Sstevel@tonic-gate 	len += strlen(pwd->pw_passwd) + 1;
989*7c478bd9Sstevel@tonic-gate 	if (adjunct) {
990*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->adjunct_tail) + 1;
991*7c478bd9Sstevel@tonic-gate 	} else {
992*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->pw_uid) + 1;
993*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->pw_gid) + 1;
994*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->pw_gecos) + 1;
995*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->pw_dir) + 1;
996*7c478bd9Sstevel@tonic-gate 		len += strlen(pwd->pw_shell) + 1;
997*7c478bd9Sstevel@tonic-gate 	}
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	/* Allocate some memory for it */
1000*7c478bd9Sstevel@tonic-gate 	s = am(myself, len);
1001*7c478bd9Sstevel@tonic-gate 	if (NULL == s)
1002*7c478bd9Sstevel@tonic-gate 		return (NULL);
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	strcpy(s, pwd->pw_name);
1005*7c478bd9Sstevel@tonic-gate 	strcat(s, sep_str);
1006*7c478bd9Sstevel@tonic-gate 	if (!adjunct) {
1007*7c478bd9Sstevel@tonic-gate 		/* Build up a passwd string */
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 		/* If LDAP contains adjunct info then passwd is 'x' */
1010*7c478bd9Sstevel@tonic-gate 		if (pwd->adjunct) {
1011*7c478bd9Sstevel@tonic-gate 			strcat(s, "##");
1012*7c478bd9Sstevel@tonic-gate 			strcat(s,  pwd->pw_name);
1013*7c478bd9Sstevel@tonic-gate 		} else {
1014*7c478bd9Sstevel@tonic-gate 			strcat(s, pwd->pw_passwd);
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1017*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_uid);
1018*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1019*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_gid);
1020*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1021*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_gecos);
1022*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1023*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_dir);
1024*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1025*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_shell);
1026*7c478bd9Sstevel@tonic-gate 	} else {
1027*7c478bd9Sstevel@tonic-gate 		/* Build up a passwd_adjunct string */
1028*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->pw_passwd);
1029*7c478bd9Sstevel@tonic-gate 		strcat(s, sep_str);
1030*7c478bd9Sstevel@tonic-gate 		strcat(s, pwd->adjunct_tail);
1031*7c478bd9Sstevel@tonic-gate 	}
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	return (s);
1034*7c478bd9Sstevel@tonic-gate }
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate /*
1037*7c478bd9Sstevel@tonic-gate  * FUNCTION:	get_old_info()
1038*7c478bd9Sstevel@tonic-gate  *
1039*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Gets as much information as possible from LDAP about one user.
1040*7c478bd9Sstevel@tonic-gate  *
1041*7c478bd9Sstevel@tonic-gate  *		This goes through the mapping system. This is messy because
1042*7c478bd9Sstevel@tonic-gate  *		them mapping system will build up a password entry from the
1043*7c478bd9Sstevel@tonic-gate  *		contents of the DIT. We then have to parse this to recover
1044*7c478bd9Sstevel@tonic-gate  *		it's individual fields.
1045*7c478bd9Sstevel@tonic-gate  *
1046*7c478bd9Sstevel@tonic-gate  * INPUT:	Pointer to user name
1047*7c478bd9Sstevel@tonic-gate  *		Domain
1048*7c478bd9Sstevel@tonic-gate  *
1049*7c478bd9Sstevel@tonic-gate  * OUTPUT:	The info in malloced space. To be freed by caller.
1050*7c478bd9Sstevel@tonic-gate  *		NULL on failure.
1051*7c478bd9Sstevel@tonic-gate  */
1052*7c478bd9Sstevel@tonic-gate struct passwd_entry *
1053*7c478bd9Sstevel@tonic-gate get_old_info(char *name, char *domain)
1054*7c478bd9Sstevel@tonic-gate {
1055*7c478bd9Sstevel@tonic-gate 	char *myself = "get_old_info";
1056*7c478bd9Sstevel@tonic-gate 	struct passwd_entry *old_passwd;
1057*7c478bd9Sstevel@tonic-gate 	char	*p;
1058*7c478bd9Sstevel@tonic-gate 	datum	key, data;
1059*7c478bd9Sstevel@tonic-gate 	suc_code res;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	/* Get the password entry */
1062*7c478bd9Sstevel@tonic-gate 	key.dptr = name;
1063*7c478bd9Sstevel@tonic-gate 	key.dsize = strlen(key.dptr);
1064*7c478bd9Sstevel@tonic-gate 	read_from_dit(PASSWD_MAPPING, domain, &key, &data);
1065*7c478bd9Sstevel@tonic-gate 	if (NULL == data.dptr) {
1066*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_ERR,
1067*7c478bd9Sstevel@tonic-gate 					"Could not read old pwd for %s", name);
1068*7c478bd9Sstevel@tonic-gate 		return (NULL);
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	/* Pull password apart */
1072*7c478bd9Sstevel@tonic-gate 	old_passwd = am(myself, sizeof (struct passwd_entry));
1073*7c478bd9Sstevel@tonic-gate 	if (NULL == old_passwd) {
1074*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc for pwd decode");
1075*7c478bd9Sstevel@tonic-gate 		sfree(data.dptr);
1076*7c478bd9Sstevel@tonic-gate 		return (NULL);
1077*7c478bd9Sstevel@tonic-gate 	}
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	/* No data yet */
1080*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_name = NULL;
1081*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_passwd = NULL;
1082*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_uid = NULL;
1083*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_gid = NULL;
1084*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_gecos = NULL;
1085*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_dir = NULL;
1086*7c478bd9Sstevel@tonic-gate 	old_passwd->pw_shell = NULL;
1087*7c478bd9Sstevel@tonic-gate 	old_passwd->adjunct_tail = NULL;
1088*7c478bd9Sstevel@tonic-gate 	old_passwd->pwd_str = NULL;
1089*7c478bd9Sstevel@tonic-gate 	old_passwd->adjunct_str = NULL;
1090*7c478bd9Sstevel@tonic-gate 	old_passwd->adjunct = FALSE;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	res = decode_pwd_entry(&data, old_passwd, FALSE);
1093*7c478bd9Sstevel@tonic-gate 	sfree(data.dptr);
1094*7c478bd9Sstevel@tonic-gate 	if (SUCCESS != res) {
1095*7c478bd9Sstevel@tonic-gate 		free_pwd_entry(old_passwd);
1096*7c478bd9Sstevel@tonic-gate 		return (NULL);
1097*7c478bd9Sstevel@tonic-gate 	}
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate 	/* Try to get the adjunct entry */
1100*7c478bd9Sstevel@tonic-gate 	read_from_dit(PASSWD_ADJUNCT_MAPPING, domain, &key, &data);
1101*7c478bd9Sstevel@tonic-gate 	if (NULL == data.dptr) {
1102*7c478bd9Sstevel@tonic-gate 		/* Fine just no adjunct data */
1103*7c478bd9Sstevel@tonic-gate 		old_passwd->adjunct = FALSE;
1104*7c478bd9Sstevel@tonic-gate 	} else {
1105*7c478bd9Sstevel@tonic-gate 		res = decode_pwd_entry(&data, old_passwd, TRUE);
1106*7c478bd9Sstevel@tonic-gate 		sfree(data.dptr);
1107*7c478bd9Sstevel@tonic-gate 		if (SUCCESS != res) {
1108*7c478bd9Sstevel@tonic-gate 			free_pwd_entry(old_passwd);
1109*7c478bd9Sstevel@tonic-gate 			return (NULL);
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 	}
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 	return (old_passwd);
1114*7c478bd9Sstevel@tonic-gate }
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate /*
1117*7c478bd9Sstevel@tonic-gate  * FUNCTION :	put_new_info()
1118*7c478bd9Sstevel@tonic-gate  *
1119*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Generates new map strings and puts them back to LDAP
1120*7c478bd9Sstevel@tonic-gate  *
1121*7c478bd9Sstevel@tonic-gate  * INPUTS:	Info to put back
1122*7c478bd9Sstevel@tonic-gate  *		Domain
1123*7c478bd9Sstevel@tonic-gate  *
1124*7c478bd9Sstevel@tonic-gate  * OUTPUT:	Answer code.
1125*7c478bd9Sstevel@tonic-gate  */
1126*7c478bd9Sstevel@tonic-gate int
1127*7c478bd9Sstevel@tonic-gate put_new_info(struct passwd_entry *pwd, char *domain)
1128*7c478bd9Sstevel@tonic-gate {
1129*7c478bd9Sstevel@tonic-gate 	datum	key, data;
1130*7c478bd9Sstevel@tonic-gate 
1131*7c478bd9Sstevel@tonic-gate 	/* Write it back to LDAP */
1132*7c478bd9Sstevel@tonic-gate 	data.dptr = pwd->pwd_str;
1133*7c478bd9Sstevel@tonic-gate 	data.dsize = strlen(data.dptr);
1134*7c478bd9Sstevel@tonic-gate 	key.dptr = pwd->pw_name;
1135*7c478bd9Sstevel@tonic-gate 	key.dsize = strlen(key.dptr);
1136*7c478bd9Sstevel@tonic-gate 	if (SUCCESS != write_to_dit(PASSWD_MAPPING, domain, key, data,
1137*7c478bd9Sstevel@tonic-gate 								TRUE, FALSE))
1138*7c478bd9Sstevel@tonic-gate 		return (2);
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 	/* If DIT contains adjunct information do the same for adjunct */
1142*7c478bd9Sstevel@tonic-gate 	if (pwd->adjunct) {
1143*7c478bd9Sstevel@tonic-gate 		data.dptr = pwd->adjunct_str;
1144*7c478bd9Sstevel@tonic-gate 		data.dsize = strlen(data.dptr);
1145*7c478bd9Sstevel@tonic-gate 		key.dptr = pwd->pw_name;
1146*7c478bd9Sstevel@tonic-gate 		key.dsize = strlen(key.dptr);
1147*7c478bd9Sstevel@tonic-gate 		if (SUCCESS != write_to_dit(PASSWD_ADJUNCT_MAPPING, domain,
1148*7c478bd9Sstevel@tonic-gate 						key, data, TRUE, FALSE))
1149*7c478bd9Sstevel@tonic-gate 			return (2);
1150*7c478bd9Sstevel@tonic-gate 	}
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate 	return (0);
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate }
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate /*
1157*7c478bd9Sstevel@tonic-gate  * FUNCTION :   get_old_shadow()
1158*7c478bd9Sstevel@tonic-gate  *
1159*7c478bd9Sstevel@tonic-gate  * DESCRIPTION :Extracts and decodes shadow information from the DIT
1160*7c478bd9Sstevel@tonic-gate  *		See also comments under decode_pwd_entry().
1161*7c478bd9Sstevel@tonic-gate  *
1162*7c478bd9Sstevel@tonic-gate  * INPUTS :     User name
1163*7c478bd9Sstevel@tonic-gate  *		Domain name
1164*7c478bd9Sstevel@tonic-gate  *
1165*7c478bd9Sstevel@tonic-gate  * OUTPUT :     Shadow information in malloced memory. To be freed by caller.
1166*7c478bd9Sstevel@tonic-gate  */
1167*7c478bd9Sstevel@tonic-gate struct spwd *
1168*7c478bd9Sstevel@tonic-gate get_old_shadow(char *name, char *domain)
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	char *myself = "get_old_shadow";
1171*7c478bd9Sstevel@tonic-gate 	struct spwd *sp;
1172*7c478bd9Sstevel@tonic-gate 	datum key, data;
1173*7c478bd9Sstevel@tonic-gate 	suc_code res;
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate 	/* Get the info */
1176*7c478bd9Sstevel@tonic-gate 	key.dptr = name;
1177*7c478bd9Sstevel@tonic-gate 	key.dsize = strlen(key.dptr);	/* Len excluding terminator */
1178*7c478bd9Sstevel@tonic-gate 	read_from_dit(AGEING_MAPPING, domain, &key, &data);
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	if (NULL == data.dptr) {
1181*7c478bd9Sstevel@tonic-gate 		/* OK just have no shadow info in DIT */
1182*7c478bd9Sstevel@tonic-gate 		return (NULL);
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	/* Pull shadow apart */
1186*7c478bd9Sstevel@tonic-gate 	if (NULL == (sp = am(myself, sizeof (struct spwd)))) {
1187*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOMEM, LOG_ERR,
1188*7c478bd9Sstevel@tonic-gate 					"Could not alloc for shadow decode");
1189*7c478bd9Sstevel@tonic-gate 		sfree(data.dptr);
1190*7c478bd9Sstevel@tonic-gate 		return (NULL);
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 	sp->sp_namp = NULL;
1193*7c478bd9Sstevel@tonic-gate 	sp->sp_pwdp = NULL;
1194*7c478bd9Sstevel@tonic-gate 
1195*7c478bd9Sstevel@tonic-gate 	res = decode_shadow_entry(&data, sp);
1196*7c478bd9Sstevel@tonic-gate 	sfree(data.dptr);
1197*7c478bd9Sstevel@tonic-gate 	if (SUCCESS != res) {
1198*7c478bd9Sstevel@tonic-gate 		free_shadow_entry(sp);
1199*7c478bd9Sstevel@tonic-gate 		return (NULL);
1200*7c478bd9Sstevel@tonic-gate 	}
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	return (sp);
1203*7c478bd9Sstevel@tonic-gate }
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate /*
1206*7c478bd9Sstevel@tonic-gate  * FUNCTION :	decode_shadow_entry()
1207*7c478bd9Sstevel@tonic-gate  *
1208*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Pulls apart ageing information. For convenience this is stored
1209*7c478bd9Sstevel@tonic-gate  *		in a partially filled spwd structure.
1210*7c478bd9Sstevel@tonic-gate  *
1211*7c478bd9Sstevel@tonic-gate  *		SEE COMMENTS FOR decode_pwd_entry()
1212*7c478bd9Sstevel@tonic-gate  */
1213*7c478bd9Sstevel@tonic-gate suc_code
1214*7c478bd9Sstevel@tonic-gate decode_shadow_entry(datum *data, struct spwd *sp)
1215*7c478bd9Sstevel@tonic-gate {
1216*7c478bd9Sstevel@tonic-gate 	char *p, *str_end, *temp;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 	/* Work out last location in string */
1219*7c478bd9Sstevel@tonic-gate 	str_end = data->dptr + data->dsize;
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	/* Name */
1222*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(data->dptr, &(sp->sp_namp), str_end)))
1223*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	/* date of last change */
1226*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1227*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1228*7c478bd9Sstevel@tonic-gate 	sp->sp_lstchg = atoi(temp);
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	/* min days to passwd change */
1231*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1232*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1233*7c478bd9Sstevel@tonic-gate 	sp->sp_min = atoi(temp);
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 	/* max days to passwd change */
1236*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1237*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1238*7c478bd9Sstevel@tonic-gate 	sp->sp_max = atoi(temp);
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	/* warning period */
1241*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1242*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1243*7c478bd9Sstevel@tonic-gate 	sp->sp_warn = atoi(temp);
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate 	/* max days inactive */
1246*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1247*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1248*7c478bd9Sstevel@tonic-gate 	sp->sp_inact = atoi(temp);
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 	/* account expiry date */
1251*7c478bd9Sstevel@tonic-gate 	if (NULL == (p = get_next_token(p, &temp, str_end)))
1252*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1253*7c478bd9Sstevel@tonic-gate 	sp->sp_expire = atoi(temp);
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate 	/* flag  */
1256*7c478bd9Sstevel@tonic-gate 	if (NULL != (p = get_next_token(p, &temp, str_end)))
1257*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1258*7c478bd9Sstevel@tonic-gate 	sp->sp_flag = atoi(temp);
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
1261*7c478bd9Sstevel@tonic-gate }
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate /*
1264*7c478bd9Sstevel@tonic-gate  * FUNCTION :	write_shadow_info()
1265*7c478bd9Sstevel@tonic-gate  *
1266*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Writes shadow information back to the DIT.
1267*7c478bd9Sstevel@tonic-gate  *
1268*7c478bd9Sstevel@tonic-gate  * INPUTS :	Domain
1269*7c478bd9Sstevel@tonic-gate  *		Information to write
1270*7c478bd9Sstevel@tonic-gate  *
1271*7c478bd9Sstevel@tonic-gate  * OUTPUT :	Success code
1272*7c478bd9Sstevel@tonic-gate  *
1273*7c478bd9Sstevel@tonic-gate  */
1274*7c478bd9Sstevel@tonic-gate suc_code
1275*7c478bd9Sstevel@tonic-gate write_shadow_info(char *domain, struct spwd *sp)
1276*7c478bd9Sstevel@tonic-gate {
1277*7c478bd9Sstevel@tonic-gate 	char *myself = "write_shadow_info";
1278*7c478bd9Sstevel@tonic-gate 	datum key, data;
1279*7c478bd9Sstevel@tonic-gate 	char *str;
1280*7c478bd9Sstevel@tonic-gate 	suc_code res;
1281*7c478bd9Sstevel@tonic-gate 	int len;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/* Work out how long string will be */
1284*7c478bd9Sstevel@tonic-gate 	len = strlen(sp->sp_namp) + 1;
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	/*
1287*7c478bd9Sstevel@tonic-gate 	 * Bit crude but if we assume 1 byte is 3 decimal characters
1288*7c478bd9Sstevel@tonic-gate 	 * will get enough buffer for the longs and some spare.
1289*7c478bd9Sstevel@tonic-gate 	 */
1290*7c478bd9Sstevel@tonic-gate 	len += 7 * (3 * sizeof (long) + 1);
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	/* Allocate some memory */
1293*7c478bd9Sstevel@tonic-gate 	str = am(myself, len);
1294*7c478bd9Sstevel@tonic-gate 	if (NULL == str) {
1295*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOMEM, LOG_ERR, "Could not aloc for shadow write");
1296*7c478bd9Sstevel@tonic-gate 		return (FAILURE);
1297*7c478bd9Sstevel@tonic-gate 	}
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 	/* Build up shadow string */
1300*7c478bd9Sstevel@tonic-gate 	sprintf(str, "%s%c%d%c%d%c%d%c%d%c%d%c%d%c%d",
1301*7c478bd9Sstevel@tonic-gate 		sp->sp_namp, COLON_CHAR,
1302*7c478bd9Sstevel@tonic-gate 		sp->sp_lstchg, COLON_CHAR,
1303*7c478bd9Sstevel@tonic-gate 		sp->sp_min, COLON_CHAR,
1304*7c478bd9Sstevel@tonic-gate 		sp->sp_max, COLON_CHAR,
1305*7c478bd9Sstevel@tonic-gate 		sp->sp_warn, COLON_CHAR,
1306*7c478bd9Sstevel@tonic-gate 		sp->sp_inact, COLON_CHAR,
1307*7c478bd9Sstevel@tonic-gate 		sp->sp_expire, COLON_CHAR,
1308*7c478bd9Sstevel@tonic-gate 		sp->sp_flag);
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 	/* Write it */
1311*7c478bd9Sstevel@tonic-gate 	data.dptr = str;
1312*7c478bd9Sstevel@tonic-gate 	data.dsize = strlen(data.dptr);
1313*7c478bd9Sstevel@tonic-gate 	key.dptr = sp->sp_namp;
1314*7c478bd9Sstevel@tonic-gate 	key.dsize = strlen(key.dptr);
1315*7c478bd9Sstevel@tonic-gate 	res = write_to_dit(AGEING_MAPPING, domain, key, data, TRUE, FALSE);
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	sfree(str);
1318*7c478bd9Sstevel@tonic-gate 	return (res);
1319*7c478bd9Sstevel@tonic-gate }
1320*7c478bd9Sstevel@tonic-gate 
1321*7c478bd9Sstevel@tonic-gate /*
1322*7c478bd9Sstevel@tonic-gate  * FUNCTION :	free_shadow_entry()
1323*7c478bd9Sstevel@tonic-gate  *
1324*7c478bd9Sstevel@tonic-gate  * DESCRIPTION:	Frees up a shadow information structure
1325*7c478bd9Sstevel@tonic-gate  *
1326*7c478bd9Sstevel@tonic-gate  * INPUTS :	Structure to free
1327*7c478bd9Sstevel@tonic-gate  *
1328*7c478bd9Sstevel@tonic-gate  * OUTPUTS :	Nothing
1329*7c478bd9Sstevel@tonic-gate  */
1330*7c478bd9Sstevel@tonic-gate void
1331*7c478bd9Sstevel@tonic-gate free_shadow_entry(struct spwd *spwd)
1332*7c478bd9Sstevel@tonic-gate {
1333*7c478bd9Sstevel@tonic-gate 	if (NULL != spwd->sp_namp)
1334*7c478bd9Sstevel@tonic-gate 		sfree(spwd->sp_namp);
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	if (NULL != spwd->sp_pwdp)
1337*7c478bd9Sstevel@tonic-gate 		sfree(spwd->sp_pwdp);
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 	/* No need to free numerics */
1340*7c478bd9Sstevel@tonic-gate 
1341*7c478bd9Sstevel@tonic-gate 	/* Free up structure */
1342*7c478bd9Sstevel@tonic-gate 	sfree(spwd);
1343*7c478bd9Sstevel@tonic-gate }
1344