xref: /titanic_54/usr/src/cmd/logins/logins.c (revision 20d7339fc2243574629020a51f08d17b7393b931)
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 /*
23*20d7339fSgww  * 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>
42*20d7339fSgww #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 	int		found;		/* TRUE if group in /etc/group */
1157c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group's ID */
1167c478bd9Sstevel@tonic-gate };
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*  Describes a specified login name (from the -l logins option)  */
1197c478bd9Sstevel@tonic-gate struct	reqlogin {
1207c478bd9Sstevel@tonic-gate 	char		*loginname;	/* Requested login name */
1217c478bd9Sstevel@tonic-gate 	struct reqlogin	*next;		/* Next item in the list */
1227c478bd9Sstevel@tonic-gate 	int		found;		/* TRUE if login in /etc/passwd */
1237c478bd9Sstevel@tonic-gate };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * This structure describes a password's information
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate struct	pwdinfo {
1307c478bd9Sstevel@tonic-gate 	long	datechg;	/* Date the password was changed (mmddyy) */
1317c478bd9Sstevel@tonic-gate 	char	*passwdstatus;	/* Password status */
1327c478bd9Sstevel@tonic-gate 	long	mindaystilchg;	/* Min days b4 pwd can change again */
1337c478bd9Sstevel@tonic-gate 	long	maxdaystilchg;	/* Max days b4 pwd can change again */
1347c478bd9Sstevel@tonic-gate 	long	warninterval;	/* Days before expire to warn user */
1357c478bd9Sstevel@tonic-gate 	long	inactive;	/* Lapsed days of inactivity before lock */
1367c478bd9Sstevel@tonic-gate 	long	expdate;	/* Date of expiration (mmddyy) */
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /* This structure describes secondary groups that a user belongs to */
1407c478bd9Sstevel@tonic-gate struct	secgrp {
1417c478bd9Sstevel@tonic-gate 	char		*groupname;	/* Name of the group */
1427c478bd9Sstevel@tonic-gate 	struct secgrp	*next;		/* Next item in the list */
1437c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group-ID */
1447c478bd9Sstevel@tonic-gate };
145*20d7339fSgww 
146*20d7339fSgww 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  *  These functions handle error and warning message writing.
1497c478bd9Sstevel@tonic-gate  *  (This deals with UNIX(r) standard message generation, so
1507c478bd9Sstevel@tonic-gate  *  the rest of the code doesn't have to.)
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  *  Functions included:
1537c478bd9Sstevel@tonic-gate  *	initmsg		Initialize the message handling functions.
1547c478bd9Sstevel@tonic-gate  *	wrtmsg		Write the message using fmtmsg().
1557c478bd9Sstevel@tonic-gate  *
1567c478bd9Sstevel@tonic-gate  *  Static data included:
1577c478bd9Sstevel@tonic-gate  *	fcnlbl		The label for standard messages
1587c478bd9Sstevel@tonic-gate  *	msgbuf		A buffer to contain the edited message
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static	char	fcnlbl[MM_MXLABELLN+1];	/* Buffer for message label */
1627c478bd9Sstevel@tonic-gate static	char	msgbuf[MM_MXTXTLN+1];	/* Buffer for message text */
163*20d7339fSgww 
164*20d7339fSgww 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * void initmsg(p)
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  *	This function initializes the message handling functions.
1697c478bd9Sstevel@tonic-gate  *
1707c478bd9Sstevel@tonic-gate  *  Arguments:
1717c478bd9Sstevel@tonic-gate  *	p	A pointer to a character string that is the name of the
1727c478bd9Sstevel@tonic-gate  *		function, used to generate the label on messages.  If this
1737c478bd9Sstevel@tonic-gate  *		string contains a slash ('/'), it only uses the characters
1747c478bd9Sstevel@tonic-gate  *		beyond the last slash in the string (this permits argv[0]
1757c478bd9Sstevel@tonic-gate  *		to be used).
1767c478bd9Sstevel@tonic-gate  *
1777c478bd9Sstevel@tonic-gate  *  Returns:  Void
1787c478bd9Sstevel@tonic-gate  */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate static void
181*20d7339fSgww initmsg(char *p)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	char   *q;	/* Local multi-use pointer */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	/* Use only the simple filename if there is a slash in the name */
186*20d7339fSgww 	if (!(q = strrchr(p, '/'))) {
187*20d7339fSgww 		q = p;
188*20d7339fSgww 	} else {
189*20d7339fSgww 		q++;
190*20d7339fSgww 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* Build the label for messages */
193*20d7339fSgww 	(void) snprintf(fcnlbl, MM_MXLABELLN, "UX:%s", q);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/* Restrict messages to the text-component */
1967c478bd9Sstevel@tonic-gate 	(void) putenv("MSGVERB=text");
1977c478bd9Sstevel@tonic-gate }
198*20d7339fSgww 
199*20d7339fSgww 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  *  void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
2027c478bd9Sstevel@tonic-gate  *
2037c478bd9Sstevel@tonic-gate  *	This function writes a message using fmtmsg()
2047c478bd9Sstevel@tonic-gate  *
2057c478bd9Sstevel@tonic-gate  *  Arguments:
2067c478bd9Sstevel@tonic-gate  *	severity	The severity-component of the message
2077c478bd9Sstevel@tonic-gate  *	action		The action-string used to generate the
2087c478bd9Sstevel@tonic-gate  *			action-component of the message
2097c478bd9Sstevel@tonic-gate  *	tag		Tag-component of the message
2107c478bd9Sstevel@tonic-gate  *	text		The text-string used to generate the text-
2117c478bd9Sstevel@tonic-gate  *			component of the message
2127c478bd9Sstevel@tonic-gate  *	txtarg		Arguments to be inserted into the "text"
2137c478bd9Sstevel@tonic-gate  *			string using vsprintf()
2147c478bd9Sstevel@tonic-gate  *
2157c478bd9Sstevel@tonic-gate  *  Returns:  Void
2167c478bd9Sstevel@tonic-gate  */
217*20d7339fSgww /*PRINTFLIKE4*/
2187c478bd9Sstevel@tonic-gate static void
2197c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	int	errorflg;	/* TRUE if problem generating message */
2227c478bd9Sstevel@tonic-gate 	va_list	argp;		/* Pointer into vararg list */
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	/* No problems yet */
2267c478bd9Sstevel@tonic-gate 	errorflg = FALSE;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/* Generate the error message */
2297c478bd9Sstevel@tonic-gate 	va_start(argp, text);
230*20d7339fSgww 	if (text != MM_NULLTXT) {
231*20d7339fSgww 		errorflg = vsnprintf(msgbuf,
232*20d7339fSgww 		    MM_MXTXTLN, text, argp) > MM_MXTXTLN;
233*20d7339fSgww 	}
2347c478bd9Sstevel@tonic-gate 	(void) fmtmsg(MM_PRINT, fcnlbl, severity,
235*20d7339fSgww 	    (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf, action, tag);
2367c478bd9Sstevel@tonic-gate 	va_end(argp);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
2397c478bd9Sstevel@tonic-gate 	 *  If there was a buffer overflow generating the error message,
2407c478bd9Sstevel@tonic-gate 	 *  write a message and quit (things are probably corrupt in the
2417c478bd9Sstevel@tonic-gate 	 *  static data space now
2427c478bd9Sstevel@tonic-gate 	 */
2437c478bd9Sstevel@tonic-gate 	if (errorflg) {
2447c478bd9Sstevel@tonic-gate 		(void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
2457c478bd9Sstevel@tonic-gate 		    gettext("Internal message buffer overflow"),
2467c478bd9Sstevel@tonic-gate 		    MM_NULLACT, MM_NULLTAG);
2477c478bd9Sstevel@tonic-gate 		exit(100);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate }
250*20d7339fSgww 
251*20d7339fSgww 
2527c478bd9Sstevel@tonic-gate /*
2537c478bd9Sstevel@tonic-gate  *  These functions allocate space for the information we gather.
2547c478bd9Sstevel@tonic-gate  *  It works by having a memory heap with strings allocated from
2557c478bd9Sstevel@tonic-gate  *  the end of the heap and structures (aligned data) allocated
2567c478bd9Sstevel@tonic-gate  *  from the beginning of the heap.  It begins with a 4k block of
2577c478bd9Sstevel@tonic-gate  *  memory then allocates memory in 4k chunks.  These functions
2587c478bd9Sstevel@tonic-gate  *  should never fail.  If they do, they report the problem and
2597c478bd9Sstevel@tonic-gate  *  exit with an exit code of 101.
2607c478bd9Sstevel@tonic-gate  *
2617c478bd9Sstevel@tonic-gate  *  Functions contained:
2627c478bd9Sstevel@tonic-gate  *	allocblk	Allocates a block of memory, aligned on a
2637c478bd9Sstevel@tonic-gate  *			4-byte (double-word) boundary.
2647c478bd9Sstevel@tonic-gate  *	allocstr	Allocates a block of memory with no
2657c478bd9Sstevel@tonic-gate  *			particular alignment
2667c478bd9Sstevel@tonic-gate  *
2677c478bd9Sstevel@tonic-gate  *  Constant definitions:
2687c478bd9Sstevel@tonic-gate  *	ALLOCBLKSZ	Size of a chunk of main memory allocated
2697c478bd9Sstevel@tonic-gate  *			using malloc()
2707c478bd9Sstevel@tonic-gate  *
2717c478bd9Sstevel@tonic-gate  *  Static data:
2727c478bd9Sstevel@tonic-gate  *	nextblkaddr	Address of the next available chunk of
2737c478bd9Sstevel@tonic-gate  *			aligned space in the heap
2747c478bd9Sstevel@tonic-gate  *	laststraddr	Address of the last chunk of unaligned space
2757c478bd9Sstevel@tonic-gate  *			allocated from the heap
2767c478bd9Sstevel@tonic-gate  *	toomuchspace	Message to write if someone attempts to allocate
2777c478bd9Sstevel@tonic-gate  *			too much space (>ALLOCBLKSZ bytes)
2787c478bd9Sstevel@tonic-gate  *	memallocdif	Message to write if there is a problem
2797c478bd9Sstevel@tonic-gate  *			allocating main menory.
2807c478bd9Sstevel@tonic-gate  */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate #define	ALLOCBLKSZ	4096
2837c478bd9Sstevel@tonic-gate 
284*20d7339fSgww static	char   *nextblkaddr = NULL;
285*20d7339fSgww static	char   *laststraddr = NULL;
2867c478bd9Sstevel@tonic-gate #define	MEMALLOCDIF	"Memory allocation difficulty.  Command terminates"
2877c478bd9Sstevel@tonic-gate #define	TOOMUCHSPACE	"Internal space allocation error.  Command terminates"
288*20d7339fSgww 
289*20d7339fSgww 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  *  void *allocblk(size)
2927c478bd9Sstevel@tonic-gate  *	unsigned int	size
2937c478bd9Sstevel@tonic-gate  *
2947c478bd9Sstevel@tonic-gate  *	This function allocates a block of aligned (4-byte or
2957c478bd9Sstevel@tonic-gate  *	double-word boundary) memory from the program's heap.
2967c478bd9Sstevel@tonic-gate  *	It returns a pointer to that block of allocated memory.
2977c478bd9Sstevel@tonic-gate  *
2987c478bd9Sstevel@tonic-gate  *  Arguments:
2997c478bd9Sstevel@tonic-gate  *	size		Minimum number of bytes to allocate (will
3007c478bd9Sstevel@tonic-gate  *			round up to multiple of 4)
3017c478bd9Sstevel@tonic-gate  *
3027c478bd9Sstevel@tonic-gate  *  Returns:  void *
3037c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static void *
307*20d7339fSgww allocblk(unsigned int size)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate 	char   *rtnval;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/* Make sure the sizes are aligned correctly */
3127c478bd9Sstevel@tonic-gate 	if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) {
3137c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
3147c478bd9Sstevel@tonic-gate 		exit(101);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	/* Set up the value we're going to return */
3187c478bd9Sstevel@tonic-gate 	rtnval = nextblkaddr;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/* Get the space we need off of the heap */
3217c478bd9Sstevel@tonic-gate 	if ((nextblkaddr += size) >= laststraddr) {
3227c478bd9Sstevel@tonic-gate 		if (!(rtnval = (char *)malloc(ALLOCBLKSZ))) {
323*20d7339fSgww 			wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG,
324*20d7339fSgww 			    gettext(MEMALLOCDIF));
3257c478bd9Sstevel@tonic-gate 			exit(101);
3267c478bd9Sstevel@tonic-gate 		}
3277c478bd9Sstevel@tonic-gate 		laststraddr = rtnval + ALLOCBLKSZ;
3287c478bd9Sstevel@tonic-gate 		nextblkaddr = rtnval + size;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/* We're through */
3327c478bd9Sstevel@tonic-gate 	return ((void *)rtnval);
3337c478bd9Sstevel@tonic-gate }
334*20d7339fSgww 
335*20d7339fSgww 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  *  char *allocstr(nbytes)
3387c478bd9Sstevel@tonic-gate  *	unsigned int	nbytes
3397c478bd9Sstevel@tonic-gate  *
3407c478bd9Sstevel@tonic-gate  *	This function allocates a block of unaligned memory from the
3417c478bd9Sstevel@tonic-gate  *	program's heap.  It returns a pointer to that block of allocated
3427c478bd9Sstevel@tonic-gate  *	memory.
3437c478bd9Sstevel@tonic-gate  *
3447c478bd9Sstevel@tonic-gate  *  Arguments:
3457c478bd9Sstevel@tonic-gate  *	nbytes		Number of bytes to allocate
3467c478bd9Sstevel@tonic-gate  *
3477c478bd9Sstevel@tonic-gate  *  Returns:  char *
3487c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
3497c478bd9Sstevel@tonic-gate  */
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate static char *
352*20d7339fSgww allocstr(unsigned int nchars)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	if (nchars > ALLOCBLKSZ) {
3557c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
3567c478bd9Sstevel@tonic-gate 		exit(101);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	if (laststraddr == NULL ||
3597c478bd9Sstevel@tonic-gate 	    (laststraddr -= nchars) < nextblkaddr) {
3607c478bd9Sstevel@tonic-gate 		if (!(nextblkaddr = (char *)malloc(ALLOCBLKSZ))) {
361*20d7339fSgww 			wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG,
362*20d7339fSgww 			    gettext(MEMALLOCDIF));
3637c478bd9Sstevel@tonic-gate 			exit(101);
3647c478bd9Sstevel@tonic-gate 		}
3657c478bd9Sstevel@tonic-gate 		laststraddr = nextblkaddr + ALLOCBLKSZ - nchars;
3667c478bd9Sstevel@tonic-gate 	}
3677c478bd9Sstevel@tonic-gate 	return (laststraddr);
3687c478bd9Sstevel@tonic-gate }
369*20d7339fSgww 
370*20d7339fSgww 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  *  These functions control the group membership list, as found in
3737c478bd9Sstevel@tonic-gate  *  the /etc/group file.
3747c478bd9Sstevel@tonic-gate  *
3757c478bd9Sstevel@tonic-gate  *  Functions included:
3767c478bd9Sstevel@tonic-gate  *	initmembers		Initialize the membership list (to NULL)
3777c478bd9Sstevel@tonic-gate  *	addmember		Adds a member to the membership list
3787c478bd9Sstevel@tonic-gate  *	isamember		Looks for a particular login-ID in the
3797c478bd9Sstevel@tonic-gate  *				list of members
3807c478bd9Sstevel@tonic-gate  *
3817c478bd9Sstevel@tonic-gate  *  Datatype Definitions:
3827c478bd9Sstevel@tonic-gate  *	struct grpmember	Describes a group member
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  *  Static Data:
3857c478bd9Sstevel@tonic-gate  *	membershead		Pointer to the head of the list of
3867c478bd9Sstevel@tonic-gate  *				group members
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate struct	grpmember {
3907c478bd9Sstevel@tonic-gate 	char			*membername;
3917c478bd9Sstevel@tonic-gate 	struct grpmember	*next;
3927c478bd9Sstevel@tonic-gate };
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate static	struct grpmember	*membershead;
395*20d7339fSgww 
396*20d7339fSgww 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  *  void initmembers()
3997c478bd9Sstevel@tonic-gate  *
4007c478bd9Sstevel@tonic-gate  *	This function initializes the list of members of specified groups.
4017c478bd9Sstevel@tonic-gate  *
4027c478bd9Sstevel@tonic-gate  *  Arguments:  None
4037c478bd9Sstevel@tonic-gate  *
4047c478bd9Sstevel@tonic-gate  *  Returns:  Void
4057c478bd9Sstevel@tonic-gate  */
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate static void
408*20d7339fSgww initmembers(void)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate 	/* Set up the members list to be a null member's list */
411*20d7339fSgww 	membershead = NULL;
4127c478bd9Sstevel@tonic-gate }
413*20d7339fSgww 
414*20d7339fSgww 
4157c478bd9Sstevel@tonic-gate /*
4167c478bd9Sstevel@tonic-gate  *  void addmember(p)
4177c478bd9Sstevel@tonic-gate  *	char   *p
4187c478bd9Sstevel@tonic-gate  *
4197c478bd9Sstevel@tonic-gate  *	This function adds a member to the group member's list.  The
4207c478bd9Sstevel@tonic-gate  *	group members list is a list of structures containing a pointer
4217c478bd9Sstevel@tonic-gate  *	to the member-name and a pointer to the next item in the
4227c478bd9Sstevel@tonic-gate  *	structure.  The structure is not ordered in any particular way.
4237c478bd9Sstevel@tonic-gate  *
4247c478bd9Sstevel@tonic-gate  *  Arguments:
4257c478bd9Sstevel@tonic-gate  *	p	Pointer to the member name
4267c478bd9Sstevel@tonic-gate  *
4277c478bd9Sstevel@tonic-gate  *  Returns:  Void
4287c478bd9Sstevel@tonic-gate  */
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate static void
431*20d7339fSgww addmember(char *p)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	struct grpmember	*new;	/* Member being added */
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	new = (struct grpmember *)allocblk(sizeof (struct grpmember));
4367c478bd9Sstevel@tonic-gate 	new->membername = strcpy(allocstr((unsigned int)strlen(p)+1), p);
4377c478bd9Sstevel@tonic-gate 	new->next = membershead;
4387c478bd9Sstevel@tonic-gate 	membershead = new;
4397c478bd9Sstevel@tonic-gate }
440*20d7339fSgww 
441*20d7339fSgww 
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate  *  init isamember(p)
4447c478bd9Sstevel@tonic-gate  *	char   *p
4457c478bd9Sstevel@tonic-gate  *
4467c478bd9Sstevel@tonic-gate  *	This function examines the list of group-members for the string
4477c478bd9Sstevel@tonic-gate  *	referenced by 'p'.  If 'p' is a member of the members list, the
4487c478bd9Sstevel@tonic-gate  *	function returns TRUE.  Otherwise it returns FALSE.
4497c478bd9Sstevel@tonic-gate  *
4507c478bd9Sstevel@tonic-gate  *  Arguments:
4517c478bd9Sstevel@tonic-gate  *	p	Pointer to the name to search for.
4527c478bd9Sstevel@tonic-gate  *
4537c478bd9Sstevel@tonic-gate  *  Returns:  int
4547c478bd9Sstevel@tonic-gate  *	TRUE	If 'p' is found in the members list,
4557c478bd9Sstevel@tonic-gate  *	FALSE	otherwise
4567c478bd9Sstevel@tonic-gate  */
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate static int
459*20d7339fSgww isamember(char *p)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	int			found;	/* TRUE if login found in list */
4627c478bd9Sstevel@tonic-gate 	struct grpmember	*pmem;	/* Group member being examined */
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/* Search the membership list for 'p' */
4667c478bd9Sstevel@tonic-gate 	found = FALSE;
4677c478bd9Sstevel@tonic-gate 	for (pmem = membershead; !found && pmem; pmem = pmem->next) {
468*20d7339fSgww 		if (strcmp(p, pmem->membername) == 0)
469*20d7339fSgww 			found = TRUE;
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	return (found);
4737c478bd9Sstevel@tonic-gate }
474*20d7339fSgww 
475*20d7339fSgww 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  *  These functions handle the display list.  The display list contains
4787c478bd9Sstevel@tonic-gate  *  all of the information we're to display.  The list contains a pointer
4797c478bd9Sstevel@tonic-gate  *  to the login-name, a pointer to the free-field (comment), and a
4807c478bd9Sstevel@tonic-gate  *  pointer to the next item in the list.  The list is ordered alpha-
4817c478bd9Sstevel@tonic-gate  *  betically (ascending) on the login-name field.  The list initially
4827c478bd9Sstevel@tonic-gate  *  contains a dummy field (to make insertion easier) that contains a
4837c478bd9Sstevel@tonic-gate  *  login-name of "".
4847c478bd9Sstevel@tonic-gate  *
4857c478bd9Sstevel@tonic-gate  *  Functions included:
4867c478bd9Sstevel@tonic-gate  *	initdisp	Initializes the display list
4877c478bd9Sstevel@tonic-gate  *	adddisp		Adds information to the display list
4887c478bd9Sstevel@tonic-gate  *	isuidindisp	Looks to see if a particular user-ID is in the
4897c478bd9Sstevel@tonic-gate  *			display list
4907c478bd9Sstevel@tonic-gate  *	genreport	Generates a report from the items in the display
4917c478bd9Sstevel@tonic-gate  *			list
4927c478bd9Sstevel@tonic-gate  *	applygroup	Add group information to the items in the display
4937c478bd9Sstevel@tonic-gate  *			list
4947c478bd9Sstevel@tonic-gate  *	applypasswd	Add extended password information to the items
4957c478bd9Sstevel@tonic-gate  *			in the display list
4967c478bd9Sstevel@tonic-gate  *
4977c478bd9Sstevel@tonic-gate  *  Datatypes Defined:
4987c478bd9Sstevel@tonic-gate  *	struct display	Describes the structure that contains the information
4997c478bd9Sstevel@tonic-gate  *			to be displayed.  Includes pointers to the login-ID,
5007c478bd9Sstevel@tonic-gate  *			free-field (comment), and the next structure in the
5017c478bd9Sstevel@tonic-gate  *			list.
5027c478bd9Sstevel@tonic-gate  *
5037c478bd9Sstevel@tonic-gate  *  Static Data:
5047c478bd9Sstevel@tonic-gate  *	displayhead	Pointer to the head of the display list.  Initially
5057c478bd9Sstevel@tonic-gate  *			references the null-item on the head of the list.
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate struct	display {
5097c478bd9Sstevel@tonic-gate 	char		*loginID;	/* Login name */
5107c478bd9Sstevel@tonic-gate 	char		*freefield;	/* Free (comment) field */
5117c478bd9Sstevel@tonic-gate 	char		*groupname;	/* Name of the primary group */
5127c478bd9Sstevel@tonic-gate 	char		*iwd;		/* Initial working directory */
5137c478bd9Sstevel@tonic-gate 	char		*shell;		/* Shell after login (may be null) */
5147c478bd9Sstevel@tonic-gate 	struct pwdinfo	*passwdinfo;	/* Password information structure */
5157c478bd9Sstevel@tonic-gate 	struct secgrp 	*secgrplist; 	/* Head of the secondary group list */
5167c478bd9Sstevel@tonic-gate 	uid_t		userID;		/* User ID */
5177c478bd9Sstevel@tonic-gate 	gid_t		groupID;	/* Group ID of primary group */
5187c478bd9Sstevel@tonic-gate 	struct display	*nextlogin;	/* Next login in the list */
5197c478bd9Sstevel@tonic-gate 	struct display	*nextuid;	/* Next user-ID in the list */
5207c478bd9Sstevel@tonic-gate };
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate static	struct display	*displayhead;
523*20d7339fSgww 
524*20d7339fSgww 
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate  *  void initdisp()
5277c478bd9Sstevel@tonic-gate  *
5287c478bd9Sstevel@tonic-gate  *	Initializes the display list.  An empty display list contains
5297c478bd9Sstevel@tonic-gate  *	a single element, the dummy element.
5307c478bd9Sstevel@tonic-gate  *
5317c478bd9Sstevel@tonic-gate  *  Arguments:  None
5327c478bd9Sstevel@tonic-gate  *
5337c478bd9Sstevel@tonic-gate  *  Returns:  Void
5347c478bd9Sstevel@tonic-gate  */
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate static void
537*20d7339fSgww initdisp(void)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	displayhead = (struct display *)allocblk(sizeof (struct display));
540*20d7339fSgww 	displayhead->nextlogin = NULL;
541*20d7339fSgww 	displayhead->nextuid = NULL;
5427c478bd9Sstevel@tonic-gate 	displayhead->loginID = "";
5437c478bd9Sstevel@tonic-gate 	displayhead->freefield = "";
5447c478bd9Sstevel@tonic-gate 	displayhead->userID = -1;
5457c478bd9Sstevel@tonic-gate }
546*20d7339fSgww 
547*20d7339fSgww 
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate  *  void adddisp(pwent)
5507c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
5517c478bd9Sstevel@tonic-gate  *
5527c478bd9Sstevel@tonic-gate  *	This function adds the appropriate information from the login
5537c478bd9Sstevel@tonic-gate  *	description referenced by 'pwent' to the list if information
5547c478bd9Sstevel@tonic-gate  *	to be displayed.  It only adds the information if the login-ID
5557c478bd9Sstevel@tonic-gate  *	(user-name) is unique.  It inserts the information in the list
5567c478bd9Sstevel@tonic-gate  *	in such a way that the list remains ordered alphabetically
5577c478bd9Sstevel@tonic-gate  *	(ascending) according to the login-ID (user-name).
5587c478bd9Sstevel@tonic-gate  *
5597c478bd9Sstevel@tonic-gate  *  Arguments:
5607c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains all of the login information
5617c478bd9Sstevel@tonic-gate  *			of the login being added to the list.  The only
5627c478bd9Sstevel@tonic-gate  *			information that this function uses is the login-ID
5637c478bd9Sstevel@tonic-gate  *			(user-name) and the free-field (comment field).
5647c478bd9Sstevel@tonic-gate  *
5657c478bd9Sstevel@tonic-gate  *  Returns:  Void
5667c478bd9Sstevel@tonic-gate  */
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate static void
569*20d7339fSgww adddisp(struct passwd *pwent)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	struct display *new;		/* Item being added to the list */
5727c478bd9Sstevel@tonic-gate 	struct display *prev;		/* Previous item in the list */
5737c478bd9Sstevel@tonic-gate 	struct display *current;	/* Next item in the list */
5747c478bd9Sstevel@tonic-gate 	int		found;		/* FLAG, insertion point found */
5757c478bd9Sstevel@tonic-gate 	int		compare = 1;	/* strcmp() compare value */
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/* Find where this value belongs in the list */
5797c478bd9Sstevel@tonic-gate 	prev = displayhead;
5807c478bd9Sstevel@tonic-gate 	found = FALSE;
581*20d7339fSgww 	while (!found && (current = prev->nextlogin)) {
582*20d7339fSgww 		if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) {
583*20d7339fSgww 			found = TRUE;
584*20d7339fSgww 		} else {
585*20d7339fSgww 			prev = current;
586*20d7339fSgww 		}
5877c478bd9Sstevel@tonic-gate 
588*20d7339fSgww 	}
5897c478bd9Sstevel@tonic-gate 	/* Insert this value in the list, only if it is unique though */
5907c478bd9Sstevel@tonic-gate 	if (compare != 0) {
5917c478bd9Sstevel@tonic-gate 		new = (struct display *)allocblk(sizeof (struct display));
592*20d7339fSgww 		new->loginID = strcpy(allocstr(
593*20d7339fSgww 		    (unsigned int)strlen(pwent->pw_name)+1), pwent->pw_name);
594*20d7339fSgww 		if (pwent->pw_comment && pwent->pw_comment[0] != '\0') {
595*20d7339fSgww 			new->freefield = strcpy(allocstr(
596*20d7339fSgww 			    (unsigned int)strlen(pwent->pw_comment)+1),
5977c478bd9Sstevel@tonic-gate 			    pwent->pw_comment);
598*20d7339fSgww 		} else {
599*20d7339fSgww 		    new->freefield = strcpy(allocstr(
600*20d7339fSgww 			(unsigned int)strlen(pwent->pw_gecos)+1),
6017c478bd9Sstevel@tonic-gate 			pwent->pw_gecos);
602*20d7339fSgww 		}
603*20d7339fSgww 		if (!pwent->pw_shell || !(*pwent->pw_shell)) {
604*20d7339fSgww 			new->shell = "/sbin/sh";
605*20d7339fSgww 		} else {
606*20d7339fSgww 			new->shell = strcpy(allocstr(
607*20d7339fSgww 			    (unsigned int)strlen(pwent->pw_shell)+1),
608*20d7339fSgww 			    pwent->pw_shell);
609*20d7339fSgww 		}
610*20d7339fSgww 		new->iwd = strcpy(allocstr(
611*20d7339fSgww 		    (unsigned int)strlen(pwent->pw_dir)+1), pwent->pw_dir);
6127c478bd9Sstevel@tonic-gate 		new->userID = pwent->pw_uid;
6137c478bd9Sstevel@tonic-gate 		new->groupID = pwent->pw_gid;
614*20d7339fSgww 		new->secgrplist = NULL;
615*20d7339fSgww 		new->passwdinfo = NULL;
616*20d7339fSgww 		new->groupname = NULL;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 		/* Add new display item to the list ordered by login-ID */
6197c478bd9Sstevel@tonic-gate 		new->nextlogin = current;
6207c478bd9Sstevel@tonic-gate 		prev->nextlogin = new;
6217c478bd9Sstevel@tonic-gate 
622*20d7339fSgww 		/*
623*20d7339fSgww 		 * Find the appropriate place for the new item in the list
624*20d7339fSgww 		 * ordered by userID
625*20d7339fSgww 		 */
6267c478bd9Sstevel@tonic-gate 		prev = displayhead;
6277c478bd9Sstevel@tonic-gate 		found = FALSE;
628*20d7339fSgww 		while (!found && (current = prev->nextuid)) {
629*20d7339fSgww 			if (current->userID > pwent->pw_uid) {
630*20d7339fSgww 				found = TRUE;
631*20d7339fSgww 			} else {
632*20d7339fSgww 				prev = current;
633*20d7339fSgww 			}
634*20d7339fSgww 		}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		/* Add the item into the list that is ordered by user-ID */
6377c478bd9Sstevel@tonic-gate 		new->nextuid = current;
6387c478bd9Sstevel@tonic-gate 		prev->nextuid = new;
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate }
641*20d7339fSgww 
642*20d7339fSgww 
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate  *  int isuidindisp(pwent)
6457c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
6467c478bd9Sstevel@tonic-gate  *
6477c478bd9Sstevel@tonic-gate  *  This function examines the display list to see if the uid in
6487c478bd9Sstevel@tonic-gate  *  the (struct passwd) referenced by "pwent" is already in the
6497c478bd9Sstevel@tonic-gate  *  display list.  It returns TRUE if it is in the list, FALSE
6507c478bd9Sstevel@tonic-gate  *  otherwise.
6517c478bd9Sstevel@tonic-gate  *
6527c478bd9Sstevel@tonic-gate  *  Since the display list is ordered by user-ID, the search continues
6537c478bd9Sstevel@tonic-gate  *  until a match is found or a user-ID is found that is larger than
6547c478bd9Sstevel@tonic-gate  *  the one we're searching for.
6557c478bd9Sstevel@tonic-gate  *
6567c478bd9Sstevel@tonic-gate  *  Arguments:
6577c478bd9Sstevel@tonic-gate  *	pwent		Structure that contains the user-ID we're to
6587c478bd9Sstevel@tonic-gate  *			look for
6597c478bd9Sstevel@tonic-gate  *
6607c478bd9Sstevel@tonic-gate  *  Returns:  int
6617c478bd9Sstevel@tonic-gate  *	TRUE if the user-ID was found, FALSE otherwise.
6627c478bd9Sstevel@tonic-gate  */
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate static int
665*20d7339fSgww isuidindisp(struct passwd *pwent)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	struct display *dp;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/*
6717c478bd9Sstevel@tonic-gate 	 *  Search the list, beginning at the beginning (where else?)
6727c478bd9Sstevel@tonic-gate 	 *  and stopping when the user-ID is found or one is found that
6737c478bd9Sstevel@tonic-gate 	 *  is greater than the user-ID we're searching for.  Recall
6747c478bd9Sstevel@tonic-gate 	 *  that this list is ordered by user-ID
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 
677*20d7339fSgww 	for (dp = displayhead->nextuid; dp && (dp->userID < pwent->pw_uid);
678*20d7339fSgww 	    dp = dp->nextuid) {
679*20d7339fSgww 		continue;
680*20d7339fSgww 	}
6817c478bd9Sstevel@tonic-gate 
682*20d7339fSgww 	/*
683*20d7339fSgww 	 * If the pointer "dp" points to a structure that has a
684*20d7339fSgww 	 * matching user-ID, return TRUE.  Otherwise FALSE
685*20d7339fSgww 	 */
6867c478bd9Sstevel@tonic-gate 	return (dp && (dp->userID == pwent->pw_uid));
6877c478bd9Sstevel@tonic-gate }
688*20d7339fSgww 
689*20d7339fSgww 
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  *  void applygroup(allgroups)
6927c478bd9Sstevel@tonic-gate  *	int	allgroups
6937c478bd9Sstevel@tonic-gate  *
6947c478bd9Sstevel@tonic-gate  *  This function applies group information to the login-IDs in the
6957c478bd9Sstevel@tonic-gate  *  display list.  It always applies the primary group information.
6967c478bd9Sstevel@tonic-gate  *  If "allgroups" is TRUE, it applies secondary information as well.
6977c478bd9Sstevel@tonic-gate  *
6987c478bd9Sstevel@tonic-gate  *  Arguments:
6997c478bd9Sstevel@tonic-gate  * 	allgroups	FLAG.  TRUE if secondary group info is to be
7007c478bd9Sstevel@tonic-gate  *			applied -- FALSE otherwise.
7017c478bd9Sstevel@tonic-gate  *
7027c478bd9Sstevel@tonic-gate  *  Returns:  void
7037c478bd9Sstevel@tonic-gate  */
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate static void
706*20d7339fSgww applygroup(int allgroups)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	struct display	*dp;		/* Display list running ptr */
7097c478bd9Sstevel@tonic-gate 	struct group	*grent;		/* Group info, from getgrent() */
7107c478bd9Sstevel@tonic-gate 	char		*p;		/* Temp char pointer */
7117c478bd9Sstevel@tonic-gate 	char		**pp;		/* Temp char * pointer */
7127c478bd9Sstevel@tonic-gate 	int		compare;	/* Value from strcmp() */
7137c478bd9Sstevel@tonic-gate 	int		done;		/* TRUE if finished, FALSE otherwise */
7147c478bd9Sstevel@tonic-gate 	struct secgrp	*psecgrp;	/* Block allocated for this info */
7157c478bd9Sstevel@tonic-gate 	struct secgrp	*psrch;		/* Secondary group -- for searching */
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	/* For each group-ID in the /etc/group file ... */
7197c478bd9Sstevel@tonic-gate 	while (grent = getgrent()) {
7207c478bd9Sstevel@tonic-gate 		/*
7217c478bd9Sstevel@tonic-gate 		 *  Set the primary group for the login-IDs in the display
7227c478bd9Sstevel@tonic-gate 		 *  list.  For each group-ID we get, leaf through the display
7237c478bd9Sstevel@tonic-gate 		 *  list and set the group-name if the group-IDs match
7247c478bd9Sstevel@tonic-gate 		 */
7257c478bd9Sstevel@tonic-gate 
726*20d7339fSgww 		p = NULL;
727*20d7339fSgww 		for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
7287c478bd9Sstevel@tonic-gate 			if ((dp->groupID == grent->gr_gid) && !dp->groupname) {
729*20d7339fSgww 				if (!p) {
730*20d7339fSgww 					p = strcpy(allocstr(
731*20d7339fSgww 					    (unsigned int)strlen(
732*20d7339fSgww 					    grent->gr_name)+1), grent->gr_name);
733*20d7339fSgww 				}
7347c478bd9Sstevel@tonic-gate 				dp->groupname = p;
7357c478bd9Sstevel@tonic-gate 			}
736*20d7339fSgww 		}
7377c478bd9Sstevel@tonic-gate 
738*20d7339fSgww 		if (!allgroups) {
739*20d7339fSgww 			continue;
740*20d7339fSgww 		}
7417c478bd9Sstevel@tonic-gate 		/*
7427c478bd9Sstevel@tonic-gate 		 *  If we're to be displaying secondary group membership,
7437c478bd9Sstevel@tonic-gate 		 *  leaf through the list of group members.  Then, attempt
7447c478bd9Sstevel@tonic-gate 		 *  to find that member in the display list.  When found,
7457c478bd9Sstevel@tonic-gate 		 *  attach secondary group info to the user.
7467c478bd9Sstevel@tonic-gate 		 */
7477c478bd9Sstevel@tonic-gate 
748*20d7339fSgww 		for (pp = grent->gr_mem; *pp; pp++) {
7497c478bd9Sstevel@tonic-gate 			done = FALSE;
750*20d7339fSgww 			for (dp = displayhead->nextlogin; !done && dp;
751*20d7339fSgww 			    dp = dp->nextlogin) {
752*20d7339fSgww 				if (((compare = strcmp(dp->loginID,
753*20d7339fSgww 				    *pp)) == 0) &&
754*20d7339fSgww 				    !(grent->gr_gid == dp->groupID)) {
755*20d7339fSgww 					if (!p) {
756*20d7339fSgww 						p = strcpy(allocstr(
757*20d7339fSgww 						    (unsigned int)strlen(
758*20d7339fSgww 						    grent->gr_name)+1),
759*20d7339fSgww 						    grent->gr_name);
760*20d7339fSgww 					}
761*20d7339fSgww 					psecgrp = (struct secgrp *)allocblk(
762*20d7339fSgww 					    sizeof (struct secgrp));
7637c478bd9Sstevel@tonic-gate 					psecgrp->groupID = grent->gr_gid;
7647c478bd9Sstevel@tonic-gate 					psecgrp->groupname = p;
765*20d7339fSgww 					psecgrp->next = NULL;
766*20d7339fSgww 					if (!dp->secgrplist) {
767*20d7339fSgww 						dp->secgrplist = psecgrp;
768*20d7339fSgww 					} else {
769*20d7339fSgww 						for (psrch = dp->secgrplist;
770*20d7339fSgww 						    psrch->next;
771*20d7339fSgww 						    psrch = psrch->next) {
772*20d7339fSgww 							continue;
773*20d7339fSgww 						}
7747c478bd9Sstevel@tonic-gate 						psrch->next = psecgrp;
7757c478bd9Sstevel@tonic-gate 					}
7767c478bd9Sstevel@tonic-gate 					done = TRUE;
777*20d7339fSgww 				} else if (compare > 0) {
778*20d7339fSgww 						done = TRUE;
7797c478bd9Sstevel@tonic-gate 				}
7807c478bd9Sstevel@tonic-gate 			}
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	/* Close the /etc/group file */
7857c478bd9Sstevel@tonic-gate 	endgrent();
7867c478bd9Sstevel@tonic-gate }
787*20d7339fSgww 
788*20d7339fSgww 
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate  *  void applypasswd()
7917c478bd9Sstevel@tonic-gate  *
7927c478bd9Sstevel@tonic-gate  *	This function applies extended password information to an item
7937c478bd9Sstevel@tonic-gate  *	to be displayed.  It allocates space for a structure describing
7947c478bd9Sstevel@tonic-gate  *	the password, then fills in that structure from the information
7957c478bd9Sstevel@tonic-gate  *	in the /etc/shadow file.
7967c478bd9Sstevel@tonic-gate  *
7977c478bd9Sstevel@tonic-gate  *  Arguments:  None
7987c478bd9Sstevel@tonic-gate  *
7997c478bd9Sstevel@tonic-gate  *  Returns:  Void
8007c478bd9Sstevel@tonic-gate  */
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate static void
803*20d7339fSgww applypasswd(void)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	struct pwdinfo	*ppasswd;	/* Ptr to pwd desc in current element */
8067c478bd9Sstevel@tonic-gate 	struct display	*dp;		/* Ptr to current element */
8077c478bd9Sstevel@tonic-gate 	struct spwd	*psp;		/* Pointer to a shadow-file entry */
8087c478bd9Sstevel@tonic-gate 	struct tm	*ptm;		/* Pointer to a time-of-day structure */
8097c478bd9Sstevel@tonic-gate 	char		*p;		/* Running character pointer */
8107c478bd9Sstevel@tonic-gate 	time_t		pwchg;		/* System-time of last pwd chg */
8117c478bd9Sstevel@tonic-gate 	time_t		pwexp;		/* System-time of password expiration */
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	/*  Make sure the shadow file is rewound  */
8157c478bd9Sstevel@tonic-gate 	setspent();
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/*
8197c478bd9Sstevel@tonic-gate 	 *  For each item in the display list...
8207c478bd9Sstevel@tonic-gate 	 */
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 		/* Allocate structure space for the password description */
8257c478bd9Sstevel@tonic-gate 		ppasswd = (struct pwdinfo *)allocblk(sizeof (struct pwdinfo));
8267c478bd9Sstevel@tonic-gate 		dp->passwdinfo = ppasswd;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		/*
8297c478bd9Sstevel@tonic-gate 		 * If there's no entry in the /etc/shadow file, assume
8307c478bd9Sstevel@tonic-gate 		 * that the login is locked
8317c478bd9Sstevel@tonic-gate 		 */
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		if (!(psp = getspnam(dp->loginID))) {
8347c478bd9Sstevel@tonic-gate 			pwchg = 0L;			/* Epoch */
8357c478bd9Sstevel@tonic-gate 			ppasswd->passwdstatus = "LK";	/* LK, Locked */
8367c478bd9Sstevel@tonic-gate 			ppasswd->mindaystilchg = 0L;
8377c478bd9Sstevel@tonic-gate 			ppasswd->maxdaystilchg = 0L;
8387c478bd9Sstevel@tonic-gate 			ppasswd->warninterval = 0L;
8397c478bd9Sstevel@tonic-gate 			ppasswd->inactive = 0L;
8407c478bd9Sstevel@tonic-gate 			pwexp = 0L;
841*20d7339fSgww 		} else {
8427c478bd9Sstevel@tonic-gate 			/*
8437c478bd9Sstevel@tonic-gate 			 * Otherwise, fill in the password information from the
8447c478bd9Sstevel@tonic-gate 			 * info in the shadow file entry
8457c478bd9Sstevel@tonic-gate 			 */
8467c478bd9Sstevel@tonic-gate 			/*  See if the login has no password  */
847*20d7339fSgww 			if (!psp->sp_pwdp || !(*psp->sp_pwdp)) {
848*20d7339fSgww 				ppasswd->passwdstatus = "NP";
849*20d7339fSgww 			} else if (strlen(psp->sp_pwdp) != 13) {
8507c478bd9Sstevel@tonic-gate 				/*
851*20d7339fSgww 				 * See if the login is explicitly locked
852*20d7339fSgww 				 * (encrypted password is <13 characters)
8537c478bd9Sstevel@tonic-gate 				 */
854*20d7339fSgww 				ppasswd->passwdstatus = "LK";
855*20d7339fSgww 			} else {
8567c478bd9Sstevel@tonic-gate 				/*
857*20d7339fSgww 				 * If it's a valid encrypted password,
858*20d7339fSgww 				 * the login is password protected
8597c478bd9Sstevel@tonic-gate 				 */
8607c478bd9Sstevel@tonic-gate 				ppasswd->passwdstatus = "PS";
8617c478bd9Sstevel@tonic-gate 				for (p = psp->sp_pwdp; *p; p++) {
862*20d7339fSgww 					if (!isalnum(*p) &&
863*20d7339fSgww 					    (*p != '.') &&
864*20d7339fSgww 					    (*p != '/')) {
8657c478bd9Sstevel@tonic-gate 						ppasswd->passwdstatus = "LK";
8667c478bd9Sstevel@tonic-gate 						break;
8677c478bd9Sstevel@tonic-gate 					}
8687c478bd9Sstevel@tonic-gate 				}
8697c478bd9Sstevel@tonic-gate 			}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 			/*
872*20d7339fSgww 			 * Set up the last-changed date,
873*20d7339fSgww 			 * the minimum days between changes,
874*20d7339fSgww 			 * the maximum life of a password,
875*20d7339fSgww 			 * the interval before expiration that the user
876*20d7339fSgww 			 * is warned,
877*20d7339fSgww 			 * the number of days a login can be inactive before
878*20d7339fSgww 			 * it expires, and the login expiration date
8797c478bd9Sstevel@tonic-gate 			 */
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 			pwchg = psp->sp_lstchg;
8827c478bd9Sstevel@tonic-gate 			ppasswd->mindaystilchg = psp->sp_min;
8837c478bd9Sstevel@tonic-gate 			ppasswd->maxdaystilchg = psp->sp_max;
8847c478bd9Sstevel@tonic-gate 			ppasswd->warninterval = psp->sp_warn;
8857c478bd9Sstevel@tonic-gate 			ppasswd->inactive = psp->sp_inact;
8867c478bd9Sstevel@tonic-gate 			pwexp = psp->sp_expire;
8877c478bd9Sstevel@tonic-gate 		}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		/*
8907c478bd9Sstevel@tonic-gate 		 * Convert the date of the last password change from days-
8917c478bd9Sstevel@tonic-gate 		 * since-epoch to mmddyy (integer) form.  Involves the
8927c478bd9Sstevel@tonic-gate 		 * intermediate step of converting the date from days-
8937c478bd9Sstevel@tonic-gate 		 * since-epoch to seconds-since-epoch.  We'll set this to
8947c478bd9Sstevel@tonic-gate 		 * somewhere near the middle of the day, since there are not
8957c478bd9Sstevel@tonic-gate 		 * always 24*60*60 seconds in a year.  (Yeech)
8967c478bd9Sstevel@tonic-gate 		 *
8977c478bd9Sstevel@tonic-gate 		 * Note:  The form mmddyy should probably be subject to
8987c478bd9Sstevel@tonic-gate 		 * internationalization -- Non-Americans will think that
8997c478bd9Sstevel@tonic-gate 		 * 070888 is 07 August 88 when the software is trying to say
9007c478bd9Sstevel@tonic-gate 		 * 08 July 88.  Systems Engineers seem to think that this isn't
9017c478bd9Sstevel@tonic-gate 		 * a problem though...
9027c478bd9Sstevel@tonic-gate 		 */
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 		if (pwchg != -1L) {
9057c478bd9Sstevel@tonic-gate 			pwchg = (pwchg * DAY) + (DAY/2);
9067c478bd9Sstevel@tonic-gate 			ptm = localtime(&pwchg);
9077c478bd9Sstevel@tonic-gate 			ppasswd->datechg = ((long)(ptm->tm_mon+1) * 10000L) +
9087c478bd9Sstevel@tonic-gate 			    (long)((ptm->tm_mday * 100) +
9097c478bd9Sstevel@tonic-gate 			    (ptm->tm_year % 100));
910*20d7339fSgww 		} else {
911*20d7339fSgww 			ppasswd->datechg = 0L;
912*20d7339fSgww 		}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 		/*
9157c478bd9Sstevel@tonic-gate 		 * Convert the passwd expiration date from days-since-epoch
9167c478bd9Sstevel@tonic-gate 		 * to mmddyy (long integer) form using the same algorithm and
9177c478bd9Sstevel@tonic-gate 		 * comments as above.
9187c478bd9Sstevel@tonic-gate 		 */
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		if (pwexp != -1L) {
9217c478bd9Sstevel@tonic-gate 			pwexp = (pwexp * DAY) + (DAY/2);
9227c478bd9Sstevel@tonic-gate 			ptm = localtime(&pwexp);
9237c478bd9Sstevel@tonic-gate 			ppasswd->expdate = ((long)(ptm->tm_mon+1) * 10000L) +
9247c478bd9Sstevel@tonic-gate 			    (long)((ptm->tm_mday * 100) +
9257c478bd9Sstevel@tonic-gate 			    (ptm->tm_year % 100));
926*20d7339fSgww 		} else {
927*20d7339fSgww 			ppasswd->expdate = 0L;
928*20d7339fSgww 		}
9297c478bd9Sstevel@tonic-gate 	}
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	/* Close the shadow password file */
9327c478bd9Sstevel@tonic-gate 	endspent();
9337c478bd9Sstevel@tonic-gate }
934*20d7339fSgww 
935*20d7339fSgww 
9367c478bd9Sstevel@tonic-gate /*
9377c478bd9Sstevel@tonic-gate  * int hasnopasswd(pwent)
9387c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
9397c478bd9Sstevel@tonic-gate  *
9407c478bd9Sstevel@tonic-gate  *	This function examines a login's password-file entry
9417c478bd9Sstevel@tonic-gate  *	and, if necessary, its shadow password-file entry and
9427c478bd9Sstevel@tonic-gate  *	returns TRUE if that user-ID has no password, meaning
9437c478bd9Sstevel@tonic-gate  *	that the user-ID can be used to log into the system
9447c478bd9Sstevel@tonic-gate  *	without giving a password.  The function returns FALSE
9457c478bd9Sstevel@tonic-gate  *	otherwise.
9467c478bd9Sstevel@tonic-gate  *
9477c478bd9Sstevel@tonic-gate  *  Arguments:
9487c478bd9Sstevel@tonic-gate  *	pwent	Login to examine.
9497c478bd9Sstevel@tonic-gate  *
9507c478bd9Sstevel@tonic-gate  *  Returns:  int
9517c478bd9Sstevel@tonic-gate  *	TRUE if the login can be used without a password, FALSE
9527c478bd9Sstevel@tonic-gate  *	otherwise.
9537c478bd9Sstevel@tonic-gate  */
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate static int
956*20d7339fSgww hasnopasswd(struct passwd *pwent)
9577c478bd9Sstevel@tonic-gate {
9587c478bd9Sstevel@tonic-gate 	struct spwd    *psp;		/* /etc/shadow file struct */
9597c478bd9Sstevel@tonic-gate 	int		nopwflag;	/* TRUE if login has no passwd */
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	/*
9627c478bd9Sstevel@tonic-gate 	 *  A login has no password if:
9637c478bd9Sstevel@tonic-gate 	 *    1.  There exists an entry for that login in the
9647c478bd9Sstevel@tonic-gate 	 *	  shadow password-file (/etc/passwd), and
9657c478bd9Sstevel@tonic-gate 	 *    2.  The encrypted password in the structure describing
966*20d7339fSgww 	 *	  that entry is either:	 NULL or a null string ("")
9677c478bd9Sstevel@tonic-gate 	 */
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/* Get the login's entry in the shadow password file */
9707c478bd9Sstevel@tonic-gate 	if (psp = getspnam(pwent->pw_name)) {
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		/* Look at the encrypted password in that entry */
9737c478bd9Sstevel@tonic-gate 		if (psp->sp_pwdp == (char *)0 ||
974*20d7339fSgww 		    *psp->sp_pwdp == '\0') {
9757c478bd9Sstevel@tonic-gate 			nopwflag = TRUE;
976*20d7339fSgww 		} else {
9777c478bd9Sstevel@tonic-gate 			nopwflag = FALSE;
9787c478bd9Sstevel@tonic-gate 		}
979*20d7339fSgww 	} else {
9807c478bd9Sstevel@tonic-gate 		nopwflag = FALSE;
981*20d7339fSgww 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/* Done ... */
9847c478bd9Sstevel@tonic-gate 	return (nopwflag);
9857c478bd9Sstevel@tonic-gate }
986*20d7339fSgww 
987*20d7339fSgww 
9887c478bd9Sstevel@tonic-gate /*
9897c478bd9Sstevel@tonic-gate  *  void writeunformatted(current, xtndflag, expflag)
9907c478bd9Sstevel@tonic-gate  *	struct display *current
9917c478bd9Sstevel@tonic-gate  *	int		xtndflag
9927c478bd9Sstevel@tonic-gate  *	int		expflag
9937c478bd9Sstevel@tonic-gate  *
9947c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
9957c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in the
9967c478bd9Sstevel@tonic-gate  *  form of a colon-list.  It writes secondary group information if
9977c478bd9Sstevel@tonic-gate  *  that information is in the structure, it writes extended
9987c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info
9997c478bd9Sstevel@tonic-gate  *  if the "xtndflag" is TRUE, and it writes password expiration
10007c478bd9Sstevel@tonic-gate  *  information if "expflag" is TRUE.
10017c478bd9Sstevel@tonic-gate  *
10027c478bd9Sstevel@tonic-gate  *  Arguments:
10037c478bd9Sstevel@tonic-gate  *	current		Structure containing information to write.
10047c478bd9Sstevel@tonic-gate  *	xtndflag	TRUE if extended information is to be written,
10057c478bd9Sstevel@tonic-gate  *			FALSE otherwise
10067c478bd9Sstevel@tonic-gate  *	expflag		TRUE if password expiration information is to
10077c478bd9Sstevel@tonic-gate  *			be written, FALSE otherwise
10087c478bd9Sstevel@tonic-gate  *
10097c478bd9Sstevel@tonic-gate  *  Returns:  void
10107c478bd9Sstevel@tonic-gate  */
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate static void
1013*20d7339fSgww writeunformatted(struct display *current, int xtndflag, int expflag)
10147c478bd9Sstevel@tonic-gate {
10157c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
10167c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	/* Write the general information */
10197c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%s:%ld:%s:%ld:%s",
10207c478bd9Sstevel@tonic-gate 	    current->loginID,
10217c478bd9Sstevel@tonic-gate 	    current->userID,
1022*20d7339fSgww 	    current->groupname == NULL ? "" : current->groupname,
10237c478bd9Sstevel@tonic-gate 	    current->groupID,
10247c478bd9Sstevel@tonic-gate 	    current->freefield);
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/*
10277c478bd9Sstevel@tonic-gate 	 * If the group information is there, write it (it's only
10287c478bd9Sstevel@tonic-gate 	 * there if it's supposed to be written)
10297c478bd9Sstevel@tonic-gate 	 */
1030*20d7339fSgww 	for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
1031*20d7339fSgww 		(void) fprintf(stdout, ":%s:%ld",
1032*20d7339fSgww 		    psecgrp->groupname, psecgrp->groupID);
1033*20d7339fSgww 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	/* If the extended info flag is TRUE, write the extended information */
10367c478bd9Sstevel@tonic-gate 	if (xtndflag) {
10377c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
10387c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, ":%s:%s:%s:%6.6ld:%ld:%ld:%ld",
10397c478bd9Sstevel@tonic-gate 		    current->iwd, current->shell,
10407c478bd9Sstevel@tonic-gate 		    pwdinfo->passwdstatus,
10417c478bd9Sstevel@tonic-gate 		    pwdinfo->datechg,
10427c478bd9Sstevel@tonic-gate 		    pwdinfo->mindaystilchg, pwdinfo->maxdaystilchg,
10437c478bd9Sstevel@tonic-gate 		    pwdinfo->warninterval);
10447c478bd9Sstevel@tonic-gate 	}
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	/* If the password expiration information is requested, write it.  */
10477c478bd9Sstevel@tonic-gate 	if (expflag) {
10487c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
1049*20d7339fSgww 		(void) fprintf(stdout, ":%ld:%ld",
1050*20d7339fSgww 		    pwdinfo->inactive, pwdinfo->expdate);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	/* Terminate the information with a new-line */
10547c478bd9Sstevel@tonic-gate 	(void) putc('\n', stdout);
10557c478bd9Sstevel@tonic-gate }
1056*20d7339fSgww 
1057*20d7339fSgww 
10587c478bd9Sstevel@tonic-gate /*
10597c478bd9Sstevel@tonic-gate  *  void writeformatted(current, xtndflag, expflag)
10607c478bd9Sstevel@tonic-gate  *	struct display *current
10617c478bd9Sstevel@tonic-gate  *	int		xtndflag
10627c478bd9Sstevel@tonic-gate  *	int		expflag
10637c478bd9Sstevel@tonic-gate  *
10647c478bd9Sstevel@tonic-gate  *  This function writes the data in the display structure "current"
10657c478bd9Sstevel@tonic-gate  *  to the standard output file.  It writes the information in an
10667c478bd9Sstevel@tonic-gate  *  easily readable format.  It writes secondary group information
10677c478bd9Sstevel@tonic-gate  *  if that information is in the structure, it writes extended
10687c478bd9Sstevel@tonic-gate  *  (initial working directory, shell, and password-aging) info if
10697c478bd9Sstevel@tonic-gate  *  "xtndflag" is TRUE, and it write password expiration information
10707c478bd9Sstevel@tonic-gate  *  if "expflag" is TRUE.
10717c478bd9Sstevel@tonic-gate  *
10727c478bd9Sstevel@tonic-gate  *  Arguments:
10737c478bd9Sstevel@tonic-gate  *	current		Structure containing info to write.
1074*20d7339fSgww  *	xtndflag	TRUE if extended information to be written,
10757c478bd9Sstevel@tonic-gate  *			FALSE otherwise
1076*20d7339fSgww  *	expflag 	TRUE if password expiration information to be written,
10777c478bd9Sstevel@tonic-gate  *			FALSE otherwise
10787c478bd9Sstevel@tonic-gate  *
10797c478bd9Sstevel@tonic-gate  *  Returns:  void
10807c478bd9Sstevel@tonic-gate  */
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate static void
1083*20d7339fSgww writeformatted(struct display *current, int xtndflag, int expflag)
10847c478bd9Sstevel@tonic-gate {
10857c478bd9Sstevel@tonic-gate 	struct secgrp  *psecgrp;	/* Secondary group info */
10867c478bd9Sstevel@tonic-gate 	struct pwdinfo *pwdinfo;	/* Password aging info */
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/* Write general information */
10897c478bd9Sstevel@tonic-gate 	(void) fprintf(stdout, "%-14s  %-6ld  %-14s  %-6ld  %s\n",
10907c478bd9Sstevel@tonic-gate 	    current->loginID, current->userID,
1091*20d7339fSgww 	    current->groupname == NULL ? "" : current->groupname,
10927c478bd9Sstevel@tonic-gate 	    current->groupID, current->freefield);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	/*
10957c478bd9Sstevel@tonic-gate 	 * Write information about secondary groups if the info exists
10967c478bd9Sstevel@tonic-gate 	 * (it only exists if it is to be written)
10977c478bd9Sstevel@tonic-gate 	 */
1098*20d7339fSgww 	for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
10997c478bd9Sstevel@tonic-gate 	    (void) fprintf(stdout, "                        %-14s  %-6ld\n",
11007c478bd9Sstevel@tonic-gate 		psecgrp->groupname, psecgrp->groupID);
1101*20d7339fSgww 	}
11027c478bd9Sstevel@tonic-gate 
1103*20d7339fSgww 	/*
1104*20d7339fSgww 	 * If the extended information flag is TRUE,
1105*20d7339fSgww 	 * write the extended information
1106*20d7339fSgww 	 */
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	if (xtndflag) {
11097c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
1110*20d7339fSgww 		(void) fprintf(stdout, "                        %s\n",
1111*20d7339fSgww 		    current->iwd);
1112*20d7339fSgww 		(void) fprintf(stdout, "                        %s\n",
1113*20d7339fSgww 		    current->shell);
1114*20d7339fSgww 		(void) fprintf(stdout, "                        %s "
1115*20d7339fSgww 		    "%6.6ld %ld %ld %ld\n",
11167c478bd9Sstevel@tonic-gate 		    pwdinfo->passwdstatus,
11177c478bd9Sstevel@tonic-gate 		    pwdinfo->datechg, pwdinfo->mindaystilchg,
11187c478bd9Sstevel@tonic-gate 		    pwdinfo->maxdaystilchg,
11197c478bd9Sstevel@tonic-gate 		    pwdinfo->warninterval);
11207c478bd9Sstevel@tonic-gate 	}
11217c478bd9Sstevel@tonic-gate 
1122*20d7339fSgww 	/*
1123*20d7339fSgww 	 * If the password expiration info flag is TRUE,
1124*20d7339fSgww 	 * write that information
1125*20d7339fSgww 	 */
11267c478bd9Sstevel@tonic-gate 	if (expflag) {
11277c478bd9Sstevel@tonic-gate 		pwdinfo = current->passwdinfo;
11287c478bd9Sstevel@tonic-gate 		(void) fprintf(stdout, "                        %ld %6.6ld\n",
11297c478bd9Sstevel@tonic-gate 		    pwdinfo->inactive, pwdinfo->expdate);
11307c478bd9Sstevel@tonic-gate 	}
11317c478bd9Sstevel@tonic-gate }
1132*20d7339fSgww 
1133*20d7339fSgww 
11347c478bd9Sstevel@tonic-gate /*
11357c478bd9Sstevel@tonic-gate  *  void genuidreport(pipeflag, xtndflag, expflag)
11367c478bd9Sstevel@tonic-gate  *	int	pipeflag
11377c478bd9Sstevel@tonic-gate  *	int	xtndflag
11387c478bd9Sstevel@tonic-gate  *	int	expflag
11397c478bd9Sstevel@tonic-gate  *
11407c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
11417c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
11427c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
11437c478bd9Sstevel@tonic-gate  *	on user-ID.  If the <pipeflag> variable is not zero, it
11447c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
11457c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
11467c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
11477c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
11487c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
11497c478bd9Sstevel@tonic-gate  *	zero, it will display password expiration information.
11507c478bd9Sstevel@tonic-gate  *
11517c478bd9Sstevel@tonic-gate  *  Arguments:
11527c478bd9Sstevel@tonic-gate  *	pipeflag	int
11537c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
11547c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
11557c478bd9Sstevel@tonic-gate  *	xtndflag	int
11567c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
11577c478bd9Sstevel@tonic-gate  *			FALSE otherwise
11587c478bd9Sstevel@tonic-gate  *	expflag		int
11597c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to be
11607c478bd9Sstevel@tonic-gate  *			displayed, FALSE otherwise
11617c478bd9Sstevel@tonic-gate  *
11627c478bd9Sstevel@tonic-gate  *  Returns:  void
11637c478bd9Sstevel@tonic-gate  */
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate static void
1166*20d7339fSgww genuidreport(int pipeflag, int xtndflag, int expflag)
11677c478bd9Sstevel@tonic-gate {
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	struct display *current;	/* Data being displayed */
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate 	/*
11737c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
1174*20d7339fSgww 	 *  (NOTE:  The first element in the list of logins to	display is
1175*20d7339fSgww 	 *  a dummy element.)
11767c478bd9Sstevel@tonic-gate 	 */
11777c478bd9Sstevel@tonic-gate 	current = displayhead;
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	/*
11807c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
11817c478bd9Sstevel@tonic-gate 	 */
1182*20d7339fSgww 	if (pipeflag) {
1183*20d7339fSgww 		for (current = displayhead->nextuid; current;
1184*20d7339fSgww 		    current = current->nextuid) {
11857c478bd9Sstevel@tonic-gate 			writeunformatted(current, xtndflag, expflag);
1186*20d7339fSgww 		}
1187*20d7339fSgww 	} else {
1188*20d7339fSgww 		for (current = displayhead->nextuid; current;
1189*20d7339fSgww 		    current = current->nextuid) {
11907c478bd9Sstevel@tonic-gate 			writeformatted(current, xtndflag, expflag);
11917c478bd9Sstevel@tonic-gate 		}
1192*20d7339fSgww 	}
1193*20d7339fSgww }
1194*20d7339fSgww 
1195*20d7339fSgww 
11967c478bd9Sstevel@tonic-gate /*
11977c478bd9Sstevel@tonic-gate  *  void genlogreport(pipeflag, xtndflag, expflag)
11987c478bd9Sstevel@tonic-gate  *	int	pipeflag
11997c478bd9Sstevel@tonic-gate  *	int	xtndflag
12007c478bd9Sstevel@tonic-gate  *	int	expflag
12017c478bd9Sstevel@tonic-gate  *
12027c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output
12037c478bd9Sstevel@tonic-gate  *	stream (stdout) containing the login-IDs in the list of
12047c478bd9Sstevel@tonic-gate  *	logins built by this command.  The list is ordered based
12057c478bd9Sstevel@tonic-gate  *	on user name.  If the <pipeflag> variable is not zero, it
12067c478bd9Sstevel@tonic-gate  *	will generate a report containing parsable records.
12077c478bd9Sstevel@tonic-gate  *	Otherwise, it will generate a columnarized report.  If
12087c478bd9Sstevel@tonic-gate  *	the <xtndflag> variable is not zero, it will include the
12097c478bd9Sstevel@tonic-gate  *	extended set of information (password aging info, home
12107c478bd9Sstevel@tonic-gate  *	directory, shell process, etc.).  If <expflag> is not
12117c478bd9Sstevel@tonic-gate  *	zero, it will include password expiration information.
12127c478bd9Sstevel@tonic-gate  *
12137c478bd9Sstevel@tonic-gate  *  Arguments:
12147c478bd9Sstevel@tonic-gate  *	pipeflag	int
12157c478bd9Sstevel@tonic-gate  *			TRUE if a parsable report is needed,
12167c478bd9Sstevel@tonic-gate  *			FALSE if a columnar report is needed
12177c478bd9Sstevel@tonic-gate  *	xtndflag	int
12187c478bd9Sstevel@tonic-gate  *			TRUE if extended set of info is to be displayed,
12197c478bd9Sstevel@tonic-gate  *			FALSE otherwise
12207c478bd9Sstevel@tonic-gate  *	expflag		int
12217c478bd9Sstevel@tonic-gate  *			TRUE if password expiration information is to
12227c478bd9Sstevel@tonic-gate  *			be displayed, FALSE otherwise
12237c478bd9Sstevel@tonic-gate  *
12247c478bd9Sstevel@tonic-gate  *  Returns:  void
12257c478bd9Sstevel@tonic-gate  */
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate static void
1228*20d7339fSgww genlogreport(int pipeflag, int xtndflag, int expflag)
12297c478bd9Sstevel@tonic-gate {
12307c478bd9Sstevel@tonic-gate 	struct display *p;	/* Value being displayed */
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	/*
12347c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
1235*20d7339fSgww 	 *  (NOTE:  The first element in the list of logins to display is
1236*20d7339fSgww 	 *  a dummy element.)
12377c478bd9Sstevel@tonic-gate 	 */
12387c478bd9Sstevel@tonic-gate 	p = displayhead;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	/*
12417c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
12427c478bd9Sstevel@tonic-gate 	 */
1243*20d7339fSgww 	if (pipeflag) {
1244*20d7339fSgww 		for (p = displayhead->nextlogin; p; p = p->nextlogin) {
12457c478bd9Sstevel@tonic-gate 			writeunformatted(p, xtndflag, expflag);
1246*20d7339fSgww 		}
1247*20d7339fSgww 	} else {
1248*20d7339fSgww 		for (p = displayhead->nextlogin; p; p = p->nextlogin) {
12497c478bd9Sstevel@tonic-gate 			writeformatted(p, xtndflag, expflag);
12507c478bd9Sstevel@tonic-gate 		}
1251*20d7339fSgww 	}
1252*20d7339fSgww }
12537c478bd9Sstevel@tonic-gate 
1254*20d7339fSgww 
1255*20d7339fSgww char *
1256*20d7339fSgww strcpmalloc(char *str)
1257*20d7339fSgww {
12587c478bd9Sstevel@tonic-gate 	if (str == NULL)
1259*20d7339fSgww 		return (NULL);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	return (strcpy(allocstr((unsigned int)strlen(str)+1), str));
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate struct localpw {
12657c478bd9Sstevel@tonic-gate 	struct localpw *next;
12667c478bd9Sstevel@tonic-gate 	struct passwd pw;
12677c478bd9Sstevel@tonic-gate };
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate struct localpw *pwtable = NULL;
12707c478bd9Sstevel@tonic-gate 
1271*20d7339fSgww /* Local passwd pointer for getpwent() -- -1 means not in use, NULL for EOF */
1272*20d7339fSgww struct localpw *pwptr;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate int in_localgetpwent = 0;	/* Set if in local_getpwent */
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate void
1277*20d7339fSgww build_localpw(void)
12787c478bd9Sstevel@tonic-gate {
12797c478bd9Sstevel@tonic-gate 	struct localpw *next, *cur;
12807c478bd9Sstevel@tonic-gate 	struct passwd *pw;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	next = (struct localpw *)allocblk(sizeof (struct localpw));
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	pwtable = next;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	while ((pw = getpwent()) != NULL) {
12877c478bd9Sstevel@tonic-gate 		/*
12887c478bd9Sstevel@tonic-gate 		 * Copy the data -- we have to alloc areas for it all
12897c478bd9Sstevel@tonic-gate 		 */
12907c478bd9Sstevel@tonic-gate 		next->pw.pw_name = strcpmalloc(pw->pw_name);
12917c478bd9Sstevel@tonic-gate 		next->pw.pw_passwd = strcpmalloc(pw->pw_passwd);
12927c478bd9Sstevel@tonic-gate 		next->pw.pw_uid = pw->pw_uid;
12937c478bd9Sstevel@tonic-gate 		next->pw.pw_gid = pw->pw_gid;
12947c478bd9Sstevel@tonic-gate 		next->pw.pw_age = strcpmalloc(pw->pw_age);
12957c478bd9Sstevel@tonic-gate 		next->pw.pw_comment = strcpmalloc(pw->pw_comment);
12967c478bd9Sstevel@tonic-gate 		next->pw.pw_gecos  = strcpmalloc(pw->pw_gecos);
12977c478bd9Sstevel@tonic-gate 		next->pw.pw_dir = strcpmalloc(pw->pw_dir);
12987c478bd9Sstevel@tonic-gate 		next->pw.pw_shell = strcpmalloc(pw->pw_shell);
12997c478bd9Sstevel@tonic-gate 
1300*20d7339fSgww 		next->next = (struct localpw *)allocblk(
1301*20d7339fSgww 		    sizeof (struct localpw));
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 		cur = next;
13047c478bd9Sstevel@tonic-gate 		next = next->next;
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	/*
13087c478bd9Sstevel@tonic-gate 	 * At this point we have one extra (struct localpw) allocated;
13097c478bd9Sstevel@tonic-gate 	 * sine alloclbk doesn't have a freeblk, we just leave it unreferenced.
13107c478bd9Sstevel@tonic-gate 	 */
13117c478bd9Sstevel@tonic-gate 
1312*20d7339fSgww 	if (pwtable == next) {
13137c478bd9Sstevel@tonic-gate 		pwtable = NULL;
1314*20d7339fSgww 	} else {
13157c478bd9Sstevel@tonic-gate 		cur->next = NULL;
1316*20d7339fSgww 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	endpwent();
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate struct passwd *
1322*20d7339fSgww local_getpwent(void)
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate 	if (!in_localgetpwent) {
13257c478bd9Sstevel@tonic-gate 		in_localgetpwent = 1;
13267c478bd9Sstevel@tonic-gate 		pwptr = pwtable;
1327*20d7339fSgww 	} else if (pwptr != NULL) {
13287c478bd9Sstevel@tonic-gate 		pwptr = pwptr->next;
1329*20d7339fSgww 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	if (pwptr != NULL)
1332*20d7339fSgww 		return (&(pwptr->pw));
13337c478bd9Sstevel@tonic-gate 	else
1334*20d7339fSgww 		return (NULL);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate void
1338*20d7339fSgww local_endpwent(void)
13397c478bd9Sstevel@tonic-gate {
13407c478bd9Sstevel@tonic-gate 	in_localgetpwent = 0;
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate long
1344*20d7339fSgww local_pwtell(void)
13457c478bd9Sstevel@tonic-gate {
1346*20d7339fSgww 	return ((long)pwptr);
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate void
1350*20d7339fSgww local_pwseek(long ptr)
13517c478bd9Sstevel@tonic-gate {
13527c478bd9Sstevel@tonic-gate 	pwptr = (struct localpw *)ptr;
13537c478bd9Sstevel@tonic-gate }
1354*20d7339fSgww 
13557c478bd9Sstevel@tonic-gate /*
13567c478bd9Sstevel@tonic-gate  * logins [-admopstux] [-l logins] [-g groups]
13577c478bd9Sstevel@tonic-gate  *
13587c478bd9Sstevel@tonic-gate  *	This command generates a report of logins administered on
13597c478bd9Sstevel@tonic-gate  *	the system.  The list will contain logins that meet criteria
13607c478bd9Sstevel@tonic-gate  *	described by the options in the list.  If there are no options,
13617c478bd9Sstevel@tonic-gate  *	it will list all logins administered.  It is intended to be used
13627c478bd9Sstevel@tonic-gate  *	only by administrators.
13637c478bd9Sstevel@tonic-gate  *
13647c478bd9Sstevel@tonic-gate  *  Options:
13657c478bd9Sstevel@tonic-gate  *	-a		Display password expiration information.
13667c478bd9Sstevel@tonic-gate  *	-d		list all logins that share user-IDs with another
13677c478bd9Sstevel@tonic-gate  *			login.
13687c478bd9Sstevel@tonic-gate  *	-g groups	specifies the names of the groups to which a login
13697c478bd9Sstevel@tonic-gate  *			must belong before it is included in the generated
13707c478bd9Sstevel@tonic-gate  *			list.  "groups" is a comma-list of group names.
13717c478bd9Sstevel@tonic-gate  *	-l logins	specifies the logins to display.  "logins" is a
13727c478bd9Sstevel@tonic-gate  *			comma-list of login names.
13737c478bd9Sstevel@tonic-gate  *	-m		in addition to the usual information, for each
13747c478bd9Sstevel@tonic-gate  *			login displayed, list all groups to which that
13757c478bd9Sstevel@tonic-gate  *			login is member.
13767c478bd9Sstevel@tonic-gate  *	-o		generate a report as a colon-list instead of in a
13777c478bd9Sstevel@tonic-gate  *			columnar format
13787c478bd9Sstevel@tonic-gate  *	-p		list all logins that have no password.
13797c478bd9Sstevel@tonic-gate  *	-s		list all system logins
13807c478bd9Sstevel@tonic-gate  *	-t		sort the report lexicographically by login name
13817c478bd9Sstevel@tonic-gate  *			instead of by user-ID
13827c478bd9Sstevel@tonic-gate  *	-u		list all user logins
13837c478bd9Sstevel@tonic-gate  *	-x		in addition to the usual information, display an
13847c478bd9Sstevel@tonic-gate  *			extended set of information that includes the home
13857c478bd9Sstevel@tonic-gate  *			directory, initial process, and password status and
13867c478bd9Sstevel@tonic-gate  *			aging information
13877c478bd9Sstevel@tonic-gate  *
13887c478bd9Sstevel@tonic-gate  * Exit Codes:
13897c478bd9Sstevel@tonic-gate  *	0	All's well that ends well
13907c478bd9Sstevel@tonic-gate  *	1	Usage error
13917c478bd9Sstevel@tonic-gate  */
13927c478bd9Sstevel@tonic-gate 
1393*20d7339fSgww int
1394*20d7339fSgww main(int argc, char *argv[])
13957c478bd9Sstevel@tonic-gate {
13967c478bd9Sstevel@tonic-gate 	struct passwd	*plookpwd;	/* Ptr to searcher pw (-d) */
13977c478bd9Sstevel@tonic-gate 	struct reqgrp	*reqgrphead;	/* Head of the req'd group list */
13987c478bd9Sstevel@tonic-gate 	struct reqgrp	*pgrp;		/* Current item in req'd group list */
13997c478bd9Sstevel@tonic-gate 	struct reqgrp	*qgrp;		/* Prev item in the req'd group list */
14007c478bd9Sstevel@tonic-gate 	struct reqlogin *reqloginhead;	/* Head of req'd login list */
1401*20d7339fSgww 	struct reqlogin *plogin;	/* Current item in req'd login list */
1402*20d7339fSgww 	struct reqlogin *qlogin;	/* Prev item in req'd login list */
14037c478bd9Sstevel@tonic-gate 	struct passwd	*pwent;		/* /etc/passwd entry */
14047c478bd9Sstevel@tonic-gate 	struct group	*grent;		/* /etc/group entry */
14057c478bd9Sstevel@tonic-gate 	char		*token;		/* Token extracted by strtok() */
14067c478bd9Sstevel@tonic-gate 	char		**pp;		/* Group member */
14077c478bd9Sstevel@tonic-gate 	char		*g_arg;		/* -g option's argument */
14087c478bd9Sstevel@tonic-gate 	char		*l_arg;		/* -l option's argument */
14097c478bd9Sstevel@tonic-gate 	long		lookpos;	/* File pos'n, rec we're looking for */
14107c478bd9Sstevel@tonic-gate 	int		a_seen;		/* Is -a requested? */
14117c478bd9Sstevel@tonic-gate 	int		d_seen;		/* Is -d requested? */
14127c478bd9Sstevel@tonic-gate 	int		g_seen;		/* Is -g requested? */
14137c478bd9Sstevel@tonic-gate 	int		l_seen;		/* Is -l requested? */
14147c478bd9Sstevel@tonic-gate 	int		m_seen;		/* Is -m requested? */
14157c478bd9Sstevel@tonic-gate 	int		o_seen;		/* Is -o requested? */
14167c478bd9Sstevel@tonic-gate 	int		p_seen;		/* Is -p requested? */
14177c478bd9Sstevel@tonic-gate 	int		s_seen;		/* Is -s requested? */
14187c478bd9Sstevel@tonic-gate 	int		t_seen;		/* Is -t requested? */
14197c478bd9Sstevel@tonic-gate 	int		u_seen;		/* Is -u requested? */
14207c478bd9Sstevel@tonic-gate 	int		x_seen;		/* Is -x requested? */
14217c478bd9Sstevel@tonic-gate 	int		errflg;		/* Is there a command-line problem */
14227c478bd9Sstevel@tonic-gate 	int		done;		/* Is the process (?) is complete */
1423*20d7339fSgww 	int		groupcount;	/* Number of groups specified */
14247c478bd9Sstevel@tonic-gate 	int		doall;		/* Are all logins to be reported */
14257c478bd9Sstevel@tonic-gate 	int		c;		/* Character returned from getopt() */
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
14307c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
14317c478bd9Sstevel@tonic-gate #endif
14327c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	/* Initializations */
14357c478bd9Sstevel@tonic-gate 	initmsg(argv[0]);
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 
1439*20d7339fSgww 	/*  Command-line processing */
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	/* Initializations */
14427c478bd9Sstevel@tonic-gate 	a_seen = FALSE;
14437c478bd9Sstevel@tonic-gate 	d_seen = FALSE;
14447c478bd9Sstevel@tonic-gate 	g_seen = FALSE;
14457c478bd9Sstevel@tonic-gate 	l_seen = FALSE;
14467c478bd9Sstevel@tonic-gate 	m_seen = FALSE;
14477c478bd9Sstevel@tonic-gate 	o_seen = FALSE;
14487c478bd9Sstevel@tonic-gate 	p_seen = FALSE;
14497c478bd9Sstevel@tonic-gate 	s_seen = FALSE;
14507c478bd9Sstevel@tonic-gate 	t_seen = FALSE;
14517c478bd9Sstevel@tonic-gate 	u_seen = FALSE;
14527c478bd9Sstevel@tonic-gate 	x_seen = FALSE;
14537c478bd9Sstevel@tonic-gate 	errflg = FALSE;
14547c478bd9Sstevel@tonic-gate 	opterr = 0;
14557c478bd9Sstevel@tonic-gate 	while (!errflg && ((c = getopt(argc, argv, OPTSTR)) != EOF)) {
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 		/* Case on the option character */
14587c478bd9Sstevel@tonic-gate 		switch (c) {
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 		/*
14617c478bd9Sstevel@tonic-gate 		 * -a option:
14627c478bd9Sstevel@tonic-gate 		 * Display password expiration information
14637c478bd9Sstevel@tonic-gate 		 */
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 		case 'a':
1466*20d7339fSgww 			if (a_seen)
1467*20d7339fSgww 				errflg = TRUE;
1468*20d7339fSgww 			else
1469*20d7339fSgww 				a_seen = TRUE;
14707c478bd9Sstevel@tonic-gate 			break;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 		/*
14737c478bd9Sstevel@tonic-gate 		 * -d option:
14747c478bd9Sstevel@tonic-gate 		 * Display logins which share user-IDs with other logins
14757c478bd9Sstevel@tonic-gate 		 */
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 		case 'd':
1478*20d7339fSgww 			if (d_seen)
1479*20d7339fSgww 				errflg = TRUE;
1480*20d7339fSgww 			else
1481*20d7339fSgww 				d_seen = TRUE;
14827c478bd9Sstevel@tonic-gate 			break;
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 		/*
14857c478bd9Sstevel@tonic-gate 		 * -g <groups> option:
14867c478bd9Sstevel@tonic-gate 		 * Display the specified groups
14877c478bd9Sstevel@tonic-gate 		 */
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 		case 'g':
1490*20d7339fSgww 			if (g_seen) {
1491*20d7339fSgww 				errflg = TRUE;
1492*20d7339fSgww 			} else {
14937c478bd9Sstevel@tonic-gate 				g_seen = TRUE;
14947c478bd9Sstevel@tonic-gate 				g_arg = optarg;
14957c478bd9Sstevel@tonic-gate 			}
14967c478bd9Sstevel@tonic-gate 			break;
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 		/*
14997c478bd9Sstevel@tonic-gate 		 * -l <logins> option:
15007c478bd9Sstevel@tonic-gate 		 * Display the specified logins
15017c478bd9Sstevel@tonic-gate 		 */
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 		case 'l':
1504*20d7339fSgww 			if (l_seen) {
1505*20d7339fSgww 				errflg = TRUE;
1506*20d7339fSgww 			} else {
15077c478bd9Sstevel@tonic-gate 				l_seen = TRUE;
15087c478bd9Sstevel@tonic-gate 				l_arg = optarg;
15097c478bd9Sstevel@tonic-gate 			}
15107c478bd9Sstevel@tonic-gate 			break;
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 		/*
15137c478bd9Sstevel@tonic-gate 		 * -m option:
15147c478bd9Sstevel@tonic-gate 		 * Display multiple group information
15157c478bd9Sstevel@tonic-gate 		 */
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		case 'm':
1518*20d7339fSgww 			if (m_seen)
1519*20d7339fSgww 				errflg = TRUE;
1520*20d7339fSgww 			else
1521*20d7339fSgww 				m_seen = TRUE;
15227c478bd9Sstevel@tonic-gate 			break;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 		/*
15257c478bd9Sstevel@tonic-gate 		 * -o option:
15267c478bd9Sstevel@tonic-gate 		 * Display information as a colon-list
15277c478bd9Sstevel@tonic-gate 		 */
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 		case 'o':
1530*20d7339fSgww 			if (o_seen)
1531*20d7339fSgww 				errflg = TRUE;
1532*20d7339fSgww 			else
1533*20d7339fSgww 				o_seen = TRUE;
15347c478bd9Sstevel@tonic-gate 			break;
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		/*
15377c478bd9Sstevel@tonic-gate 		 * -p option:
15387c478bd9Sstevel@tonic-gate 		 * Select logins that have no password
15397c478bd9Sstevel@tonic-gate 		 */
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 		case 'p':
1542*20d7339fSgww 			if (p_seen)
1543*20d7339fSgww 				errflg = TRUE;
1544*20d7339fSgww 			else
1545*20d7339fSgww 				p_seen = TRUE;
15467c478bd9Sstevel@tonic-gate 			break;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 		/*
15497c478bd9Sstevel@tonic-gate 		 * -s option:
15507c478bd9Sstevel@tonic-gate 		 * Select system logins
15517c478bd9Sstevel@tonic-gate 		 */
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 		case 's':
1554*20d7339fSgww 			if (s_seen)
1555*20d7339fSgww 				errflg = TRUE;
1556*20d7339fSgww 			else
1557*20d7339fSgww 				s_seen = TRUE;
15587c478bd9Sstevel@tonic-gate 			break;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 		/*
15617c478bd9Sstevel@tonic-gate 		 * -t option:
15627c478bd9Sstevel@tonic-gate 		 * Sort alphabetically by login-ID instead of numerically
15637c478bd9Sstevel@tonic-gate 		 * by user-ID
15647c478bd9Sstevel@tonic-gate 		 */
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 		case 't':
1567*20d7339fSgww 			if (t_seen)
1568*20d7339fSgww 				errflg = TRUE;
1569*20d7339fSgww 			else
1570*20d7339fSgww 				t_seen = TRUE;
15717c478bd9Sstevel@tonic-gate 			break;
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 		/*
15747c478bd9Sstevel@tonic-gate 		 * -u option:
15757c478bd9Sstevel@tonic-gate 		 * Select user logins
15767c478bd9Sstevel@tonic-gate 		 */
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 		case 'u':
1579*20d7339fSgww 			if (u_seen)
1580*20d7339fSgww 				errflg = TRUE;
1581*20d7339fSgww 			else
1582*20d7339fSgww 				u_seen = TRUE;
15837c478bd9Sstevel@tonic-gate 			break;
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 		/*
15867c478bd9Sstevel@tonic-gate 		 * -x option:
15877c478bd9Sstevel@tonic-gate 		 * Display extended info (init working dir, shell, pwd info)
15887c478bd9Sstevel@tonic-gate 		 */
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		case 'x':
1591*20d7339fSgww 			if (x_seen)
1592*20d7339fSgww 				errflg = TRUE;
1593*20d7339fSgww 			else
1594*20d7339fSgww 				x_seen = TRUE;
15957c478bd9Sstevel@tonic-gate 			break;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		default:		/* Oops.... */
15987c478bd9Sstevel@tonic-gate 			errflg = TRUE;
15997c478bd9Sstevel@tonic-gate 		}
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	/* Write out a usage message if necessary and quit */
16037c478bd9Sstevel@tonic-gate 	if (errflg || (optind != argc)) {
16047c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(USAGE_MSG));
16057c478bd9Sstevel@tonic-gate 		exit(1);
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/*
16117c478bd9Sstevel@tonic-gate 	 *  The following section does preparation work, setting up for
16127c478bd9Sstevel@tonic-gate 	 *  building the list of logins to display
16137c478bd9Sstevel@tonic-gate 	 */
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	/*
16167c478bd9Sstevel@tonic-gate 	 * Very first thing, build an in-core structure of passwd file entries.
16177c478bd9Sstevel@tonic-gate 	 * This is important since we have to assume that getpwent() is going
16187c478bd9Sstevel@tonic-gate 	 * out to one or more network name services that could be changing
16197c478bd9Sstevel@tonic-gate 	 * on the fly.  This will limit us to one pass through the network data.
16207c478bd9Sstevel@tonic-gate 	 */
16217c478bd9Sstevel@tonic-gate 	build_localpw();
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	/*
16257c478bd9Sstevel@tonic-gate 	 *  If the -g groups option was on the command line, build a
16267c478bd9Sstevel@tonic-gate 	 *  list containing groups we're to list logins for.
16277c478bd9Sstevel@tonic-gate 	 */
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	if (g_seen) {
16307c478bd9Sstevel@tonic-gate 		groupcount = 0;
1631*20d7339fSgww 		reqgrphead = NULL;
16327c478bd9Sstevel@tonic-gate 		if (token = strtok(g_arg, ",")) {
1633*20d7339fSgww 			pgrp = (struct reqgrp *)allocblk(
1634*20d7339fSgww 			    sizeof (struct reqgrp));
16357c478bd9Sstevel@tonic-gate 			pgrp->groupname = token;
16367c478bd9Sstevel@tonic-gate 			pgrp->found = FALSE;
1637*20d7339fSgww 			pgrp->next = NULL;
16387c478bd9Sstevel@tonic-gate 			groupcount++;
16397c478bd9Sstevel@tonic-gate 			reqgrphead = pgrp;
16407c478bd9Sstevel@tonic-gate 			qgrp = pgrp;
16417c478bd9Sstevel@tonic-gate 			while (token = strtok(NULL, ",")) {
1642*20d7339fSgww 				pgrp = (struct reqgrp *)allocblk(
1643*20d7339fSgww 				    sizeof (struct reqgrp));
16447c478bd9Sstevel@tonic-gate 				pgrp->groupname = token;
16457c478bd9Sstevel@tonic-gate 				pgrp->found = FALSE;
1646*20d7339fSgww 				pgrp->next = NULL;
16477c478bd9Sstevel@tonic-gate 				groupcount++;
16487c478bd9Sstevel@tonic-gate 				qgrp->next = pgrp;
16497c478bd9Sstevel@tonic-gate 				qgrp = pgrp;
16507c478bd9Sstevel@tonic-gate 			}
16517c478bd9Sstevel@tonic-gate 		}
16527c478bd9Sstevel@tonic-gate 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	/*
16567c478bd9Sstevel@tonic-gate 	 *  If -l logins is on the command line, build a list of
16577c478bd9Sstevel@tonic-gate 	 *  logins we're to generate reports for.
16587c478bd9Sstevel@tonic-gate 	 */
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	if (l_seen) {
1661*20d7339fSgww 		reqloginhead = NULL;
16627c478bd9Sstevel@tonic-gate 		if (token = strtok(l_arg, ",")) {
1663*20d7339fSgww 			plogin = (struct reqlogin *)allocblk(
1664*20d7339fSgww 			    sizeof (struct reqlogin));
16657c478bd9Sstevel@tonic-gate 			plogin->loginname = token;
16667c478bd9Sstevel@tonic-gate 			plogin->found = FALSE;
1667*20d7339fSgww 			plogin->next = NULL;
16687c478bd9Sstevel@tonic-gate 			reqloginhead = plogin;
16697c478bd9Sstevel@tonic-gate 			qlogin = plogin;
16707c478bd9Sstevel@tonic-gate 			while (token = strtok(NULL, ",")) {
1671*20d7339fSgww 				plogin = (struct reqlogin *)allocblk(
1672*20d7339fSgww 				    sizeof (struct reqlogin));
16737c478bd9Sstevel@tonic-gate 				plogin->loginname = token;
16747c478bd9Sstevel@tonic-gate 				plogin->found = FALSE;
1675*20d7339fSgww 				plogin->next = NULL;
16767c478bd9Sstevel@tonic-gate 				qlogin->next = plogin;
16777c478bd9Sstevel@tonic-gate 				qlogin = plogin;
16787c478bd9Sstevel@tonic-gate 			}
16797c478bd9Sstevel@tonic-gate 		}
16807c478bd9Sstevel@tonic-gate 		while (pwent = local_getpwent()) {
16817c478bd9Sstevel@tonic-gate 			done = FALSE;
16827c478bd9Sstevel@tonic-gate 			for (plogin = reqloginhead; !done && plogin;
16837c478bd9Sstevel@tonic-gate 			    plogin = plogin->next) {
16847c478bd9Sstevel@tonic-gate 				if (strcmp(pwent->pw_name,
16857c478bd9Sstevel@tonic-gate 				    plogin->loginname) == 0) {
16867c478bd9Sstevel@tonic-gate 					plogin->found = TRUE;
16877c478bd9Sstevel@tonic-gate 					done = TRUE;
16887c478bd9Sstevel@tonic-gate 				}
16897c478bd9Sstevel@tonic-gate 			}
16907c478bd9Sstevel@tonic-gate 		}
16917c478bd9Sstevel@tonic-gate 		local_endpwent();
16927c478bd9Sstevel@tonic-gate 	}
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	/*
16957c478bd9Sstevel@tonic-gate 	 *  Generate the list of login information to display
16967c478bd9Sstevel@tonic-gate 	 */
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 	/* Initialize the login list */
16997c478bd9Sstevel@tonic-gate 	initmembers();
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	/*
17037c478bd9Sstevel@tonic-gate 	 *  If -g groups was specified, generate a list of members
17047c478bd9Sstevel@tonic-gate 	 *  of the specified groups
17057c478bd9Sstevel@tonic-gate 	 */
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	if (g_seen) {
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 		/* For each group in the /etc/group file ... */
17107c478bd9Sstevel@tonic-gate 		while (grent = getgrent()) {
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 			/* For each group mentioned with the -g option ... */
1713*20d7339fSgww 			for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
1714*20d7339fSgww 			    pgrp = pgrp->next) {
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 				if (!pgrp->found) {
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 					/*
1719*20d7339fSgww 					 *  If the mentioned group is found
1720*20d7339fSgww 					 * in the  /etc/group file ...
17217c478bd9Sstevel@tonic-gate 					 */
1722*20d7339fSgww 					if (strcmp(grent->gr_name,
1723*20d7339fSgww 					    pgrp->groupname) == 0) {
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 						/*
1726*20d7339fSgww 						 * Mark the entry is found,
1727*20d7339fSgww 						 * remembering the group-ID
1728*20d7339fSgww 						 * for later
17297c478bd9Sstevel@tonic-gate 						 */
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 						pgrp->found = TRUE;
17327c478bd9Sstevel@tonic-gate 						groupcount--;
17337c478bd9Sstevel@tonic-gate 						pgrp->groupID = grent->gr_gid;
1734*20d7339fSgww 						for (pp = grent->gr_mem; *pp;
1735*20d7339fSgww 						    pp++) {
1736*20d7339fSgww 							addmember(*pp);
17377c478bd9Sstevel@tonic-gate 						}
17387c478bd9Sstevel@tonic-gate 					}
17397c478bd9Sstevel@tonic-gate 				}
17407c478bd9Sstevel@tonic-gate 			}
1741*20d7339fSgww 		}
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 		/*
17447c478bd9Sstevel@tonic-gate 		 * If any groups weren't found, write a message indicating
17457c478bd9Sstevel@tonic-gate 		 * such, then continue
17467c478bd9Sstevel@tonic-gate 		 */
17477c478bd9Sstevel@tonic-gate 
1748*20d7339fSgww 		qgrp = NULL;
17497c478bd9Sstevel@tonic-gate 		for (pgrp = reqgrphead; pgrp; pgrp = pgrp->next) {
17507c478bd9Sstevel@tonic-gate 			if (!pgrp->found) {
1751*20d7339fSgww 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
1752*20d7339fSgww 				    gettext("%s was not found"),
1753*20d7339fSgww 				    pgrp->groupname);
1754*20d7339fSgww 				if (!qgrp) {
1755*20d7339fSgww 					reqgrphead = pgrp->next;
1756*20d7339fSgww 				} else {
1757*20d7339fSgww 				qgrp->next = pgrp->next;
17587c478bd9Sstevel@tonic-gate 				}
1759*20d7339fSgww 			} else {
1760*20d7339fSgww 				qgrp = pgrp;
1761*20d7339fSgww 			}
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 		endgrent();
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	/* Initialize the list of logins to display */
17687c478bd9Sstevel@tonic-gate 	initdisp();
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate 	/*
17727c478bd9Sstevel@tonic-gate 	 *  Add logins that have user-IDs that are used more than once,
17737c478bd9Sstevel@tonic-gate 	 *  if requested.  This command is pretty slow, since the algorithm
17747c478bd9Sstevel@tonic-gate 	 *  reads from the /etc/passwd file 1+2+3+...+n times where n is the
17757c478bd9Sstevel@tonic-gate 	 *  number of login-IDs in the /etc/passwd file.  (Actually, this
17767c478bd9Sstevel@tonic-gate 	 *  can be optimized so it's not quite that bad, but the order or
17777c478bd9Sstevel@tonic-gate 	 *  magnitude stays the same.)
17787c478bd9Sstevel@tonic-gate 	 *
17797c478bd9Sstevel@tonic-gate 	 *  Note:  This processing needs to be done before any other options
17807c478bd9Sstevel@tonic-gate 	 *	   are processed -- the algorithm contains an optimization
17817c478bd9Sstevel@tonic-gate 	 *	   that insists on the display list being empty before this
17827c478bd9Sstevel@tonic-gate 	 *	   option is processed.
17837c478bd9Sstevel@tonic-gate 	 */
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	if (d_seen) {
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 		/*
17887c478bd9Sstevel@tonic-gate 		 * The following code is a quick&dirty reimplementation of the
17897c478bd9Sstevel@tonic-gate 		 * original algorithm, which opened the password file twice (to
17907c478bd9Sstevel@tonic-gate 		 * get two file pointer into the data) and then used fgetpwent()
17917c478bd9Sstevel@tonic-gate 		 * in undocumented ways to scan through the file, checking for
17927c478bd9Sstevel@tonic-gate 		 * duplicates.  This does not work when getpwent() is used to
17937c478bd9Sstevel@tonic-gate 		 * go out over the network, since there is not file pointer.
17947c478bd9Sstevel@tonic-gate 		 *
1795*20d7339fSgww 		 * Instead an in-memory list of passwd structures is built,
1796*20d7339fSgww 		 * and then this list is scanned.  The routines
1797*20d7339fSgww 		 * Local_getpwent(), etc., are designed to mimic the standard
1798*20d7339fSgww 		 * library routines, so this code does not have to be
1799*20d7339fSgww 		 * extensively modified.
18007c478bd9Sstevel@tonic-gate 		 */
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 		/*
18037c478bd9Sstevel@tonic-gate 		 * For reference, here is the original comment about the next
1804*20d7339fSgww 		 * section of code.  Some of the code has changed, but the
1805*20d7339fSgww 		 * algorithm is the same:
18067c478bd9Sstevel@tonic-gate 		 *
18077c478bd9Sstevel@tonic-gate 		 * Open the system password file once.  This instance will be
18087c478bd9Sstevel@tonic-gate 		 * used to leaf through the file once, reading each entry once,
18097c478bd9Sstevel@tonic-gate 		 * and searching the remainder of the file for another login-ID
18107c478bd9Sstevel@tonic-gate 		 * that has the same user-ID.  Note that there are lots of
18117c478bd9Sstevel@tonic-gate 		 * contortions one has to go through when reading two instances
18127c478bd9Sstevel@tonic-gate 		 * of the /etc/passwd file.  That's why there's some seeking,
18137c478bd9Sstevel@tonic-gate 		 * re-reading of the same record, and other junk.  Luckily, this
18147c478bd9Sstevel@tonic-gate 		 * feature won't be requested very often, and still isn't too
18157c478bd9Sstevel@tonic-gate 		 * slow...
18167c478bd9Sstevel@tonic-gate 		 */
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 		/* For each entry in the passwd database ... */
18197c478bd9Sstevel@tonic-gate 		while (plookpwd = local_getpwent()) {
18207c478bd9Sstevel@tonic-gate 			/*
1821*20d7339fSgww 			 * Optimization -- If the login's user-ID is already
1822*20d7339fSgww 			 * in the display list, there's no reason to process
1823*20d7339fSgww 			 * this  entry -- it's already there.
18247c478bd9Sstevel@tonic-gate 			 */
18257c478bd9Sstevel@tonic-gate 			if (!isuidindisp(plookpwd)) {
18267c478bd9Sstevel@tonic-gate 				/*
1827*20d7339fSgww 				 * Rememeber the current entry's position,
1828*20d7339fSgww 				 * so when we finish scanning through the
1829*20d7339fSgww 				 * database looking for duplicates we can
1830*20d7339fSgww 				 * return to the current place, so that the
1831*20d7339fSgww 				 * enclosing loop will march in an orderly
1832*20d7339fSgww 				 * fashion through the passwd database.
18337c478bd9Sstevel@tonic-gate 				 */
18347c478bd9Sstevel@tonic-gate 				done = FALSE;
18357c478bd9Sstevel@tonic-gate 				lookpos = local_pwtell();
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 				/*
1838*20d7339fSgww 				 * For each record in the passwd database
1839*20d7339fSgww 				 * beyond the searching record ...
18407c478bd9Sstevel@tonic-gate 				 */
18417c478bd9Sstevel@tonic-gate 				while (pwent = local_getpwent()) {
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 					/*
1844*20d7339fSgww 					 * If there's a match between the
1845*20d7339fSgww 					 * searcher's user-ID and the
1846*20d7339fSgww 					 * searchee's user-ID ...
18477c478bd9Sstevel@tonic-gate 					 */
18487c478bd9Sstevel@tonic-gate 					if (pwent->pw_uid == plookpwd->pw_uid) {
18497c478bd9Sstevel@tonic-gate 						/*
1850*20d7339fSgww 						 * If this is the first
1851*20d7339fSgww 						 * duplicate of this searcher
18527c478bd9Sstevel@tonic-gate 						 * that we find,
1853*20d7339fSgww 						 * add the searcher's
1854*20d7339fSgww 						 * record to the display list
1855*20d7339fSgww 						 * (It wants to be on the
1856*20d7339fSgww 						 * list first to avoid
1857*20d7339fSgww 						 * ordering "flakeyness")
18587c478bd9Sstevel@tonic-gate 						 */
18597c478bd9Sstevel@tonic-gate 						if (done == FALSE) {
18607c478bd9Sstevel@tonic-gate 							adddisp(plookpwd);
1861*20d7339fSgww 							done = TRUE;
18627c478bd9Sstevel@tonic-gate 						}
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 						/*
1865*20d7339fSgww 						 * Now add the searchee's
1866*20d7339fSgww 						 * record
18677c478bd9Sstevel@tonic-gate 						 */
18687c478bd9Sstevel@tonic-gate 						adddisp(pwent);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 					}
18717c478bd9Sstevel@tonic-gate 				}
18727c478bd9Sstevel@tonic-gate 				/* Reposition to searcher record */
18737c478bd9Sstevel@tonic-gate 				local_pwseek(lookpos);
18747c478bd9Sstevel@tonic-gate 			}
18757c478bd9Sstevel@tonic-gate 		}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 		local_endpwent();
18787c478bd9Sstevel@tonic-gate 	}
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	/*
18827c478bd9Sstevel@tonic-gate 	 *  Loop through the passwd database squirelling away the
18837c478bd9Sstevel@tonic-gate 	 *  information we need for the display.
18847c478bd9Sstevel@tonic-gate 	 *
18857c478bd9Sstevel@tonic-gate 	 *  NOTE:  Once a login is added to the list, the rest of the
18867c478bd9Sstevel@tonic-gate 	 *	   body of the loop is bypassed (via a continue statement).
18877c478bd9Sstevel@tonic-gate 	 */
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	doall = !(s_seen || u_seen || p_seen || d_seen || l_seen || g_seen);
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	if (doall || s_seen || u_seen || p_seen || l_seen || g_seen) {
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 		while (pwent = local_getpwent()) {
18947c478bd9Sstevel@tonic-gate 			done = FALSE;
18957c478bd9Sstevel@tonic-gate 
1896*20d7339fSgww 			/*
1897*20d7339fSgww 			 * If no user-specific options were specified,
1898*20d7339fSgww 			 * include this login-ID
1899*20d7339fSgww 			 */
19007c478bd9Sstevel@tonic-gate 			if (doall) {
19017c478bd9Sstevel@tonic-gate 				adddisp(pwent);
19027c478bd9Sstevel@tonic-gate 				continue;
19037c478bd9Sstevel@tonic-gate 			}
19047c478bd9Sstevel@tonic-gate 
1905*20d7339fSgww 			/*
1906*20d7339fSgww 			 * If the user specified system login-IDs,
1907*20d7339fSgww 			 * and this is a system ID, include it
1908*20d7339fSgww 			 */
1909*20d7339fSgww 			if (s_seen) {
1910*20d7339fSgww 				if (isasystemlogin(pwent)) {
19117c478bd9Sstevel@tonic-gate 					adddisp(pwent);
19127c478bd9Sstevel@tonic-gate 					continue;
19137c478bd9Sstevel@tonic-gate 				}
1914*20d7339fSgww 			}
19157c478bd9Sstevel@tonic-gate 
1916*20d7339fSgww 			/*
1917*20d7339fSgww 			 * If the user specified user login-IDs,
1918*20d7339fSgww 			 * and this is a user ID, include it
1919*20d7339fSgww 			 */
1920*20d7339fSgww 			if (u_seen) {
1921*20d7339fSgww 				if (isauserlogin(pwent)) {
19227c478bd9Sstevel@tonic-gate 					adddisp(pwent);
19237c478bd9Sstevel@tonic-gate 					continue;
19247c478bd9Sstevel@tonic-gate 				}
1925*20d7339fSgww 			}
19267c478bd9Sstevel@tonic-gate 
1927*20d7339fSgww 			/*
1928*20d7339fSgww 			 * If the user is asking for login-IDs that have
1929*20d7339fSgww 			 * no password, and this one has no password, include it
1930*20d7339fSgww 			 */
1931*20d7339fSgww 			if (p_seen) {
1932*20d7339fSgww 				if (hasnopasswd(pwent)) {
19337c478bd9Sstevel@tonic-gate 					adddisp(pwent);
19347c478bd9Sstevel@tonic-gate 					continue;
19357c478bd9Sstevel@tonic-gate 				}
1936*20d7339fSgww 			}
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 			/*
19397c478bd9Sstevel@tonic-gate 			 * If specific logins were requested, leaf through
19407c478bd9Sstevel@tonic-gate 			 * the list of logins they requested.  If this login
19417c478bd9Sstevel@tonic-gate 			 * is on the list, include it.
19427c478bd9Sstevel@tonic-gate 			 */
19437c478bd9Sstevel@tonic-gate 			if (l_seen) {
1944*20d7339fSgww 				for (plogin = reqloginhead; !done && plogin;
1945*20d7339fSgww 				    plogin = plogin->next) {
1946*20d7339fSgww 					if (strcmp(pwent->pw_name,
1947*20d7339fSgww 					    plogin->loginname) == 0) {
19487c478bd9Sstevel@tonic-gate 						plogin->found = TRUE;
19497c478bd9Sstevel@tonic-gate 						adddisp(pwent);
19507c478bd9Sstevel@tonic-gate 						done = TRUE;
19517c478bd9Sstevel@tonic-gate 					}
19527c478bd9Sstevel@tonic-gate 				}
1953*20d7339fSgww 				if (done)
1954*20d7339fSgww 					continue;
19557c478bd9Sstevel@tonic-gate 			}
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 			/*
19587c478bd9Sstevel@tonic-gate 			 * If specific groups were requested, leaf through the
1959*20d7339fSgww 			 * list of login-IDs that belong to those groups.
1960*20d7339fSgww 			 * If this login-ID is in that list, or its primary
1961*20d7339fSgww 			 * group is one of those requested, include it.
19627c478bd9Sstevel@tonic-gate 			 */
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 			if (g_seen) {
1965*20d7339fSgww 				for (pgrp = reqgrphead; !done && pgrp;
1966*20d7339fSgww 				    pgrp = pgrp->next) {
19677c478bd9Sstevel@tonic-gate 					if (pwent->pw_gid == pgrp->groupID) {
19687c478bd9Sstevel@tonic-gate 						adddisp(pwent);
19697c478bd9Sstevel@tonic-gate 						done = TRUE;
19707c478bd9Sstevel@tonic-gate 					}
1971*20d7339fSgww 				}
19727c478bd9Sstevel@tonic-gate 				if (!done && isamember(pwent->pw_name)) {
19737c478bd9Sstevel@tonic-gate 					adddisp(pwent);
19747c478bd9Sstevel@tonic-gate 					done = TRUE;
19757c478bd9Sstevel@tonic-gate 				}
19767c478bd9Sstevel@tonic-gate 			}
1977*20d7339fSgww 			if (done)
1978*20d7339fSgww 				continue;
19797c478bd9Sstevel@tonic-gate 		}
1980*20d7339fSgww 
19817c478bd9Sstevel@tonic-gate 		local_endpwent();
19827c478bd9Sstevel@tonic-gate 	}
19837c478bd9Sstevel@tonic-gate 
1984*20d7339fSgww 	/* Let the user know about logins they requested that don't exist */
1985*20d7339fSgww 	if (l_seen) {
1986*20d7339fSgww 		for (plogin = reqloginhead; plogin; plogin = plogin->next) {
1987*20d7339fSgww 			if (!plogin->found) {
1988*20d7339fSgww 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
1989*20d7339fSgww 				    gettext("%s was not found"),
1990*20d7339fSgww 				    plogin->loginname);
1991*20d7339fSgww 			}
1992*20d7339fSgww 		}
1993*20d7339fSgww 	}
19947c478bd9Sstevel@tonic-gate 
1995*20d7339fSgww 	/*  Apply group information */
19967c478bd9Sstevel@tonic-gate 	applygroup(m_seen);
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	/*
20007c478bd9Sstevel@tonic-gate 	 * Apply password information (only needed if the extended
20017c478bd9Sstevel@tonic-gate 	 * set of information has been requested)
20027c478bd9Sstevel@tonic-gate 	 */
2003*20d7339fSgww 	if (x_seen || a_seen)
2004*20d7339fSgww 		applypasswd();
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	/*
2008*20d7339fSgww 	 * Generate a report from this display items we've squirreled away
20097c478bd9Sstevel@tonic-gate 	 */
20107c478bd9Sstevel@tonic-gate 
2011*20d7339fSgww 	if (t_seen)
2012*20d7339fSgww 		genlogreport(o_seen, x_seen, a_seen);
2013*20d7339fSgww 	else
2014*20d7339fSgww 		genuidreport(o_seen, x_seen, a_seen);
20157c478bd9Sstevel@tonic-gate 
2016*20d7339fSgww 	/*  We're through! */
20177c478bd9Sstevel@tonic-gate 	return (0);
20187c478bd9Sstevel@tonic-gate }
2019