xref: /titanic_44/usr/src/cmd/users/users.c (revision 8d489c7a815fcac696803219572e95aa01532b0f)
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 
237c478bd9Sstevel@tonic-gate /*
247c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28*8d489c7aSmuffin /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*8d489c7aSmuffin /*	  All Rights Reserved  	*/
30*8d489c7aSmuffin 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /*
347c478bd9Sstevel@tonic-gate  * users.c
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  *	This file contains the source for the administrative command
377c478bd9Sstevel@tonic-gate  *	"listusers" (available to the general user population) that
387c478bd9Sstevel@tonic-gate  *	produces a report containing user login-IDs and their "free
397c478bd9Sstevel@tonic-gate  *	field" (typically contains the user's name and other information).
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  *  Header files referenced:
447c478bd9Sstevel@tonic-gate  *	sys/types.h	System type definitions
457c478bd9Sstevel@tonic-gate  *	stdio.h		Definitions for standard I/O functions and constants
467c478bd9Sstevel@tonic-gate  *	string.h	Definitions for string-handling functions
477c478bd9Sstevel@tonic-gate  *	grp.h		Definitions for referencing the /etc/group file
487c478bd9Sstevel@tonic-gate  *	pwd.h		Definitions for referencing the /etc/passwd file
497c478bd9Sstevel@tonic-gate  *	varargs.h	Definitions for using a variable argument list
507c478bd9Sstevel@tonic-gate  *	fmtmsg.h	Definitions for using the standard message formatting
517c478bd9Sstevel@tonic-gate  *			facility
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include <sys/types.h>
557c478bd9Sstevel@tonic-gate #include <stdio.h>
567c478bd9Sstevel@tonic-gate #include <string.h>
577c478bd9Sstevel@tonic-gate #include <grp.h>
587c478bd9Sstevel@tonic-gate #include <pwd.h>
597c478bd9Sstevel@tonic-gate #include <stdarg.h>
607c478bd9Sstevel@tonic-gate #include <fmtmsg.h>
61*8d489c7aSmuffin #include <stdlib.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  *  Externals referenced (and not defined by a header file):
667c478bd9Sstevel@tonic-gate  *	malloc		Allocate memory from main memory
677c478bd9Sstevel@tonic-gate  *	getopt		Extract the next option from the command line
687c478bd9Sstevel@tonic-gate  *	optind		The argument count of the next option to extract from
697c478bd9Sstevel@tonic-gate  *			the command line
707c478bd9Sstevel@tonic-gate  *	optarg		A pointer to the argument of the option just extracted
717c478bd9Sstevel@tonic-gate  *			from the command line
727c478bd9Sstevel@tonic-gate  *	opterr		FLAG:  !0 tells getopt() to write an error message if
737c478bd9Sstevel@tonic-gate  *			it detects an error
747c478bd9Sstevel@tonic-gate  *	getpwent	Get next entry from the /etc/passwd file
757c478bd9Sstevel@tonic-gate  *	getgrent	Get next entry from the /etc/group file
767c478bd9Sstevel@tonic-gate  *	fmtmsg		Standard message generation facility
777c478bd9Sstevel@tonic-gate  *	putenv		Modify the environment
787c478bd9Sstevel@tonic-gate  *	exit		Exit the program
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  *  Local constant definitions
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #ifndef	FALSE
867c478bd9Sstevel@tonic-gate #define	FALSE			0
877c478bd9Sstevel@tonic-gate #endif
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate #ifndef	TRUE
907c478bd9Sstevel@tonic-gate #define	TRUE			('t')
917c478bd9Sstevel@tonic-gate #endif
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	USAGE_MSG		"usage: listusers [-g groups] [-l logins]"
947c478bd9Sstevel@tonic-gate #define	MAXLOGINSIZE		14
957c478bd9Sstevel@tonic-gate #define	LOGINFIELDSZ		MAXLOGINSIZE+2
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate #define	isauserlogin(uid)	(uid >= 100)
987c478bd9Sstevel@tonic-gate #define	isasystemlogin(uid)	(uid < 100)
997c478bd9Sstevel@tonic-gate #define	isausergroup(gid)	(gid >= 100)
1007c478bd9Sstevel@tonic-gate #define	isasystemgroup(gid)	(gid < 100)
101*8d489c7aSmuffin 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  *  Local datatype definitions
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * This structure describes a specified group name
1087c478bd9Sstevel@tonic-gate  * (from the -g groups option)
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate struct	reqgrp {
1127c478bd9Sstevel@tonic-gate 	char		*groupname;
1137c478bd9Sstevel@tonic-gate 	struct reqgrp	*next;
1147c478bd9Sstevel@tonic-gate 	int		found;
1157c478bd9Sstevel@tonic-gate 	gid_t		groupID;
1167c478bd9Sstevel@tonic-gate };
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate  * This structure describes a specified login name
1207c478bd9Sstevel@tonic-gate  * (from the -l logins option)
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate struct	reqlogin {
1247c478bd9Sstevel@tonic-gate 	char		*loginname;
1257c478bd9Sstevel@tonic-gate 	struct reqlogin	*next;
1267c478bd9Sstevel@tonic-gate 	int		found;
1277c478bd9Sstevel@tonic-gate };
128*8d489c7aSmuffin 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  *  These functions handle error and warning message writing.
1317c478bd9Sstevel@tonic-gate  *  (This deals with UNIX(r) standard message generation, so
1327c478bd9Sstevel@tonic-gate  *  the rest of the code doesn't have to.)
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  *  Functions included:
1357c478bd9Sstevel@tonic-gate  *	initmsg		Initialize the message handling functions.
1367c478bd9Sstevel@tonic-gate  *	wrtmsg		Write the message using the standard message
1377c478bd9Sstevel@tonic-gate  *			generation facility.
1387c478bd9Sstevel@tonic-gate  *
1397c478bd9Sstevel@tonic-gate  *  Static data included:
1407c478bd9Sstevel@tonic-gate  *	fcnlbl		The label for standard messages
1417c478bd9Sstevel@tonic-gate  *	msgbuf		A buffer to contain the edited message
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static	char	fcnlbl[MM_MXLABELLN+1];	/* Buffer for message label */
1457c478bd9Sstevel@tonic-gate static	char	msgbuf[MM_MXTXTLN+1];	/* Buffer for message text */
146*8d489c7aSmuffin 
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate  * void initmsg(p)
1497c478bd9Sstevel@tonic-gate  *
1507c478bd9Sstevel@tonic-gate  *	This function initializes the message handling functions.
1517c478bd9Sstevel@tonic-gate  *
1527c478bd9Sstevel@tonic-gate  *  Arguments:
1537c478bd9Sstevel@tonic-gate  *	p	A pointer to a character string that is the name of the
1547c478bd9Sstevel@tonic-gate  *		command, used to generate the label on messages.  If this
1557c478bd9Sstevel@tonic-gate  *		string contains a slash ('/'), it only uses the characters
1567c478bd9Sstevel@tonic-gate  *		beyond the last slash in the string (this permits argv[0]
1577c478bd9Sstevel@tonic-gate  *		to be used).
1587c478bd9Sstevel@tonic-gate  *
1597c478bd9Sstevel@tonic-gate  *  Returns:  Void
1607c478bd9Sstevel@tonic-gate  */
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static void
initmsg(char * p)163*8d489c7aSmuffin initmsg(char *p)	/* Ptr to command name */
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	/* Automatic data */
1667c478bd9Sstevel@tonic-gate 	char   *q;		/* Local multi-use pointer */
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	/* Use only the simple filename if there is a slash in the name */
169*8d489c7aSmuffin 	if ((q = strrchr(p, '/')) == NULL)
170*8d489c7aSmuffin 		q = p;
171*8d489c7aSmuffin 	else
172*8d489c7aSmuffin 		q++;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* Build the label for messages */
1757c478bd9Sstevel@tonic-gate 	(void) snprintf(fcnlbl, sizeof (fcnlbl), "UX:%s", q);
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	/*
1787c478bd9Sstevel@tonic-gate 	 * Now that we've done all of that work, set things up so that
1797c478bd9Sstevel@tonic-gate 	 * only the text-component of a message is printed.  (This piece
1807c478bd9Sstevel@tonic-gate 	 * of code will most probably go away in SVR4.1.
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	(void) putenv("MSGVERB=text");
1837c478bd9Sstevel@tonic-gate }
184*8d489c7aSmuffin 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  *  void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
1877c478bd9Sstevel@tonic-gate  *
1887c478bd9Sstevel@tonic-gate  *	This function writes a message using the standard message
1897c478bd9Sstevel@tonic-gate  * 	generation facility.
1907c478bd9Sstevel@tonic-gate  *
1917c478bd9Sstevel@tonic-gate  *  Arguments:
1927c478bd9Sstevel@tonic-gate  *	severity	The severity-component of the message
1937c478bd9Sstevel@tonic-gate  *	action		The action-string used to generate the action-
1947c478bd9Sstevel@tonic-gate  *			component of the message
1957c478bd9Sstevel@tonic-gate  *	tag		Tag-component of the message
1967c478bd9Sstevel@tonic-gate  *	text		The text-string used to generate the text-component
1977c478bd9Sstevel@tonic-gate  *			of the message
1987c478bd9Sstevel@tonic-gate  *	txtarg		Arguments to be inserted into the "text" string using
1997c478bd9Sstevel@tonic-gate  *			vsnprintf()
2007c478bd9Sstevel@tonic-gate  *
2017c478bd9Sstevel@tonic-gate  *  Returns:  Void
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /* VARARGS4 */
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static void
wrtmsg(int severity,char * action,char * tag,char * text,...)2077c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	/* Automatic data */
2107c478bd9Sstevel@tonic-gate 	int		errorflg;	/* FLAG:  True if error writing msg */
2117c478bd9Sstevel@tonic-gate 	va_list		argp;		/* Pointer into vararg list */
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	errorflg = FALSE;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/* Generate the error message */
2167c478bd9Sstevel@tonic-gate 	va_start(argp, text);
217*8d489c7aSmuffin 	if (text != MM_NULLTXT) {
218*8d489c7aSmuffin 		/* LINTED */
2197c478bd9Sstevel@tonic-gate 		errorflg = vsnprintf(msgbuf, sizeof (msgbuf), text, argp) >
2207c478bd9Sstevel@tonic-gate 		    MM_MXTXTLN;
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 	(void) fmtmsg(MM_PRINT, fcnlbl, severity,
2237c478bd9Sstevel@tonic-gate 	    (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf,
2247c478bd9Sstevel@tonic-gate 	    action, tag);
2257c478bd9Sstevel@tonic-gate 	va_end(argp);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	/*
2287c478bd9Sstevel@tonic-gate 	 *  If there would have been a buffer overflow generating the error
2297c478bd9Sstevel@tonic-gate 	 *  message, the message will be truncated, so write a message and quit.
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	if (errorflg) {
2337c478bd9Sstevel@tonic-gate 		(void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
2347c478bd9Sstevel@tonic-gate 		    "Internal message buffer overflow",
2357c478bd9Sstevel@tonic-gate 		    MM_NULLACT, MM_NULLTAG);
2367c478bd9Sstevel@tonic-gate 		exit(100);
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate }
239*8d489c7aSmuffin 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  *  These functions allocate space for the information we gather.
2427c478bd9Sstevel@tonic-gate  *  It works by having a memory heap with strings allocated from
2437c478bd9Sstevel@tonic-gate  *  the end of the heap and structures (aligned data) allocated
2447c478bd9Sstevel@tonic-gate  *  from the beginning of the heap.  It begins with a 4k block of
2457c478bd9Sstevel@tonic-gate  *  memory then allocates memory in 4k chunks.  These functions
2467c478bd9Sstevel@tonic-gate  *  should never fail.  If they do, they report the problem and
2477c478bd9Sstevel@tonic-gate  *  exit with an exit code of 101.
2487c478bd9Sstevel@tonic-gate  *
2497c478bd9Sstevel@tonic-gate  *  Functions contained:
2507c478bd9Sstevel@tonic-gate  *	allocblk	Allocates a block of memory, aligned on a
2517c478bd9Sstevel@tonic-gate  *			4-byte (double-word) boundary.
2527c478bd9Sstevel@tonic-gate  *	allocstr	Allocates a block of memory with no particular
2537c478bd9Sstevel@tonic-gate  *			alignment
2547c478bd9Sstevel@tonic-gate  *
2557c478bd9Sstevel@tonic-gate  *  Constant definitions:
2567c478bd9Sstevel@tonic-gate  *	ALLOCBLKSZ	Size of a chunk of main memory allocated using
2577c478bd9Sstevel@tonic-gate  *			malloc()
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  *  Static data:
2607c478bd9Sstevel@tonic-gate  *	nextblkaddr	Address of the next available chunk of aligned
2617c478bd9Sstevel@tonic-gate  *			space in the heap
2627c478bd9Sstevel@tonic-gate  *	laststraddr	Address of the last chunk of unaligned space
2637c478bd9Sstevel@tonic-gate  *			allocated from the heap
2647c478bd9Sstevel@tonic-gate  *	toomuchspace	Message to write if someone attempts to allocate
2657c478bd9Sstevel@tonic-gate  *			too much space (>ALLOCBLKSZ bytes)
2667c478bd9Sstevel@tonic-gate  *	memallocdif	Message to write if there is a problem allocating
2677c478bd9Sstevel@tonic-gate  *			main memory.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate #define	ALLOCBLKSZ	4096
2717c478bd9Sstevel@tonic-gate 
272*8d489c7aSmuffin static char	*nextblkaddr = NULL;
273*8d489c7aSmuffin static char	*laststraddr = NULL;
274*8d489c7aSmuffin static char	*memallocdif =
275*8d489c7aSmuffin 	"Memory allocation difficulty.  Command terminates";
276*8d489c7aSmuffin static char	*toomuchspace =
277*8d489c7aSmuffin 	"Internal space allocation error.  Command terminates";
278*8d489c7aSmuffin 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  *  void *allocblk(size)
2817c478bd9Sstevel@tonic-gate  *	unsigned int	size
2827c478bd9Sstevel@tonic-gate  *
2837c478bd9Sstevel@tonic-gate  *	This function allocates a block of aligned (4-byte or double-
2847c478bd9Sstevel@tonic-gate  *	word boundary) memory from the program's heap.  It returns a
2857c478bd9Sstevel@tonic-gate  *	pointer to that block of allocated memory.
2867c478bd9Sstevel@tonic-gate  *
2877c478bd9Sstevel@tonic-gate  *  Arguments:
2887c478bd9Sstevel@tonic-gate  *	size		Minimum number of bytes to allocate (will
2897c478bd9Sstevel@tonic-gate  *			round up to multiple of 4)
2907c478bd9Sstevel@tonic-gate  *
2917c478bd9Sstevel@tonic-gate  *  Returns:  void *
2927c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
2937c478bd9Sstevel@tonic-gate  */
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate static void *
allocblk(unsigned int size)296*8d489c7aSmuffin allocblk(unsigned int size)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	/* Automatic data */
2997c478bd9Sstevel@tonic-gate 	char   *rtnval;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* Make sure the sizes are aligned correctly */
3037c478bd9Sstevel@tonic-gate 	if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) {
3047c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace);
3057c478bd9Sstevel@tonic-gate 		exit(101);
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/* Set up the value we're going to return */
3097c478bd9Sstevel@tonic-gate 	rtnval = nextblkaddr;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/* Get the space we need off of the heap */
3127c478bd9Sstevel@tonic-gate 	if ((nextblkaddr += size) >= laststraddr) {
313*8d489c7aSmuffin 		if ((rtnval = malloc(ALLOCBLKSZ)) == NULL) {
3147c478bd9Sstevel@tonic-gate 			wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif);
3157c478bd9Sstevel@tonic-gate 			exit(101);
3167c478bd9Sstevel@tonic-gate 		}
3177c478bd9Sstevel@tonic-gate 		laststraddr = rtnval + ALLOCBLKSZ;
3187c478bd9Sstevel@tonic-gate 		nextblkaddr = rtnval + size;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	/* We're through */
3227c478bd9Sstevel@tonic-gate 	return ((void *)rtnval);
3237c478bd9Sstevel@tonic-gate }
324*8d489c7aSmuffin 
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate  *  char *allocstr(nbytes)
3277c478bd9Sstevel@tonic-gate  *	unsigned int	nbytes
3287c478bd9Sstevel@tonic-gate  *
3297c478bd9Sstevel@tonic-gate  *	This function allocates a block of unaligned memory from the
3307c478bd9Sstevel@tonic-gate  *	program's heap.  It returns a pointer to that block of allocated
3317c478bd9Sstevel@tonic-gate  *	memory.
3327c478bd9Sstevel@tonic-gate  *
3337c478bd9Sstevel@tonic-gate  *  Arguments:
3347c478bd9Sstevel@tonic-gate  *	nbytes		Number of bytes to allocate
3357c478bd9Sstevel@tonic-gate  *
3367c478bd9Sstevel@tonic-gate  *  Returns:  char *
3377c478bd9Sstevel@tonic-gate  *	Pointer to the allocated block of memory
3387c478bd9Sstevel@tonic-gate  */
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate static char *
allocstr(unsigned int nchars)341*8d489c7aSmuffin allocstr(unsigned int nchars)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate 	if (nchars > ALLOCBLKSZ) {
3447c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace);
3457c478bd9Sstevel@tonic-gate 		exit(101);
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 	if ((laststraddr -= nchars) < nextblkaddr) {
348*8d489c7aSmuffin 		if ((nextblkaddr = malloc(ALLOCBLKSZ)) == NULL) {
3497c478bd9Sstevel@tonic-gate 			wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif);
3507c478bd9Sstevel@tonic-gate 			exit(101);
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 		laststraddr = nextblkaddr + ALLOCBLKSZ - nchars;
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	return (laststraddr);
3557c478bd9Sstevel@tonic-gate }
356*8d489c7aSmuffin 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  *  These functions control the group membership list, as found in the
3597c478bd9Sstevel@tonic-gate  *  /etc/group file.
3607c478bd9Sstevel@tonic-gate  *
3617c478bd9Sstevel@tonic-gate  *  Functions included:
3627c478bd9Sstevel@tonic-gate  *	initmembers		Initialize the membership list (to NULL)
3637c478bd9Sstevel@tonic-gate  *	addmember		Adds a member to the membership list
3647c478bd9Sstevel@tonic-gate  *	isamember		Looks for a particular login-ID in the list
3657c478bd9Sstevel@tonic-gate  *				of members
3667c478bd9Sstevel@tonic-gate  *
3677c478bd9Sstevel@tonic-gate  *  Datatype Definitions:
3687c478bd9Sstevel@tonic-gate  *	struct grpmember	Describes a group member
3697c478bd9Sstevel@tonic-gate  *
3707c478bd9Sstevel@tonic-gate  *  Static Data:
3717c478bd9Sstevel@tonic-gate  *	membershead		Pointer to the head of the list of group members
3727c478bd9Sstevel@tonic-gate  */
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate struct	grpmember {
3757c478bd9Sstevel@tonic-gate 	char			*membername;
3767c478bd9Sstevel@tonic-gate 	struct grpmember	*next;
3777c478bd9Sstevel@tonic-gate };
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate static	struct grpmember	*membershead;
380*8d489c7aSmuffin 
3817c478bd9Sstevel@tonic-gate /*
3827c478bd9Sstevel@tonic-gate  *  void initmembers()
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  *	This function initializes the list of members of specified groups.
3857c478bd9Sstevel@tonic-gate  *
3867c478bd9Sstevel@tonic-gate  *  Arguments:  None
3877c478bd9Sstevel@tonic-gate  *
3887c478bd9Sstevel@tonic-gate  *  Returns:  Void
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate static void
initmembers(void)392*8d489c7aSmuffin initmembers(void)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	/* Set up the members list to be a null member's list */
395*8d489c7aSmuffin 	membershead = NULL;
3967c478bd9Sstevel@tonic-gate }
397*8d489c7aSmuffin 
3987c478bd9Sstevel@tonic-gate /*
3997c478bd9Sstevel@tonic-gate  *  void addmember(p)
4007c478bd9Sstevel@tonic-gate  *	char   *p
4017c478bd9Sstevel@tonic-gate  *
4027c478bd9Sstevel@tonic-gate  *	This function adds a member to the group member's list.  The
4037c478bd9Sstevel@tonic-gate  *	group members list is a list of structures containing a pointer
4047c478bd9Sstevel@tonic-gate  *	to the member-name and a pointer to the next item in the structure.
4057c478bd9Sstevel@tonic-gate  *	The structure is not ordered in any particular way.
4067c478bd9Sstevel@tonic-gate  *
4077c478bd9Sstevel@tonic-gate  *  Arguments:
4087c478bd9Sstevel@tonic-gate  *	p	Pointer to the member name
4097c478bd9Sstevel@tonic-gate  *
4107c478bd9Sstevel@tonic-gate  *  Returns:  Void
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate static void
addmember(char * p)414*8d489c7aSmuffin addmember(char *p)
4157c478bd9Sstevel@tonic-gate {
4167c478bd9Sstevel@tonic-gate 	/* Automatic data */
4177c478bd9Sstevel@tonic-gate 	struct grpmember	*new;	/* Member being added */
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	new = (struct grpmember *)allocblk(sizeof (struct grpmember));
4207c478bd9Sstevel@tonic-gate 	new->membername = strcpy(allocstr((unsigned int)strlen(p)+1), p);
4217c478bd9Sstevel@tonic-gate 	new->next = membershead;
4227c478bd9Sstevel@tonic-gate 	membershead = new;
4237c478bd9Sstevel@tonic-gate }
424*8d489c7aSmuffin 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  *  init isamember(p)
4277c478bd9Sstevel@tonic-gate  *	char   *p
4287c478bd9Sstevel@tonic-gate  *
4297c478bd9Sstevel@tonic-gate  *	This function examines the list of group-members for the string
4307c478bd9Sstevel@tonic-gate  *	referenced by 'p'.  If 'p' is a member of the members list, the
4317c478bd9Sstevel@tonic-gate  *	function returns TRUE.  Otherwise it returns FALSE.
4327c478bd9Sstevel@tonic-gate  *
4337c478bd9Sstevel@tonic-gate  *  Arguments:
4347c478bd9Sstevel@tonic-gate  *	p	Pointer to the name to search for.
4357c478bd9Sstevel@tonic-gate  *
4367c478bd9Sstevel@tonic-gate  *  Returns:  int
4377c478bd9Sstevel@tonic-gate  *	TRUE	If 'p' is found in the members list,
4387c478bd9Sstevel@tonic-gate  *	FALSE	otherwise
4397c478bd9Sstevel@tonic-gate  */
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate static int
isamember(char * p)442*8d489c7aSmuffin isamember(char *p)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate 	/* Automatic Data */
4457c478bd9Sstevel@tonic-gate 	int			found;	/* FLAG:  TRUE if login found */
4467c478bd9Sstevel@tonic-gate 	struct grpmember	*pmem;	/* Pointer to group member */
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/* Search the membership list for the 'p' */
4507c478bd9Sstevel@tonic-gate 	found = FALSE;
4517c478bd9Sstevel@tonic-gate 	for (pmem = membershead; !found && pmem; pmem = pmem->next) {
4527c478bd9Sstevel@tonic-gate 		if (strcmp(p, pmem->membername) == 0) found = TRUE;
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	return (found);
4567c478bd9Sstevel@tonic-gate }
457*8d489c7aSmuffin 
4587c478bd9Sstevel@tonic-gate /*
4597c478bd9Sstevel@tonic-gate  *  These functions handle the display list.  The display list contains
4607c478bd9Sstevel@tonic-gate  *  all of the information we're to display.  The list contains a pointer
4617c478bd9Sstevel@tonic-gate  *  to the login-name, a pointer to the free-field (comment), and a pointer
4627c478bd9Sstevel@tonic-gate  *  to the next item in the list.  The list is ordered alphabetically
4637c478bd9Sstevel@tonic-gate  *  (ascending) on the login-name field.  The list initially contains a
4647c478bd9Sstevel@tonic-gate  *  dummy field (to make insertion easier) that contains a login-name of "".
4657c478bd9Sstevel@tonic-gate  *
4667c478bd9Sstevel@tonic-gate  *  Functions included:
4677c478bd9Sstevel@tonic-gate  *	initdisp	Initializes the display list
4687c478bd9Sstevel@tonic-gate  *	adddisp		Adds information to the display list
4697c478bd9Sstevel@tonic-gate  *	genreport	Generates a report from the items in the display list
4707c478bd9Sstevel@tonic-gate  *
4717c478bd9Sstevel@tonic-gate  *  Datatypes Defined:
4727c478bd9Sstevel@tonic-gate  *	struct display	Describes the structure that contains the
4737c478bd9Sstevel@tonic-gate  *			information to be displayed.  Includes pointers
4747c478bd9Sstevel@tonic-gate  *			to the login-ID, free-field (comment), and the
4757c478bd9Sstevel@tonic-gate  *			next structure in the list.
4767c478bd9Sstevel@tonic-gate  *
4777c478bd9Sstevel@tonic-gate  *  Static Data:
4787c478bd9Sstevel@tonic-gate  *	displayhead	Pointer to the head of the list of login-IDs to
4797c478bd9Sstevel@tonic-gate  *			be displayed.  Initially references the null-item
4807c478bd9Sstevel@tonic-gate  *			on the head of the list.
4817c478bd9Sstevel@tonic-gate  */
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate struct	display {
4847c478bd9Sstevel@tonic-gate 	char		*loginID;
4857c478bd9Sstevel@tonic-gate 	char		*freefield;
4867c478bd9Sstevel@tonic-gate 	struct display	*next;
4877c478bd9Sstevel@tonic-gate };
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate static	struct display *displayhead;
490*8d489c7aSmuffin 
4917c478bd9Sstevel@tonic-gate /*
4927c478bd9Sstevel@tonic-gate  *  void initdisp()
4937c478bd9Sstevel@tonic-gate  *
4947c478bd9Sstevel@tonic-gate  *	Initializes the display list.  An empty display list contains a
4957c478bd9Sstevel@tonic-gate  *	single element, the dummy element.
4967c478bd9Sstevel@tonic-gate  *
4977c478bd9Sstevel@tonic-gate  *  Arguments:  None
4987c478bd9Sstevel@tonic-gate  *
4997c478bd9Sstevel@tonic-gate  *  Returns:  Void
5007c478bd9Sstevel@tonic-gate  */
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate static void
initdisp(void)503*8d489c7aSmuffin initdisp(void)
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate 	displayhead = (struct display *)allocblk(sizeof (struct display));
506*8d489c7aSmuffin 	displayhead->next = NULL;
5077c478bd9Sstevel@tonic-gate 	displayhead->loginID = "";
5087c478bd9Sstevel@tonic-gate 	displayhead->freefield = "";
5097c478bd9Sstevel@tonic-gate }
510*8d489c7aSmuffin 
5117c478bd9Sstevel@tonic-gate /*
5127c478bd9Sstevel@tonic-gate  *  void adddisp(pwent)
5137c478bd9Sstevel@tonic-gate  *	struct passwd  *pwent
5147c478bd9Sstevel@tonic-gate  *
5157c478bd9Sstevel@tonic-gate  *	This function adds the appropriate information from the login
5167c478bd9Sstevel@tonic-gate  *	description referenced by 'pwent' to the list if information
5177c478bd9Sstevel@tonic-gate  *	to be displayed.  It only adds the information if the login-ID
5187c478bd9Sstevel@tonic-gate  *	(user-name) is unique.  It inserts the information in the list
5197c478bd9Sstevel@tonic-gate  *	in such a way that the list remains ordered alphabetically
5207c478bd9Sstevel@tonic-gate  *	(ascending) according to the login-ID (user-name).
5217c478bd9Sstevel@tonic-gate  *
5227c478bd9Sstevel@tonic-gate  *  Arguments:
5237c478bd9Sstevel@tonic-gate  *	pwent		Points to the (struct passwd) structure that
5247c478bd9Sstevel@tonic-gate  *			contains all of the login information on the
5257c478bd9Sstevel@tonic-gate  *			login being added to the list.  The only
5267c478bd9Sstevel@tonic-gate  *			information that this function uses is the
5277c478bd9Sstevel@tonic-gate  *			login-ID (user-name) and the free-field
5287c478bd9Sstevel@tonic-gate  *			(comment field).
5297c478bd9Sstevel@tonic-gate  *
5307c478bd9Sstevel@tonic-gate  *  Returns:  Void
5317c478bd9Sstevel@tonic-gate  */
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static void
adddisp(struct passwd * pwent)534*8d489c7aSmuffin adddisp(struct passwd *pwent)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	/* Automatic data */
5377c478bd9Sstevel@tonic-gate 	struct display	*new;		/* Display item being added */
5387c478bd9Sstevel@tonic-gate 	struct display	*prev;		/* Previous display item */
5397c478bd9Sstevel@tonic-gate 	struct display	*current;	/* Next display item */
5407c478bd9Sstevel@tonic-gate 	int	found;			/* FLAG, insertion point found */
5417c478bd9Sstevel@tonic-gate 	int	compare = 1;		/* strcmp() compare value */
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/* Find where this value belongs in the list */
5457c478bd9Sstevel@tonic-gate 	prev = displayhead;
5467c478bd9Sstevel@tonic-gate 	current = displayhead->next;
5477c478bd9Sstevel@tonic-gate 	found = FALSE;
5487c478bd9Sstevel@tonic-gate 	while (!found && current) {
5497c478bd9Sstevel@tonic-gate 		if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0)
5507c478bd9Sstevel@tonic-gate 			found = TRUE;
5517c478bd9Sstevel@tonic-gate 		else {
5527c478bd9Sstevel@tonic-gate 			prev = current;
5537c478bd9Sstevel@tonic-gate 			current = current->next;
5547c478bd9Sstevel@tonic-gate 		}
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	/* Insert this value in the list, only if it is unique though */
5587c478bd9Sstevel@tonic-gate 	if (compare != 0) {
559*8d489c7aSmuffin 		/*
560*8d489c7aSmuffin 		 * Build a display structure containing the value to add to
561*8d489c7aSmuffin 		 * the list, and add to the list
562*8d489c7aSmuffin 		 */
5637c478bd9Sstevel@tonic-gate 		new = (struct display *)allocblk(sizeof (struct display));
564*8d489c7aSmuffin 		new->loginID =
565*8d489c7aSmuffin 		    strcpy(allocstr((unsigned int)strlen(pwent->pw_name)+1),
566*8d489c7aSmuffin 		    pwent->pw_name);
5677c478bd9Sstevel@tonic-gate 		if (pwent->pw_comment && pwent->pw_comment[0] != '\0')
5687c478bd9Sstevel@tonic-gate 			new->freefield =
569*8d489c7aSmuffin 			    strcpy(allocstr(
570*8d489c7aSmuffin 			    (unsigned int)strlen(pwent->pw_comment)+1),
5717c478bd9Sstevel@tonic-gate 			    pwent->pw_comment);
5727c478bd9Sstevel@tonic-gate 		else
5737c478bd9Sstevel@tonic-gate 			new->freefield =
574*8d489c7aSmuffin 			    strcpy(allocstr(
575*8d489c7aSmuffin 			    (unsigned int)strlen(pwent->pw_gecos)+1),
5767c478bd9Sstevel@tonic-gate 			    pwent->pw_gecos);
5777c478bd9Sstevel@tonic-gate 		new->next = current;
5787c478bd9Sstevel@tonic-gate 		prev->next = new;
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate }
581*8d489c7aSmuffin 
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate  *  void genreport()
5847c478bd9Sstevel@tonic-gate  *
5857c478bd9Sstevel@tonic-gate  *	This function generates a report on the standard output stream
5867c478bd9Sstevel@tonic-gate  *	(stdout) containing the login-IDs and the free-fields of the
5877c478bd9Sstevel@tonic-gate  *	logins that match the list criteria (-g and -l options)
5887c478bd9Sstevel@tonic-gate  *
5897c478bd9Sstevel@tonic-gate  *  Arguments:  None
5907c478bd9Sstevel@tonic-gate  *
5917c478bd9Sstevel@tonic-gate  *  Returns:  Void
5927c478bd9Sstevel@tonic-gate  */
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate static void
genreport(void)595*8d489c7aSmuffin genreport(void)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/* Automatic data */
5997c478bd9Sstevel@tonic-gate 	struct display		*current;	/* Value to display */
6007c478bd9Sstevel@tonic-gate 	int			i;		/* Counter of characters */
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/*
6037c478bd9Sstevel@tonic-gate 	 *  Initialization for loop.
6047c478bd9Sstevel@tonic-gate 	 *  (NOTE:  The first element in the list of logins to display
6057c478bd9Sstevel@tonic-gate 	 *  is a dummy element.)
6067c478bd9Sstevel@tonic-gate 	 */
6077c478bd9Sstevel@tonic-gate 	current = displayhead;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	/*
6107c478bd9Sstevel@tonic-gate 	 *  Display elements in the list
6117c478bd9Sstevel@tonic-gate 	 */
6127c478bd9Sstevel@tonic-gate 	for (current = displayhead->next; current; current = current->next) {
6137c478bd9Sstevel@tonic-gate 		(void) fputs(current->loginID, stdout);
614*8d489c7aSmuffin 		for (i = LOGINFIELDSZ - strlen(current->loginID); --i >= 0;
615*8d489c7aSmuffin 		    (void) putc(' ', stdout))
616*8d489c7aSmuffin 			;
6177c478bd9Sstevel@tonic-gate 		(void) fputs(current->freefield, stdout);
6187c478bd9Sstevel@tonic-gate 		(void) putc('\n', stdout);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate }
621*8d489c7aSmuffin 
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate  * listusers [-l logins] [-g groups]
6247c478bd9Sstevel@tonic-gate  *
6257c478bd9Sstevel@tonic-gate  *	This command generates a list of user login-IDs.  Specific login-IDs
6267c478bd9Sstevel@tonic-gate  *	can be listed, as can logins belonging in specific groups.
6277c478bd9Sstevel@tonic-gate  *
6287c478bd9Sstevel@tonic-gate  *	-l logins	specifies the login-IDs to display.  "logins" is a
6297c478bd9Sstevel@tonic-gate  *			comma-list of login-IDs.
6307c478bd9Sstevel@tonic-gate  *	-g groups	specifies the names of the groups to which a login-ID
6317c478bd9Sstevel@tonic-gate  *			must belong before it is included in the generated list.
6327c478bd9Sstevel@tonic-gate  *			"groups" is a comma-list of group names.
6337c478bd9Sstevel@tonic-gate  * Exit Codes:
6347c478bd9Sstevel@tonic-gate  *	0	All's well that ends well
6357c478bd9Sstevel@tonic-gate  *	1	Usage error
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate 
638*8d489c7aSmuffin int
main(int argc,char ** argv)639*8d489c7aSmuffin main(int argc, char **argv)
6407c478bd9Sstevel@tonic-gate {
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/* Automatic data */
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	struct reqgrp	*reqgrphead;	/* Head of the req'd group list */
6457c478bd9Sstevel@tonic-gate 	struct reqgrp	*pgrp;	/* Current item in the req'd group list */
6467c478bd9Sstevel@tonic-gate 	struct reqgrp	*qgrp;		/* Prev item in the req'd group list */
6477c478bd9Sstevel@tonic-gate 	struct reqgrp	*rgrp;	/* Running ptr for scanning group list */
6487c478bd9Sstevel@tonic-gate 	struct reqlogin	*reqloginhead;	/* Head of req'd login list */
6497c478bd9Sstevel@tonic-gate 	struct reqlogin	*plogin; /* Current item in the req'd login list */
6507c478bd9Sstevel@tonic-gate 	struct reqlogin	*qlogin; /* Previous item in the req'd login list */
6517c478bd9Sstevel@tonic-gate 	struct reqlogin	*rlogin; /* Running ptr for scanning login list */
6527c478bd9Sstevel@tonic-gate 	struct passwd	*pwent;		/* Ptr to an /etc/passwd entry */
6537c478bd9Sstevel@tonic-gate 	struct group	*grent;		/* Ptr to an /etc/group entry */
6547c478bd9Sstevel@tonic-gate 	char	*token;		/* Ptr to a token extracted by strtok() */
6557c478bd9Sstevel@tonic-gate 	char	**pp;		/* Ptr to a member of a group */
6567c478bd9Sstevel@tonic-gate 	char	*g_arg;		/* Ptr to the -g option's argument */
6577c478bd9Sstevel@tonic-gate 	char	*l_arg;		/* Ptr to the -l option's argument */
6587c478bd9Sstevel@tonic-gate 	int	g_seen;		/* FLAG, true if -g on cmd */
6597c478bd9Sstevel@tonic-gate 	int	l_seen;		/* FLAG, TRUE if -l is on the command line */
6607c478bd9Sstevel@tonic-gate 	int	errflg;	/* FLAG, TRUE if there is a command-line problem */
6617c478bd9Sstevel@tonic-gate 	int	done;		/* FLAG, TRUE if the process (?) is complete */
6627c478bd9Sstevel@tonic-gate 	int	groupcount;	/* Number of groups specified by the user */
6637c478bd9Sstevel@tonic-gate 	int	rc;		/* Return code from strcmp() */
6647c478bd9Sstevel@tonic-gate 	int	c;		/* Character returned from getopt() */
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	/* Initializations */
6687c478bd9Sstevel@tonic-gate 	initmsg(argv[0]);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/* Command-line processing */
6717c478bd9Sstevel@tonic-gate 	g_seen = FALSE;
6727c478bd9Sstevel@tonic-gate 	l_seen = FALSE;
6737c478bd9Sstevel@tonic-gate 	errflg = FALSE;
6747c478bd9Sstevel@tonic-gate 	opterr = 0;
6757c478bd9Sstevel@tonic-gate 	while (!errflg && ((c = getopt(argc, argv, "g:l:")) != EOF)) {
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate 		/* Case on the option character */
6787c478bd9Sstevel@tonic-gate 		switch (c) {
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		case 'g':
681*8d489c7aSmuffin 			if (g_seen)
682*8d489c7aSmuffin 				errflg = TRUE;
6837c478bd9Sstevel@tonic-gate 			else {
6847c478bd9Sstevel@tonic-gate 				g_seen = TRUE;
6857c478bd9Sstevel@tonic-gate 				g_arg = optarg;
6867c478bd9Sstevel@tonic-gate 			}
6877c478bd9Sstevel@tonic-gate 			break;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 		case 'l':
690*8d489c7aSmuffin 			if (l_seen)
691*8d489c7aSmuffin 				errflg = TRUE;
6927c478bd9Sstevel@tonic-gate 			else {
6937c478bd9Sstevel@tonic-gate 				l_seen = TRUE;
6947c478bd9Sstevel@tonic-gate 				l_arg = optarg;
6957c478bd9Sstevel@tonic-gate 			}
6967c478bd9Sstevel@tonic-gate 			break;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		default:
6997c478bd9Sstevel@tonic-gate 			errflg = TRUE;
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	/* Write out a usage message if necessary and quit */
7047c478bd9Sstevel@tonic-gate 	if (errflg || (optind != argc)) {
7057c478bd9Sstevel@tonic-gate 		wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, USAGE_MSG);
7067c478bd9Sstevel@tonic-gate 		exit(1);
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	/*
7117c478bd9Sstevel@tonic-gate 	 *  If the -g groups option was on the command line, build a
7127c478bd9Sstevel@tonic-gate 	 *  list containing groups we're to list logins for.
7137c478bd9Sstevel@tonic-gate 	 */
7147c478bd9Sstevel@tonic-gate 	if (g_seen) {
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		/* Begin with an empty list */
7177c478bd9Sstevel@tonic-gate 		groupcount = 0;
718*8d489c7aSmuffin 		reqgrphead = NULL;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		/* Extract the first token putting an element on the list */
721*8d489c7aSmuffin 		if ((token = strtok(g_arg, ",")) != NULL) {
722*8d489c7aSmuffin 			pgrp = (struct reqgrp *)
723*8d489c7aSmuffin 			    allocblk(sizeof (struct reqgrp));
7247c478bd9Sstevel@tonic-gate 			pgrp->groupname = token;
7257c478bd9Sstevel@tonic-gate 			pgrp->found = FALSE;
726*8d489c7aSmuffin 			pgrp->next = NULL;
7277c478bd9Sstevel@tonic-gate 			groupcount++;
7287c478bd9Sstevel@tonic-gate 			reqgrphead = pgrp;
7297c478bd9Sstevel@tonic-gate 			qgrp = pgrp;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 			/*
732*8d489c7aSmuffin 			 * Extract subsequent tokens (group names), avoiding
733*8d489c7aSmuffin 			 * duplicate names (note, list is NOT empty)
7347c478bd9Sstevel@tonic-gate 			 */
735*8d489c7aSmuffin 			while (token = strtok(NULL, ",")) {
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 				/* Check for duplication */
7387c478bd9Sstevel@tonic-gate 				rgrp = reqgrphead;
739*8d489c7aSmuffin 				while (rgrp &&
740*8d489c7aSmuffin 				    (rc = strcmp(token, rgrp->groupname)))
741*8d489c7aSmuffin 					rgrp = rgrp->next;
7427c478bd9Sstevel@tonic-gate 				if (rc != 0) {
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 					/* Not a duplicate.  Add on the list */
745*8d489c7aSmuffin 					pgrp = (struct reqgrp *)
746*8d489c7aSmuffin 					    allocblk(sizeof (struct reqgrp));
7477c478bd9Sstevel@tonic-gate 					pgrp->groupname = token;
7487c478bd9Sstevel@tonic-gate 					pgrp->found = FALSE;
749*8d489c7aSmuffin 					pgrp->next = NULL;
7507c478bd9Sstevel@tonic-gate 					groupcount++;
7517c478bd9Sstevel@tonic-gate 					qgrp->next = pgrp;
7527c478bd9Sstevel@tonic-gate 					qgrp = pgrp;
7537c478bd9Sstevel@tonic-gate 				}
7547c478bd9Sstevel@tonic-gate 			}
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 	}
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	/*
7597c478bd9Sstevel@tonic-gate 	 *  If -l logins is on the command line, build a list of logins
7607c478bd9Sstevel@tonic-gate 	 *  we're to generate reports for.
7617c478bd9Sstevel@tonic-gate 	 */
7627c478bd9Sstevel@tonic-gate 	if (l_seen) {
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 		/* Begin with a null list */
765*8d489c7aSmuffin 		reqloginhead = NULL;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 		/* Extract the first token from the argument to the -l option */
7687c478bd9Sstevel@tonic-gate 		if (token = strtok(l_arg, ",")) {
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 			/* Put the first element in the list */
771*8d489c7aSmuffin 			plogin = (struct reqlogin *)
772*8d489c7aSmuffin 			    allocblk(sizeof (struct reqlogin));
7737c478bd9Sstevel@tonic-gate 			plogin->loginname = token;
7747c478bd9Sstevel@tonic-gate 			plogin->found = FALSE;
775*8d489c7aSmuffin 			plogin->next = NULL;
7767c478bd9Sstevel@tonic-gate 			reqloginhead = plogin;
7777c478bd9Sstevel@tonic-gate 			qlogin = plogin;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 			/*
7807c478bd9Sstevel@tonic-gate 			 * For each subsequent token in the -l argument's
7817c478bd9Sstevel@tonic-gate 			 * comma list ...
7827c478bd9Sstevel@tonic-gate 			 */
7837c478bd9Sstevel@tonic-gate 
784*8d489c7aSmuffin 			while (token = strtok(NULL, ",")) {
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 				/* Check for duplication (list is not empty) */
7877c478bd9Sstevel@tonic-gate 				rlogin = reqloginhead;
788*8d489c7aSmuffin 				while (rlogin &&
789*8d489c7aSmuffin 				    (rc = strcmp(token, rlogin->loginname)))
7907c478bd9Sstevel@tonic-gate 					rlogin = rlogin->next;
7917c478bd9Sstevel@tonic-gate 
792*8d489c7aSmuffin 				/*
793*8d489c7aSmuffin 				 * If it's not a duplicate,
794*8d489c7aSmuffin 				 * add it to the list
795*8d489c7aSmuffin 				 */
7967c478bd9Sstevel@tonic-gate 				if (rc != 0) {
797*8d489c7aSmuffin 					plogin = (struct reqlogin *)
798*8d489c7aSmuffin 					    allocblk(sizeof (struct reqlogin));
7997c478bd9Sstevel@tonic-gate 					plogin->loginname = token;
8007c478bd9Sstevel@tonic-gate 					plogin->found = FALSE;
801*8d489c7aSmuffin 					plogin->next = NULL;
8027c478bd9Sstevel@tonic-gate 					qlogin->next = plogin;
8037c478bd9Sstevel@tonic-gate 					qlogin = plogin;
8047c478bd9Sstevel@tonic-gate 				}
8057c478bd9Sstevel@tonic-gate 			}
8067c478bd9Sstevel@tonic-gate 		}
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	/*
8117c478bd9Sstevel@tonic-gate 	 *  If the user requested that only logins be listed in that belong
8127c478bd9Sstevel@tonic-gate 	 *  to certain groups, compile a list of logins that belong in that
8137c478bd9Sstevel@tonic-gate 	 *  group.  If the user also requested specific logins, that list
8147c478bd9Sstevel@tonic-gate 	 *  will be limited to those logins.
8157c478bd9Sstevel@tonic-gate 	 */
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	/* Initialize the login list */
8187c478bd9Sstevel@tonic-gate 	initmembers();
8197c478bd9Sstevel@tonic-gate 	if (g_seen) {
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		/* For each group in the /etc/group file ... */
8227c478bd9Sstevel@tonic-gate 		while (grent = getgrent()) {
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 			/* For each group mentioned with the -g option ... */
825*8d489c7aSmuffin 			for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
826*8d489c7aSmuffin 			    pgrp = pgrp->next) {
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 				if (pgrp->found == FALSE) {
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 					/*
831*8d489c7aSmuffin 					 * If the mentioned group is found in
832*8d489c7aSmuffin 					 * the /etc/group file ...
8337c478bd9Sstevel@tonic-gate 					 */
834*8d489c7aSmuffin 					if (strcmp(grent->gr_name,
835*8d489c7aSmuffin 					    pgrp->groupname) == 0) {
8367c478bd9Sstevel@tonic-gate 
837*8d489c7aSmuffin 						/*
838*8d489c7aSmuffin 						 * Mark the entry is found,
839*8d489c7aSmuffin 						 * remembering the group-ID
840*8d489c7aSmuffin 						 * for later
841*8d489c7aSmuffin 						 */
8427c478bd9Sstevel@tonic-gate 						pgrp->found = TRUE;
8437c478bd9Sstevel@tonic-gate 						groupcount--;
8447c478bd9Sstevel@tonic-gate 						pgrp->groupID = grent->gr_gid;
8457c478bd9Sstevel@tonic-gate 						if (isausergroup(pgrp->groupID))
846*8d489c7aSmuffin 							for (pp = grent->gr_mem;
847*8d489c7aSmuffin 							    *pp; pp++)
848*8d489c7aSmuffin 								addmember(*pp);
8497c478bd9Sstevel@tonic-gate 					}
8507c478bd9Sstevel@tonic-gate 				}
8517c478bd9Sstevel@tonic-gate 			}
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 
854*8d489c7aSmuffin 		/*
855*8d489c7aSmuffin 		 * If any groups weren't found, write a message
856*8d489c7aSmuffin 		 * indicating such, then continue
857*8d489c7aSmuffin 		 */
858*8d489c7aSmuffin 		qgrp = NULL;
8597c478bd9Sstevel@tonic-gate 		for (pgrp = reqgrphead; pgrp; pgrp = pgrp->next) {
8607c478bd9Sstevel@tonic-gate 			if (!pgrp->found) {
861*8d489c7aSmuffin 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
862*8d489c7aSmuffin 				    "%s was not found", pgrp->groupname);
863*8d489c7aSmuffin 				if (!qgrp)
864*8d489c7aSmuffin 					reqgrphead = pgrp->next;
865*8d489c7aSmuffin 				else
866*8d489c7aSmuffin 					qgrp->next = pgrp->next;
867*8d489c7aSmuffin 			} else if (isasystemgroup(pgrp->groupID)) {
868*8d489c7aSmuffin 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
869*8d489c7aSmuffin 				    "%s is not a user group", pgrp->groupname);
870*8d489c7aSmuffin 				if (!qgrp)
871*8d489c7aSmuffin 					reqgrphead = pgrp->next;
872*8d489c7aSmuffin 				else
873*8d489c7aSmuffin 					qgrp->next = pgrp->next;
874*8d489c7aSmuffin 			} else
875*8d489c7aSmuffin 				qgrp = pgrp;
8767c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	/* Initialize the list of logins to display */
8817c478bd9Sstevel@tonic-gate 	initdisp();
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 *  Loop through the /etc/passwd file squirelling away the
8867c478bd9Sstevel@tonic-gate 	 *  information we need for the display.
8877c478bd9Sstevel@tonic-gate 	 */
8887c478bd9Sstevel@tonic-gate 	while (pwent = getpwent()) {
8897c478bd9Sstevel@tonic-gate 
890*8d489c7aSmuffin 		/*
891*8d489c7aSmuffin 		 * The login from /etc/passwd hasn't been included in
892*8d489c7aSmuffin 		 * the display yet
893*8d489c7aSmuffin 		 */
8947c478bd9Sstevel@tonic-gate 		done = FALSE;
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		/*
8987c478bd9Sstevel@tonic-gate 		 * If the login was explicitly requested, include it in
8997c478bd9Sstevel@tonic-gate 		 * the display if it is a user login
9007c478bd9Sstevel@tonic-gate 		 */
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 		if (l_seen) {
903*8d489c7aSmuffin 			for (plogin = reqloginhead; !done && plogin;
904*8d489c7aSmuffin 			    plogin = plogin->next) {
905*8d489c7aSmuffin 				if (strcmp(pwent->pw_name,
906*8d489c7aSmuffin 				    plogin->loginname) == 0) {
9077c478bd9Sstevel@tonic-gate 					plogin->found = TRUE;
908*8d489c7aSmuffin 					if (isauserlogin(pwent->pw_uid))
909*8d489c7aSmuffin 						adddisp(pwent);
9107c478bd9Sstevel@tonic-gate 					else
911*8d489c7aSmuffin 						wrtmsg(MM_WARNING, MM_NULLACT,
912*8d489c7aSmuffin 						    MM_NULLTAG,
913*8d489c7aSmuffin 						    "%s is not a user login",
914*8d489c7aSmuffin 						    plogin->loginname);
9157c478bd9Sstevel@tonic-gate 					done = TRUE;
9167c478bd9Sstevel@tonic-gate 				}
9177c478bd9Sstevel@tonic-gate 			}
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		/*
9227c478bd9Sstevel@tonic-gate 		 *  If the login-ID isn't already on the list, if its primary
9237c478bd9Sstevel@tonic-gate 		 *  group-ID is one of those groups requested, or it is a member
9247c478bd9Sstevel@tonic-gate 		 *  of the groups requested, include it in the display if it is
9257c478bd9Sstevel@tonic-gate 		 *  a user login (uid >= 100).
9267c478bd9Sstevel@tonic-gate 		 */
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		if (isauserlogin(pwent->pw_uid)) {
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 			if (!done && g_seen) {
931*8d489c7aSmuffin 				for (pgrp = reqgrphead; !done && pgrp;
932*8d489c7aSmuffin 				    pgrp = pgrp->next)
9337c478bd9Sstevel@tonic-gate 					if (pwent->pw_gid == pgrp->groupID) {
9347c478bd9Sstevel@tonic-gate 						adddisp(pwent);
9357c478bd9Sstevel@tonic-gate 						done = TRUE;
9367c478bd9Sstevel@tonic-gate 					}
9377c478bd9Sstevel@tonic-gate 				if (!done && isamember(pwent->pw_name)) {
9387c478bd9Sstevel@tonic-gate 					adddisp(pwent);
9397c478bd9Sstevel@tonic-gate 					done = TRUE;
9407c478bd9Sstevel@tonic-gate 				}
9417c478bd9Sstevel@tonic-gate 			}
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 			/*
945*8d489c7aSmuffin 			 * If neither -l nor -g is on the command-line and
946*8d489c7aSmuffin 			 * the login-ID is a user login, include it in
947*8d489c7aSmuffin 			 * the display.
9487c478bd9Sstevel@tonic-gate 			 */
9497c478bd9Sstevel@tonic-gate 
950*8d489c7aSmuffin 			if (!l_seen && !g_seen)
951*8d489c7aSmuffin 				adddisp(pwent);
9527c478bd9Sstevel@tonic-gate 		}
9537c478bd9Sstevel@tonic-gate 	}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* Let the user know about logins they requested that don't exist */
956*8d489c7aSmuffin 	if (l_seen)
957*8d489c7aSmuffin 		for (plogin = reqloginhead; plogin; plogin = plogin->next)
9587c478bd9Sstevel@tonic-gate 			if (!plogin->found)
959*8d489c7aSmuffin 				wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
960*8d489c7aSmuffin 				    "%s was not found", plogin->loginname);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	/*
9647c478bd9Sstevel@tonic-gate 	 * Generate a report from this display items we've squirreled away
9657c478bd9Sstevel@tonic-gate 	 */
9667c478bd9Sstevel@tonic-gate 	genreport();
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 *  We're through!
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	return (0);
9727c478bd9Sstevel@tonic-gate }
973