xref: /titanic_53/usr/src/cmd/passwd/passwd.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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
31*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /*
36*7c478bd9Sstevel@tonic-gate  * passwd is a program whose sole purpose is to manage
37*7c478bd9Sstevel@tonic-gate  * the password file, map, or table. It allows system administrator
38*7c478bd9Sstevel@tonic-gate  * to add, change and display password attributes.
39*7c478bd9Sstevel@tonic-gate  * Non privileged user can change password or display
40*7c478bd9Sstevel@tonic-gate  * password attributes which corresponds to their login name.
41*7c478bd9Sstevel@tonic-gate  */
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate #include <stdio.h>
44*7c478bd9Sstevel@tonic-gate #include <pwd.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
46*7c478bd9Sstevel@tonic-gate #include <errno.h>
47*7c478bd9Sstevel@tonic-gate #include <unistd.h>
48*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
49*7c478bd9Sstevel@tonic-gate #include <locale.h>
50*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
51*7c478bd9Sstevel@tonic-gate #include <errno.h>
52*7c478bd9Sstevel@tonic-gate #include <string.h>
53*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
54*7c478bd9Sstevel@tonic-gate #include <security/pam_modules.h>
55*7c478bd9Sstevel@tonic-gate #include <security/pam_impl.h>
56*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h>
57*7c478bd9Sstevel@tonic-gate #undef GROUP
58*7c478bd9Sstevel@tonic-gate #include <syslog.h>
59*7c478bd9Sstevel@tonic-gate #include <userdefs.h>
60*7c478bd9Sstevel@tonic-gate #include <passwdutil.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #include <deflt.h>
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate #undef	GROUP
67*7c478bd9Sstevel@tonic-gate #include <bsm/adt.h>
68*7c478bd9Sstevel@tonic-gate #include <bsm/adt_event.h>
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /*
71*7c478bd9Sstevel@tonic-gate  * flags indicate password attributes to be modified
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #define	LFLAG 0x001		/* lock user's password  */
75*7c478bd9Sstevel@tonic-gate #define	DFLAG 0x002		/* delete user's  password */
76*7c478bd9Sstevel@tonic-gate #define	MFLAG 0x004		/* set max field -- # of days passwd is valid */
77*7c478bd9Sstevel@tonic-gate #define	NFLAG 0x008		/* set min field -- # of days between */
78*7c478bd9Sstevel@tonic-gate 				/* password changes */
79*7c478bd9Sstevel@tonic-gate #define	SFLAG 0x010		/* display password attributes */
80*7c478bd9Sstevel@tonic-gate #define	FFLAG 0x020		/* expire  user's password */
81*7c478bd9Sstevel@tonic-gate #define	AFLAG 0x040		/* display password attributes for all users */
82*7c478bd9Sstevel@tonic-gate #define	SAFLAG (SFLAG|AFLAG)	/* display password attributes for all users */
83*7c478bd9Sstevel@tonic-gate #define	WFLAG 0x100		/* warn user to change passwd */
84*7c478bd9Sstevel@tonic-gate #define	OFLAG 0x200		/* domain name */
85*7c478bd9Sstevel@tonic-gate #define	EFLAG 0x400		/* change shell */
86*7c478bd9Sstevel@tonic-gate #define	GFLAG 0x800		/* change gecos information */
87*7c478bd9Sstevel@tonic-gate #define	HFLAG 0x1000		/* change home directory */
88*7c478bd9Sstevel@tonic-gate #define	XFLAG 0x2000		/* no login */
89*7c478bd9Sstevel@tonic-gate #define	UFLAG 0x4000		/* unlock user's password */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #define	NONAGEFLAG	(EFLAG | GFLAG | HFLAG)
92*7c478bd9Sstevel@tonic-gate #define	AGEFLAG	(LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
93*7c478bd9Sstevel@tonic-gate #define	MUTEXFLAG	(DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate  * exit code
98*7c478bd9Sstevel@tonic-gate  */
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate #define	SUCCESS	0	/* succeeded */
101*7c478bd9Sstevel@tonic-gate #define	NOPERM	1	/* No permission */
102*7c478bd9Sstevel@tonic-gate #define	BADOPT	2	/* Invalid combination of option */
103*7c478bd9Sstevel@tonic-gate #define	FMERR	3	/* File/table manipulation error */
104*7c478bd9Sstevel@tonic-gate #define	FATAL	4	/* Old file/table can not be recovered */
105*7c478bd9Sstevel@tonic-gate #define	FBUSY	5	/* Lock file/table busy */
106*7c478bd9Sstevel@tonic-gate #define	BADSYN	6	/* Incorrect syntax */
107*7c478bd9Sstevel@tonic-gate #define	BADAGE	7	/* Aging is disabled  */
108*7c478bd9Sstevel@tonic-gate #define	NOMEM	8	/* No memory */
109*7c478bd9Sstevel@tonic-gate #define	SYSERR	9	/* System error */
110*7c478bd9Sstevel@tonic-gate #define	EXPIRED	10	/* Account expired */
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /*
113*7c478bd9Sstevel@tonic-gate  * define error messages
114*7c478bd9Sstevel@tonic-gate  */
115*7c478bd9Sstevel@tonic-gate #define	MSG_NP		"Permission denied"
116*7c478bd9Sstevel@tonic-gate #define	MSG_BS		"Invalid combination of options"
117*7c478bd9Sstevel@tonic-gate #define	MSG_FE		"Unexpected failure. Password file/table unchanged."
118*7c478bd9Sstevel@tonic-gate #define	MSG_FF		"Unexpected failure. Password file/table missing."
119*7c478bd9Sstevel@tonic-gate #define	MSG_FB		"Password file/table busy. Try again later."
120*7c478bd9Sstevel@tonic-gate #define	MSG_NV  	"Invalid argument to option"
121*7c478bd9Sstevel@tonic-gate #define	MSG_AD		"Password aging is disabled"
122*7c478bd9Sstevel@tonic-gate #define	MSG_RS		"Cannot change from restricted shell %s\n"
123*7c478bd9Sstevel@tonic-gate #define	MSG_NM		"Out of memory."
124*7c478bd9Sstevel@tonic-gate #define	MSG_UNACCEPT	"%s is unacceptable as a new shell\n"
125*7c478bd9Sstevel@tonic-gate #define	MSG_UNAVAIL	"warning: %s is unavailable on this machine\n"
126*7c478bd9Sstevel@tonic-gate #define	MSG_COLON	"':' is not allowed.\n"
127*7c478bd9Sstevel@tonic-gate #define	MSG_MAXLEN	"Maximum number of characters allowed is %d."
128*7c478bd9Sstevel@tonic-gate #define	MSG_CONTROL	"Control characters are not allowed.\n"
129*7c478bd9Sstevel@tonic-gate #define	MSG_SHELL_UNCHANGED	"Login shell unchanged.\n"
130*7c478bd9Sstevel@tonic-gate #define	MSG_GECOS_UNCHANGED	"Finger information unchanged.\n"
131*7c478bd9Sstevel@tonic-gate #define	MSG_DIR_UNCHANGED	"Homedir information unchanged.\n"
132*7c478bd9Sstevel@tonic-gate #define	MSG_NAME	"\nName [%s]: "
133*7c478bd9Sstevel@tonic-gate #define	MSG_HOMEDIR	"\nHome Directory [%s]: "
134*7c478bd9Sstevel@tonic-gate #define	MSG_OLDSHELL	"Old shell: %s\n"
135*7c478bd9Sstevel@tonic-gate #define	MSG_NEWSHELL	"New shell: "
136*7c478bd9Sstevel@tonic-gate #define	MSG_AGAIN	"\nPlease try again\n"
137*7c478bd9Sstevel@tonic-gate #define	MSG_INPUTHDR	"Default values are printed inside of '[]'.\n" \
138*7c478bd9Sstevel@tonic-gate 			"To accept the default, type <return>.\n" \
139*7c478bd9Sstevel@tonic-gate 			"To have a blank entry, type the word 'none'.\n"
140*7c478bd9Sstevel@tonic-gate #define	MSG_UNKNOWN	"%s: User unknown: %s\n"
141*7c478bd9Sstevel@tonic-gate #define	MSG_ACCOUNT_EXP	"User account has expired: %s\n"
142*7c478bd9Sstevel@tonic-gate #define	MSG_AUTHTOK_EXP	"Your password has been expired for too long.\n" \
143*7c478bd9Sstevel@tonic-gate 			"Please contact the system administrator.\n"
144*7c478bd9Sstevel@tonic-gate #define	MSG_NIS_HOMEDIR	"-h does not apply to NIS"
145*7c478bd9Sstevel@tonic-gate #define	MSG_CUR_PASS	"Enter existing login password: "
146*7c478bd9Sstevel@tonic-gate #define	MSG_CUR_PASS_UNAME	"Enter %s's existing login password: "
147*7c478bd9Sstevel@tonic-gate #define	MSG_SUCCESS	"%s: password information changed for %s\n"
148*7c478bd9Sstevel@tonic-gate #define	MSG_SORRY	"%s: Sorry, wrong passwd\n"
149*7c478bd9Sstevel@tonic-gate #define	MSG_INFO	"%s: Changing password for %s\n"
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate /*
153*7c478bd9Sstevel@tonic-gate  * return code from ckarg() routine
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate #define	FAIL 		-1
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate /*
158*7c478bd9Sstevel@tonic-gate  *  defind password file name
159*7c478bd9Sstevel@tonic-gate  */
160*7c478bd9Sstevel@tonic-gate #define	PASSWD 			"/etc/passwd"
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate #define	MAX_INPUT_LEN		512
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate #define	DEF_ATTEMPTS	3
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate /* Number of characters in that make up an encrypted password (for now) */
167*7c478bd9Sstevel@tonic-gate #define	NUMCP			13
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
170*7c478bd9Sstevel@tonic-gate #define	dprintf1	printf
171*7c478bd9Sstevel@tonic-gate #else
172*7c478bd9Sstevel@tonic-gate #define	dprintf1(w, x)
173*7c478bd9Sstevel@tonic-gate #endif
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate extern int	optind;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate static int		retval = SUCCESS;
178*7c478bd9Sstevel@tonic-gate static int		pam_retval = PAM_SUCCESS;
179*7c478bd9Sstevel@tonic-gate static uid_t		uid;
180*7c478bd9Sstevel@tonic-gate static char		*prognamep;
181*7c478bd9Sstevel@tonic-gate static long		maxdate;	/* password aging information */
182*7c478bd9Sstevel@tonic-gate static int		passwd_conv();
183*7c478bd9Sstevel@tonic-gate static struct pam_conv	pam_conv = {passwd_conv, NULL};
184*7c478bd9Sstevel@tonic-gate static pam_handle_t	*pamh;		/* Authentication handle */
185*7c478bd9Sstevel@tonic-gate static char		*usrname;	/* user whose attribute we update */
186*7c478bd9Sstevel@tonic-gate static adt_session_data_t *ah;  /* audit session handle */
187*7c478bd9Sstevel@tonic-gate static adt_event_data_t *event = NULL; /* event to be generated */
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate static pam_repository_t	auth_rep;
190*7c478bd9Sstevel@tonic-gate static pwu_repository_t	repository;
191*7c478bd9Sstevel@tonic-gate static pwu_repository_t	__REPFILES = { "files", NULL, 0 };
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate /*
194*7c478bd9Sstevel@tonic-gate  * Function Declarations
195*7c478bd9Sstevel@tonic-gate  */
196*7c478bd9Sstevel@tonic-gate extern	nis_name	nis_local_directory(void);
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate extern	void		setusershell(void);
199*7c478bd9Sstevel@tonic-gate extern	char		*getusershell(void);
200*7c478bd9Sstevel@tonic-gate extern	void		endusershell(void);
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate static	void		passwd_exit(int retcode);
203*7c478bd9Sstevel@tonic-gate static	void		rusage(void);
204*7c478bd9Sstevel@tonic-gate static	int		ckuid(void);
205*7c478bd9Sstevel@tonic-gate static	int		ckarg(int argc, char **argv, attrlist **attributes);
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate static	int		get_namelist(pwu_repository_t, char ***, int *);
208*7c478bd9Sstevel@tonic-gate static	int		get_namelist_files(char ***, int *);
209*7c478bd9Sstevel@tonic-gate static	int		get_namelist_nisplus(char ***, int *);
210*7c478bd9Sstevel@tonic-gate static	int		get_attr(char *, pwu_repository_t *, attrlist **);
211*7c478bd9Sstevel@tonic-gate static	void		display_attr(char *, attrlist *);
212*7c478bd9Sstevel@tonic-gate static	void		free_attr(attrlist *);
213*7c478bd9Sstevel@tonic-gate static	void		attrlist_add(attrlist **, attrtype, char *);
214*7c478bd9Sstevel@tonic-gate static	void		attrlist_reorder(attrlist **);
215*7c478bd9Sstevel@tonic-gate static	char		*userinput(char *, pwu_repository_t *, attrtype);
216*7c478bd9Sstevel@tonic-gate static	char		*getresponse(char *);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate /*
219*7c478bd9Sstevel@tonic-gate  * main():
220*7c478bd9Sstevel@tonic-gate  *	The main routine will call ckarg() to parse the command line
221*7c478bd9Sstevel@tonic-gate  *	arguments and call the appropriate functions to perform the
222*7c478bd9Sstevel@tonic-gate  *	tasks specified by the arguments. It allows system
223*7c478bd9Sstevel@tonic-gate  * 	administrator to add, change and display password attributes.
224*7c478bd9Sstevel@tonic-gate  * 	Non privileged user can change password or display
225*7c478bd9Sstevel@tonic-gate  * 	password attributes which corresponds to their login name.
226*7c478bd9Sstevel@tonic-gate  */
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate void
229*7c478bd9Sstevel@tonic-gate main(argc, argv)
230*7c478bd9Sstevel@tonic-gate 	int argc;
231*7c478bd9Sstevel@tonic-gate 	char *argv[];
232*7c478bd9Sstevel@tonic-gate {
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	int	flag;
235*7c478bd9Sstevel@tonic-gate 	char	**namelist;
236*7c478bd9Sstevel@tonic-gate 	int	num_user;
237*7c478bd9Sstevel@tonic-gate 	int	i;
238*7c478bd9Sstevel@tonic-gate 	attrlist *attributes = NULL;
239*7c478bd9Sstevel@tonic-gate 	char	*input;
240*7c478bd9Sstevel@tonic-gate 	int	tries = 1;
241*7c478bd9Sstevel@tonic-gate 	int	updated_reps;
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	if (prognamep = strrchr(argv[0], '/'))
245*7c478bd9Sstevel@tonic-gate 		++prognamep;
246*7c478bd9Sstevel@tonic-gate 	else
247*7c478bd9Sstevel@tonic-gate 		prognamep = argv[0];
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	auth_rep.type = NULL;
250*7c478bd9Sstevel@tonic-gate 	auth_rep.scope = NULL;
251*7c478bd9Sstevel@tonic-gate 	repository.type = NULL;
252*7c478bd9Sstevel@tonic-gate 	repository.scope = NULL;
253*7c478bd9Sstevel@tonic-gate 	repository.scope_len = 0;
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	/* initialization for variables, set locale and textdomain  */
257*7c478bd9Sstevel@tonic-gate 	i = 0;
258*7c478bd9Sstevel@tonic-gate 	flag = 0;
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 	uid = getuid();		/* get the user id */
261*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
264*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
265*7c478bd9Sstevel@tonic-gate #endif
266*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	/*
269*7c478bd9Sstevel@tonic-gate 	 * ckarg() parses the arguments. In case of an error,
270*7c478bd9Sstevel@tonic-gate 	 * it sets the retval and returns FAIL (-1).
271*7c478bd9Sstevel@tonic-gate 	 */
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	flag = ckarg(argc, argv, &attributes);
274*7c478bd9Sstevel@tonic-gate 	dprintf1("flag is %0x\n", flag);
275*7c478bd9Sstevel@tonic-gate 	if (flag == FAIL)
276*7c478bd9Sstevel@tonic-gate 		passwd_exit(retval);
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	argc -= optind;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	if (argc < 1) {
281*7c478bd9Sstevel@tonic-gate 		if ((usrname = getlogin()) == NULL) {
282*7c478bd9Sstevel@tonic-gate 			struct passwd *pass = getpwuid(uid);
283*7c478bd9Sstevel@tonic-gate 			if (pass != NULL)
284*7c478bd9Sstevel@tonic-gate 				usrname = pass->pw_name;
285*7c478bd9Sstevel@tonic-gate 			else {
286*7c478bd9Sstevel@tonic-gate 				rusage();
287*7c478bd9Sstevel@tonic-gate 				exit(NOPERM);
288*7c478bd9Sstevel@tonic-gate 			}
289*7c478bd9Sstevel@tonic-gate 		} else if (flag == 0) {
290*7c478bd9Sstevel@tonic-gate 			/*
291*7c478bd9Sstevel@tonic-gate 			 * If flag is zero, change passwd.
292*7c478bd9Sstevel@tonic-gate 			 * Otherwise, it will display or
293*7c478bd9Sstevel@tonic-gate 			 * modify password aging attributes
294*7c478bd9Sstevel@tonic-gate 			 */
295*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(MSG_INFO), prognamep,
296*7c478bd9Sstevel@tonic-gate 			    usrname);
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 	} else
299*7c478bd9Sstevel@tonic-gate 		usrname = argv[optind];
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS)
302*7c478bd9Sstevel@tonic-gate 		passwd_exit(NOPERM);
303*7c478bd9Sstevel@tonic-gate 
304*7c478bd9Sstevel@tonic-gate 	auth_rep.type = repository.type;
305*7c478bd9Sstevel@tonic-gate 	auth_rep.scope = repository.scope;
306*7c478bd9Sstevel@tonic-gate 	auth_rep.scope_len = repository.scope_len;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	if (auth_rep.type != NULL) {
309*7c478bd9Sstevel@tonic-gate 		if (pam_set_item(pamh, PAM_REPOSITORY, (void *)&auth_rep)
310*7c478bd9Sstevel@tonic-gate 		    != PAM_SUCCESS) {
311*7c478bd9Sstevel@tonic-gate 			passwd_exit(NOPERM);
312*7c478bd9Sstevel@tonic-gate 		}
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	if (flag ==  SAFLAG) {	/* display password attributes for all users */
316*7c478bd9Sstevel@tonic-gate 		retval = get_namelist(repository, &namelist, &num_user);
317*7c478bd9Sstevel@tonic-gate 		if (retval != SUCCESS)
318*7c478bd9Sstevel@tonic-gate 			(void) passwd_exit(retval);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 		if (num_user == 0) {
321*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: %s\n", prognamep,
322*7c478bd9Sstevel@tonic-gate 					gettext(MSG_FF));
323*7c478bd9Sstevel@tonic-gate 			passwd_exit(FATAL);
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 		i = 0;
326*7c478bd9Sstevel@tonic-gate 		while (namelist[i] != NULL) {
327*7c478bd9Sstevel@tonic-gate 			(void) get_attr(namelist[i], &repository,
328*7c478bd9Sstevel@tonic-gate 			    &attributes);
329*7c478bd9Sstevel@tonic-gate 			(void) display_attr(namelist[i], attributes);
330*7c478bd9Sstevel@tonic-gate 			(void) free(namelist[i]);
331*7c478bd9Sstevel@tonic-gate 			(void) free_attr(attributes);
332*7c478bd9Sstevel@tonic-gate 			i++;
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 		(void) free(namelist);
335*7c478bd9Sstevel@tonic-gate 		passwd_exit(SUCCESS);
336*7c478bd9Sstevel@tonic-gate 	} else if (flag == SFLAG) { /* display password attributes by user */
337*7c478bd9Sstevel@tonic-gate 		if (get_attr(usrname, &repository, &attributes) ==
338*7c478bd9Sstevel@tonic-gate 		    PWU_SUCCESS) {
339*7c478bd9Sstevel@tonic-gate 			(void) display_attr(usrname, attributes);
340*7c478bd9Sstevel@tonic-gate 			(void) free_attr(attributes);
341*7c478bd9Sstevel@tonic-gate 		}
342*7c478bd9Sstevel@tonic-gate 		passwd_exit(SUCCESS);
343*7c478bd9Sstevel@tonic-gate 		/* NOT REACHED */
344*7c478bd9Sstevel@tonic-gate 	}
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 	switch (pam_authenticate(pamh, 0)) {
348*7c478bd9Sstevel@tonic-gate 	case PAM_SUCCESS:
349*7c478bd9Sstevel@tonic-gate 		break;
350*7c478bd9Sstevel@tonic-gate 	case PAM_USER_UNKNOWN:
351*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(MSG_UNKNOWN), prognamep,
352*7c478bd9Sstevel@tonic-gate 		    usrname);
353*7c478bd9Sstevel@tonic-gate 		passwd_exit(NOPERM);
354*7c478bd9Sstevel@tonic-gate 		break;
355*7c478bd9Sstevel@tonic-gate 	case PAM_PERM_DENIED:
356*7c478bd9Sstevel@tonic-gate 		passwd_exit(NOPERM);
357*7c478bd9Sstevel@tonic-gate 		break;
358*7c478bd9Sstevel@tonic-gate 	case PAM_AUTH_ERR:
359*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(MSG_SORRY), prognamep);
360*7c478bd9Sstevel@tonic-gate 		passwd_exit(NOPERM);
361*7c478bd9Sstevel@tonic-gate 		break;
362*7c478bd9Sstevel@tonic-gate 	default:
363*7c478bd9Sstevel@tonic-gate 		/* system error */
364*7c478bd9Sstevel@tonic-gate 		passwd_exit(FMERR);
365*7c478bd9Sstevel@tonic-gate 		break;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	if (flag == 0) {			/* changing user password */
369*7c478bd9Sstevel@tonic-gate 		int	chk_authtok = 0;	/* check password strength */
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 		dprintf1("call pam_chauthtok() repository name =%s\n",
372*7c478bd9Sstevel@tonic-gate 		    repository.type);
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate 		/* Set up for Audit */
375*7c478bd9Sstevel@tonic-gate 		if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
376*7c478bd9Sstevel@tonic-gate 			perror("adt_start_session");
377*7c478bd9Sstevel@tonic-gate 			passwd_exit(SYSERR);
378*7c478bd9Sstevel@tonic-gate 		}
379*7c478bd9Sstevel@tonic-gate 		if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
380*7c478bd9Sstevel@tonic-gate 			perror("adt_alloc_event");
381*7c478bd9Sstevel@tonic-gate 			passwd_exit(NOMEM);
382*7c478bd9Sstevel@tonic-gate 		}
383*7c478bd9Sstevel@tonic-gate 		if (argc >= 1) {
384*7c478bd9Sstevel@tonic-gate 			/* save target user */
385*7c478bd9Sstevel@tonic-gate 			event->adt_passwd.username = usrname;
386*7c478bd9Sstevel@tonic-gate 		}
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 		/* Don't check account expiration when invoked by root */
389*7c478bd9Sstevel@tonic-gate 		if (ckuid() != SUCCESS) {
390*7c478bd9Sstevel@tonic-gate 			pam_retval = pam_acct_mgmt(pamh, PAM_SILENT);
391*7c478bd9Sstevel@tonic-gate 			switch (pam_retval) {
392*7c478bd9Sstevel@tonic-gate 			case PAM_ACCT_EXPIRED:
393*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
394*7c478bd9Sstevel@tonic-gate 				    gettext(MSG_ACCOUNT_EXP), usrname);
395*7c478bd9Sstevel@tonic-gate 				passwd_exit(EXPIRED);
396*7c478bd9Sstevel@tonic-gate 				break;
397*7c478bd9Sstevel@tonic-gate 			case PAM_AUTHTOK_EXPIRED:
398*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
399*7c478bd9Sstevel@tonic-gate 				    gettext(MSG_AUTHTOK_EXP));
400*7c478bd9Sstevel@tonic-gate 				passwd_exit(NOPERM);
401*7c478bd9Sstevel@tonic-gate 				break;
402*7c478bd9Sstevel@tonic-gate 			case PAM_NEW_AUTHTOK_REQD:
403*7c478bd9Sstevel@tonic-gate 				/* valid error when changing passwords */
404*7c478bd9Sstevel@tonic-gate 				break;
405*7c478bd9Sstevel@tonic-gate 			case PAM_SUCCESS:
406*7c478bd9Sstevel@tonic-gate 				/* Ok to change password */
407*7c478bd9Sstevel@tonic-gate 				break;
408*7c478bd9Sstevel@tonic-gate 			default:
409*7c478bd9Sstevel@tonic-gate 				passwd_exit(NOPERM);
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 		}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 		pam_retval = PAM_AUTHTOK_ERR;
415*7c478bd9Sstevel@tonic-gate 		tries = 1;
416*7c478bd9Sstevel@tonic-gate 		if (ckuid() == SUCCESS) {
417*7c478bd9Sstevel@tonic-gate 			/* bypass password strength checks */
418*7c478bd9Sstevel@tonic-gate 			chk_authtok = PAM_NO_AUTHTOK_CHECK;
419*7c478bd9Sstevel@tonic-gate 		}
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		while (pam_retval == PAM_AUTHTOK_ERR && tries <= DEF_ATTEMPTS) {
422*7c478bd9Sstevel@tonic-gate 			if (tries > 1)
423*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(MSG_AGAIN));
424*7c478bd9Sstevel@tonic-gate 			pam_retval = pam_chauthtok(pamh, chk_authtok);
425*7c478bd9Sstevel@tonic-gate 			if (pam_retval == PAM_TRY_AGAIN) {
426*7c478bd9Sstevel@tonic-gate 				(void) sleep(1);
427*7c478bd9Sstevel@tonic-gate 				pam_retval = pam_chauthtok(pamh, chk_authtok);
428*7c478bd9Sstevel@tonic-gate 			}
429*7c478bd9Sstevel@tonic-gate 			tries++;
430*7c478bd9Sstevel@tonic-gate 		}
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 		switch (pam_retval) {
433*7c478bd9Sstevel@tonic-gate 		case PAM_SUCCESS:
434*7c478bd9Sstevel@tonic-gate 			retval = SUCCESS;
435*7c478bd9Sstevel@tonic-gate 			break;
436*7c478bd9Sstevel@tonic-gate 		case PAM_AUTHTOK_DISABLE_AGING:
437*7c478bd9Sstevel@tonic-gate 			retval = BADAGE;
438*7c478bd9Sstevel@tonic-gate 			break;
439*7c478bd9Sstevel@tonic-gate 		case PAM_AUTHTOK_LOCK_BUSY:
440*7c478bd9Sstevel@tonic-gate 			retval = FBUSY;
441*7c478bd9Sstevel@tonic-gate 			break;
442*7c478bd9Sstevel@tonic-gate 		case PAM_TRY_AGAIN:
443*7c478bd9Sstevel@tonic-gate 			retval = FBUSY;
444*7c478bd9Sstevel@tonic-gate 			break;
445*7c478bd9Sstevel@tonic-gate 		case PAM_AUTHTOK_ERR:
446*7c478bd9Sstevel@tonic-gate 		case PAM_AUTHTOK_RECOVERY_ERR:
447*7c478bd9Sstevel@tonic-gate 		default:
448*7c478bd9Sstevel@tonic-gate 			retval = NOPERM;
449*7c478bd9Sstevel@tonic-gate 			break;
450*7c478bd9Sstevel@tonic-gate 		}
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 		(void) passwd_exit(retval);
453*7c478bd9Sstevel@tonic-gate 		/* NOT REACHED */
454*7c478bd9Sstevel@tonic-gate 	} else {		/* changing attributes */
455*7c478bd9Sstevel@tonic-gate 		switch (flag) {
456*7c478bd9Sstevel@tonic-gate 		case EFLAG:		/* changing user password attributes */
457*7c478bd9Sstevel@tonic-gate 			input = userinput(usrname, &repository, ATTR_SHELL);
458*7c478bd9Sstevel@tonic-gate 			if (input)
459*7c478bd9Sstevel@tonic-gate 				attrlist_add(&attributes, ATTR_SHELL, input);
460*7c478bd9Sstevel@tonic-gate 			else
461*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(MSG_SHELL_UNCHANGED));
462*7c478bd9Sstevel@tonic-gate 			break;
463*7c478bd9Sstevel@tonic-gate 		case GFLAG:
464*7c478bd9Sstevel@tonic-gate 			input = userinput(usrname, &repository, ATTR_GECOS);
465*7c478bd9Sstevel@tonic-gate 			if (input)
466*7c478bd9Sstevel@tonic-gate 				attrlist_add(&attributes, ATTR_GECOS, input);
467*7c478bd9Sstevel@tonic-gate 			else
468*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(MSG_GECOS_UNCHANGED));
469*7c478bd9Sstevel@tonic-gate 			break;
470*7c478bd9Sstevel@tonic-gate 		case HFLAG:
471*7c478bd9Sstevel@tonic-gate 			input = userinput(usrname, &repository, ATTR_HOMEDIR);
472*7c478bd9Sstevel@tonic-gate 			if (input)
473*7c478bd9Sstevel@tonic-gate 				attrlist_add(&attributes, ATTR_HOMEDIR, input);
474*7c478bd9Sstevel@tonic-gate 			else
475*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext(MSG_DIR_UNCHANGED));
476*7c478bd9Sstevel@tonic-gate 			break;
477*7c478bd9Sstevel@tonic-gate 		}
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		if (attributes != NULL) {
480*7c478bd9Sstevel@tonic-gate 			retval = __set_authtoken_attr(usrname,
481*7c478bd9Sstevel@tonic-gate 			    pamh->ps_item[PAM_AUTHTOK].pi_addr,
482*7c478bd9Sstevel@tonic-gate 			    NULL, &repository, attributes, &updated_reps);
483*7c478bd9Sstevel@tonic-gate 			switch (retval) {
484*7c478bd9Sstevel@tonic-gate 			case PWU_SUCCESS:
485*7c478bd9Sstevel@tonic-gate 				for (i = 1; i <= REP_LAST; i <<= 1) {
486*7c478bd9Sstevel@tonic-gate 					if ((updated_reps & i) == 0)
487*7c478bd9Sstevel@tonic-gate 						continue;
488*7c478bd9Sstevel@tonic-gate 					(void) printf(gettext(MSG_SUCCESS),
489*7c478bd9Sstevel@tonic-gate 					    prognamep, usrname);
490*7c478bd9Sstevel@tonic-gate 				}
491*7c478bd9Sstevel@tonic-gate 				retval = SUCCESS;
492*7c478bd9Sstevel@tonic-gate 				break;
493*7c478bd9Sstevel@tonic-gate 			case PWU_AGING_DISABLED:
494*7c478bd9Sstevel@tonic-gate 				retval = BADAGE;
495*7c478bd9Sstevel@tonic-gate 				break;
496*7c478bd9Sstevel@tonic-gate 			default:
497*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
498*7c478bd9Sstevel@tonic-gate 				break;
499*7c478bd9Sstevel@tonic-gate 			}
500*7c478bd9Sstevel@tonic-gate 		} else {
501*7c478bd9Sstevel@tonic-gate 			retval = SUCCESS; /* nothing to change won't fail */
502*7c478bd9Sstevel@tonic-gate 		}
503*7c478bd9Sstevel@tonic-gate 		(void) passwd_exit(retval);
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate }
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate /*
508*7c478bd9Sstevel@tonic-gate  * Get a line of input from the user.
509*7c478bd9Sstevel@tonic-gate  *
510*7c478bd9Sstevel@tonic-gate  * If the line is empty, or the input equals 'oldval', NULL is returned.
511*7c478bd9Sstevel@tonic-gate  * therwise, a malloced string containing the input (minus the trailing
512*7c478bd9Sstevel@tonic-gate  * newline) is returned.
513*7c478bd9Sstevel@tonic-gate  */
514*7c478bd9Sstevel@tonic-gate char *
515*7c478bd9Sstevel@tonic-gate getresponse(char *oldval)
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	char    resp[MAX_INPUT_LEN];
518*7c478bd9Sstevel@tonic-gate 	char    *retval = NULL;
519*7c478bd9Sstevel@tonic-gate 	int	resplen;
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 	(void) fgets(resp, sizeof (resp) - 1, stdin);
522*7c478bd9Sstevel@tonic-gate 	resplen = strlen(resp) - 1;
523*7c478bd9Sstevel@tonic-gate 	if (resp[resplen] == '\n')
524*7c478bd9Sstevel@tonic-gate 		resp[resplen] = '\0';
525*7c478bd9Sstevel@tonic-gate 	if (*resp != '\0' && strcmp(resp, oldval) != 0)
526*7c478bd9Sstevel@tonic-gate 		retval = strdup(resp);
527*7c478bd9Sstevel@tonic-gate 	return (retval);
528*7c478bd9Sstevel@tonic-gate }
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate /*
531*7c478bd9Sstevel@tonic-gate  * char *userinput(item)
532*7c478bd9Sstevel@tonic-gate  *
533*7c478bd9Sstevel@tonic-gate  * user conversation function. The old value of attribute "item" is
534*7c478bd9Sstevel@tonic-gate  * displayed while the user is asked to provide a new value.
535*7c478bd9Sstevel@tonic-gate  *
536*7c478bd9Sstevel@tonic-gate  * returns a malloc()-ed string if the user actualy provided input
537*7c478bd9Sstevel@tonic-gate  * or NULL if the user simply hit return or the input equals the old
538*7c478bd9Sstevel@tonic-gate  * value (not changed).
539*7c478bd9Sstevel@tonic-gate  */
540*7c478bd9Sstevel@tonic-gate char *
541*7c478bd9Sstevel@tonic-gate userinput(char *name, pwu_repository_t *rep, attrtype type)
542*7c478bd9Sstevel@tonic-gate {
543*7c478bd9Sstevel@tonic-gate 	attrlist oldattr;
544*7c478bd9Sstevel@tonic-gate 	char *oldval;			/* shorthand for oldattr.data.val_s */
545*7c478bd9Sstevel@tonic-gate 	char *valid;			/* points to valid shells */
546*7c478bd9Sstevel@tonic-gate 	char *response;
547*7c478bd9Sstevel@tonic-gate 	char *cp;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	oldattr.type = type;
550*7c478bd9Sstevel@tonic-gate 	oldattr.next = NULL;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	if (__get_authtoken_attr(name, rep, &oldattr) != PWU_SUCCESS)
553*7c478bd9Sstevel@tonic-gate 		passwd_exit(FMERR);
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	oldval = oldattr.data.val_s;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (type == ATTR_SHELL) {
558*7c478bd9Sstevel@tonic-gate 		/* No current shell: set DEFSHL as default choice */
559*7c478bd9Sstevel@tonic-gate 		if (*oldval == '\0') {
560*7c478bd9Sstevel@tonic-gate 			free(oldval);
561*7c478bd9Sstevel@tonic-gate 			oldval = strdup(DEFSHL);
562*7c478bd9Sstevel@tonic-gate 		}
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		if (ckuid() != SUCCESS) {
565*7c478bd9Sstevel@tonic-gate 			/* User must currently have a valid shell */
566*7c478bd9Sstevel@tonic-gate 			setusershell();
567*7c478bd9Sstevel@tonic-gate 			valid = getusershell();
568*7c478bd9Sstevel@tonic-gate 			while (valid && strcmp(valid, oldval) != 0)
569*7c478bd9Sstevel@tonic-gate 				valid = getusershell();
570*7c478bd9Sstevel@tonic-gate 			endusershell();
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 			if (valid == NULL) {
573*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(MSG_RS), oldval);
574*7c478bd9Sstevel@tonic-gate 				free(oldval);
575*7c478bd9Sstevel@tonic-gate 				return (NULL);
576*7c478bd9Sstevel@tonic-gate 			}
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext(MSG_OLDSHELL), oldval);
579*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext(MSG_NEWSHELL));
580*7c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 		response = getresponse(oldval);
583*7c478bd9Sstevel@tonic-gate 		free(oldval); /* We don't need the old value anymore */
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 		if (response == NULL || *response == '\0')
586*7c478bd9Sstevel@tonic-gate 			return (NULL);
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 		/* Make sure new shell is listed */
589*7c478bd9Sstevel@tonic-gate 		setusershell();
590*7c478bd9Sstevel@tonic-gate 		valid = getusershell();
591*7c478bd9Sstevel@tonic-gate 		while (valid) {
592*7c478bd9Sstevel@tonic-gate 			char *cp;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 			/* Allow user to give shell without path */
595*7c478bd9Sstevel@tonic-gate 			if (*response == '/') {
596*7c478bd9Sstevel@tonic-gate 				cp = valid;
597*7c478bd9Sstevel@tonic-gate 			} else {
598*7c478bd9Sstevel@tonic-gate 				if ((cp = strrchr(valid, '/')) == NULL)
599*7c478bd9Sstevel@tonic-gate 					cp = valid;
600*7c478bd9Sstevel@tonic-gate 				else
601*7c478bd9Sstevel@tonic-gate 					cp++;
602*7c478bd9Sstevel@tonic-gate 			}
603*7c478bd9Sstevel@tonic-gate 			if (strcmp(cp, response) == 0) {
604*7c478bd9Sstevel@tonic-gate 				if (*response != '/') {
605*7c478bd9Sstevel@tonic-gate 					/* take shell name including path */
606*7c478bd9Sstevel@tonic-gate 					free(response);
607*7c478bd9Sstevel@tonic-gate 					response = strdup(valid);
608*7c478bd9Sstevel@tonic-gate 				}
609*7c478bd9Sstevel@tonic-gate 				break;
610*7c478bd9Sstevel@tonic-gate 			}
611*7c478bd9Sstevel@tonic-gate 			valid = getusershell();
612*7c478bd9Sstevel@tonic-gate 		}
613*7c478bd9Sstevel@tonic-gate 		endusershell();
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 		if (valid == NULL) {    /* No valid shell matches */
616*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(MSG_UNACCEPT), response);
617*7c478bd9Sstevel@tonic-gate 			return (NULL);
618*7c478bd9Sstevel@tonic-gate 		}
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 		if (access(response, X_OK) < 0)
621*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(MSG_UNAVAIL), response);
622*7c478bd9Sstevel@tonic-gate 		return (response);
623*7c478bd9Sstevel@tonic-gate 		/* NOT REACHED */
624*7c478bd9Sstevel@tonic-gate 	}
625*7c478bd9Sstevel@tonic-gate 	/*
626*7c478bd9Sstevel@tonic-gate 	 * if type == SHELL, we have returned by now. Only GECOS and
627*7c478bd9Sstevel@tonic-gate 	 * HOMEDIR get to this point.
628*7c478bd9Sstevel@tonic-gate 	 */
629*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext(MSG_INPUTHDR));
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	/*
632*7c478bd9Sstevel@tonic-gate 	 * PRE: oldval points to malloced string with Old Value
633*7c478bd9Sstevel@tonic-gate 	 * INV: oldval remains unchanged
634*7c478bd9Sstevel@tonic-gate 	 * POST:response points to valid string or NULL.
635*7c478bd9Sstevel@tonic-gate 	 */
636*7c478bd9Sstevel@tonic-gate 	for (;;) {
637*7c478bd9Sstevel@tonic-gate 		if (type == ATTR_GECOS)
638*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(MSG_NAME), oldval);
639*7c478bd9Sstevel@tonic-gate 		else if (type == ATTR_HOMEDIR)
640*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext(MSG_HOMEDIR), oldval);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 		response = getresponse(oldval);
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		if (response && strcmp(response, "none") == 0)
645*7c478bd9Sstevel@tonic-gate 			*response = '\0';
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 		/* No-change or empty string are OK */
648*7c478bd9Sstevel@tonic-gate 		if (response == NULL || *response == '\0')
649*7c478bd9Sstevel@tonic-gate 			break;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 		/* Check for illegal characters */
652*7c478bd9Sstevel@tonic-gate 		if (strchr(response, ':')) {
653*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s", gettext(MSG_COLON));
654*7c478bd9Sstevel@tonic-gate 			free(response);
655*7c478bd9Sstevel@tonic-gate 		} else if (strlen(response) > MAX_INPUT_LEN - 1) {
656*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(MSG_MAXLEN),
657*7c478bd9Sstevel@tonic-gate 			    MAX_INPUT_LEN);
658*7c478bd9Sstevel@tonic-gate 			free(response);
659*7c478bd9Sstevel@tonic-gate 		} else {
660*7c478bd9Sstevel@tonic-gate 			/* don't allow control characters */
661*7c478bd9Sstevel@tonic-gate 			for (cp = response; *cp >= 040; cp++)
662*7c478bd9Sstevel@tonic-gate 				;
663*7c478bd9Sstevel@tonic-gate 			if (*cp != '\0') {
664*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(MSG_CONTROL));
665*7c478bd9Sstevel@tonic-gate 				free(response);
666*7c478bd9Sstevel@tonic-gate 			} else
667*7c478bd9Sstevel@tonic-gate 				break;	/* response is a valid string */
668*7c478bd9Sstevel@tonic-gate 		}
669*7c478bd9Sstevel@tonic-gate 		/*
670*7c478bd9Sstevel@tonic-gate 		 * We only get here if the input was invalid.
671*7c478bd9Sstevel@tonic-gate 		 * In that case, we again ask the user for input.
672*7c478bd9Sstevel@tonic-gate 		 */
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 	free(oldval);
675*7c478bd9Sstevel@tonic-gate 	return (response);
676*7c478bd9Sstevel@tonic-gate }
677*7c478bd9Sstevel@tonic-gate /*
678*7c478bd9Sstevel@tonic-gate  * ckarg():
679*7c478bd9Sstevel@tonic-gate  *	This function parses and verifies the
680*7c478bd9Sstevel@tonic-gate  * 	arguments.  It takes three parameters:
681*7c478bd9Sstevel@tonic-gate  * 	argc => # of arguments
682*7c478bd9Sstevel@tonic-gate  * 	argv => pointer to an argument
683*7c478bd9Sstevel@tonic-gate  * 	attrlist => pointer to list of password attributes
684*7c478bd9Sstevel@tonic-gate  */
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate static int
687*7c478bd9Sstevel@tonic-gate ckarg(int argc, char **argv, attrlist **attributes)
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	extern char	*optarg;
690*7c478bd9Sstevel@tonic-gate 	char		*char_p;
691*7c478bd9Sstevel@tonic-gate 	int	opt;
692*7c478bd9Sstevel@tonic-gate 	int	flag;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	flag = 0;
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:D:N")) != EOF) {
697*7c478bd9Sstevel@tonic-gate 		switch (opt) {
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 		case 'r': /* Repository Specified */
700*7c478bd9Sstevel@tonic-gate 			/* repository: this option should be specified first */
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 			if (repository.type != NULL) {
703*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
704*7c478bd9Sstevel@tonic-gate 			"Repository is already defined or specified.\n"));
705*7c478bd9Sstevel@tonic-gate 				rusage();
706*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
707*7c478bd9Sstevel@tonic-gate 				return (FAIL);
708*7c478bd9Sstevel@tonic-gate 			}
709*7c478bd9Sstevel@tonic-gate 			if (strcmp(optarg, "nisplus") == 0) {
710*7c478bd9Sstevel@tonic-gate 				repository.type = optarg;
711*7c478bd9Sstevel@tonic-gate 				repository.scope = nis_local_directory();
712*7c478bd9Sstevel@tonic-gate 				if (repository.scope != NULL) {
713*7c478bd9Sstevel@tonic-gate 					repository.scope_len =
714*7c478bd9Sstevel@tonic-gate 					    strlen(repository.scope)+ 1;
715*7c478bd9Sstevel@tonic-gate 				}
716*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(optarg, "nis") == 0) {
717*7c478bd9Sstevel@tonic-gate 				repository.type = optarg;
718*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(optarg, "ldap") == 0) {
719*7c478bd9Sstevel@tonic-gate 				repository.type = optarg;
720*7c478bd9Sstevel@tonic-gate 			} else if (strcmp(optarg, "files") == 0) {
721*7c478bd9Sstevel@tonic-gate 				repository.type = optarg;
722*7c478bd9Sstevel@tonic-gate 			} else {
723*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
724*7c478bd9Sstevel@tonic-gate 				    gettext("invalid repository: %s\n"),
725*7c478bd9Sstevel@tonic-gate 				    optarg);
726*7c478bd9Sstevel@tonic-gate 				rusage();
727*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
728*7c478bd9Sstevel@tonic-gate 				return (FAIL);
729*7c478bd9Sstevel@tonic-gate 			}
730*7c478bd9Sstevel@tonic-gate 			break;
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 		case 'd': /* Delete Auth Token */
733*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -d is files */
734*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
735*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 			/*
738*7c478bd9Sstevel@tonic-gate 			 * Delete the password - only privileged processes
739*7c478bd9Sstevel@tonic-gate 			 * can execute this for FILES
740*7c478bd9Sstevel@tonic-gate 			 */
741*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE) {
742*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
743*7c478bd9Sstevel@tonic-gate 				    "-d only applies to files repository\n"));
744*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
745*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
746*7c478bd9Sstevel@tonic-gate 				return (FAIL);
747*7c478bd9Sstevel@tonic-gate 			}
748*7c478bd9Sstevel@tonic-gate 
749*7c478bd9Sstevel@tonic-gate 			if (ckuid() != SUCCESS) {
750*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
751*7c478bd9Sstevel@tonic-gate 				return (FAIL);
752*7c478bd9Sstevel@tonic-gate 			}
753*7c478bd9Sstevel@tonic-gate 			if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG)) {
754*7c478bd9Sstevel@tonic-gate 				rusage();
755*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
756*7c478bd9Sstevel@tonic-gate 				return (FAIL);
757*7c478bd9Sstevel@tonic-gate 			}
758*7c478bd9Sstevel@tonic-gate 			flag |= DFLAG;
759*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_PASSWD, NULL);
760*7c478bd9Sstevel@tonic-gate 			break;
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 		case 'N': /* set account to be "no login" */
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -N is files */
765*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
766*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
769*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
770*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
771*7c478bd9Sstevel@tonic-gate 			"-N only applies to files or nisplus repository\n"));
772*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
773*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
774*7c478bd9Sstevel@tonic-gate 				return (FAIL);
775*7c478bd9Sstevel@tonic-gate 			}
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 			/*
778*7c478bd9Sstevel@tonic-gate 			 * Only privileged processes can execute this
779*7c478bd9Sstevel@tonic-gate 			 * for FILES
780*7c478bd9Sstevel@tonic-gate 			 */
781*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
782*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
783*7c478bd9Sstevel@tonic-gate 				return (FAIL);
784*7c478bd9Sstevel@tonic-gate 			if (flag & (MUTEXFLAG|NONAGEFLAG)) {
785*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
786*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
787*7c478bd9Sstevel@tonic-gate 				return (FAIL);
788*7c478bd9Sstevel@tonic-gate 			}
789*7c478bd9Sstevel@tonic-gate 			flag |= XFLAG;
790*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_NOLOGIN_ACCOUNT, NULL);
791*7c478bd9Sstevel@tonic-gate 			break;
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 		case 'l': /* lock the password */
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -l is files */
796*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
797*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
800*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
801*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
802*7c478bd9Sstevel@tonic-gate 			"-l only applies to files or nisplus repository\n"));
803*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
804*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
805*7c478bd9Sstevel@tonic-gate 				return (FAIL);
806*7c478bd9Sstevel@tonic-gate 			}
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 			/*
809*7c478bd9Sstevel@tonic-gate 			 * Only privileged processes can execute this
810*7c478bd9Sstevel@tonic-gate 			 * for FILES
811*7c478bd9Sstevel@tonic-gate 			 */
812*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
813*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
814*7c478bd9Sstevel@tonic-gate 				return (FAIL);
815*7c478bd9Sstevel@tonic-gate 			if (flag & (MUTEXFLAG|NONAGEFLAG)) {
816*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
817*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
818*7c478bd9Sstevel@tonic-gate 				return (FAIL);
819*7c478bd9Sstevel@tonic-gate 			}
820*7c478bd9Sstevel@tonic-gate 			flag |= LFLAG;
821*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_LOCK_ACCOUNT, NULL);
822*7c478bd9Sstevel@tonic-gate 			break;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 		case 'u': /* unlock the password */
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -u is files */
827*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
828*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
831*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
832*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
833*7c478bd9Sstevel@tonic-gate 			"-u only applies to files or nisplus repository\n"));
834*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
835*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
836*7c478bd9Sstevel@tonic-gate 				return (FAIL);
837*7c478bd9Sstevel@tonic-gate 			}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 			/*
840*7c478bd9Sstevel@tonic-gate 			 * Only privileged processes can execute this
841*7c478bd9Sstevel@tonic-gate 			 * for FILES
842*7c478bd9Sstevel@tonic-gate 			 */
843*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
844*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
845*7c478bd9Sstevel@tonic-gate 				return (FAIL);
846*7c478bd9Sstevel@tonic-gate 			if (flag & (MUTEXFLAG|NONAGEFLAG)) {
847*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
848*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
849*7c478bd9Sstevel@tonic-gate 				return (FAIL);
850*7c478bd9Sstevel@tonic-gate 			}
851*7c478bd9Sstevel@tonic-gate 			flag |= UFLAG;
852*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_UNLOCK_ACCOUNT, NULL);
853*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_RST_FAILED_LOGINS, NULL);
854*7c478bd9Sstevel@tonic-gate 			break;
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 		case 'x': /* set the max date */
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -x is files */
859*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
860*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
863*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
864*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
865*7c478bd9Sstevel@tonic-gate 			"-x only applies to files or nisplus repository\n"));
866*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
867*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
868*7c478bd9Sstevel@tonic-gate 				return (FAIL);
869*7c478bd9Sstevel@tonic-gate 			}
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 			/*
872*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
873*7c478bd9Sstevel@tonic-gate 			 * for FILES
874*7c478bd9Sstevel@tonic-gate 			 */
875*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
876*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
877*7c478bd9Sstevel@tonic-gate 				return (FAIL);
878*7c478bd9Sstevel@tonic-gate 			}
879*7c478bd9Sstevel@tonic-gate 			if (flag & (SAFLAG|MFLAG|NONAGEFLAG)) {
880*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
881*7c478bd9Sstevel@tonic-gate 				return (FAIL);
882*7c478bd9Sstevel@tonic-gate 			}
883*7c478bd9Sstevel@tonic-gate 			flag |= MFLAG;
884*7c478bd9Sstevel@tonic-gate 			if ((int)strlen(optarg)  <= 0 ||
885*7c478bd9Sstevel@tonic-gate 			    (maxdate = strtol(optarg, &char_p, 10)) < -1 ||
886*7c478bd9Sstevel@tonic-gate 			    *char_p != '\0') {
887*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s -x\n",
888*7c478bd9Sstevel@tonic-gate 					prognamep, gettext(MSG_NV));
889*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
890*7c478bd9Sstevel@tonic-gate 				return (FAIL);
891*7c478bd9Sstevel@tonic-gate 			}
892*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_MAX, optarg);
893*7c478bd9Sstevel@tonic-gate 			break;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 		case 'n': /* set the min date */
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -n is files */
898*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
899*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
902*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
903*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
904*7c478bd9Sstevel@tonic-gate 			"-n only applies to files or nisplus repository\n"));
905*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
906*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
907*7c478bd9Sstevel@tonic-gate 				return (FAIL);
908*7c478bd9Sstevel@tonic-gate 			}
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 			/*
911*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
912*7c478bd9Sstevel@tonic-gate 			 * for FILES
913*7c478bd9Sstevel@tonic-gate 			 */
914*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
915*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
916*7c478bd9Sstevel@tonic-gate 				return (FAIL);
917*7c478bd9Sstevel@tonic-gate 			if (flag & (SAFLAG|NFLAG|NONAGEFLAG)) {
918*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
919*7c478bd9Sstevel@tonic-gate 				return (FAIL);
920*7c478bd9Sstevel@tonic-gate 			}
921*7c478bd9Sstevel@tonic-gate 			flag |= NFLAG;
922*7c478bd9Sstevel@tonic-gate 			if ((int)strlen(optarg)  <= 0 ||
923*7c478bd9Sstevel@tonic-gate 			    (strtol(optarg, &char_p, 10)) < 0 ||
924*7c478bd9Sstevel@tonic-gate 			    *char_p != '\0') {
925*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s -n\n",
926*7c478bd9Sstevel@tonic-gate 					prognamep, gettext(MSG_NV));
927*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
928*7c478bd9Sstevel@tonic-gate 				return (FAIL);
929*7c478bd9Sstevel@tonic-gate 			}
930*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_MIN, optarg);
931*7c478bd9Sstevel@tonic-gate 			break;
932*7c478bd9Sstevel@tonic-gate 
933*7c478bd9Sstevel@tonic-gate 		case 'w': /* set the warning field */
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -w is files */
936*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
937*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
940*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
941*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
942*7c478bd9Sstevel@tonic-gate 			"-w only applies to files or nisplus repository\n"));
943*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
944*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
945*7c478bd9Sstevel@tonic-gate 				return (FAIL);
946*7c478bd9Sstevel@tonic-gate 			}
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate 			/*
949*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
950*7c478bd9Sstevel@tonic-gate 			 * for FILES
951*7c478bd9Sstevel@tonic-gate 			 */
952*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
953*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
954*7c478bd9Sstevel@tonic-gate 				return (FAIL);
955*7c478bd9Sstevel@tonic-gate 			}
956*7c478bd9Sstevel@tonic-gate 			if (flag & (SAFLAG|WFLAG|NONAGEFLAG)) {
957*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
958*7c478bd9Sstevel@tonic-gate 				return (FAIL);
959*7c478bd9Sstevel@tonic-gate 			}
960*7c478bd9Sstevel@tonic-gate 			flag |= WFLAG;
961*7c478bd9Sstevel@tonic-gate 			if ((int)strlen(optarg)  <= 0 ||
962*7c478bd9Sstevel@tonic-gate 			    (strtol(optarg, &char_p, 10)) < 0 ||
963*7c478bd9Sstevel@tonic-gate 			    *char_p != '\0') {
964*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: %s -w\n",
965*7c478bd9Sstevel@tonic-gate 					prognamep, gettext(MSG_NV));
966*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
967*7c478bd9Sstevel@tonic-gate 				return (FAIL);
968*7c478bd9Sstevel@tonic-gate 			}
969*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_WARN, optarg);
970*7c478bd9Sstevel@tonic-gate 			break;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 		case 's': /* display password attributes */
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -s is files */
975*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
976*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 			/* display password attributes */
980*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
981*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
982*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
983*7c478bd9Sstevel@tonic-gate 			"-s only applies to files or nisplus repository\n"));
984*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
985*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
986*7c478bd9Sstevel@tonic-gate 				return (FAIL);
987*7c478bd9Sstevel@tonic-gate 			}
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 			/*
990*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
991*7c478bd9Sstevel@tonic-gate 			 * for FILES
992*7c478bd9Sstevel@tonic-gate 			 */
993*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
994*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
995*7c478bd9Sstevel@tonic-gate 				return (FAIL);
996*7c478bd9Sstevel@tonic-gate 			if (flag && (flag != AFLAG)) {
997*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
998*7c478bd9Sstevel@tonic-gate 				return (FAIL);
999*7c478bd9Sstevel@tonic-gate 			}
1000*7c478bd9Sstevel@tonic-gate 			flag |= SFLAG;
1001*7c478bd9Sstevel@tonic-gate 			break;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 		case 'a': /* display password attributes */
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -a is files */
1006*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
1007*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
1010*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
1011*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1012*7c478bd9Sstevel@tonic-gate 			"-a only applies to files or nisplus repository\n"));
1013*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
1014*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
1015*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1016*7c478bd9Sstevel@tonic-gate 			}
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 			/*
1019*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
1020*7c478bd9Sstevel@tonic-gate 			 * for FILES
1021*7c478bd9Sstevel@tonic-gate 			 */
1022*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
1023*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
1024*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1025*7c478bd9Sstevel@tonic-gate 			if (flag && (flag != SFLAG)) {
1026*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1027*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1028*7c478bd9Sstevel@tonic-gate 			}
1029*7c478bd9Sstevel@tonic-gate 			flag |= AFLAG;
1030*7c478bd9Sstevel@tonic-gate 			break;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 		case 'f': /* expire password attributes	*/
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -f is files */
1035*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
1036*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) == FALSE &&
1039*7c478bd9Sstevel@tonic-gate 			    IS_NISPLUS(repository) == FALSE) {
1040*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1041*7c478bd9Sstevel@tonic-gate 			"-f only applies to files or nisplus repository\n"));
1042*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
1043*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
1044*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1045*7c478bd9Sstevel@tonic-gate 			}
1046*7c478bd9Sstevel@tonic-gate 
1047*7c478bd9Sstevel@tonic-gate 			/*
1048*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
1049*7c478bd9Sstevel@tonic-gate 			 * for FILES
1050*7c478bd9Sstevel@tonic-gate 			 */
1051*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) &&
1052*7c478bd9Sstevel@tonic-gate 				((retval = ckuid()) != SUCCESS))
1053*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1054*7c478bd9Sstevel@tonic-gate 			if (flag & (SAFLAG|FFLAG|NONAGEFLAG)) {
1055*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1056*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1057*7c478bd9Sstevel@tonic-gate 			}
1058*7c478bd9Sstevel@tonic-gate 			flag |= FFLAG;
1059*7c478bd9Sstevel@tonic-gate 			attrlist_add(attributes, ATTR_EXPIRE_PASSWORD, NULL);
1060*7c478bd9Sstevel@tonic-gate 			break;
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate 		case 'D': /* domain name specified */
1063*7c478bd9Sstevel@tonic-gate 			if (IS_NISPLUS(repository) == FALSE) {
1064*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1065*7c478bd9Sstevel@tonic-gate 				    "-D only applies to nisplus repository\n"));
1066*7c478bd9Sstevel@tonic-gate 				rusage();	/* exit */
1067*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
1068*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1069*7c478bd9Sstevel@tonic-gate 			}
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 			if (flag & AFLAG) {
1072*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1073*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1074*7c478bd9Sstevel@tonic-gate 			}
1075*7c478bd9Sstevel@tonic-gate 			/* It is cleaner not to set this flag */
1076*7c478bd9Sstevel@tonic-gate 			/* flag |= OFLAG; */
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 			/* get domain from optarg */
1079*7c478bd9Sstevel@tonic-gate 			repository.scope = optarg;
1080*7c478bd9Sstevel@tonic-gate 			if (repository.scope != NULL) {
1081*7c478bd9Sstevel@tonic-gate 				repository.scope_len =
1082*7c478bd9Sstevel@tonic-gate 				    strlen(repository.scope)+1;
1083*7c478bd9Sstevel@tonic-gate 			}
1084*7c478bd9Sstevel@tonic-gate 			break;
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 		case 'e': /* change login shell */
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -e is files */
1089*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
1090*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 			/*
1093*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
1094*7c478bd9Sstevel@tonic-gate 			 * for FILES
1095*7c478bd9Sstevel@tonic-gate 			 */
1096*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1097*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
1098*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1099*7c478bd9Sstevel@tonic-gate 			}
1100*7c478bd9Sstevel@tonic-gate 			if (flag & (EFLAG|SAFLAG|AGEFLAG)) {
1101*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1102*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1103*7c478bd9Sstevel@tonic-gate 			}
1104*7c478bd9Sstevel@tonic-gate 			flag |= EFLAG;
1105*7c478bd9Sstevel@tonic-gate 			break;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 		case 'g': /* change gecos information */
1108*7c478bd9Sstevel@tonic-gate 
1109*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -g is files */
1110*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
1111*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate 			/*
1114*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
1115*7c478bd9Sstevel@tonic-gate 			 * for FILES
1116*7c478bd9Sstevel@tonic-gate 			 */
1117*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1118*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
1119*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1120*7c478bd9Sstevel@tonic-gate 			}
1121*7c478bd9Sstevel@tonic-gate 			if (flag & (GFLAG|SAFLAG|AGEFLAG)) {
1122*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1123*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1124*7c478bd9Sstevel@tonic-gate 			}
1125*7c478bd9Sstevel@tonic-gate 			flag |= GFLAG;
1126*7c478bd9Sstevel@tonic-gate 			break;
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 		case 'h': /* change home dir */
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 			/* if no repository the default for -h is files */
1131*7c478bd9Sstevel@tonic-gate 			if (repository.type == NULL)
1132*7c478bd9Sstevel@tonic-gate 				repository = __REPFILES;
1133*7c478bd9Sstevel@tonic-gate 			/*
1134*7c478bd9Sstevel@tonic-gate 			 * Only privileged process can execute this
1135*7c478bd9Sstevel@tonic-gate 			 * for FILES
1136*7c478bd9Sstevel@tonic-gate 			 */
1137*7c478bd9Sstevel@tonic-gate 			if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1138*7c478bd9Sstevel@tonic-gate 				retval = NOPERM;
1139*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1140*7c478bd9Sstevel@tonic-gate 			}
1141*7c478bd9Sstevel@tonic-gate 			if (IS_NIS(repository)) {
1142*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "%s\n",
1143*7c478bd9Sstevel@tonic-gate 				    gettext(MSG_NIS_HOMEDIR));
1144*7c478bd9Sstevel@tonic-gate 				retval = BADSYN;
1145*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1146*7c478bd9Sstevel@tonic-gate 			}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 			if (flag & (HFLAG|SAFLAG|AGEFLAG)) {
1149*7c478bd9Sstevel@tonic-gate 				retval = BADOPT;
1150*7c478bd9Sstevel@tonic-gate 				return (FAIL);
1151*7c478bd9Sstevel@tonic-gate 			}
1152*7c478bd9Sstevel@tonic-gate 			flag |= HFLAG;
1153*7c478bd9Sstevel@tonic-gate 			break;
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 		case '?':
1156*7c478bd9Sstevel@tonic-gate 			rusage();
1157*7c478bd9Sstevel@tonic-gate 			retval = BADOPT;
1158*7c478bd9Sstevel@tonic-gate 			return (FAIL);
1159*7c478bd9Sstevel@tonic-gate 		}
1160*7c478bd9Sstevel@tonic-gate 	}
1161*7c478bd9Sstevel@tonic-gate 
1162*7c478bd9Sstevel@tonic-gate 	argc -= optind;
1163*7c478bd9Sstevel@tonic-gate 	if (argc > 1) {
1164*7c478bd9Sstevel@tonic-gate 		rusage();
1165*7c478bd9Sstevel@tonic-gate 		retval = BADSYN;
1166*7c478bd9Sstevel@tonic-gate 		return (FAIL);
1167*7c478bd9Sstevel@tonic-gate 	}
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 	/* Make sure (EXPIRE comes after (MAX comes after MIN)) */
1170*7c478bd9Sstevel@tonic-gate 	attrlist_reorder(attributes);
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	/* If no options are specified or only the show option */
1173*7c478bd9Sstevel@tonic-gate 	/* is specified, return because no option error checking */
1174*7c478bd9Sstevel@tonic-gate 	/* is needed */
1175*7c478bd9Sstevel@tonic-gate 	if (!flag || (flag == SFLAG))
1176*7c478bd9Sstevel@tonic-gate 		return (flag);
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	/* AFLAG must be used with SFLAG */
1179*7c478bd9Sstevel@tonic-gate 	if (flag == AFLAG) {
1180*7c478bd9Sstevel@tonic-gate 		rusage();
1181*7c478bd9Sstevel@tonic-gate 		retval = BADSYN;
1182*7c478bd9Sstevel@tonic-gate 		return (FAIL);
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	if (flag != SAFLAG && argc < 1) {
1186*7c478bd9Sstevel@tonic-gate 		/*
1187*7c478bd9Sstevel@tonic-gate 		 * user name is not specified (argc<1), it can't be
1188*7c478bd9Sstevel@tonic-gate 		 * aging info update.
1189*7c478bd9Sstevel@tonic-gate 		 */
1190*7c478bd9Sstevel@tonic-gate 		if (!(flag & NONAGEFLAG)) {
1191*7c478bd9Sstevel@tonic-gate 			rusage();
1192*7c478bd9Sstevel@tonic-gate 			retval = BADSYN;
1193*7c478bd9Sstevel@tonic-gate 			return (FAIL);
1194*7c478bd9Sstevel@tonic-gate 		}
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	/* user name(s) may not be specified when SAFLAG is used. */
1198*7c478bd9Sstevel@tonic-gate 	if (flag == SAFLAG && argc >= 1) {
1199*7c478bd9Sstevel@tonic-gate 		rusage();
1200*7c478bd9Sstevel@tonic-gate 		retval = BADSYN;
1201*7c478bd9Sstevel@tonic-gate 		return (FAIL);
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate 	/*
1205*7c478bd9Sstevel@tonic-gate 	 * If aging is being turned off (maxdate == -1), mindate may not
1206*7c478bd9Sstevel@tonic-gate 	 * be specified.
1207*7c478bd9Sstevel@tonic-gate 	 */
1208*7c478bd9Sstevel@tonic-gate 	if ((maxdate == -1) && (flag & NFLAG)) {
1209*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s -n\n",
1210*7c478bd9Sstevel@tonic-gate 				prognamep, gettext(MSG_NV));
1211*7c478bd9Sstevel@tonic-gate 		retval = BADOPT;
1212*7c478bd9Sstevel@tonic-gate 		return (FAIL);
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate 	return (flag);
1216*7c478bd9Sstevel@tonic-gate }
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate /*
1219*7c478bd9Sstevel@tonic-gate  *
1220*7c478bd9Sstevel@tonic-gate  * ckuid():
1221*7c478bd9Sstevel@tonic-gate  *	This function returns SUCCESS if the caller is root, else
1222*7c478bd9Sstevel@tonic-gate  *	it returns NOPERM.
1223*7c478bd9Sstevel@tonic-gate  *
1224*7c478bd9Sstevel@tonic-gate  */
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate static int
1227*7c478bd9Sstevel@tonic-gate ckuid()
1228*7c478bd9Sstevel@tonic-gate {
1229*7c478bd9Sstevel@tonic-gate 	if (uid != 0) {
1230*7c478bd9Sstevel@tonic-gate 		return (retval = NOPERM);
1231*7c478bd9Sstevel@tonic-gate 	}
1232*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
1233*7c478bd9Sstevel@tonic-gate }
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate /*
1237*7c478bd9Sstevel@tonic-gate  * get_attr()
1238*7c478bd9Sstevel@tonic-gate  */
1239*7c478bd9Sstevel@tonic-gate int
1240*7c478bd9Sstevel@tonic-gate get_attr(char *username, pwu_repository_t *repository, attrlist **attributes)
1241*7c478bd9Sstevel@tonic-gate {
1242*7c478bd9Sstevel@tonic-gate 	int res;
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	attrlist_add(attributes, ATTR_PASSWD, NULL);
1245*7c478bd9Sstevel@tonic-gate 	attrlist_add(attributes, ATTR_LSTCHG, "0");
1246*7c478bd9Sstevel@tonic-gate 	attrlist_add(attributes, ATTR_MIN, "0");
1247*7c478bd9Sstevel@tonic-gate 	attrlist_add(attributes, ATTR_MAX, "0");
1248*7c478bd9Sstevel@tonic-gate 	attrlist_add(attributes, ATTR_WARN, "0");
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 	res = __get_authtoken_attr(username, repository, *attributes);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	if (res == PWU_SUCCESS) {
1253*7c478bd9Sstevel@tonic-gate 		retval = SUCCESS;
1254*7c478bd9Sstevel@tonic-gate 		return (PWU_SUCCESS);
1255*7c478bd9Sstevel@tonic-gate 	}
1256*7c478bd9Sstevel@tonic-gate 
1257*7c478bd9Sstevel@tonic-gate 	if (res == PWU_NOT_FOUND)
1258*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(MSG_UNKNOWN), prognamep,
1259*7c478bd9Sstevel@tonic-gate 		    username);
1260*7c478bd9Sstevel@tonic-gate 
1261*7c478bd9Sstevel@tonic-gate 	retval = NOPERM;
1262*7c478bd9Sstevel@tonic-gate 	passwd_exit(retval);
1263*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1264*7c478bd9Sstevel@tonic-gate }
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate /*
1267*7c478bd9Sstevel@tonic-gate  * display_attr():
1268*7c478bd9Sstevel@tonic-gate  * This function prints out the password attributes of a usr
1269*7c478bd9Sstevel@tonic-gate  * onto standand output.
1270*7c478bd9Sstevel@tonic-gate  */
1271*7c478bd9Sstevel@tonic-gate void
1272*7c478bd9Sstevel@tonic-gate display_attr(char *usrname, attrlist *attributes)
1273*7c478bd9Sstevel@tonic-gate {
1274*7c478bd9Sstevel@tonic-gate 	char	*status;
1275*7c478bd9Sstevel@tonic-gate 	char	*passwd;
1276*7c478bd9Sstevel@tonic-gate 	long	lstchg;
1277*7c478bd9Sstevel@tonic-gate 	int	min, max, warn;
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	while (attributes) {
1280*7c478bd9Sstevel@tonic-gate 		switch (attributes->type) {
1281*7c478bd9Sstevel@tonic-gate 		case ATTR_PASSWD:
1282*7c478bd9Sstevel@tonic-gate 			passwd = attributes->data.val_s;
1283*7c478bd9Sstevel@tonic-gate 			if (passwd == NULL || *passwd == '\0')
1284*7c478bd9Sstevel@tonic-gate 				status = "NP  ";
1285*7c478bd9Sstevel@tonic-gate 			else if (strncmp(passwd, LOCKSTRING,
1286*7c478bd9Sstevel@tonic-gate 			    sizeof (LOCKSTRING)-1) == 0)
1287*7c478bd9Sstevel@tonic-gate 				status = "LK  ";
1288*7c478bd9Sstevel@tonic-gate 			else if (strncmp(passwd, NOLOGINSTRING,
1289*7c478bd9Sstevel@tonic-gate 			    sizeof (NOLOGINSTRING)-1) == 0)
1290*7c478bd9Sstevel@tonic-gate 				status = "NL  ";
1291*7c478bd9Sstevel@tonic-gate 			else
1292*7c478bd9Sstevel@tonic-gate 				status = "PS  ";
1293*7c478bd9Sstevel@tonic-gate 			break;
1294*7c478bd9Sstevel@tonic-gate 		case ATTR_LSTCHG:
1295*7c478bd9Sstevel@tonic-gate 			lstchg = attributes->data.val_i * DAY;
1296*7c478bd9Sstevel@tonic-gate 			break;
1297*7c478bd9Sstevel@tonic-gate 		case ATTR_MIN:
1298*7c478bd9Sstevel@tonic-gate 			min = attributes->data.val_i;
1299*7c478bd9Sstevel@tonic-gate 			break;
1300*7c478bd9Sstevel@tonic-gate 		case ATTR_MAX:
1301*7c478bd9Sstevel@tonic-gate 			max = attributes->data.val_i;
1302*7c478bd9Sstevel@tonic-gate 			break;
1303*7c478bd9Sstevel@tonic-gate 		case ATTR_WARN:
1304*7c478bd9Sstevel@tonic-gate 			warn = attributes->data.val_i;
1305*7c478bd9Sstevel@tonic-gate 			break;
1306*7c478bd9Sstevel@tonic-gate 		}
1307*7c478bd9Sstevel@tonic-gate 		attributes = attributes->next;
1308*7c478bd9Sstevel@tonic-gate 	}
1309*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%-8s  ", usrname);
1310*7c478bd9Sstevel@tonic-gate 
1311*7c478bd9Sstevel@tonic-gate 	if (status)
1312*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, "%s  ", status);
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	if (max != -1) {
1315*7c478bd9Sstevel@tonic-gate 		if (lstchg == 0) {
1316*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "00/00/00  ");
1317*7c478bd9Sstevel@tonic-gate 		} else {
1318*7c478bd9Sstevel@tonic-gate 			struct tm *tmp;
1319*7c478bd9Sstevel@tonic-gate 			tmp = gmtime(&lstchg);
1320*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "%.2d/%.2d/%.2d  ",
1321*7c478bd9Sstevel@tonic-gate 			    tmp->tm_mon + 1,
1322*7c478bd9Sstevel@tonic-gate 			    tmp->tm_mday,
1323*7c478bd9Sstevel@tonic-gate 			    tmp->tm_year % 100);
1324*7c478bd9Sstevel@tonic-gate 		}
1325*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, (min >= 0) ? "%4d  " : "      ", min);
1326*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, "%4d  ", max);
1327*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, (warn > 0) ? "%4d  " : "      ", warn);
1328*7c478bd9Sstevel@tonic-gate 	}
1329*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "\n");
1330*7c478bd9Sstevel@tonic-gate }
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate void
1333*7c478bd9Sstevel@tonic-gate free_attr(attrlist *attributes)
1334*7c478bd9Sstevel@tonic-gate {
1335*7c478bd9Sstevel@tonic-gate 	while (attributes) {
1336*7c478bd9Sstevel@tonic-gate 		if (attributes->type == ATTR_PASSWD)
1337*7c478bd9Sstevel@tonic-gate 			free(attributes->data.val_s);
1338*7c478bd9Sstevel@tonic-gate 		attributes = attributes->next;
1339*7c478bd9Sstevel@tonic-gate 	}
1340*7c478bd9Sstevel@tonic-gate }
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate /*
1343*7c478bd9Sstevel@tonic-gate  *
1344*7c478bd9Sstevel@tonic-gate  * get_namelist_files():
1345*7c478bd9Sstevel@tonic-gate  *	This function gets a list of user names on the system from
1346*7c478bd9Sstevel@tonic-gate  *	the /etc/passwd file.
1347*7c478bd9Sstevel@tonic-gate  *
1348*7c478bd9Sstevel@tonic-gate  */
1349*7c478bd9Sstevel@tonic-gate int
1350*7c478bd9Sstevel@tonic-gate get_namelist_files(namelist_p, num_user)
1351*7c478bd9Sstevel@tonic-gate 	char ***namelist_p;
1352*7c478bd9Sstevel@tonic-gate 	int *num_user;
1353*7c478bd9Sstevel@tonic-gate {
1354*7c478bd9Sstevel@tonic-gate 	FILE		*pwfp;
1355*7c478bd9Sstevel@tonic-gate 	struct passwd	*pwd;
1356*7c478bd9Sstevel@tonic-gate 	int		max_user;
1357*7c478bd9Sstevel@tonic-gate 	int		nuser;
1358*7c478bd9Sstevel@tonic-gate 	char	**nl;
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	nuser = 0;
1361*7c478bd9Sstevel@tonic-gate 	errno = 0;
1362*7c478bd9Sstevel@tonic-gate 	pwd = NULL;
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	if ((pwfp = fopen(PASSWD, "r")) == NULL)
1365*7c478bd9Sstevel@tonic-gate 		return (NOPERM);
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	/*
1368*7c478bd9Sstevel@tonic-gate 	 * find out the actual number of entries in the PASSWD file
1369*7c478bd9Sstevel@tonic-gate 	 */
1370*7c478bd9Sstevel@tonic-gate 	max_user = 1;			/* need one slot for terminator NULL */
1371*7c478bd9Sstevel@tonic-gate 	while ((pwd = fgetpwent(pwfp)) != NULL)
1372*7c478bd9Sstevel@tonic-gate 		max_user++;
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	/*
1375*7c478bd9Sstevel@tonic-gate 	 *	reset the file stream pointer
1376*7c478bd9Sstevel@tonic-gate 	 */
1377*7c478bd9Sstevel@tonic-gate 	rewind(pwfp);
1378*7c478bd9Sstevel@tonic-gate 
1379*7c478bd9Sstevel@tonic-gate 	nl = (char **)calloc(max_user, (sizeof (char *)));
1380*7c478bd9Sstevel@tonic-gate 	if (nl == NULL) {
1381*7c478bd9Sstevel@tonic-gate 		(void) fclose(pwfp);
1382*7c478bd9Sstevel@tonic-gate 		return (FMERR);
1383*7c478bd9Sstevel@tonic-gate 	}
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 	while ((pwd = fgetpwent(pwfp)) != NULL) {
1386*7c478bd9Sstevel@tonic-gate 		if ((nl[nuser] = strdup(pwd->pw_name)) == NULL) {
1387*7c478bd9Sstevel@tonic-gate 			(void) fclose(pwfp);
1388*7c478bd9Sstevel@tonic-gate 			return (FMERR);
1389*7c478bd9Sstevel@tonic-gate 		}
1390*7c478bd9Sstevel@tonic-gate 		nuser++;
1391*7c478bd9Sstevel@tonic-gate 	}
1392*7c478bd9Sstevel@tonic-gate 
1393*7c478bd9Sstevel@tonic-gate 	nl[nuser] = NULL;
1394*7c478bd9Sstevel@tonic-gate 	*num_user = nuser;
1395*7c478bd9Sstevel@tonic-gate 	*namelist_p = nl;
1396*7c478bd9Sstevel@tonic-gate 	(void) fclose(pwfp);
1397*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
1398*7c478bd9Sstevel@tonic-gate }
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate /*
1401*7c478bd9Sstevel@tonic-gate  * get_namelist_nisplus
1402*7c478bd9Sstevel@tonic-gate  *
1403*7c478bd9Sstevel@tonic-gate  */
1404*7c478bd9Sstevel@tonic-gate 
1405*7c478bd9Sstevel@tonic-gate /*
1406*7c478bd9Sstevel@tonic-gate  * Our private version of the switch frontend for getspent.  We want to
1407*7c478bd9Sstevel@tonic-gate  * search just the nisplus sp file, so we want to bypass normal nsswitch.conf
1408*7c478bd9Sstevel@tonic-gate  * based processing.  This implementation compatible with version 2 of the
1409*7c478bd9Sstevel@tonic-gate  * name service switch.
1410*7c478bd9Sstevel@tonic-gate  */
1411*7c478bd9Sstevel@tonic-gate #define	NSS_NISPLUS_ONLY	"nisplus"
1412*7c478bd9Sstevel@tonic-gate 
1413*7c478bd9Sstevel@tonic-gate extern int str2spwd(const char *, int, void *, char *, int);
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
1416*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context);
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate static void
1419*7c478bd9Sstevel@tonic-gate _np_nss_initf_shadow(p)
1420*7c478bd9Sstevel@tonic-gate 	nss_db_params_t	*p;
1421*7c478bd9Sstevel@tonic-gate {
1422*7c478bd9Sstevel@tonic-gate 	p->name	= NSS_DBNAM_SHADOW;
1423*7c478bd9Sstevel@tonic-gate 	p->config_name    = NSS_DBNAM_PASSWD;	/* Use config for "passwd" */
1424*7c478bd9Sstevel@tonic-gate 	p->default_config = NSS_NISPLUS_ONLY;   /* Use nisplus only */
1425*7c478bd9Sstevel@tonic-gate 	p->flags = NSS_USE_DEFAULT_CONFIG;
1426*7c478bd9Sstevel@tonic-gate }
1427*7c478bd9Sstevel@tonic-gate 
1428*7c478bd9Sstevel@tonic-gate static void
1429*7c478bd9Sstevel@tonic-gate _np_setspent()
1430*7c478bd9Sstevel@tonic-gate {
1431*7c478bd9Sstevel@tonic-gate 	nss_setent(&db_root, _np_nss_initf_shadow, &context);
1432*7c478bd9Sstevel@tonic-gate }
1433*7c478bd9Sstevel@tonic-gate 
1434*7c478bd9Sstevel@tonic-gate static void
1435*7c478bd9Sstevel@tonic-gate _np_endspent()
1436*7c478bd9Sstevel@tonic-gate {
1437*7c478bd9Sstevel@tonic-gate 	nss_endent(&db_root, _np_nss_initf_shadow, &context);
1438*7c478bd9Sstevel@tonic-gate 	nss_delete(&db_root);
1439*7c478bd9Sstevel@tonic-gate }
1440*7c478bd9Sstevel@tonic-gate 
1441*7c478bd9Sstevel@tonic-gate static struct spwd *
1442*7c478bd9Sstevel@tonic-gate _np_getspent_r(result, buffer, buflen)
1443*7c478bd9Sstevel@tonic-gate 	struct spwd	*result;
1444*7c478bd9Sstevel@tonic-gate 	char		*buffer;
1445*7c478bd9Sstevel@tonic-gate 	int		buflen;
1446*7c478bd9Sstevel@tonic-gate {
1447*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
1448*7c478bd9Sstevel@tonic-gate 	char		*nam;
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 	/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
1451*7c478bd9Sstevel@tonic-gate 
1452*7c478bd9Sstevel@tonic-gate 	do {
1453*7c478bd9Sstevel@tonic-gate 		NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd);
1454*7c478bd9Sstevel@tonic-gate 			/* No key to fill in */
1455*7c478bd9Sstevel@tonic-gate 		(void) nss_getent(&db_root, _np_nss_initf_shadow, &context,
1456*7c478bd9Sstevel@tonic-gate 		    &arg);
1457*7c478bd9Sstevel@tonic-gate 	} while (arg.returnval != 0 &&
1458*7c478bd9Sstevel@tonic-gate 			(nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 &&
1459*7c478bd9Sstevel@tonic-gate 			(*nam == '+' || *nam == '-'));
1460*7c478bd9Sstevel@tonic-gate 
1461*7c478bd9Sstevel@tonic-gate 	return (struct spwd *)NSS_XbyY_FINI(&arg);
1462*7c478bd9Sstevel@tonic-gate }
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate static nss_XbyY_buf_t *buffer;
1465*7c478bd9Sstevel@tonic-gate 
1466*7c478bd9Sstevel@tonic-gate static struct spwd *
1467*7c478bd9Sstevel@tonic-gate _np_getspent()
1468*7c478bd9Sstevel@tonic-gate {
1469*7c478bd9Sstevel@tonic-gate 	nss_XbyY_buf_t	*b;
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	b = NSS_XbyY_ALLOC(&buffer, sizeof (struct spwd), NSS_BUFLEN_SHADOW);
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 	return (b == 0 ? 0 : _np_getspent_r(b->result, b->buffer, b->buflen));
1474*7c478bd9Sstevel@tonic-gate }
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate int
1477*7c478bd9Sstevel@tonic-gate get_namelist_nisplus(char ***namelist_p, int *num_user)
1478*7c478bd9Sstevel@tonic-gate {
1479*7c478bd9Sstevel@tonic-gate 	int nuser = 0;
1480*7c478bd9Sstevel@tonic-gate 	int alloced = 100;
1481*7c478bd9Sstevel@tonic-gate 	char **nl;
1482*7c478bd9Sstevel@tonic-gate 	struct spwd *p;
1483*7c478bd9Sstevel@tonic-gate 
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 	if ((nl = calloc(alloced, sizeof (*nl))) == NULL)
1486*7c478bd9Sstevel@tonic-gate 		return (FMERR);
1487*7c478bd9Sstevel@tonic-gate 
1488*7c478bd9Sstevel@tonic-gate 	(void) _np_setspent();
1489*7c478bd9Sstevel@tonic-gate 	while ((p = _np_getspent()) != NULL) {
1490*7c478bd9Sstevel@tonic-gate 		if ((nl[nuser] = strdup(p->sp_namp)) == NULL) {
1491*7c478bd9Sstevel@tonic-gate 			_np_endspent();
1492*7c478bd9Sstevel@tonic-gate 			return (FMERR);
1493*7c478bd9Sstevel@tonic-gate 		}
1494*7c478bd9Sstevel@tonic-gate 		if (++nuser == alloced) {
1495*7c478bd9Sstevel@tonic-gate 			alloced += 100;
1496*7c478bd9Sstevel@tonic-gate 			nl = realloc(nl, alloced * (sizeof (*nl)));
1497*7c478bd9Sstevel@tonic-gate 			if (nl == NULL) {
1498*7c478bd9Sstevel@tonic-gate 				_np_endspent();
1499*7c478bd9Sstevel@tonic-gate 				return (FMERR);
1500*7c478bd9Sstevel@tonic-gate 			}
1501*7c478bd9Sstevel@tonic-gate 		}
1502*7c478bd9Sstevel@tonic-gate 	}
1503*7c478bd9Sstevel@tonic-gate 	(void) _np_endspent();
1504*7c478bd9Sstevel@tonic-gate 	nl[nuser] = NULL;
1505*7c478bd9Sstevel@tonic-gate 
1506*7c478bd9Sstevel@tonic-gate 	*namelist_p = nl;
1507*7c478bd9Sstevel@tonic-gate 	*num_user = nuser;		/* including NULL */
1508*7c478bd9Sstevel@tonic-gate 
1509*7c478bd9Sstevel@tonic-gate 	return (SUCCESS);
1510*7c478bd9Sstevel@tonic-gate }
1511*7c478bd9Sstevel@tonic-gate 
1512*7c478bd9Sstevel@tonic-gate int
1513*7c478bd9Sstevel@tonic-gate get_namelist(pwu_repository_t repository, char ***namelist, int *num_user)
1514*7c478bd9Sstevel@tonic-gate {
1515*7c478bd9Sstevel@tonic-gate 	if (IS_NISPLUS(repository))
1516*7c478bd9Sstevel@tonic-gate 		return (get_namelist_nisplus(namelist, num_user));
1517*7c478bd9Sstevel@tonic-gate 	else if (IS_FILES(repository))
1518*7c478bd9Sstevel@tonic-gate 		return (get_namelist_files(namelist, num_user));
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	rusage();
1521*7c478bd9Sstevel@tonic-gate 	return (BADSYN);
1522*7c478bd9Sstevel@tonic-gate }
1523*7c478bd9Sstevel@tonic-gate 
1524*7c478bd9Sstevel@tonic-gate /*
1525*7c478bd9Sstevel@tonic-gate  *
1526*7c478bd9Sstevel@tonic-gate  * passwd_exit():
1527*7c478bd9Sstevel@tonic-gate  *	This function will call exit() with appropriate exit code
1528*7c478bd9Sstevel@tonic-gate  *	according to the input "retcode" value.
1529*7c478bd9Sstevel@tonic-gate  *	It also calls pam_end() to clean-up buffers before exit.
1530*7c478bd9Sstevel@tonic-gate  *
1531*7c478bd9Sstevel@tonic-gate  */
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate void
1534*7c478bd9Sstevel@tonic-gate passwd_exit(retcode)
1535*7c478bd9Sstevel@tonic-gate 	int	retcode;
1536*7c478bd9Sstevel@tonic-gate {
1537*7c478bd9Sstevel@tonic-gate 
1538*7c478bd9Sstevel@tonic-gate 	if (pamh)
1539*7c478bd9Sstevel@tonic-gate 		(void) pam_end(pamh, pam_retval);
1540*7c478bd9Sstevel@tonic-gate 
1541*7c478bd9Sstevel@tonic-gate 	switch (retcode) {
1542*7c478bd9Sstevel@tonic-gate 	case SUCCESS:
1543*7c478bd9Sstevel@tonic-gate 			break;
1544*7c478bd9Sstevel@tonic-gate 	case NOPERM:
1545*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_NP));
1546*7c478bd9Sstevel@tonic-gate 			break;
1547*7c478bd9Sstevel@tonic-gate 	case BADOPT:
1548*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_BS));
1549*7c478bd9Sstevel@tonic-gate 			break;
1550*7c478bd9Sstevel@tonic-gate 	case FMERR:
1551*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_FE));
1552*7c478bd9Sstevel@tonic-gate 			break;
1553*7c478bd9Sstevel@tonic-gate 	case FATAL:
1554*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_FF));
1555*7c478bd9Sstevel@tonic-gate 			break;
1556*7c478bd9Sstevel@tonic-gate 	case FBUSY:
1557*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_FB));
1558*7c478bd9Sstevel@tonic-gate 			break;
1559*7c478bd9Sstevel@tonic-gate 	case BADSYN:
1560*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_NV));
1561*7c478bd9Sstevel@tonic-gate 			break;
1562*7c478bd9Sstevel@tonic-gate 	case BADAGE:
1563*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_AD));
1564*7c478bd9Sstevel@tonic-gate 			break;
1565*7c478bd9Sstevel@tonic-gate 	case NOMEM:
1566*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_NM));
1567*7c478bd9Sstevel@tonic-gate 			break;
1568*7c478bd9Sstevel@tonic-gate 	default:
1569*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", gettext(MSG_NP));
1570*7c478bd9Sstevel@tonic-gate 			retcode = NOPERM;
1571*7c478bd9Sstevel@tonic-gate 			break;
1572*7c478bd9Sstevel@tonic-gate 	}
1573*7c478bd9Sstevel@tonic-gate 	/* write password record */
1574*7c478bd9Sstevel@tonic-gate 	if (event != NULL) {
1575*7c478bd9Sstevel@tonic-gate 		if (adt_put_event(event,
1576*7c478bd9Sstevel@tonic-gate 		    retcode == SUCCESS ? ADT_SUCCESS : ADT_FAILURE,
1577*7c478bd9Sstevel@tonic-gate 		    retcode == SUCCESS ? ADT_SUCCESS : ADT_FAIL_PAM +
1578*7c478bd9Sstevel@tonic-gate 		    pam_retval) != 0) {
1579*7c478bd9Sstevel@tonic-gate 			adt_free_event(event);
1580*7c478bd9Sstevel@tonic-gate 			(void) adt_end_session(ah);
1581*7c478bd9Sstevel@tonic-gate 			perror("adt_put_event");
1582*7c478bd9Sstevel@tonic-gate 			exit(retcode);
1583*7c478bd9Sstevel@tonic-gate 		}
1584*7c478bd9Sstevel@tonic-gate 		adt_free_event(event);
1585*7c478bd9Sstevel@tonic-gate 	}
1586*7c478bd9Sstevel@tonic-gate 	(void) adt_end_session(ah);
1587*7c478bd9Sstevel@tonic-gate 	exit(retcode);
1588*7c478bd9Sstevel@tonic-gate }
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate /*
1591*7c478bd9Sstevel@tonic-gate  *
1592*7c478bd9Sstevel@tonic-gate  * passwd_conv():
1593*7c478bd9Sstevel@tonic-gate  *	This is the conv (conversation) function called from
1594*7c478bd9Sstevel@tonic-gate  *	a PAM authentication module to print error messages
1595*7c478bd9Sstevel@tonic-gate  *	or garner information from the user.
1596*7c478bd9Sstevel@tonic-gate  *
1597*7c478bd9Sstevel@tonic-gate  */
1598*7c478bd9Sstevel@tonic-gate 
1599*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1600*7c478bd9Sstevel@tonic-gate static int
1601*7c478bd9Sstevel@tonic-gate passwd_conv(num_msg, msg, response, appdata_ptr)
1602*7c478bd9Sstevel@tonic-gate 	int num_msg;
1603*7c478bd9Sstevel@tonic-gate 	struct pam_message **msg;
1604*7c478bd9Sstevel@tonic-gate 	struct pam_response **response;
1605*7c478bd9Sstevel@tonic-gate 	void *appdata_ptr;
1606*7c478bd9Sstevel@tonic-gate {
1607*7c478bd9Sstevel@tonic-gate 	struct pam_message	*m;
1608*7c478bd9Sstevel@tonic-gate 	struct pam_response	*r;
1609*7c478bd9Sstevel@tonic-gate 	char 			*temp;
1610*7c478bd9Sstevel@tonic-gate 	int			k, i;
1611*7c478bd9Sstevel@tonic-gate 
1612*7c478bd9Sstevel@tonic-gate 	if (num_msg <= 0)
1613*7c478bd9Sstevel@tonic-gate 		return (PAM_CONV_ERR);
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 	*response = (struct pam_response *)calloc(num_msg,
1616*7c478bd9Sstevel@tonic-gate 						sizeof (struct pam_response));
1617*7c478bd9Sstevel@tonic-gate 	if (*response == NULL)
1618*7c478bd9Sstevel@tonic-gate 		return (PAM_BUF_ERR);
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate 	k = num_msg;
1621*7c478bd9Sstevel@tonic-gate 	m = *msg;
1622*7c478bd9Sstevel@tonic-gate 	r = *response;
1623*7c478bd9Sstevel@tonic-gate 	while (k--) {
1624*7c478bd9Sstevel@tonic-gate 
1625*7c478bd9Sstevel@tonic-gate 		switch (m->msg_style) {
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 		case PAM_PROMPT_ECHO_OFF:
1628*7c478bd9Sstevel@tonic-gate 			temp = getpassphrase(m->msg);
1629*7c478bd9Sstevel@tonic-gate 			if (temp != NULL) {
1630*7c478bd9Sstevel@tonic-gate 				r->resp = strdup(temp);
1631*7c478bd9Sstevel@tonic-gate 				(void) memset(temp, 0, strlen(temp));
1632*7c478bd9Sstevel@tonic-gate 				if (r->resp == NULL) {
1633*7c478bd9Sstevel@tonic-gate 					/* free responses */
1634*7c478bd9Sstevel@tonic-gate 					r = *response;
1635*7c478bd9Sstevel@tonic-gate 					for (i = 0; i < num_msg; i++, r++) {
1636*7c478bd9Sstevel@tonic-gate 						if (r->resp)
1637*7c478bd9Sstevel@tonic-gate 							free(r->resp);
1638*7c478bd9Sstevel@tonic-gate 					}
1639*7c478bd9Sstevel@tonic-gate 					free(*response);
1640*7c478bd9Sstevel@tonic-gate 					*response = NULL;
1641*7c478bd9Sstevel@tonic-gate 					return (PAM_BUF_ERR);
1642*7c478bd9Sstevel@tonic-gate 				}
1643*7c478bd9Sstevel@tonic-gate 			}
1644*7c478bd9Sstevel@tonic-gate 			m++;
1645*7c478bd9Sstevel@tonic-gate 			r++;
1646*7c478bd9Sstevel@tonic-gate 			break;
1647*7c478bd9Sstevel@tonic-gate 
1648*7c478bd9Sstevel@tonic-gate 		case PAM_PROMPT_ECHO_ON:
1649*7c478bd9Sstevel@tonic-gate 			if (m->msg != NULL) {
1650*7c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stdout);
1651*7c478bd9Sstevel@tonic-gate 			}
1652*7c478bd9Sstevel@tonic-gate 			r->resp = (char *)calloc(PAM_MAX_RESP_SIZE,
1653*7c478bd9Sstevel@tonic-gate 							sizeof (char));
1654*7c478bd9Sstevel@tonic-gate 			if (r->resp == NULL) {
1655*7c478bd9Sstevel@tonic-gate 				/* free responses */
1656*7c478bd9Sstevel@tonic-gate 				r = *response;
1657*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < num_msg; i++, r++) {
1658*7c478bd9Sstevel@tonic-gate 					if (r->resp)
1659*7c478bd9Sstevel@tonic-gate 						free(r->resp);
1660*7c478bd9Sstevel@tonic-gate 				}
1661*7c478bd9Sstevel@tonic-gate 				free(*response);
1662*7c478bd9Sstevel@tonic-gate 				*response = NULL;
1663*7c478bd9Sstevel@tonic-gate 				return (PAM_BUF_ERR);
1664*7c478bd9Sstevel@tonic-gate 			}
1665*7c478bd9Sstevel@tonic-gate 			if (fgets(r->resp, PAM_MAX_RESP_SIZE-1, stdin)) {
1666*7c478bd9Sstevel@tonic-gate 				int len = strlen(r->resp);
1667*7c478bd9Sstevel@tonic-gate 				if (r->resp[len-1] == '\n')
1668*7c478bd9Sstevel@tonic-gate 					r->resp[len-1] = '\0';
1669*7c478bd9Sstevel@tonic-gate 			}
1670*7c478bd9Sstevel@tonic-gate 			m++;
1671*7c478bd9Sstevel@tonic-gate 			r++;
1672*7c478bd9Sstevel@tonic-gate 			break;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 		case PAM_ERROR_MSG:
1675*7c478bd9Sstevel@tonic-gate 			if (m->msg != NULL) {
1676*7c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stderr);
1677*7c478bd9Sstevel@tonic-gate 				(void) fputs("\n", stderr);
1678*7c478bd9Sstevel@tonic-gate 			}
1679*7c478bd9Sstevel@tonic-gate 			m++;
1680*7c478bd9Sstevel@tonic-gate 			r++;
1681*7c478bd9Sstevel@tonic-gate 			break;
1682*7c478bd9Sstevel@tonic-gate 		case PAM_TEXT_INFO:
1683*7c478bd9Sstevel@tonic-gate 			if (m->msg != NULL) {
1684*7c478bd9Sstevel@tonic-gate 				(void) fputs(m->msg, stdout);
1685*7c478bd9Sstevel@tonic-gate 				(void) fputs("\n", stdout);
1686*7c478bd9Sstevel@tonic-gate 			}
1687*7c478bd9Sstevel@tonic-gate 			m++;
1688*7c478bd9Sstevel@tonic-gate 			r++;
1689*7c478bd9Sstevel@tonic-gate 			break;
1690*7c478bd9Sstevel@tonic-gate 
1691*7c478bd9Sstevel@tonic-gate 		default:
1692*7c478bd9Sstevel@tonic-gate 			break;
1693*7c478bd9Sstevel@tonic-gate 		}
1694*7c478bd9Sstevel@tonic-gate 	}
1695*7c478bd9Sstevel@tonic-gate 	return (PAM_SUCCESS);
1696*7c478bd9Sstevel@tonic-gate }
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate /*
1699*7c478bd9Sstevel@tonic-gate  * 		Utilities Functions
1700*7c478bd9Sstevel@tonic-gate  */
1701*7c478bd9Sstevel@tonic-gate 
1702*7c478bd9Sstevel@tonic-gate /*
1703*7c478bd9Sstevel@tonic-gate  * int attrlist_add(attrlist **l, attrtype type, char *val)
1704*7c478bd9Sstevel@tonic-gate  * add an item, with type "type" and value "val", at the tail of list l.
1705*7c478bd9Sstevel@tonic-gate  * This functions exits the application on OutOfMem error.
1706*7c478bd9Sstevel@tonic-gate  */
1707*7c478bd9Sstevel@tonic-gate void
1708*7c478bd9Sstevel@tonic-gate attrlist_add(attrlist **l, attrtype type, char *val)
1709*7c478bd9Sstevel@tonic-gate {
1710*7c478bd9Sstevel@tonic-gate 	attrlist **w;
1711*7c478bd9Sstevel@tonic-gate 
1712*7c478bd9Sstevel@tonic-gate 	/* tail insert */
1713*7c478bd9Sstevel@tonic-gate 	for (w = l; *w != NULL; w = &(*w)->next)
1714*7c478bd9Sstevel@tonic-gate 		;
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate 	if ((*w = malloc(sizeof (**w))) == NULL)
1717*7c478bd9Sstevel@tonic-gate 		passwd_exit(NOMEM);
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 	(*w)->type = type;
1720*7c478bd9Sstevel@tonic-gate 	(*w)->next = NULL;
1721*7c478bd9Sstevel@tonic-gate 
1722*7c478bd9Sstevel@tonic-gate 	switch (type) {
1723*7c478bd9Sstevel@tonic-gate 	case ATTR_MIN:
1724*7c478bd9Sstevel@tonic-gate 	case ATTR_WARN:
1725*7c478bd9Sstevel@tonic-gate 	case ATTR_MAX:
1726*7c478bd9Sstevel@tonic-gate 		(*w)->data.val_i = atoi(val);
1727*7c478bd9Sstevel@tonic-gate 		break;
1728*7c478bd9Sstevel@tonic-gate 	default:
1729*7c478bd9Sstevel@tonic-gate 		(*w)->data.val_s = val;
1730*7c478bd9Sstevel@tonic-gate 		break;
1731*7c478bd9Sstevel@tonic-gate 	}
1732*7c478bd9Sstevel@tonic-gate }
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate /*
1735*7c478bd9Sstevel@tonic-gate  * attrlist_reorder(attrlist **l)
1736*7c478bd9Sstevel@tonic-gate  * Make sure that
1737*7c478bd9Sstevel@tonic-gate  * 	- if EXPIRE and MAX or MIN is set, EXPIRE comes after MAX/MIN
1738*7c478bd9Sstevel@tonic-gate  *	- if both MIN and MAX are set, MAX comes before MIN.
1739*7c478bd9Sstevel@tonic-gate  */
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate static void
1742*7c478bd9Sstevel@tonic-gate attrlist_reorder(attrlist **l)
1743*7c478bd9Sstevel@tonic-gate {
1744*7c478bd9Sstevel@tonic-gate 	attrlist	**w;
1745*7c478bd9Sstevel@tonic-gate 	attrlist	*exp = NULL;	/* ATTR_EXPIRE_PASSWORD, if found */
1746*7c478bd9Sstevel@tonic-gate 	attrlist	*max = NULL;	/* ATTR_MAX, if found */
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate 	if (*l == NULL || (*l)->next == NULL)
1749*7c478bd9Sstevel@tonic-gate 		return;		/* order of list with <= one item is ok */
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 	/*
1752*7c478bd9Sstevel@tonic-gate 	 * We simply walk the list, take off the EXPIRE and MAX items if
1753*7c478bd9Sstevel@tonic-gate 	 * they appear, and put them (first MAX, them EXPIRE) at the end
1754*7c478bd9Sstevel@tonic-gate 	 * of the list.
1755*7c478bd9Sstevel@tonic-gate 	 */
1756*7c478bd9Sstevel@tonic-gate 	w = l;
1757*7c478bd9Sstevel@tonic-gate 	while (*w != NULL) {
1758*7c478bd9Sstevel@tonic-gate 		if ((*w)->type == ATTR_EXPIRE_PASSWORD) {
1759*7c478bd9Sstevel@tonic-gate 			exp = *w;
1760*7c478bd9Sstevel@tonic-gate 			*w = (*w)->next;
1761*7c478bd9Sstevel@tonic-gate 		} else if ((*w)->type == ATTR_MAX) {
1762*7c478bd9Sstevel@tonic-gate 			max = *w;
1763*7c478bd9Sstevel@tonic-gate 			*w = (*w)->next;
1764*7c478bd9Sstevel@tonic-gate 		} else
1765*7c478bd9Sstevel@tonic-gate 			w = &(*w)->next;
1766*7c478bd9Sstevel@tonic-gate 	}
1767*7c478bd9Sstevel@tonic-gate 
1768*7c478bd9Sstevel@tonic-gate 	/* 'w' points to the address of the 'next' field of the last element */
1769*7c478bd9Sstevel@tonic-gate 
1770*7c478bd9Sstevel@tonic-gate 	if (max) {
1771*7c478bd9Sstevel@tonic-gate 		*w = max;
1772*7c478bd9Sstevel@tonic-gate 		w = &max->next;
1773*7c478bd9Sstevel@tonic-gate 	}
1774*7c478bd9Sstevel@tonic-gate 	if (exp) {
1775*7c478bd9Sstevel@tonic-gate 		*w = exp;
1776*7c478bd9Sstevel@tonic-gate 		w = &exp->next;
1777*7c478bd9Sstevel@tonic-gate 	}
1778*7c478bd9Sstevel@tonic-gate 	*w = NULL;
1779*7c478bd9Sstevel@tonic-gate }
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate void
1782*7c478bd9Sstevel@tonic-gate rusage()
1783*7c478bd9Sstevel@tonic-gate {
1784*7c478bd9Sstevel@tonic-gate 
1785*7c478bd9Sstevel@tonic-gate #define	MSG(a) (void) fprintf(stderr, gettext((a)));
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	MSG("usage:\n");
1788*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd [-r files | -r nis | -r nisplus | -r ldap] [name]\n");
1789*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd [-r files] [-egh] [name]\n");
1790*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd [-r files] -sa\n");
1791*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd [-r files] -s [name]\n");
1792*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd [-r files] [-d|-l|-N|-u] [-f] [-n min] [-w warn] "
1793*7c478bd9Sstevel@tonic-gate 	    "[-x max] name\n");
1794*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r nis [-eg] [name]\n");
1795*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r nisplus [-egh] [-D domainname] [name]\n");
1796*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r nisplus -sa\n");
1797*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r nisplus [-D domainname] -s [name]\n");
1798*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r nisplus [-D domainname] [-l|-N|-u] [-f] [-n min] "
1799*7c478bd9Sstevel@tonic-gate 	    "[-w warn]\n");
1800*7c478bd9Sstevel@tonic-gate 	MSG("\t\t[-x max] name\n");
1801*7c478bd9Sstevel@tonic-gate 	MSG("\tpasswd -r ldap [-egh] [name]\n");
1802*7c478bd9Sstevel@tonic-gate #undef MSG
1803*7c478bd9Sstevel@tonic-gate }
1804