xref: /titanic_54/usr/src/cmd/logins/logins.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 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"       /* SVr4.0 1.15.1.2 */
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  * logins.c
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  *	This file contains the source for the administrative command
36*7c478bd9Sstevel@tonic-gate  *	"logins" (available to the administrator) that produces a report
37*7c478bd9Sstevel@tonic-gate  *	containing login-IDs and other requested information.
38*7c478bd9Sstevel@tonic-gate  */
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate /*
41*7c478bd9Sstevel@tonic-gate  *  Header files referenced:
42*7c478bd9Sstevel@tonic-gate  *	sys/types.h	System data types
43*7c478bd9Sstevel@tonic-gate  *	stdio.h		Definitions for standard I/O functions and constants
44*7c478bd9Sstevel@tonic-gate  *	unistd.h	Standard UNIX definitions
45*7c478bd9Sstevel@tonic-gate  *	string.h	Definitions for string-handling functions
46*7c478bd9Sstevel@tonic-gate  *	ctype.h		Character-type definitions
47*7c478bd9Sstevel@tonic-gate  *	grp.h		Definitions for referencing the /etc/group file
48*7c478bd9Sstevel@tonic-gate  *	pwd.h		Definitions for referencing the /etc/passwd file
49*7c478bd9Sstevel@tonic-gate  *	shadow.h	Definitions for the shadow password file /etc/shadow
50*7c478bd9Sstevel@tonic-gate  *	time.h		Time definitions (ctime(), asctime(), etc.)
51*7c478bd9Sstevel@tonic-gate  *	stdarg.h	Definitions for using a variable argument list
52*7c478bd9Sstevel@tonic-gate  *	fmtmsg.h	Definitions for using the standard message generator
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #include	<sys/types.h>
56*7c478bd9Sstevel@tonic-gate #include	<stdio.h>
57*7c478bd9Sstevel@tonic-gate #include	<unistd.h>
58*7c478bd9Sstevel@tonic-gate #include	<string.h>
59*7c478bd9Sstevel@tonic-gate #include	<ctype.h>
60*7c478bd9Sstevel@tonic-gate #include	<grp.h>
61*7c478bd9Sstevel@tonic-gate #include	<pwd.h>
62*7c478bd9Sstevel@tonic-gate #include	<shadow.h>
63*7c478bd9Sstevel@tonic-gate #include	<time.h>
64*7c478bd9Sstevel@tonic-gate #include	<stdarg.h>
65*7c478bd9Sstevel@tonic-gate #include	<fmtmsg.h>
66*7c478bd9Sstevel@tonic-gate #include <locale.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate /*
69*7c478bd9Sstevel@tonic-gate  *  Externals referenced (and not defined by a header file):
70*7c478bd9Sstevel@tonic-gate  *	malloc		Allocate memory from main memory
71*7c478bd9Sstevel@tonic-gate  *	getopt		Extract the next option from the command line
72*7c478bd9Sstevel@tonic-gate  *	optind		The argument count of the next option to extract
73*7c478bd9Sstevel@tonic-gate  *			from the command line
74*7c478bd9Sstevel@tonic-gate  *	optarg		A pointer to the argument of the option just extracted
75*7c478bd9Sstevel@tonic-gate  *			from the command line
76*7c478bd9Sstevel@tonic-gate  *	opterr		FLAG:  !0 tells getopt() to write an error message if
77*7c478bd9Sstevel@tonic-gate  *			it detects an error
78*7c478bd9Sstevel@tonic-gate  *	getpwent	Get next entry from the /etc/passwd file
79*7c478bd9Sstevel@tonic-gate  *	getpwuid	Get next entry from the /etc/passwd file that has a
80*7c478bd9Sstevel@tonic-gate  *			specific user-ID
81*7c478bd9Sstevel@tonic-gate  *	fgetpwent	Get next entry from an /etc/passwd-like file
82*7c478bd9Sstevel@tonic-gate  *	setpwent	Rewind the /etc/passwd file
83*7c478bd9Sstevel@tonic-gate  *	endpwent	Quit using the /etc/passwd file
84*7c478bd9Sstevel@tonic-gate  *	getgrent	Get next entry from the /etc/group file
85*7c478bd9Sstevel@tonic-gate  *	setgrent	Rewind the /etc/group file
86*7c478bd9Sstevel@tonic-gate  *	endgrent	Quit using the /etc/passwd file
87*7c478bd9Sstevel@tonic-gate  *	getspnam	Get the next entry for a specific login-ID from the
88*7c478bd9Sstevel@tonic-gate  *			/etc/shadow file
89*7c478bd9Sstevel@tonic-gate  *	setspent	Rewind the /etc/shadow file
90*7c478bd9Sstevel@tonic-gate  *	endspent	Quit using the /etc/shadow file
91*7c478bd9Sstevel@tonic-gate  *	fmtmsg		Interface to the standard message generation facility
92*7c478bd9Sstevel@tonic-gate  *	putenv		Modify the environment
93*7c478bd9Sstevel@tonic-gate  *	exit		Exit the program
94*7c478bd9Sstevel@tonic-gate  */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate extern	void	       *malloc();
97*7c478bd9Sstevel@tonic-gate extern	int		getopt();
98*7c478bd9Sstevel@tonic-gate extern	char	       *optarg;
99*7c478bd9Sstevel@tonic-gate extern	int		optind;
100*7c478bd9Sstevel@tonic-gate extern	int		opterr;
101*7c478bd9Sstevel@tonic-gate extern	struct passwd  *getpwent();
102*7c478bd9Sstevel@tonic-gate extern	struct passwd  *getpwuid();
103*7c478bd9Sstevel@tonic-gate extern	struct passwd  *fgetpwent();
104*7c478bd9Sstevel@tonic-gate extern	void		setpwent();
105*7c478bd9Sstevel@tonic-gate extern	void		endpwent();
106*7c478bd9Sstevel@tonic-gate extern	struct group   *getgrent();
107*7c478bd9Sstevel@tonic-gate extern	void		setgrent();
108*7c478bd9Sstevel@tonic-gate extern	void		endgrent();
109*7c478bd9Sstevel@tonic-gate extern	struct spwd    *getspnam();
110*7c478bd9Sstevel@tonic-gate extern	void		setspent();
111*7c478bd9Sstevel@tonic-gate extern	void		endspent();
112*7c478bd9Sstevel@tonic-gate extern	int		fmtmsg();
113*7c478bd9Sstevel@tonic-gate extern	int		putenv();
114*7c478bd9Sstevel@tonic-gate extern	void		exit();
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate /*
117*7c478bd9Sstevel@tonic-gate  *  Local constant definitions
118*7c478bd9Sstevel@tonic-gate  *	TRUE			Boolean constant
119*7c478bd9Sstevel@tonic-gate  *	FALSE			Boolean constant
120*7c478bd9Sstevel@tonic-gate  *	USAGE_MSG		Message used to display a usage error
121*7c478bd9Sstevel@tonic-gate  *	MAXLOGINSIZE		Maximum length of a valid login-ID
122*7c478bd9Sstevel@tonic-gate  *	MAXSYSTEMLOGIN		Maximum value of a system user-ID.
123*7c478bd9Sstevel@tonic-gate  *	OPTSTR			Options to this command
124*7c478bd9Sstevel@tonic-gate  *	ROOT_ID			The user-ID of an administrator
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate #ifndef	FALSE
128*7c478bd9Sstevel@tonic-gate #define	FALSE			0
129*7c478bd9Sstevel@tonic-gate #endif
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate #ifndef	TRUE
132*7c478bd9Sstevel@tonic-gate #define	TRUE			((int) 't')
133*7c478bd9Sstevel@tonic-gate #endif
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate #define	USAGE_MSG		"usage: logins [-admopstux] [-g groups] [-l logins]"
136*7c478bd9Sstevel@tonic-gate #define	MAXLOGINSIZE		14
137*7c478bd9Sstevel@tonic-gate #define	MAXSYSTEMLOGIN		99
138*7c478bd9Sstevel@tonic-gate #define	OPTSTR			"adg:l:mopstux"
139*7c478bd9Sstevel@tonic-gate #define	ROOT_ID			0
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate /*
142*7c478bd9Sstevel@tonic-gate  *  The following macros do their function for now but will probably have
143*7c478bd9Sstevel@tonic-gate  *  to be replaced by functions sometime in the near future.  The maximum
144*7c478bd9Sstevel@tonic-gate  *  system login value may someday be administerable, in which case these
145*7c478bd9Sstevel@tonic-gate  *  will have to be changed to become functions
146*7c478bd9Sstevel@tonic-gate  *
147*7c478bd9Sstevel@tonic-gate  *	isasystemlogin	Returns TRUE if the user-ID in the "struct passwd"
148*7c478bd9Sstevel@tonic-gate  *			structure referenced by the function's argument is
149*7c478bd9Sstevel@tonic-gate  *			less than or equal to the maximum value for a system
150*7c478bd9Sstevel@tonic-gate  *			user-ID, FALSE otherwise.
151*7c478bd9Sstevel@tonic-gate  *	isauserlogin	Returns TRUE if the user-ID in the "struct passwd"
152*7c478bd9Sstevel@tonic-gate  *			structure referenced by the function's argument is
153*7c478bd9Sstevel@tonic-gate  *			greater than the maximum value for a system user-ID,
154*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise.
155*7c478bd9Sstevel@tonic-gate  */
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate #define	isauserlogin(pw)	(pw->pw_uid > MAXSYSTEMLOGIN)
158*7c478bd9Sstevel@tonic-gate #define isasystemlogin(pw)	(pw->pw_uid <= MAXSYSTEMLOGIN)
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate /*
162*7c478bd9Sstevel@tonic-gate  *  Local datatype definitions
163*7c478bd9Sstevel@tonic-gate  *	struct reqgrp		Describes a group as requested through the
164*7c478bd9Sstevel@tonic-gate  *				-g option
165*7c478bd9Sstevel@tonic-gate  *	struct reqlogin		Describes a login-ID as requested through
166*7c478bd9Sstevel@tonic-gate  *				the -l option
167*7c478bd9Sstevel@tonic-gate  *	struct pwdinfo		Describes a password's aging information,
168*7c478bd9Sstevel@tonic-gate  *				as extracted from /etc/shadow
169*7c478bd9Sstevel@tonic-gate  *	struct secgrp		Describes a login-ID's secondary group
170*7c478bd9Sstevel@tonic-gate  */
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate /*  Describes a specified group name (from the -g groups option)  */
173*7c478bd9Sstevel@tonic-gate struct	reqgrp {
174*7c478bd9Sstevel@tonic-gate 	char	       *groupname;	/* Requested group name */
175*7c478bd9Sstevel@tonic-gate 	struct reqgrp  *next;		/* Next item in the list */
176*7c478bd9Sstevel@tonic-gate 	int		found;		/* TRUE if group in /etc/group */
177*7c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group's ID */
178*7c478bd9Sstevel@tonic-gate };
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*  Describes a specified login name (from the -l logins option)  */
181*7c478bd9Sstevel@tonic-gate struct	reqlogin {
182*7c478bd9Sstevel@tonic-gate 	char	        *loginname;	/* Requested login name */
183*7c478bd9Sstevel@tonic-gate 	struct reqlogin *next;		/* Next item in the list */
184*7c478bd9Sstevel@tonic-gate 	int	 	 found;		/* TRUE if login in /etc/passwd */
185*7c478bd9Sstevel@tonic-gate };
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate /*
188*7c478bd9Sstevel@tonic-gate  * This structure describes a password's information
189*7c478bd9Sstevel@tonic-gate  */
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate struct	pwdinfo {
192*7c478bd9Sstevel@tonic-gate 	long		datechg;	/* Date the password was changed (mmddyy) */
193*7c478bd9Sstevel@tonic-gate 	char	       *passwdstatus;	/* Password status */
194*7c478bd9Sstevel@tonic-gate 	long		mindaystilchg;	/* Min days b4 pwd can change again */
195*7c478bd9Sstevel@tonic-gate 	long		maxdaystilchg;	/* Max days b4 pwd can change again */
196*7c478bd9Sstevel@tonic-gate 	long		warninterval;	/* Days before expire to warn user */
197*7c478bd9Sstevel@tonic-gate 	long		inactive;	/* Lapsed days of inactivity before lock */
198*7c478bd9Sstevel@tonic-gate 	long		expdate;	/* Date of expiration (mmddyy) */
199*7c478bd9Sstevel@tonic-gate };
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate /* This structure describes secondary groups that a user belongs to */
202*7c478bd9Sstevel@tonic-gate struct	secgrp {
203*7c478bd9Sstevel@tonic-gate 	char	       *groupname;	/* Name of the group */
204*7c478bd9Sstevel@tonic-gate 	struct secgrp  *next;		/* Next item in the list */
205*7c478bd9Sstevel@tonic-gate 	gid_t	        groupID;	/* Group-ID */
206*7c478bd9Sstevel@tonic-gate };
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate  *  These functions handle error and warning message writing.
210*7c478bd9Sstevel@tonic-gate  *  (This deals with UNIX(r) standard message generation, so
211*7c478bd9Sstevel@tonic-gate  *  the rest of the code doesn't have to.)
212*7c478bd9Sstevel@tonic-gate  *
213*7c478bd9Sstevel@tonic-gate  *  Functions included:
214*7c478bd9Sstevel@tonic-gate  *	initmsg		Initialize the message handling functions.
215*7c478bd9Sstevel@tonic-gate  *	wrtmsg		Write the message using fmtmsg().
216*7c478bd9Sstevel@tonic-gate  *
217*7c478bd9Sstevel@tonic-gate  *  Static data included:
218*7c478bd9Sstevel@tonic-gate  *	fcnlbl		The label for standard messages
219*7c478bd9Sstevel@tonic-gate  *	msgbuf		A buffer to contain the edited message
220*7c478bd9Sstevel@tonic-gate  */
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate static	char	fcnlbl[MM_MXLABELLN+1];	/* Buffer for message label */
223*7c478bd9Sstevel@tonic-gate static	char	msgbuf[MM_MXTXTLN+1];	/* Buffer for message text */
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate /*
226*7c478bd9Sstevel@tonic-gate  * void initmsg(p)
227*7c478bd9Sstevel@tonic-gate  *
228*7c478bd9Sstevel@tonic-gate  *	This function initializes the message handling functions.
229*7c478bd9Sstevel@tonic-gate  *
230*7c478bd9Sstevel@tonic-gate  *  Arguments:
231*7c478bd9Sstevel@tonic-gate  *	p	A pointer to a character string that is the name of the
232*7c478bd9Sstevel@tonic-gate  *		function, used to generate the label on messages.  If this
233*7c478bd9Sstevel@tonic-gate  *		string contains a slash ('/'), it only uses the characters
234*7c478bd9Sstevel@tonic-gate  *		beyond the last slash in the string (this permits argv[0]
235*7c478bd9Sstevel@tonic-gate  *		to be used).
236*7c478bd9Sstevel@tonic-gate  *
237*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
238*7c478bd9Sstevel@tonic-gate  */
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate static void
241*7c478bd9Sstevel@tonic-gate initmsg(p)
242*7c478bd9Sstevel@tonic-gate 	char   *p;	/* Command name (as invoked) */
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
245*7c478bd9Sstevel@tonic-gate 	char   *q;	/* Local multi-use pointer */
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	/* Use only the simple filename if there is a slash in the name */
248*7c478bd9Sstevel@tonic-gate 	if (!(q = strrchr(p, '/'))) q = p;
249*7c478bd9Sstevel@tonic-gate 	else q++;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	/* Build the label for messages */
252*7c478bd9Sstevel@tonic-gate 	(void) sprintf(fcnlbl, "UX:%s", q);
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	/* Restrict messages to the text-component */
255*7c478bd9Sstevel@tonic-gate 	(void) putenv("MSGVERB=text");
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate /*
259*7c478bd9Sstevel@tonic-gate  *  void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
260*7c478bd9Sstevel@tonic-gate  *
261*7c478bd9Sstevel@tonic-gate  *	This function writes a message using fmtmsg()
262*7c478bd9Sstevel@tonic-gate  *
263*7c478bd9Sstevel@tonic-gate  *  Arguments:
264*7c478bd9Sstevel@tonic-gate  *	severity	The severity-component of the message
265*7c478bd9Sstevel@tonic-gate  *	action		The action-string used to generate the
266*7c478bd9Sstevel@tonic-gate  *			action-component of the message
267*7c478bd9Sstevel@tonic-gate  *	tag		Tag-component of the message
268*7c478bd9Sstevel@tonic-gate  *	text		The text-string used to generate the text-
269*7c478bd9Sstevel@tonic-gate  *			component of the message
270*7c478bd9Sstevel@tonic-gate  *	txtarg		Arguments to be inserted into the "text"
271*7c478bd9Sstevel@tonic-gate  *			string using vsprintf()
272*7c478bd9Sstevel@tonic-gate  *
273*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
274*7c478bd9Sstevel@tonic-gate  */
275*7c478bd9Sstevel@tonic-gate /*VARARGS4*/
276*7c478bd9Sstevel@tonic-gate static void
277*7c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
278*7c478bd9Sstevel@tonic-gate {
279*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
280*7c478bd9Sstevel@tonic-gate 	int	errorflg;	/* TRUE if problem generating message */
281*7c478bd9Sstevel@tonic-gate 	va_list	argp;		/* Pointer into vararg list */
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	/* No problems yet */
285*7c478bd9Sstevel@tonic-gate 	errorflg = FALSE;
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	/* Generate the error message */
288*7c478bd9Sstevel@tonic-gate 	va_start(argp, text);
289*7c478bd9Sstevel@tonic-gate 	if (text != MM_NULLTXT) errorflg = vsprintf(msgbuf, text, argp) > MM_MXTXTLN;
290*7c478bd9Sstevel@tonic-gate 	(void) fmtmsg(MM_PRINT, fcnlbl, severity,
291*7c478bd9Sstevel@tonic-gate 		      (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf,
292*7c478bd9Sstevel@tonic-gate 		      action, tag);
293*7c478bd9Sstevel@tonic-gate 	va_end(argp);
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	/*
296*7c478bd9Sstevel@tonic-gate 	 *  If there was a buffer overflow generating the error message,
297*7c478bd9Sstevel@tonic-gate 	 *  write a message and quit (things are probably corrupt in the
298*7c478bd9Sstevel@tonic-gate 	 *  static data space now
299*7c478bd9Sstevel@tonic-gate 	 */
300*7c478bd9Sstevel@tonic-gate 	if (errorflg) {
301*7c478bd9Sstevel@tonic-gate 	    (void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
302*7c478bd9Sstevel@tonic-gate 			  gettext("Internal message buffer overflow"),
303*7c478bd9Sstevel@tonic-gate 			  MM_NULLACT, MM_NULLTAG);
304*7c478bd9Sstevel@tonic-gate 	    exit(100);
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate /*
310*7c478bd9Sstevel@tonic-gate  *  These functions allocate space for the information we gather.
311*7c478bd9Sstevel@tonic-gate  *  It works by having a memory heap with strings allocated from
312*7c478bd9Sstevel@tonic-gate  *  the end of the heap and structures (aligned data) allocated
313*7c478bd9Sstevel@tonic-gate  *  from the beginning of the heap.  It begins with a 4k block of
314*7c478bd9Sstevel@tonic-gate  *  memory then allocates memory in 4k chunks.  These functions
315*7c478bd9Sstevel@tonic-gate  *  should never fail.  If they do, they report the problem and
316*7c478bd9Sstevel@tonic-gate  *  exit with an exit code of 101.
317*7c478bd9Sstevel@tonic-gate  *
318*7c478bd9Sstevel@tonic-gate  *  Functions contained:
319*7c478bd9Sstevel@tonic-gate  *	allocblk	Allocates a block of memory, aligned on a
320*7c478bd9Sstevel@tonic-gate  *			4-byte (double-word) boundary.
321*7c478bd9Sstevel@tonic-gate  *	allocstr	Allocates a block of memory with no
322*7c478bd9Sstevel@tonic-gate  *			particular alignment
323*7c478bd9Sstevel@tonic-gate  *
324*7c478bd9Sstevel@tonic-gate  *  Constant definitions:
325*7c478bd9Sstevel@tonic-gate  *	ALLOCBLKSZ	Size of a chunk of main memory allocated
326*7c478bd9Sstevel@tonic-gate  *			using malloc()
327*7c478bd9Sstevel@tonic-gate  *
328*7c478bd9Sstevel@tonic-gate  *  Static data:
329*7c478bd9Sstevel@tonic-gate  *	nextblkaddr	Address of the next available chunk of
330*7c478bd9Sstevel@tonic-gate  *			aligned space in the heap
331*7c478bd9Sstevel@tonic-gate  *	laststraddr	Address of the last chunk of unaligned space
332*7c478bd9Sstevel@tonic-gate  *			allocated from the heap
333*7c478bd9Sstevel@tonic-gate  *	toomuchspace	Message to write if someone attempts to allocate
334*7c478bd9Sstevel@tonic-gate  *			too much space (>ALLOCBLKSZ bytes)
335*7c478bd9Sstevel@tonic-gate  *	memallocdif	Message to write if there is a problem
336*7c478bd9Sstevel@tonic-gate  *			allocating main menory.
337*7c478bd9Sstevel@tonic-gate  */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate #define	ALLOCBLKSZ	4096
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate static	char   *nextblkaddr = (char *) NULL;
342*7c478bd9Sstevel@tonic-gate static	char   *laststraddr = (char *) NULL;
343*7c478bd9Sstevel@tonic-gate #define	MEMALLOCDIF	"Memory allocation difficulty.  Command terminates"
344*7c478bd9Sstevel@tonic-gate #define	TOOMUCHSPACE	"Internal space allocation error.  Command terminates"
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate /*
347*7c478bd9Sstevel@tonic-gate  *  void *allocblk(size)
348*7c478bd9Sstevel@tonic-gate  *	unsigned int	size
349*7c478bd9Sstevel@tonic-gate  *
350*7c478bd9Sstevel@tonic-gate  *	This function allocates a block of aligned (4-byte or
351*7c478bd9Sstevel@tonic-gate  *	double-word boundary) memory from the program's heap.
352*7c478bd9Sstevel@tonic-gate  *	It returns a pointer to that block of allocated memory.
353*7c478bd9Sstevel@tonic-gate  *
354*7c478bd9Sstevel@tonic-gate  *  Arguments:
355*7c478bd9Sstevel@tonic-gate  *	size		Minimum number of bytes to allocate (will
356*7c478bd9Sstevel@tonic-gate  *			round up to multiple of 4)
357*7c478bd9Sstevel@tonic-gate  *
358*7c478bd9Sstevel@tonic-gate  *  Returns:  void *
359*7c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
360*7c478bd9Sstevel@tonic-gate  */
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate static void *
363*7c478bd9Sstevel@tonic-gate allocblk(size)
364*7c478bd9Sstevel@tonic-gate 	unsigned int	size;
365*7c478bd9Sstevel@tonic-gate {
366*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
367*7c478bd9Sstevel@tonic-gate 	char   *rtnval;
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	/* Make sure the sizes are aligned correctly */
371*7c478bd9Sstevel@tonic-gate 	if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) {
372*7c478bd9Sstevel@tonic-gate 	    wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
373*7c478bd9Sstevel@tonic-gate 	    exit(101);
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	/* Set up the value we're going to return */
377*7c478bd9Sstevel@tonic-gate 	rtnval = nextblkaddr;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	/* Get the space we need off of the heap */
380*7c478bd9Sstevel@tonic-gate 	if ((nextblkaddr += size) >= laststraddr) {
381*7c478bd9Sstevel@tonic-gate 	    if (!(rtnval = (char *) malloc(ALLOCBLKSZ))) {
382*7c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(MEMALLOCDIF));
383*7c478bd9Sstevel@tonic-gate 		exit(101);
384*7c478bd9Sstevel@tonic-gate 	    }
385*7c478bd9Sstevel@tonic-gate 	    laststraddr = rtnval + ALLOCBLKSZ;
386*7c478bd9Sstevel@tonic-gate 	    nextblkaddr = rtnval + size;
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	/* We're through */
390*7c478bd9Sstevel@tonic-gate 	return((void *) rtnval);
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate /*
394*7c478bd9Sstevel@tonic-gate  *  char *allocstr(nbytes)
395*7c478bd9Sstevel@tonic-gate  *	unsigned int	nbytes
396*7c478bd9Sstevel@tonic-gate  *
397*7c478bd9Sstevel@tonic-gate  *	This function allocates a block of unaligned memory from the
398*7c478bd9Sstevel@tonic-gate  *	program's heap.  It returns a pointer to that block of allocated
399*7c478bd9Sstevel@tonic-gate  *	memory.
400*7c478bd9Sstevel@tonic-gate  *
401*7c478bd9Sstevel@tonic-gate  *  Arguments:
402*7c478bd9Sstevel@tonic-gate  *	nbytes		Number of bytes to allocate
403*7c478bd9Sstevel@tonic-gate  *
404*7c478bd9Sstevel@tonic-gate  *  Returns:  char *
405*7c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
406*7c478bd9Sstevel@tonic-gate  */
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate static char *
409*7c478bd9Sstevel@tonic-gate allocstr(nchars)
410*7c478bd9Sstevel@tonic-gate 	unsigned int	nchars;
411*7c478bd9Sstevel@tonic-gate {
412*7c478bd9Sstevel@tonic-gate 	if (nchars > ALLOCBLKSZ) {
413*7c478bd9Sstevel@tonic-gate 	    wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
414*7c478bd9Sstevel@tonic-gate 	    exit(101);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	if (laststraddr == NULL ||
417*7c478bd9Sstevel@tonic-gate 	    (laststraddr -= nchars) < nextblkaddr) {
418*7c478bd9Sstevel@tonic-gate 	    if (!(nextblkaddr = (char *) malloc(ALLOCBLKSZ))) {
419*7c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(MEMALLOCDIF));
420*7c478bd9Sstevel@tonic-gate 		exit(101);
421*7c478bd9Sstevel@tonic-gate 	    }
422*7c478bd9Sstevel@tonic-gate 	    laststraddr = nextblkaddr + ALLOCBLKSZ - nchars;
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 	return(laststraddr);
425*7c478bd9Sstevel@tonic-gate }
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate /*
428*7c478bd9Sstevel@tonic-gate  *  These functions control the group membership list, as found in
429*7c478bd9Sstevel@tonic-gate  *  the /etc/group file.
430*7c478bd9Sstevel@tonic-gate  *
431*7c478bd9Sstevel@tonic-gate  *  Functions included:
432*7c478bd9Sstevel@tonic-gate  *	initmembers		Initialize the membership list (to NULL)
433*7c478bd9Sstevel@tonic-gate  *	addmember		Adds a member to the membership list
434*7c478bd9Sstevel@tonic-gate  *	isamember		Looks for a particular login-ID in the
435*7c478bd9Sstevel@tonic-gate  *				list of members
436*7c478bd9Sstevel@tonic-gate  *
437*7c478bd9Sstevel@tonic-gate  *  Datatype Definitions:
438*7c478bd9Sstevel@tonic-gate  *	struct grpmember	Describes a group member
439*7c478bd9Sstevel@tonic-gate  *
440*7c478bd9Sstevel@tonic-gate  *  Static Data:
441*7c478bd9Sstevel@tonic-gate  *	membershead		Pointer to the head of the list of
442*7c478bd9Sstevel@tonic-gate  *				group members
443*7c478bd9Sstevel@tonic-gate  */
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate struct	grpmember {
446*7c478bd9Sstevel@tonic-gate 	char	               *membername;
447*7c478bd9Sstevel@tonic-gate 	struct grpmember       *next;
448*7c478bd9Sstevel@tonic-gate };
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate static	struct grpmember       *membershead;
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate /*
453*7c478bd9Sstevel@tonic-gate  *  void initmembers()
454*7c478bd9Sstevel@tonic-gate  *
455*7c478bd9Sstevel@tonic-gate  *	This function initializes the list of members of specified groups.
456*7c478bd9Sstevel@tonic-gate  *
457*7c478bd9Sstevel@tonic-gate  *  Arguments:  None
458*7c478bd9Sstevel@tonic-gate  *
459*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate static void
463*7c478bd9Sstevel@tonic-gate initmembers()
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 	/* Set up the members list to be a null member's list */
466*7c478bd9Sstevel@tonic-gate 	membershead = (struct grpmember *) NULL;
467*7c478bd9Sstevel@tonic-gate }
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate /*
470*7c478bd9Sstevel@tonic-gate  *  void addmember(p)
471*7c478bd9Sstevel@tonic-gate  *	char   *p
472*7c478bd9Sstevel@tonic-gate  *
473*7c478bd9Sstevel@tonic-gate  *	This function adds a member to the group member's list.  The
474*7c478bd9Sstevel@tonic-gate  *	group members list is a list of structures containing a pointer
475*7c478bd9Sstevel@tonic-gate  *	to the member-name and a pointer to the next item in the
476*7c478bd9Sstevel@tonic-gate  *	structure.  The structure is not ordered in any particular way.
477*7c478bd9Sstevel@tonic-gate  *
478*7c478bd9Sstevel@tonic-gate  *  Arguments:
479*7c478bd9Sstevel@tonic-gate  *	p	Pointer to the member name
480*7c478bd9Sstevel@tonic-gate  *
481*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
482*7c478bd9Sstevel@tonic-gate  */
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate static void
485*7c478bd9Sstevel@tonic-gate addmember(p)
486*7c478bd9Sstevel@tonic-gate 	char   *p;
487*7c478bd9Sstevel@tonic-gate {
488*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
489*7c478bd9Sstevel@tonic-gate 	struct grpmember       *new;	/* Member being added */
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	new = (struct grpmember *) allocblk(sizeof(struct grpmember));
492*7c478bd9Sstevel@tonic-gate 	new->membername = strcpy(allocstr((unsigned int) strlen(p)+1), p);
493*7c478bd9Sstevel@tonic-gate 	new->next = membershead;
494*7c478bd9Sstevel@tonic-gate 	membershead = new;
495*7c478bd9Sstevel@tonic-gate }
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate /*
498*7c478bd9Sstevel@tonic-gate  *  init isamember(p)
499*7c478bd9Sstevel@tonic-gate  *	char   *p
500*7c478bd9Sstevel@tonic-gate  *
501*7c478bd9Sstevel@tonic-gate  *	This function examines the list of group-members for the string
502*7c478bd9Sstevel@tonic-gate  *	referenced by 'p'.  If 'p' is a member of the members list, the
503*7c478bd9Sstevel@tonic-gate  *	function returns TRUE.  Otherwise it returns FALSE.
504*7c478bd9Sstevel@tonic-gate  *
505*7c478bd9Sstevel@tonic-gate  *  Arguments:
506*7c478bd9Sstevel@tonic-gate  *	p	Pointer to the name to search for.
507*7c478bd9Sstevel@tonic-gate  *
508*7c478bd9Sstevel@tonic-gate  *  Returns:  int
509*7c478bd9Sstevel@tonic-gate  *	TRUE	If 'p' is found in the members list,
510*7c478bd9Sstevel@tonic-gate  *	FALSE	otherwise
511*7c478bd9Sstevel@tonic-gate  */
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate static int
514*7c478bd9Sstevel@tonic-gate isamember(p)
515*7c478bd9Sstevel@tonic-gate 	char   *p;
516*7c478bd9Sstevel@tonic-gate {
517*7c478bd9Sstevel@tonic-gate 	/* Automatic Data */
518*7c478bd9Sstevel@tonic-gate 	int			found;	/* TRUE if login found in list */
519*7c478bd9Sstevel@tonic-gate 	struct grpmember       *pmem;	/* Group member being examined */
520*7c478bd9Sstevel@tonic-gate 
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	/* Search the membership list for 'p' */
523*7c478bd9Sstevel@tonic-gate 	found = FALSE;
524*7c478bd9Sstevel@tonic-gate 	for (pmem = membershead ; !found && pmem ; pmem = pmem->next) {
525*7c478bd9Sstevel@tonic-gate 	    if (strcmp(p, pmem->membername) == 0) found = TRUE;
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	return (found);
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate /*
532*7c478bd9Sstevel@tonic-gate  *  These functions handle the display list.  The display list contains
533*7c478bd9Sstevel@tonic-gate  *  all of the information we're to display.  The list contains a pointer
534*7c478bd9Sstevel@tonic-gate  *  to the login-name, a pointer to the free-field (comment), and a
535*7c478bd9Sstevel@tonic-gate  *  pointer to the next item in the list.  The list is ordered alpha-
536*7c478bd9Sstevel@tonic-gate  *  betically (ascending) on the login-name field.  The list initially
537*7c478bd9Sstevel@tonic-gate  *  contains a dummy field (to make insertion easier) that contains a
538*7c478bd9Sstevel@tonic-gate  *  login-name of "".
539*7c478bd9Sstevel@tonic-gate  *
540*7c478bd9Sstevel@tonic-gate  *  Functions included:
541*7c478bd9Sstevel@tonic-gate  *	initdisp	Initializes the display list
542*7c478bd9Sstevel@tonic-gate  *	adddisp		Adds information to the display list
543*7c478bd9Sstevel@tonic-gate  *	isuidindisp	Looks to see if a particular user-ID is in the
544*7c478bd9Sstevel@tonic-gate  *			display list
545*7c478bd9Sstevel@tonic-gate  *	genreport	Generates a report from the items in the display
546*7c478bd9Sstevel@tonic-gate  *			list
547*7c478bd9Sstevel@tonic-gate  *	applygroup	Add group information to the items in the display
548*7c478bd9Sstevel@tonic-gate  *			list
549*7c478bd9Sstevel@tonic-gate  *	applypasswd	Add extended password information to the items
550*7c478bd9Sstevel@tonic-gate  *			in the display list
551*7c478bd9Sstevel@tonic-gate  *
552*7c478bd9Sstevel@tonic-gate  *  Datatypes Defined:
553*7c478bd9Sstevel@tonic-gate  *	struct display	Describes the structure that contains the information
554*7c478bd9Sstevel@tonic-gate  *			to be displayed.  Includes pointers to the login-ID,
555*7c478bd9Sstevel@tonic-gate  *			free-field (comment), and the next structure in the
556*7c478bd9Sstevel@tonic-gate  *			list.
557*7c478bd9Sstevel@tonic-gate  *
558*7c478bd9Sstevel@tonic-gate  *  Static Data:
559*7c478bd9Sstevel@tonic-gate  *	displayhead	Pointer to the head of the display list.  Initially
560*7c478bd9Sstevel@tonic-gate  *			references the null-item on the head of the list.
561*7c478bd9Sstevel@tonic-gate  */
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate struct	display {
564*7c478bd9Sstevel@tonic-gate 	char	       *loginID;	/* Login name */
565*7c478bd9Sstevel@tonic-gate 	char	       *freefield;	/* Free (comment) field */
566*7c478bd9Sstevel@tonic-gate 	char	       *groupname;	/* Name of the primary group */
567*7c478bd9Sstevel@tonic-gate 	char	       *iwd;		/* Initial working directory */
568*7c478bd9Sstevel@tonic-gate 	char	       *shell;		/* Shell after login (may be null) */
569*7c478bd9Sstevel@tonic-gate 	struct pwdinfo *passwdinfo;	/* Password information structure */
570*7c478bd9Sstevel@tonic-gate 	struct secgrp  *secgrplist; 	/* Head of the secondary group list */
571*7c478bd9Sstevel@tonic-gate 	uid_t		userID;		/* User ID */
572*7c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group ID of primary group */
573*7c478bd9Sstevel@tonic-gate 	struct display *nextlogin;	/* Next login in the list */
574*7c478bd9Sstevel@tonic-gate 	struct display *nextuid;	/* Next user-ID in the list */
575*7c478bd9Sstevel@tonic-gate };
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate static	struct display *displayhead;
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate /*
580*7c478bd9Sstevel@tonic-gate  *  void initdisp()
581*7c478bd9Sstevel@tonic-gate  *
582*7c478bd9Sstevel@tonic-gate  *	Initializes the display list.  An empty display list contains
583*7c478bd9Sstevel@tonic-gate  *	a single element, the dummy element.
584*7c478bd9Sstevel@tonic-gate  *
585*7c478bd9Sstevel@tonic-gate  *  Arguments:  None
586*7c478bd9Sstevel@tonic-gate  *
587*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
588*7c478bd9Sstevel@tonic-gate  */
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate static void
591*7c478bd9Sstevel@tonic-gate initdisp()
592*7c478bd9Sstevel@tonic-gate {
593*7c478bd9Sstevel@tonic-gate 	displayhead = (struct display *) allocblk(sizeof(struct display));
594*7c478bd9Sstevel@tonic-gate 	displayhead->nextlogin = (struct display *) NULL;
595*7c478bd9Sstevel@tonic-gate 	displayhead->nextuid = (struct display *) NULL;
596*7c478bd9Sstevel@tonic-gate 	displayhead->loginID = "";
597*7c478bd9Sstevel@tonic-gate 	displayhead->freefield = "";
598*7c478bd9Sstevel@tonic-gate 	displayhead->userID = -1;
599*7c478bd9Sstevel@tonic-gate }
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate /*
602*7c478bd9Sstevel@tonic-gate  *  void adddisp(pwent)
603*7c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
604*7c478bd9Sstevel@tonic-gate  *
605*7c478bd9Sstevel@tonic-gate  *	This function adds the appropriate information from the login
606*7c478bd9Sstevel@tonic-gate  *	description referenced by 'pwent' to the list if information
607*7c478bd9Sstevel@tonic-gate  *	to be displayed.  It only adds the information if the login-ID
608*7c478bd9Sstevel@tonic-gate  *	(user-name) is unique.  It inserts the information in the list
609*7c478bd9Sstevel@tonic-gate  *	in such a way that the list remains ordered alphabetically
610*7c478bd9Sstevel@tonic-gate  *	(ascending) according to the login-ID (user-name).
611*7c478bd9Sstevel@tonic-gate  *
612*7c478bd9Sstevel@tonic-gate  *  Arguments:
613*7c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains all of the login information
614*7c478bd9Sstevel@tonic-gate  *			of the login being added to the list.  The only
615*7c478bd9Sstevel@tonic-gate  *			information that this function uses is the login-ID
616*7c478bd9Sstevel@tonic-gate  *			(user-name) and the free-field (comment field).
617*7c478bd9Sstevel@tonic-gate  *
618*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
619*7c478bd9Sstevel@tonic-gate  */
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate static void
622*7c478bd9Sstevel@tonic-gate adddisp(pwent)
623*7c478bd9Sstevel@tonic-gate 	struct passwd  *pwent;
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
626*7c478bd9Sstevel@tonic-gate 	struct display *new;		/* Item being added to the list */
627*7c478bd9Sstevel@tonic-gate 	struct display *prev;		/* Previous item in the list */
628*7c478bd9Sstevel@tonic-gate 	struct display *current;	/* Next item in the list */
629*7c478bd9Sstevel@tonic-gate 	int		found;		/* FLAG, insertion point found */
630*7c478bd9Sstevel@tonic-gate 	int		compare = 1;	/* strcmp() compare value */
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	/* Find where this value belongs in the list */
634*7c478bd9Sstevel@tonic-gate 	prev = displayhead;
635*7c478bd9Sstevel@tonic-gate 	found = FALSE;
636*7c478bd9Sstevel@tonic-gate 	while (!found && (current = prev->nextlogin))
637*7c478bd9Sstevel@tonic-gate 	    if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) found = TRUE;
638*7c478bd9Sstevel@tonic-gate 	    else prev = current;
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	/* Insert this value in the list, only if it is unique though */
641*7c478bd9Sstevel@tonic-gate 	if (compare != 0) {
642*7c478bd9Sstevel@tonic-gate 	    new = (struct display *) allocblk(sizeof(struct display));
643*7c478bd9Sstevel@tonic-gate 	    new->loginID = strcpy(allocstr((unsigned int) strlen(pwent->pw_name)+1), pwent->pw_name);
644*7c478bd9Sstevel@tonic-gate 	    if (pwent->pw_comment && pwent->pw_comment[0] != '\0')
645*7c478bd9Sstevel@tonic-gate 		    new->freefield =
646*7c478bd9Sstevel@tonic-gate 			    strcpy(allocstr((unsigned int)
647*7c478bd9Sstevel@tonic-gate 					    strlen(pwent->pw_comment)+1),
648*7c478bd9Sstevel@tonic-gate 				   pwent->pw_comment);
649*7c478bd9Sstevel@tonic-gate 	    else
650*7c478bd9Sstevel@tonic-gate 		    new->freefield =
651*7c478bd9Sstevel@tonic-gate 			    strcpy(allocstr((unsigned int)
652*7c478bd9Sstevel@tonic-gate 					    strlen(pwent->pw_gecos)+1),
653*7c478bd9Sstevel@tonic-gate 				   pwent->pw_gecos);
654*7c478bd9Sstevel@tonic-gate 	    if (!pwent->pw_shell || !(*pwent->pw_shell)) new->shell = "/sbin/sh";
655*7c478bd9Sstevel@tonic-gate 	    else new->shell = strcpy(allocstr((unsigned int) strlen(pwent->pw_shell)+1), pwent->pw_shell);
656*7c478bd9Sstevel@tonic-gate 	    new->iwd = strcpy(allocstr((unsigned int) strlen(pwent->pw_dir)+1), pwent->pw_dir);
657*7c478bd9Sstevel@tonic-gate 	    new->userID = pwent->pw_uid;
658*7c478bd9Sstevel@tonic-gate 	    new->groupID = pwent->pw_gid;
659*7c478bd9Sstevel@tonic-gate 	    new->secgrplist = (struct secgrp *) NULL;
660*7c478bd9Sstevel@tonic-gate 	    new->passwdinfo = (struct pwdinfo *) NULL;
661*7c478bd9Sstevel@tonic-gate 	    new->groupname = (char *) NULL;
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate 	    /* Add new display item to the list ordered by login-ID */
664*7c478bd9Sstevel@tonic-gate 	    new->nextlogin = current;
665*7c478bd9Sstevel@tonic-gate 	    prev->nextlogin = new;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	    /* Find the appropriate place for the new item in the list
668*7c478bd9Sstevel@tonic-gate 	     * ordered by userID */
669*7c478bd9Sstevel@tonic-gate 	    prev = displayhead;
670*7c478bd9Sstevel@tonic-gate 	    found = FALSE;
671*7c478bd9Sstevel@tonic-gate 	    while (!found && (current = prev->nextuid))
672*7c478bd9Sstevel@tonic-gate 		if (current->userID > pwent->pw_uid) found = TRUE;
673*7c478bd9Sstevel@tonic-gate 		else prev = current;
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	    /* Add the item into the list that is ordered by user-ID */
676*7c478bd9Sstevel@tonic-gate 	    new->nextuid = current;
677*7c478bd9Sstevel@tonic-gate 	    prev->nextuid = new;
678*7c478bd9Sstevel@tonic-gate 	}
679*7c478bd9Sstevel@tonic-gate }
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate /*
682*7c478bd9Sstevel@tonic-gate  *  int isuidindisp(pwent)
683*7c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
684*7c478bd9Sstevel@tonic-gate  *
685*7c478bd9Sstevel@tonic-gate  *  This function examines the display list to see if the uid in
686*7c478bd9Sstevel@tonic-gate  *  the (struct passwd) referenced by "pwent" is already in the
687*7c478bd9Sstevel@tonic-gate  *  display list.  It returns TRUE if it is in the list, FALSE
688*7c478bd9Sstevel@tonic-gate  *  otherwise.
689*7c478bd9Sstevel@tonic-gate  *
690*7c478bd9Sstevel@tonic-gate  *  Since the display list is ordered by user-ID, the search continues
691*7c478bd9Sstevel@tonic-gate  *  until a match is found or a user-ID is found that is larger than
692*7c478bd9Sstevel@tonic-gate  *  the one we're searching for.
693*7c478bd9Sstevel@tonic-gate  *
694*7c478bd9Sstevel@tonic-gate  *  Arguments:
695*7c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains the user-ID we're to
696*7c478bd9Sstevel@tonic-gate  *			look for
697*7c478bd9Sstevel@tonic-gate  *
698*7c478bd9Sstevel@tonic-gate  *  Returns:  int
699*7c478bd9Sstevel@tonic-gate  *	TRUE if the user-ID was found, FALSE otherwise.
700*7c478bd9Sstevel@tonic-gate  */
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate static int
703*7c478bd9Sstevel@tonic-gate isuidindisp(pwent)
704*7c478bd9Sstevel@tonic-gate 	struct passwd  *pwent;		/* Struct of user to look for */
705*7c478bd9Sstevel@tonic-gate {
706*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
707*7c478bd9Sstevel@tonic-gate 	struct display *dp;
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	/*
711*7c478bd9Sstevel@tonic-gate 	 *  Search the list, beginning at the beginning (where else?)
712*7c478bd9Sstevel@tonic-gate 	 *  and stopping when the user-ID is found or one is found that
713*7c478bd9Sstevel@tonic-gate 	 *  is greater than the user-ID we're searching for.  Recall
714*7c478bd9Sstevel@tonic-gate 	 *  that this list is ordered by user-ID
715*7c478bd9Sstevel@tonic-gate 	 */
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 	for (dp = displayhead->nextuid ; dp && (dp->userID < pwent->pw_uid) ; dp = dp->nextuid) ;
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	/* If the pointer "dp" points to a structure that has a
720*7c478bd9Sstevel@tonic-gate 	 * matching user-ID, return TRUE.  Otherwise FALSE */
721*7c478bd9Sstevel@tonic-gate 	return (dp && (dp->userID == pwent->pw_uid));
722*7c478bd9Sstevel@tonic-gate }
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate /*
725*7c478bd9Sstevel@tonic-gate  *  void applygroup(allgroups)
726*7c478bd9Sstevel@tonic-gate  *	int	allgroups
727*7c478bd9Sstevel@tonic-gate  *
728*7c478bd9Sstevel@tonic-gate  *  This function applies group information to the login-IDs in the
729*7c478bd9Sstevel@tonic-gate  *  display list.  It always applies the primary group information.
730*7c478bd9Sstevel@tonic-gate  *  If "allgroups" is TRUE, it applies secondary information as well.
731*7c478bd9Sstevel@tonic-gate  *
732*7c478bd9Sstevel@tonic-gate  *  Arguments:
733*7c478bd9Sstevel@tonic-gate  * 	allgroups	FLAG.  TRUE if secondary group info is to be
734*7c478bd9Sstevel@tonic-gate  *			applied -- FALSE otherwise.
735*7c478bd9Sstevel@tonic-gate  *
736*7c478bd9Sstevel@tonic-gate  *  Returns:  void
737*7c478bd9Sstevel@tonic-gate  */
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate static void
740*7c478bd9Sstevel@tonic-gate applygroup(allgroups)
741*7c478bd9Sstevel@tonic-gate 	int	allgroups;	/* TRUE if applying secondary groups */
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate 	/* Automatic Data */
744*7c478bd9Sstevel@tonic-gate 	struct display *dp;		/* Display list running ptr */
745*7c478bd9Sstevel@tonic-gate 	struct group   *grent;		/* Group info, from getgrent() */
746*7c478bd9Sstevel@tonic-gate 	char	       *p;		/* Temp char pointer */
747*7c478bd9Sstevel@tonic-gate 	char          **pp;		/* Temp char * pointer */
748*7c478bd9Sstevel@tonic-gate 	int		compare;	/* Value from strcmp() */
749*7c478bd9Sstevel@tonic-gate 	int		done;		/* TRUE if finished, FALSE otherwise */
750*7c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Block allocated for this info */
751*7c478bd9Sstevel@tonic-gate 	struct secgrp  *psrch;		/* Secondary group -- for searching */
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* For each group-ID in the /etc/group file ... */
755*7c478bd9Sstevel@tonic-gate 	while (grent = getgrent()) {
756*7c478bd9Sstevel@tonic-gate 	    /*
757*7c478bd9Sstevel@tonic-gate 	     *  Set the primary group for the login-IDs in the display
758*7c478bd9Sstevel@tonic-gate 	     *  list.  For each group-ID we get, leaf through the display
759*7c478bd9Sstevel@tonic-gate 	     *  list and set the group-name if the group-IDs match
760*7c478bd9Sstevel@tonic-gate 	     */
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	    p = (char *) NULL;
763*7c478bd9Sstevel@tonic-gate 	    for (dp = displayhead->nextuid ; dp ; dp = dp->nextuid)
764*7c478bd9Sstevel@tonic-gate 		if ((dp->groupID == grent->gr_gid) && !dp->groupname) {
765*7c478bd9Sstevel@tonic-gate 		    if (!p) p = strcpy(allocstr((unsigned int) strlen(grent->gr_name)+1), grent->gr_name);
766*7c478bd9Sstevel@tonic-gate 		    dp->groupname = p;
767*7c478bd9Sstevel@tonic-gate 		}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	    /*
770*7c478bd9Sstevel@tonic-gate 	     *  If we're to be displaying secondary group membership,
771*7c478bd9Sstevel@tonic-gate 	     *  leaf through the list of group members.  Then, attempt
772*7c478bd9Sstevel@tonic-gate 	     *  to find that member in the display list.  When found,
773*7c478bd9Sstevel@tonic-gate 	     *  attach secondary group info to the user.
774*7c478bd9Sstevel@tonic-gate 	     */
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	    if (allgroups) for (pp = grent->gr_mem ; *pp ; pp++) {
777*7c478bd9Sstevel@tonic-gate 		done = FALSE;
778*7c478bd9Sstevel@tonic-gate 		for (dp = displayhead->nextlogin ; !done && dp ; dp = dp->nextlogin) {
779*7c478bd9Sstevel@tonic-gate 		    if (((compare = strcmp(dp->loginID, *pp)) == 0) && !(grent->gr_gid == dp->groupID)) {
780*7c478bd9Sstevel@tonic-gate 			if (!p) p = strcpy(allocstr((unsigned int) strlen(grent->gr_name)+1), grent->gr_name);
781*7c478bd9Sstevel@tonic-gate 			psecgrp = (struct secgrp *) allocblk(sizeof(struct secgrp));
782*7c478bd9Sstevel@tonic-gate 			psecgrp->groupID = grent->gr_gid;
783*7c478bd9Sstevel@tonic-gate 			psecgrp->groupname = p;
784*7c478bd9Sstevel@tonic-gate 			psecgrp->next = (struct secgrp *) NULL;
785*7c478bd9Sstevel@tonic-gate 			if (!dp->secgrplist) dp->secgrplist = psecgrp;
786*7c478bd9Sstevel@tonic-gate 			else {
787*7c478bd9Sstevel@tonic-gate 			    for (psrch = dp->secgrplist ; psrch->next ; psrch = psrch->next) ;
788*7c478bd9Sstevel@tonic-gate 			    psrch->next = psecgrp;
789*7c478bd9Sstevel@tonic-gate 			}
790*7c478bd9Sstevel@tonic-gate 			done = TRUE;
791*7c478bd9Sstevel@tonic-gate 		    }
792*7c478bd9Sstevel@tonic-gate 		    else if (compare > 0) done = TRUE;
793*7c478bd9Sstevel@tonic-gate 		}
794*7c478bd9Sstevel@tonic-gate 	    }
795*7c478bd9Sstevel@tonic-gate 	}
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	/* Close the /etc/group file */
798*7c478bd9Sstevel@tonic-gate 	endgrent();
799*7c478bd9Sstevel@tonic-gate }
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate /*
802*7c478bd9Sstevel@tonic-gate  *  void applypasswd()
803*7c478bd9Sstevel@tonic-gate  *
804*7c478bd9Sstevel@tonic-gate  *	This function applies extended password information to an item
805*7c478bd9Sstevel@tonic-gate  *	to be displayed.  It allocates space for a structure describing
806*7c478bd9Sstevel@tonic-gate  *	the password, then fills in that structure from the information
807*7c478bd9Sstevel@tonic-gate  *	in the /etc/shadow file.
808*7c478bd9Sstevel@tonic-gate  *
809*7c478bd9Sstevel@tonic-gate  *  Arguments:  None
810*7c478bd9Sstevel@tonic-gate  *
811*7c478bd9Sstevel@tonic-gate  *  Returns:  Void
812*7c478bd9Sstevel@tonic-gate  */
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate static void
815*7c478bd9Sstevel@tonic-gate applypasswd()
816*7c478bd9Sstevel@tonic-gate {
817*7c478bd9Sstevel@tonic-gate 	/*
818*7c478bd9Sstevel@tonic-gate 	 *  Local declarations
819*7c478bd9Sstevel@tonic-gate 	 */
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	struct pwdinfo *ppasswd;	/* Ptr to pwd desc in current element */
822*7c478bd9Sstevel@tonic-gate 	struct display *dp;		/* Ptr to current element */
823*7c478bd9Sstevel@tonic-gate 	struct spwd    *psp;		/* Pointer to a shadow-file entry */
824*7c478bd9Sstevel@tonic-gate 	struct tm      *ptm;		/* Pointer to a time-of-day structure */
825*7c478bd9Sstevel@tonic-gate 	char	       *p;		/* Running character pointer */
826*7c478bd9Sstevel@tonic-gate 	time_t 		pwchg;		/* System-time of last pwd chg */
827*7c478bd9Sstevel@tonic-gate 	time_t 		pwexp;		/* System-time of password expiration */
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	/*  Make sure the shadow file is rewound  */
831*7c478bd9Sstevel@tonic-gate 	setspent();
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	/*
835*7c478bd9Sstevel@tonic-gate 	 *  For each item in the display list...
836*7c478bd9Sstevel@tonic-gate 	 */
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	for (dp = displayhead->nextuid ; dp ; dp = dp->nextuid) {
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate 	    /* Allocate structure space for the password description */
841*7c478bd9Sstevel@tonic-gate 	    ppasswd = (struct pwdinfo *) allocblk(sizeof(struct pwdinfo));
842*7c478bd9Sstevel@tonic-gate 	    dp->passwdinfo = ppasswd;
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 	    /*
845*7c478bd9Sstevel@tonic-gate 	     * If there's no entry in the /etc/shadow file, assume
846*7c478bd9Sstevel@tonic-gate 	     * that the login is locked
847*7c478bd9Sstevel@tonic-gate 	     */
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	    if (!(psp = getspnam(dp->loginID))) {
850*7c478bd9Sstevel@tonic-gate 		pwchg = 0L;			/* Epoch */
851*7c478bd9Sstevel@tonic-gate 		ppasswd->passwdstatus = "LK";	/* LK, Locked */
852*7c478bd9Sstevel@tonic-gate 		ppasswd->mindaystilchg = 0L;
853*7c478bd9Sstevel@tonic-gate 		ppasswd->maxdaystilchg = 0L;
854*7c478bd9Sstevel@tonic-gate 		ppasswd->warninterval = 0L;
855*7c478bd9Sstevel@tonic-gate 		ppasswd->inactive = 0L;
856*7c478bd9Sstevel@tonic-gate 		pwexp = 0L;
857*7c478bd9Sstevel@tonic-gate 	    }
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	    /*
860*7c478bd9Sstevel@tonic-gate 	     * Otherwise, fill in the password information from the
861*7c478bd9Sstevel@tonic-gate 	     * info in the shadow file entry
862*7c478bd9Sstevel@tonic-gate 	     */
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	    else {
865*7c478bd9Sstevel@tonic-gate 		/*  See if the login has no password  */
866*7c478bd9Sstevel@tonic-gate 		if (!psp->sp_pwdp || !(*psp->sp_pwdp)) ppasswd->passwdstatus = "NP";
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 		/*
869*7c478bd9Sstevel@tonic-gate 		 * See if the login is explicitly locked (encrypted
870*7c478bd9Sstevel@tonic-gate 		 * password is <13 characters)
871*7c478bd9Sstevel@tonic-gate 		 */
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 		else if (strlen(psp->sp_pwdp) != 13) ppasswd->passwdstatus = "LK";
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 		/*
876*7c478bd9Sstevel@tonic-gate 		 * If it's a valid encrypted password, the login is
877*7c478bd9Sstevel@tonic-gate 		 * password protected
878*7c478bd9Sstevel@tonic-gate 		 */
879*7c478bd9Sstevel@tonic-gate 		else {
880*7c478bd9Sstevel@tonic-gate 		    ppasswd->passwdstatus = "PS";
881*7c478bd9Sstevel@tonic-gate 		    for (p = psp->sp_pwdp ; *p ; p++) {
882*7c478bd9Sstevel@tonic-gate 			if (!isalnum(*p) && (*p != '.') && (*p != '/')) {
883*7c478bd9Sstevel@tonic-gate 			    ppasswd->passwdstatus = "LK";
884*7c478bd9Sstevel@tonic-gate 			    break;
885*7c478bd9Sstevel@tonic-gate 			}
886*7c478bd9Sstevel@tonic-gate 		    }
887*7c478bd9Sstevel@tonic-gate 		}
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 		/*
890*7c478bd9Sstevel@tonic-gate 		 * Set up the last-changed date, the minimum days between
891*7c478bd9Sstevel@tonic-gate 		 * changes, the maximum life of a password, the interval
892*7c478bd9Sstevel@tonic-gate 		 * before expiration that the user is warned, the number of
893*7c478bd9Sstevel@tonic-gate 		 * days a login can be inactive before it expires, and the
894*7c478bd9Sstevel@tonic-gate 		 * login expiration date
895*7c478bd9Sstevel@tonic-gate 		 */
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 		pwchg = psp->sp_lstchg;
898*7c478bd9Sstevel@tonic-gate 		ppasswd->mindaystilchg = psp->sp_min;
899*7c478bd9Sstevel@tonic-gate 		ppasswd->maxdaystilchg = psp->sp_max;
900*7c478bd9Sstevel@tonic-gate 		ppasswd->warninterval = psp->sp_warn;
901*7c478bd9Sstevel@tonic-gate 		ppasswd->inactive = psp->sp_inact;
902*7c478bd9Sstevel@tonic-gate 		pwexp = psp->sp_expire;
903*7c478bd9Sstevel@tonic-gate 	    }
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	    /*
906*7c478bd9Sstevel@tonic-gate 	     * Convert the date of the last password change from days-
907*7c478bd9Sstevel@tonic-gate 	     * since-epoch to mmddyy (integer) form.  Involves the
908*7c478bd9Sstevel@tonic-gate 	     * intermediate step of converting the date from days-
909*7c478bd9Sstevel@tonic-gate 	     * since-epoch to seconds-since-epoch.  We'll set this to
910*7c478bd9Sstevel@tonic-gate 	     * somewhere near the middle of the day, since there are not
911*7c478bd9Sstevel@tonic-gate 	     * always 24*60*60 seconds in a year.  (Yeech)
912*7c478bd9Sstevel@tonic-gate 	     *
913*7c478bd9Sstevel@tonic-gate 	     * Note:  The form mmddyy should probably be subject to
914*7c478bd9Sstevel@tonic-gate 	     * internationalization -- Non-Americans will think that
915*7c478bd9Sstevel@tonic-gate 	     * 070888 is 07 August 88 when the software is trying to say
916*7c478bd9Sstevel@tonic-gate 	     * 08 July 88.  Systems Engineers seem to think that this isn't
917*7c478bd9Sstevel@tonic-gate 	     * a problem though...
918*7c478bd9Sstevel@tonic-gate 	     */
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	    if (pwchg != -1L) {
921*7c478bd9Sstevel@tonic-gate 	        pwchg = (pwchg * DAY) + (DAY/2);
922*7c478bd9Sstevel@tonic-gate 		ptm = localtime(&pwchg);
923*7c478bd9Sstevel@tonic-gate 		ppasswd->datechg = ((long) (ptm->tm_mon+1) * 10000L) +
924*7c478bd9Sstevel@tonic-gate 				    (long) ((ptm->tm_mday * 100) +
925*7c478bd9Sstevel@tonic-gate 					    (ptm->tm_year % 100));
926*7c478bd9Sstevel@tonic-gate 	    } else ppasswd->datechg = 0L;
927*7c478bd9Sstevel@tonic-gate 
928*7c478bd9Sstevel@tonic-gate 	    /*
929*7c478bd9Sstevel@tonic-gate 	     * Convert the passwd expiration date from days-since-epoch
930*7c478bd9Sstevel@tonic-gate 	     * to mmddyy (long integer) form using the same algorithm and
931*7c478bd9Sstevel@tonic-gate 	     * comments as above.
932*7c478bd9Sstevel@tonic-gate 	     */
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	    if (pwexp != -1L) {
935*7c478bd9Sstevel@tonic-gate 		pwexp = (pwexp * DAY) + (DAY/2);
936*7c478bd9Sstevel@tonic-gate 		ptm = localtime(&pwexp);
937*7c478bd9Sstevel@tonic-gate 		ppasswd->expdate = ((long) (ptm->tm_mon+1) * 10000L) +
938*7c478bd9Sstevel@tonic-gate 				    (long) ((ptm->tm_mday * 100) +
939*7c478bd9Sstevel@tonic-gate 					    (ptm->tm_year % 100));
940*7c478bd9Sstevel@tonic-gate 	    } else ppasswd->expdate = 0L;
941*7c478bd9Sstevel@tonic-gate 	}
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	/* Close the shadow password file */
944*7c478bd9Sstevel@tonic-gate 	endspent();
945*7c478bd9Sstevel@tonic-gate }
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate /*
948*7c478bd9Sstevel@tonic-gate  * int hasnopasswd(pwent)
949*7c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
950*7c478bd9Sstevel@tonic-gate  *
951*7c478bd9Sstevel@tonic-gate  *	This function examines a login's password-file entry
952*7c478bd9Sstevel@tonic-gate  *	and, if necessary, its shadow password-file entry and
953*7c478bd9Sstevel@tonic-gate  *	returns TRUE if that user-ID has no password, meaning
954*7c478bd9Sstevel@tonic-gate  *	that the user-ID can be used to log into the system
955*7c478bd9Sstevel@tonic-gate  *	without giving a password.  The function returns FALSE
956*7c478bd9Sstevel@tonic-gate  *	otherwise.
957*7c478bd9Sstevel@tonic-gate  *
958*7c478bd9Sstevel@tonic-gate  *  Arguments:
959*7c478bd9Sstevel@tonic-gate  *	pwent	Login to examine.
960*7c478bd9Sstevel@tonic-gate  *
961*7c478bd9Sstevel@tonic-gate  *  Returns:  int
962*7c478bd9Sstevel@tonic-gate  *	TRUE if the login can be used without a password, FALSE
963*7c478bd9Sstevel@tonic-gate  *	otherwise.
964*7c478bd9Sstevel@tonic-gate  */
965*7c478bd9Sstevel@tonic-gate 
966*7c478bd9Sstevel@tonic-gate static int
967*7c478bd9Sstevel@tonic-gate hasnopasswd(pwent)
968*7c478bd9Sstevel@tonic-gate 	struct passwd  *pwent;	/* /etc/passwd entry of login to check */
969*7c478bd9Sstevel@tonic-gate {
970*7c478bd9Sstevel@tonic-gate 	/* Local definitions */
971*7c478bd9Sstevel@tonic-gate 	struct spwd    *psp;		/* /etc/shadow file struct */
972*7c478bd9Sstevel@tonic-gate 	int		nopwflag;	/* TRUE if login has no passwd */
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	/*
975*7c478bd9Sstevel@tonic-gate 	 *  A login has no password if:
976*7c478bd9Sstevel@tonic-gate 	 *    1.  There exists an entry for that login in the
977*7c478bd9Sstevel@tonic-gate 	 *	  shadow password-file (/etc/passwd), and
978*7c478bd9Sstevel@tonic-gate 	 *    2.  The encrypted password in the structure describing
979*7c478bd9Sstevel@tonic-gate 	 *	  that entry is either:
980*7c478bd9Sstevel@tonic-gate 	 *	      a.  (char *) NULL
981*7c478bd9Sstevel@tonic-gate 	 *	      b.  A null string ("")
982*7c478bd9Sstevel@tonic-gate 	 */
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	/* Get the login's entry in the shadow password file */
985*7c478bd9Sstevel@tonic-gate 	if (psp = getspnam(pwent->pw_name)) {
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	    /* Look at the encrypted password in that entry */
988*7c478bd9Sstevel@tonic-gate 	    if (psp->sp_pwdp == (char *)0 ||
989*7c478bd9Sstevel@tonic-gate 			 *psp->sp_pwdp == '\0')
990*7c478bd9Sstevel@tonic-gate 		nopwflag = TRUE;
991*7c478bd9Sstevel@tonic-gate 	    else
992*7c478bd9Sstevel@tonic-gate 		nopwflag = FALSE;
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 	else
995*7c478bd9Sstevel@tonic-gate 		nopwflag = FALSE;
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	/* Done ... */
998*7c478bd9Sstevel@tonic-gate 	return(nopwflag);
999*7c478bd9Sstevel@tonic-gate }
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate /*
1002*7c478bd9Sstevel@tonic-gate  *  void writeunformatted(current, xtndflag, expflag)
1003*7c478bd9Sstevel@tonic-gate  *	struct display *current
1004*7c478bd9Sstevel@tonic-gate  *	int		xtndflag
1005*7c478bd9Sstevel@tonic-gate  *	int		expflag
1006*7c478bd9Sstevel@tonic-gate  *
1007*7c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
1008*7c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in the
1009*7c478bd9Sstevel@tonic-gate  *  form of a colon-list.  It writes secondary group information if
1010*7c478bd9Sstevel@tonic-gate  *  that information is in the structure, it writes extended
1011*7c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info
1012*7c478bd9Sstevel@tonic-gate  *  if the "xtndflag" is TRUE, and it writes password expiration
1013*7c478bd9Sstevel@tonic-gate  *  information if "expflag" is TRUE.
1014*7c478bd9Sstevel@tonic-gate  *
1015*7c478bd9Sstevel@tonic-gate  *  Arguments:
1016*7c478bd9Sstevel@tonic-gate  *	current		Structure containing information to write.
1017*7c478bd9Sstevel@tonic-gate  *	xtndflag	TRUE if extended information is to be written,
1018*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1019*7c478bd9Sstevel@tonic-gate  *	expflag		TRUE if password expiration information is to
1020*7c478bd9Sstevel@tonic-gate  *			be written, FALSE otherwise
1021*7c478bd9Sstevel@tonic-gate  *
1022*7c478bd9Sstevel@tonic-gate  *  Returns:  void
1023*7c478bd9Sstevel@tonic-gate  */
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate static void
1026*7c478bd9Sstevel@tonic-gate writeunformatted(current, xtndflag, expflag)
1027*7c478bd9Sstevel@tonic-gate 	struct display *current;	/* Struct with info to write */
1028*7c478bd9Sstevel@tonic-gate 	int		xtndflag;	/* Write extended output flag */
1029*7c478bd9Sstevel@tonic-gate 	int		expflag;	/* Write password expiration info flag */
1030*7c478bd9Sstevel@tonic-gate {
1031*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
1032*7c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
1033*7c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	/* Write the general information */
1036*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%s:%ld:%s:%ld:%s",
1037*7c478bd9Sstevel@tonic-gate 		       current->loginID,
1038*7c478bd9Sstevel@tonic-gate 		       current->userID,
1039*7c478bd9Sstevel@tonic-gate 		       current->groupname == (char *) NULL ? "" : current->groupname,
1040*7c478bd9Sstevel@tonic-gate 		       current->groupID,
1041*7c478bd9Sstevel@tonic-gate 		       current->freefield);
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	/*
1044*7c478bd9Sstevel@tonic-gate 	 * If the group information is there, write it (it's only
1045*7c478bd9Sstevel@tonic-gate 	 * there if it's supposed to be written)
1046*7c478bd9Sstevel@tonic-gate 	 */
1047*7c478bd9Sstevel@tonic-gate 	for (psecgrp = current->secgrplist ; psecgrp ; psecgrp = psecgrp->next)
1048*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, ":%s:%ld", psecgrp->groupname, psecgrp->groupID);
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	/* If the extended info flag is TRUE, write the extended information */
1051*7c478bd9Sstevel@tonic-gate 	if (xtndflag) {
1052*7c478bd9Sstevel@tonic-gate 	    pwdinfo = current->passwdinfo;
1053*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, ":%s:%s:%s:%6.6ld:%ld:%ld:%ld",
1054*7c478bd9Sstevel@tonic-gate 			   current->iwd, current->shell,
1055*7c478bd9Sstevel@tonic-gate 			   pwdinfo->passwdstatus,
1056*7c478bd9Sstevel@tonic-gate 			   pwdinfo->datechg,
1057*7c478bd9Sstevel@tonic-gate 			   pwdinfo->mindaystilchg, pwdinfo->maxdaystilchg,
1058*7c478bd9Sstevel@tonic-gate 			   pwdinfo->warninterval);
1059*7c478bd9Sstevel@tonic-gate 	}
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	/* If the password expiration information is requested, write it.  */
1062*7c478bd9Sstevel@tonic-gate 	if (expflag) {
1063*7c478bd9Sstevel@tonic-gate 	    pwdinfo = current->passwdinfo;
1064*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, ":%ld:%ld", pwdinfo->inactive, pwdinfo->expdate);
1065*7c478bd9Sstevel@tonic-gate 	}
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	/* Terminate the information with a new-line */
1068*7c478bd9Sstevel@tonic-gate 	(void) putc('\n', stdout);
1069*7c478bd9Sstevel@tonic-gate }
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate /*
1072*7c478bd9Sstevel@tonic-gate  *  void writeformatted(current, xtndflag, expflag)
1073*7c478bd9Sstevel@tonic-gate  *	struct display *current
1074*7c478bd9Sstevel@tonic-gate  *	int		xtndflag
1075*7c478bd9Sstevel@tonic-gate  *	int		expflag
1076*7c478bd9Sstevel@tonic-gate  *
1077*7c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
1078*7c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in an
1079*7c478bd9Sstevel@tonic-gate  *  easily readable format.  It writes secondary group information
1080*7c478bd9Sstevel@tonic-gate  *  if that information is in the structure, it writes extended
1081*7c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info if
1082*7c478bd9Sstevel@tonic-gate  *  "xtndflag" is TRUE, and it write password expiration information
1083*7c478bd9Sstevel@tonic-gate  *  if "expflag" is TRUE.
1084*7c478bd9Sstevel@tonic-gate  *
1085*7c478bd9Sstevel@tonic-gate  *  Arguments:
1086*7c478bd9Sstevel@tonic-gate  *	current		Structure containing info to write.
1087*7c478bd9Sstevel@tonic-gate  *	xtndflag	TRUE if extended information is to be written,
1088*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1089*7c478bd9Sstevel@tonic-gate  *	expflag		TRUE if password expiration information is to be written,
1090*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1091*7c478bd9Sstevel@tonic-gate  *
1092*7c478bd9Sstevel@tonic-gate  *  Returns:  void
1093*7c478bd9Sstevel@tonic-gate  */
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate static void
1096*7c478bd9Sstevel@tonic-gate writeformatted(current, xtndflag, expflag)
1097*7c478bd9Sstevel@tonic-gate 	struct display *current;	/* Struct with info to write */
1098*7c478bd9Sstevel@tonic-gate 	int		xtndflag;	/* Write extended output flag */
1099*7c478bd9Sstevel@tonic-gate 	int		expflag;	/* Write password expiration info flag */
1100*7c478bd9Sstevel@tonic-gate {
1101*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
1102*7c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
1103*7c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	/* Write general information */
1106*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%-14s  %-6ld  %-14s  %-6ld  %s\n",
1107*7c478bd9Sstevel@tonic-gate 		       current->loginID, current->userID,
1108*7c478bd9Sstevel@tonic-gate 		       current->groupname == (char *) NULL ? "" : current->groupname,
1109*7c478bd9Sstevel@tonic-gate 		       current->groupID, current->freefield);
1110*7c478bd9Sstevel@tonic-gate 
1111*7c478bd9Sstevel@tonic-gate 	/*
1112*7c478bd9Sstevel@tonic-gate 	 * Write information about secondary groups if the info exists
1113*7c478bd9Sstevel@tonic-gate 	 * (it only exists if it is to be written)
1114*7c478bd9Sstevel@tonic-gate 	 */
1115*7c478bd9Sstevel@tonic-gate 	for (psecgrp = current->secgrplist ; psecgrp ; psecgrp = psecgrp->next)
1116*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %-14s  %-6ld\n",
1117*7c478bd9Sstevel@tonic-gate 			   psecgrp->groupname, psecgrp->groupID);
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/* If the extended information flag is TRUE, write the extended information */
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate 	if (xtndflag) {
1122*7c478bd9Sstevel@tonic-gate 	    pwdinfo = current->passwdinfo;
1123*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %s\n", current->iwd);
1124*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %s\n", current->shell);
1125*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %s %6.6ld %ld %ld %ld\n",
1126*7c478bd9Sstevel@tonic-gate 			   pwdinfo->passwdstatus,
1127*7c478bd9Sstevel@tonic-gate 			   pwdinfo->datechg, pwdinfo->mindaystilchg,
1128*7c478bd9Sstevel@tonic-gate 			   pwdinfo->maxdaystilchg,
1129*7c478bd9Sstevel@tonic-gate 			   pwdinfo->warninterval);
1130*7c478bd9Sstevel@tonic-gate 	}
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	/* If the password expiration info flag is TRUE, write that information */
1133*7c478bd9Sstevel@tonic-gate 	if (expflag) {
1134*7c478bd9Sstevel@tonic-gate 	    pwdinfo = current->passwdinfo;
1135*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %ld %6.6ld\n",
1136*7c478bd9Sstevel@tonic-gate 			   pwdinfo->inactive, pwdinfo->expdate);
1137*7c478bd9Sstevel@tonic-gate     }
1138*7c478bd9Sstevel@tonic-gate }
1139*7c478bd9Sstevel@tonic-gate 
1140*7c478bd9Sstevel@tonic-gate /*
1141*7c478bd9Sstevel@tonic-gate  *  void genuidreport(pipeflag, xtndflag, expflag)
1142*7c478bd9Sstevel@tonic-gate  *	int	pipeflag
1143*7c478bd9Sstevel@tonic-gate  *	int	xtndflag
1144*7c478bd9Sstevel@tonic-gate  *	int	expflag
1145*7c478bd9Sstevel@tonic-gate  *
1146*7c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
1147*7c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
1148*7c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
1149*7c478bd9Sstevel@tonic-gate  *	on user-ID.  If the <pipeflag> variable is not zero, it
1150*7c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
1151*7c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
1152*7c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
1153*7c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
1154*7c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
1155*7c478bd9Sstevel@tonic-gate  *	zero, it will display password expiration information.
1156*7c478bd9Sstevel@tonic-gate  *
1157*7c478bd9Sstevel@tonic-gate  *  Arguments:
1158*7c478bd9Sstevel@tonic-gate  *	pipeflag	int
1159*7c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
1160*7c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
1161*7c478bd9Sstevel@tonic-gate  *	xtndflag	int
1162*7c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
1163*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1164*7c478bd9Sstevel@tonic-gate  *	expflag		int
1165*7c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to be
1166*7c478bd9Sstevel@tonic-gate  *			displayed, FALSE otherwise
1167*7c478bd9Sstevel@tonic-gate  *
1168*7c478bd9Sstevel@tonic-gate  *  Returns:  void
1169*7c478bd9Sstevel@tonic-gate  */
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate static void
1172*7c478bd9Sstevel@tonic-gate genuidreport(pipeflag, xtndflag, expflag)
1173*7c478bd9Sstevel@tonic-gate 	int	pipeflag;	/* Parsible output flag */
1174*7c478bd9Sstevel@tonic-gate 	int	xtndflag;	/* Extended info flag */
1175*7c478bd9Sstevel@tonic-gate 	int	expflag;	/* Password expiration info flag */
1176*7c478bd9Sstevel@tonic-gate {
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
1179*7c478bd9Sstevel@tonic-gate 	struct display *current;	/* Data being displayed */
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate 
1182*7c478bd9Sstevel@tonic-gate 	/*
1183*7c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
1184*7c478bd9Sstevel@tonic-gate 	 *  (NOTE:  The first element in the list of logins to
1185*7c478bd9Sstevel@tonic-gate 	 *          display is a dummy element.)
1186*7c478bd9Sstevel@tonic-gate 	 */
1187*7c478bd9Sstevel@tonic-gate 	current = displayhead;
1188*7c478bd9Sstevel@tonic-gate 
1189*7c478bd9Sstevel@tonic-gate 	/*
1190*7c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
1191*7c478bd9Sstevel@tonic-gate 	 */
1192*7c478bd9Sstevel@tonic-gate 	if (pipeflag)
1193*7c478bd9Sstevel@tonic-gate 	    for (current = displayhead->nextuid ; current ; current = current->nextuid)
1194*7c478bd9Sstevel@tonic-gate 	    	writeunformatted(current, xtndflag, expflag);
1195*7c478bd9Sstevel@tonic-gate 	else
1196*7c478bd9Sstevel@tonic-gate 	    for (current = displayhead->nextuid ; current ; current = current->nextuid)
1197*7c478bd9Sstevel@tonic-gate 	    	writeformatted(current, xtndflag, expflag);
1198*7c478bd9Sstevel@tonic-gate }
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate /*
1201*7c478bd9Sstevel@tonic-gate  *  void genlogreport(pipeflag, xtndflag, expflag)
1202*7c478bd9Sstevel@tonic-gate  *	int	pipeflag
1203*7c478bd9Sstevel@tonic-gate  *	int	xtndflag
1204*7c478bd9Sstevel@tonic-gate  *	int	expflag
1205*7c478bd9Sstevel@tonic-gate  *
1206*7c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
1207*7c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
1208*7c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
1209*7c478bd9Sstevel@tonic-gate  *	on user name.  If the <pipeflag> variable is not zero, it
1210*7c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
1211*7c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
1212*7c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
1213*7c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
1214*7c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
1215*7c478bd9Sstevel@tonic-gate  *	zero, it will include password expiration information.
1216*7c478bd9Sstevel@tonic-gate  *
1217*7c478bd9Sstevel@tonic-gate  *  Arguments:
1218*7c478bd9Sstevel@tonic-gate  *	pipeflag	int
1219*7c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
1220*7c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
1221*7c478bd9Sstevel@tonic-gate  *	xtndflag	int
1222*7c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
1223*7c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1224*7c478bd9Sstevel@tonic-gate  *	expflag		int
1225*7c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to
1226*7c478bd9Sstevel@tonic-gate  *			be displayed, FALSE otherwise
1227*7c478bd9Sstevel@tonic-gate  *
1228*7c478bd9Sstevel@tonic-gate  *  Returns:  void
1229*7c478bd9Sstevel@tonic-gate  */
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate static void
1232*7c478bd9Sstevel@tonic-gate genlogreport(pipeflag, xtndflag, expflag)
1233*7c478bd9Sstevel@tonic-gate 	int	pipeflag;	/* Parsable output flag */
1234*7c478bd9Sstevel@tonic-gate 	int	xtndflag;	/* Extended info flag */
1235*7c478bd9Sstevel@tonic-gate 	int	expflag;	/* Password expiration info flag */
1236*7c478bd9Sstevel@tonic-gate {
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
1239*7c478bd9Sstevel@tonic-gate 	struct display *p;	/* Value being displayed */
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	/*
1243*7c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
1244*7c478bd9Sstevel@tonic-gate 	 *  (NOTE:  The first element in the list of logins to
1245*7c478bd9Sstevel@tonic-gate 	 *          display is a dummy element.)
1246*7c478bd9Sstevel@tonic-gate 	 */
1247*7c478bd9Sstevel@tonic-gate 	p = displayhead;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	/*
1250*7c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
1251*7c478bd9Sstevel@tonic-gate 	 */
1252*7c478bd9Sstevel@tonic-gate 	if (pipeflag)
1253*7c478bd9Sstevel@tonic-gate 	    for (p = displayhead->nextlogin ; p ; p = p->nextlogin)
1254*7c478bd9Sstevel@tonic-gate 	    	writeunformatted(p, xtndflag, expflag);
1255*7c478bd9Sstevel@tonic-gate 	else
1256*7c478bd9Sstevel@tonic-gate 	    for (p = displayhead->nextlogin ; p ; p = p->nextlogin)
1257*7c478bd9Sstevel@tonic-gate 	    	writeformatted(p, xtndflag, expflag);
1258*7c478bd9Sstevel@tonic-gate }
1259*7c478bd9Sstevel@tonic-gate 
1260*7c478bd9Sstevel@tonic-gate char *
1261*7c478bd9Sstevel@tonic-gate strcpmalloc(str)
1262*7c478bd9Sstevel@tonic-gate char *str;
1263*7c478bd9Sstevel@tonic-gate {
1264*7c478bd9Sstevel@tonic-gate 	char *cp;
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
1267*7c478bd9Sstevel@tonic-gate 		return NULL;
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate 	return (strcpy(allocstr((unsigned int)strlen(str)+1), str));
1270*7c478bd9Sstevel@tonic-gate }
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate struct localpw {
1273*7c478bd9Sstevel@tonic-gate 	struct localpw *next;
1274*7c478bd9Sstevel@tonic-gate 	struct passwd pw;
1275*7c478bd9Sstevel@tonic-gate };
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate struct localpw *pwtable = NULL;
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate struct localpw *pwptr;		/* Local passwd pointer for getpwent()
1280*7c478bd9Sstevel@tonic-gate 				 * -- -1 means not in use, NULL for EOF */
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate int in_localgetpwent = 0;	/* Set if in local_getpwent */
1283*7c478bd9Sstevel@tonic-gate 
1284*7c478bd9Sstevel@tonic-gate void
1285*7c478bd9Sstevel@tonic-gate build_localpw()
1286*7c478bd9Sstevel@tonic-gate {
1287*7c478bd9Sstevel@tonic-gate 	struct localpw *next, *cur;
1288*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	next = (struct localpw *) allocblk(sizeof (struct localpw));
1291*7c478bd9Sstevel@tonic-gate 
1292*7c478bd9Sstevel@tonic-gate 	pwtable = next;
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	while ((pw = getpwent()) != NULL) {
1295*7c478bd9Sstevel@tonic-gate 		/*
1296*7c478bd9Sstevel@tonic-gate 		 * Copy the data -- we have to alloc areas for it all
1297*7c478bd9Sstevel@tonic-gate 		 */
1298*7c478bd9Sstevel@tonic-gate 		next->pw.pw_name = strcpmalloc(pw->pw_name);
1299*7c478bd9Sstevel@tonic-gate 		next->pw.pw_passwd = strcpmalloc(pw->pw_passwd);
1300*7c478bd9Sstevel@tonic-gate 		next->pw.pw_uid = pw->pw_uid;
1301*7c478bd9Sstevel@tonic-gate 		next->pw.pw_gid = pw->pw_gid;
1302*7c478bd9Sstevel@tonic-gate 		next->pw.pw_age = strcpmalloc(pw->pw_age);
1303*7c478bd9Sstevel@tonic-gate 		next->pw.pw_comment = strcpmalloc(pw->pw_comment);
1304*7c478bd9Sstevel@tonic-gate 		next->pw.pw_gecos  = strcpmalloc(pw->pw_gecos);
1305*7c478bd9Sstevel@tonic-gate 		next->pw.pw_dir = strcpmalloc(pw->pw_dir);
1306*7c478bd9Sstevel@tonic-gate 		next->pw.pw_shell = strcpmalloc(pw->pw_shell);
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 		next->next = (struct localpw *) allocblk(sizeof (struct localpw));
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate 		cur = next;
1311*7c478bd9Sstevel@tonic-gate 		next = next->next;
1312*7c478bd9Sstevel@tonic-gate 	}
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	/*
1315*7c478bd9Sstevel@tonic-gate 	 * At this point we have one extra (struct localpw) allocated;
1316*7c478bd9Sstevel@tonic-gate 	 * sine alloclbk doesn't have a freeblk, we just leave it unreferenced.
1317*7c478bd9Sstevel@tonic-gate 	 */
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	if (pwtable == next)
1320*7c478bd9Sstevel@tonic-gate 		pwtable = NULL;
1321*7c478bd9Sstevel@tonic-gate 	else
1322*7c478bd9Sstevel@tonic-gate 		cur->next = NULL;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	endpwent();
1325*7c478bd9Sstevel@tonic-gate }
1326*7c478bd9Sstevel@tonic-gate 
1327*7c478bd9Sstevel@tonic-gate struct passwd *
1328*7c478bd9Sstevel@tonic-gate local_getpwent()
1329*7c478bd9Sstevel@tonic-gate {
1330*7c478bd9Sstevel@tonic-gate 	if (!in_localgetpwent) {
1331*7c478bd9Sstevel@tonic-gate 		in_localgetpwent = 1;
1332*7c478bd9Sstevel@tonic-gate 		pwptr = pwtable;
1333*7c478bd9Sstevel@tonic-gate 	} else if ( pwptr != NULL)
1334*7c478bd9Sstevel@tonic-gate 		pwptr = pwptr->next;
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	if (pwptr != NULL)
1337*7c478bd9Sstevel@tonic-gate 		return &(pwptr->pw);
1338*7c478bd9Sstevel@tonic-gate 	else
1339*7c478bd9Sstevel@tonic-gate 		return NULL;
1340*7c478bd9Sstevel@tonic-gate }
1341*7c478bd9Sstevel@tonic-gate 
1342*7c478bd9Sstevel@tonic-gate void
1343*7c478bd9Sstevel@tonic-gate local_endpwent()
1344*7c478bd9Sstevel@tonic-gate {
1345*7c478bd9Sstevel@tonic-gate 	in_localgetpwent = 0;
1346*7c478bd9Sstevel@tonic-gate }
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate long
1349*7c478bd9Sstevel@tonic-gate local_pwtell()
1350*7c478bd9Sstevel@tonic-gate {
1351*7c478bd9Sstevel@tonic-gate 	return (long)pwptr;
1352*7c478bd9Sstevel@tonic-gate }
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate void
1355*7c478bd9Sstevel@tonic-gate local_pwseek(ptr)
1356*7c478bd9Sstevel@tonic-gate long ptr;
1357*7c478bd9Sstevel@tonic-gate {
1358*7c478bd9Sstevel@tonic-gate 	pwptr = (struct localpw *)ptr;
1359*7c478bd9Sstevel@tonic-gate }
1360*7c478bd9Sstevel@tonic-gate 
1361*7c478bd9Sstevel@tonic-gate /*
1362*7c478bd9Sstevel@tonic-gate  * logins [-admopstux] [-l logins] [-g groups]
1363*7c478bd9Sstevel@tonic-gate  *
1364*7c478bd9Sstevel@tonic-gate  *	This command generates a report of logins administered on
1365*7c478bd9Sstevel@tonic-gate  *	the system.  The list will contain logins that meet criteria
1366*7c478bd9Sstevel@tonic-gate  *	described by the options in the list.  If there are no options,
1367*7c478bd9Sstevel@tonic-gate  *	it will list all logins administered.  It is intended to be used
1368*7c478bd9Sstevel@tonic-gate  *	only by administrators.
1369*7c478bd9Sstevel@tonic-gate  *
1370*7c478bd9Sstevel@tonic-gate  *  Options:
1371*7c478bd9Sstevel@tonic-gate  *	-a		Display password expiration information.
1372*7c478bd9Sstevel@tonic-gate  *	-d		list all logins that share user-IDs with another
1373*7c478bd9Sstevel@tonic-gate  *			login.
1374*7c478bd9Sstevel@tonic-gate  *	-g groups	specifies the names of the groups to which a login
1375*7c478bd9Sstevel@tonic-gate  *			must belong before it is included in the generated
1376*7c478bd9Sstevel@tonic-gate  *			list.  "groups" is a comma-list of group names.
1377*7c478bd9Sstevel@tonic-gate  *	-l logins	specifies the logins to display.  "logins" is a
1378*7c478bd9Sstevel@tonic-gate  *			comma-list of login names.
1379*7c478bd9Sstevel@tonic-gate  *	-m		in addition to the usual information, for each
1380*7c478bd9Sstevel@tonic-gate  *			login displayed, list all groups to which that
1381*7c478bd9Sstevel@tonic-gate  *			login is member.
1382*7c478bd9Sstevel@tonic-gate  *	-o		generate a report as a colon-list instead of in a
1383*7c478bd9Sstevel@tonic-gate  *			columnar format
1384*7c478bd9Sstevel@tonic-gate  *	-p		list all logins that have no password.
1385*7c478bd9Sstevel@tonic-gate  *	-s		list all system logins
1386*7c478bd9Sstevel@tonic-gate  *	-t		sort the report lexicographically by login name
1387*7c478bd9Sstevel@tonic-gate  *			instead of by user-ID
1388*7c478bd9Sstevel@tonic-gate  *	-u		list all user logins
1389*7c478bd9Sstevel@tonic-gate  *	-x		in addition to the usual information, display an
1390*7c478bd9Sstevel@tonic-gate  *			extended set of information that includes the home
1391*7c478bd9Sstevel@tonic-gate  *			directory, initial process, and password status and
1392*7c478bd9Sstevel@tonic-gate  *			aging information
1393*7c478bd9Sstevel@tonic-gate  *
1394*7c478bd9Sstevel@tonic-gate  * Exit Codes:
1395*7c478bd9Sstevel@tonic-gate  *	0	All's well that ends well
1396*7c478bd9Sstevel@tonic-gate  *	1	Usage error
1397*7c478bd9Sstevel@tonic-gate  */
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate main(argc, argv)
1400*7c478bd9Sstevel@tonic-gate 	int	argc;	/* Number of args on the command line */
1401*7c478bd9Sstevel@tonic-gate 	char   *argv[];	/* Pointers pointing to the arguments */
1402*7c478bd9Sstevel@tonic-gate {
1403*7c478bd9Sstevel@tonic-gate 
1404*7c478bd9Sstevel@tonic-gate 	/* Automatic data */
1405*7c478bd9Sstevel@tonic-gate 
1406*7c478bd9Sstevel@tonic-gate 	struct passwd	       *plookpwd;	/* Ptr to searcher pw (-d) */
1407*7c478bd9Sstevel@tonic-gate 	struct reqgrp	       *reqgrphead;	/* Head of the req'd group list */
1408*7c478bd9Sstevel@tonic-gate 	struct reqgrp	       *pgrp;		/* Current item in req'd group list */
1409*7c478bd9Sstevel@tonic-gate 	struct reqgrp	       *qgrp;		/* Prev item in the req'd group list */
1410*7c478bd9Sstevel@tonic-gate 	struct reqlogin        *reqloginhead;	/* Head of req'd login list */
1411*7c478bd9Sstevel@tonic-gate 	struct reqlogin	       *plogin;		/* Current item in the req'd login list */
1412*7c478bd9Sstevel@tonic-gate 	struct reqlogin	       *qlogin;		/* Prev item in the req'd login list */
1413*7c478bd9Sstevel@tonic-gate 	struct passwd	       *pwent;		/* /etc/passwd entry */
1414*7c478bd9Sstevel@tonic-gate 	struct group	       *grent;		/* /etc/group entry */
1415*7c478bd9Sstevel@tonic-gate 	char		       *token;		/* Token extracted by strtok() */
1416*7c478bd9Sstevel@tonic-gate 	char		      **pp;		/* Group member */
1417*7c478bd9Sstevel@tonic-gate 	char		       *g_arg;		/* -g option's argument */
1418*7c478bd9Sstevel@tonic-gate 	char		       *l_arg;		/* -l option's argument */
1419*7c478bd9Sstevel@tonic-gate 	long			lookpos;	/* File pos'n, rec we're looking for */
1420*7c478bd9Sstevel@tonic-gate 	int			a_seen;		/* Is -a requested? */
1421*7c478bd9Sstevel@tonic-gate 	int			d_seen;		/* Is -d requested? */
1422*7c478bd9Sstevel@tonic-gate 	int	 	 	g_seen;		/* Is -g requested? */
1423*7c478bd9Sstevel@tonic-gate 	int			l_seen;		/* Is -l requested? */
1424*7c478bd9Sstevel@tonic-gate 	int			m_seen;		/* Is -m requested? */
1425*7c478bd9Sstevel@tonic-gate 	int			o_seen;		/* Is -o requested? */
1426*7c478bd9Sstevel@tonic-gate 	int			p_seen;		/* Is -p requested? */
1427*7c478bd9Sstevel@tonic-gate 	int			s_seen;		/* Is -s requested? */
1428*7c478bd9Sstevel@tonic-gate 	int			t_seen;		/* Is -t requested? */
1429*7c478bd9Sstevel@tonic-gate 	int			u_seen;		/* Is -u requested? */
1430*7c478bd9Sstevel@tonic-gate 	int			x_seen;		/* Is -x requested? */
1431*7c478bd9Sstevel@tonic-gate 	int			errflg;		/* Is there a command-line problem */
1432*7c478bd9Sstevel@tonic-gate 	int			done;		/* Is the process (?) is complete */
1433*7c478bd9Sstevel@tonic-gate 	int			groupcount;	/* Number of groups specified by the user */
1434*7c478bd9Sstevel@tonic-gate 	int			doall;		/* Are all logins to be reported */
1435*7c478bd9Sstevel@tonic-gate 	int			c;		/* Character returned from getopt() */
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1440*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1441*7c478bd9Sstevel@tonic-gate #endif
1442*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate 	/* Initializations */
1445*7c478bd9Sstevel@tonic-gate 	initmsg(argv[0]);
1446*7c478bd9Sstevel@tonic-gate 
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	/*
1450*7c478bd9Sstevel@tonic-gate 	 *  Command-line processing
1451*7c478bd9Sstevel@tonic-gate 	 */
1452*7c478bd9Sstevel@tonic-gate 
1453*7c478bd9Sstevel@tonic-gate 	/* Initializations */
1454*7c478bd9Sstevel@tonic-gate 	a_seen = FALSE;
1455*7c478bd9Sstevel@tonic-gate 	d_seen = FALSE;
1456*7c478bd9Sstevel@tonic-gate 	g_seen = FALSE;
1457*7c478bd9Sstevel@tonic-gate 	l_seen = FALSE;
1458*7c478bd9Sstevel@tonic-gate 	m_seen = FALSE;
1459*7c478bd9Sstevel@tonic-gate 	o_seen = FALSE;
1460*7c478bd9Sstevel@tonic-gate 	p_seen = FALSE;
1461*7c478bd9Sstevel@tonic-gate 	s_seen = FALSE;
1462*7c478bd9Sstevel@tonic-gate 	t_seen = FALSE;
1463*7c478bd9Sstevel@tonic-gate 	u_seen = FALSE;
1464*7c478bd9Sstevel@tonic-gate 	x_seen = FALSE;
1465*7c478bd9Sstevel@tonic-gate 	errflg = FALSE;
1466*7c478bd9Sstevel@tonic-gate 	opterr = 0;
1467*7c478bd9Sstevel@tonic-gate 	while (!errflg && ((c = getopt(argc, argv, OPTSTR)) != EOF)) {
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	    /* Case on the option character */
1470*7c478bd9Sstevel@tonic-gate 	    switch(c) {
1471*7c478bd9Sstevel@tonic-gate 
1472*7c478bd9Sstevel@tonic-gate 	    /*
1473*7c478bd9Sstevel@tonic-gate 	     * -a option:
1474*7c478bd9Sstevel@tonic-gate 	     * Display password expiration information
1475*7c478bd9Sstevel@tonic-gate 	     */
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate 	    case 'a':
1478*7c478bd9Sstevel@tonic-gate 		if (a_seen) errflg = TRUE;
1479*7c478bd9Sstevel@tonic-gate 		else a_seen = TRUE;
1480*7c478bd9Sstevel@tonic-gate 		break;
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	    /*
1483*7c478bd9Sstevel@tonic-gate 	     * -d option:
1484*7c478bd9Sstevel@tonic-gate 	     * Display logins which share user-IDs with other logins
1485*7c478bd9Sstevel@tonic-gate 	     */
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 	    case 'd':
1488*7c478bd9Sstevel@tonic-gate 		if (d_seen) errflg = TRUE;
1489*7c478bd9Sstevel@tonic-gate 		else d_seen = TRUE;
1490*7c478bd9Sstevel@tonic-gate 		break;
1491*7c478bd9Sstevel@tonic-gate 
1492*7c478bd9Sstevel@tonic-gate 	    /*
1493*7c478bd9Sstevel@tonic-gate 	     * -g <groups> option:
1494*7c478bd9Sstevel@tonic-gate 	     * Display the specified groups
1495*7c478bd9Sstevel@tonic-gate 	     */
1496*7c478bd9Sstevel@tonic-gate 
1497*7c478bd9Sstevel@tonic-gate 	    case 'g':
1498*7c478bd9Sstevel@tonic-gate 		if (g_seen) errflg = TRUE;
1499*7c478bd9Sstevel@tonic-gate 		else {
1500*7c478bd9Sstevel@tonic-gate 		    g_seen = TRUE;
1501*7c478bd9Sstevel@tonic-gate 		    g_arg = optarg;
1502*7c478bd9Sstevel@tonic-gate 		}
1503*7c478bd9Sstevel@tonic-gate 		break;
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	    /*
1506*7c478bd9Sstevel@tonic-gate 	     * -l <logins> option:
1507*7c478bd9Sstevel@tonic-gate 	     * Display the specified logins
1508*7c478bd9Sstevel@tonic-gate 	     */
1509*7c478bd9Sstevel@tonic-gate 
1510*7c478bd9Sstevel@tonic-gate 	    case 'l':
1511*7c478bd9Sstevel@tonic-gate 		if (l_seen) errflg = TRUE;
1512*7c478bd9Sstevel@tonic-gate 		else {
1513*7c478bd9Sstevel@tonic-gate 		    l_seen = TRUE;
1514*7c478bd9Sstevel@tonic-gate 		    l_arg = optarg;
1515*7c478bd9Sstevel@tonic-gate 		}
1516*7c478bd9Sstevel@tonic-gate 		break;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 	    /*
1519*7c478bd9Sstevel@tonic-gate 	     * -m option:
1520*7c478bd9Sstevel@tonic-gate 	     * Display multiple group information
1521*7c478bd9Sstevel@tonic-gate 	     */
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate 	    case 'm':
1524*7c478bd9Sstevel@tonic-gate 		if (m_seen) errflg = TRUE;
1525*7c478bd9Sstevel@tonic-gate 		else m_seen = TRUE;
1526*7c478bd9Sstevel@tonic-gate 		break;
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 	    /*
1529*7c478bd9Sstevel@tonic-gate 	     * -o option:
1530*7c478bd9Sstevel@tonic-gate 	     * Display information as a colon-list
1531*7c478bd9Sstevel@tonic-gate 	     */
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate 	    case 'o':
1534*7c478bd9Sstevel@tonic-gate 		if (o_seen) errflg = TRUE;
1535*7c478bd9Sstevel@tonic-gate 		else o_seen = TRUE;
1536*7c478bd9Sstevel@tonic-gate 		break;
1537*7c478bd9Sstevel@tonic-gate 
1538*7c478bd9Sstevel@tonic-gate 	    /*
1539*7c478bd9Sstevel@tonic-gate 	     * -p option:
1540*7c478bd9Sstevel@tonic-gate 	     * Select logins that have no password
1541*7c478bd9Sstevel@tonic-gate 	     */
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 	    case 'p':
1544*7c478bd9Sstevel@tonic-gate 		if (p_seen) errflg = TRUE;
1545*7c478bd9Sstevel@tonic-gate 		else p_seen = TRUE;
1546*7c478bd9Sstevel@tonic-gate 		break;
1547*7c478bd9Sstevel@tonic-gate 
1548*7c478bd9Sstevel@tonic-gate 	    /*
1549*7c478bd9Sstevel@tonic-gate 	     * -s option:
1550*7c478bd9Sstevel@tonic-gate 	     * Select system logins
1551*7c478bd9Sstevel@tonic-gate 	     */
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate 	    case 's':
1554*7c478bd9Sstevel@tonic-gate 		if (s_seen) errflg = TRUE;
1555*7c478bd9Sstevel@tonic-gate 		else s_seen = TRUE;
1556*7c478bd9Sstevel@tonic-gate 		break;
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	    /*
1559*7c478bd9Sstevel@tonic-gate 	     * -t option:
1560*7c478bd9Sstevel@tonic-gate 	     * Sort alphabetically by login-ID instead of numerically
1561*7c478bd9Sstevel@tonic-gate 	     * by user-ID
1562*7c478bd9Sstevel@tonic-gate 	     */
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate 	    case 't':
1565*7c478bd9Sstevel@tonic-gate 		if (t_seen) errflg = TRUE;
1566*7c478bd9Sstevel@tonic-gate 		else t_seen = TRUE;
1567*7c478bd9Sstevel@tonic-gate 		break;
1568*7c478bd9Sstevel@tonic-gate 
1569*7c478bd9Sstevel@tonic-gate 	    /*
1570*7c478bd9Sstevel@tonic-gate 	     * -u option:
1571*7c478bd9Sstevel@tonic-gate 	     * Select user logins
1572*7c478bd9Sstevel@tonic-gate 	     */
1573*7c478bd9Sstevel@tonic-gate 
1574*7c478bd9Sstevel@tonic-gate 	    case 'u':
1575*7c478bd9Sstevel@tonic-gate 		if (u_seen) errflg = TRUE;
1576*7c478bd9Sstevel@tonic-gate 		else u_seen = TRUE;
1577*7c478bd9Sstevel@tonic-gate 		break;
1578*7c478bd9Sstevel@tonic-gate 
1579*7c478bd9Sstevel@tonic-gate 	    /*
1580*7c478bd9Sstevel@tonic-gate 	     * -x option:
1581*7c478bd9Sstevel@tonic-gate 	     * Display extended info (init working dir, shell, pwd info)
1582*7c478bd9Sstevel@tonic-gate 	     */
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 	    case 'x':
1585*7c478bd9Sstevel@tonic-gate 		if (x_seen) errflg = TRUE;
1586*7c478bd9Sstevel@tonic-gate 		else x_seen = TRUE;
1587*7c478bd9Sstevel@tonic-gate 		break;
1588*7c478bd9Sstevel@tonic-gate 
1589*7c478bd9Sstevel@tonic-gate 	    default:			/* Oops.... */
1590*7c478bd9Sstevel@tonic-gate 		errflg = TRUE;
1591*7c478bd9Sstevel@tonic-gate 	    }
1592*7c478bd9Sstevel@tonic-gate 	}
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 	/* Write out a usage message if necessary and quit */
1595*7c478bd9Sstevel@tonic-gate 	if (errflg || (optind != argc)) {
1596*7c478bd9Sstevel@tonic-gate 	    wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(USAGE_MSG));
1597*7c478bd9Sstevel@tonic-gate 	    exit(1);
1598*7c478bd9Sstevel@tonic-gate 	}
1599*7c478bd9Sstevel@tonic-gate 
1600*7c478bd9Sstevel@tonic-gate 
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 	/*
1603*7c478bd9Sstevel@tonic-gate 	 *  The following section does preparation work, setting up for
1604*7c478bd9Sstevel@tonic-gate 	 *  building the list of logins to display
1605*7c478bd9Sstevel@tonic-gate 	 */
1606*7c478bd9Sstevel@tonic-gate 
1607*7c478bd9Sstevel@tonic-gate 	/*
1608*7c478bd9Sstevel@tonic-gate 	 * Very first thing, build an in-core structure of passwd file entries.
1609*7c478bd9Sstevel@tonic-gate 	 * This is important since we have to assume that getpwent() is going
1610*7c478bd9Sstevel@tonic-gate 	 * out to one or more network name services that could be changing
1611*7c478bd9Sstevel@tonic-gate 	 * on the fly.  This will limit us to one pass through the network data.
1612*7c478bd9Sstevel@tonic-gate 	 */
1613*7c478bd9Sstevel@tonic-gate 	build_localpw();
1614*7c478bd9Sstevel@tonic-gate 
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 	/*
1617*7c478bd9Sstevel@tonic-gate 	 *  If the -g groups option was on the command line, build a
1618*7c478bd9Sstevel@tonic-gate 	 *  list containing groups we're to list logins for.
1619*7c478bd9Sstevel@tonic-gate 	 */
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate 	if (g_seen) {
1622*7c478bd9Sstevel@tonic-gate 	    groupcount = 0;
1623*7c478bd9Sstevel@tonic-gate 	    reqgrphead = (struct reqgrp *) NULL;
1624*7c478bd9Sstevel@tonic-gate 	    if (token = strtok(g_arg, ",")) {
1625*7c478bd9Sstevel@tonic-gate 		pgrp = (struct reqgrp *) allocblk(sizeof(struct reqgrp));
1626*7c478bd9Sstevel@tonic-gate 		pgrp->groupname = token;
1627*7c478bd9Sstevel@tonic-gate 		pgrp->found = FALSE;
1628*7c478bd9Sstevel@tonic-gate 		pgrp->next = (struct reqgrp *) NULL;
1629*7c478bd9Sstevel@tonic-gate 		groupcount++;
1630*7c478bd9Sstevel@tonic-gate 		reqgrphead = pgrp;
1631*7c478bd9Sstevel@tonic-gate 		qgrp = pgrp;
1632*7c478bd9Sstevel@tonic-gate 		while (token = strtok(NULL, ",")) {
1633*7c478bd9Sstevel@tonic-gate 		    pgrp = (struct reqgrp *) allocblk(sizeof(struct reqgrp));
1634*7c478bd9Sstevel@tonic-gate 		    pgrp->groupname = token;
1635*7c478bd9Sstevel@tonic-gate 		    pgrp->found = FALSE;
1636*7c478bd9Sstevel@tonic-gate 		    pgrp->next = (struct reqgrp *) NULL;
1637*7c478bd9Sstevel@tonic-gate 		    groupcount++;
1638*7c478bd9Sstevel@tonic-gate 		    qgrp->next = pgrp;
1639*7c478bd9Sstevel@tonic-gate 		    qgrp = pgrp;
1640*7c478bd9Sstevel@tonic-gate 		}
1641*7c478bd9Sstevel@tonic-gate 	    }
1642*7c478bd9Sstevel@tonic-gate 	}
1643*7c478bd9Sstevel@tonic-gate 
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 	/*
1646*7c478bd9Sstevel@tonic-gate 	 *  If -l logins is on the command line, build a list of
1647*7c478bd9Sstevel@tonic-gate 	 *  logins we're to generate reports for.
1648*7c478bd9Sstevel@tonic-gate 	 */
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 	if (l_seen) {
1651*7c478bd9Sstevel@tonic-gate 	    reqloginhead = (struct reqlogin *) NULL;
1652*7c478bd9Sstevel@tonic-gate 	    if (token = strtok(l_arg, ",")) {
1653*7c478bd9Sstevel@tonic-gate 		plogin = (struct reqlogin *) allocblk(sizeof(struct reqlogin));
1654*7c478bd9Sstevel@tonic-gate 		plogin->loginname = token;
1655*7c478bd9Sstevel@tonic-gate 		plogin->found = FALSE;
1656*7c478bd9Sstevel@tonic-gate 		plogin->next = (struct reqlogin *) NULL;
1657*7c478bd9Sstevel@tonic-gate 		reqloginhead = plogin;
1658*7c478bd9Sstevel@tonic-gate 		qlogin = plogin;
1659*7c478bd9Sstevel@tonic-gate 		while (token = strtok(NULL, ",")) {
1660*7c478bd9Sstevel@tonic-gate 		    plogin = (struct reqlogin *) allocblk(sizeof(struct reqlogin));
1661*7c478bd9Sstevel@tonic-gate 		    plogin->loginname = token;
1662*7c478bd9Sstevel@tonic-gate 		    plogin->found = FALSE;
1663*7c478bd9Sstevel@tonic-gate 		    plogin->next = (struct reqlogin *) NULL;
1664*7c478bd9Sstevel@tonic-gate 		    qlogin->next = plogin;
1665*7c478bd9Sstevel@tonic-gate 		    qlogin = plogin;
1666*7c478bd9Sstevel@tonic-gate 		}
1667*7c478bd9Sstevel@tonic-gate 	    }
1668*7c478bd9Sstevel@tonic-gate 	}
1669*7c478bd9Sstevel@tonic-gate 
1670*7c478bd9Sstevel@tonic-gate 	if (l_seen) {
1671*7c478bd9Sstevel@tonic-gate 		while(pwent = local_getpwent()) {
1672*7c478bd9Sstevel@tonic-gate 			done = FALSE;
1673*7c478bd9Sstevel@tonic-gate 			for (plogin = reqloginhead ; !done && plogin ;
1674*7c478bd9Sstevel@tonic-gate 						plogin = plogin->next) {
1675*7c478bd9Sstevel@tonic-gate 				if (strcmp(pwent->pw_name,
1676*7c478bd9Sstevel@tonic-gate 					   plogin->loginname) == 0) {
1677*7c478bd9Sstevel@tonic-gate 				    	plogin->found = TRUE;
1678*7c478bd9Sstevel@tonic-gate 			    		done = TRUE;
1679*7c478bd9Sstevel@tonic-gate 				}
1680*7c478bd9Sstevel@tonic-gate 		    	}
1681*7c478bd9Sstevel@tonic-gate 		}
1682*7c478bd9Sstevel@tonic-gate 		local_endpwent();
1683*7c478bd9Sstevel@tonic-gate 	}
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 	/*
1686*7c478bd9Sstevel@tonic-gate 	 *  Generate the list of login information to display
1687*7c478bd9Sstevel@tonic-gate 	 */
1688*7c478bd9Sstevel@tonic-gate 
1689*7c478bd9Sstevel@tonic-gate 	/* Initialize the login list */
1690*7c478bd9Sstevel@tonic-gate 	initmembers();
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 	/*
1694*7c478bd9Sstevel@tonic-gate 	 *  If -g groups was specified, generate a list of members
1695*7c478bd9Sstevel@tonic-gate 	 *  of the specified groups
1696*7c478bd9Sstevel@tonic-gate 	 */
1697*7c478bd9Sstevel@tonic-gate 
1698*7c478bd9Sstevel@tonic-gate 	if (g_seen) {
1699*7c478bd9Sstevel@tonic-gate 
1700*7c478bd9Sstevel@tonic-gate 	    /* For each group in the /etc/group file ... */
1701*7c478bd9Sstevel@tonic-gate 	    while (grent = getgrent()) {
1702*7c478bd9Sstevel@tonic-gate 
1703*7c478bd9Sstevel@tonic-gate 		/* For each group mentioned with the -g option ... */
1704*7c478bd9Sstevel@tonic-gate 		for (pgrp = reqgrphead ; (groupcount > 0) && pgrp ; pgrp = pgrp->next) {
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 		    if (!pgrp->found) {
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 			/*
1709*7c478bd9Sstevel@tonic-gate 			 *  If the mentioned group is found in the
1710*7c478bd9Sstevel@tonic-gate 			 *  /etc/group file ...
1711*7c478bd9Sstevel@tonic-gate 			 */
1712*7c478bd9Sstevel@tonic-gate 			if (strcmp(grent->gr_name, pgrp->groupname) == 0) {
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate 			    /*
1715*7c478bd9Sstevel@tonic-gate 			     * Mark the entry is found, remembering the
1716*7c478bd9Sstevel@tonic-gate 			     * group-ID for later
1717*7c478bd9Sstevel@tonic-gate 			     */
1718*7c478bd9Sstevel@tonic-gate 
1719*7c478bd9Sstevel@tonic-gate 			    pgrp->found = TRUE;
1720*7c478bd9Sstevel@tonic-gate 			    groupcount--;
1721*7c478bd9Sstevel@tonic-gate 			    pgrp->groupID = grent->gr_gid;
1722*7c478bd9Sstevel@tonic-gate 			    for (pp = grent->gr_mem ; *pp ; pp++) addmember(*pp);
1723*7c478bd9Sstevel@tonic-gate 			}
1724*7c478bd9Sstevel@tonic-gate 		    }
1725*7c478bd9Sstevel@tonic-gate 		}
1726*7c478bd9Sstevel@tonic-gate 	    }
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate 
1729*7c478bd9Sstevel@tonic-gate 	    /*
1730*7c478bd9Sstevel@tonic-gate 	     * If any groups weren't found, write a message indicating
1731*7c478bd9Sstevel@tonic-gate 	     * such, then continue
1732*7c478bd9Sstevel@tonic-gate 	     */
1733*7c478bd9Sstevel@tonic-gate 
1734*7c478bd9Sstevel@tonic-gate 	    qgrp = (struct reqgrp *) NULL;
1735*7c478bd9Sstevel@tonic-gate 	    for (pgrp = reqgrphead ; pgrp ; pgrp = pgrp->next) {
1736*7c478bd9Sstevel@tonic-gate 		if (!pgrp->found) {
1737*7c478bd9Sstevel@tonic-gate 		    wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, gettext("%s was not found"), pgrp->groupname);
1738*7c478bd9Sstevel@tonic-gate 		    if (!qgrp) reqgrphead = pgrp->next;
1739*7c478bd9Sstevel@tonic-gate 		    else qgrp->next = pgrp->next;
1740*7c478bd9Sstevel@tonic-gate 		}
1741*7c478bd9Sstevel@tonic-gate 		else qgrp = pgrp;
1742*7c478bd9Sstevel@tonic-gate 	    }
1743*7c478bd9Sstevel@tonic-gate 	    endgrent();
1744*7c478bd9Sstevel@tonic-gate 	}
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 	/* Initialize the list of logins to display */
1748*7c478bd9Sstevel@tonic-gate 	initdisp();
1749*7c478bd9Sstevel@tonic-gate 
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate 	/*
1752*7c478bd9Sstevel@tonic-gate 	 *  Add logins that have user-IDs that are used more than once,
1753*7c478bd9Sstevel@tonic-gate 	 *  if requested.  This command is pretty slow, since the algorithm
1754*7c478bd9Sstevel@tonic-gate 	 *  reads from the /etc/passwd file 1+2+3+...+n times where n is the
1755*7c478bd9Sstevel@tonic-gate 	 *  number of login-IDs in the /etc/passwd file.  (Actually, this
1756*7c478bd9Sstevel@tonic-gate 	 *  can be optimized so it's not quite that bad, but the order or
1757*7c478bd9Sstevel@tonic-gate 	 *  magnitude stays the same.)
1758*7c478bd9Sstevel@tonic-gate 	 *
1759*7c478bd9Sstevel@tonic-gate 	 *  Note:  This processing needs to be done before any other options
1760*7c478bd9Sstevel@tonic-gate 	 *         are processed -- the algorithm contains an optimization
1761*7c478bd9Sstevel@tonic-gate 	 *	   that insists on the display list being empty before this
1762*7c478bd9Sstevel@tonic-gate 	 *	   option is processed.
1763*7c478bd9Sstevel@tonic-gate 	 */
1764*7c478bd9Sstevel@tonic-gate 
1765*7c478bd9Sstevel@tonic-gate 	if (d_seen) {
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate 	    /*
1768*7c478bd9Sstevel@tonic-gate 	     * The following code is a quick&dirty reimplementation of the
1769*7c478bd9Sstevel@tonic-gate 	     * original algorithm, which opened the password file twice (to
1770*7c478bd9Sstevel@tonic-gate 	     * get two file pointer into the data) and then used fgetpwent()
1771*7c478bd9Sstevel@tonic-gate 	     * in undocumented ways to scan through the file, checking for
1772*7c478bd9Sstevel@tonic-gate 	     * duplicates.  This does not work when getpwent() is used to
1773*7c478bd9Sstevel@tonic-gate 	     * go out over the network, since there is not file pointer.
1774*7c478bd9Sstevel@tonic-gate 	     *
1775*7c478bd9Sstevel@tonic-gate 	     * Instead an in-memory list of passwd structures is built, and then
1776*7c478bd9Sstevel@tonic-gate 	     * this list is scanned.  The routines Local_getpwent(), etc.,
1777*7c478bd9Sstevel@tonic-gate 	     * are designed to mimic the standard library routines, so this code
1778*7c478bd9Sstevel@tonic-gate 	     * does not have to be extensively modified.
1779*7c478bd9Sstevel@tonic-gate 	     */
1780*7c478bd9Sstevel@tonic-gate 
1781*7c478bd9Sstevel@tonic-gate 	    /*
1782*7c478bd9Sstevel@tonic-gate 	     * For reference, here is the original comment about the next
1783*7c478bd9Sstevel@tonic-gate 	     * section of code.  Some of the code has changed, but the algorithm
1784*7c478bd9Sstevel@tonic-gate 	     * is the same:
1785*7c478bd9Sstevel@tonic-gate 	     *
1786*7c478bd9Sstevel@tonic-gate 	     * Open the system password file once.  This instance will be
1787*7c478bd9Sstevel@tonic-gate 	     * used to leaf through the file once, reading each entry once,
1788*7c478bd9Sstevel@tonic-gate 	     * and searching the remainder of the file for another login-ID
1789*7c478bd9Sstevel@tonic-gate 	     * that has the same user-ID.  Note that there are lots of
1790*7c478bd9Sstevel@tonic-gate 	     * contortions one has to go through when reading two instances
1791*7c478bd9Sstevel@tonic-gate 	     * of the /etc/passwd file.  That's why there's some seeking,
1792*7c478bd9Sstevel@tonic-gate 	     * re-reading of the same record, and other junk.  Luckily, this
1793*7c478bd9Sstevel@tonic-gate 	     * feature won't be requested very often, and still isn't too
1794*7c478bd9Sstevel@tonic-gate 	     * slow...
1795*7c478bd9Sstevel@tonic-gate 	     */
1796*7c478bd9Sstevel@tonic-gate 
1797*7c478bd9Sstevel@tonic-gate 	    /* For each entry in the passwd database ... */
1798*7c478bd9Sstevel@tonic-gate 	    while (plookpwd = local_getpwent()) {
1799*7c478bd9Sstevel@tonic-gate 		/*
1800*7c478bd9Sstevel@tonic-gate 		 *  Optimization -- If the login's user-ID is already in
1801*7c478bd9Sstevel@tonic-gate 		 *  the display list, there's no reason to process this
1802*7c478bd9Sstevel@tonic-gate 		 *  entry -- it's already there.
1803*7c478bd9Sstevel@tonic-gate 		 */
1804*7c478bd9Sstevel@tonic-gate  		if (!isuidindisp(plookpwd)) {
1805*7c478bd9Sstevel@tonic-gate 
1806*7c478bd9Sstevel@tonic-gate 		    /*
1807*7c478bd9Sstevel@tonic-gate 		     * Rememeber the current entry's position, so when we finish
1808*7c478bd9Sstevel@tonic-gate 		     * scanning through the database looking for duplicates
1809*7c478bd9Sstevel@tonic-gate 		     * we can return to the current place, so that the enclosing
1810*7c478bd9Sstevel@tonic-gate 		     * loop will march in an orderly fashion through the passwd
1811*7c478bd9Sstevel@tonic-gate 		     * database.
1812*7c478bd9Sstevel@tonic-gate 		     */
1813*7c478bd9Sstevel@tonic-gate 		    done = FALSE;
1814*7c478bd9Sstevel@tonic-gate 		    lookpos = local_pwtell();
1815*7c478bd9Sstevel@tonic-gate 
1816*7c478bd9Sstevel@tonic-gate 		    /*
1817*7c478bd9Sstevel@tonic-gate 		     * For each record in the passwd database beyond
1818*7c478bd9Sstevel@tonic-gate 		     * the searching record ...
1819*7c478bd9Sstevel@tonic-gate 		     */
1820*7c478bd9Sstevel@tonic-gate 		    while (pwent = local_getpwent()) {
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate 			/*
1823*7c478bd9Sstevel@tonic-gate 			 * If there's a match between the searcher's user-
1824*7c478bd9Sstevel@tonic-gate 			 * ID and the searchee's user-ID ...
1825*7c478bd9Sstevel@tonic-gate 			 */
1826*7c478bd9Sstevel@tonic-gate 			if (pwent->pw_uid == plookpwd->pw_uid) {
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate 			    /*
1829*7c478bd9Sstevel@tonic-gate 			     * If this is the first duplicate of this searcher
1830*7c478bd9Sstevel@tonic-gate 			     * that we find,
1831*7c478bd9Sstevel@tonic-gate 			     * add the searcher's record to the display list
1832*7c478bd9Sstevel@tonic-gate 			     * (It wants to be on the list first
1833*7c478bd9Sstevel@tonic-gate 			     * to avoid ordering "flakeyness")
1834*7c478bd9Sstevel@tonic-gate 			     */
1835*7c478bd9Sstevel@tonic-gate 			    if (done == FALSE) {
1836*7c478bd9Sstevel@tonic-gate 				adddisp(plookpwd);
1837*7c478bd9Sstevel@tonic-gate 				done == TRUE;
1838*7c478bd9Sstevel@tonic-gate 			    }
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 			    /*
1841*7c478bd9Sstevel@tonic-gate 			     * Now add the searchee's record
1842*7c478bd9Sstevel@tonic-gate 			     */
1843*7c478bd9Sstevel@tonic-gate 			    adddisp(pwent);
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 		    	}
1846*7c478bd9Sstevel@tonic-gate 		    }
1847*7c478bd9Sstevel@tonic-gate 		    /* Reposition to searcher record */
1848*7c478bd9Sstevel@tonic-gate 		    local_pwseek(lookpos);
1849*7c478bd9Sstevel@tonic-gate 		}
1850*7c478bd9Sstevel@tonic-gate 	    }
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate 	    local_endpwent();
1853*7c478bd9Sstevel@tonic-gate 	}
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 	/*
1857*7c478bd9Sstevel@tonic-gate 	 *  Loop through the passwd database squirelling away the
1858*7c478bd9Sstevel@tonic-gate 	 *  information we need for the display.
1859*7c478bd9Sstevel@tonic-gate 	 *
1860*7c478bd9Sstevel@tonic-gate 	 *  NOTE:  Once a login is added to the list, the rest of the
1861*7c478bd9Sstevel@tonic-gate 	 *	   body of the loop is bypassed (via a continue statement).
1862*7c478bd9Sstevel@tonic-gate 	 */
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 	doall = !(s_seen || u_seen || p_seen || d_seen || l_seen || g_seen);
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate 	if (doall || s_seen || u_seen || p_seen || l_seen || g_seen) {
1867*7c478bd9Sstevel@tonic-gate 
1868*7c478bd9Sstevel@tonic-gate 	    while (pwent = local_getpwent()) {
1869*7c478bd9Sstevel@tonic-gate 		done = FALSE;
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 		/* If no user-specific options were specified,
1872*7c478bd9Sstevel@tonic-gate 		 * include this login-ID */
1873*7c478bd9Sstevel@tonic-gate 		if (doall) {
1874*7c478bd9Sstevel@tonic-gate 		    adddisp(pwent);
1875*7c478bd9Sstevel@tonic-gate 		    continue;
1876*7c478bd9Sstevel@tonic-gate 		}
1877*7c478bd9Sstevel@tonic-gate 
1878*7c478bd9Sstevel@tonic-gate 		/* If the user specified system login-IDs,
1879*7c478bd9Sstevel@tonic-gate 		 * and this is a system ID, include it */
1880*7c478bd9Sstevel@tonic-gate 		if (s_seen) if (isasystemlogin(pwent)) {
1881*7c478bd9Sstevel@tonic-gate 		    adddisp(pwent);
1882*7c478bd9Sstevel@tonic-gate 		    continue;
1883*7c478bd9Sstevel@tonic-gate 		}
1884*7c478bd9Sstevel@tonic-gate 
1885*7c478bd9Sstevel@tonic-gate 		/* If the user specified user login-IDs,
1886*7c478bd9Sstevel@tonic-gate 		 * and this is a user ID, include it */
1887*7c478bd9Sstevel@tonic-gate 		if (u_seen) if (isauserlogin(pwent)) {
1888*7c478bd9Sstevel@tonic-gate 		    adddisp(pwent);
1889*7c478bd9Sstevel@tonic-gate 		    continue;
1890*7c478bd9Sstevel@tonic-gate 		}
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 		/* If the user is asking for login-IDs that have
1893*7c478bd9Sstevel@tonic-gate 		 * no password, and this one has no password,
1894*7c478bd9Sstevel@tonic-gate 		 * include it */
1895*7c478bd9Sstevel@tonic-gate 		if (p_seen) if (hasnopasswd(pwent)) {
1896*7c478bd9Sstevel@tonic-gate 		    adddisp(pwent);
1897*7c478bd9Sstevel@tonic-gate 		    continue;
1898*7c478bd9Sstevel@tonic-gate 		}
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate 		/*
1901*7c478bd9Sstevel@tonic-gate 		 * If specific logins were requested, leaf through
1902*7c478bd9Sstevel@tonic-gate 		 * the list of logins they requested.  If this login
1903*7c478bd9Sstevel@tonic-gate 		 * is on the list, include it.
1904*7c478bd9Sstevel@tonic-gate 		 */
1905*7c478bd9Sstevel@tonic-gate 		if (l_seen) {
1906*7c478bd9Sstevel@tonic-gate 		    for (plogin = reqloginhead ; !done && plogin ; plogin = plogin->next) {
1907*7c478bd9Sstevel@tonic-gate 			if (strcmp(pwent->pw_name, plogin->loginname) == 0) {
1908*7c478bd9Sstevel@tonic-gate 			    plogin->found = TRUE;
1909*7c478bd9Sstevel@tonic-gate 			    adddisp(pwent);
1910*7c478bd9Sstevel@tonic-gate 			    done = TRUE;
1911*7c478bd9Sstevel@tonic-gate 			}
1912*7c478bd9Sstevel@tonic-gate 		    }
1913*7c478bd9Sstevel@tonic-gate 		    if (done) continue;
1914*7c478bd9Sstevel@tonic-gate 		}
1915*7c478bd9Sstevel@tonic-gate 
1916*7c478bd9Sstevel@tonic-gate 		/*
1917*7c478bd9Sstevel@tonic-gate 		 * If specific groups were requested, leaf through the
1918*7c478bd9Sstevel@tonic-gate 		 * list of login-IDs that belong to those groups.  If this
1919*7c478bd9Sstevel@tonic-gate 		 * login-ID is in that list, or its primary group is one
1920*7c478bd9Sstevel@tonic-gate 		 * of those requested, include it.
1921*7c478bd9Sstevel@tonic-gate 		 */
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 		if (g_seen) {
1924*7c478bd9Sstevel@tonic-gate 		    for (pgrp = reqgrphead ; !done && pgrp ; pgrp = pgrp->next)
1925*7c478bd9Sstevel@tonic-gate 			if (pwent->pw_gid == pgrp->groupID) {
1926*7c478bd9Sstevel@tonic-gate 			    adddisp(pwent);
1927*7c478bd9Sstevel@tonic-gate 			    done = TRUE;
1928*7c478bd9Sstevel@tonic-gate 		    }
1929*7c478bd9Sstevel@tonic-gate 		    if (!done && isamember(pwent->pw_name)) {
1930*7c478bd9Sstevel@tonic-gate 			adddisp(pwent);
1931*7c478bd9Sstevel@tonic-gate 			done = TRUE;
1932*7c478bd9Sstevel@tonic-gate 		    }
1933*7c478bd9Sstevel@tonic-gate 		}
1934*7c478bd9Sstevel@tonic-gate 		if (done) continue;
1935*7c478bd9Sstevel@tonic-gate 	    }
1936*7c478bd9Sstevel@tonic-gate 	    local_endpwent();
1937*7c478bd9Sstevel@tonic-gate 	}
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	/* Let the user know about logins they requested that
1940*7c478bd9Sstevel@tonic-gate 	 * don't exist */
1941*7c478bd9Sstevel@tonic-gate 	if (l_seen) for (plogin = reqloginhead ; plogin ; plogin = plogin->next)
1942*7c478bd9Sstevel@tonic-gate 	    if (!plogin->found)
1943*7c478bd9Sstevel@tonic-gate 		wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, gettext("%s was not found"), plogin->loginname);
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate 	/*
1946*7c478bd9Sstevel@tonic-gate 	 *  Apply group information
1947*7c478bd9Sstevel@tonic-gate 	 */
1948*7c478bd9Sstevel@tonic-gate 	applygroup(m_seen);
1949*7c478bd9Sstevel@tonic-gate 
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 	/*
1952*7c478bd9Sstevel@tonic-gate 	 * Apply password information (only needed if the extended
1953*7c478bd9Sstevel@tonic-gate 	 * set of information has been requested)
1954*7c478bd9Sstevel@tonic-gate 	 */
1955*7c478bd9Sstevel@tonic-gate 	if (x_seen || a_seen) applypasswd();
1956*7c478bd9Sstevel@tonic-gate 
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	/*
1959*7c478bd9Sstevel@tonic-gate 	 * Generate a report from this display items we've squirreled
1960*7c478bd9Sstevel@tonic-gate 	 * away
1961*7c478bd9Sstevel@tonic-gate 	 */
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate 	if (t_seen) genlogreport(o_seen, x_seen, a_seen);
1964*7c478bd9Sstevel@tonic-gate 	else genuidreport(o_seen, x_seen, a_seen);
1965*7c478bd9Sstevel@tonic-gate 
1966*7c478bd9Sstevel@tonic-gate 	/*
1967*7c478bd9Sstevel@tonic-gate 	 *  We're through!
1968*7c478bd9Sstevel@tonic-gate 	 */
1969*7c478bd9Sstevel@tonic-gate 	exit(0);
1970*7c478bd9Sstevel@tonic-gate 
1971*7c478bd9Sstevel@tonic-gate #ifdef	lint
1972*7c478bd9Sstevel@tonic-gate 	return(0);
1973*7c478bd9Sstevel@tonic-gate #endif
1974*7c478bd9Sstevel@tonic-gate }
1975