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
288d489c7aSmuffin /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
298d489c7aSmuffin /* All Rights Reserved */
308d489c7aSmuffin
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * users.c
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * This file contains the source for the administrative command
357c478bd9Sstevel@tonic-gate * "listusers" (available to the general user population) that
367c478bd9Sstevel@tonic-gate * produces a report containing user login-IDs and their "free
377c478bd9Sstevel@tonic-gate * field" (typically contains the user's name and other information).
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * Header files referenced:
427c478bd9Sstevel@tonic-gate * sys/types.h System type definitions
437c478bd9Sstevel@tonic-gate * stdio.h Definitions for standard I/O functions and constants
447c478bd9Sstevel@tonic-gate * string.h Definitions for string-handling functions
457c478bd9Sstevel@tonic-gate * grp.h Definitions for referencing the /etc/group file
467c478bd9Sstevel@tonic-gate * pwd.h Definitions for referencing the /etc/passwd file
477c478bd9Sstevel@tonic-gate * varargs.h Definitions for using a variable argument list
487c478bd9Sstevel@tonic-gate * fmtmsg.h Definitions for using the standard message formatting
497c478bd9Sstevel@tonic-gate * facility
507c478bd9Sstevel@tonic-gate */
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #include <sys/types.h>
537c478bd9Sstevel@tonic-gate #include <stdio.h>
547c478bd9Sstevel@tonic-gate #include <string.h>
557c478bd9Sstevel@tonic-gate #include <grp.h>
567c478bd9Sstevel@tonic-gate #include <pwd.h>
577c478bd9Sstevel@tonic-gate #include <stdarg.h>
587c478bd9Sstevel@tonic-gate #include <fmtmsg.h>
598d489c7aSmuffin #include <stdlib.h>
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate * Externals referenced (and not defined by a header file):
647c478bd9Sstevel@tonic-gate * malloc Allocate memory from main memory
657c478bd9Sstevel@tonic-gate * getopt Extract the next option from the command line
667c478bd9Sstevel@tonic-gate * optind The argument count of the next option to extract from
677c478bd9Sstevel@tonic-gate * the command line
687c478bd9Sstevel@tonic-gate * optarg A pointer to the argument of the option just extracted
697c478bd9Sstevel@tonic-gate * from the command line
707c478bd9Sstevel@tonic-gate * opterr FLAG: !0 tells getopt() to write an error message if
717c478bd9Sstevel@tonic-gate * it detects an error
727c478bd9Sstevel@tonic-gate * getpwent Get next entry from the /etc/passwd file
737c478bd9Sstevel@tonic-gate * getgrent Get next entry from the /etc/group file
747c478bd9Sstevel@tonic-gate * fmtmsg Standard message generation facility
757c478bd9Sstevel@tonic-gate * putenv Modify the environment
767c478bd9Sstevel@tonic-gate * exit Exit the program
777c478bd9Sstevel@tonic-gate */
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate * Local constant definitions
817c478bd9Sstevel@tonic-gate */
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate #ifndef FALSE
847c478bd9Sstevel@tonic-gate #define FALSE 0
857c478bd9Sstevel@tonic-gate #endif
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate #ifndef TRUE
887c478bd9Sstevel@tonic-gate #define TRUE ('t')
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate #define USAGE_MSG "usage: listusers [-g groups] [-l logins]"
927c478bd9Sstevel@tonic-gate #define MAXLOGINSIZE 14
937c478bd9Sstevel@tonic-gate #define LOGINFIELDSZ MAXLOGINSIZE+2
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate #define isauserlogin(uid) (uid >= 100)
967c478bd9Sstevel@tonic-gate #define isasystemlogin(uid) (uid < 100)
977c478bd9Sstevel@tonic-gate #define isausergroup(gid) (gid >= 100)
987c478bd9Sstevel@tonic-gate #define isasystemgroup(gid) (gid < 100)
998d489c7aSmuffin
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate * Local datatype definitions
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * This structure describes a specified group name
1067c478bd9Sstevel@tonic-gate * (from the -g groups option)
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate struct reqgrp {
1107c478bd9Sstevel@tonic-gate char *groupname;
1117c478bd9Sstevel@tonic-gate struct reqgrp *next;
1127c478bd9Sstevel@tonic-gate int found;
1137c478bd9Sstevel@tonic-gate gid_t groupID;
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * This structure describes a specified login name
1187c478bd9Sstevel@tonic-gate * (from the -l logins option)
1197c478bd9Sstevel@tonic-gate */
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate struct reqlogin {
1227c478bd9Sstevel@tonic-gate char *loginname;
1237c478bd9Sstevel@tonic-gate struct reqlogin *next;
1247c478bd9Sstevel@tonic-gate int found;
1257c478bd9Sstevel@tonic-gate };
1268d489c7aSmuffin
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate * These functions handle error and warning message writing.
1297c478bd9Sstevel@tonic-gate * (This deals with UNIX(r) standard message generation, so
1307c478bd9Sstevel@tonic-gate * the rest of the code doesn't have to.)
1317c478bd9Sstevel@tonic-gate *
1327c478bd9Sstevel@tonic-gate * Functions included:
1337c478bd9Sstevel@tonic-gate * initmsg Initialize the message handling functions.
1347c478bd9Sstevel@tonic-gate * wrtmsg Write the message using the standard message
1357c478bd9Sstevel@tonic-gate * generation facility.
1367c478bd9Sstevel@tonic-gate *
1377c478bd9Sstevel@tonic-gate * Static data included:
1387c478bd9Sstevel@tonic-gate * fcnlbl The label for standard messages
1397c478bd9Sstevel@tonic-gate * msgbuf A buffer to contain the edited message
1407c478bd9Sstevel@tonic-gate */
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate static char fcnlbl[MM_MXLABELLN+1]; /* Buffer for message label */
1437c478bd9Sstevel@tonic-gate static char msgbuf[MM_MXTXTLN+1]; /* Buffer for message text */
1448d489c7aSmuffin
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate * void initmsg(p)
1477c478bd9Sstevel@tonic-gate *
1487c478bd9Sstevel@tonic-gate * This function initializes the message handling functions.
1497c478bd9Sstevel@tonic-gate *
1507c478bd9Sstevel@tonic-gate * Arguments:
1517c478bd9Sstevel@tonic-gate * p A pointer to a character string that is the name of the
1527c478bd9Sstevel@tonic-gate * command, used to generate the label on messages. If this
1537c478bd9Sstevel@tonic-gate * string contains a slash ('/'), it only uses the characters
1547c478bd9Sstevel@tonic-gate * beyond the last slash in the string (this permits argv[0]
1557c478bd9Sstevel@tonic-gate * to be used).
1567c478bd9Sstevel@tonic-gate *
1577c478bd9Sstevel@tonic-gate * Returns: Void
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate static void
initmsg(char * p)1618d489c7aSmuffin initmsg(char *p) /* Ptr to command name */
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate /* Automatic data */
1647c478bd9Sstevel@tonic-gate char *q; /* Local multi-use pointer */
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate /* Use only the simple filename if there is a slash in the name */
1678d489c7aSmuffin if ((q = strrchr(p, '/')) == NULL)
1688d489c7aSmuffin q = p;
1698d489c7aSmuffin else
1708d489c7aSmuffin q++;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate /* Build the label for messages */
1737c478bd9Sstevel@tonic-gate (void) snprintf(fcnlbl, sizeof (fcnlbl), "UX:%s", q);
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate * Now that we've done all of that work, set things up so that
1777c478bd9Sstevel@tonic-gate * only the text-component of a message is printed. (This piece
1787c478bd9Sstevel@tonic-gate * of code will most probably go away in SVR4.1.
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate (void) putenv("MSGVERB=text");
1817c478bd9Sstevel@tonic-gate }
1828d489c7aSmuffin
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate * void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
1857c478bd9Sstevel@tonic-gate *
1867c478bd9Sstevel@tonic-gate * This function writes a message using the standard message
1877c478bd9Sstevel@tonic-gate * generation facility.
1887c478bd9Sstevel@tonic-gate *
1897c478bd9Sstevel@tonic-gate * Arguments:
1907c478bd9Sstevel@tonic-gate * severity The severity-component of the message
1917c478bd9Sstevel@tonic-gate * action The action-string used to generate the action-
1927c478bd9Sstevel@tonic-gate * component of the message
1937c478bd9Sstevel@tonic-gate * tag Tag-component of the message
1947c478bd9Sstevel@tonic-gate * text The text-string used to generate the text-component
1957c478bd9Sstevel@tonic-gate * of the message
1967c478bd9Sstevel@tonic-gate * txtarg Arguments to be inserted into the "text" string using
1977c478bd9Sstevel@tonic-gate * vsnprintf()
1987c478bd9Sstevel@tonic-gate *
1997c478bd9Sstevel@tonic-gate * Returns: Void
2007c478bd9Sstevel@tonic-gate */
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /* VARARGS4 */
2037c478bd9Sstevel@tonic-gate
2047c478bd9Sstevel@tonic-gate static void
wrtmsg(int severity,char * action,char * tag,char * text,...)2057c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate /* Automatic data */
2087c478bd9Sstevel@tonic-gate int errorflg; /* FLAG: True if error writing msg */
2097c478bd9Sstevel@tonic-gate va_list argp; /* Pointer into vararg list */
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate errorflg = FALSE;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate /* Generate the error message */
2147c478bd9Sstevel@tonic-gate va_start(argp, text);
2158d489c7aSmuffin if (text != MM_NULLTXT) {
2168d489c7aSmuffin /* LINTED */
2177c478bd9Sstevel@tonic-gate errorflg = vsnprintf(msgbuf, sizeof (msgbuf), text, argp) >
2187c478bd9Sstevel@tonic-gate MM_MXTXTLN;
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, severity,
2217c478bd9Sstevel@tonic-gate (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf,
2227c478bd9Sstevel@tonic-gate action, tag);
2237c478bd9Sstevel@tonic-gate va_end(argp);
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate * If there would have been a buffer overflow generating the error
2277c478bd9Sstevel@tonic-gate * message, the message will be truncated, so write a message and quit.
2287c478bd9Sstevel@tonic-gate */
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate if (errorflg) {
2317c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
2327c478bd9Sstevel@tonic-gate "Internal message buffer overflow",
2337c478bd9Sstevel@tonic-gate MM_NULLACT, MM_NULLTAG);
2347c478bd9Sstevel@tonic-gate exit(100);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate }
2378d489c7aSmuffin
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate * These functions allocate space for the information we gather.
2407c478bd9Sstevel@tonic-gate * It works by having a memory heap with strings allocated from
2417c478bd9Sstevel@tonic-gate * the end of the heap and structures (aligned data) allocated
2427c478bd9Sstevel@tonic-gate * from the beginning of the heap. It begins with a 4k block of
2437c478bd9Sstevel@tonic-gate * memory then allocates memory in 4k chunks. These functions
2447c478bd9Sstevel@tonic-gate * should never fail. If they do, they report the problem and
2457c478bd9Sstevel@tonic-gate * exit with an exit code of 101.
2467c478bd9Sstevel@tonic-gate *
2477c478bd9Sstevel@tonic-gate * Functions contained:
2487c478bd9Sstevel@tonic-gate * allocblk Allocates a block of memory, aligned on a
2497c478bd9Sstevel@tonic-gate * 4-byte (double-word) boundary.
2507c478bd9Sstevel@tonic-gate * allocstr Allocates a block of memory with no particular
2517c478bd9Sstevel@tonic-gate * alignment
2527c478bd9Sstevel@tonic-gate *
2537c478bd9Sstevel@tonic-gate * Constant definitions:
2547c478bd9Sstevel@tonic-gate * ALLOCBLKSZ Size of a chunk of main memory allocated using
2557c478bd9Sstevel@tonic-gate * malloc()
2567c478bd9Sstevel@tonic-gate *
2577c478bd9Sstevel@tonic-gate * Static data:
2587c478bd9Sstevel@tonic-gate * nextblkaddr Address of the next available chunk of aligned
2597c478bd9Sstevel@tonic-gate * space in the heap
2607c478bd9Sstevel@tonic-gate * laststraddr Address of the last chunk of unaligned space
2617c478bd9Sstevel@tonic-gate * allocated from the heap
2627c478bd9Sstevel@tonic-gate * toomuchspace Message to write if someone attempts to allocate
2637c478bd9Sstevel@tonic-gate * too much space (>ALLOCBLKSZ bytes)
2647c478bd9Sstevel@tonic-gate * memallocdif Message to write if there is a problem allocating
2657c478bd9Sstevel@tonic-gate * main memory.
2667c478bd9Sstevel@tonic-gate */
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate #define ALLOCBLKSZ 4096
2697c478bd9Sstevel@tonic-gate
2708d489c7aSmuffin static char *nextblkaddr = NULL;
2718d489c7aSmuffin static char *laststraddr = NULL;
2728d489c7aSmuffin static char *memallocdif =
2738d489c7aSmuffin "Memory allocation difficulty. Command terminates";
2748d489c7aSmuffin static char *toomuchspace =
2758d489c7aSmuffin "Internal space allocation error. Command terminates";
2768d489c7aSmuffin
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate * void *allocblk(size)
2797c478bd9Sstevel@tonic-gate * unsigned int size
2807c478bd9Sstevel@tonic-gate *
2817c478bd9Sstevel@tonic-gate * This function allocates a block of aligned (4-byte or double-
2827c478bd9Sstevel@tonic-gate * word boundary) memory from the program's heap. It returns a
2837c478bd9Sstevel@tonic-gate * pointer to that block of allocated memory.
2847c478bd9Sstevel@tonic-gate *
2857c478bd9Sstevel@tonic-gate * Arguments:
2867c478bd9Sstevel@tonic-gate * size Minimum number of bytes to allocate (will
2877c478bd9Sstevel@tonic-gate * round up to multiple of 4)
2887c478bd9Sstevel@tonic-gate *
2897c478bd9Sstevel@tonic-gate * Returns: void *
2907c478bd9Sstevel@tonic-gate * Pointer to the allocated block of memory
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate static void *
allocblk(unsigned int size)2948d489c7aSmuffin allocblk(unsigned int size)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate /* Automatic data */
2977c478bd9Sstevel@tonic-gate char *rtnval;
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /* Make sure the sizes are aligned correctly */
3017c478bd9Sstevel@tonic-gate if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) {
3027c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace);
3037c478bd9Sstevel@tonic-gate exit(101);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate /* Set up the value we're going to return */
3077c478bd9Sstevel@tonic-gate rtnval = nextblkaddr;
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /* Get the space we need off of the heap */
3107c478bd9Sstevel@tonic-gate if ((nextblkaddr += size) >= laststraddr) {
3118d489c7aSmuffin if ((rtnval = malloc(ALLOCBLKSZ)) == NULL) {
3127c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif);
3137c478bd9Sstevel@tonic-gate exit(101);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate laststraddr = rtnval + ALLOCBLKSZ;
3167c478bd9Sstevel@tonic-gate nextblkaddr = rtnval + size;
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate /* We're through */
3207c478bd9Sstevel@tonic-gate return ((void *)rtnval);
3217c478bd9Sstevel@tonic-gate }
3228d489c7aSmuffin
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate * char *allocstr(nbytes)
3257c478bd9Sstevel@tonic-gate * unsigned int nbytes
3267c478bd9Sstevel@tonic-gate *
3277c478bd9Sstevel@tonic-gate * This function allocates a block of unaligned memory from the
3287c478bd9Sstevel@tonic-gate * program's heap. It returns a pointer to that block of allocated
3297c478bd9Sstevel@tonic-gate * memory.
3307c478bd9Sstevel@tonic-gate *
3317c478bd9Sstevel@tonic-gate * Arguments:
3327c478bd9Sstevel@tonic-gate * nbytes Number of bytes to allocate
3337c478bd9Sstevel@tonic-gate *
3347c478bd9Sstevel@tonic-gate * Returns: char *
3357c478bd9Sstevel@tonic-gate * Pointer to the allocated block of memory
3367c478bd9Sstevel@tonic-gate */
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate static char *
allocstr(unsigned int nchars)3398d489c7aSmuffin allocstr(unsigned int nchars)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate if (nchars > ALLOCBLKSZ) {
3427c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace);
3437c478bd9Sstevel@tonic-gate exit(101);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate if ((laststraddr -= nchars) < nextblkaddr) {
3468d489c7aSmuffin if ((nextblkaddr = malloc(ALLOCBLKSZ)) == NULL) {
3477c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif);
3487c478bd9Sstevel@tonic-gate exit(101);
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate laststraddr = nextblkaddr + ALLOCBLKSZ - nchars;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate return (laststraddr);
3537c478bd9Sstevel@tonic-gate }
3548d489c7aSmuffin
3557c478bd9Sstevel@tonic-gate /*
3567c478bd9Sstevel@tonic-gate * These functions control the group membership list, as found in the
3577c478bd9Sstevel@tonic-gate * /etc/group file.
3587c478bd9Sstevel@tonic-gate *
3597c478bd9Sstevel@tonic-gate * Functions included:
3607c478bd9Sstevel@tonic-gate * initmembers Initialize the membership list (to NULL)
3617c478bd9Sstevel@tonic-gate * addmember Adds a member to the membership list
3627c478bd9Sstevel@tonic-gate * isamember Looks for a particular login-ID in the list
3637c478bd9Sstevel@tonic-gate * of members
3647c478bd9Sstevel@tonic-gate *
3657c478bd9Sstevel@tonic-gate * Datatype Definitions:
3667c478bd9Sstevel@tonic-gate * struct grpmember Describes a group member
3677c478bd9Sstevel@tonic-gate *
3687c478bd9Sstevel@tonic-gate * Static Data:
3697c478bd9Sstevel@tonic-gate * membershead Pointer to the head of the list of group members
3707c478bd9Sstevel@tonic-gate */
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate struct grpmember {
3737c478bd9Sstevel@tonic-gate char *membername;
3747c478bd9Sstevel@tonic-gate struct grpmember *next;
3757c478bd9Sstevel@tonic-gate };
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate static struct grpmember *membershead;
3788d489c7aSmuffin
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * void initmembers()
3817c478bd9Sstevel@tonic-gate *
3827c478bd9Sstevel@tonic-gate * This function initializes the list of members of specified groups.
3837c478bd9Sstevel@tonic-gate *
3847c478bd9Sstevel@tonic-gate * Arguments: None
3857c478bd9Sstevel@tonic-gate *
3867c478bd9Sstevel@tonic-gate * Returns: Void
3877c478bd9Sstevel@tonic-gate */
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate static void
initmembers(void)3908d489c7aSmuffin initmembers(void)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate /* Set up the members list to be a null member's list */
3938d489c7aSmuffin membershead = NULL;
3947c478bd9Sstevel@tonic-gate }
3958d489c7aSmuffin
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * void addmember(p)
3987c478bd9Sstevel@tonic-gate * char *p
3997c478bd9Sstevel@tonic-gate *
4007c478bd9Sstevel@tonic-gate * This function adds a member to the group member's list. The
4017c478bd9Sstevel@tonic-gate * group members list is a list of structures containing a pointer
4027c478bd9Sstevel@tonic-gate * to the member-name and a pointer to the next item in the structure.
4037c478bd9Sstevel@tonic-gate * The structure is not ordered in any particular way.
4047c478bd9Sstevel@tonic-gate *
4057c478bd9Sstevel@tonic-gate * Arguments:
4067c478bd9Sstevel@tonic-gate * p Pointer to the member name
4077c478bd9Sstevel@tonic-gate *
4087c478bd9Sstevel@tonic-gate * Returns: Void
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate static void
addmember(char * p)4128d489c7aSmuffin addmember(char *p)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate /* Automatic data */
4157c478bd9Sstevel@tonic-gate struct grpmember *new; /* Member being added */
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate new = (struct grpmember *)allocblk(sizeof (struct grpmember));
4187c478bd9Sstevel@tonic-gate new->membername = strcpy(allocstr((unsigned int)strlen(p)+1), p);
4197c478bd9Sstevel@tonic-gate new->next = membershead;
4207c478bd9Sstevel@tonic-gate membershead = new;
4217c478bd9Sstevel@tonic-gate }
4228d489c7aSmuffin
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate * init isamember(p)
4257c478bd9Sstevel@tonic-gate * char *p
4267c478bd9Sstevel@tonic-gate *
4277c478bd9Sstevel@tonic-gate * This function examines the list of group-members for the string
4287c478bd9Sstevel@tonic-gate * referenced by 'p'. If 'p' is a member of the members list, the
4297c478bd9Sstevel@tonic-gate * function returns TRUE. Otherwise it returns FALSE.
4307c478bd9Sstevel@tonic-gate *
4317c478bd9Sstevel@tonic-gate * Arguments:
4327c478bd9Sstevel@tonic-gate * p Pointer to the name to search for.
4337c478bd9Sstevel@tonic-gate *
4347c478bd9Sstevel@tonic-gate * Returns: int
4357c478bd9Sstevel@tonic-gate * TRUE If 'p' is found in the members list,
4367c478bd9Sstevel@tonic-gate * FALSE otherwise
4377c478bd9Sstevel@tonic-gate */
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate static int
isamember(char * p)4408d489c7aSmuffin isamember(char *p)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate /* Automatic Data */
4437c478bd9Sstevel@tonic-gate int found; /* FLAG: TRUE if login found */
4447c478bd9Sstevel@tonic-gate struct grpmember *pmem; /* Pointer to group member */
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate /* Search the membership list for the 'p' */
4487c478bd9Sstevel@tonic-gate found = FALSE;
4497c478bd9Sstevel@tonic-gate for (pmem = membershead; !found && pmem; pmem = pmem->next) {
4507c478bd9Sstevel@tonic-gate if (strcmp(p, pmem->membername) == 0) found = TRUE;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate return (found);
4547c478bd9Sstevel@tonic-gate }
4558d489c7aSmuffin
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate * These functions handle the display list. The display list contains
4587c478bd9Sstevel@tonic-gate * all of the information we're to display. The list contains a pointer
4597c478bd9Sstevel@tonic-gate * to the login-name, a pointer to the free-field (comment), and a pointer
4607c478bd9Sstevel@tonic-gate * to the next item in the list. The list is ordered alphabetically
4617c478bd9Sstevel@tonic-gate * (ascending) on the login-name field. The list initially contains a
4627c478bd9Sstevel@tonic-gate * dummy field (to make insertion easier) that contains a login-name of "".
4637c478bd9Sstevel@tonic-gate *
4647c478bd9Sstevel@tonic-gate * Functions included:
4657c478bd9Sstevel@tonic-gate * initdisp Initializes the display list
4667c478bd9Sstevel@tonic-gate * adddisp Adds information to the display list
4677c478bd9Sstevel@tonic-gate * genreport Generates a report from the items in the display list
4687c478bd9Sstevel@tonic-gate *
4697c478bd9Sstevel@tonic-gate * Datatypes Defined:
4707c478bd9Sstevel@tonic-gate * struct display Describes the structure that contains the
4717c478bd9Sstevel@tonic-gate * information to be displayed. Includes pointers
4727c478bd9Sstevel@tonic-gate * to the login-ID, free-field (comment), and the
4737c478bd9Sstevel@tonic-gate * next structure in the list.
4747c478bd9Sstevel@tonic-gate *
4757c478bd9Sstevel@tonic-gate * Static Data:
4767c478bd9Sstevel@tonic-gate * displayhead Pointer to the head of the list of login-IDs to
4777c478bd9Sstevel@tonic-gate * be displayed. Initially references the null-item
4787c478bd9Sstevel@tonic-gate * on the head of the list.
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate struct display {
4827c478bd9Sstevel@tonic-gate char *loginID;
4837c478bd9Sstevel@tonic-gate char *freefield;
4847c478bd9Sstevel@tonic-gate struct display *next;
4857c478bd9Sstevel@tonic-gate };
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate static struct display *displayhead;
4888d489c7aSmuffin
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate * void initdisp()
4917c478bd9Sstevel@tonic-gate *
4927c478bd9Sstevel@tonic-gate * Initializes the display list. An empty display list contains a
4937c478bd9Sstevel@tonic-gate * single element, the dummy element.
4947c478bd9Sstevel@tonic-gate *
4957c478bd9Sstevel@tonic-gate * Arguments: None
4967c478bd9Sstevel@tonic-gate *
4977c478bd9Sstevel@tonic-gate * Returns: Void
4987c478bd9Sstevel@tonic-gate */
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate static void
initdisp(void)5018d489c7aSmuffin initdisp(void)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate displayhead = (struct display *)allocblk(sizeof (struct display));
5048d489c7aSmuffin displayhead->next = NULL;
5057c478bd9Sstevel@tonic-gate displayhead->loginID = "";
5067c478bd9Sstevel@tonic-gate displayhead->freefield = "";
5077c478bd9Sstevel@tonic-gate }
5088d489c7aSmuffin
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate * void adddisp(pwent)
5117c478bd9Sstevel@tonic-gate * struct passwd *pwent
5127c478bd9Sstevel@tonic-gate *
5137c478bd9Sstevel@tonic-gate * This function adds the appropriate information from the login
5147c478bd9Sstevel@tonic-gate * description referenced by 'pwent' to the list if information
5157c478bd9Sstevel@tonic-gate * to be displayed. It only adds the information if the login-ID
5167c478bd9Sstevel@tonic-gate * (user-name) is unique. It inserts the information in the list
5177c478bd9Sstevel@tonic-gate * in such a way that the list remains ordered alphabetically
5187c478bd9Sstevel@tonic-gate * (ascending) according to the login-ID (user-name).
5197c478bd9Sstevel@tonic-gate *
5207c478bd9Sstevel@tonic-gate * Arguments:
5217c478bd9Sstevel@tonic-gate * pwent Points to the (struct passwd) structure that
5227c478bd9Sstevel@tonic-gate * contains all of the login information on the
5237c478bd9Sstevel@tonic-gate * login being added to the list. The only
5247c478bd9Sstevel@tonic-gate * information that this function uses is the
5257c478bd9Sstevel@tonic-gate * login-ID (user-name) and the free-field
5267c478bd9Sstevel@tonic-gate * (comment field).
5277c478bd9Sstevel@tonic-gate *
5287c478bd9Sstevel@tonic-gate * Returns: Void
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate static void
adddisp(struct passwd * pwent)5328d489c7aSmuffin adddisp(struct passwd *pwent)
5337c478bd9Sstevel@tonic-gate {
5347c478bd9Sstevel@tonic-gate /* Automatic data */
5357c478bd9Sstevel@tonic-gate struct display *new; /* Display item being added */
5367c478bd9Sstevel@tonic-gate struct display *prev; /* Previous display item */
5377c478bd9Sstevel@tonic-gate struct display *current; /* Next display item */
5387c478bd9Sstevel@tonic-gate int found; /* FLAG, insertion point found */
5397c478bd9Sstevel@tonic-gate int compare = 1; /* strcmp() compare value */
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /* Find where this value belongs in the list */
5437c478bd9Sstevel@tonic-gate prev = displayhead;
5447c478bd9Sstevel@tonic-gate current = displayhead->next;
5457c478bd9Sstevel@tonic-gate found = FALSE;
5467c478bd9Sstevel@tonic-gate while (!found && current) {
5477c478bd9Sstevel@tonic-gate if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0)
5487c478bd9Sstevel@tonic-gate found = TRUE;
5497c478bd9Sstevel@tonic-gate else {
5507c478bd9Sstevel@tonic-gate prev = current;
5517c478bd9Sstevel@tonic-gate current = current->next;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate /* Insert this value in the list, only if it is unique though */
5567c478bd9Sstevel@tonic-gate if (compare != 0) {
5578d489c7aSmuffin /*
5588d489c7aSmuffin * Build a display structure containing the value to add to
5598d489c7aSmuffin * the list, and add to the list
5608d489c7aSmuffin */
5617c478bd9Sstevel@tonic-gate new = (struct display *)allocblk(sizeof (struct display));
5628d489c7aSmuffin new->loginID =
5638d489c7aSmuffin strcpy(allocstr((unsigned int)strlen(pwent->pw_name)+1),
5648d489c7aSmuffin pwent->pw_name);
5657c478bd9Sstevel@tonic-gate if (pwent->pw_comment && pwent->pw_comment[0] != '\0')
5667c478bd9Sstevel@tonic-gate new->freefield =
5678d489c7aSmuffin strcpy(allocstr(
5688d489c7aSmuffin (unsigned int)strlen(pwent->pw_comment)+1),
5697c478bd9Sstevel@tonic-gate pwent->pw_comment);
5707c478bd9Sstevel@tonic-gate else
5717c478bd9Sstevel@tonic-gate new->freefield =
5728d489c7aSmuffin strcpy(allocstr(
5738d489c7aSmuffin (unsigned int)strlen(pwent->pw_gecos)+1),
5747c478bd9Sstevel@tonic-gate pwent->pw_gecos);
5757c478bd9Sstevel@tonic-gate new->next = current;
5767c478bd9Sstevel@tonic-gate prev->next = new;
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate }
5798d489c7aSmuffin
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate * void genreport()
5827c478bd9Sstevel@tonic-gate *
5837c478bd9Sstevel@tonic-gate * This function generates a report on the standard output stream
5847c478bd9Sstevel@tonic-gate * (stdout) containing the login-IDs and the free-fields of the
5857c478bd9Sstevel@tonic-gate * logins that match the list criteria (-g and -l options)
5867c478bd9Sstevel@tonic-gate *
5877c478bd9Sstevel@tonic-gate * Arguments: None
5887c478bd9Sstevel@tonic-gate *
5897c478bd9Sstevel@tonic-gate * Returns: Void
5907c478bd9Sstevel@tonic-gate */
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate static void
genreport(void)5938d489c7aSmuffin genreport(void)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /* Automatic data */
5977c478bd9Sstevel@tonic-gate struct display *current; /* Value to display */
5987c478bd9Sstevel@tonic-gate int i; /* Counter of characters */
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate * Initialization for loop.
6027c478bd9Sstevel@tonic-gate * (NOTE: The first element in the list of logins to display
6037c478bd9Sstevel@tonic-gate * is a dummy element.)
6047c478bd9Sstevel@tonic-gate */
6057c478bd9Sstevel@tonic-gate current = displayhead;
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate /*
6087c478bd9Sstevel@tonic-gate * Display elements in the list
6097c478bd9Sstevel@tonic-gate */
6107c478bd9Sstevel@tonic-gate for (current = displayhead->next; current; current = current->next) {
6117c478bd9Sstevel@tonic-gate (void) fputs(current->loginID, stdout);
6128d489c7aSmuffin for (i = LOGINFIELDSZ - strlen(current->loginID); --i >= 0;
6138d489c7aSmuffin (void) putc(' ', stdout))
6148d489c7aSmuffin ;
6157c478bd9Sstevel@tonic-gate (void) fputs(current->freefield, stdout);
6167c478bd9Sstevel@tonic-gate (void) putc('\n', stdout);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate }
6198d489c7aSmuffin
6207c478bd9Sstevel@tonic-gate /*
6217c478bd9Sstevel@tonic-gate * listusers [-l logins] [-g groups]
6227c478bd9Sstevel@tonic-gate *
6237c478bd9Sstevel@tonic-gate * This command generates a list of user login-IDs. Specific login-IDs
6247c478bd9Sstevel@tonic-gate * can be listed, as can logins belonging in specific groups.
6257c478bd9Sstevel@tonic-gate *
6267c478bd9Sstevel@tonic-gate * -l logins specifies the login-IDs to display. "logins" is a
6277c478bd9Sstevel@tonic-gate * comma-list of login-IDs.
6287c478bd9Sstevel@tonic-gate * -g groups specifies the names of the groups to which a login-ID
6297c478bd9Sstevel@tonic-gate * must belong before it is included in the generated list.
6307c478bd9Sstevel@tonic-gate * "groups" is a comma-list of group names.
6317c478bd9Sstevel@tonic-gate * Exit Codes:
6327c478bd9Sstevel@tonic-gate * 0 All's well that ends well
6337c478bd9Sstevel@tonic-gate * 1 Usage error
6347c478bd9Sstevel@tonic-gate */
6357c478bd9Sstevel@tonic-gate
6368d489c7aSmuffin int
main(int argc,char ** argv)6378d489c7aSmuffin main(int argc, char **argv)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate /* Automatic data */
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate struct reqgrp *reqgrphead; /* Head of the req'd group list */
6437c478bd9Sstevel@tonic-gate struct reqgrp *pgrp; /* Current item in the req'd group list */
6447c478bd9Sstevel@tonic-gate struct reqgrp *qgrp; /* Prev item in the req'd group list */
6457c478bd9Sstevel@tonic-gate struct reqgrp *rgrp; /* Running ptr for scanning group list */
6467c478bd9Sstevel@tonic-gate struct reqlogin *reqloginhead; /* Head of req'd login list */
6477c478bd9Sstevel@tonic-gate struct reqlogin *plogin; /* Current item in the req'd login list */
6487c478bd9Sstevel@tonic-gate struct reqlogin *qlogin; /* Previous item in the req'd login list */
6497c478bd9Sstevel@tonic-gate struct reqlogin *rlogin; /* Running ptr for scanning login list */
6507c478bd9Sstevel@tonic-gate struct passwd *pwent; /* Ptr to an /etc/passwd entry */
6517c478bd9Sstevel@tonic-gate struct group *grent; /* Ptr to an /etc/group entry */
6527c478bd9Sstevel@tonic-gate char *token; /* Ptr to a token extracted by strtok() */
6537c478bd9Sstevel@tonic-gate char **pp; /* Ptr to a member of a group */
654*dfae6925SToomas Soome char *g_arg = NULL; /* Ptr to the -g option's argument */
655*dfae6925SToomas Soome char *l_arg = NULL; /* Ptr to the -l option's argument */
6567c478bd9Sstevel@tonic-gate int g_seen; /* FLAG, true if -g on cmd */
6577c478bd9Sstevel@tonic-gate int l_seen; /* FLAG, TRUE if -l is on the command line */
6587c478bd9Sstevel@tonic-gate int errflg; /* FLAG, TRUE if there is a command-line problem */
6597c478bd9Sstevel@tonic-gate int done; /* FLAG, TRUE if the process (?) is complete */
660*dfae6925SToomas Soome int groupcount = 0; /* Number of groups specified by the user */
6617c478bd9Sstevel@tonic-gate int rc; /* Return code from strcmp() */
6627c478bd9Sstevel@tonic-gate int c; /* Character returned from getopt() */
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate /* Initializations */
6667c478bd9Sstevel@tonic-gate initmsg(argv[0]);
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate /* Command-line processing */
6697c478bd9Sstevel@tonic-gate g_seen = FALSE;
6707c478bd9Sstevel@tonic-gate l_seen = FALSE;
6717c478bd9Sstevel@tonic-gate errflg = FALSE;
6727c478bd9Sstevel@tonic-gate opterr = 0;
6737c478bd9Sstevel@tonic-gate while (!errflg && ((c = getopt(argc, argv, "g:l:")) != EOF)) {
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate /* Case on the option character */
6767c478bd9Sstevel@tonic-gate switch (c) {
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate case 'g':
6798d489c7aSmuffin if (g_seen)
6808d489c7aSmuffin errflg = TRUE;
6817c478bd9Sstevel@tonic-gate else {
6827c478bd9Sstevel@tonic-gate g_seen = TRUE;
6837c478bd9Sstevel@tonic-gate g_arg = optarg;
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate break;
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate case 'l':
6888d489c7aSmuffin if (l_seen)
6898d489c7aSmuffin errflg = TRUE;
6907c478bd9Sstevel@tonic-gate else {
6917c478bd9Sstevel@tonic-gate l_seen = TRUE;
6927c478bd9Sstevel@tonic-gate l_arg = optarg;
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate break;
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate default:
6977c478bd9Sstevel@tonic-gate errflg = TRUE;
6987c478bd9Sstevel@tonic-gate }
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate /* Write out a usage message if necessary and quit */
7027c478bd9Sstevel@tonic-gate if (errflg || (optind != argc)) {
7037c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, USAGE_MSG);
7047c478bd9Sstevel@tonic-gate exit(1);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate * If the -g groups option was on the command line, build a
7107c478bd9Sstevel@tonic-gate * list containing groups we're to list logins for.
7117c478bd9Sstevel@tonic-gate */
712*dfae6925SToomas Soome reqgrphead = NULL;
7137c478bd9Sstevel@tonic-gate if (g_seen) {
7147c478bd9Sstevel@tonic-gate
7157c478bd9Sstevel@tonic-gate /* Begin with an empty list */
7167c478bd9Sstevel@tonic-gate groupcount = 0;
7177c478bd9Sstevel@tonic-gate
7187c478bd9Sstevel@tonic-gate /* Extract the first token putting an element on the list */
7198d489c7aSmuffin if ((token = strtok(g_arg, ",")) != NULL) {
7208d489c7aSmuffin pgrp = (struct reqgrp *)
7218d489c7aSmuffin allocblk(sizeof (struct reqgrp));
7227c478bd9Sstevel@tonic-gate pgrp->groupname = token;
7237c478bd9Sstevel@tonic-gate pgrp->found = FALSE;
7248d489c7aSmuffin pgrp->next = NULL;
7257c478bd9Sstevel@tonic-gate groupcount++;
7267c478bd9Sstevel@tonic-gate reqgrphead = pgrp;
7277c478bd9Sstevel@tonic-gate qgrp = pgrp;
7287c478bd9Sstevel@tonic-gate
7297c478bd9Sstevel@tonic-gate /*
7308d489c7aSmuffin * Extract subsequent tokens (group names), avoiding
7318d489c7aSmuffin * duplicate names (note, list is NOT empty)
7327c478bd9Sstevel@tonic-gate */
733*dfae6925SToomas Soome while ((token = strtok(NULL, ",")) != NULL) {
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate /* Check for duplication */
7367c478bd9Sstevel@tonic-gate rgrp = reqgrphead;
737*dfae6925SToomas Soome rc = 0;
7388d489c7aSmuffin while (rgrp &&
7398d489c7aSmuffin (rc = strcmp(token, rgrp->groupname)))
7408d489c7aSmuffin rgrp = rgrp->next;
7417c478bd9Sstevel@tonic-gate if (rc != 0) {
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate /* Not a duplicate. Add on the list */
7448d489c7aSmuffin pgrp = (struct reqgrp *)
7458d489c7aSmuffin allocblk(sizeof (struct reqgrp));
7467c478bd9Sstevel@tonic-gate pgrp->groupname = token;
7477c478bd9Sstevel@tonic-gate pgrp->found = FALSE;
7488d489c7aSmuffin pgrp->next = NULL;
7497c478bd9Sstevel@tonic-gate groupcount++;
7507c478bd9Sstevel@tonic-gate qgrp->next = pgrp;
7517c478bd9Sstevel@tonic-gate qgrp = pgrp;
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate }
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate /*
7587c478bd9Sstevel@tonic-gate * If -l logins is on the command line, build a list of logins
7597c478bd9Sstevel@tonic-gate * we're to generate reports for.
760*dfae6925SToomas Soome * Begin with a null list.
7617c478bd9Sstevel@tonic-gate */
7628d489c7aSmuffin reqloginhead = NULL;
763*dfae6925SToomas Soome if (l_seen) {
7647c478bd9Sstevel@tonic-gate /* Extract the first token from the argument to the -l option */
765*dfae6925SToomas Soome if ((token = strtok(l_arg, ",")) != NULL) {
7667c478bd9Sstevel@tonic-gate
7677c478bd9Sstevel@tonic-gate /* Put the first element in the list */
7688d489c7aSmuffin plogin = (struct reqlogin *)
7698d489c7aSmuffin allocblk(sizeof (struct reqlogin));
7707c478bd9Sstevel@tonic-gate plogin->loginname = token;
7717c478bd9Sstevel@tonic-gate plogin->found = FALSE;
7728d489c7aSmuffin plogin->next = NULL;
7737c478bd9Sstevel@tonic-gate reqloginhead = plogin;
7747c478bd9Sstevel@tonic-gate qlogin = plogin;
7757c478bd9Sstevel@tonic-gate
7767c478bd9Sstevel@tonic-gate /*
7777c478bd9Sstevel@tonic-gate * For each subsequent token in the -l argument's
7787c478bd9Sstevel@tonic-gate * comma list ...
7797c478bd9Sstevel@tonic-gate */
7807c478bd9Sstevel@tonic-gate
781*dfae6925SToomas Soome while ((token = strtok(NULL, ",")) != NULL) {
7827c478bd9Sstevel@tonic-gate
7837c478bd9Sstevel@tonic-gate /* Check for duplication (list is not empty) */
7847c478bd9Sstevel@tonic-gate rlogin = reqloginhead;
785*dfae6925SToomas Soome rc = 0;
7868d489c7aSmuffin while (rlogin &&
7878d489c7aSmuffin (rc = strcmp(token, rlogin->loginname)))
7887c478bd9Sstevel@tonic-gate rlogin = rlogin->next;
7897c478bd9Sstevel@tonic-gate
7908d489c7aSmuffin /*
7918d489c7aSmuffin * If it's not a duplicate,
7928d489c7aSmuffin * add it to the list
7938d489c7aSmuffin */
7947c478bd9Sstevel@tonic-gate if (rc != 0) {
7958d489c7aSmuffin plogin = (struct reqlogin *)
7968d489c7aSmuffin allocblk(sizeof (struct reqlogin));
7977c478bd9Sstevel@tonic-gate plogin->loginname = token;
7987c478bd9Sstevel@tonic-gate plogin->found = FALSE;
7998d489c7aSmuffin plogin->next = NULL;
8007c478bd9Sstevel@tonic-gate qlogin->next = plogin;
8017c478bd9Sstevel@tonic-gate qlogin = plogin;
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate }
8067c478bd9Sstevel@tonic-gate
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate * If the user requested that only logins be listed in that belong
8107c478bd9Sstevel@tonic-gate * to certain groups, compile a list of logins that belong in that
8117c478bd9Sstevel@tonic-gate * group. If the user also requested specific logins, that list
8127c478bd9Sstevel@tonic-gate * will be limited to those logins.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate /* Initialize the login list */
8167c478bd9Sstevel@tonic-gate initmembers();
8177c478bd9Sstevel@tonic-gate if (g_seen) {
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate /* For each group in the /etc/group file ... */
820*dfae6925SToomas Soome while ((grent = getgrent()) != NULL) {
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate /* For each group mentioned with the -g option ... */
8238d489c7aSmuffin for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
8248d489c7aSmuffin pgrp = pgrp->next) {
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate if (pgrp->found == FALSE) {
8277c478bd9Sstevel@tonic-gate
8287c478bd9Sstevel@tonic-gate /*
8298d489c7aSmuffin * If the mentioned group is found in
8308d489c7aSmuffin * the /etc/group file ...
8317c478bd9Sstevel@tonic-gate */
8328d489c7aSmuffin if (strcmp(grent->gr_name,
8338d489c7aSmuffin pgrp->groupname) == 0) {
8347c478bd9Sstevel@tonic-gate
8358d489c7aSmuffin /*
8368d489c7aSmuffin * Mark the entry is found,
8378d489c7aSmuffin * remembering the group-ID
8388d489c7aSmuffin * for later
8398d489c7aSmuffin */
8407c478bd9Sstevel@tonic-gate pgrp->found = TRUE;
8417c478bd9Sstevel@tonic-gate groupcount--;
8427c478bd9Sstevel@tonic-gate pgrp->groupID = grent->gr_gid;
8437c478bd9Sstevel@tonic-gate if (isausergroup(pgrp->groupID))
8448d489c7aSmuffin for (pp = grent->gr_mem;
8458d489c7aSmuffin *pp; pp++)
8468d489c7aSmuffin addmember(*pp);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate }
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate
8528d489c7aSmuffin /*
8538d489c7aSmuffin * If any groups weren't found, write a message
8548d489c7aSmuffin * indicating such, then continue
8558d489c7aSmuffin */
8568d489c7aSmuffin qgrp = NULL;
8577c478bd9Sstevel@tonic-gate for (pgrp = reqgrphead; pgrp; pgrp = pgrp->next) {
8587c478bd9Sstevel@tonic-gate if (!pgrp->found) {
8598d489c7aSmuffin wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
8608d489c7aSmuffin "%s was not found", pgrp->groupname);
8618d489c7aSmuffin if (!qgrp)
8628d489c7aSmuffin reqgrphead = pgrp->next;
8638d489c7aSmuffin else
8648d489c7aSmuffin qgrp->next = pgrp->next;
8658d489c7aSmuffin } else if (isasystemgroup(pgrp->groupID)) {
8668d489c7aSmuffin wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
8678d489c7aSmuffin "%s is not a user group", pgrp->groupname);
8688d489c7aSmuffin if (!qgrp)
8698d489c7aSmuffin reqgrphead = pgrp->next;
8708d489c7aSmuffin else
8718d489c7aSmuffin qgrp->next = pgrp->next;
8728d489c7aSmuffin } else
8738d489c7aSmuffin qgrp = pgrp;
8747c478bd9Sstevel@tonic-gate }
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /* Initialize the list of logins to display */
8797c478bd9Sstevel@tonic-gate initdisp();
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate * Loop through the /etc/passwd file squirelling away the
8847c478bd9Sstevel@tonic-gate * information we need for the display.
8857c478bd9Sstevel@tonic-gate */
886*dfae6925SToomas Soome while ((pwent = getpwent()) != NULL) {
8877c478bd9Sstevel@tonic-gate
8888d489c7aSmuffin /*
8898d489c7aSmuffin * The login from /etc/passwd hasn't been included in
8908d489c7aSmuffin * the display yet
8918d489c7aSmuffin */
8927c478bd9Sstevel@tonic-gate done = FALSE;
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate * If the login was explicitly requested, include it in
8977c478bd9Sstevel@tonic-gate * the display if it is a user login
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate if (l_seen) {
9018d489c7aSmuffin for (plogin = reqloginhead; !done && plogin;
9028d489c7aSmuffin plogin = plogin->next) {
9038d489c7aSmuffin if (strcmp(pwent->pw_name,
9048d489c7aSmuffin plogin->loginname) == 0) {
9057c478bd9Sstevel@tonic-gate plogin->found = TRUE;
9068d489c7aSmuffin if (isauserlogin(pwent->pw_uid))
9078d489c7aSmuffin adddisp(pwent);
9087c478bd9Sstevel@tonic-gate else
9098d489c7aSmuffin wrtmsg(MM_WARNING, MM_NULLACT,
9108d489c7aSmuffin MM_NULLTAG,
9118d489c7aSmuffin "%s is not a user login",
9128d489c7aSmuffin plogin->loginname);
9137c478bd9Sstevel@tonic-gate done = TRUE;
9147c478bd9Sstevel@tonic-gate }
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate }
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate /*
9207c478bd9Sstevel@tonic-gate * If the login-ID isn't already on the list, if its primary
9217c478bd9Sstevel@tonic-gate * group-ID is one of those groups requested, or it is a member
9227c478bd9Sstevel@tonic-gate * of the groups requested, include it in the display if it is
9237c478bd9Sstevel@tonic-gate * a user login (uid >= 100).
9247c478bd9Sstevel@tonic-gate */
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate if (isauserlogin(pwent->pw_uid)) {
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate if (!done && g_seen) {
9298d489c7aSmuffin for (pgrp = reqgrphead; !done && pgrp;
9308d489c7aSmuffin pgrp = pgrp->next)
9317c478bd9Sstevel@tonic-gate if (pwent->pw_gid == pgrp->groupID) {
9327c478bd9Sstevel@tonic-gate adddisp(pwent);
9337c478bd9Sstevel@tonic-gate done = TRUE;
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate if (!done && isamember(pwent->pw_name)) {
9367c478bd9Sstevel@tonic-gate adddisp(pwent);
9377c478bd9Sstevel@tonic-gate done = TRUE;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate
9427c478bd9Sstevel@tonic-gate /*
9438d489c7aSmuffin * If neither -l nor -g is on the command-line and
9448d489c7aSmuffin * the login-ID is a user login, include it in
9458d489c7aSmuffin * the display.
9467c478bd9Sstevel@tonic-gate */
9477c478bd9Sstevel@tonic-gate
9488d489c7aSmuffin if (!l_seen && !g_seen)
9498d489c7aSmuffin adddisp(pwent);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate /* Let the user know about logins they requested that don't exist */
9548d489c7aSmuffin if (l_seen)
9558d489c7aSmuffin for (plogin = reqloginhead; plogin; plogin = plogin->next)
9567c478bd9Sstevel@tonic-gate if (!plogin->found)
9578d489c7aSmuffin wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
9588d489c7aSmuffin "%s was not found", plogin->loginname);
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate * Generate a report from this display items we've squirreled away
9637c478bd9Sstevel@tonic-gate */
9647c478bd9Sstevel@tonic-gate genreport();
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate /*
9677c478bd9Sstevel@tonic-gate * We're through!
9687c478bd9Sstevel@tonic-gate */
9697c478bd9Sstevel@tonic-gate return (0);
9707c478bd9Sstevel@tonic-gate }
971