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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 * 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 119020d7339fSgww local_endpwent(void) 11917c478bd9Sstevel@tonic-gate { 11927c478bd9Sstevel@tonic-gate in_localgetpwent = 0; 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate long 119620d7339fSgww local_pwtell(void) 11977c478bd9Sstevel@tonic-gate { 119820d7339fSgww return ((long)pwptr); 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate void 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 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