xref: /titanic_54/usr/src/cmd/logins/logins.c (revision b816ddf83939c2b433da956720fad32dfb172096)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
2320d7339fSgww  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.15.1.2 */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * logins.c
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  *	This file contains the source for the administrative command
367c478bd9Sstevel@tonic-gate  *	"logins" (available to the administrator) that produces a report
377c478bd9Sstevel@tonic-gate  *	containing login-IDs and other requested information.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate #include <stdio.h>
4220d7339fSgww #include <stdlib.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <ctype.h>
467c478bd9Sstevel@tonic-gate #include <grp.h>
477c478bd9Sstevel@tonic-gate #include <pwd.h>
487c478bd9Sstevel@tonic-gate #include <shadow.h>
497c478bd9Sstevel@tonic-gate #include <time.h>
507c478bd9Sstevel@tonic-gate #include <stdarg.h>
517c478bd9Sstevel@tonic-gate #include <fmtmsg.h>
527c478bd9Sstevel@tonic-gate #include <locale.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  *  Local constant definitions
567c478bd9Sstevel@tonic-gate  *	TRUE			Boolean constant
577c478bd9Sstevel@tonic-gate  *	FALSE			Boolean constant
587c478bd9Sstevel@tonic-gate  *	USAGE_MSG		Message used to display a usage error
597c478bd9Sstevel@tonic-gate  *	MAXLOGINSIZE		Maximum length of a valid login-ID
607c478bd9Sstevel@tonic-gate  *	MAXSYSTEMLOGIN		Maximum value of a system user-ID.
617c478bd9Sstevel@tonic-gate  *	OPTSTR			Options to this command
627c478bd9Sstevel@tonic-gate  *	ROOT_ID			The user-ID of an administrator
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #ifndef	FALSE
667c478bd9Sstevel@tonic-gate #define	FALSE			0
677c478bd9Sstevel@tonic-gate #endif
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #ifndef	TRUE
707c478bd9Sstevel@tonic-gate #define	TRUE			((int)'t')
717c478bd9Sstevel@tonic-gate #endif
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	USAGE_MSG	"usage: logins [-admopstux] [-g groups] [-l logins]"
747c478bd9Sstevel@tonic-gate #define	MAXLOGINSIZE	14
757c478bd9Sstevel@tonic-gate #define	MAXSYSTEMLOGIN	99
767c478bd9Sstevel@tonic-gate #define	OPTSTR		"adg:l:mopstux"
777c478bd9Sstevel@tonic-gate #define	ROOT_ID		0
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  *  The following macros do their function for now but will probably have
817c478bd9Sstevel@tonic-gate  *  to be replaced by functions sometime in the near future.  The maximum
827c478bd9Sstevel@tonic-gate  *  system login value may someday be administerable, in which case these
837c478bd9Sstevel@tonic-gate  *  will have to be changed to become functions
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  *	isasystemlogin	Returns TRUE if the user-ID in the "struct passwd"
867c478bd9Sstevel@tonic-gate  *			structure referenced by the function's argument is
877c478bd9Sstevel@tonic-gate  *			less than or equal to the maximum value for a system
887c478bd9Sstevel@tonic-gate  *			user-ID, FALSE otherwise.
897c478bd9Sstevel@tonic-gate  *	isauserlogin	Returns TRUE if the user-ID in the "struct passwd"
907c478bd9Sstevel@tonic-gate  *			structure referenced by the function's argument is
917c478bd9Sstevel@tonic-gate  *			greater than the maximum value for a system user-ID,
927c478bd9Sstevel@tonic-gate  *			FALSE otherwise.
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	isauserlogin(pw)	(pw->pw_uid > MAXSYSTEMLOGIN)
967c478bd9Sstevel@tonic-gate #define	isasystemlogin(pw)	(pw->pw_uid <= MAXSYSTEMLOGIN)
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  *  Local datatype definitions
1017c478bd9Sstevel@tonic-gate  *	struct reqgrp		Describes a group as requested through the
1027c478bd9Sstevel@tonic-gate  *				-g option
1037c478bd9Sstevel@tonic-gate  *	struct reqlogin		Describes a login-ID as requested through
1047c478bd9Sstevel@tonic-gate  *				the -l option
1057c478bd9Sstevel@tonic-gate  *	struct pwdinfo		Describes a password's aging information,
1067c478bd9Sstevel@tonic-gate  *				as extracted from /etc/shadow
1077c478bd9Sstevel@tonic-gate  *	struct secgrp		Describes a login-ID's secondary group
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*  Describes a specified group name (from the -g groups option)  */
1117c478bd9Sstevel@tonic-gate struct	reqgrp {
1127c478bd9Sstevel@tonic-gate 	char		*groupname;	/* Requested group name */
1137c478bd9Sstevel@tonic-gate 	struct reqgrp	*next;		/* Next item in the list */
1147c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group's ID */
1157c478bd9Sstevel@tonic-gate };
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /*  Describes a specified login name (from the -l logins option)  */
1187c478bd9Sstevel@tonic-gate struct	reqlogin {
1197c478bd9Sstevel@tonic-gate 	char		*loginname;	/* Requested login name */
1207c478bd9Sstevel@tonic-gate 	struct reqlogin	*next;		/* Next item in the list */
1217c478bd9Sstevel@tonic-gate 	int		found;		/* TRUE if login in /etc/passwd */
1227c478bd9Sstevel@tonic-gate };
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * This structure describes a password's information
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate struct	pwdinfo {
1297c478bd9Sstevel@tonic-gate 	long	datechg;	/* Date the password was changed (mmddyy) */
1307c478bd9Sstevel@tonic-gate 	char	*passwdstatus;	/* Password status */
1317c478bd9Sstevel@tonic-gate 	long	mindaystilchg;	/* Min days b4 pwd can change again */
1327c478bd9Sstevel@tonic-gate 	long	maxdaystilchg;	/* Max days b4 pwd can change again */
1337c478bd9Sstevel@tonic-gate 	long	warninterval;	/* Days before expire to warn user */
1347c478bd9Sstevel@tonic-gate 	long	inactive;	/* Lapsed days of inactivity before lock */
1357c478bd9Sstevel@tonic-gate 	long	expdate;	/* Date of expiration (mmddyy) */
1367c478bd9Sstevel@tonic-gate };
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /* This structure describes secondary groups that a user belongs to */
1397c478bd9Sstevel@tonic-gate struct	secgrp {
1407c478bd9Sstevel@tonic-gate 	char		*groupname;	/* Name of the group */
1417c478bd9Sstevel@tonic-gate 	struct secgrp	*next;		/* Next item in the list */
1427c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group-ID */
1437c478bd9Sstevel@tonic-gate };
14420d7339fSgww 
14520d7339fSgww 
1467c478bd9Sstevel@tonic-gate /*
1477c478bd9Sstevel@tonic-gate  *  These functions handle error and warning message writing.
1487c478bd9Sstevel@tonic-gate  *  (This deals with UNIX(r) standard message generation, so
1497c478bd9Sstevel@tonic-gate  *  the rest of the code doesn't have to.)
1507c478bd9Sstevel@tonic-gate  *
1517c478bd9Sstevel@tonic-gate  *  Functions included:
1527c478bd9Sstevel@tonic-gate  *	initmsg		Initialize the message handling functions.
1537c478bd9Sstevel@tonic-gate  *	wrtmsg		Write the message using fmtmsg().
1547c478bd9Sstevel@tonic-gate  *
1557c478bd9Sstevel@tonic-gate  *  Static data included:
1567c478bd9Sstevel@tonic-gate  *	fcnlbl		The label for standard messages
1577c478bd9Sstevel@tonic-gate  *	msgbuf		A buffer to contain the edited message
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate static	char	fcnlbl[MM_MXLABELLN+1];	/* Buffer for message label */
1617c478bd9Sstevel@tonic-gate static	char	msgbuf[MM_MXTXTLN+1];	/* Buffer for message text */
16220d7339fSgww 
16320d7339fSgww 
1647c478bd9Sstevel@tonic-gate /*
1657c478bd9Sstevel@tonic-gate  * void initmsg(p)
1667c478bd9Sstevel@tonic-gate  *
1677c478bd9Sstevel@tonic-gate  *	This function initializes the message handling functions.
1687c478bd9Sstevel@tonic-gate  *
1697c478bd9Sstevel@tonic-gate  *  Arguments:
1707c478bd9Sstevel@tonic-gate  *	p	A pointer to a character string that is the name of the
1717c478bd9Sstevel@tonic-gate  *		function, used to generate the label on messages.  If this
1727c478bd9Sstevel@tonic-gate  *		string contains a slash ('/'), it only uses the characters
1737c478bd9Sstevel@tonic-gate  *		beyond the last slash in the string (this permits argv[0]
1747c478bd9Sstevel@tonic-gate  *		to be used).
1757c478bd9Sstevel@tonic-gate  *
1767c478bd9Sstevel@tonic-gate  *  Returns:  Void
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate static void
18020d7339fSgww initmsg(char *p)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	char   *q;	/* Local multi-use pointer */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* Use only the simple filename if there is a slash in the name */
18520d7339fSgww 	if (!(q = strrchr(p, '/'))) {
18620d7339fSgww 		q = p;
18720d7339fSgww 	} else {
18820d7339fSgww 		q++;
18920d7339fSgww 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/* Build the label for messages */
19220d7339fSgww 	(void) snprintf(fcnlbl, MM_MXLABELLN, "UX:%s", q);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/* Restrict messages to the text-component */
1957c478bd9Sstevel@tonic-gate 	(void) putenv("MSGVERB=text");
1967c478bd9Sstevel@tonic-gate }
19720d7339fSgww 
19820d7339fSgww 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  *  void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
2017c478bd9Sstevel@tonic-gate  *
2027c478bd9Sstevel@tonic-gate  *	This function writes a message using fmtmsg()
2037c478bd9Sstevel@tonic-gate  *
2047c478bd9Sstevel@tonic-gate  *  Arguments:
2057c478bd9Sstevel@tonic-gate  *	severity	The severity-component of the message
2067c478bd9Sstevel@tonic-gate  *	action		The action-string used to generate the
2077c478bd9Sstevel@tonic-gate  *			action-component of the message
2087c478bd9Sstevel@tonic-gate  *	tag		Tag-component of the message
2097c478bd9Sstevel@tonic-gate  *	text		The text-string used to generate the text-
2107c478bd9Sstevel@tonic-gate  *			component of the message
2117c478bd9Sstevel@tonic-gate  *	txtarg		Arguments to be inserted into the "text"
2127c478bd9Sstevel@tonic-gate  *			string using vsprintf()
2137c478bd9Sstevel@tonic-gate  *
2147c478bd9Sstevel@tonic-gate  *  Returns:  Void
2157c478bd9Sstevel@tonic-gate  */
21620d7339fSgww /*PRINTFLIKE4*/
2177c478bd9Sstevel@tonic-gate static void
2187c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	int	errorflg;	/* TRUE if problem generating message */
2217c478bd9Sstevel@tonic-gate 	va_list	argp;		/* Pointer into vararg list */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/* No problems yet */
2257c478bd9Sstevel@tonic-gate 	errorflg = FALSE;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/* Generate the error message */
2287c478bd9Sstevel@tonic-gate 	va_start(argp, text);
22920d7339fSgww 	if (text != MM_NULLTXT) {
23020d7339fSgww 		errorflg = vsnprintf(msgbuf,
23120d7339fSgww 		    MM_MXTXTLN, text, argp) > MM_MXTXTLN;
23220d7339fSgww 	}
2337c478bd9Sstevel@tonic-gate 	(void) fmtmsg(MM_PRINT, fcnlbl, severity,
23420d7339fSgww 	    (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf, action, tag);
2357c478bd9Sstevel@tonic-gate 	va_end(argp);
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/*
2387c478bd9Sstevel@tonic-gate 	 *  If there was a buffer overflow generating the error message,
2397c478bd9Sstevel@tonic-gate 	 *  write a message and quit (things are probably corrupt in the
2407c478bd9Sstevel@tonic-gate 	 *  static data space now
2417c478bd9Sstevel@tonic-gate 	 */
2427c478bd9Sstevel@tonic-gate 	if (errorflg) {
2437c478bd9Sstevel@tonic-gate 		(void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
2447c478bd9Sstevel@tonic-gate 		    gettext("Internal message buffer overflow"),
2457c478bd9Sstevel@tonic-gate 		    MM_NULLACT, MM_NULLTAG);
2467c478bd9Sstevel@tonic-gate 		exit(100);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate }
24920d7339fSgww 
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate  *  These functions control the group membership list, as found in
2527c478bd9Sstevel@tonic-gate  *  the /etc/group file.
2537c478bd9Sstevel@tonic-gate  *
2547c478bd9Sstevel@tonic-gate  *  Functions included:
2557c478bd9Sstevel@tonic-gate  *	addmember		Adds a member to the membership list
2567c478bd9Sstevel@tonic-gate  *	isamember		Looks for a particular login-ID in the
2577c478bd9Sstevel@tonic-gate  *				list of members
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  *  Datatype Definitions:
2607c478bd9Sstevel@tonic-gate  *	struct grpmember	Describes a group member
2617c478bd9Sstevel@tonic-gate  *
2627c478bd9Sstevel@tonic-gate  *  Static Data:
2637c478bd9Sstevel@tonic-gate  *	membershead		Pointer to the head of the list of
2647c478bd9Sstevel@tonic-gate  *				group members
2657c478bd9Sstevel@tonic-gate  */
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate struct	grpmember {
2687c478bd9Sstevel@tonic-gate 	char			*membername;
2697c478bd9Sstevel@tonic-gate 	struct grpmember	*next;
2707c478bd9Sstevel@tonic-gate };
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate static	struct grpmember	*membershead;
27320d7339fSgww 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  *  void addmember(p)
2767c478bd9Sstevel@tonic-gate  *	char   *p
2777c478bd9Sstevel@tonic-gate  *
2787c478bd9Sstevel@tonic-gate  *	This function adds a member to the group member's list.  The
2797c478bd9Sstevel@tonic-gate  *	group members list is a list of structures containing a pointer
2807c478bd9Sstevel@tonic-gate  *	to the member-name and a pointer to the next item in the
2817c478bd9Sstevel@tonic-gate  *	structure.  The structure is not ordered in any particular way.
2827c478bd9Sstevel@tonic-gate  *
2837c478bd9Sstevel@tonic-gate  *  Arguments:
2847c478bd9Sstevel@tonic-gate  *	p	Pointer to the member name
2857c478bd9Sstevel@tonic-gate  *
2867c478bd9Sstevel@tonic-gate  *  Returns:  Void
2877c478bd9Sstevel@tonic-gate  */
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static void
29020d7339fSgww addmember(char *p)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	struct grpmember	*new;	/* Member being added */
2937c478bd9Sstevel@tonic-gate 
294*b816ddf8Sgww 	new = malloc(sizeof (struct grpmember));
295*b816ddf8Sgww 	new->membername = strdup(p);
2967c478bd9Sstevel@tonic-gate 	new->next = membershead;
2977c478bd9Sstevel@tonic-gate 	membershead = new;
2987c478bd9Sstevel@tonic-gate }
29920d7339fSgww 
30020d7339fSgww 
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate  *  init isamember(p)
3037c478bd9Sstevel@tonic-gate  *	char   *p
3047c478bd9Sstevel@tonic-gate  *
3057c478bd9Sstevel@tonic-gate  *	This function examines the list of group-members for the string
3067c478bd9Sstevel@tonic-gate  *	referenced by 'p'.  If 'p' is a member of the members list, the
3077c478bd9Sstevel@tonic-gate  *	function returns TRUE.  Otherwise it returns FALSE.
3087c478bd9Sstevel@tonic-gate  *
3097c478bd9Sstevel@tonic-gate  *  Arguments:
3107c478bd9Sstevel@tonic-gate  *	p	Pointer to the name to search for.
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  *  Returns:  int
3137c478bd9Sstevel@tonic-gate  *	TRUE	If 'p' is found in the members list,
3147c478bd9Sstevel@tonic-gate  *	FALSE	otherwise
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate static int
31820d7339fSgww isamember(char *p)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	int			found;	/* TRUE if login found in list */
3217c478bd9Sstevel@tonic-gate 	struct grpmember	*pmem;	/* Group member being examined */
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/* Search the membership list for 'p' */
3257c478bd9Sstevel@tonic-gate 	found = FALSE;
3267c478bd9Sstevel@tonic-gate 	for (pmem = membershead; !found && pmem; pmem = pmem->next) {
32720d7339fSgww 		if (strcmp(p, pmem->membername) == 0)
32820d7339fSgww 			found = TRUE;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	return (found);
3327c478bd9Sstevel@tonic-gate }
33320d7339fSgww 
33420d7339fSgww 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  *  These functions handle the display list.  The display list contains
3377c478bd9Sstevel@tonic-gate  *  all of the information we're to display.  The list contains a pointer
3387c478bd9Sstevel@tonic-gate  *  to the login-name, a pointer to the free-field (comment), and a
3397c478bd9Sstevel@tonic-gate  *  pointer to the next item in the list.  The list is ordered alpha-
3407c478bd9Sstevel@tonic-gate  *  betically (ascending) on the login-name field.  The list initially
3417c478bd9Sstevel@tonic-gate  *  contains a dummy field (to make insertion easier) that contains a
3427c478bd9Sstevel@tonic-gate  *  login-name of "".
3437c478bd9Sstevel@tonic-gate  *
3447c478bd9Sstevel@tonic-gate  *  Functions included:
3457c478bd9Sstevel@tonic-gate  *	initdisp	Initializes the display list
3467c478bd9Sstevel@tonic-gate  *	adddisp		Adds information to the display list
3477c478bd9Sstevel@tonic-gate  *	isuidindisp	Looks to see if a particular user-ID is in the
3487c478bd9Sstevel@tonic-gate  *			display list
3497c478bd9Sstevel@tonic-gate  *	genreport	Generates a report from the items in the display
3507c478bd9Sstevel@tonic-gate  *			list
3517c478bd9Sstevel@tonic-gate  *	applygroup	Add group information to the items in the display
3527c478bd9Sstevel@tonic-gate  *			list
3537c478bd9Sstevel@tonic-gate  *	applypasswd	Add extended password information to the items
3547c478bd9Sstevel@tonic-gate  *			in the display list
3557c478bd9Sstevel@tonic-gate  *
3567c478bd9Sstevel@tonic-gate  *  Datatypes Defined:
3577c478bd9Sstevel@tonic-gate  *	struct display	Describes the structure that contains the information
3587c478bd9Sstevel@tonic-gate  *			to be displayed.  Includes pointers to the login-ID,
3597c478bd9Sstevel@tonic-gate  *			free-field (comment), and the next structure in the
3607c478bd9Sstevel@tonic-gate  *			list.
3617c478bd9Sstevel@tonic-gate  *
3627c478bd9Sstevel@tonic-gate  *  Static Data:
3637c478bd9Sstevel@tonic-gate  *	displayhead	Pointer to the head of the display list.  Initially
3647c478bd9Sstevel@tonic-gate  *			references the null-item on the head of the list.
3657c478bd9Sstevel@tonic-gate  */
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate struct	display {
3687c478bd9Sstevel@tonic-gate 	char		*loginID;	/* Login name */
3697c478bd9Sstevel@tonic-gate 	char		*freefield;	/* Free (comment) field */
3707c478bd9Sstevel@tonic-gate 	char		*groupname;	/* Name of the primary group */
3717c478bd9Sstevel@tonic-gate 	char		*iwd;		/* Initial working directory */
3727c478bd9Sstevel@tonic-gate 	char		*shell;		/* Shell after login (may be null) */
3737c478bd9Sstevel@tonic-gate 	struct pwdinfo	*passwdinfo;	/* Password information structure */
3747c478bd9Sstevel@tonic-gate 	struct secgrp 	*secgrplist; 	/* Head of the secondary group list */
3757c478bd9Sstevel@tonic-gate 	uid_t		userID;		/* User ID */
3767c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group ID of primary group */
3777c478bd9Sstevel@tonic-gate 	struct display	*nextlogin;	/* Next login in the list */
3787c478bd9Sstevel@tonic-gate 	struct display	*nextuid;	/* Next user-ID in the list */
3797c478bd9Sstevel@tonic-gate };
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate static	struct display	*displayhead;
38220d7339fSgww 
38320d7339fSgww 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  *  void initdisp()
3867c478bd9Sstevel@tonic-gate  *
3877c478bd9Sstevel@tonic-gate  *	Initializes the display list.  An empty display list contains
3887c478bd9Sstevel@tonic-gate  *	a single element, the dummy element.
3897c478bd9Sstevel@tonic-gate  *
3907c478bd9Sstevel@tonic-gate  *  Arguments:  None
3917c478bd9Sstevel@tonic-gate  *
3927c478bd9Sstevel@tonic-gate  *  Returns:  Void
3937c478bd9Sstevel@tonic-gate  */
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate static void
39620d7339fSgww initdisp(void)
3977c478bd9Sstevel@tonic-gate {
398*b816ddf8Sgww 	displayhead = malloc(sizeof (struct display));
39920d7339fSgww 	displayhead->nextlogin = NULL;
40020d7339fSgww 	displayhead->nextuid = NULL;
4017c478bd9Sstevel@tonic-gate 	displayhead->loginID = "";
4027c478bd9Sstevel@tonic-gate 	displayhead->freefield = "";
4037c478bd9Sstevel@tonic-gate 	displayhead->userID = -1;
4047c478bd9Sstevel@tonic-gate }
40520d7339fSgww 
40620d7339fSgww 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  *  void adddisp(pwent)
4097c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
4107c478bd9Sstevel@tonic-gate  *
4117c478bd9Sstevel@tonic-gate  *	This function adds the appropriate information from the login
4127c478bd9Sstevel@tonic-gate  *	description referenced by 'pwent' to the list if information
4137c478bd9Sstevel@tonic-gate  *	to be displayed.  It only adds the information if the login-ID
4147c478bd9Sstevel@tonic-gate  *	(user-name) is unique.  It inserts the information in the list
4157c478bd9Sstevel@tonic-gate  *	in such a way that the list remains ordered alphabetically
4167c478bd9Sstevel@tonic-gate  *	(ascending) according to the login-ID (user-name).
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  *  Arguments:
4197c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains all of the login information
4207c478bd9Sstevel@tonic-gate  *			of the login being added to the list.  The only
4217c478bd9Sstevel@tonic-gate  *			information that this function uses is the login-ID
4227c478bd9Sstevel@tonic-gate  *			(user-name) and the free-field (comment field).
4237c478bd9Sstevel@tonic-gate  *
4247c478bd9Sstevel@tonic-gate  *  Returns:  Void
4257c478bd9Sstevel@tonic-gate  */
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate static void
42820d7339fSgww adddisp(struct passwd *pwent)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	struct display *new;		/* Item being added to the list */
4317c478bd9Sstevel@tonic-gate 	struct display *prev;		/* Previous item in the list */
4327c478bd9Sstevel@tonic-gate 	struct display *current;	/* Next item in the list */
4337c478bd9Sstevel@tonic-gate 	int		found;		/* FLAG, insertion point found */
4347c478bd9Sstevel@tonic-gate 	int		compare = 1;	/* strcmp() compare value */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/* Find where this value belongs in the list */
4387c478bd9Sstevel@tonic-gate 	prev = displayhead;
4397c478bd9Sstevel@tonic-gate 	found = FALSE;
44020d7339fSgww 	while (!found && (current = prev->nextlogin)) {
44120d7339fSgww 		if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) {
44220d7339fSgww 			found = TRUE;
44320d7339fSgww 		} else {
44420d7339fSgww 			prev = current;
44520d7339fSgww 		}
4467c478bd9Sstevel@tonic-gate 
44720d7339fSgww 	}
4487c478bd9Sstevel@tonic-gate 	/* Insert this value in the list, only if it is unique though */
4497c478bd9Sstevel@tonic-gate 	if (compare != 0) {
450*b816ddf8Sgww 		new = malloc(sizeof (struct display));
451*b816ddf8Sgww 		new->loginID = strdup(pwent->pw_name);
45220d7339fSgww 		if (pwent->pw_comment && pwent->pw_comment[0] != '\0') {
453*b816ddf8Sgww 			new->freefield = strdup(pwent->pw_comment);
45420d7339fSgww 		} else {
455*b816ddf8Sgww 		    new->freefield = strdup(pwent->pw_gecos);
45620d7339fSgww 		}
45720d7339fSgww 		if (!pwent->pw_shell || !(*pwent->pw_shell)) {
45820d7339fSgww 			new->shell = "/sbin/sh";
45920d7339fSgww 		} else {
460*b816ddf8Sgww 			new->shell = strdup(pwent->pw_shell);
46120d7339fSgww 		}
462*b816ddf8Sgww 		new->iwd = strdup(pwent->pw_dir);
4637c478bd9Sstevel@tonic-gate 		new->userID = pwent->pw_uid;
4647c478bd9Sstevel@tonic-gate 		new->groupID = pwent->pw_gid;
46520d7339fSgww 		new->secgrplist = NULL;
46620d7339fSgww 		new->passwdinfo = NULL;
46720d7339fSgww 		new->groupname = NULL;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		/* Add new display item to the list ordered by login-ID */
4707c478bd9Sstevel@tonic-gate 		new->nextlogin = current;
4717c478bd9Sstevel@tonic-gate 		prev->nextlogin = new;
4727c478bd9Sstevel@tonic-gate 
47320d7339fSgww 		/*
47420d7339fSgww 		 * Find the appropriate place for the new item in the list
47520d7339fSgww 		 * ordered by userID
47620d7339fSgww 		 */
4777c478bd9Sstevel@tonic-gate 		prev = displayhead;
4787c478bd9Sstevel@tonic-gate 		found = FALSE;
47920d7339fSgww 		while (!found && (current = prev->nextuid)) {
48020d7339fSgww 			if (current->userID > pwent->pw_uid) {
48120d7339fSgww 				found = TRUE;
48220d7339fSgww 			} else {
48320d7339fSgww 				prev = current;
48420d7339fSgww 			}
48520d7339fSgww 		}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		/* Add the item into the list that is ordered by user-ID */
4887c478bd9Sstevel@tonic-gate 		new->nextuid = current;
4897c478bd9Sstevel@tonic-gate 		prev->nextuid = new;
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate }
49220d7339fSgww 
49320d7339fSgww 
4947c478bd9Sstevel@tonic-gate /*
4957c478bd9Sstevel@tonic-gate  *  int isuidindisp(pwent)
4967c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
4977c478bd9Sstevel@tonic-gate  *
4987c478bd9Sstevel@tonic-gate  *  This function examines the display list to see if the uid in
4997c478bd9Sstevel@tonic-gate  *  the (struct passwd) referenced by "pwent" is already in the
5007c478bd9Sstevel@tonic-gate  *  display list.  It returns TRUE if it is in the list, FALSE
5017c478bd9Sstevel@tonic-gate  *  otherwise.
5027c478bd9Sstevel@tonic-gate  *
5037c478bd9Sstevel@tonic-gate  *  Since the display list is ordered by user-ID, the search continues
5047c478bd9Sstevel@tonic-gate  *  until a match is found or a user-ID is found that is larger than
5057c478bd9Sstevel@tonic-gate  *  the one we're searching for.
5067c478bd9Sstevel@tonic-gate  *
5077c478bd9Sstevel@tonic-gate  *  Arguments:
5087c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains the user-ID we're to
5097c478bd9Sstevel@tonic-gate  *			look for
5107c478bd9Sstevel@tonic-gate  *
5117c478bd9Sstevel@tonic-gate  *  Returns:  int
5127c478bd9Sstevel@tonic-gate  *	TRUE if the user-ID was found, FALSE otherwise.
5137c478bd9Sstevel@tonic-gate  */
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate static int
51620d7339fSgww isuidindisp(struct passwd *pwent)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	struct display *dp;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 *  Search the list, beginning at the beginning (where else?)
5237c478bd9Sstevel@tonic-gate 	 *  and stopping when the user-ID is found or one is found that
5247c478bd9Sstevel@tonic-gate 	 *  is greater than the user-ID we're searching for.  Recall
5257c478bd9Sstevel@tonic-gate 	 *  that this list is ordered by user-ID
5267c478bd9Sstevel@tonic-gate 	 */
5277c478bd9Sstevel@tonic-gate 
52820d7339fSgww 	for (dp = displayhead->nextuid; dp && (dp->userID < pwent->pw_uid);
52920d7339fSgww 	    dp = dp->nextuid) {
53020d7339fSgww 		continue;
53120d7339fSgww 	}
5327c478bd9Sstevel@tonic-gate 
53320d7339fSgww 	/*
53420d7339fSgww 	 * If the pointer "dp" points to a structure that has a
53520d7339fSgww 	 * matching user-ID, return TRUE.  Otherwise FALSE
53620d7339fSgww 	 */
5377c478bd9Sstevel@tonic-gate 	return (dp && (dp->userID == pwent->pw_uid));
5387c478bd9Sstevel@tonic-gate }
53920d7339fSgww 
54020d7339fSgww 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  *  void applygroup(allgroups)
5437c478bd9Sstevel@tonic-gate  *	int	allgroups
5447c478bd9Sstevel@tonic-gate  *
5457c478bd9Sstevel@tonic-gate  *  This function applies group information to the login-IDs in the
5467c478bd9Sstevel@tonic-gate  *  display list.  It always applies the primary group information.
5477c478bd9Sstevel@tonic-gate  *  If "allgroups" is TRUE, it applies secondary information as well.
5487c478bd9Sstevel@tonic-gate  *
5497c478bd9Sstevel@tonic-gate  *  Arguments:
5507c478bd9Sstevel@tonic-gate  * 	allgroups	FLAG.  TRUE if secondary group info is to be
5517c478bd9Sstevel@tonic-gate  *			applied -- FALSE otherwise.
5527c478bd9Sstevel@tonic-gate  *
5537c478bd9Sstevel@tonic-gate  *  Returns:  void
5547c478bd9Sstevel@tonic-gate  */
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate static void
55720d7339fSgww applygroup(int allgroups)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	struct display	*dp;		/* Display list running ptr */
5607c478bd9Sstevel@tonic-gate 	struct group	*grent;		/* Group info, from getgrent() */
5617c478bd9Sstevel@tonic-gate 	char		*p;		/* Temp char pointer */
5627c478bd9Sstevel@tonic-gate 	char		**pp;		/* Temp char * pointer */
5637c478bd9Sstevel@tonic-gate 	int		compare;	/* Value from strcmp() */
5647c478bd9Sstevel@tonic-gate 	int		done;		/* TRUE if finished, FALSE otherwise */
5657c478bd9Sstevel@tonic-gate 	struct secgrp	*psecgrp;	/* Block allocated for this info */
5667c478bd9Sstevel@tonic-gate 	struct secgrp	*psrch;		/* Secondary group -- for searching */
5677c478bd9Sstevel@tonic-gate 
568*b816ddf8Sgww 	if (!allgroups) {
569*b816ddf8Sgww 		/* short circute getting all the groups */
570*b816ddf8Sgww 		for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
571*b816ddf8Sgww 			if ((grent = getgrgid(dp->groupID)) != NULL) {
572*b816ddf8Sgww 				dp->groupname = strdup(grent->gr_name);
573*b816ddf8Sgww 			}
574*b816ddf8Sgww 		}
575*b816ddf8Sgww 		return;
576*b816ddf8Sgww 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/* For each group-ID in the /etc/group file ... */
5797c478bd9Sstevel@tonic-gate 	while (grent = getgrent()) {
5807c478bd9Sstevel@tonic-gate 		/*
5817c478bd9Sstevel@tonic-gate 		 *  Set the primary group for the login-IDs in the display
5827c478bd9Sstevel@tonic-gate 		 *  list.  For each group-ID we get, leaf through the display
5837c478bd9Sstevel@tonic-gate 		 *  list and set the group-name if the group-IDs match
5847c478bd9Sstevel@tonic-gate 		 */
5857c478bd9Sstevel@tonic-gate 
58620d7339fSgww 		p = NULL;
58720d7339fSgww 		for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
5887c478bd9Sstevel@tonic-gate 			if ((dp->groupID == grent->gr_gid) && !dp->groupname) {
58920d7339fSgww 				if (!p) {
590*b816ddf8Sgww 					p = strdup(grent->gr_name);
59120d7339fSgww 				}
5927c478bd9Sstevel@tonic-gate 				dp->groupname = p;
5937c478bd9Sstevel@tonic-gate 			}
59420d7339fSgww 		}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 *  If we're to be displaying secondary group membership,
5987c478bd9Sstevel@tonic-gate 		 *  leaf through the list of group members.  Then, attempt
5997c478bd9Sstevel@tonic-gate 		 *  to find that member in the display list.  When found,
6007c478bd9Sstevel@tonic-gate 		 *  attach secondary group info to the user.
6017c478bd9Sstevel@tonic-gate 		 */
6027c478bd9Sstevel@tonic-gate 
60320d7339fSgww 		for (pp = grent->gr_mem; *pp; pp++) {
6047c478bd9Sstevel@tonic-gate 			done = FALSE;
60520d7339fSgww 			for (dp = displayhead->nextlogin; !done && dp;
60620d7339fSgww 			    dp = dp->nextlogin) {
60720d7339fSgww 				if (((compare = strcmp(dp->loginID,
60820d7339fSgww 				    *pp)) == 0) &&
60920d7339fSgww 				    !(grent->gr_gid == dp->groupID)) {
61020d7339fSgww 					if (!p) {
611*b816ddf8Sgww 						p = strdup(grent->gr_name);
61220d7339fSgww 					}
613*b816ddf8Sgww 					psecgrp = malloc(
61420d7339fSgww 					    sizeof (struct secgrp));
6157c478bd9Sstevel@tonic-gate 					psecgrp->groupID = grent->gr_gid;
6167c478bd9Sstevel@tonic-gate 					psecgrp->groupname = p;
61720d7339fSgww 					psecgrp->next = NULL;
61820d7339fSgww 					if (!dp->secgrplist) {
61920d7339fSgww 						dp->secgrplist = psecgrp;
62020d7339fSgww 					} else {
62120d7339fSgww 						for (psrch = dp->secgrplist;
62220d7339fSgww 						    psrch->next;
62320d7339fSgww 						    psrch = psrch->next) {
62420d7339fSgww 							continue;
62520d7339fSgww 						}
6267c478bd9Sstevel@tonic-gate 						psrch->next = psecgrp;
6277c478bd9Sstevel@tonic-gate 					}
6287c478bd9Sstevel@tonic-gate 					done = TRUE;
62920d7339fSgww 				} else if (compare > 0) {
63020d7339fSgww 						done = TRUE;
6317c478bd9Sstevel@tonic-gate 				}
6327c478bd9Sstevel@tonic-gate 			}
6337c478bd9Sstevel@tonic-gate 		}
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/* Close the /etc/group file */
6377c478bd9Sstevel@tonic-gate 	endgrent();
6387c478bd9Sstevel@tonic-gate }
63920d7339fSgww 
64020d7339fSgww 
6417c478bd9Sstevel@tonic-gate /*
6427c478bd9Sstevel@tonic-gate  *  void applypasswd()
6437c478bd9Sstevel@tonic-gate  *
6447c478bd9Sstevel@tonic-gate  *	This function applies extended password information to an item
6457c478bd9Sstevel@tonic-gate  *	to be displayed.  It allocates space for a structure describing
6467c478bd9Sstevel@tonic-gate  *	the password, then fills in that structure from the information
6477c478bd9Sstevel@tonic-gate  *	in the /etc/shadow file.
6487c478bd9Sstevel@tonic-gate  *
6497c478bd9Sstevel@tonic-gate  *  Arguments:  None
6507c478bd9Sstevel@tonic-gate  *
6517c478bd9Sstevel@tonic-gate  *  Returns:  Void
6527c478bd9Sstevel@tonic-gate  */
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate static void
65520d7339fSgww applypasswd(void)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	struct pwdinfo	*ppasswd;	/* Ptr to pwd desc in current element */
6587c478bd9Sstevel@tonic-gate 	struct display	*dp;		/* Ptr to current element */
6597c478bd9Sstevel@tonic-gate 	struct spwd	*psp;		/* Pointer to a shadow-file entry */
6607c478bd9Sstevel@tonic-gate 	struct tm	*ptm;		/* Pointer to a time-of-day structure */
6617c478bd9Sstevel@tonic-gate 	time_t		pwchg;		/* System-time of last pwd chg */
6627c478bd9Sstevel@tonic-gate 	time_t		pwexp;		/* System-time of password expiration */
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/*  Make sure the shadow file is rewound  */
6667c478bd9Sstevel@tonic-gate 	setspent();
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	/*
6707c478bd9Sstevel@tonic-gate 	 *  For each item in the display list...
6717c478bd9Sstevel@tonic-gate 	 */
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 		/* Allocate structure space for the password description */
676*b816ddf8Sgww 		ppasswd = malloc(sizeof (struct pwdinfo));
6777c478bd9Sstevel@tonic-gate 		dp->passwdinfo = ppasswd;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 		/*
6807c478bd9Sstevel@tonic-gate 		 * If there's no entry in the /etc/shadow file, assume
6817c478bd9Sstevel@tonic-gate 		 * that the login is locked
6827c478bd9Sstevel@tonic-gate 		 */
6837c478bd9Sstevel@tonic-gate 
684*b816ddf8Sgww 		if ((psp = getspnam(dp->loginID)) == NULL) {
6857c478bd9Sstevel@tonic-gate 			pwchg = 0L;			/* Epoch */
6867c478bd9Sstevel@tonic-gate 			ppasswd->passwdstatus = "LK";	/* LK, Locked */
6877c478bd9Sstevel@tonic-gate 			ppasswd->mindaystilchg = 0L;
6887c478bd9Sstevel@tonic-gate 			ppasswd->maxdaystilchg = 0L;
6897c478bd9Sstevel@tonic-gate 			ppasswd->warninterval = 0L;
6907c478bd9Sstevel@tonic-gate 			ppasswd->inactive = 0L;
6917c478bd9Sstevel@tonic-gate 			pwexp = 0L;
69220d7339fSgww 		} else {
6937c478bd9Sstevel@tonic-gate 			/*
6947c478bd9Sstevel@tonic-gate 			 * Otherwise, fill in the password information from the
695*b816ddf8Sgww 			 * info in the shadow entry
6967c478bd9Sstevel@tonic-gate 			 */
697*b816ddf8Sgww 			if (psp->sp_pwdp == NULL || (*psp->sp_pwdp) == '\0')
69820d7339fSgww 				ppasswd->passwdstatus = "NP";
699*b816ddf8Sgww 			else if (strncmp(psp->sp_pwdp, LOCKSTRING,
700*b816ddf8Sgww 			    sizeof (LOCKSTRING)-1) == 0)
70120d7339fSgww 				ppasswd->passwdstatus = "LK";
702*b816ddf8Sgww 			else if (strncmp(psp->sp_pwdp, NOLOGINSTRING,
703*b816ddf8Sgww 			    sizeof (NOLOGINSTRING)-1) == 0)
704*b816ddf8Sgww 				ppasswd->passwdstatus = "NL";
705*b816ddf8Sgww 			else if ((strlen(psp->sp_pwdp) == 13 &&
706*b816ddf8Sgww 			    psp->sp_pwdp[0] != '$') ||
707*b816ddf8Sgww 			    psp->sp_pwdp[0] == '$')
7087c478bd9Sstevel@tonic-gate 				ppasswd->passwdstatus = "PS";
709*b816ddf8Sgww 			else
710*b816ddf8Sgww 				ppasswd->passwdstatus = "UN";
7117c478bd9Sstevel@tonic-gate 			/*
71220d7339fSgww 			 * Set up the last-changed date,
71320d7339fSgww 			 * the minimum days between changes,
71420d7339fSgww 			 * the maximum life of a password,
71520d7339fSgww 			 * the interval before expiration that the user
71620d7339fSgww 			 * is warned,
71720d7339fSgww 			 * the number of days a login can be inactive before
71820d7339fSgww 			 * it expires, and the login expiration date
7197c478bd9Sstevel@tonic-gate 			 */
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 			pwchg = psp->sp_lstchg;
7227c478bd9Sstevel@tonic-gate 			ppasswd->mindaystilchg = psp->sp_min;
7237c478bd9Sstevel@tonic-gate 			ppasswd->maxdaystilchg = psp->sp_max;
7247c478bd9Sstevel@tonic-gate 			ppasswd->warninterval = psp->sp_warn;
7257c478bd9Sstevel@tonic-gate 			ppasswd->inactive = psp->sp_inact;
7267c478bd9Sstevel@tonic-gate 			pwexp = psp->sp_expire;
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 		/*
7307c478bd9Sstevel@tonic-gate 		 * Convert the date of the last password change from days-
7317c478bd9Sstevel@tonic-gate 		 * since-epoch to mmddyy (integer) form.  Involves the
7327c478bd9Sstevel@tonic-gate 		 * intermediate step of converting the date from days-
7337c478bd9Sstevel@tonic-gate 		 * since-epoch to seconds-since-epoch.  We'll set this to
7347c478bd9Sstevel@tonic-gate 		 * somewhere near the middle of the day, since there are not
7357c478bd9Sstevel@tonic-gate 		 * always 24*60*60 seconds in a year.  (Yeech)
7367c478bd9Sstevel@tonic-gate 		 *
7377c478bd9Sstevel@tonic-gate 		 * Note:  The form mmddyy should probably be subject to
7387c478bd9Sstevel@tonic-gate 		 * internationalization -- Non-Americans will think that
7397c478bd9Sstevel@tonic-gate 		 * 070888 is 07 August 88 when the software is trying to say
7407c478bd9Sstevel@tonic-gate 		 * 08 July 88.  Systems Engineers seem to think that this isn't
7417c478bd9Sstevel@tonic-gate 		 * a problem though...
7427c478bd9Sstevel@tonic-gate 		 */
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		if (pwchg != -1L) {
7457c478bd9Sstevel@tonic-gate 			pwchg = (pwchg * DAY) + (DAY/2);
7467c478bd9Sstevel@tonic-gate 			ptm = localtime(&pwchg);
7477c478bd9Sstevel@tonic-gate 			ppasswd->datechg = ((long)(ptm->tm_mon+1) * 10000L) +
7487c478bd9Sstevel@tonic-gate 			    (long)((ptm->tm_mday * 100) +
7497c478bd9Sstevel@tonic-gate 			    (ptm->tm_year % 100));
75020d7339fSgww 		} else {
75120d7339fSgww 			ppasswd->datechg = 0L;
75220d7339fSgww 		}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 		/*
7557c478bd9Sstevel@tonic-gate 		 * Convert the passwd expiration date from days-since-epoch
7567c478bd9Sstevel@tonic-gate 		 * to mmddyy (long integer) form using the same algorithm and
7577c478bd9Sstevel@tonic-gate 		 * comments as above.
7587c478bd9Sstevel@tonic-gate 		 */
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (pwexp != -1L) {
7617c478bd9Sstevel@tonic-gate 			pwexp = (pwexp * DAY) + (DAY/2);
7627c478bd9Sstevel@tonic-gate 			ptm = localtime(&pwexp);
7637c478bd9Sstevel@tonic-gate 			ppasswd->expdate = ((long)(ptm->tm_mon+1) * 10000L) +
7647c478bd9Sstevel@tonic-gate 			    (long)((ptm->tm_mday * 100) +
7657c478bd9Sstevel@tonic-gate 			    (ptm->tm_year % 100));
76620d7339fSgww 		} else {
76720d7339fSgww 			ppasswd->expdate = 0L;
76820d7339fSgww 		}
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* Close the shadow password file */
7727c478bd9Sstevel@tonic-gate 	endspent();
7737c478bd9Sstevel@tonic-gate }
77420d7339fSgww 
77520d7339fSgww 
7767c478bd9Sstevel@tonic-gate /*
7777c478bd9Sstevel@tonic-gate  * int hasnopasswd(pwent)
7787c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
7797c478bd9Sstevel@tonic-gate  *
7807c478bd9Sstevel@tonic-gate  *	This function examines a login's password-file entry
7817c478bd9Sstevel@tonic-gate  *	and, if necessary, its shadow password-file entry and
7827c478bd9Sstevel@tonic-gate  *	returns TRUE if that user-ID has no password, meaning
7837c478bd9Sstevel@tonic-gate  *	that the user-ID can be used to log into the system
7847c478bd9Sstevel@tonic-gate  *	without giving a password.  The function returns FALSE
7857c478bd9Sstevel@tonic-gate  *	otherwise.
7867c478bd9Sstevel@tonic-gate  *
7877c478bd9Sstevel@tonic-gate  *  Arguments:
7887c478bd9Sstevel@tonic-gate  *	pwent	Login to examine.
7897c478bd9Sstevel@tonic-gate  *
7907c478bd9Sstevel@tonic-gate  *  Returns:  int
7917c478bd9Sstevel@tonic-gate  *	TRUE if the login can be used without a password, FALSE
7927c478bd9Sstevel@tonic-gate  *	otherwise.
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static int
79620d7339fSgww hasnopasswd(struct passwd *pwent)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate 	struct spwd    *psp;		/* /etc/shadow file struct */
7997c478bd9Sstevel@tonic-gate 	int		nopwflag;	/* TRUE if login has no passwd */
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/*
8027c478bd9Sstevel@tonic-gate 	 *  A login has no password if:
8037c478bd9Sstevel@tonic-gate 	 *    1.  There exists an entry for that login in the
8047c478bd9Sstevel@tonic-gate 	 *	  shadow password-file (/etc/passwd), and
8057c478bd9Sstevel@tonic-gate 	 *    2.  The encrypted password in the structure describing
80620d7339fSgww 	 *	  that entry is either:	 NULL or a null string ("")
8077c478bd9Sstevel@tonic-gate 	 */
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	/* Get the login's entry in the shadow password file */
8107c478bd9Sstevel@tonic-gate 	if (psp = getspnam(pwent->pw_name)) {
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		/* Look at the encrypted password in that entry */
8137c478bd9Sstevel@tonic-gate 		if (psp->sp_pwdp == (char *)0 ||
81420d7339fSgww 		    *psp->sp_pwdp == '\0') {
8157c478bd9Sstevel@tonic-gate 			nopwflag = TRUE;
81620d7339fSgww 		} else {
8177c478bd9Sstevel@tonic-gate 			nopwflag = FALSE;
8187c478bd9Sstevel@tonic-gate 		}
81920d7339fSgww 	} else {
8207c478bd9Sstevel@tonic-gate 		nopwflag = FALSE;
82120d7339fSgww 	}
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 	/* Done ... */
8247c478bd9Sstevel@tonic-gate 	return (nopwflag);
8257c478bd9Sstevel@tonic-gate }
82620d7339fSgww 
82720d7339fSgww 
8287c478bd9Sstevel@tonic-gate /*
8297c478bd9Sstevel@tonic-gate  *  void writeunformatted(current, xtndflag, expflag)
8307c478bd9Sstevel@tonic-gate  *	struct display *current
8317c478bd9Sstevel@tonic-gate  *	int		xtndflag
8327c478bd9Sstevel@tonic-gate  *	int		expflag
8337c478bd9Sstevel@tonic-gate  *
8347c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
8357c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in the
8367c478bd9Sstevel@tonic-gate  *  form of a colon-list.  It writes secondary group information if
8377c478bd9Sstevel@tonic-gate  *  that information is in the structure, it writes extended
8387c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info
8397c478bd9Sstevel@tonic-gate  *  if the "xtndflag" is TRUE, and it writes password expiration
8407c478bd9Sstevel@tonic-gate  *  information if "expflag" is TRUE.
8417c478bd9Sstevel@tonic-gate  *
8427c478bd9Sstevel@tonic-gate  *  Arguments:
8437c478bd9Sstevel@tonic-gate  *	current		Structure containing information to write.
8447c478bd9Sstevel@tonic-gate  *	xtndflag	TRUE if extended information is to be written,
8457c478bd9Sstevel@tonic-gate  *			FALSE otherwise
8467c478bd9Sstevel@tonic-gate  *	expflag		TRUE if password expiration information is to
8477c478bd9Sstevel@tonic-gate  *			be written, FALSE otherwise
8487c478bd9Sstevel@tonic-gate  *
8497c478bd9Sstevel@tonic-gate  *  Returns:  void
8507c478bd9Sstevel@tonic-gate  */
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate static void
85320d7339fSgww writeunformatted(struct display *current, int xtndflag, int expflag)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
8567c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	/* Write the general information */
8597c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%s:%ld:%s:%ld:%s",
8607c478bd9Sstevel@tonic-gate 	    current->loginID,
8617c478bd9Sstevel@tonic-gate 	    current->userID,
86220d7339fSgww 	    current->groupname == NULL ? "" : current->groupname,
8637c478bd9Sstevel@tonic-gate 	    current->groupID,
8647c478bd9Sstevel@tonic-gate 	    current->freefield);
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 	/*
8677c478bd9Sstevel@tonic-gate 	 * If the group information is there, write it (it's only
8687c478bd9Sstevel@tonic-gate 	 * there if it's supposed to be written)
8697c478bd9Sstevel@tonic-gate 	 */
87020d7339fSgww 	for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
87120d7339fSgww 		(void) fprintf(stdout, ":%s:%ld",
87220d7339fSgww 		    psecgrp->groupname, psecgrp->groupID);
87320d7339fSgww 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	/* If the extended info flag is TRUE, write the extended information */
8767c478bd9Sstevel@tonic-gate 	if (xtndflag) {
8777c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
8787c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, ":%s:%s:%s:%6.6ld:%ld:%ld:%ld",
8797c478bd9Sstevel@tonic-gate 		    current->iwd, current->shell,
8807c478bd9Sstevel@tonic-gate 		    pwdinfo->passwdstatus,
8817c478bd9Sstevel@tonic-gate 		    pwdinfo->datechg,
8827c478bd9Sstevel@tonic-gate 		    pwdinfo->mindaystilchg, pwdinfo->maxdaystilchg,
8837c478bd9Sstevel@tonic-gate 		    pwdinfo->warninterval);
8847c478bd9Sstevel@tonic-gate 	}
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 	/* If the password expiration information is requested, write it.  */
8877c478bd9Sstevel@tonic-gate 	if (expflag) {
8887c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
88920d7339fSgww 		(void) fprintf(stdout, ":%ld:%ld",
89020d7339fSgww 		    pwdinfo->inactive, pwdinfo->expdate);
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/* Terminate the information with a new-line */
8947c478bd9Sstevel@tonic-gate 	(void) putc('\n', stdout);
8957c478bd9Sstevel@tonic-gate }
89620d7339fSgww 
89720d7339fSgww 
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate  *  void writeformatted(current, xtndflag, expflag)
9007c478bd9Sstevel@tonic-gate  *	struct display *current
9017c478bd9Sstevel@tonic-gate  *	int		xtndflag
9027c478bd9Sstevel@tonic-gate  *	int		expflag
9037c478bd9Sstevel@tonic-gate  *
9047c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
9057c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in an
9067c478bd9Sstevel@tonic-gate  *  easily readable format.  It writes secondary group information
9077c478bd9Sstevel@tonic-gate  *  if that information is in the structure, it writes extended
9087c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info if
9097c478bd9Sstevel@tonic-gate  *  "xtndflag" is TRUE, and it write password expiration information
9107c478bd9Sstevel@tonic-gate  *  if "expflag" is TRUE.
9117c478bd9Sstevel@tonic-gate  *
9127c478bd9Sstevel@tonic-gate  *  Arguments:
9137c478bd9Sstevel@tonic-gate  *	current		Structure containing info to write.
91420d7339fSgww  *	xtndflag	TRUE if extended information to be written,
9157c478bd9Sstevel@tonic-gate  *			FALSE otherwise
91620d7339fSgww  *	expflag 	TRUE if password expiration information to be written,
9177c478bd9Sstevel@tonic-gate  *			FALSE otherwise
9187c478bd9Sstevel@tonic-gate  *
9197c478bd9Sstevel@tonic-gate  *  Returns:  void
9207c478bd9Sstevel@tonic-gate  */
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate static void
92320d7339fSgww writeformatted(struct display *current, int xtndflag, int expflag)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
9267c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* Write general information */
9297c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%-14s  %-6ld  %-14s  %-6ld  %s\n",
9307c478bd9Sstevel@tonic-gate 	    current->loginID, current->userID,
93120d7339fSgww 	    current->groupname == NULL ? "" : current->groupname,
9327c478bd9Sstevel@tonic-gate 	    current->groupID, current->freefield);
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	/*
9357c478bd9Sstevel@tonic-gate 	 * Write information about secondary groups if the info exists
9367c478bd9Sstevel@tonic-gate 	 * (it only exists if it is to be written)
9377c478bd9Sstevel@tonic-gate 	 */
93820d7339fSgww 	for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
9397c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %-14s  %-6ld\n",
9407c478bd9Sstevel@tonic-gate 		psecgrp->groupname, psecgrp->groupID);
94120d7339fSgww 	}
9427c478bd9Sstevel@tonic-gate 
94320d7339fSgww 	/*
94420d7339fSgww 	 * If the extended information flag is TRUE,
94520d7339fSgww 	 * write the extended information
94620d7339fSgww 	 */
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (xtndflag) {
9497c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
95020d7339fSgww 		(void) fprintf(stdout, "                        %s\n",
95120d7339fSgww 		    current->iwd);
95220d7339fSgww 		(void) fprintf(stdout, "                        %s\n",
95320d7339fSgww 		    current->shell);
95420d7339fSgww 		(void) fprintf(stdout, "                        %s "
95520d7339fSgww 		    "%6.6ld %ld %ld %ld\n",
9567c478bd9Sstevel@tonic-gate 		    pwdinfo->passwdstatus,
9577c478bd9Sstevel@tonic-gate 		    pwdinfo->datechg, pwdinfo->mindaystilchg,
9587c478bd9Sstevel@tonic-gate 		    pwdinfo->maxdaystilchg,
9597c478bd9Sstevel@tonic-gate 		    pwdinfo->warninterval);
9607c478bd9Sstevel@tonic-gate 	}
9617c478bd9Sstevel@tonic-gate 
96220d7339fSgww 	/*
96320d7339fSgww 	 * If the password expiration info flag is TRUE,
96420d7339fSgww 	 * write that information
96520d7339fSgww 	 */
9667c478bd9Sstevel@tonic-gate 	if (expflag) {
9677c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
9687c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, "                        %ld %6.6ld\n",
9697c478bd9Sstevel@tonic-gate 		    pwdinfo->inactive, pwdinfo->expdate);
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate }
97220d7339fSgww 
97320d7339fSgww 
9747c478bd9Sstevel@tonic-gate /*
9757c478bd9Sstevel@tonic-gate  *  void genuidreport(pipeflag, xtndflag, expflag)
9767c478bd9Sstevel@tonic-gate  *	int	pipeflag
9777c478bd9Sstevel@tonic-gate  *	int	xtndflag
9787c478bd9Sstevel@tonic-gate  *	int	expflag
9797c478bd9Sstevel@tonic-gate  *
9807c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
9817c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
9827c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
9837c478bd9Sstevel@tonic-gate  *	on user-ID.  If the <pipeflag> variable is not zero, it
9847c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
9857c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
9867c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
9877c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
9887c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
9897c478bd9Sstevel@tonic-gate  *	zero, it will display password expiration information.
9907c478bd9Sstevel@tonic-gate  *
9917c478bd9Sstevel@tonic-gate  *  Arguments:
9927c478bd9Sstevel@tonic-gate  *	pipeflag	int
9937c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
9947c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
9957c478bd9Sstevel@tonic-gate  *	xtndflag	int
9967c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
9977c478bd9Sstevel@tonic-gate  *			FALSE otherwise
9987c478bd9Sstevel@tonic-gate  *	expflag		int
9997c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to be
10007c478bd9Sstevel@tonic-gate  *			displayed, FALSE otherwise
10017c478bd9Sstevel@tonic-gate  *
10027c478bd9Sstevel@tonic-gate  *  Returns:  void
10037c478bd9Sstevel@tonic-gate  */
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate static void
100620d7339fSgww genuidreport(int pipeflag, int xtndflag, int expflag)
10077c478bd9Sstevel@tonic-gate {
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	struct display *current;	/* Data being displayed */
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	/*
10137c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
101420d7339fSgww 	 *  (NOTE:  The first element in the list of logins to	display is
101520d7339fSgww 	 *  a dummy element.)
10167c478bd9Sstevel@tonic-gate 	 */
10177c478bd9Sstevel@tonic-gate 	current = displayhead;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/*
10207c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
10217c478bd9Sstevel@tonic-gate 	 */
102220d7339fSgww 	if (pipeflag) {
102320d7339fSgww 		for (current = displayhead->nextuid; current;
102420d7339fSgww 		    current = current->nextuid) {
10257c478bd9Sstevel@tonic-gate 			writeunformatted(current, xtndflag, expflag);
102620d7339fSgww 		}
102720d7339fSgww 	} else {
102820d7339fSgww 		for (current = displayhead->nextuid; current;
102920d7339fSgww 		    current = current->nextuid) {
10307c478bd9Sstevel@tonic-gate 			writeformatted(current, xtndflag, expflag);
10317c478bd9Sstevel@tonic-gate 		}
103220d7339fSgww 	}
103320d7339fSgww }
103420d7339fSgww 
103520d7339fSgww 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  *  void genlogreport(pipeflag, xtndflag, expflag)
10387c478bd9Sstevel@tonic-gate  *	int	pipeflag
10397c478bd9Sstevel@tonic-gate  *	int	xtndflag
10407c478bd9Sstevel@tonic-gate  *	int	expflag
10417c478bd9Sstevel@tonic-gate  *
10427c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
10437c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
10447c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
10457c478bd9Sstevel@tonic-gate  *	on user name.  If the <pipeflag> variable is not zero, it
10467c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
10477c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
10487c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
10497c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
10507c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
10517c478bd9Sstevel@tonic-gate  *	zero, it will include password expiration information.
10527c478bd9Sstevel@tonic-gate  *
10537c478bd9Sstevel@tonic-gate  *  Arguments:
10547c478bd9Sstevel@tonic-gate  *	pipeflag	int
10557c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
10567c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
10577c478bd9Sstevel@tonic-gate  *	xtndflag	int
10587c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
10597c478bd9Sstevel@tonic-gate  *			FALSE otherwise
10607c478bd9Sstevel@tonic-gate  *	expflag		int
10617c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to
10627c478bd9Sstevel@tonic-gate  *			be displayed, FALSE otherwise
10637c478bd9Sstevel@tonic-gate  *
10647c478bd9Sstevel@tonic-gate  *  Returns:  void
10657c478bd9Sstevel@tonic-gate  */
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate static void
106820d7339fSgww genlogreport(int pipeflag, int xtndflag, int expflag)
10697c478bd9Sstevel@tonic-gate {
10707c478bd9Sstevel@tonic-gate 	struct display *p;	/* Value being displayed */
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	/*
10747c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
107520d7339fSgww 	 *  (NOTE:  The first element in the list of logins to display is
107620d7339fSgww 	 *  a dummy element.)
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	p = displayhead;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	/*
10817c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
10827c478bd9Sstevel@tonic-gate 	 */
108320d7339fSgww 	if (pipeflag) {
108420d7339fSgww 		for (p = displayhead->nextlogin; p; p = p->nextlogin) {
10857c478bd9Sstevel@tonic-gate 			writeunformatted(p, xtndflag, expflag);
108620d7339fSgww 		}
108720d7339fSgww 	} else {
108820d7339fSgww 		for (p = displayhead->nextlogin; p; p = p->nextlogin) {
10897c478bd9Sstevel@tonic-gate 			writeformatted(p, xtndflag, expflag);
10907c478bd9Sstevel@tonic-gate 		}
109120d7339fSgww 	}
109220d7339fSgww }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate struct localpw {
10957c478bd9Sstevel@tonic-gate 	struct localpw *next;
10967c478bd9Sstevel@tonic-gate 	struct passwd pw;
10977c478bd9Sstevel@tonic-gate };
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate struct localpw *pwtable = NULL;
11007c478bd9Sstevel@tonic-gate 
110120d7339fSgww /* Local passwd pointer for getpwent() -- -1 means not in use, NULL for EOF */
110220d7339fSgww struct localpw *pwptr;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate int in_localgetpwent = 0;	/* Set if in local_getpwent */
11057c478bd9Sstevel@tonic-gate 
1106*b816ddf8Sgww static struct localpw *
1107*b816ddf8Sgww fill_localpw(struct localpw *lpw, struct passwd *pw) {
1108*b816ddf8Sgww 	struct localpw *cur;
1109*b816ddf8Sgww 
1110*b816ddf8Sgww 	/*
1111*b816ddf8Sgww 	 * Copy the data -- we have to alloc areas for it all
1112*b816ddf8Sgww 	 */
1113*b816ddf8Sgww 	lpw->pw.pw_name = strdup(pw->pw_name);
1114*b816ddf8Sgww 	lpw->pw.pw_passwd = strdup(pw->pw_passwd);
1115*b816ddf8Sgww 	lpw->pw.pw_uid = pw->pw_uid;
1116*b816ddf8Sgww 	lpw->pw.pw_gid = pw->pw_gid;
1117*b816ddf8Sgww 	lpw->pw.pw_age = strdup(pw->pw_age);
1118*b816ddf8Sgww 	lpw->pw.pw_comment = strdup(pw->pw_comment);
1119*b816ddf8Sgww 	lpw->pw.pw_gecos  = strdup(pw->pw_gecos);
1120*b816ddf8Sgww 	lpw->pw.pw_dir = strdup(pw->pw_dir);
1121*b816ddf8Sgww 	lpw->pw.pw_shell = strdup(pw->pw_shell);
1122*b816ddf8Sgww 
1123*b816ddf8Sgww 	cur = lpw;
1124*b816ddf8Sgww 	lpw->next = malloc(sizeof (struct localpw));
1125*b816ddf8Sgww 	return (cur);
1126*b816ddf8Sgww }
1127*b816ddf8Sgww 
11287c478bd9Sstevel@tonic-gate void
1129*b816ddf8Sgww build_localpw(struct reqlogin *req_head)
11307c478bd9Sstevel@tonic-gate {
11317c478bd9Sstevel@tonic-gate 	struct localpw *next, *cur;
11327c478bd9Sstevel@tonic-gate 	struct passwd *pw;
1133*b816ddf8Sgww 	struct reqlogin *req_next;
11347c478bd9Sstevel@tonic-gate 
1135*b816ddf8Sgww 	next = malloc(sizeof (struct localpw));
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	pwtable = next;
11387c478bd9Sstevel@tonic-gate 
1139*b816ddf8Sgww 	req_next = req_head;
1140*b816ddf8Sgww 
1141*b816ddf8Sgww 	while (req_next != NULL) {
1142*b816ddf8Sgww 		if ((pw = getpwnam(req_next->loginname)) != NULL) {
1143*b816ddf8Sgww 			/*
1144*b816ddf8Sgww 			 * Copy the data -- we have to alloc areas for it all
1145*b816ddf8Sgww 			 */
1146*b816ddf8Sgww 			cur = fill_localpw(next, pw);
1147*b816ddf8Sgww 			req_next->found = TRUE;
1148*b816ddf8Sgww 			next = cur->next;
1149*b816ddf8Sgww 		}
1150*b816ddf8Sgww 
1151*b816ddf8Sgww 		req_next = req_next->next;
1152*b816ddf8Sgww 	}
1153*b816ddf8Sgww 
1154*b816ddf8Sgww 	if (req_head == NULL) {
11557c478bd9Sstevel@tonic-gate 		while ((pw = getpwent()) != NULL) {
11567c478bd9Sstevel@tonic-gate 			/*
11577c478bd9Sstevel@tonic-gate 			 * Copy the data -- we have to alloc areas for it all
11587c478bd9Sstevel@tonic-gate 			 */
1159*b816ddf8Sgww 			cur = fill_localpw(next, pw);
1160*b816ddf8Sgww 			next = cur->next;
11617c478bd9Sstevel@tonic-gate 		}
1162*b816ddf8Sgww 	}
11637c478bd9Sstevel@tonic-gate 
116420d7339fSgww 	if (pwtable == next) {
11657c478bd9Sstevel@tonic-gate 		pwtable = NULL;
116620d7339fSgww 	} else {
1167*b816ddf8Sgww 		free(next);
11687c478bd9Sstevel@tonic-gate 		cur->next = NULL;
116920d7339fSgww 	}
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	endpwent();
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate struct passwd *
117520d7339fSgww local_getpwent(void)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate 	if (!in_localgetpwent) {
11787c478bd9Sstevel@tonic-gate 		in_localgetpwent = 1;
11797c478bd9Sstevel@tonic-gate 		pwptr = pwtable;
118020d7339fSgww 	} else if (pwptr != NULL) {
11817c478bd9Sstevel@tonic-gate 		pwptr = pwptr->next;
118220d7339fSgww 	}
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	if (pwptr != NULL)
118520d7339fSgww 		return (&(pwptr->pw));
11867c478bd9Sstevel@tonic-gate 	else
118720d7339fSgww 		return (NULL);
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate void
119120d7339fSgww local_endpwent(void)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 	in_localgetpwent = 0;
11947c478bd9Sstevel@tonic-gate }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate long
119720d7339fSgww local_pwtell(void)
11987c478bd9Sstevel@tonic-gate {
119920d7339fSgww 	return ((long)pwptr);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate void
120320d7339fSgww local_pwseek(long ptr)
12047c478bd9Sstevel@tonic-gate {
12057c478bd9Sstevel@tonic-gate 	pwptr = (struct localpw *)ptr;
12067c478bd9Sstevel@tonic-gate }
120720d7339fSgww 
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate  * logins [-admopstux] [-l logins] [-g groups]
12107c478bd9Sstevel@tonic-gate  *
12117c478bd9Sstevel@tonic-gate  *	This command generates a report of logins administered on
12127c478bd9Sstevel@tonic-gate  *	the system.  The list will contain logins that meet criteria
12137c478bd9Sstevel@tonic-gate  *	described by the options in the list.  If there are no options,
12147c478bd9Sstevel@tonic-gate  *	it will list all logins administered.  It is intended to be used
12157c478bd9Sstevel@tonic-gate  *	only by administrators.
12167c478bd9Sstevel@tonic-gate  *
12177c478bd9Sstevel@tonic-gate  *  Options:
12187c478bd9Sstevel@tonic-gate  *	-a		Display password expiration information.
12197c478bd9Sstevel@tonic-gate  *	-d		list all logins that share user-IDs with another
12207c478bd9Sstevel@tonic-gate  *			login.
12217c478bd9Sstevel@tonic-gate  *	-g groups	specifies the names of the groups to which a login
12227c478bd9Sstevel@tonic-gate  *			must belong before it is included in the generated
12237c478bd9Sstevel@tonic-gate  *			list.  "groups" is a comma-list of group names.
12247c478bd9Sstevel@tonic-gate  *	-l logins	specifies the logins to display.  "logins" is a
12257c478bd9Sstevel@tonic-gate  *			comma-list of login names.
12267c478bd9Sstevel@tonic-gate  *	-m		in addition to the usual information, for each
12277c478bd9Sstevel@tonic-gate  *			login displayed, list all groups to which that
12287c478bd9Sstevel@tonic-gate  *			login is member.
12297c478bd9Sstevel@tonic-gate  *	-o		generate a report as a colon-list instead of in a
12307c478bd9Sstevel@tonic-gate  *			columnar format
12317c478bd9Sstevel@tonic-gate  *	-p		list all logins that have no password.
12327c478bd9Sstevel@tonic-gate  *	-s		list all system logins
12337c478bd9Sstevel@tonic-gate  *	-t		sort the report lexicographically by login name
12347c478bd9Sstevel@tonic-gate  *			instead of by user-ID
12357c478bd9Sstevel@tonic-gate  *	-u		list all user logins
12367c478bd9Sstevel@tonic-gate  *	-x		in addition to the usual information, display an
12377c478bd9Sstevel@tonic-gate  *			extended set of information that includes the home
12387c478bd9Sstevel@tonic-gate  *			directory, initial process, and password status and
12397c478bd9Sstevel@tonic-gate  *			aging information
12407c478bd9Sstevel@tonic-gate  *
12417c478bd9Sstevel@tonic-gate  * Exit Codes:
12427c478bd9Sstevel@tonic-gate  *	0	All's well that ends well
12437c478bd9Sstevel@tonic-gate  *	1	Usage error
12447c478bd9Sstevel@tonic-gate  */
12457c478bd9Sstevel@tonic-gate 
124620d7339fSgww int
124720d7339fSgww main(int argc, char *argv[])
12487c478bd9Sstevel@tonic-gate {
12497c478bd9Sstevel@tonic-gate 	struct passwd	*plookpwd;	/* Ptr to searcher pw (-d) */
12507c478bd9Sstevel@tonic-gate 	struct reqgrp	*reqgrphead;	/* Head of the req'd group list */
12517c478bd9Sstevel@tonic-gate 	struct reqgrp	*pgrp;		/* Current item in req'd group list */
12527c478bd9Sstevel@tonic-gate 	struct reqgrp	*qgrp;		/* Prev item in the req'd group list */
12537c478bd9Sstevel@tonic-gate 	struct reqlogin *reqloginhead;	/* Head of req'd login list */
125420d7339fSgww 	struct reqlogin *plogin;	/* Current item in req'd login list */
125520d7339fSgww 	struct reqlogin *qlogin;	/* Prev item in req'd login list */
12567c478bd9Sstevel@tonic-gate 	struct passwd	*pwent;		/* /etc/passwd entry */
12577c478bd9Sstevel@tonic-gate 	struct group	*grent;		/* /etc/group entry */
12587c478bd9Sstevel@tonic-gate 	char		*token;		/* Token extracted by strtok() */
12597c478bd9Sstevel@tonic-gate 	char		**pp;		/* Group member */
12607c478bd9Sstevel@tonic-gate 	char		*g_arg;		/* -g option's argument */
12617c478bd9Sstevel@tonic-gate 	char		*l_arg;		/* -l option's argument */
12627c478bd9Sstevel@tonic-gate 	long		lookpos;	/* File pos'n, rec we're looking for */
12637c478bd9Sstevel@tonic-gate 	int		a_seen;		/* Is -a requested? */
12647c478bd9Sstevel@tonic-gate 	int		d_seen;		/* Is -d requested? */
12657c478bd9Sstevel@tonic-gate 	int		g_seen;		/* Is -g requested? */
12667c478bd9Sstevel@tonic-gate 	int		l_seen;		/* Is -l requested? */
12677c478bd9Sstevel@tonic-gate 	int		m_seen;		/* Is -m requested? */
12687c478bd9Sstevel@tonic-gate 	int		o_seen;		/* Is -o requested? */
12697c478bd9Sstevel@tonic-gate 	int		p_seen;		/* Is -p requested? */
12707c478bd9Sstevel@tonic-gate 	int		s_seen;		/* Is -s requested? */
12717c478bd9Sstevel@tonic-gate 	int		t_seen;		/* Is -t requested? */
12727c478bd9Sstevel@tonic-gate 	int		u_seen;		/* Is -u requested? */
12737c478bd9Sstevel@tonic-gate 	int		x_seen;		/* Is -x requested? */
12747c478bd9Sstevel@tonic-gate 	int		errflg;		/* Is there a command-line problem */
12757c478bd9Sstevel@tonic-gate 	int		done;		/* Is the process (?) is complete */
127620d7339fSgww 	int		groupcount;	/* Number of groups specified */
12777c478bd9Sstevel@tonic-gate 	int		doall;		/* Are all logins to be reported */
12787c478bd9Sstevel@tonic-gate 	int		c;		/* Character returned from getopt() */
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
12837c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
12847c478bd9Sstevel@tonic-gate #endif
12857c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/* Initializations */
12887c478bd9Sstevel@tonic-gate 	initmsg(argv[0]);
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 
129220d7339fSgww 	/*  Command-line processing */
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate 	/* Initializations */
12957c478bd9Sstevel@tonic-gate 	a_seen = FALSE;
12967c478bd9Sstevel@tonic-gate 	d_seen = FALSE;
12977c478bd9Sstevel@tonic-gate 	g_seen = FALSE;
12987c478bd9Sstevel@tonic-gate 	l_seen = FALSE;
12997c478bd9Sstevel@tonic-gate 	m_seen = FALSE;
13007c478bd9Sstevel@tonic-gate 	o_seen = FALSE;
13017c478bd9Sstevel@tonic-gate 	p_seen = FALSE;
13027c478bd9Sstevel@tonic-gate 	s_seen = FALSE;
13037c478bd9Sstevel@tonic-gate 	t_seen = FALSE;
13047c478bd9Sstevel@tonic-gate 	u_seen = FALSE;
13057c478bd9Sstevel@tonic-gate 	x_seen = FALSE;
13067c478bd9Sstevel@tonic-gate 	errflg = FALSE;
13077c478bd9Sstevel@tonic-gate 	opterr = 0;
13087c478bd9Sstevel@tonic-gate 	while (!errflg && ((c = getopt(argc, argv, OPTSTR)) != EOF)) {
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		/* Case on the option character */
13117c478bd9Sstevel@tonic-gate 		switch (c) {
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 		/*
13147c478bd9Sstevel@tonic-gate 		 * -a option:
13157c478bd9Sstevel@tonic-gate 		 * Display password expiration information
13167c478bd9Sstevel@tonic-gate 		 */
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 		case 'a':
131920d7339fSgww 			if (a_seen)
132020d7339fSgww 				errflg = TRUE;
132120d7339fSgww 			else
132220d7339fSgww 				a_seen = TRUE;
13237c478bd9Sstevel@tonic-gate 			break;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		/*
13267c478bd9Sstevel@tonic-gate 		 * -d option:
13277c478bd9Sstevel@tonic-gate 		 * Display logins which share user-IDs with other logins
13287c478bd9Sstevel@tonic-gate 		 */
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		case 'd':
133120d7339fSgww 			if (d_seen)
133220d7339fSgww 				errflg = TRUE;
133320d7339fSgww 			else
133420d7339fSgww 				d_seen = TRUE;
13357c478bd9Sstevel@tonic-gate 			break;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 		/*
13387c478bd9Sstevel@tonic-gate 		 * -g <groups> option:
13397c478bd9Sstevel@tonic-gate 		 * Display the specified groups
13407c478bd9Sstevel@tonic-gate 		 */
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 		case 'g':
134320d7339fSgww 			if (g_seen) {
134420d7339fSgww 				errflg = TRUE;
134520d7339fSgww 			} else {
13467c478bd9Sstevel@tonic-gate 				g_seen = TRUE;
13477c478bd9Sstevel@tonic-gate 				g_arg = optarg;
13487c478bd9Sstevel@tonic-gate 			}
13497c478bd9Sstevel@tonic-gate 			break;
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 		/*
13527c478bd9Sstevel@tonic-gate 		 * -l <logins> option:
13537c478bd9Sstevel@tonic-gate 		 * Display the specified logins
13547c478bd9Sstevel@tonic-gate 		 */
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate 		case 'l':
135720d7339fSgww 			if (l_seen) {
135820d7339fSgww 				errflg = TRUE;
135920d7339fSgww 			} else {
13607c478bd9Sstevel@tonic-gate 				l_seen = TRUE;
13617c478bd9Sstevel@tonic-gate 				l_arg = optarg;
13627c478bd9Sstevel@tonic-gate 			}
13637c478bd9Sstevel@tonic-gate 			break;
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		/*
13667c478bd9Sstevel@tonic-gate 		 * -m option:
13677c478bd9Sstevel@tonic-gate 		 * Display multiple group information
13687c478bd9Sstevel@tonic-gate 		 */
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 		case 'm':
137120d7339fSgww 			if (m_seen)
137220d7339fSgww 				errflg = TRUE;
137320d7339fSgww 			else
137420d7339fSgww 				m_seen = TRUE;
13757c478bd9Sstevel@tonic-gate 			break;
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 		/*
13787c478bd9Sstevel@tonic-gate 		 * -o option:
13797c478bd9Sstevel@tonic-gate 		 * Display information as a colon-list
13807c478bd9Sstevel@tonic-gate 		 */
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 		case 'o':
138320d7339fSgww 			if (o_seen)
138420d7339fSgww 				errflg = TRUE;
138520d7339fSgww 			else
138620d7339fSgww 				o_seen = TRUE;
13877c478bd9Sstevel@tonic-gate 			break;
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 		/*
13907c478bd9Sstevel@tonic-gate 		 * -p option:
13917c478bd9Sstevel@tonic-gate 		 * Select logins that have no password
13927c478bd9Sstevel@tonic-gate 		 */
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate 		case 'p':
139520d7339fSgww 			if (p_seen)
139620d7339fSgww 				errflg = TRUE;
139720d7339fSgww 			else
139820d7339fSgww 				p_seen = TRUE;
13997c478bd9Sstevel@tonic-gate 			break;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 		/*
14027c478bd9Sstevel@tonic-gate 		 * -s option:
14037c478bd9Sstevel@tonic-gate 		 * Select system logins
14047c478bd9Sstevel@tonic-gate 		 */
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 		case 's':
140720d7339fSgww 			if (s_seen)
140820d7339fSgww 				errflg = TRUE;
140920d7339fSgww 			else
141020d7339fSgww 				s_seen = TRUE;
14117c478bd9Sstevel@tonic-gate 			break;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		/*
14147c478bd9Sstevel@tonic-gate 		 * -t option:
14157c478bd9Sstevel@tonic-gate 		 * Sort alphabetically by login-ID instead of numerically
14167c478bd9Sstevel@tonic-gate 		 * by user-ID
14177c478bd9Sstevel@tonic-gate 		 */
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 		case 't':
142020d7339fSgww 			if (t_seen)
142120d7339fSgww 				errflg = TRUE;
142220d7339fSgww 			else
142320d7339fSgww 				t_seen = TRUE;
14247c478bd9Sstevel@tonic-gate 			break;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 		/*
14277c478bd9Sstevel@tonic-gate 		 * -u option:
14287c478bd9Sstevel@tonic-gate 		 * Select user logins
14297c478bd9Sstevel@tonic-gate 		 */
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		case 'u':
143220d7339fSgww 			if (u_seen)
143320d7339fSgww 				errflg = TRUE;
143420d7339fSgww 			else
143520d7339fSgww 				u_seen = TRUE;
14367c478bd9Sstevel@tonic-gate 			break;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		/*
14397c478bd9Sstevel@tonic-gate 		 * -x option:
14407c478bd9Sstevel@tonic-gate 		 * Display extended info (init working dir, shell, pwd info)
14417c478bd9Sstevel@tonic-gate 		 */
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		case 'x':
144420d7339fSgww 			if (x_seen)
144520d7339fSgww 				errflg = TRUE;
144620d7339fSgww 			else
144720d7339fSgww 				x_seen = TRUE;
14487c478bd9Sstevel@tonic-gate 			break;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 		default:		/* Oops.... */
14517c478bd9Sstevel@tonic-gate 			errflg = TRUE;
14527c478bd9Sstevel@tonic-gate 		}
14537c478bd9Sstevel@tonic-gate 	}
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/* Write out a usage message if necessary and quit */
14567c478bd9Sstevel@tonic-gate 	if (errflg || (optind != argc)) {
14577c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(USAGE_MSG));
14587c478bd9Sstevel@tonic-gate 		exit(1);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	/*
14627c478bd9Sstevel@tonic-gate 	 *  The following section does preparation work, setting up for
14637c478bd9Sstevel@tonic-gate 	 *  building the list of logins to display
14647c478bd9Sstevel@tonic-gate 	 */
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	/*
14687c478bd9Sstevel@tonic-gate 	 *  If -l logins is on the command line, build a list of
14697c478bd9Sstevel@tonic-gate 	 *  logins we're to generate reports for.
14707c478bd9Sstevel@tonic-gate 	 */
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	if (l_seen) {
147320d7339fSgww 		reqloginhead = NULL;
14747c478bd9Sstevel@tonic-gate 		if (token = strtok(l_arg, ",")) {
1475*b816ddf8Sgww 			plogin = malloc(sizeof (struct reqlogin));
14767c478bd9Sstevel@tonic-gate 			plogin->loginname = token;
14777c478bd9Sstevel@tonic-gate 			plogin->found = FALSE;
147820d7339fSgww 			plogin->next = NULL;
14797c478bd9Sstevel@tonic-gate 			reqloginhead = plogin;
14807c478bd9Sstevel@tonic-gate 			qlogin = plogin;
14817c478bd9Sstevel@tonic-gate 			while (token = strtok(NULL, ",")) {
1482*b816ddf8Sgww 				plogin = malloc(sizeof (struct reqlogin));
14837c478bd9Sstevel@tonic-gate 				plogin->loginname = token;
14847c478bd9Sstevel@tonic-gate 				plogin->found = FALSE;
148520d7339fSgww 				plogin->next = NULL;
14867c478bd9Sstevel@tonic-gate 				qlogin->next = plogin;
14877c478bd9Sstevel@tonic-gate 				qlogin = plogin;
14887c478bd9Sstevel@tonic-gate 			}
14897c478bd9Sstevel@tonic-gate 		}
1490*b816ddf8Sgww 		/*
1491*b816ddf8Sgww 		 * Build an in-core structure of just the passwd database
1492*b816ddf8Sgww 		 * entries requested.  This greatly reduces the time
1493*b816ddf8Sgww 		 * to get all entries and filter later.
1494*b816ddf8Sgww 		 */
1495*b816ddf8Sgww 		build_localpw(reqloginhead);
1496*b816ddf8Sgww 	} else {
1497*b816ddf8Sgww 		/*
1498*b816ddf8Sgww 		 * Build an in-core structure of all passwd database
1499*b816ddf8Sgww 		 * entries.  This is important since we have to assume that
1500*b816ddf8Sgww 		 * getpwent() is going out to one or more network name
1501*b816ddf8Sgww 		 * services that could be changing on the fly.  This will
1502*b816ddf8Sgww 		 * limit us to one pass through the network data.
1503*b816ddf8Sgww 		 */
1504*b816ddf8Sgww 		build_localpw(NULL);
1505*b816ddf8Sgww 	}
1506*b816ddf8Sgww 
1507*b816ddf8Sgww 	/*
1508*b816ddf8Sgww 	 *  If the -g groups option was on the command line, build a
1509*b816ddf8Sgww 	 *  list containing groups we're to list logins for.
1510*b816ddf8Sgww 	 */
1511*b816ddf8Sgww 
1512*b816ddf8Sgww 	if (g_seen) {
1513*b816ddf8Sgww 		groupcount = 0;
1514*b816ddf8Sgww 		reqgrphead = NULL;
1515*b816ddf8Sgww 		if (token = strtok(g_arg, ",")) {
1516*b816ddf8Sgww 			pgrp = malloc(sizeof (struct reqgrp));
1517*b816ddf8Sgww 			pgrp->groupname = token;
1518*b816ddf8Sgww 			pgrp->next = NULL;
1519*b816ddf8Sgww 			groupcount++;
1520*b816ddf8Sgww 			reqgrphead = pgrp;
1521*b816ddf8Sgww 			qgrp = pgrp;
1522*b816ddf8Sgww 			while (token = strtok(NULL, ",")) {
1523*b816ddf8Sgww 				pgrp = malloc(sizeof (struct reqgrp));
1524*b816ddf8Sgww 				pgrp->groupname = token;
1525*b816ddf8Sgww 				pgrp->next = NULL;
1526*b816ddf8Sgww 				groupcount++;
1527*b816ddf8Sgww 				qgrp->next = pgrp;
1528*b816ddf8Sgww 				qgrp = pgrp;
15297c478bd9Sstevel@tonic-gate 			}
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 	}
1532*b816ddf8Sgww 
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	/*
15357c478bd9Sstevel@tonic-gate 	 *  Generate the list of login information to display
15367c478bd9Sstevel@tonic-gate 	 */
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	/* Initialize the login list */
1539*b816ddf8Sgww 	membershead = NULL;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	/*
15437c478bd9Sstevel@tonic-gate 	 *  If -g groups was specified, generate a list of members
15447c478bd9Sstevel@tonic-gate 	 *  of the specified groups
15457c478bd9Sstevel@tonic-gate 	 */
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	if (g_seen) {
15487c478bd9Sstevel@tonic-gate 		/* For each group mentioned with the -g option ... */
154920d7339fSgww 		for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
155020d7339fSgww 		    pgrp = pgrp->next) {
1551*b816ddf8Sgww 			if ((grent = getgrnam(pgrp->groupname)) != NULL) {
15527c478bd9Sstevel@tonic-gate 				/*
1553*b816ddf8Sgww 				 * Remembering the group-ID for later
15547c478bd9Sstevel@tonic-gate 				 */
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 				groupcount--;
15577c478bd9Sstevel@tonic-gate 				pgrp->groupID = grent->gr_gid;
1558*b816ddf8Sgww 				for (pp = grent->gr_mem; *pp; pp++) {
155920d7339fSgww 					addmember(*pp);
15607c478bd9Sstevel@tonic-gate 				}
1561*b816ddf8Sgww 			} else {
156220d7339fSgww 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
156320d7339fSgww 				    gettext("%s was not found"),
156420d7339fSgww 				    pgrp->groupname);
156520d7339fSgww 			}
15667c478bd9Sstevel@tonic-gate 		}
15677c478bd9Sstevel@tonic-gate 	}
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	/* Initialize the list of logins to display */
15717c478bd9Sstevel@tonic-gate 	initdisp();
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	/*
15757c478bd9Sstevel@tonic-gate 	 *  Add logins that have user-IDs that are used more than once,
15767c478bd9Sstevel@tonic-gate 	 *  if requested.  This command is pretty slow, since the algorithm
15777c478bd9Sstevel@tonic-gate 	 *  reads from the /etc/passwd file 1+2+3+...+n times where n is the
15787c478bd9Sstevel@tonic-gate 	 *  number of login-IDs in the /etc/passwd file.  (Actually, this
15797c478bd9Sstevel@tonic-gate 	 *  can be optimized so it's not quite that bad, but the order or
15807c478bd9Sstevel@tonic-gate 	 *  magnitude stays the same.)
15817c478bd9Sstevel@tonic-gate 	 *
15827c478bd9Sstevel@tonic-gate 	 *  Note:  This processing needs to be done before any other options
15837c478bd9Sstevel@tonic-gate 	 *	   are processed -- the algorithm contains an optimization
15847c478bd9Sstevel@tonic-gate 	 *	   that insists on the display list being empty before this
15857c478bd9Sstevel@tonic-gate 	 *	   option is processed.
15867c478bd9Sstevel@tonic-gate 	 */
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	if (d_seen) {
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		/*
15917c478bd9Sstevel@tonic-gate 		 * The following code is a quick&dirty reimplementation of the
15927c478bd9Sstevel@tonic-gate 		 * original algorithm, which opened the password file twice (to
15937c478bd9Sstevel@tonic-gate 		 * get two file pointer into the data) and then used fgetpwent()
15947c478bd9Sstevel@tonic-gate 		 * in undocumented ways to scan through the file, checking for
15957c478bd9Sstevel@tonic-gate 		 * duplicates.  This does not work when getpwent() is used to
15967c478bd9Sstevel@tonic-gate 		 * go out over the network, since there is not file pointer.
15977c478bd9Sstevel@tonic-gate 		 *
159820d7339fSgww 		 * Instead an in-memory list of passwd structures is built,
159920d7339fSgww 		 * and then this list is scanned.  The routines
160020d7339fSgww 		 * Local_getpwent(), etc., are designed to mimic the standard
160120d7339fSgww 		 * library routines, so this code does not have to be
160220d7339fSgww 		 * extensively modified.
16037c478bd9Sstevel@tonic-gate 		 */
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 		/*
16067c478bd9Sstevel@tonic-gate 		 * For reference, here is the original comment about the next
160720d7339fSgww 		 * section of code.  Some of the code has changed, but the
160820d7339fSgww 		 * algorithm is the same:
16097c478bd9Sstevel@tonic-gate 		 *
16107c478bd9Sstevel@tonic-gate 		 * Open the system password file once.  This instance will be
16117c478bd9Sstevel@tonic-gate 		 * used to leaf through the file once, reading each entry once,
16127c478bd9Sstevel@tonic-gate 		 * and searching the remainder of the file for another login-ID
16137c478bd9Sstevel@tonic-gate 		 * that has the same user-ID.  Note that there are lots of
16147c478bd9Sstevel@tonic-gate 		 * contortions one has to go through when reading two instances
16157c478bd9Sstevel@tonic-gate 		 * of the /etc/passwd file.  That's why there's some seeking,
16167c478bd9Sstevel@tonic-gate 		 * re-reading of the same record, and other junk.  Luckily, this
16177c478bd9Sstevel@tonic-gate 		 * feature won't be requested very often, and still isn't too
16187c478bd9Sstevel@tonic-gate 		 * slow...
16197c478bd9Sstevel@tonic-gate 		 */
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 		/* For each entry in the passwd database ... */
16227c478bd9Sstevel@tonic-gate 		while (plookpwd = local_getpwent()) {
16237c478bd9Sstevel@tonic-gate 			/*
162420d7339fSgww 			 * Optimization -- If the login's user-ID is already
162520d7339fSgww 			 * in the display list, there's no reason to process
162620d7339fSgww 			 * this  entry -- it's already there.
16277c478bd9Sstevel@tonic-gate 			 */
16287c478bd9Sstevel@tonic-gate 			if (!isuidindisp(plookpwd)) {
16297c478bd9Sstevel@tonic-gate 				/*
163020d7339fSgww 				 * Rememeber the current entry's position,
163120d7339fSgww 				 * so when we finish scanning through the
163220d7339fSgww 				 * database looking for duplicates we can
163320d7339fSgww 				 * return to the current place, so that the
163420d7339fSgww 				 * enclosing loop will march in an orderly
163520d7339fSgww 				 * fashion through the passwd database.
16367c478bd9Sstevel@tonic-gate 				 */
16377c478bd9Sstevel@tonic-gate 				done = FALSE;
16387c478bd9Sstevel@tonic-gate 				lookpos = local_pwtell();
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 				/*
164120d7339fSgww 				 * For each record in the passwd database
164220d7339fSgww 				 * beyond the searching record ...
16437c478bd9Sstevel@tonic-gate 				 */
16447c478bd9Sstevel@tonic-gate 				while (pwent = local_getpwent()) {
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate 					/*
164720d7339fSgww 					 * If there's a match between the
164820d7339fSgww 					 * searcher's user-ID and the
164920d7339fSgww 					 * searchee's user-ID ...
16507c478bd9Sstevel@tonic-gate 					 */
16517c478bd9Sstevel@tonic-gate 					if (pwent->pw_uid == plookpwd->pw_uid) {
16527c478bd9Sstevel@tonic-gate 						/*
165320d7339fSgww 						 * If this is the first
165420d7339fSgww 						 * duplicate of this searcher
16557c478bd9Sstevel@tonic-gate 						 * that we find,
165620d7339fSgww 						 * add the searcher's
165720d7339fSgww 						 * record to the display list
165820d7339fSgww 						 * (It wants to be on the
165920d7339fSgww 						 * list first to avoid
166020d7339fSgww 						 * ordering "flakeyness")
16617c478bd9Sstevel@tonic-gate 						 */
16627c478bd9Sstevel@tonic-gate 						if (done == FALSE) {
16637c478bd9Sstevel@tonic-gate 							adddisp(plookpwd);
166420d7339fSgww 							done = TRUE;
16657c478bd9Sstevel@tonic-gate 						}
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 						/*
166820d7339fSgww 						 * Now add the searchee's
166920d7339fSgww 						 * record
16707c478bd9Sstevel@tonic-gate 						 */
16717c478bd9Sstevel@tonic-gate 						adddisp(pwent);
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 					}
16747c478bd9Sstevel@tonic-gate 				}
16757c478bd9Sstevel@tonic-gate 				/* Reposition to searcher record */
16767c478bd9Sstevel@tonic-gate 				local_pwseek(lookpos);
16777c478bd9Sstevel@tonic-gate 			}
16787c478bd9Sstevel@tonic-gate 		}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		local_endpwent();
16817c478bd9Sstevel@tonic-gate 	}
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 
16847c478bd9Sstevel@tonic-gate 	/*
16857c478bd9Sstevel@tonic-gate 	 *  Loop through the passwd database squirelling away the
16867c478bd9Sstevel@tonic-gate 	 *  information we need for the display.
16877c478bd9Sstevel@tonic-gate 	 *
16887c478bd9Sstevel@tonic-gate 	 *  NOTE:  Once a login is added to the list, the rest of the
16897c478bd9Sstevel@tonic-gate 	 *	   body of the loop is bypassed (via a continue statement).
16907c478bd9Sstevel@tonic-gate 	 */
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate 	doall = !(s_seen || u_seen || p_seen || d_seen || l_seen || g_seen);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	if (doall || s_seen || u_seen || p_seen || l_seen || g_seen) {
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 		while (pwent = local_getpwent()) {
16977c478bd9Sstevel@tonic-gate 			done = FALSE;
16987c478bd9Sstevel@tonic-gate 
169920d7339fSgww 			/*
170020d7339fSgww 			 * If no user-specific options were specified,
170120d7339fSgww 			 * include this login-ID
170220d7339fSgww 			 */
17037c478bd9Sstevel@tonic-gate 			if (doall) {
17047c478bd9Sstevel@tonic-gate 				adddisp(pwent);
17057c478bd9Sstevel@tonic-gate 				continue;
17067c478bd9Sstevel@tonic-gate 			}
17077c478bd9Sstevel@tonic-gate 
170820d7339fSgww 			/*
170920d7339fSgww 			 * If the user specified system login-IDs,
171020d7339fSgww 			 * and this is a system ID, include it
171120d7339fSgww 			 */
171220d7339fSgww 			if (s_seen) {
171320d7339fSgww 				if (isasystemlogin(pwent)) {
17147c478bd9Sstevel@tonic-gate 					adddisp(pwent);
17157c478bd9Sstevel@tonic-gate 					continue;
17167c478bd9Sstevel@tonic-gate 				}
171720d7339fSgww 			}
17187c478bd9Sstevel@tonic-gate 
171920d7339fSgww 			/*
172020d7339fSgww 			 * If the user specified user login-IDs,
172120d7339fSgww 			 * and this is a user ID, include it
172220d7339fSgww 			 */
172320d7339fSgww 			if (u_seen) {
172420d7339fSgww 				if (isauserlogin(pwent)) {
17257c478bd9Sstevel@tonic-gate 					adddisp(pwent);
17267c478bd9Sstevel@tonic-gate 					continue;
17277c478bd9Sstevel@tonic-gate 				}
172820d7339fSgww 			}
17297c478bd9Sstevel@tonic-gate 
173020d7339fSgww 			/*
173120d7339fSgww 			 * If the user is asking for login-IDs that have
173220d7339fSgww 			 * no password, and this one has no password, include it
173320d7339fSgww 			 */
173420d7339fSgww 			if (p_seen) {
173520d7339fSgww 				if (hasnopasswd(pwent)) {
17367c478bd9Sstevel@tonic-gate 					adddisp(pwent);
17377c478bd9Sstevel@tonic-gate 					continue;
17387c478bd9Sstevel@tonic-gate 				}
173920d7339fSgww 			}
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 			/*
17427c478bd9Sstevel@tonic-gate 			 * If specific logins were requested, leaf through
17437c478bd9Sstevel@tonic-gate 			 * the list of logins they requested.  If this login
17447c478bd9Sstevel@tonic-gate 			 * is on the list, include it.
17457c478bd9Sstevel@tonic-gate 			 */
17467c478bd9Sstevel@tonic-gate 			if (l_seen) {
174720d7339fSgww 				for (plogin = reqloginhead; !done && plogin;
174820d7339fSgww 				    plogin = plogin->next) {
174920d7339fSgww 					if (strcmp(pwent->pw_name,
175020d7339fSgww 					    plogin->loginname) == 0) {
17517c478bd9Sstevel@tonic-gate 						plogin->found = TRUE;
17527c478bd9Sstevel@tonic-gate 						adddisp(pwent);
17537c478bd9Sstevel@tonic-gate 						done = TRUE;
17547c478bd9Sstevel@tonic-gate 					}
17557c478bd9Sstevel@tonic-gate 				}
175620d7339fSgww 				if (done)
175720d7339fSgww 					continue;
17587c478bd9Sstevel@tonic-gate 			}
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 			/*
17617c478bd9Sstevel@tonic-gate 			 * If specific groups were requested, leaf through the
176220d7339fSgww 			 * list of login-IDs that belong to those groups.
176320d7339fSgww 			 * If this login-ID is in that list, or its primary
176420d7339fSgww 			 * group is one of those requested, include it.
17657c478bd9Sstevel@tonic-gate 			 */
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 			if (g_seen) {
176820d7339fSgww 				for (pgrp = reqgrphead; !done && pgrp;
176920d7339fSgww 				    pgrp = pgrp->next) {
17707c478bd9Sstevel@tonic-gate 					if (pwent->pw_gid == pgrp->groupID) {
17717c478bd9Sstevel@tonic-gate 						adddisp(pwent);
17727c478bd9Sstevel@tonic-gate 						done = TRUE;
17737c478bd9Sstevel@tonic-gate 					}
177420d7339fSgww 				}
17757c478bd9Sstevel@tonic-gate 				if (!done && isamember(pwent->pw_name)) {
17767c478bd9Sstevel@tonic-gate 					adddisp(pwent);
17777c478bd9Sstevel@tonic-gate 					done = TRUE;
17787c478bd9Sstevel@tonic-gate 				}
17797c478bd9Sstevel@tonic-gate 			}
178020d7339fSgww 			if (done)
178120d7339fSgww 				continue;
17827c478bd9Sstevel@tonic-gate 		}
178320d7339fSgww 
17847c478bd9Sstevel@tonic-gate 		local_endpwent();
17857c478bd9Sstevel@tonic-gate 	}
17867c478bd9Sstevel@tonic-gate 
178720d7339fSgww 	/* Let the user know about logins they requested that don't exist */
178820d7339fSgww 	if (l_seen) {
178920d7339fSgww 		for (plogin = reqloginhead; plogin; plogin = plogin->next) {
179020d7339fSgww 			if (!plogin->found) {
179120d7339fSgww 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
179220d7339fSgww 				    gettext("%s was not found"),
179320d7339fSgww 				    plogin->loginname);
179420d7339fSgww 			}
179520d7339fSgww 		}
179620d7339fSgww 	}
17977c478bd9Sstevel@tonic-gate 
179820d7339fSgww 	/*  Apply group information */
17997c478bd9Sstevel@tonic-gate 	applygroup(m_seen);
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 	/*
18037c478bd9Sstevel@tonic-gate 	 * Apply password information (only needed if the extended
18047c478bd9Sstevel@tonic-gate 	 * set of information has been requested)
18057c478bd9Sstevel@tonic-gate 	 */
180620d7339fSgww 	if (x_seen || a_seen)
180720d7339fSgww 		applypasswd();
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/*
181120d7339fSgww 	 * Generate a report from this display items we've squirreled away
18127c478bd9Sstevel@tonic-gate 	 */
18137c478bd9Sstevel@tonic-gate 
181420d7339fSgww 	if (t_seen)
181520d7339fSgww 		genlogreport(o_seen, x_seen, a_seen);
181620d7339fSgww 	else
181720d7339fSgww 		genuidreport(o_seen, x_seen, a_seen);
18187c478bd9Sstevel@tonic-gate 
181920d7339fSgww 	/*  We're through! */
18207c478bd9Sstevel@tonic-gate 	return (0);
18217c478bd9Sstevel@tonic-gate }
1822