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
5*f48205beScasper * Common Development and Distribution License (the "License").
6*f48205beScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22*f48205beScasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
267c478bd9Sstevel@tonic-gate /* All Rights Reserved */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.15.1.2 */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * logins.c
337c478bd9Sstevel@tonic-gate *
347c478bd9Sstevel@tonic-gate * This file contains the source for the administrative command
357c478bd9Sstevel@tonic-gate * "logins" (available to the administrator) that produces a report
367c478bd9Sstevel@tonic-gate * containing login-IDs and other requested information.
377c478bd9Sstevel@tonic-gate */
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
407c478bd9Sstevel@tonic-gate #include <stdio.h>
4120d7339fSgww #include <stdlib.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate #include <string.h>
447c478bd9Sstevel@tonic-gate #include <ctype.h>
457c478bd9Sstevel@tonic-gate #include <grp.h>
467c478bd9Sstevel@tonic-gate #include <pwd.h>
477c478bd9Sstevel@tonic-gate #include <shadow.h>
487c478bd9Sstevel@tonic-gate #include <time.h>
497c478bd9Sstevel@tonic-gate #include <stdarg.h>
507c478bd9Sstevel@tonic-gate #include <fmtmsg.h>
517c478bd9Sstevel@tonic-gate #include <locale.h>
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate * Local constant definitions
557c478bd9Sstevel@tonic-gate * TRUE Boolean constant
567c478bd9Sstevel@tonic-gate * FALSE Boolean constant
577c478bd9Sstevel@tonic-gate * USAGE_MSG Message used to display a usage error
587c478bd9Sstevel@tonic-gate * MAXLOGINSIZE Maximum length of a valid login-ID
597c478bd9Sstevel@tonic-gate * MAXSYSTEMLOGIN Maximum value of a system user-ID.
607c478bd9Sstevel@tonic-gate * OPTSTR Options to this command
617c478bd9Sstevel@tonic-gate * ROOT_ID The user-ID of an administrator
627c478bd9Sstevel@tonic-gate */
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate #ifndef FALSE
657c478bd9Sstevel@tonic-gate #define FALSE 0
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate #ifndef TRUE
697c478bd9Sstevel@tonic-gate #define TRUE ((int)'t')
707c478bd9Sstevel@tonic-gate #endif
717c478bd9Sstevel@tonic-gate
727c478bd9Sstevel@tonic-gate #define USAGE_MSG "usage: logins [-admopstux] [-g groups] [-l logins]"
737c478bd9Sstevel@tonic-gate #define MAXLOGINSIZE 14
747c478bd9Sstevel@tonic-gate #define MAXSYSTEMLOGIN 99
757c478bd9Sstevel@tonic-gate #define OPTSTR "adg:l:mopstux"
767c478bd9Sstevel@tonic-gate #define ROOT_ID 0
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * The following macros do their function for now but will probably have
807c478bd9Sstevel@tonic-gate * to be replaced by functions sometime in the near future. The maximum
817c478bd9Sstevel@tonic-gate * system login value may someday be administerable, in which case these
827c478bd9Sstevel@tonic-gate * will have to be changed to become functions
837c478bd9Sstevel@tonic-gate *
847c478bd9Sstevel@tonic-gate * isasystemlogin Returns TRUE if the user-ID in the "struct passwd"
857c478bd9Sstevel@tonic-gate * structure referenced by the function's argument is
867c478bd9Sstevel@tonic-gate * less than or equal to the maximum value for a system
877c478bd9Sstevel@tonic-gate * user-ID, FALSE otherwise.
887c478bd9Sstevel@tonic-gate * isauserlogin Returns TRUE if the user-ID in the "struct passwd"
897c478bd9Sstevel@tonic-gate * structure referenced by the function's argument is
907c478bd9Sstevel@tonic-gate * greater than the maximum value for a system user-ID,
917c478bd9Sstevel@tonic-gate * FALSE otherwise.
927c478bd9Sstevel@tonic-gate */
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate #define isauserlogin(pw) (pw->pw_uid > MAXSYSTEMLOGIN)
957c478bd9Sstevel@tonic-gate #define isasystemlogin(pw) (pw->pw_uid <= MAXSYSTEMLOGIN)
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate * Local datatype definitions
1007c478bd9Sstevel@tonic-gate * struct reqgrp Describes a group as requested through the
1017c478bd9Sstevel@tonic-gate * -g option
1027c478bd9Sstevel@tonic-gate * struct reqlogin Describes a login-ID as requested through
1037c478bd9Sstevel@tonic-gate * the -l option
1047c478bd9Sstevel@tonic-gate * struct pwdinfo Describes a password's aging information,
1057c478bd9Sstevel@tonic-gate * as extracted from /etc/shadow
1067c478bd9Sstevel@tonic-gate * struct secgrp Describes a login-ID's secondary group
1077c478bd9Sstevel@tonic-gate */
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* Describes a specified group name (from the -g groups option) */
1107c478bd9Sstevel@tonic-gate struct reqgrp {
1117c478bd9Sstevel@tonic-gate char *groupname; /* Requested group name */
1127c478bd9Sstevel@tonic-gate struct reqgrp *next; /* Next item in the list */
1137c478bd9Sstevel@tonic-gate gid_t groupID; /* Group's ID */
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /* Describes a specified login name (from the -l logins option) */
1177c478bd9Sstevel@tonic-gate struct reqlogin {
1187c478bd9Sstevel@tonic-gate char *loginname; /* Requested login name */
1197c478bd9Sstevel@tonic-gate struct reqlogin *next; /* Next item in the list */
1207c478bd9Sstevel@tonic-gate int found; /* TRUE if login in /etc/passwd */
1217c478bd9Sstevel@tonic-gate };
1227c478bd9Sstevel@tonic-gate
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate * This structure describes a password's information
1257c478bd9Sstevel@tonic-gate */
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate struct pwdinfo {
1287c478bd9Sstevel@tonic-gate long datechg; /* Date the password was changed (mmddyy) */
1297c478bd9Sstevel@tonic-gate char *passwdstatus; /* Password status */
1307c478bd9Sstevel@tonic-gate long mindaystilchg; /* Min days b4 pwd can change again */
1317c478bd9Sstevel@tonic-gate long maxdaystilchg; /* Max days b4 pwd can change again */
1327c478bd9Sstevel@tonic-gate long warninterval; /* Days before expire to warn user */
1337c478bd9Sstevel@tonic-gate long inactive; /* Lapsed days of inactivity before lock */
1347c478bd9Sstevel@tonic-gate long expdate; /* Date of expiration (mmddyy) */
1357c478bd9Sstevel@tonic-gate };
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate /* This structure describes secondary groups that a user belongs to */
1387c478bd9Sstevel@tonic-gate struct secgrp {
1397c478bd9Sstevel@tonic-gate char *groupname; /* Name of the group */
1407c478bd9Sstevel@tonic-gate struct secgrp *next; /* Next item in the list */
1417c478bd9Sstevel@tonic-gate gid_t groupID; /* Group-ID */
1427c478bd9Sstevel@tonic-gate };
14320d7339fSgww
14420d7339fSgww
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate * These functions handle error and warning message writing.
1477c478bd9Sstevel@tonic-gate * (This deals with UNIX(r) standard message generation, so
1487c478bd9Sstevel@tonic-gate * the rest of the code doesn't have to.)
1497c478bd9Sstevel@tonic-gate *
1507c478bd9Sstevel@tonic-gate * Functions included:
1517c478bd9Sstevel@tonic-gate * initmsg Initialize the message handling functions.
1527c478bd9Sstevel@tonic-gate * wrtmsg Write the message using fmtmsg().
1537c478bd9Sstevel@tonic-gate *
1547c478bd9Sstevel@tonic-gate * Static data included:
1557c478bd9Sstevel@tonic-gate * fcnlbl The label for standard messages
1567c478bd9Sstevel@tonic-gate * msgbuf A buffer to contain the edited message
1577c478bd9Sstevel@tonic-gate */
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gate static char fcnlbl[MM_MXLABELLN+1]; /* Buffer for message label */
1607c478bd9Sstevel@tonic-gate static char msgbuf[MM_MXTXTLN+1]; /* Buffer for message text */
16120d7339fSgww
16220d7339fSgww
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * void initmsg(p)
1657c478bd9Sstevel@tonic-gate *
1667c478bd9Sstevel@tonic-gate * This function initializes the message handling functions.
1677c478bd9Sstevel@tonic-gate *
1687c478bd9Sstevel@tonic-gate * Arguments:
1697c478bd9Sstevel@tonic-gate * p A pointer to a character string that is the name of the
1707c478bd9Sstevel@tonic-gate * function, used to generate the label on messages. If this
1717c478bd9Sstevel@tonic-gate * string contains a slash ('/'), it only uses the characters
1727c478bd9Sstevel@tonic-gate * beyond the last slash in the string (this permits argv[0]
1737c478bd9Sstevel@tonic-gate * to be used).
1747c478bd9Sstevel@tonic-gate *
1757c478bd9Sstevel@tonic-gate * Returns: Void
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate static void
initmsg(char * p)17920d7339fSgww initmsg(char *p)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate char *q; /* Local multi-use pointer */
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /* Use only the simple filename if there is a slash in the name */
18420d7339fSgww if (!(q = strrchr(p, '/'))) {
18520d7339fSgww q = p;
18620d7339fSgww } else {
18720d7339fSgww q++;
18820d7339fSgww }
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate /* Build the label for messages */
19120d7339fSgww (void) snprintf(fcnlbl, MM_MXLABELLN, "UX:%s", q);
1927c478bd9Sstevel@tonic-gate
1937c478bd9Sstevel@tonic-gate /* Restrict messages to the text-component */
1947c478bd9Sstevel@tonic-gate (void) putenv("MSGVERB=text");
1957c478bd9Sstevel@tonic-gate }
19620d7339fSgww
19720d7339fSgww
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate * void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]])
2007c478bd9Sstevel@tonic-gate *
2017c478bd9Sstevel@tonic-gate * This function writes a message using fmtmsg()
2027c478bd9Sstevel@tonic-gate *
2037c478bd9Sstevel@tonic-gate * Arguments:
2047c478bd9Sstevel@tonic-gate * severity The severity-component of the message
2057c478bd9Sstevel@tonic-gate * action The action-string used to generate the
2067c478bd9Sstevel@tonic-gate * action-component of the message
2077c478bd9Sstevel@tonic-gate * tag Tag-component of the message
2087c478bd9Sstevel@tonic-gate * text The text-string used to generate the text-
2097c478bd9Sstevel@tonic-gate * component of the message
2107c478bd9Sstevel@tonic-gate * txtarg Arguments to be inserted into the "text"
2117c478bd9Sstevel@tonic-gate * string using vsprintf()
2127c478bd9Sstevel@tonic-gate *
2137c478bd9Sstevel@tonic-gate * Returns: Void
2147c478bd9Sstevel@tonic-gate */
21520d7339fSgww /*PRINTFLIKE4*/
2167c478bd9Sstevel@tonic-gate static void
wrtmsg(int severity,char * action,char * tag,char * text,...)2177c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate int errorflg; /* TRUE if problem generating message */
2207c478bd9Sstevel@tonic-gate va_list argp; /* Pointer into vararg list */
2217c478bd9Sstevel@tonic-gate
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate /* No problems yet */
2247c478bd9Sstevel@tonic-gate errorflg = FALSE;
2257c478bd9Sstevel@tonic-gate
2267c478bd9Sstevel@tonic-gate /* Generate the error message */
2277c478bd9Sstevel@tonic-gate va_start(argp, text);
22820d7339fSgww if (text != MM_NULLTXT) {
22920d7339fSgww errorflg = vsnprintf(msgbuf,
23020d7339fSgww MM_MXTXTLN, text, argp) > MM_MXTXTLN;
23120d7339fSgww }
2327c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, severity,
23320d7339fSgww (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf, action, tag);
2347c478bd9Sstevel@tonic-gate va_end(argp);
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate * If there was a buffer overflow generating the error message,
2387c478bd9Sstevel@tonic-gate * write a message and quit (things are probably corrupt in the
2397c478bd9Sstevel@tonic-gate * static data space now
2407c478bd9Sstevel@tonic-gate */
2417c478bd9Sstevel@tonic-gate if (errorflg) {
2427c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING,
2437c478bd9Sstevel@tonic-gate gettext("Internal message buffer overflow"),
2447c478bd9Sstevel@tonic-gate MM_NULLACT, MM_NULLTAG);
2457c478bd9Sstevel@tonic-gate exit(100);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate }
24820d7339fSgww
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate * These functions control the group membership list, as found in
2517c478bd9Sstevel@tonic-gate * the /etc/group file.
2527c478bd9Sstevel@tonic-gate *
2537c478bd9Sstevel@tonic-gate * Functions included:
2547c478bd9Sstevel@tonic-gate * addmember Adds a member to the membership list
2557c478bd9Sstevel@tonic-gate * isamember Looks for a particular login-ID in the
2567c478bd9Sstevel@tonic-gate * list of members
2577c478bd9Sstevel@tonic-gate *
2587c478bd9Sstevel@tonic-gate * Datatype Definitions:
2597c478bd9Sstevel@tonic-gate * struct grpmember Describes a group member
2607c478bd9Sstevel@tonic-gate *
2617c478bd9Sstevel@tonic-gate * Static Data:
2627c478bd9Sstevel@tonic-gate * membershead Pointer to the head of the list of
2637c478bd9Sstevel@tonic-gate * group members
2647c478bd9Sstevel@tonic-gate */
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate struct grpmember {
2677c478bd9Sstevel@tonic-gate char *membername;
2687c478bd9Sstevel@tonic-gate struct grpmember *next;
2697c478bd9Sstevel@tonic-gate };
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate static struct grpmember *membershead;
27220d7339fSgww
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate * void addmember(p)
2757c478bd9Sstevel@tonic-gate * char *p
2767c478bd9Sstevel@tonic-gate *
2777c478bd9Sstevel@tonic-gate * This function adds a member to the group member's list. The
2787c478bd9Sstevel@tonic-gate * group members list is a list of structures containing a pointer
2797c478bd9Sstevel@tonic-gate * to the member-name and a pointer to the next item in the
2807c478bd9Sstevel@tonic-gate * structure. The structure is not ordered in any particular way.
2817c478bd9Sstevel@tonic-gate *
2827c478bd9Sstevel@tonic-gate * Arguments:
2837c478bd9Sstevel@tonic-gate * p Pointer to the member name
2847c478bd9Sstevel@tonic-gate *
2857c478bd9Sstevel@tonic-gate * Returns: Void
2867c478bd9Sstevel@tonic-gate */
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate static void
addmember(char * p)28920d7339fSgww addmember(char *p)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate struct grpmember *new; /* Member being added */
2927c478bd9Sstevel@tonic-gate
293b816ddf8Sgww new = malloc(sizeof (struct grpmember));
294b816ddf8Sgww new->membername = strdup(p);
2957c478bd9Sstevel@tonic-gate new->next = membershead;
2967c478bd9Sstevel@tonic-gate membershead = new;
2977c478bd9Sstevel@tonic-gate }
29820d7339fSgww
29920d7339fSgww
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate * init isamember(p)
3027c478bd9Sstevel@tonic-gate * char *p
3037c478bd9Sstevel@tonic-gate *
3047c478bd9Sstevel@tonic-gate * This function examines the list of group-members for the string
3057c478bd9Sstevel@tonic-gate * referenced by 'p'. If 'p' is a member of the members list, the
3067c478bd9Sstevel@tonic-gate * function returns TRUE. Otherwise it returns FALSE.
3077c478bd9Sstevel@tonic-gate *
3087c478bd9Sstevel@tonic-gate * Arguments:
3097c478bd9Sstevel@tonic-gate * p Pointer to the name to search for.
3107c478bd9Sstevel@tonic-gate *
3117c478bd9Sstevel@tonic-gate * Returns: int
3127c478bd9Sstevel@tonic-gate * TRUE If 'p' is found in the members list,
3137c478bd9Sstevel@tonic-gate * FALSE otherwise
3147c478bd9Sstevel@tonic-gate */
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate static int
isamember(char * p)31720d7339fSgww isamember(char *p)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate int found; /* TRUE if login found in list */
3207c478bd9Sstevel@tonic-gate struct grpmember *pmem; /* Group member being examined */
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate /* Search the membership list for 'p' */
3247c478bd9Sstevel@tonic-gate found = FALSE;
3257c478bd9Sstevel@tonic-gate for (pmem = membershead; !found && pmem; pmem = pmem->next) {
32620d7339fSgww if (strcmp(p, pmem->membername) == 0)
32720d7339fSgww found = TRUE;
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gate return (found);
3317c478bd9Sstevel@tonic-gate }
33220d7339fSgww
33320d7339fSgww
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate * These functions handle the display list. The display list contains
3367c478bd9Sstevel@tonic-gate * all of the information we're to display. The list contains a pointer
3377c478bd9Sstevel@tonic-gate * to the login-name, a pointer to the free-field (comment), and a
3387c478bd9Sstevel@tonic-gate * pointer to the next item in the list. The list is ordered alpha-
3397c478bd9Sstevel@tonic-gate * betically (ascending) on the login-name field. The list initially
3407c478bd9Sstevel@tonic-gate * contains a dummy field (to make insertion easier) that contains a
3417c478bd9Sstevel@tonic-gate * login-name of "".
3427c478bd9Sstevel@tonic-gate *
3437c478bd9Sstevel@tonic-gate * Functions included:
3447c478bd9Sstevel@tonic-gate * initdisp Initializes the display list
3457c478bd9Sstevel@tonic-gate * adddisp Adds information to the display list
3467c478bd9Sstevel@tonic-gate * isuidindisp Looks to see if a particular user-ID is in the
3477c478bd9Sstevel@tonic-gate * display list
3487c478bd9Sstevel@tonic-gate * genreport Generates a report from the items in the display
3497c478bd9Sstevel@tonic-gate * list
3507c478bd9Sstevel@tonic-gate * applygroup Add group information to the items in the display
3517c478bd9Sstevel@tonic-gate * list
3527c478bd9Sstevel@tonic-gate * applypasswd Add extended password information to the items
3537c478bd9Sstevel@tonic-gate * in the display list
3547c478bd9Sstevel@tonic-gate *
3557c478bd9Sstevel@tonic-gate * Datatypes Defined:
3567c478bd9Sstevel@tonic-gate * struct display Describes the structure that contains the information
3577c478bd9Sstevel@tonic-gate * to be displayed. Includes pointers to the login-ID,
3587c478bd9Sstevel@tonic-gate * free-field (comment), and the next structure in the
3597c478bd9Sstevel@tonic-gate * list.
3607c478bd9Sstevel@tonic-gate *
3617c478bd9Sstevel@tonic-gate * Static Data:
3627c478bd9Sstevel@tonic-gate * displayhead Pointer to the head of the display list. Initially
3637c478bd9Sstevel@tonic-gate * references the null-item on the head of the list.
3647c478bd9Sstevel@tonic-gate */
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate struct display {
3677c478bd9Sstevel@tonic-gate char *loginID; /* Login name */
3687c478bd9Sstevel@tonic-gate char *freefield; /* Free (comment) field */
3697c478bd9Sstevel@tonic-gate char *groupname; /* Name of the primary group */
3707c478bd9Sstevel@tonic-gate char *iwd; /* Initial working directory */
3717c478bd9Sstevel@tonic-gate char *shell; /* Shell after login (may be null) */
3727c478bd9Sstevel@tonic-gate struct pwdinfo *passwdinfo; /* Password information structure */
3737c478bd9Sstevel@tonic-gate struct secgrp *secgrplist; /* Head of the secondary group list */
3747c478bd9Sstevel@tonic-gate uid_t userID; /* User ID */
3757c478bd9Sstevel@tonic-gate gid_t groupID; /* Group ID of primary group */
3767c478bd9Sstevel@tonic-gate struct display *nextlogin; /* Next login in the list */
3777c478bd9Sstevel@tonic-gate struct display *nextuid; /* Next user-ID in the list */
3787c478bd9Sstevel@tonic-gate };
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate static struct display *displayhead;
38120d7339fSgww
38220d7339fSgww
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate * void initdisp()
3857c478bd9Sstevel@tonic-gate *
3867c478bd9Sstevel@tonic-gate * Initializes the display list. An empty display list contains
3877c478bd9Sstevel@tonic-gate * a single element, the dummy element.
3887c478bd9Sstevel@tonic-gate *
3897c478bd9Sstevel@tonic-gate * Arguments: None
3907c478bd9Sstevel@tonic-gate *
3917c478bd9Sstevel@tonic-gate * Returns: Void
3927c478bd9Sstevel@tonic-gate */
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate static void
initdisp(void)39520d7339fSgww initdisp(void)
3967c478bd9Sstevel@tonic-gate {
397b816ddf8Sgww displayhead = malloc(sizeof (struct display));
39820d7339fSgww displayhead->nextlogin = NULL;
39920d7339fSgww displayhead->nextuid = NULL;
4007c478bd9Sstevel@tonic-gate displayhead->loginID = "";
4017c478bd9Sstevel@tonic-gate displayhead->freefield = "";
402*f48205beScasper displayhead->userID = (uid_t)-1;
4037c478bd9Sstevel@tonic-gate }
40420d7339fSgww
40520d7339fSgww
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate * void adddisp(pwent)
4087c478bd9Sstevel@tonic-gate * struct passwd *pwent
4097c478bd9Sstevel@tonic-gate *
4107c478bd9Sstevel@tonic-gate * This function adds the appropriate information from the login
4117c478bd9Sstevel@tonic-gate * description referenced by 'pwent' to the list if information
4127c478bd9Sstevel@tonic-gate * to be displayed. It only adds the information if the login-ID
4137c478bd9Sstevel@tonic-gate * (user-name) is unique. It inserts the information in the list
4147c478bd9Sstevel@tonic-gate * in such a way that the list remains ordered alphabetically
4157c478bd9Sstevel@tonic-gate * (ascending) according to the login-ID (user-name).
4167c478bd9Sstevel@tonic-gate *
4177c478bd9Sstevel@tonic-gate * Arguments:
4187c478bd9Sstevel@tonic-gate * pwent Structure that contains all of the login information
4197c478bd9Sstevel@tonic-gate * of the login being added to the list. The only
4207c478bd9Sstevel@tonic-gate * information that this function uses is the login-ID
4217c478bd9Sstevel@tonic-gate * (user-name) and the free-field (comment field).
4227c478bd9Sstevel@tonic-gate *
4237c478bd9Sstevel@tonic-gate * Returns: Void
4247c478bd9Sstevel@tonic-gate */
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate static void
adddisp(struct passwd * pwent)42720d7339fSgww adddisp(struct passwd *pwent)
4287c478bd9Sstevel@tonic-gate {
4297c478bd9Sstevel@tonic-gate struct display *new; /* Item being added to the list */
4307c478bd9Sstevel@tonic-gate struct display *prev; /* Previous item in the list */
4317c478bd9Sstevel@tonic-gate struct display *current; /* Next item in the list */
4327c478bd9Sstevel@tonic-gate int found; /* FLAG, insertion point found */
4337c478bd9Sstevel@tonic-gate int compare = 1; /* strcmp() compare value */
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate /* Find where this value belongs in the list */
4377c478bd9Sstevel@tonic-gate prev = displayhead;
4387c478bd9Sstevel@tonic-gate found = FALSE;
43920d7339fSgww while (!found && (current = prev->nextlogin)) {
44020d7339fSgww if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) {
44120d7339fSgww found = TRUE;
44220d7339fSgww } else {
44320d7339fSgww prev = current;
44420d7339fSgww }
4457c478bd9Sstevel@tonic-gate
44620d7339fSgww }
4477c478bd9Sstevel@tonic-gate /* Insert this value in the list, only if it is unique though */
4487c478bd9Sstevel@tonic-gate if (compare != 0) {
449b816ddf8Sgww new = malloc(sizeof (struct display));
450b816ddf8Sgww new->loginID = strdup(pwent->pw_name);
45120d7339fSgww if (pwent->pw_comment && pwent->pw_comment[0] != '\0') {
452b816ddf8Sgww new->freefield = strdup(pwent->pw_comment);
45320d7339fSgww } else {
454b816ddf8Sgww new->freefield = strdup(pwent->pw_gecos);
45520d7339fSgww }
45620d7339fSgww if (!pwent->pw_shell || !(*pwent->pw_shell)) {
45720d7339fSgww new->shell = "/sbin/sh";
45820d7339fSgww } else {
459b816ddf8Sgww new->shell = strdup(pwent->pw_shell);
46020d7339fSgww }
461b816ddf8Sgww new->iwd = strdup(pwent->pw_dir);
4627c478bd9Sstevel@tonic-gate new->userID = pwent->pw_uid;
4637c478bd9Sstevel@tonic-gate new->groupID = pwent->pw_gid;
46420d7339fSgww new->secgrplist = NULL;
46520d7339fSgww new->passwdinfo = NULL;
46620d7339fSgww new->groupname = NULL;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate /* Add new display item to the list ordered by login-ID */
4697c478bd9Sstevel@tonic-gate new->nextlogin = current;
4707c478bd9Sstevel@tonic-gate prev->nextlogin = new;
4717c478bd9Sstevel@tonic-gate
47220d7339fSgww /*
47320d7339fSgww * Find the appropriate place for the new item in the list
47420d7339fSgww * ordered by userID
47520d7339fSgww */
4767c478bd9Sstevel@tonic-gate prev = displayhead;
4777c478bd9Sstevel@tonic-gate found = FALSE;
47820d7339fSgww while (!found && (current = prev->nextuid)) {
47920d7339fSgww if (current->userID > pwent->pw_uid) {
48020d7339fSgww found = TRUE;
48120d7339fSgww } else {
48220d7339fSgww prev = current;
48320d7339fSgww }
48420d7339fSgww }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /* Add the item into the list that is ordered by user-ID */
4877c478bd9Sstevel@tonic-gate new->nextuid = current;
4887c478bd9Sstevel@tonic-gate prev->nextuid = new;
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate }
49120d7339fSgww
49220d7339fSgww
4937c478bd9Sstevel@tonic-gate /*
4947c478bd9Sstevel@tonic-gate * int isuidindisp(pwent)
4957c478bd9Sstevel@tonic-gate * struct passwd *pwent
4967c478bd9Sstevel@tonic-gate *
4977c478bd9Sstevel@tonic-gate * This function examines the display list to see if the uid in
4987c478bd9Sstevel@tonic-gate * the (struct passwd) referenced by "pwent" is already in the
4997c478bd9Sstevel@tonic-gate * display list. It returns TRUE if it is in the list, FALSE
5007c478bd9Sstevel@tonic-gate * otherwise.
5017c478bd9Sstevel@tonic-gate *
5027c478bd9Sstevel@tonic-gate * Since the display list is ordered by user-ID, the search continues
5037c478bd9Sstevel@tonic-gate * until a match is found or a user-ID is found that is larger than
5047c478bd9Sstevel@tonic-gate * the one we're searching for.
5057c478bd9Sstevel@tonic-gate *
5067c478bd9Sstevel@tonic-gate * Arguments:
5077c478bd9Sstevel@tonic-gate * pwent Structure that contains the user-ID we're to
5087c478bd9Sstevel@tonic-gate * look for
5097c478bd9Sstevel@tonic-gate *
5107c478bd9Sstevel@tonic-gate * Returns: int
5117c478bd9Sstevel@tonic-gate * TRUE if the user-ID was found, FALSE otherwise.
5127c478bd9Sstevel@tonic-gate */
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate static int
isuidindisp(struct passwd * pwent)51520d7339fSgww isuidindisp(struct passwd *pwent)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate struct display *dp;
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate * Search the list, beginning at the beginning (where else?)
5227c478bd9Sstevel@tonic-gate * and stopping when the user-ID is found or one is found that
5237c478bd9Sstevel@tonic-gate * is greater than the user-ID we're searching for. Recall
5247c478bd9Sstevel@tonic-gate * that this list is ordered by user-ID
5257c478bd9Sstevel@tonic-gate */
5267c478bd9Sstevel@tonic-gate
52720d7339fSgww for (dp = displayhead->nextuid; dp && (dp->userID < pwent->pw_uid);
52820d7339fSgww dp = dp->nextuid) {
52920d7339fSgww continue;
53020d7339fSgww }
5317c478bd9Sstevel@tonic-gate
53220d7339fSgww /*
53320d7339fSgww * If the pointer "dp" points to a structure that has a
53420d7339fSgww * matching user-ID, return TRUE. Otherwise FALSE
53520d7339fSgww */
5367c478bd9Sstevel@tonic-gate return (dp && (dp->userID == pwent->pw_uid));
5377c478bd9Sstevel@tonic-gate }
53820d7339fSgww
53920d7339fSgww
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate * void applygroup(allgroups)
5427c478bd9Sstevel@tonic-gate * int allgroups
5437c478bd9Sstevel@tonic-gate *
5447c478bd9Sstevel@tonic-gate * This function applies group information to the login-IDs in the
5457c478bd9Sstevel@tonic-gate * display list. It always applies the primary group information.
5467c478bd9Sstevel@tonic-gate * If "allgroups" is TRUE, it applies secondary information as well.
5477c478bd9Sstevel@tonic-gate *
5487c478bd9Sstevel@tonic-gate * Arguments:
5497c478bd9Sstevel@tonic-gate * allgroups FLAG. TRUE if secondary group info is to be
5507c478bd9Sstevel@tonic-gate * applied -- FALSE otherwise.
5517c478bd9Sstevel@tonic-gate *
5527c478bd9Sstevel@tonic-gate * Returns: void
5537c478bd9Sstevel@tonic-gate */
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate static void
applygroup(int allgroups)55620d7339fSgww applygroup(int allgroups)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate struct display *dp; /* Display list running ptr */
5597c478bd9Sstevel@tonic-gate struct group *grent; /* Group info, from getgrent() */
5607c478bd9Sstevel@tonic-gate char *p; /* Temp char pointer */
5617c478bd9Sstevel@tonic-gate char **pp; /* Temp char * pointer */
5627c478bd9Sstevel@tonic-gate int compare; /* Value from strcmp() */
5637c478bd9Sstevel@tonic-gate int done; /* TRUE if finished, FALSE otherwise */
5647c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Block allocated for this info */
5657c478bd9Sstevel@tonic-gate struct secgrp *psrch; /* Secondary group -- for searching */
5667c478bd9Sstevel@tonic-gate
567b816ddf8Sgww if (!allgroups) {
568b816ddf8Sgww /* short circute getting all the groups */
569b816ddf8Sgww for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
570b816ddf8Sgww if ((grent = getgrgid(dp->groupID)) != NULL) {
571b816ddf8Sgww dp->groupname = strdup(grent->gr_name);
572b816ddf8Sgww }
573b816ddf8Sgww }
574b816ddf8Sgww return;
575b816ddf8Sgww }
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate /* For each group-ID in the /etc/group file ... */
5787c478bd9Sstevel@tonic-gate while (grent = getgrent()) {
5797c478bd9Sstevel@tonic-gate /*
5807c478bd9Sstevel@tonic-gate * Set the primary group for the login-IDs in the display
5817c478bd9Sstevel@tonic-gate * list. For each group-ID we get, leaf through the display
5827c478bd9Sstevel@tonic-gate * list and set the group-name if the group-IDs match
5837c478bd9Sstevel@tonic-gate */
5847c478bd9Sstevel@tonic-gate
58520d7339fSgww p = NULL;
58620d7339fSgww for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
5877c478bd9Sstevel@tonic-gate if ((dp->groupID == grent->gr_gid) && !dp->groupname) {
58820d7339fSgww if (!p) {
589b816ddf8Sgww p = strdup(grent->gr_name);
59020d7339fSgww }
5917c478bd9Sstevel@tonic-gate dp->groupname = p;
5927c478bd9Sstevel@tonic-gate }
59320d7339fSgww }
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * If we're to be displaying secondary group membership,
5977c478bd9Sstevel@tonic-gate * leaf through the list of group members. Then, attempt
5987c478bd9Sstevel@tonic-gate * to find that member in the display list. When found,
5997c478bd9Sstevel@tonic-gate * attach secondary group info to the user.
6007c478bd9Sstevel@tonic-gate */
6017c478bd9Sstevel@tonic-gate
60220d7339fSgww for (pp = grent->gr_mem; *pp; pp++) {
6037c478bd9Sstevel@tonic-gate done = FALSE;
60420d7339fSgww for (dp = displayhead->nextlogin; !done && dp;
60520d7339fSgww dp = dp->nextlogin) {
60620d7339fSgww if (((compare = strcmp(dp->loginID,
60720d7339fSgww *pp)) == 0) &&
60820d7339fSgww !(grent->gr_gid == dp->groupID)) {
60920d7339fSgww if (!p) {
610b816ddf8Sgww p = strdup(grent->gr_name);
61120d7339fSgww }
612b816ddf8Sgww psecgrp = malloc(
61320d7339fSgww sizeof (struct secgrp));
6147c478bd9Sstevel@tonic-gate psecgrp->groupID = grent->gr_gid;
6157c478bd9Sstevel@tonic-gate psecgrp->groupname = p;
61620d7339fSgww psecgrp->next = NULL;
61720d7339fSgww if (!dp->secgrplist) {
61820d7339fSgww dp->secgrplist = psecgrp;
61920d7339fSgww } else {
62020d7339fSgww for (psrch = dp->secgrplist;
62120d7339fSgww psrch->next;
62220d7339fSgww psrch = psrch->next) {
62320d7339fSgww continue;
62420d7339fSgww }
6257c478bd9Sstevel@tonic-gate psrch->next = psecgrp;
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate done = TRUE;
62820d7339fSgww } else if (compare > 0) {
62920d7339fSgww done = TRUE;
6307c478bd9Sstevel@tonic-gate }
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate /* Close the /etc/group file */
6367c478bd9Sstevel@tonic-gate endgrent();
6377c478bd9Sstevel@tonic-gate }
63820d7339fSgww
63920d7339fSgww
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate * void applypasswd()
6427c478bd9Sstevel@tonic-gate *
6437c478bd9Sstevel@tonic-gate * This function applies extended password information to an item
6447c478bd9Sstevel@tonic-gate * to be displayed. It allocates space for a structure describing
6457c478bd9Sstevel@tonic-gate * the password, then fills in that structure from the information
6467c478bd9Sstevel@tonic-gate * in the /etc/shadow file.
6477c478bd9Sstevel@tonic-gate *
6487c478bd9Sstevel@tonic-gate * Arguments: None
6497c478bd9Sstevel@tonic-gate *
6507c478bd9Sstevel@tonic-gate * Returns: Void
6517c478bd9Sstevel@tonic-gate */
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate static void
applypasswd(void)65420d7339fSgww applypasswd(void)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate struct pwdinfo *ppasswd; /* Ptr to pwd desc in current element */
6577c478bd9Sstevel@tonic-gate struct display *dp; /* Ptr to current element */
6587c478bd9Sstevel@tonic-gate struct spwd *psp; /* Pointer to a shadow-file entry */
6597c478bd9Sstevel@tonic-gate struct tm *ptm; /* Pointer to a time-of-day structure */
6607c478bd9Sstevel@tonic-gate time_t pwchg; /* System-time of last pwd chg */
6617c478bd9Sstevel@tonic-gate time_t pwexp; /* System-time of password expiration */
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /* Make sure the shadow file is rewound */
6657c478bd9Sstevel@tonic-gate setspent();
6667c478bd9Sstevel@tonic-gate
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate /*
6697c478bd9Sstevel@tonic-gate * For each item in the display list...
6707c478bd9Sstevel@tonic-gate */
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate /* Allocate structure space for the password description */
675b816ddf8Sgww ppasswd = malloc(sizeof (struct pwdinfo));
6767c478bd9Sstevel@tonic-gate dp->passwdinfo = ppasswd;
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate * If there's no entry in the /etc/shadow file, assume
6807c478bd9Sstevel@tonic-gate * that the login is locked
6817c478bd9Sstevel@tonic-gate */
6827c478bd9Sstevel@tonic-gate
683b816ddf8Sgww if ((psp = getspnam(dp->loginID)) == NULL) {
6847c478bd9Sstevel@tonic-gate pwchg = 0L; /* Epoch */
6857c478bd9Sstevel@tonic-gate ppasswd->passwdstatus = "LK"; /* LK, Locked */
6867c478bd9Sstevel@tonic-gate ppasswd->mindaystilchg = 0L;
6877c478bd9Sstevel@tonic-gate ppasswd->maxdaystilchg = 0L;
6887c478bd9Sstevel@tonic-gate ppasswd->warninterval = 0L;
6897c478bd9Sstevel@tonic-gate ppasswd->inactive = 0L;
6907c478bd9Sstevel@tonic-gate pwexp = 0L;
69120d7339fSgww } else {
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate * Otherwise, fill in the password information from the
694b816ddf8Sgww * info in the shadow entry
6957c478bd9Sstevel@tonic-gate */
696b816ddf8Sgww if (psp->sp_pwdp == NULL || (*psp->sp_pwdp) == '\0')
69720d7339fSgww ppasswd->passwdstatus = "NP";
698b816ddf8Sgww else if (strncmp(psp->sp_pwdp, LOCKSTRING,
699b816ddf8Sgww sizeof (LOCKSTRING)-1) == 0)
70020d7339fSgww ppasswd->passwdstatus = "LK";
701b816ddf8Sgww else if (strncmp(psp->sp_pwdp, NOLOGINSTRING,
702b816ddf8Sgww sizeof (NOLOGINSTRING)-1) == 0)
703b816ddf8Sgww ppasswd->passwdstatus = "NL";
704b816ddf8Sgww else if ((strlen(psp->sp_pwdp) == 13 &&
705b816ddf8Sgww psp->sp_pwdp[0] != '$') ||
706b816ddf8Sgww psp->sp_pwdp[0] == '$')
7077c478bd9Sstevel@tonic-gate ppasswd->passwdstatus = "PS";
708b816ddf8Sgww else
709b816ddf8Sgww ppasswd->passwdstatus = "UN";
7107c478bd9Sstevel@tonic-gate /*
71120d7339fSgww * Set up the last-changed date,
71220d7339fSgww * the minimum days between changes,
71320d7339fSgww * the maximum life of a password,
71420d7339fSgww * the interval before expiration that the user
71520d7339fSgww * is warned,
71620d7339fSgww * the number of days a login can be inactive before
71720d7339fSgww * it expires, and the login expiration date
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate pwchg = psp->sp_lstchg;
7217c478bd9Sstevel@tonic-gate ppasswd->mindaystilchg = psp->sp_min;
7227c478bd9Sstevel@tonic-gate ppasswd->maxdaystilchg = psp->sp_max;
7237c478bd9Sstevel@tonic-gate ppasswd->warninterval = psp->sp_warn;
7247c478bd9Sstevel@tonic-gate ppasswd->inactive = psp->sp_inact;
7257c478bd9Sstevel@tonic-gate pwexp = psp->sp_expire;
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate * Convert the date of the last password change from days-
7307c478bd9Sstevel@tonic-gate * since-epoch to mmddyy (integer) form. Involves the
7317c478bd9Sstevel@tonic-gate * intermediate step of converting the date from days-
7327c478bd9Sstevel@tonic-gate * since-epoch to seconds-since-epoch. We'll set this to
7337c478bd9Sstevel@tonic-gate * somewhere near the middle of the day, since there are not
7347c478bd9Sstevel@tonic-gate * always 24*60*60 seconds in a year. (Yeech)
7357c478bd9Sstevel@tonic-gate *
7367c478bd9Sstevel@tonic-gate * Note: The form mmddyy should probably be subject to
7377c478bd9Sstevel@tonic-gate * internationalization -- Non-Americans will think that
7387c478bd9Sstevel@tonic-gate * 070888 is 07 August 88 when the software is trying to say
7397c478bd9Sstevel@tonic-gate * 08 July 88. Systems Engineers seem to think that this isn't
7407c478bd9Sstevel@tonic-gate * a problem though...
7417c478bd9Sstevel@tonic-gate */
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate if (pwchg != -1L) {
7447c478bd9Sstevel@tonic-gate pwchg = (pwchg * DAY) + (DAY/2);
7457c478bd9Sstevel@tonic-gate ptm = localtime(&pwchg);
7467c478bd9Sstevel@tonic-gate ppasswd->datechg = ((long)(ptm->tm_mon+1) * 10000L) +
7477c478bd9Sstevel@tonic-gate (long)((ptm->tm_mday * 100) +
7487c478bd9Sstevel@tonic-gate (ptm->tm_year % 100));
74920d7339fSgww } else {
75020d7339fSgww ppasswd->datechg = 0L;
75120d7339fSgww }
7527c478bd9Sstevel@tonic-gate
7537c478bd9Sstevel@tonic-gate /*
7547c478bd9Sstevel@tonic-gate * Convert the passwd expiration date from days-since-epoch
7557c478bd9Sstevel@tonic-gate * to mmddyy (long integer) form using the same algorithm and
7567c478bd9Sstevel@tonic-gate * comments as above.
7577c478bd9Sstevel@tonic-gate */
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate if (pwexp != -1L) {
7607c478bd9Sstevel@tonic-gate pwexp = (pwexp * DAY) + (DAY/2);
7617c478bd9Sstevel@tonic-gate ptm = localtime(&pwexp);
7627c478bd9Sstevel@tonic-gate ppasswd->expdate = ((long)(ptm->tm_mon+1) * 10000L) +
7637c478bd9Sstevel@tonic-gate (long)((ptm->tm_mday * 100) +
7647c478bd9Sstevel@tonic-gate (ptm->tm_year % 100));
76520d7339fSgww } else {
76620d7339fSgww ppasswd->expdate = 0L;
76720d7339fSgww }
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate /* Close the shadow password file */
7717c478bd9Sstevel@tonic-gate endspent();
7727c478bd9Sstevel@tonic-gate }
77320d7339fSgww
77420d7339fSgww
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate * int hasnopasswd(pwent)
7777c478bd9Sstevel@tonic-gate * struct passwd *pwent
7787c478bd9Sstevel@tonic-gate *
7797c478bd9Sstevel@tonic-gate * This function examines a login's password-file entry
7807c478bd9Sstevel@tonic-gate * and, if necessary, its shadow password-file entry and
7817c478bd9Sstevel@tonic-gate * returns TRUE if that user-ID has no password, meaning
7827c478bd9Sstevel@tonic-gate * that the user-ID can be used to log into the system
7837c478bd9Sstevel@tonic-gate * without giving a password. The function returns FALSE
7847c478bd9Sstevel@tonic-gate * otherwise.
7857c478bd9Sstevel@tonic-gate *
7867c478bd9Sstevel@tonic-gate * Arguments:
7877c478bd9Sstevel@tonic-gate * pwent Login to examine.
7887c478bd9Sstevel@tonic-gate *
7897c478bd9Sstevel@tonic-gate * Returns: int
7907c478bd9Sstevel@tonic-gate * TRUE if the login can be used without a password, FALSE
7917c478bd9Sstevel@tonic-gate * otherwise.
7927c478bd9Sstevel@tonic-gate */
7937c478bd9Sstevel@tonic-gate
7947c478bd9Sstevel@tonic-gate static int
hasnopasswd(struct passwd * pwent)79520d7339fSgww hasnopasswd(struct passwd *pwent)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate struct spwd *psp; /* /etc/shadow file struct */
7987c478bd9Sstevel@tonic-gate int nopwflag; /* TRUE if login has no passwd */
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate * A login has no password if:
8027c478bd9Sstevel@tonic-gate * 1. There exists an entry for that login in the
8037c478bd9Sstevel@tonic-gate * shadow password-file (/etc/passwd), and
8047c478bd9Sstevel@tonic-gate * 2. The encrypted password in the structure describing
80520d7339fSgww * that entry is either: NULL or a null string ("")
8067c478bd9Sstevel@tonic-gate */
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate /* Get the login's entry in the shadow password file */
8097c478bd9Sstevel@tonic-gate if (psp = getspnam(pwent->pw_name)) {
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate /* Look at the encrypted password in that entry */
8127c478bd9Sstevel@tonic-gate if (psp->sp_pwdp == (char *)0 ||
81320d7339fSgww *psp->sp_pwdp == '\0') {
8147c478bd9Sstevel@tonic-gate nopwflag = TRUE;
81520d7339fSgww } else {
8167c478bd9Sstevel@tonic-gate nopwflag = FALSE;
8177c478bd9Sstevel@tonic-gate }
81820d7339fSgww } else {
8197c478bd9Sstevel@tonic-gate nopwflag = FALSE;
82020d7339fSgww }
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate /* Done ... */
8237c478bd9Sstevel@tonic-gate return (nopwflag);
8247c478bd9Sstevel@tonic-gate }
82520d7339fSgww
82620d7339fSgww
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * void writeunformatted(current, xtndflag, expflag)
8297c478bd9Sstevel@tonic-gate * struct display *current
8307c478bd9Sstevel@tonic-gate * int xtndflag
8317c478bd9Sstevel@tonic-gate * int expflag
8327c478bd9Sstevel@tonic-gate *
8337c478bd9Sstevel@tonic-gate * This function writes the data in the display structure "current"
8347c478bd9Sstevel@tonic-gate * to the standard output file. It writes the information in the
8357c478bd9Sstevel@tonic-gate * form of a colon-list. It writes secondary group information if
8367c478bd9Sstevel@tonic-gate * that information is in the structure, it writes extended
8377c478bd9Sstevel@tonic-gate * (initial working directory, shell, and password-aging) info
8387c478bd9Sstevel@tonic-gate * if the "xtndflag" is TRUE, and it writes password expiration
8397c478bd9Sstevel@tonic-gate * information if "expflag" is TRUE.
8407c478bd9Sstevel@tonic-gate *
8417c478bd9Sstevel@tonic-gate * Arguments:
8427c478bd9Sstevel@tonic-gate * current Structure containing information to write.
8437c478bd9Sstevel@tonic-gate * xtndflag TRUE if extended information is to be written,
8447c478bd9Sstevel@tonic-gate * FALSE otherwise
8457c478bd9Sstevel@tonic-gate * expflag TRUE if password expiration information is to
8467c478bd9Sstevel@tonic-gate * be written, FALSE otherwise
8477c478bd9Sstevel@tonic-gate *
8487c478bd9Sstevel@tonic-gate * Returns: void
8497c478bd9Sstevel@tonic-gate */
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate static void
writeunformatted(struct display * current,int xtndflag,int expflag)85220d7339fSgww writeunformatted(struct display *current, int xtndflag, int expflag)
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Secondary group info */
8557c478bd9Sstevel@tonic-gate struct pwdinfo *pwdinfo; /* Password aging info */
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /* Write the general information */
858*f48205beScasper (void) fprintf(stdout, "%s:%u:%s:%u:%s",
8597c478bd9Sstevel@tonic-gate current->loginID,
8607c478bd9Sstevel@tonic-gate current->userID,
86120d7339fSgww current->groupname == NULL ? "" : current->groupname,
8627c478bd9Sstevel@tonic-gate current->groupID,
8637c478bd9Sstevel@tonic-gate current->freefield);
8647c478bd9Sstevel@tonic-gate
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * If the group information is there, write it (it's only
8677c478bd9Sstevel@tonic-gate * there if it's supposed to be written)
8687c478bd9Sstevel@tonic-gate */
86920d7339fSgww for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
870*f48205beScasper (void) fprintf(stdout, ":%s:%u",
87120d7339fSgww psecgrp->groupname, psecgrp->groupID);
87220d7339fSgww }
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate /* If the extended info flag is TRUE, write the extended information */
8757c478bd9Sstevel@tonic-gate if (xtndflag) {
8767c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo;
8777c478bd9Sstevel@tonic-gate (void) fprintf(stdout, ":%s:%s:%s:%6.6ld:%ld:%ld:%ld",
8787c478bd9Sstevel@tonic-gate current->iwd, current->shell,
8797c478bd9Sstevel@tonic-gate pwdinfo->passwdstatus,
8807c478bd9Sstevel@tonic-gate pwdinfo->datechg,
8817c478bd9Sstevel@tonic-gate pwdinfo->mindaystilchg, pwdinfo->maxdaystilchg,
8827c478bd9Sstevel@tonic-gate pwdinfo->warninterval);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate /* If the password expiration information is requested, write it. */
8867c478bd9Sstevel@tonic-gate if (expflag) {
8877c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo;
88820d7339fSgww (void) fprintf(stdout, ":%ld:%ld",
88920d7339fSgww pwdinfo->inactive, pwdinfo->expdate);
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate /* Terminate the information with a new-line */
8937c478bd9Sstevel@tonic-gate (void) putc('\n', stdout);
8947c478bd9Sstevel@tonic-gate }
89520d7339fSgww
89620d7339fSgww
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate * void writeformatted(current, xtndflag, expflag)
8997c478bd9Sstevel@tonic-gate * struct display *current
9007c478bd9Sstevel@tonic-gate * int xtndflag
9017c478bd9Sstevel@tonic-gate * int expflag
9027c478bd9Sstevel@tonic-gate *
9037c478bd9Sstevel@tonic-gate * This function writes the data in the display structure "current"
9047c478bd9Sstevel@tonic-gate * to the standard output file. It writes the information in an
9057c478bd9Sstevel@tonic-gate * easily readable format. It writes secondary group information
9067c478bd9Sstevel@tonic-gate * if that information is in the structure, it writes extended
9077c478bd9Sstevel@tonic-gate * (initial working directory, shell, and password-aging) info if
9087c478bd9Sstevel@tonic-gate * "xtndflag" is TRUE, and it write password expiration information
9097c478bd9Sstevel@tonic-gate * if "expflag" is TRUE.
9107c478bd9Sstevel@tonic-gate *
9117c478bd9Sstevel@tonic-gate * Arguments:
9127c478bd9Sstevel@tonic-gate * current Structure containing info to write.
91320d7339fSgww * xtndflag TRUE if extended information to be written,
9147c478bd9Sstevel@tonic-gate * FALSE otherwise
91520d7339fSgww * expflag TRUE if password expiration information to be written,
9167c478bd9Sstevel@tonic-gate * FALSE otherwise
9177c478bd9Sstevel@tonic-gate *
9187c478bd9Sstevel@tonic-gate * Returns: void
9197c478bd9Sstevel@tonic-gate */
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate static void
writeformatted(struct display * current,int xtndflag,int expflag)92220d7339fSgww writeformatted(struct display *current, int xtndflag, int expflag)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Secondary group info */
9257c478bd9Sstevel@tonic-gate struct pwdinfo *pwdinfo; /* Password aging info */
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate /* Write general information */
928*f48205beScasper (void) fprintf(stdout, "%-14s %-6u %-14s %-6u %s\n",
9297c478bd9Sstevel@tonic-gate current->loginID, current->userID,
93020d7339fSgww current->groupname == NULL ? "" : current->groupname,
9317c478bd9Sstevel@tonic-gate current->groupID, current->freefield);
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate /*
9347c478bd9Sstevel@tonic-gate * Write information about secondary groups if the info exists
9357c478bd9Sstevel@tonic-gate * (it only exists if it is to be written)
9367c478bd9Sstevel@tonic-gate */
93720d7339fSgww for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) {
938*f48205beScasper (void) fprintf(stdout, " %-14s %-6u\n",
9397c478bd9Sstevel@tonic-gate psecgrp->groupname, psecgrp->groupID);
94020d7339fSgww }
9417c478bd9Sstevel@tonic-gate
94220d7339fSgww /*
94320d7339fSgww * If the extended information flag is TRUE,
94420d7339fSgww * write the extended information
94520d7339fSgww */
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate if (xtndflag) {
9487c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo;
94920d7339fSgww (void) fprintf(stdout, " %s\n",
95020d7339fSgww current->iwd);
95120d7339fSgww (void) fprintf(stdout, " %s\n",
95220d7339fSgww current->shell);
95320d7339fSgww (void) fprintf(stdout, " %s "
95420d7339fSgww "%6.6ld %ld %ld %ld\n",
9557c478bd9Sstevel@tonic-gate pwdinfo->passwdstatus,
9567c478bd9Sstevel@tonic-gate pwdinfo->datechg, pwdinfo->mindaystilchg,
9577c478bd9Sstevel@tonic-gate pwdinfo->maxdaystilchg,
9587c478bd9Sstevel@tonic-gate pwdinfo->warninterval);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate
96120d7339fSgww /*
96220d7339fSgww * If the password expiration info flag is TRUE,
96320d7339fSgww * write that information
96420d7339fSgww */
9657c478bd9Sstevel@tonic-gate if (expflag) {
9667c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo;
9677c478bd9Sstevel@tonic-gate (void) fprintf(stdout, " %ld %6.6ld\n",
9687c478bd9Sstevel@tonic-gate pwdinfo->inactive, pwdinfo->expdate);
9697c478bd9Sstevel@tonic-gate }
9707c478bd9Sstevel@tonic-gate }
97120d7339fSgww
97220d7339fSgww
9737c478bd9Sstevel@tonic-gate /*
9747c478bd9Sstevel@tonic-gate * void genuidreport(pipeflag, xtndflag, expflag)
9757c478bd9Sstevel@tonic-gate * int pipeflag
9767c478bd9Sstevel@tonic-gate * int xtndflag
9777c478bd9Sstevel@tonic-gate * int expflag
9787c478bd9Sstevel@tonic-gate *
9797c478bd9Sstevel@tonic-gate * This function generates a report on the standard output
9807c478bd9Sstevel@tonic-gate * stream (stdout) containing the login-IDs in the list of
9817c478bd9Sstevel@tonic-gate * logins built by this command. The list is ordered based
9827c478bd9Sstevel@tonic-gate * on user-ID. If the <pipeflag> variable is not zero, it
9837c478bd9Sstevel@tonic-gate * will generate a report containing parsable records.
9847c478bd9Sstevel@tonic-gate * Otherwise, it will generate a columnarized report. If
9857c478bd9Sstevel@tonic-gate * the <xtndflag> variable is not zero, it will include the
9867c478bd9Sstevel@tonic-gate * extended set of information (password aging info, home
9877c478bd9Sstevel@tonic-gate * directory, shell process, etc.). If <expflag> is not
9887c478bd9Sstevel@tonic-gate * zero, it will display password expiration information.
9897c478bd9Sstevel@tonic-gate *
9907c478bd9Sstevel@tonic-gate * Arguments:
9917c478bd9Sstevel@tonic-gate * pipeflag int
9927c478bd9Sstevel@tonic-gate * TRUE if a parsable report is needed,
9937c478bd9Sstevel@tonic-gate * FALSE if a columnar report is needed
9947c478bd9Sstevel@tonic-gate * xtndflag int
9957c478bd9Sstevel@tonic-gate * TRUE if extended set of info is to be displayed,
9967c478bd9Sstevel@tonic-gate * FALSE otherwise
9977c478bd9Sstevel@tonic-gate * expflag int
9987c478bd9Sstevel@tonic-gate * TRUE if password expiration information is to be
9997c478bd9Sstevel@tonic-gate * displayed, FALSE otherwise
10007c478bd9Sstevel@tonic-gate *
10017c478bd9Sstevel@tonic-gate * Returns: void
10027c478bd9Sstevel@tonic-gate */
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate static void
genuidreport(int pipeflag,int xtndflag,int expflag)100520d7339fSgww genuidreport(int pipeflag, int xtndflag, int expflag)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate
10087c478bd9Sstevel@tonic-gate struct display *current; /* Data being displayed */
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate
10117c478bd9Sstevel@tonic-gate /*
10127c478bd9Sstevel@tonic-gate * Initialization for loop.
101320d7339fSgww * (NOTE: The first element in the list of logins to display is
101420d7339fSgww * a dummy element.)
10157c478bd9Sstevel@tonic-gate */
10167c478bd9Sstevel@tonic-gate current = displayhead;
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate /*
10197c478bd9Sstevel@tonic-gate * Display elements in the list
10207c478bd9Sstevel@tonic-gate */
102120d7339fSgww if (pipeflag) {
102220d7339fSgww for (current = displayhead->nextuid; current;
102320d7339fSgww current = current->nextuid) {
10247c478bd9Sstevel@tonic-gate writeunformatted(current, xtndflag, expflag);
102520d7339fSgww }
102620d7339fSgww } else {
102720d7339fSgww for (current = displayhead->nextuid; current;
102820d7339fSgww current = current->nextuid) {
10297c478bd9Sstevel@tonic-gate writeformatted(current, xtndflag, expflag);
10307c478bd9Sstevel@tonic-gate }
103120d7339fSgww }
103220d7339fSgww }
103320d7339fSgww
103420d7339fSgww
10357c478bd9Sstevel@tonic-gate /*
10367c478bd9Sstevel@tonic-gate * void genlogreport(pipeflag, xtndflag, expflag)
10377c478bd9Sstevel@tonic-gate * int pipeflag
10387c478bd9Sstevel@tonic-gate * int xtndflag
10397c478bd9Sstevel@tonic-gate * int expflag
10407c478bd9Sstevel@tonic-gate *
10417c478bd9Sstevel@tonic-gate * This function generates a report on the standard output
10427c478bd9Sstevel@tonic-gate * stream (stdout) containing the login-IDs in the list of
10437c478bd9Sstevel@tonic-gate * logins built by this command. The list is ordered based
10447c478bd9Sstevel@tonic-gate * on user name. If the <pipeflag> variable is not zero, it
10457c478bd9Sstevel@tonic-gate * will generate a report containing parsable records.
10467c478bd9Sstevel@tonic-gate * Otherwise, it will generate a columnarized report. If
10477c478bd9Sstevel@tonic-gate * the <xtndflag> variable is not zero, it will include the
10487c478bd9Sstevel@tonic-gate * extended set of information (password aging info, home
10497c478bd9Sstevel@tonic-gate * directory, shell process, etc.). If <expflag> is not
10507c478bd9Sstevel@tonic-gate * zero, it will include password expiration information.
10517c478bd9Sstevel@tonic-gate *
10527c478bd9Sstevel@tonic-gate * Arguments:
10537c478bd9Sstevel@tonic-gate * pipeflag int
10547c478bd9Sstevel@tonic-gate * TRUE if a parsable report is needed,
10557c478bd9Sstevel@tonic-gate * FALSE if a columnar report is needed
10567c478bd9Sstevel@tonic-gate * xtndflag int
10577c478bd9Sstevel@tonic-gate * TRUE if extended set of info is to be displayed,
10587c478bd9Sstevel@tonic-gate * FALSE otherwise
10597c478bd9Sstevel@tonic-gate * expflag int
10607c478bd9Sstevel@tonic-gate * TRUE if password expiration information is to
10617c478bd9Sstevel@tonic-gate * be displayed, FALSE otherwise
10627c478bd9Sstevel@tonic-gate *
10637c478bd9Sstevel@tonic-gate * Returns: void
10647c478bd9Sstevel@tonic-gate */
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate static void
genlogreport(int pipeflag,int xtndflag,int expflag)106720d7339fSgww genlogreport(int pipeflag, int xtndflag, int expflag)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate struct display *p; /* Value being displayed */
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate
10727c478bd9Sstevel@tonic-gate /*
10737c478bd9Sstevel@tonic-gate * Initialization for loop.
107420d7339fSgww * (NOTE: The first element in the list of logins to display is
107520d7339fSgww * a dummy element.)
10767c478bd9Sstevel@tonic-gate */
10777c478bd9Sstevel@tonic-gate p = displayhead;
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate * Display elements in the list
10817c478bd9Sstevel@tonic-gate */
108220d7339fSgww if (pipeflag) {
108320d7339fSgww for (p = displayhead->nextlogin; p; p = p->nextlogin) {
10847c478bd9Sstevel@tonic-gate writeunformatted(p, xtndflag, expflag);
108520d7339fSgww }
108620d7339fSgww } else {
108720d7339fSgww for (p = displayhead->nextlogin; p; p = p->nextlogin) {
10887c478bd9Sstevel@tonic-gate writeformatted(p, xtndflag, expflag);
10897c478bd9Sstevel@tonic-gate }
109020d7339fSgww }
109120d7339fSgww }
10927c478bd9Sstevel@tonic-gate
10937c478bd9Sstevel@tonic-gate struct localpw {
10947c478bd9Sstevel@tonic-gate struct localpw *next;
10957c478bd9Sstevel@tonic-gate struct passwd pw;
10967c478bd9Sstevel@tonic-gate };
10977c478bd9Sstevel@tonic-gate
10987c478bd9Sstevel@tonic-gate struct localpw *pwtable = NULL;
10997c478bd9Sstevel@tonic-gate
110020d7339fSgww /* Local passwd pointer for getpwent() -- -1 means not in use, NULL for EOF */
110120d7339fSgww struct localpw *pwptr;
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate int in_localgetpwent = 0; /* Set if in local_getpwent */
11047c478bd9Sstevel@tonic-gate
1105b816ddf8Sgww static struct localpw *
fill_localpw(struct localpw * lpw,struct passwd * pw)1106b816ddf8Sgww fill_localpw(struct localpw *lpw, struct passwd *pw) {
1107b816ddf8Sgww struct localpw *cur;
1108b816ddf8Sgww
1109b816ddf8Sgww /*
1110b816ddf8Sgww * Copy the data -- we have to alloc areas for it all
1111b816ddf8Sgww */
1112b816ddf8Sgww lpw->pw.pw_name = strdup(pw->pw_name);
1113b816ddf8Sgww lpw->pw.pw_passwd = strdup(pw->pw_passwd);
1114b816ddf8Sgww lpw->pw.pw_uid = pw->pw_uid;
1115b816ddf8Sgww lpw->pw.pw_gid = pw->pw_gid;
1116b816ddf8Sgww lpw->pw.pw_age = strdup(pw->pw_age);
1117b816ddf8Sgww lpw->pw.pw_comment = strdup(pw->pw_comment);
1118b816ddf8Sgww lpw->pw.pw_gecos = strdup(pw->pw_gecos);
1119b816ddf8Sgww lpw->pw.pw_dir = strdup(pw->pw_dir);
1120b816ddf8Sgww lpw->pw.pw_shell = strdup(pw->pw_shell);
1121b816ddf8Sgww
1122b816ddf8Sgww cur = lpw;
1123b816ddf8Sgww lpw->next = malloc(sizeof (struct localpw));
1124b816ddf8Sgww return (cur);
1125b816ddf8Sgww }
1126b816ddf8Sgww
11277c478bd9Sstevel@tonic-gate void
build_localpw(struct reqlogin * req_head)1128b816ddf8Sgww build_localpw(struct reqlogin *req_head)
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate struct localpw *next, *cur;
11317c478bd9Sstevel@tonic-gate struct passwd *pw;
1132b816ddf8Sgww struct reqlogin *req_next;
11337c478bd9Sstevel@tonic-gate
1134b816ddf8Sgww next = malloc(sizeof (struct localpw));
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate pwtable = next;
11377c478bd9Sstevel@tonic-gate
1138b816ddf8Sgww req_next = req_head;
1139b816ddf8Sgww
1140b816ddf8Sgww while (req_next != NULL) {
1141b816ddf8Sgww if ((pw = getpwnam(req_next->loginname)) != NULL) {
1142b816ddf8Sgww /*
1143b816ddf8Sgww * Copy the data -- we have to alloc areas for it all
1144b816ddf8Sgww */
1145b816ddf8Sgww cur = fill_localpw(next, pw);
1146b816ddf8Sgww req_next->found = TRUE;
1147b816ddf8Sgww next = cur->next;
1148b816ddf8Sgww }
1149b816ddf8Sgww
1150b816ddf8Sgww req_next = req_next->next;
1151b816ddf8Sgww }
1152b816ddf8Sgww
1153b816ddf8Sgww if (req_head == NULL) {
11547c478bd9Sstevel@tonic-gate while ((pw = getpwent()) != NULL) {
11557c478bd9Sstevel@tonic-gate /*
11567c478bd9Sstevel@tonic-gate * Copy the data -- we have to alloc areas for it all
11577c478bd9Sstevel@tonic-gate */
1158b816ddf8Sgww cur = fill_localpw(next, pw);
1159b816ddf8Sgww next = cur->next;
11607c478bd9Sstevel@tonic-gate }
1161b816ddf8Sgww }
11627c478bd9Sstevel@tonic-gate
116320d7339fSgww if (pwtable == next) {
11647c478bd9Sstevel@tonic-gate pwtable = NULL;
116520d7339fSgww } else {
1166b816ddf8Sgww free(next);
11677c478bd9Sstevel@tonic-gate cur->next = NULL;
116820d7339fSgww }
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate endpwent();
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate struct passwd *
local_getpwent(void)117420d7339fSgww local_getpwent(void)
11757c478bd9Sstevel@tonic-gate {
11767c478bd9Sstevel@tonic-gate if (!in_localgetpwent) {
11777c478bd9Sstevel@tonic-gate in_localgetpwent = 1;
11787c478bd9Sstevel@tonic-gate pwptr = pwtable;
117920d7339fSgww } else if (pwptr != NULL) {
11807c478bd9Sstevel@tonic-gate pwptr = pwptr->next;
118120d7339fSgww }
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate if (pwptr != NULL)
118420d7339fSgww return (&(pwptr->pw));
11857c478bd9Sstevel@tonic-gate else
118620d7339fSgww return (NULL);
11877c478bd9Sstevel@tonic-gate }
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate void
local_endpwent(void)119020d7339fSgww local_endpwent(void)
11917c478bd9Sstevel@tonic-gate {
11927c478bd9Sstevel@tonic-gate in_localgetpwent = 0;
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate long
local_pwtell(void)119620d7339fSgww local_pwtell(void)
11977c478bd9Sstevel@tonic-gate {
119820d7339fSgww return ((long)pwptr);
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate
12017c478bd9Sstevel@tonic-gate void
local_pwseek(long ptr)120220d7339fSgww local_pwseek(long ptr)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate pwptr = (struct localpw *)ptr;
12057c478bd9Sstevel@tonic-gate }
120620d7339fSgww
12077c478bd9Sstevel@tonic-gate /*
12087c478bd9Sstevel@tonic-gate * logins [-admopstux] [-l logins] [-g groups]
12097c478bd9Sstevel@tonic-gate *
12107c478bd9Sstevel@tonic-gate * This command generates a report of logins administered on
12117c478bd9Sstevel@tonic-gate * the system. The list will contain logins that meet criteria
12127c478bd9Sstevel@tonic-gate * described by the options in the list. If there are no options,
12137c478bd9Sstevel@tonic-gate * it will list all logins administered. It is intended to be used
12147c478bd9Sstevel@tonic-gate * only by administrators.
12157c478bd9Sstevel@tonic-gate *
12167c478bd9Sstevel@tonic-gate * Options:
12177c478bd9Sstevel@tonic-gate * -a Display password expiration information.
12187c478bd9Sstevel@tonic-gate * -d list all logins that share user-IDs with another
12197c478bd9Sstevel@tonic-gate * login.
12207c478bd9Sstevel@tonic-gate * -g groups specifies the names of the groups to which a login
12217c478bd9Sstevel@tonic-gate * must belong before it is included in the generated
12227c478bd9Sstevel@tonic-gate * list. "groups" is a comma-list of group names.
12237c478bd9Sstevel@tonic-gate * -l logins specifies the logins to display. "logins" is a
12247c478bd9Sstevel@tonic-gate * comma-list of login names.
12257c478bd9Sstevel@tonic-gate * -m in addition to the usual information, for each
12267c478bd9Sstevel@tonic-gate * login displayed, list all groups to which that
12277c478bd9Sstevel@tonic-gate * login is member.
12287c478bd9Sstevel@tonic-gate * -o generate a report as a colon-list instead of in a
12297c478bd9Sstevel@tonic-gate * columnar format
12307c478bd9Sstevel@tonic-gate * -p list all logins that have no password.
12317c478bd9Sstevel@tonic-gate * -s list all system logins
12327c478bd9Sstevel@tonic-gate * -t sort the report lexicographically by login name
12337c478bd9Sstevel@tonic-gate * instead of by user-ID
12347c478bd9Sstevel@tonic-gate * -u list all user logins
12357c478bd9Sstevel@tonic-gate * -x in addition to the usual information, display an
12367c478bd9Sstevel@tonic-gate * extended set of information that includes the home
12377c478bd9Sstevel@tonic-gate * directory, initial process, and password status and
12387c478bd9Sstevel@tonic-gate * aging information
12397c478bd9Sstevel@tonic-gate *
12407c478bd9Sstevel@tonic-gate * Exit Codes:
12417c478bd9Sstevel@tonic-gate * 0 All's well that ends well
12427c478bd9Sstevel@tonic-gate * 1 Usage error
12437c478bd9Sstevel@tonic-gate */
12447c478bd9Sstevel@tonic-gate
124520d7339fSgww int
main(int argc,char * argv[])124620d7339fSgww main(int argc, char *argv[])
12477c478bd9Sstevel@tonic-gate {
12487c478bd9Sstevel@tonic-gate struct passwd *plookpwd; /* Ptr to searcher pw (-d) */
12497c478bd9Sstevel@tonic-gate struct reqgrp *reqgrphead; /* Head of the req'd group list */
12507c478bd9Sstevel@tonic-gate struct reqgrp *pgrp; /* Current item in req'd group list */
12517c478bd9Sstevel@tonic-gate struct reqgrp *qgrp; /* Prev item in the req'd group list */
12527c478bd9Sstevel@tonic-gate struct reqlogin *reqloginhead; /* Head of req'd login list */
125320d7339fSgww struct reqlogin *plogin; /* Current item in req'd login list */
125420d7339fSgww struct reqlogin *qlogin; /* Prev item in req'd login list */
12557c478bd9Sstevel@tonic-gate struct passwd *pwent; /* /etc/passwd entry */
12567c478bd9Sstevel@tonic-gate struct group *grent; /* /etc/group entry */
12577c478bd9Sstevel@tonic-gate char *token; /* Token extracted by strtok() */
12587c478bd9Sstevel@tonic-gate char **pp; /* Group member */
12597c478bd9Sstevel@tonic-gate char *g_arg; /* -g option's argument */
12607c478bd9Sstevel@tonic-gate char *l_arg; /* -l option's argument */
12617c478bd9Sstevel@tonic-gate long lookpos; /* File pos'n, rec we're looking for */
12627c478bd9Sstevel@tonic-gate int a_seen; /* Is -a requested? */
12637c478bd9Sstevel@tonic-gate int d_seen; /* Is -d requested? */
12647c478bd9Sstevel@tonic-gate int g_seen; /* Is -g requested? */
12657c478bd9Sstevel@tonic-gate int l_seen; /* Is -l requested? */
12667c478bd9Sstevel@tonic-gate int m_seen; /* Is -m requested? */
12677c478bd9Sstevel@tonic-gate int o_seen; /* Is -o requested? */
12687c478bd9Sstevel@tonic-gate int p_seen; /* Is -p requested? */
12697c478bd9Sstevel@tonic-gate int s_seen; /* Is -s requested? */
12707c478bd9Sstevel@tonic-gate int t_seen; /* Is -t requested? */
12717c478bd9Sstevel@tonic-gate int u_seen; /* Is -u requested? */
12727c478bd9Sstevel@tonic-gate int x_seen; /* Is -x requested? */
12737c478bd9Sstevel@tonic-gate int errflg; /* Is there a command-line problem */
12747c478bd9Sstevel@tonic-gate int done; /* Is the process (?) is complete */
127520d7339fSgww int groupcount; /* Number of groups specified */
12767c478bd9Sstevel@tonic-gate int doall; /* Are all logins to be reported */
12777c478bd9Sstevel@tonic-gate int c; /* Character returned from getopt() */
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
12827c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
12837c478bd9Sstevel@tonic-gate #endif
12847c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate /* Initializations */
12877c478bd9Sstevel@tonic-gate initmsg(argv[0]);
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate
129120d7339fSgww /* Command-line processing */
12927c478bd9Sstevel@tonic-gate
12937c478bd9Sstevel@tonic-gate /* Initializations */
12947c478bd9Sstevel@tonic-gate a_seen = FALSE;
12957c478bd9Sstevel@tonic-gate d_seen = FALSE;
12967c478bd9Sstevel@tonic-gate g_seen = FALSE;
12977c478bd9Sstevel@tonic-gate l_seen = FALSE;
12987c478bd9Sstevel@tonic-gate m_seen = FALSE;
12997c478bd9Sstevel@tonic-gate o_seen = FALSE;
13007c478bd9Sstevel@tonic-gate p_seen = FALSE;
13017c478bd9Sstevel@tonic-gate s_seen = FALSE;
13027c478bd9Sstevel@tonic-gate t_seen = FALSE;
13037c478bd9Sstevel@tonic-gate u_seen = FALSE;
13047c478bd9Sstevel@tonic-gate x_seen = FALSE;
13057c478bd9Sstevel@tonic-gate errflg = FALSE;
13067c478bd9Sstevel@tonic-gate opterr = 0;
13077c478bd9Sstevel@tonic-gate while (!errflg && ((c = getopt(argc, argv, OPTSTR)) != EOF)) {
13087c478bd9Sstevel@tonic-gate
13097c478bd9Sstevel@tonic-gate /* Case on the option character */
13107c478bd9Sstevel@tonic-gate switch (c) {
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate /*
13137c478bd9Sstevel@tonic-gate * -a option:
13147c478bd9Sstevel@tonic-gate * Display password expiration information
13157c478bd9Sstevel@tonic-gate */
13167c478bd9Sstevel@tonic-gate
13177c478bd9Sstevel@tonic-gate case 'a':
131820d7339fSgww if (a_seen)
131920d7339fSgww errflg = TRUE;
132020d7339fSgww else
132120d7339fSgww a_seen = TRUE;
13227c478bd9Sstevel@tonic-gate break;
13237c478bd9Sstevel@tonic-gate
13247c478bd9Sstevel@tonic-gate /*
13257c478bd9Sstevel@tonic-gate * -d option:
13267c478bd9Sstevel@tonic-gate * Display logins which share user-IDs with other logins
13277c478bd9Sstevel@tonic-gate */
13287c478bd9Sstevel@tonic-gate
13297c478bd9Sstevel@tonic-gate case 'd':
133020d7339fSgww if (d_seen)
133120d7339fSgww errflg = TRUE;
133220d7339fSgww else
133320d7339fSgww d_seen = TRUE;
13347c478bd9Sstevel@tonic-gate break;
13357c478bd9Sstevel@tonic-gate
13367c478bd9Sstevel@tonic-gate /*
13377c478bd9Sstevel@tonic-gate * -g <groups> option:
13387c478bd9Sstevel@tonic-gate * Display the specified groups
13397c478bd9Sstevel@tonic-gate */
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate case 'g':
134220d7339fSgww if (g_seen) {
134320d7339fSgww errflg = TRUE;
134420d7339fSgww } else {
13457c478bd9Sstevel@tonic-gate g_seen = TRUE;
13467c478bd9Sstevel@tonic-gate g_arg = optarg;
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate break;
13497c478bd9Sstevel@tonic-gate
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate * -l <logins> option:
13527c478bd9Sstevel@tonic-gate * Display the specified logins
13537c478bd9Sstevel@tonic-gate */
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate case 'l':
135620d7339fSgww if (l_seen) {
135720d7339fSgww errflg = TRUE;
135820d7339fSgww } else {
13597c478bd9Sstevel@tonic-gate l_seen = TRUE;
13607c478bd9Sstevel@tonic-gate l_arg = optarg;
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate break;
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate /*
13657c478bd9Sstevel@tonic-gate * -m option:
13667c478bd9Sstevel@tonic-gate * Display multiple group information
13677c478bd9Sstevel@tonic-gate */
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate case 'm':
137020d7339fSgww if (m_seen)
137120d7339fSgww errflg = TRUE;
137220d7339fSgww else
137320d7339fSgww m_seen = TRUE;
13747c478bd9Sstevel@tonic-gate break;
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate /*
13777c478bd9Sstevel@tonic-gate * -o option:
13787c478bd9Sstevel@tonic-gate * Display information as a colon-list
13797c478bd9Sstevel@tonic-gate */
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate case 'o':
138220d7339fSgww if (o_seen)
138320d7339fSgww errflg = TRUE;
138420d7339fSgww else
138520d7339fSgww o_seen = TRUE;
13867c478bd9Sstevel@tonic-gate break;
13877c478bd9Sstevel@tonic-gate
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate * -p option:
13907c478bd9Sstevel@tonic-gate * Select logins that have no password
13917c478bd9Sstevel@tonic-gate */
13927c478bd9Sstevel@tonic-gate
13937c478bd9Sstevel@tonic-gate case 'p':
139420d7339fSgww if (p_seen)
139520d7339fSgww errflg = TRUE;
139620d7339fSgww else
139720d7339fSgww p_seen = TRUE;
13987c478bd9Sstevel@tonic-gate break;
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate /*
14017c478bd9Sstevel@tonic-gate * -s option:
14027c478bd9Sstevel@tonic-gate * Select system logins
14037c478bd9Sstevel@tonic-gate */
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate case 's':
140620d7339fSgww if (s_seen)
140720d7339fSgww errflg = TRUE;
140820d7339fSgww else
140920d7339fSgww s_seen = TRUE;
14107c478bd9Sstevel@tonic-gate break;
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate * -t option:
14147c478bd9Sstevel@tonic-gate * Sort alphabetically by login-ID instead of numerically
14157c478bd9Sstevel@tonic-gate * by user-ID
14167c478bd9Sstevel@tonic-gate */
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate case 't':
141920d7339fSgww if (t_seen)
142020d7339fSgww errflg = TRUE;
142120d7339fSgww else
142220d7339fSgww t_seen = TRUE;
14237c478bd9Sstevel@tonic-gate break;
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate /*
14267c478bd9Sstevel@tonic-gate * -u option:
14277c478bd9Sstevel@tonic-gate * Select user logins
14287c478bd9Sstevel@tonic-gate */
14297c478bd9Sstevel@tonic-gate
14307c478bd9Sstevel@tonic-gate case 'u':
143120d7339fSgww if (u_seen)
143220d7339fSgww errflg = TRUE;
143320d7339fSgww else
143420d7339fSgww u_seen = TRUE;
14357c478bd9Sstevel@tonic-gate break;
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate /*
14387c478bd9Sstevel@tonic-gate * -x option:
14397c478bd9Sstevel@tonic-gate * Display extended info (init working dir, shell, pwd info)
14407c478bd9Sstevel@tonic-gate */
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate case 'x':
144320d7339fSgww if (x_seen)
144420d7339fSgww errflg = TRUE;
144520d7339fSgww else
144620d7339fSgww x_seen = TRUE;
14477c478bd9Sstevel@tonic-gate break;
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate default: /* Oops.... */
14507c478bd9Sstevel@tonic-gate errflg = TRUE;
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate /* Write out a usage message if necessary and quit */
14557c478bd9Sstevel@tonic-gate if (errflg || (optind != argc)) {
14567c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(USAGE_MSG));
14577c478bd9Sstevel@tonic-gate exit(1);
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate /*
14617c478bd9Sstevel@tonic-gate * The following section does preparation work, setting up for
14627c478bd9Sstevel@tonic-gate * building the list of logins to display
14637c478bd9Sstevel@tonic-gate */
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate /*
14677c478bd9Sstevel@tonic-gate * If -l logins is on the command line, build a list of
14687c478bd9Sstevel@tonic-gate * logins we're to generate reports for.
14697c478bd9Sstevel@tonic-gate */
14707c478bd9Sstevel@tonic-gate
14717c478bd9Sstevel@tonic-gate if (l_seen) {
147220d7339fSgww reqloginhead = NULL;
14737c478bd9Sstevel@tonic-gate if (token = strtok(l_arg, ",")) {
1474b816ddf8Sgww plogin = malloc(sizeof (struct reqlogin));
14757c478bd9Sstevel@tonic-gate plogin->loginname = token;
14767c478bd9Sstevel@tonic-gate plogin->found = FALSE;
147720d7339fSgww plogin->next = NULL;
14787c478bd9Sstevel@tonic-gate reqloginhead = plogin;
14797c478bd9Sstevel@tonic-gate qlogin = plogin;
14807c478bd9Sstevel@tonic-gate while (token = strtok(NULL, ",")) {
1481b816ddf8Sgww plogin = malloc(sizeof (struct reqlogin));
14827c478bd9Sstevel@tonic-gate plogin->loginname = token;
14837c478bd9Sstevel@tonic-gate plogin->found = FALSE;
148420d7339fSgww plogin->next = NULL;
14857c478bd9Sstevel@tonic-gate qlogin->next = plogin;
14867c478bd9Sstevel@tonic-gate qlogin = plogin;
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate }
1489b816ddf8Sgww /*
1490b816ddf8Sgww * Build an in-core structure of just the passwd database
1491b816ddf8Sgww * entries requested. This greatly reduces the time
1492b816ddf8Sgww * to get all entries and filter later.
1493b816ddf8Sgww */
1494b816ddf8Sgww build_localpw(reqloginhead);
1495b816ddf8Sgww } else {
1496b816ddf8Sgww /*
1497b816ddf8Sgww * Build an in-core structure of all passwd database
1498b816ddf8Sgww * entries. This is important since we have to assume that
1499b816ddf8Sgww * getpwent() is going out to one or more network name
1500b816ddf8Sgww * services that could be changing on the fly. This will
1501b816ddf8Sgww * limit us to one pass through the network data.
1502b816ddf8Sgww */
1503b816ddf8Sgww build_localpw(NULL);
1504b816ddf8Sgww }
1505b816ddf8Sgww
1506b816ddf8Sgww /*
1507b816ddf8Sgww * If the -g groups option was on the command line, build a
1508b816ddf8Sgww * list containing groups we're to list logins for.
1509b816ddf8Sgww */
1510b816ddf8Sgww
1511b816ddf8Sgww if (g_seen) {
1512b816ddf8Sgww groupcount = 0;
1513b816ddf8Sgww reqgrphead = NULL;
1514b816ddf8Sgww if (token = strtok(g_arg, ",")) {
1515b816ddf8Sgww pgrp = malloc(sizeof (struct reqgrp));
1516b816ddf8Sgww pgrp->groupname = token;
1517b816ddf8Sgww pgrp->next = NULL;
1518b816ddf8Sgww groupcount++;
1519b816ddf8Sgww reqgrphead = pgrp;
1520b816ddf8Sgww qgrp = pgrp;
1521b816ddf8Sgww while (token = strtok(NULL, ",")) {
1522b816ddf8Sgww pgrp = malloc(sizeof (struct reqgrp));
1523b816ddf8Sgww pgrp->groupname = token;
1524b816ddf8Sgww pgrp->next = NULL;
1525b816ddf8Sgww groupcount++;
1526b816ddf8Sgww qgrp->next = pgrp;
1527b816ddf8Sgww qgrp = pgrp;
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate }
15307c478bd9Sstevel@tonic-gate }
1531b816ddf8Sgww
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate * Generate the list of login information to display
15357c478bd9Sstevel@tonic-gate */
15367c478bd9Sstevel@tonic-gate
15377c478bd9Sstevel@tonic-gate /* Initialize the login list */
1538b816ddf8Sgww membershead = NULL;
15397c478bd9Sstevel@tonic-gate
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate /*
15427c478bd9Sstevel@tonic-gate * If -g groups was specified, generate a list of members
15437c478bd9Sstevel@tonic-gate * of the specified groups
15447c478bd9Sstevel@tonic-gate */
15457c478bd9Sstevel@tonic-gate
15467c478bd9Sstevel@tonic-gate if (g_seen) {
15477c478bd9Sstevel@tonic-gate /* For each group mentioned with the -g option ... */
154820d7339fSgww for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
154920d7339fSgww pgrp = pgrp->next) {
1550b816ddf8Sgww if ((grent = getgrnam(pgrp->groupname)) != NULL) {
15517c478bd9Sstevel@tonic-gate /*
1552b816ddf8Sgww * Remembering the group-ID for later
15537c478bd9Sstevel@tonic-gate */
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate groupcount--;
15567c478bd9Sstevel@tonic-gate pgrp->groupID = grent->gr_gid;
1557b816ddf8Sgww for (pp = grent->gr_mem; *pp; pp++) {
155820d7339fSgww addmember(*pp);
15597c478bd9Sstevel@tonic-gate }
1560b816ddf8Sgww } else {
156120d7339fSgww wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
156220d7339fSgww gettext("%s was not found"),
156320d7339fSgww pgrp->groupname);
156420d7339fSgww }
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate
15687c478bd9Sstevel@tonic-gate
15697c478bd9Sstevel@tonic-gate /* Initialize the list of logins to display */
15707c478bd9Sstevel@tonic-gate initdisp();
15717c478bd9Sstevel@tonic-gate
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate /*
15747c478bd9Sstevel@tonic-gate * Add logins that have user-IDs that are used more than once,
15757c478bd9Sstevel@tonic-gate * if requested. This command is pretty slow, since the algorithm
15767c478bd9Sstevel@tonic-gate * reads from the /etc/passwd file 1+2+3+...+n times where n is the
15777c478bd9Sstevel@tonic-gate * number of login-IDs in the /etc/passwd file. (Actually, this
15787c478bd9Sstevel@tonic-gate * can be optimized so it's not quite that bad, but the order or
15797c478bd9Sstevel@tonic-gate * magnitude stays the same.)
15807c478bd9Sstevel@tonic-gate *
15817c478bd9Sstevel@tonic-gate * Note: This processing needs to be done before any other options
15827c478bd9Sstevel@tonic-gate * are processed -- the algorithm contains an optimization
15837c478bd9Sstevel@tonic-gate * that insists on the display list being empty before this
15847c478bd9Sstevel@tonic-gate * option is processed.
15857c478bd9Sstevel@tonic-gate */
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate if (d_seen) {
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate /*
15907c478bd9Sstevel@tonic-gate * The following code is a quick&dirty reimplementation of the
15917c478bd9Sstevel@tonic-gate * original algorithm, which opened the password file twice (to
15927c478bd9Sstevel@tonic-gate * get two file pointer into the data) and then used fgetpwent()
15937c478bd9Sstevel@tonic-gate * in undocumented ways to scan through the file, checking for
15947c478bd9Sstevel@tonic-gate * duplicates. This does not work when getpwent() is used to
15957c478bd9Sstevel@tonic-gate * go out over the network, since there is not file pointer.
15967c478bd9Sstevel@tonic-gate *
159720d7339fSgww * Instead an in-memory list of passwd structures is built,
159820d7339fSgww * and then this list is scanned. The routines
159920d7339fSgww * Local_getpwent(), etc., are designed to mimic the standard
160020d7339fSgww * library routines, so this code does not have to be
160120d7339fSgww * extensively modified.
16027c478bd9Sstevel@tonic-gate */
16037c478bd9Sstevel@tonic-gate
16047c478bd9Sstevel@tonic-gate /*
16057c478bd9Sstevel@tonic-gate * For reference, here is the original comment about the next
160620d7339fSgww * section of code. Some of the code has changed, but the
160720d7339fSgww * algorithm is the same:
16087c478bd9Sstevel@tonic-gate *
16097c478bd9Sstevel@tonic-gate * Open the system password file once. This instance will be
16107c478bd9Sstevel@tonic-gate * used to leaf through the file once, reading each entry once,
16117c478bd9Sstevel@tonic-gate * and searching the remainder of the file for another login-ID
16127c478bd9Sstevel@tonic-gate * that has the same user-ID. Note that there are lots of
16137c478bd9Sstevel@tonic-gate * contortions one has to go through when reading two instances
16147c478bd9Sstevel@tonic-gate * of the /etc/passwd file. That's why there's some seeking,
16157c478bd9Sstevel@tonic-gate * re-reading of the same record, and other junk. Luckily, this
16167c478bd9Sstevel@tonic-gate * feature won't be requested very often, and still isn't too
16177c478bd9Sstevel@tonic-gate * slow...
16187c478bd9Sstevel@tonic-gate */
16197c478bd9Sstevel@tonic-gate
16207c478bd9Sstevel@tonic-gate /* For each entry in the passwd database ... */
16217c478bd9Sstevel@tonic-gate while (plookpwd = local_getpwent()) {
16227c478bd9Sstevel@tonic-gate /*
162320d7339fSgww * Optimization -- If the login's user-ID is already
162420d7339fSgww * in the display list, there's no reason to process
162520d7339fSgww * this entry -- it's already there.
16267c478bd9Sstevel@tonic-gate */
16277c478bd9Sstevel@tonic-gate if (!isuidindisp(plookpwd)) {
16287c478bd9Sstevel@tonic-gate /*
162920d7339fSgww * Rememeber the current entry's position,
163020d7339fSgww * so when we finish scanning through the
163120d7339fSgww * database looking for duplicates we can
163220d7339fSgww * return to the current place, so that the
163320d7339fSgww * enclosing loop will march in an orderly
163420d7339fSgww * fashion through the passwd database.
16357c478bd9Sstevel@tonic-gate */
16367c478bd9Sstevel@tonic-gate done = FALSE;
16377c478bd9Sstevel@tonic-gate lookpos = local_pwtell();
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate /*
164020d7339fSgww * For each record in the passwd database
164120d7339fSgww * beyond the searching record ...
16427c478bd9Sstevel@tonic-gate */
16437c478bd9Sstevel@tonic-gate while (pwent = local_getpwent()) {
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate /*
164620d7339fSgww * If there's a match between the
164720d7339fSgww * searcher's user-ID and the
164820d7339fSgww * searchee's user-ID ...
16497c478bd9Sstevel@tonic-gate */
16507c478bd9Sstevel@tonic-gate if (pwent->pw_uid == plookpwd->pw_uid) {
16517c478bd9Sstevel@tonic-gate /*
165220d7339fSgww * If this is the first
165320d7339fSgww * duplicate of this searcher
16547c478bd9Sstevel@tonic-gate * that we find,
165520d7339fSgww * add the searcher's
165620d7339fSgww * record to the display list
165720d7339fSgww * (It wants to be on the
165820d7339fSgww * list first to avoid
165920d7339fSgww * ordering "flakeyness")
16607c478bd9Sstevel@tonic-gate */
16617c478bd9Sstevel@tonic-gate if (done == FALSE) {
16627c478bd9Sstevel@tonic-gate adddisp(plookpwd);
166320d7339fSgww done = TRUE;
16647c478bd9Sstevel@tonic-gate }
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate /*
166720d7339fSgww * Now add the searchee's
166820d7339fSgww * record
16697c478bd9Sstevel@tonic-gate */
16707c478bd9Sstevel@tonic-gate adddisp(pwent);
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate }
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate /* Reposition to searcher record */
16757c478bd9Sstevel@tonic-gate local_pwseek(lookpos);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate local_endpwent();
16807c478bd9Sstevel@tonic-gate }
16817c478bd9Sstevel@tonic-gate
16827c478bd9Sstevel@tonic-gate
16837c478bd9Sstevel@tonic-gate /*
16847c478bd9Sstevel@tonic-gate * Loop through the passwd database squirelling away the
16857c478bd9Sstevel@tonic-gate * information we need for the display.
16867c478bd9Sstevel@tonic-gate *
16877c478bd9Sstevel@tonic-gate * NOTE: Once a login is added to the list, the rest of the
16887c478bd9Sstevel@tonic-gate * body of the loop is bypassed (via a continue statement).
16897c478bd9Sstevel@tonic-gate */
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate doall = !(s_seen || u_seen || p_seen || d_seen || l_seen || g_seen);
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate if (doall || s_seen || u_seen || p_seen || l_seen || g_seen) {
16947c478bd9Sstevel@tonic-gate
16957c478bd9Sstevel@tonic-gate while (pwent = local_getpwent()) {
16967c478bd9Sstevel@tonic-gate done = FALSE;
16977c478bd9Sstevel@tonic-gate
169820d7339fSgww /*
169920d7339fSgww * If no user-specific options were specified,
170020d7339fSgww * include this login-ID
170120d7339fSgww */
17027c478bd9Sstevel@tonic-gate if (doall) {
17037c478bd9Sstevel@tonic-gate adddisp(pwent);
17047c478bd9Sstevel@tonic-gate continue;
17057c478bd9Sstevel@tonic-gate }
17067c478bd9Sstevel@tonic-gate
170720d7339fSgww /*
170820d7339fSgww * If the user specified system login-IDs,
170920d7339fSgww * and this is a system ID, include it
171020d7339fSgww */
171120d7339fSgww if (s_seen) {
171220d7339fSgww if (isasystemlogin(pwent)) {
17137c478bd9Sstevel@tonic-gate adddisp(pwent);
17147c478bd9Sstevel@tonic-gate continue;
17157c478bd9Sstevel@tonic-gate }
171620d7339fSgww }
17177c478bd9Sstevel@tonic-gate
171820d7339fSgww /*
171920d7339fSgww * If the user specified user login-IDs,
172020d7339fSgww * and this is a user ID, include it
172120d7339fSgww */
172220d7339fSgww if (u_seen) {
172320d7339fSgww if (isauserlogin(pwent)) {
17247c478bd9Sstevel@tonic-gate adddisp(pwent);
17257c478bd9Sstevel@tonic-gate continue;
17267c478bd9Sstevel@tonic-gate }
172720d7339fSgww }
17287c478bd9Sstevel@tonic-gate
172920d7339fSgww /*
173020d7339fSgww * If the user is asking for login-IDs that have
173120d7339fSgww * no password, and this one has no password, include it
173220d7339fSgww */
173320d7339fSgww if (p_seen) {
173420d7339fSgww if (hasnopasswd(pwent)) {
17357c478bd9Sstevel@tonic-gate adddisp(pwent);
17367c478bd9Sstevel@tonic-gate continue;
17377c478bd9Sstevel@tonic-gate }
173820d7339fSgww }
17397c478bd9Sstevel@tonic-gate
17407c478bd9Sstevel@tonic-gate /*
17417c478bd9Sstevel@tonic-gate * If specific logins were requested, leaf through
17427c478bd9Sstevel@tonic-gate * the list of logins they requested. If this login
17437c478bd9Sstevel@tonic-gate * is on the list, include it.
17447c478bd9Sstevel@tonic-gate */
17457c478bd9Sstevel@tonic-gate if (l_seen) {
174620d7339fSgww for (plogin = reqloginhead; !done && plogin;
174720d7339fSgww plogin = plogin->next) {
174820d7339fSgww if (strcmp(pwent->pw_name,
174920d7339fSgww plogin->loginname) == 0) {
17507c478bd9Sstevel@tonic-gate plogin->found = TRUE;
17517c478bd9Sstevel@tonic-gate adddisp(pwent);
17527c478bd9Sstevel@tonic-gate done = TRUE;
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate }
175520d7339fSgww if (done)
175620d7339fSgww continue;
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate * If specific groups were requested, leaf through the
176120d7339fSgww * list of login-IDs that belong to those groups.
176220d7339fSgww * If this login-ID is in that list, or its primary
176320d7339fSgww * group is one of those requested, include it.
17647c478bd9Sstevel@tonic-gate */
17657c478bd9Sstevel@tonic-gate
17667c478bd9Sstevel@tonic-gate if (g_seen) {
176720d7339fSgww for (pgrp = reqgrphead; !done && pgrp;
176820d7339fSgww pgrp = pgrp->next) {
17697c478bd9Sstevel@tonic-gate if (pwent->pw_gid == pgrp->groupID) {
17707c478bd9Sstevel@tonic-gate adddisp(pwent);
17717c478bd9Sstevel@tonic-gate done = TRUE;
17727c478bd9Sstevel@tonic-gate }
177320d7339fSgww }
17747c478bd9Sstevel@tonic-gate if (!done && isamember(pwent->pw_name)) {
17757c478bd9Sstevel@tonic-gate adddisp(pwent);
17767c478bd9Sstevel@tonic-gate done = TRUE;
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate }
177920d7339fSgww if (done)
178020d7339fSgww continue;
17817c478bd9Sstevel@tonic-gate }
178220d7339fSgww
17837c478bd9Sstevel@tonic-gate local_endpwent();
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate
178620d7339fSgww /* Let the user know about logins they requested that don't exist */
178720d7339fSgww if (l_seen) {
178820d7339fSgww for (plogin = reqloginhead; plogin; plogin = plogin->next) {
178920d7339fSgww if (!plogin->found) {
179020d7339fSgww wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
179120d7339fSgww gettext("%s was not found"),
179220d7339fSgww plogin->loginname);
179320d7339fSgww }
179420d7339fSgww }
179520d7339fSgww }
17967c478bd9Sstevel@tonic-gate
179720d7339fSgww /* Apply group information */
17987c478bd9Sstevel@tonic-gate applygroup(m_seen);
17997c478bd9Sstevel@tonic-gate
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate /*
18027c478bd9Sstevel@tonic-gate * Apply password information (only needed if the extended
18037c478bd9Sstevel@tonic-gate * set of information has been requested)
18047c478bd9Sstevel@tonic-gate */
180520d7339fSgww if (x_seen || a_seen)
180620d7339fSgww applypasswd();
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate
18097c478bd9Sstevel@tonic-gate /*
181020d7339fSgww * Generate a report from this display items we've squirreled away
18117c478bd9Sstevel@tonic-gate */
18127c478bd9Sstevel@tonic-gate
181320d7339fSgww if (t_seen)
181420d7339fSgww genlogreport(o_seen, x_seen, a_seen);
181520d7339fSgww else
181620d7339fSgww genuidreport(o_seen, x_seen, a_seen);
18177c478bd9Sstevel@tonic-gate
181820d7339fSgww /* We're through! */
18197c478bd9Sstevel@tonic-gate return (0);
18207c478bd9Sstevel@tonic-gate }
1821