17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 2320d7339fSgww * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.15.1.2 */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * logins.c 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * This file contains the source for the administrative command 367c478bd9Sstevel@tonic-gate * "logins" (available to the administrator) that produces a report 377c478bd9Sstevel@tonic-gate * containing login-IDs and other requested information. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <stdio.h> 4220d7339fSgww #include <stdlib.h> 437c478bd9Sstevel@tonic-gate #include <unistd.h> 447c478bd9Sstevel@tonic-gate #include <string.h> 457c478bd9Sstevel@tonic-gate #include <ctype.h> 467c478bd9Sstevel@tonic-gate #include <grp.h> 477c478bd9Sstevel@tonic-gate #include <pwd.h> 487c478bd9Sstevel@tonic-gate #include <shadow.h> 497c478bd9Sstevel@tonic-gate #include <time.h> 507c478bd9Sstevel@tonic-gate #include <stdarg.h> 517c478bd9Sstevel@tonic-gate #include <fmtmsg.h> 527c478bd9Sstevel@tonic-gate #include <locale.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * Local constant definitions 567c478bd9Sstevel@tonic-gate * TRUE Boolean constant 577c478bd9Sstevel@tonic-gate * FALSE Boolean constant 587c478bd9Sstevel@tonic-gate * USAGE_MSG Message used to display a usage error 597c478bd9Sstevel@tonic-gate * MAXLOGINSIZE Maximum length of a valid login-ID 607c478bd9Sstevel@tonic-gate * MAXSYSTEMLOGIN Maximum value of a system user-ID. 617c478bd9Sstevel@tonic-gate * OPTSTR Options to this command 627c478bd9Sstevel@tonic-gate * ROOT_ID The user-ID of an administrator 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #ifndef FALSE 667c478bd9Sstevel@tonic-gate #define FALSE 0 677c478bd9Sstevel@tonic-gate #endif 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #ifndef TRUE 707c478bd9Sstevel@tonic-gate #define TRUE ((int)'t') 717c478bd9Sstevel@tonic-gate #endif 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #define USAGE_MSG "usage: logins [-admopstux] [-g groups] [-l logins]" 747c478bd9Sstevel@tonic-gate #define MAXLOGINSIZE 14 757c478bd9Sstevel@tonic-gate #define MAXSYSTEMLOGIN 99 767c478bd9Sstevel@tonic-gate #define OPTSTR "adg:l:mopstux" 777c478bd9Sstevel@tonic-gate #define ROOT_ID 0 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * The following macros do their function for now but will probably have 817c478bd9Sstevel@tonic-gate * to be replaced by functions sometime in the near future. The maximum 827c478bd9Sstevel@tonic-gate * system login value may someday be administerable, in which case these 837c478bd9Sstevel@tonic-gate * will have to be changed to become functions 847c478bd9Sstevel@tonic-gate * 857c478bd9Sstevel@tonic-gate * isasystemlogin Returns TRUE if the user-ID in the "struct passwd" 867c478bd9Sstevel@tonic-gate * structure referenced by the function's argument is 877c478bd9Sstevel@tonic-gate * less than or equal to the maximum value for a system 887c478bd9Sstevel@tonic-gate * user-ID, FALSE otherwise. 897c478bd9Sstevel@tonic-gate * isauserlogin Returns TRUE if the user-ID in the "struct passwd" 907c478bd9Sstevel@tonic-gate * structure referenced by the function's argument is 917c478bd9Sstevel@tonic-gate * greater than the maximum value for a system user-ID, 927c478bd9Sstevel@tonic-gate * FALSE otherwise. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate #define isauserlogin(pw) (pw->pw_uid > MAXSYSTEMLOGIN) 967c478bd9Sstevel@tonic-gate #define isasystemlogin(pw) (pw->pw_uid <= MAXSYSTEMLOGIN) 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate /* 1007c478bd9Sstevel@tonic-gate * Local datatype definitions 1017c478bd9Sstevel@tonic-gate * struct reqgrp Describes a group as requested through the 1027c478bd9Sstevel@tonic-gate * -g option 1037c478bd9Sstevel@tonic-gate * struct reqlogin Describes a login-ID as requested through 1047c478bd9Sstevel@tonic-gate * the -l option 1057c478bd9Sstevel@tonic-gate * struct pwdinfo Describes a password's aging information, 1067c478bd9Sstevel@tonic-gate * as extracted from /etc/shadow 1077c478bd9Sstevel@tonic-gate * struct secgrp Describes a login-ID's secondary group 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate /* Describes a specified group name (from the -g groups option) */ 1117c478bd9Sstevel@tonic-gate struct reqgrp { 1127c478bd9Sstevel@tonic-gate char *groupname; /* Requested group name */ 1137c478bd9Sstevel@tonic-gate struct reqgrp *next; /* Next item in the list */ 1147c478bd9Sstevel@tonic-gate gid_t groupID; /* Group's ID */ 1157c478bd9Sstevel@tonic-gate }; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* Describes a specified login name (from the -l logins option) */ 1187c478bd9Sstevel@tonic-gate struct reqlogin { 1197c478bd9Sstevel@tonic-gate char *loginname; /* Requested login name */ 1207c478bd9Sstevel@tonic-gate struct reqlogin *next; /* Next item in the list */ 1217c478bd9Sstevel@tonic-gate int found; /* TRUE if login in /etc/passwd */ 1227c478bd9Sstevel@tonic-gate }; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * This structure describes a password's information 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate struct pwdinfo { 1297c478bd9Sstevel@tonic-gate long datechg; /* Date the password was changed (mmddyy) */ 1307c478bd9Sstevel@tonic-gate char *passwdstatus; /* Password status */ 1317c478bd9Sstevel@tonic-gate long mindaystilchg; /* Min days b4 pwd can change again */ 1327c478bd9Sstevel@tonic-gate long maxdaystilchg; /* Max days b4 pwd can change again */ 1337c478bd9Sstevel@tonic-gate long warninterval; /* Days before expire to warn user */ 1347c478bd9Sstevel@tonic-gate long inactive; /* Lapsed days of inactivity before lock */ 1357c478bd9Sstevel@tonic-gate long expdate; /* Date of expiration (mmddyy) */ 1367c478bd9Sstevel@tonic-gate }; 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* This structure describes secondary groups that a user belongs to */ 1397c478bd9Sstevel@tonic-gate struct secgrp { 1407c478bd9Sstevel@tonic-gate char *groupname; /* Name of the group */ 1417c478bd9Sstevel@tonic-gate struct secgrp *next; /* Next item in the list */ 1427c478bd9Sstevel@tonic-gate gid_t groupID; /* Group-ID */ 1437c478bd9Sstevel@tonic-gate }; 14420d7339fSgww 14520d7339fSgww 1467c478bd9Sstevel@tonic-gate /* 1477c478bd9Sstevel@tonic-gate * These functions handle error and warning message writing. 1487c478bd9Sstevel@tonic-gate * (This deals with UNIX(r) standard message generation, so 1497c478bd9Sstevel@tonic-gate * the rest of the code doesn't have to.) 1507c478bd9Sstevel@tonic-gate * 1517c478bd9Sstevel@tonic-gate * Functions included: 1527c478bd9Sstevel@tonic-gate * initmsg Initialize the message handling functions. 1537c478bd9Sstevel@tonic-gate * wrtmsg Write the message using fmtmsg(). 1547c478bd9Sstevel@tonic-gate * 1557c478bd9Sstevel@tonic-gate * Static data included: 1567c478bd9Sstevel@tonic-gate * fcnlbl The label for standard messages 1577c478bd9Sstevel@tonic-gate * msgbuf A buffer to contain the edited message 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static char fcnlbl[MM_MXLABELLN+1]; /* Buffer for message label */ 1617c478bd9Sstevel@tonic-gate static char msgbuf[MM_MXTXTLN+1]; /* Buffer for message text */ 16220d7339fSgww 16320d7339fSgww 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * void initmsg(p) 1667c478bd9Sstevel@tonic-gate * 1677c478bd9Sstevel@tonic-gate * This function initializes the message handling functions. 1687c478bd9Sstevel@tonic-gate * 1697c478bd9Sstevel@tonic-gate * Arguments: 1707c478bd9Sstevel@tonic-gate * p A pointer to a character string that is the name of the 1717c478bd9Sstevel@tonic-gate * function, used to generate the label on messages. If this 1727c478bd9Sstevel@tonic-gate * string contains a slash ('/'), it only uses the characters 1737c478bd9Sstevel@tonic-gate * beyond the last slash in the string (this permits argv[0] 1747c478bd9Sstevel@tonic-gate * to be used). 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * Returns: Void 1777c478bd9Sstevel@tonic-gate */ 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate static void 18020d7339fSgww initmsg(char *p) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate char *q; /* Local multi-use pointer */ 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate /* Use only the simple filename if there is a slash in the name */ 18520d7339fSgww if (!(q = strrchr(p, '/'))) { 18620d7339fSgww q = p; 18720d7339fSgww } else { 18820d7339fSgww q++; 18920d7339fSgww } 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* Build the label for messages */ 19220d7339fSgww (void) snprintf(fcnlbl, MM_MXLABELLN, "UX:%s", q); 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate /* Restrict messages to the text-component */ 1957c478bd9Sstevel@tonic-gate (void) putenv("MSGVERB=text"); 1967c478bd9Sstevel@tonic-gate } 19720d7339fSgww 19820d7339fSgww 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]]) 2017c478bd9Sstevel@tonic-gate * 2027c478bd9Sstevel@tonic-gate * This function writes a message using fmtmsg() 2037c478bd9Sstevel@tonic-gate * 2047c478bd9Sstevel@tonic-gate * Arguments: 2057c478bd9Sstevel@tonic-gate * severity The severity-component of the message 2067c478bd9Sstevel@tonic-gate * action The action-string used to generate the 2077c478bd9Sstevel@tonic-gate * action-component of the message 2087c478bd9Sstevel@tonic-gate * tag Tag-component of the message 2097c478bd9Sstevel@tonic-gate * text The text-string used to generate the text- 2107c478bd9Sstevel@tonic-gate * component of the message 2117c478bd9Sstevel@tonic-gate * txtarg Arguments to be inserted into the "text" 2127c478bd9Sstevel@tonic-gate * string using vsprintf() 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * Returns: Void 2157c478bd9Sstevel@tonic-gate */ 21620d7339fSgww /*PRINTFLIKE4*/ 2177c478bd9Sstevel@tonic-gate static void 2187c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...) 2197c478bd9Sstevel@tonic-gate { 2207c478bd9Sstevel@tonic-gate int errorflg; /* TRUE if problem generating message */ 2217c478bd9Sstevel@tonic-gate va_list argp; /* Pointer into vararg list */ 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* No problems yet */ 2257c478bd9Sstevel@tonic-gate errorflg = FALSE; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* Generate the error message */ 2287c478bd9Sstevel@tonic-gate va_start(argp, text); 22920d7339fSgww if (text != MM_NULLTXT) { 23020d7339fSgww errorflg = vsnprintf(msgbuf, 23120d7339fSgww MM_MXTXTLN, text, argp) > MM_MXTXTLN; 23220d7339fSgww } 2337c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, severity, 23420d7339fSgww (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf, action, tag); 2357c478bd9Sstevel@tonic-gate va_end(argp); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * If there was a buffer overflow generating the error message, 2397c478bd9Sstevel@tonic-gate * write a message and quit (things are probably corrupt in the 2407c478bd9Sstevel@tonic-gate * static data space now 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate if (errorflg) { 2437c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING, 2447c478bd9Sstevel@tonic-gate gettext("Internal message buffer overflow"), 2457c478bd9Sstevel@tonic-gate MM_NULLACT, MM_NULLTAG); 2467c478bd9Sstevel@tonic-gate exit(100); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate } 24920d7339fSgww 2507c478bd9Sstevel@tonic-gate /* 2517c478bd9Sstevel@tonic-gate * These functions control the group membership list, as found in 2527c478bd9Sstevel@tonic-gate * the /etc/group file. 2537c478bd9Sstevel@tonic-gate * 2547c478bd9Sstevel@tonic-gate * Functions included: 2557c478bd9Sstevel@tonic-gate * addmember Adds a member to the membership list 2567c478bd9Sstevel@tonic-gate * isamember Looks for a particular login-ID in the 2577c478bd9Sstevel@tonic-gate * list of members 2587c478bd9Sstevel@tonic-gate * 2597c478bd9Sstevel@tonic-gate * Datatype Definitions: 2607c478bd9Sstevel@tonic-gate * struct grpmember Describes a group member 2617c478bd9Sstevel@tonic-gate * 2627c478bd9Sstevel@tonic-gate * Static Data: 2637c478bd9Sstevel@tonic-gate * membershead Pointer to the head of the list of 2647c478bd9Sstevel@tonic-gate * group members 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate struct grpmember { 2687c478bd9Sstevel@tonic-gate char *membername; 2697c478bd9Sstevel@tonic-gate struct grpmember *next; 2707c478bd9Sstevel@tonic-gate }; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate static struct grpmember *membershead; 27320d7339fSgww 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * void addmember(p) 2767c478bd9Sstevel@tonic-gate * char *p 2777c478bd9Sstevel@tonic-gate * 2787c478bd9Sstevel@tonic-gate * This function adds a member to the group member's list. The 2797c478bd9Sstevel@tonic-gate * group members list is a list of structures containing a pointer 2807c478bd9Sstevel@tonic-gate * to the member-name and a pointer to the next item in the 2817c478bd9Sstevel@tonic-gate * structure. The structure is not ordered in any particular way. 2827c478bd9Sstevel@tonic-gate * 2837c478bd9Sstevel@tonic-gate * Arguments: 2847c478bd9Sstevel@tonic-gate * p Pointer to the member name 2857c478bd9Sstevel@tonic-gate * 2867c478bd9Sstevel@tonic-gate * Returns: Void 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate static void 29020d7339fSgww addmember(char *p) 2917c478bd9Sstevel@tonic-gate { 2927c478bd9Sstevel@tonic-gate struct grpmember *new; /* Member being added */ 2937c478bd9Sstevel@tonic-gate 294*b816ddf8Sgww new = malloc(sizeof (struct grpmember)); 295*b816ddf8Sgww new->membername = strdup(p); 2967c478bd9Sstevel@tonic-gate new->next = membershead; 2977c478bd9Sstevel@tonic-gate membershead = new; 2987c478bd9Sstevel@tonic-gate } 29920d7339fSgww 30020d7339fSgww 3017c478bd9Sstevel@tonic-gate /* 3027c478bd9Sstevel@tonic-gate * init isamember(p) 3037c478bd9Sstevel@tonic-gate * char *p 3047c478bd9Sstevel@tonic-gate * 3057c478bd9Sstevel@tonic-gate * This function examines the list of group-members for the string 3067c478bd9Sstevel@tonic-gate * referenced by 'p'. If 'p' is a member of the members list, the 3077c478bd9Sstevel@tonic-gate * function returns TRUE. Otherwise it returns FALSE. 3087c478bd9Sstevel@tonic-gate * 3097c478bd9Sstevel@tonic-gate * Arguments: 3107c478bd9Sstevel@tonic-gate * p Pointer to the name to search for. 3117c478bd9Sstevel@tonic-gate * 3127c478bd9Sstevel@tonic-gate * Returns: int 3137c478bd9Sstevel@tonic-gate * TRUE If 'p' is found in the members list, 3147c478bd9Sstevel@tonic-gate * FALSE otherwise 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate static int 31820d7339fSgww isamember(char *p) 3197c478bd9Sstevel@tonic-gate { 3207c478bd9Sstevel@tonic-gate int found; /* TRUE if login found in list */ 3217c478bd9Sstevel@tonic-gate struct grpmember *pmem; /* Group member being examined */ 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate /* Search the membership list for 'p' */ 3257c478bd9Sstevel@tonic-gate found = FALSE; 3267c478bd9Sstevel@tonic-gate for (pmem = membershead; !found && pmem; pmem = pmem->next) { 32720d7339fSgww if (strcmp(p, pmem->membername) == 0) 32820d7339fSgww found = TRUE; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate return (found); 3327c478bd9Sstevel@tonic-gate } 33320d7339fSgww 33420d7339fSgww 3357c478bd9Sstevel@tonic-gate /* 3367c478bd9Sstevel@tonic-gate * These functions handle the display list. The display list contains 3377c478bd9Sstevel@tonic-gate * all of the information we're to display. The list contains a pointer 3387c478bd9Sstevel@tonic-gate * to the login-name, a pointer to the free-field (comment), and a 3397c478bd9Sstevel@tonic-gate * pointer to the next item in the list. The list is ordered alpha- 3407c478bd9Sstevel@tonic-gate * betically (ascending) on the login-name field. The list initially 3417c478bd9Sstevel@tonic-gate * contains a dummy field (to make insertion easier) that contains a 3427c478bd9Sstevel@tonic-gate * login-name of "". 3437c478bd9Sstevel@tonic-gate * 3447c478bd9Sstevel@tonic-gate * Functions included: 3457c478bd9Sstevel@tonic-gate * initdisp Initializes the display list 3467c478bd9Sstevel@tonic-gate * adddisp Adds information to the display list 3477c478bd9Sstevel@tonic-gate * isuidindisp Looks to see if a particular user-ID is in the 3487c478bd9Sstevel@tonic-gate * display list 3497c478bd9Sstevel@tonic-gate * genreport Generates a report from the items in the display 3507c478bd9Sstevel@tonic-gate * list 3517c478bd9Sstevel@tonic-gate * applygroup Add group information to the items in the display 3527c478bd9Sstevel@tonic-gate * list 3537c478bd9Sstevel@tonic-gate * applypasswd Add extended password information to the items 3547c478bd9Sstevel@tonic-gate * in the display list 3557c478bd9Sstevel@tonic-gate * 3567c478bd9Sstevel@tonic-gate * Datatypes Defined: 3577c478bd9Sstevel@tonic-gate * struct display Describes the structure that contains the information 3587c478bd9Sstevel@tonic-gate * to be displayed. Includes pointers to the login-ID, 3597c478bd9Sstevel@tonic-gate * free-field (comment), and the next structure in the 3607c478bd9Sstevel@tonic-gate * list. 3617c478bd9Sstevel@tonic-gate * 3627c478bd9Sstevel@tonic-gate * Static Data: 3637c478bd9Sstevel@tonic-gate * displayhead Pointer to the head of the display list. Initially 3647c478bd9Sstevel@tonic-gate * references the null-item on the head of the list. 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate struct display { 3687c478bd9Sstevel@tonic-gate char *loginID; /* Login name */ 3697c478bd9Sstevel@tonic-gate char *freefield; /* Free (comment) field */ 3707c478bd9Sstevel@tonic-gate char *groupname; /* Name of the primary group */ 3717c478bd9Sstevel@tonic-gate char *iwd; /* Initial working directory */ 3727c478bd9Sstevel@tonic-gate char *shell; /* Shell after login (may be null) */ 3737c478bd9Sstevel@tonic-gate struct pwdinfo *passwdinfo; /* Password information structure */ 3747c478bd9Sstevel@tonic-gate struct secgrp *secgrplist; /* Head of the secondary group list */ 3757c478bd9Sstevel@tonic-gate uid_t userID; /* User ID */ 3767c478bd9Sstevel@tonic-gate gid_t groupID; /* Group ID of primary group */ 3777c478bd9Sstevel@tonic-gate struct display *nextlogin; /* Next login in the list */ 3787c478bd9Sstevel@tonic-gate struct display *nextuid; /* Next user-ID in the list */ 3797c478bd9Sstevel@tonic-gate }; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate static struct display *displayhead; 38220d7339fSgww 38320d7339fSgww 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * void initdisp() 3867c478bd9Sstevel@tonic-gate * 3877c478bd9Sstevel@tonic-gate * Initializes the display list. An empty display list contains 3887c478bd9Sstevel@tonic-gate * a single element, the dummy element. 3897c478bd9Sstevel@tonic-gate * 3907c478bd9Sstevel@tonic-gate * Arguments: None 3917c478bd9Sstevel@tonic-gate * 3927c478bd9Sstevel@tonic-gate * Returns: Void 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate static void 39620d7339fSgww initdisp(void) 3977c478bd9Sstevel@tonic-gate { 398*b816ddf8Sgww displayhead = malloc(sizeof (struct display)); 39920d7339fSgww displayhead->nextlogin = NULL; 40020d7339fSgww displayhead->nextuid = NULL; 4017c478bd9Sstevel@tonic-gate displayhead->loginID = ""; 4027c478bd9Sstevel@tonic-gate displayhead->freefield = ""; 4037c478bd9Sstevel@tonic-gate displayhead->userID = -1; 4047c478bd9Sstevel@tonic-gate } 40520d7339fSgww 40620d7339fSgww 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * void adddisp(pwent) 4097c478bd9Sstevel@tonic-gate * struct passwd *pwent 4107c478bd9Sstevel@tonic-gate * 4117c478bd9Sstevel@tonic-gate * This function adds the appropriate information from the login 4127c478bd9Sstevel@tonic-gate * description referenced by 'pwent' to the list if information 4137c478bd9Sstevel@tonic-gate * to be displayed. It only adds the information if the login-ID 4147c478bd9Sstevel@tonic-gate * (user-name) is unique. It inserts the information in the list 4157c478bd9Sstevel@tonic-gate * in such a way that the list remains ordered alphabetically 4167c478bd9Sstevel@tonic-gate * (ascending) according to the login-ID (user-name). 4177c478bd9Sstevel@tonic-gate * 4187c478bd9Sstevel@tonic-gate * Arguments: 4197c478bd9Sstevel@tonic-gate * pwent Structure that contains all of the login information 4207c478bd9Sstevel@tonic-gate * of the login being added to the list. The only 4217c478bd9Sstevel@tonic-gate * information that this function uses is the login-ID 4227c478bd9Sstevel@tonic-gate * (user-name) and the free-field (comment field). 4237c478bd9Sstevel@tonic-gate * 4247c478bd9Sstevel@tonic-gate * Returns: Void 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate static void 42820d7339fSgww adddisp(struct passwd *pwent) 4297c478bd9Sstevel@tonic-gate { 4307c478bd9Sstevel@tonic-gate struct display *new; /* Item being added to the list */ 4317c478bd9Sstevel@tonic-gate struct display *prev; /* Previous item in the list */ 4327c478bd9Sstevel@tonic-gate struct display *current; /* Next item in the list */ 4337c478bd9Sstevel@tonic-gate int found; /* FLAG, insertion point found */ 4347c478bd9Sstevel@tonic-gate int compare = 1; /* strcmp() compare value */ 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* Find where this value belongs in the list */ 4387c478bd9Sstevel@tonic-gate prev = displayhead; 4397c478bd9Sstevel@tonic-gate found = FALSE; 44020d7339fSgww while (!found && (current = prev->nextlogin)) { 44120d7339fSgww if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) { 44220d7339fSgww found = TRUE; 44320d7339fSgww } else { 44420d7339fSgww prev = current; 44520d7339fSgww } 4467c478bd9Sstevel@tonic-gate 44720d7339fSgww } 4487c478bd9Sstevel@tonic-gate /* Insert this value in the list, only if it is unique though */ 4497c478bd9Sstevel@tonic-gate if (compare != 0) { 450*b816ddf8Sgww new = malloc(sizeof (struct display)); 451*b816ddf8Sgww new->loginID = strdup(pwent->pw_name); 45220d7339fSgww if (pwent->pw_comment && pwent->pw_comment[0] != '\0') { 453*b816ddf8Sgww new->freefield = strdup(pwent->pw_comment); 45420d7339fSgww } else { 455*b816ddf8Sgww new->freefield = strdup(pwent->pw_gecos); 45620d7339fSgww } 45720d7339fSgww if (!pwent->pw_shell || !(*pwent->pw_shell)) { 45820d7339fSgww new->shell = "/sbin/sh"; 45920d7339fSgww } else { 460*b816ddf8Sgww new->shell = strdup(pwent->pw_shell); 46120d7339fSgww } 462*b816ddf8Sgww new->iwd = strdup(pwent->pw_dir); 4637c478bd9Sstevel@tonic-gate new->userID = pwent->pw_uid; 4647c478bd9Sstevel@tonic-gate new->groupID = pwent->pw_gid; 46520d7339fSgww new->secgrplist = NULL; 46620d7339fSgww new->passwdinfo = NULL; 46720d7339fSgww new->groupname = NULL; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* Add new display item to the list ordered by login-ID */ 4707c478bd9Sstevel@tonic-gate new->nextlogin = current; 4717c478bd9Sstevel@tonic-gate prev->nextlogin = new; 4727c478bd9Sstevel@tonic-gate 47320d7339fSgww /* 47420d7339fSgww * Find the appropriate place for the new item in the list 47520d7339fSgww * ordered by userID 47620d7339fSgww */ 4777c478bd9Sstevel@tonic-gate prev = displayhead; 4787c478bd9Sstevel@tonic-gate found = FALSE; 47920d7339fSgww while (!found && (current = prev->nextuid)) { 48020d7339fSgww if (current->userID > pwent->pw_uid) { 48120d7339fSgww found = TRUE; 48220d7339fSgww } else { 48320d7339fSgww prev = current; 48420d7339fSgww } 48520d7339fSgww } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate /* Add the item into the list that is ordered by user-ID */ 4887c478bd9Sstevel@tonic-gate new->nextuid = current; 4897c478bd9Sstevel@tonic-gate prev->nextuid = new; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate } 49220d7339fSgww 49320d7339fSgww 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * int isuidindisp(pwent) 4967c478bd9Sstevel@tonic-gate * struct passwd *pwent 4977c478bd9Sstevel@tonic-gate * 4987c478bd9Sstevel@tonic-gate * This function examines the display list to see if the uid in 4997c478bd9Sstevel@tonic-gate * the (struct passwd) referenced by "pwent" is already in the 5007c478bd9Sstevel@tonic-gate * display list. It returns TRUE if it is in the list, FALSE 5017c478bd9Sstevel@tonic-gate * otherwise. 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate * Since the display list is ordered by user-ID, the search continues 5047c478bd9Sstevel@tonic-gate * until a match is found or a user-ID is found that is larger than 5057c478bd9Sstevel@tonic-gate * the one we're searching for. 5067c478bd9Sstevel@tonic-gate * 5077c478bd9Sstevel@tonic-gate * Arguments: 5087c478bd9Sstevel@tonic-gate * pwent Structure that contains the user-ID we're to 5097c478bd9Sstevel@tonic-gate * look for 5107c478bd9Sstevel@tonic-gate * 5117c478bd9Sstevel@tonic-gate * Returns: int 5127c478bd9Sstevel@tonic-gate * TRUE if the user-ID was found, FALSE otherwise. 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate static int 51620d7339fSgww isuidindisp(struct passwd *pwent) 5177c478bd9Sstevel@tonic-gate { 5187c478bd9Sstevel@tonic-gate struct display *dp; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* 5227c478bd9Sstevel@tonic-gate * Search the list, beginning at the beginning (where else?) 5237c478bd9Sstevel@tonic-gate * and stopping when the user-ID is found or one is found that 5247c478bd9Sstevel@tonic-gate * is greater than the user-ID we're searching for. Recall 5257c478bd9Sstevel@tonic-gate * that this list is ordered by user-ID 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate 52820d7339fSgww for (dp = displayhead->nextuid; dp && (dp->userID < pwent->pw_uid); 52920d7339fSgww dp = dp->nextuid) { 53020d7339fSgww continue; 53120d7339fSgww } 5327c478bd9Sstevel@tonic-gate 53320d7339fSgww /* 53420d7339fSgww * If the pointer "dp" points to a structure that has a 53520d7339fSgww * matching user-ID, return TRUE. Otherwise FALSE 53620d7339fSgww */ 5377c478bd9Sstevel@tonic-gate return (dp && (dp->userID == pwent->pw_uid)); 5387c478bd9Sstevel@tonic-gate } 53920d7339fSgww 54020d7339fSgww 5417c478bd9Sstevel@tonic-gate /* 5427c478bd9Sstevel@tonic-gate * void applygroup(allgroups) 5437c478bd9Sstevel@tonic-gate * int allgroups 5447c478bd9Sstevel@tonic-gate * 5457c478bd9Sstevel@tonic-gate * This function applies group information to the login-IDs in the 5467c478bd9Sstevel@tonic-gate * display list. It always applies the primary group information. 5477c478bd9Sstevel@tonic-gate * If "allgroups" is TRUE, it applies secondary information as well. 5487c478bd9Sstevel@tonic-gate * 5497c478bd9Sstevel@tonic-gate * Arguments: 5507c478bd9Sstevel@tonic-gate * allgroups FLAG. TRUE if secondary group info is to be 5517c478bd9Sstevel@tonic-gate * applied -- FALSE otherwise. 5527c478bd9Sstevel@tonic-gate * 5537c478bd9Sstevel@tonic-gate * Returns: void 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate static void 55720d7339fSgww applygroup(int allgroups) 5587c478bd9Sstevel@tonic-gate { 5597c478bd9Sstevel@tonic-gate struct display *dp; /* Display list running ptr */ 5607c478bd9Sstevel@tonic-gate struct group *grent; /* Group info, from getgrent() */ 5617c478bd9Sstevel@tonic-gate char *p; /* Temp char pointer */ 5627c478bd9Sstevel@tonic-gate char **pp; /* Temp char * pointer */ 5637c478bd9Sstevel@tonic-gate int compare; /* Value from strcmp() */ 5647c478bd9Sstevel@tonic-gate int done; /* TRUE if finished, FALSE otherwise */ 5657c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Block allocated for this info */ 5667c478bd9Sstevel@tonic-gate struct secgrp *psrch; /* Secondary group -- for searching */ 5677c478bd9Sstevel@tonic-gate 568*b816ddf8Sgww if (!allgroups) { 569*b816ddf8Sgww /* short circute getting all the groups */ 570*b816ddf8Sgww for (dp = displayhead->nextuid; dp; dp = dp->nextuid) { 571*b816ddf8Sgww if ((grent = getgrgid(dp->groupID)) != NULL) { 572*b816ddf8Sgww dp->groupname = strdup(grent->gr_name); 573*b816ddf8Sgww } 574*b816ddf8Sgww } 575*b816ddf8Sgww return; 576*b816ddf8Sgww } 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate /* For each group-ID in the /etc/group file ... */ 5797c478bd9Sstevel@tonic-gate while (grent = getgrent()) { 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Set the primary group for the login-IDs in the display 5827c478bd9Sstevel@tonic-gate * list. For each group-ID we get, leaf through the display 5837c478bd9Sstevel@tonic-gate * list and set the group-name if the group-IDs match 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate 58620d7339fSgww p = NULL; 58720d7339fSgww for (dp = displayhead->nextuid; dp; dp = dp->nextuid) { 5887c478bd9Sstevel@tonic-gate if ((dp->groupID == grent->gr_gid) && !dp->groupname) { 58920d7339fSgww if (!p) { 590*b816ddf8Sgww p = strdup(grent->gr_name); 59120d7339fSgww } 5927c478bd9Sstevel@tonic-gate dp->groupname = p; 5937c478bd9Sstevel@tonic-gate } 59420d7339fSgww } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * If we're to be displaying secondary group membership, 5987c478bd9Sstevel@tonic-gate * leaf through the list of group members. Then, attempt 5997c478bd9Sstevel@tonic-gate * to find that member in the display list. When found, 6007c478bd9Sstevel@tonic-gate * attach secondary group info to the user. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate 60320d7339fSgww for (pp = grent->gr_mem; *pp; pp++) { 6047c478bd9Sstevel@tonic-gate done = FALSE; 60520d7339fSgww for (dp = displayhead->nextlogin; !done && dp; 60620d7339fSgww dp = dp->nextlogin) { 60720d7339fSgww if (((compare = strcmp(dp->loginID, 60820d7339fSgww *pp)) == 0) && 60920d7339fSgww !(grent->gr_gid == dp->groupID)) { 61020d7339fSgww if (!p) { 611*b816ddf8Sgww p = strdup(grent->gr_name); 61220d7339fSgww } 613*b816ddf8Sgww psecgrp = malloc( 61420d7339fSgww sizeof (struct secgrp)); 6157c478bd9Sstevel@tonic-gate psecgrp->groupID = grent->gr_gid; 6167c478bd9Sstevel@tonic-gate psecgrp->groupname = p; 61720d7339fSgww psecgrp->next = NULL; 61820d7339fSgww if (!dp->secgrplist) { 61920d7339fSgww dp->secgrplist = psecgrp; 62020d7339fSgww } else { 62120d7339fSgww for (psrch = dp->secgrplist; 62220d7339fSgww psrch->next; 62320d7339fSgww psrch = psrch->next) { 62420d7339fSgww continue; 62520d7339fSgww } 6267c478bd9Sstevel@tonic-gate psrch->next = psecgrp; 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate done = TRUE; 62920d7339fSgww } else if (compare > 0) { 63020d7339fSgww done = TRUE; 6317c478bd9Sstevel@tonic-gate } 6327c478bd9Sstevel@tonic-gate } 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate } 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate /* Close the /etc/group file */ 6377c478bd9Sstevel@tonic-gate endgrent(); 6387c478bd9Sstevel@tonic-gate } 63920d7339fSgww 64020d7339fSgww 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * void applypasswd() 6437c478bd9Sstevel@tonic-gate * 6447c478bd9Sstevel@tonic-gate * This function applies extended password information to an item 6457c478bd9Sstevel@tonic-gate * to be displayed. It allocates space for a structure describing 6467c478bd9Sstevel@tonic-gate * the password, then fills in that structure from the information 6477c478bd9Sstevel@tonic-gate * in the /etc/shadow file. 6487c478bd9Sstevel@tonic-gate * 6497c478bd9Sstevel@tonic-gate * Arguments: None 6507c478bd9Sstevel@tonic-gate * 6517c478bd9Sstevel@tonic-gate * Returns: Void 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate 6547c478bd9Sstevel@tonic-gate static void 65520d7339fSgww applypasswd(void) 6567c478bd9Sstevel@tonic-gate { 6577c478bd9Sstevel@tonic-gate struct pwdinfo *ppasswd; /* Ptr to pwd desc in current element */ 6587c478bd9Sstevel@tonic-gate struct display *dp; /* Ptr to current element */ 6597c478bd9Sstevel@tonic-gate struct spwd *psp; /* Pointer to a shadow-file entry */ 6607c478bd9Sstevel@tonic-gate struct tm *ptm; /* Pointer to a time-of-day structure */ 6617c478bd9Sstevel@tonic-gate time_t pwchg; /* System-time of last pwd chg */ 6627c478bd9Sstevel@tonic-gate time_t pwexp; /* System-time of password expiration */ 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate /* Make sure the shadow file is rewound */ 6667c478bd9Sstevel@tonic-gate setspent(); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * For each item in the display list... 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate for (dp = displayhead->nextuid; dp; dp = dp->nextuid) { 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate /* Allocate structure space for the password description */ 676*b816ddf8Sgww ppasswd = malloc(sizeof (struct pwdinfo)); 6777c478bd9Sstevel@tonic-gate dp->passwdinfo = ppasswd; 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * If there's no entry in the /etc/shadow file, assume 6817c478bd9Sstevel@tonic-gate * that the login is locked 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate 684*b816ddf8Sgww if ((psp = getspnam(dp->loginID)) == NULL) { 6857c478bd9Sstevel@tonic-gate pwchg = 0L; /* Epoch */ 6867c478bd9Sstevel@tonic-gate ppasswd->passwdstatus = "LK"; /* LK, Locked */ 6877c478bd9Sstevel@tonic-gate ppasswd->mindaystilchg = 0L; 6887c478bd9Sstevel@tonic-gate ppasswd->maxdaystilchg = 0L; 6897c478bd9Sstevel@tonic-gate ppasswd->warninterval = 0L; 6907c478bd9Sstevel@tonic-gate ppasswd->inactive = 0L; 6917c478bd9Sstevel@tonic-gate pwexp = 0L; 69220d7339fSgww } else { 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * Otherwise, fill in the password information from the 695*b816ddf8Sgww * info in the shadow entry 6967c478bd9Sstevel@tonic-gate */ 697*b816ddf8Sgww if (psp->sp_pwdp == NULL || (*psp->sp_pwdp) == '\0') 69820d7339fSgww ppasswd->passwdstatus = "NP"; 699*b816ddf8Sgww else if (strncmp(psp->sp_pwdp, LOCKSTRING, 700*b816ddf8Sgww sizeof (LOCKSTRING)-1) == 0) 70120d7339fSgww ppasswd->passwdstatus = "LK"; 702*b816ddf8Sgww else if (strncmp(psp->sp_pwdp, NOLOGINSTRING, 703*b816ddf8Sgww sizeof (NOLOGINSTRING)-1) == 0) 704*b816ddf8Sgww ppasswd->passwdstatus = "NL"; 705*b816ddf8Sgww else if ((strlen(psp->sp_pwdp) == 13 && 706*b816ddf8Sgww psp->sp_pwdp[0] != '$') || 707*b816ddf8Sgww psp->sp_pwdp[0] == '$') 7087c478bd9Sstevel@tonic-gate ppasswd->passwdstatus = "PS"; 709*b816ddf8Sgww else 710*b816ddf8Sgww ppasswd->passwdstatus = "UN"; 7117c478bd9Sstevel@tonic-gate /* 71220d7339fSgww * Set up the last-changed date, 71320d7339fSgww * the minimum days between changes, 71420d7339fSgww * the maximum life of a password, 71520d7339fSgww * the interval before expiration that the user 71620d7339fSgww * is warned, 71720d7339fSgww * the number of days a login can be inactive before 71820d7339fSgww * it expires, and the login expiration date 7197c478bd9Sstevel@tonic-gate */ 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate pwchg = psp->sp_lstchg; 7227c478bd9Sstevel@tonic-gate ppasswd->mindaystilchg = psp->sp_min; 7237c478bd9Sstevel@tonic-gate ppasswd->maxdaystilchg = psp->sp_max; 7247c478bd9Sstevel@tonic-gate ppasswd->warninterval = psp->sp_warn; 7257c478bd9Sstevel@tonic-gate ppasswd->inactive = psp->sp_inact; 7267c478bd9Sstevel@tonic-gate pwexp = psp->sp_expire; 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * Convert the date of the last password change from days- 7317c478bd9Sstevel@tonic-gate * since-epoch to mmddyy (integer) form. Involves the 7327c478bd9Sstevel@tonic-gate * intermediate step of converting the date from days- 7337c478bd9Sstevel@tonic-gate * since-epoch to seconds-since-epoch. We'll set this to 7347c478bd9Sstevel@tonic-gate * somewhere near the middle of the day, since there are not 7357c478bd9Sstevel@tonic-gate * always 24*60*60 seconds in a year. (Yeech) 7367c478bd9Sstevel@tonic-gate * 7377c478bd9Sstevel@tonic-gate * Note: The form mmddyy should probably be subject to 7387c478bd9Sstevel@tonic-gate * internationalization -- Non-Americans will think that 7397c478bd9Sstevel@tonic-gate * 070888 is 07 August 88 when the software is trying to say 7407c478bd9Sstevel@tonic-gate * 08 July 88. Systems Engineers seem to think that this isn't 7417c478bd9Sstevel@tonic-gate * a problem though... 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate if (pwchg != -1L) { 7457c478bd9Sstevel@tonic-gate pwchg = (pwchg * DAY) + (DAY/2); 7467c478bd9Sstevel@tonic-gate ptm = localtime(&pwchg); 7477c478bd9Sstevel@tonic-gate ppasswd->datechg = ((long)(ptm->tm_mon+1) * 10000L) + 7487c478bd9Sstevel@tonic-gate (long)((ptm->tm_mday * 100) + 7497c478bd9Sstevel@tonic-gate (ptm->tm_year % 100)); 75020d7339fSgww } else { 75120d7339fSgww ppasswd->datechg = 0L; 75220d7339fSgww } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * Convert the passwd expiration date from days-since-epoch 7567c478bd9Sstevel@tonic-gate * to mmddyy (long integer) form using the same algorithm and 7577c478bd9Sstevel@tonic-gate * comments as above. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate if (pwexp != -1L) { 7617c478bd9Sstevel@tonic-gate pwexp = (pwexp * DAY) + (DAY/2); 7627c478bd9Sstevel@tonic-gate ptm = localtime(&pwexp); 7637c478bd9Sstevel@tonic-gate ppasswd->expdate = ((long)(ptm->tm_mon+1) * 10000L) + 7647c478bd9Sstevel@tonic-gate (long)((ptm->tm_mday * 100) + 7657c478bd9Sstevel@tonic-gate (ptm->tm_year % 100)); 76620d7339fSgww } else { 76720d7339fSgww ppasswd->expdate = 0L; 76820d7339fSgww } 7697c478bd9Sstevel@tonic-gate } 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* Close the shadow password file */ 7727c478bd9Sstevel@tonic-gate endspent(); 7737c478bd9Sstevel@tonic-gate } 77420d7339fSgww 77520d7339fSgww 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * int hasnopasswd(pwent) 7787c478bd9Sstevel@tonic-gate * struct passwd *pwent 7797c478bd9Sstevel@tonic-gate * 7807c478bd9Sstevel@tonic-gate * This function examines a login's password-file entry 7817c478bd9Sstevel@tonic-gate * and, if necessary, its shadow password-file entry and 7827c478bd9Sstevel@tonic-gate * returns TRUE if that user-ID has no password, meaning 7837c478bd9Sstevel@tonic-gate * that the user-ID can be used to log into the system 7847c478bd9Sstevel@tonic-gate * without giving a password. The function returns FALSE 7857c478bd9Sstevel@tonic-gate * otherwise. 7867c478bd9Sstevel@tonic-gate * 7877c478bd9Sstevel@tonic-gate * Arguments: 7887c478bd9Sstevel@tonic-gate * pwent Login to examine. 7897c478bd9Sstevel@tonic-gate * 7907c478bd9Sstevel@tonic-gate * Returns: int 7917c478bd9Sstevel@tonic-gate * TRUE if the login can be used without a password, FALSE 7927c478bd9Sstevel@tonic-gate * otherwise. 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate static int 79620d7339fSgww hasnopasswd(struct passwd *pwent) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate struct spwd *psp; /* /etc/shadow file struct */ 7997c478bd9Sstevel@tonic-gate int nopwflag; /* TRUE if login has no passwd */ 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * A login has no password if: 8037c478bd9Sstevel@tonic-gate * 1. There exists an entry for that login in the 8047c478bd9Sstevel@tonic-gate * shadow password-file (/etc/passwd), and 8057c478bd9Sstevel@tonic-gate * 2. The encrypted password in the structure describing 80620d7339fSgww * that entry is either: NULL or a null string ("") 8077c478bd9Sstevel@tonic-gate */ 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* Get the login's entry in the shadow password file */ 8107c478bd9Sstevel@tonic-gate if (psp = getspnam(pwent->pw_name)) { 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate /* Look at the encrypted password in that entry */ 8137c478bd9Sstevel@tonic-gate if (psp->sp_pwdp == (char *)0 || 81420d7339fSgww *psp->sp_pwdp == '\0') { 8157c478bd9Sstevel@tonic-gate nopwflag = TRUE; 81620d7339fSgww } else { 8177c478bd9Sstevel@tonic-gate nopwflag = FALSE; 8187c478bd9Sstevel@tonic-gate } 81920d7339fSgww } else { 8207c478bd9Sstevel@tonic-gate nopwflag = FALSE; 82120d7339fSgww } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* Done ... */ 8247c478bd9Sstevel@tonic-gate return (nopwflag); 8257c478bd9Sstevel@tonic-gate } 82620d7339fSgww 82720d7339fSgww 8287c478bd9Sstevel@tonic-gate /* 8297c478bd9Sstevel@tonic-gate * void writeunformatted(current, xtndflag, expflag) 8307c478bd9Sstevel@tonic-gate * struct display *current 8317c478bd9Sstevel@tonic-gate * int xtndflag 8327c478bd9Sstevel@tonic-gate * int expflag 8337c478bd9Sstevel@tonic-gate * 8347c478bd9Sstevel@tonic-gate * This function writes the data in the display structure "current" 8357c478bd9Sstevel@tonic-gate * to the standard output file. It writes the information in the 8367c478bd9Sstevel@tonic-gate * form of a colon-list. It writes secondary group information if 8377c478bd9Sstevel@tonic-gate * that information is in the structure, it writes extended 8387c478bd9Sstevel@tonic-gate * (initial working directory, shell, and password-aging) info 8397c478bd9Sstevel@tonic-gate * if the "xtndflag" is TRUE, and it writes password expiration 8407c478bd9Sstevel@tonic-gate * information if "expflag" is TRUE. 8417c478bd9Sstevel@tonic-gate * 8427c478bd9Sstevel@tonic-gate * Arguments: 8437c478bd9Sstevel@tonic-gate * current Structure containing information to write. 8447c478bd9Sstevel@tonic-gate * xtndflag TRUE if extended information is to be written, 8457c478bd9Sstevel@tonic-gate * FALSE otherwise 8467c478bd9Sstevel@tonic-gate * expflag TRUE if password expiration information is to 8477c478bd9Sstevel@tonic-gate * be written, FALSE otherwise 8487c478bd9Sstevel@tonic-gate * 8497c478bd9Sstevel@tonic-gate * Returns: void 8507c478bd9Sstevel@tonic-gate */ 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate static void 85320d7339fSgww writeunformatted(struct display *current, int xtndflag, int expflag) 8547c478bd9Sstevel@tonic-gate { 8557c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Secondary group info */ 8567c478bd9Sstevel@tonic-gate struct pwdinfo *pwdinfo; /* Password aging info */ 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate /* Write the general information */ 8597c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%s:%ld:%s:%ld:%s", 8607c478bd9Sstevel@tonic-gate current->loginID, 8617c478bd9Sstevel@tonic-gate current->userID, 86220d7339fSgww current->groupname == NULL ? "" : current->groupname, 8637c478bd9Sstevel@tonic-gate current->groupID, 8647c478bd9Sstevel@tonic-gate current->freefield); 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * If the group information is there, write it (it's only 8687c478bd9Sstevel@tonic-gate * there if it's supposed to be written) 8697c478bd9Sstevel@tonic-gate */ 87020d7339fSgww for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) { 87120d7339fSgww (void) fprintf(stdout, ":%s:%ld", 87220d7339fSgww psecgrp->groupname, psecgrp->groupID); 87320d7339fSgww } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* If the extended info flag is TRUE, write the extended information */ 8767c478bd9Sstevel@tonic-gate if (xtndflag) { 8777c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo; 8787c478bd9Sstevel@tonic-gate (void) fprintf(stdout, ":%s:%s:%s:%6.6ld:%ld:%ld:%ld", 8797c478bd9Sstevel@tonic-gate current->iwd, current->shell, 8807c478bd9Sstevel@tonic-gate pwdinfo->passwdstatus, 8817c478bd9Sstevel@tonic-gate pwdinfo->datechg, 8827c478bd9Sstevel@tonic-gate pwdinfo->mindaystilchg, pwdinfo->maxdaystilchg, 8837c478bd9Sstevel@tonic-gate pwdinfo->warninterval); 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* If the password expiration information is requested, write it. */ 8877c478bd9Sstevel@tonic-gate if (expflag) { 8887c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo; 88920d7339fSgww (void) fprintf(stdout, ":%ld:%ld", 89020d7339fSgww pwdinfo->inactive, pwdinfo->expdate); 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* Terminate the information with a new-line */ 8947c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 8957c478bd9Sstevel@tonic-gate } 89620d7339fSgww 89720d7339fSgww 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * void writeformatted(current, xtndflag, expflag) 9007c478bd9Sstevel@tonic-gate * struct display *current 9017c478bd9Sstevel@tonic-gate * int xtndflag 9027c478bd9Sstevel@tonic-gate * int expflag 9037c478bd9Sstevel@tonic-gate * 9047c478bd9Sstevel@tonic-gate * This function writes the data in the display structure "current" 9057c478bd9Sstevel@tonic-gate * to the standard output file. It writes the information in an 9067c478bd9Sstevel@tonic-gate * easily readable format. It writes secondary group information 9077c478bd9Sstevel@tonic-gate * if that information is in the structure, it writes extended 9087c478bd9Sstevel@tonic-gate * (initial working directory, shell, and password-aging) info if 9097c478bd9Sstevel@tonic-gate * "xtndflag" is TRUE, and it write password expiration information 9107c478bd9Sstevel@tonic-gate * if "expflag" is TRUE. 9117c478bd9Sstevel@tonic-gate * 9127c478bd9Sstevel@tonic-gate * Arguments: 9137c478bd9Sstevel@tonic-gate * current Structure containing info to write. 91420d7339fSgww * xtndflag TRUE if extended information to be written, 9157c478bd9Sstevel@tonic-gate * FALSE otherwise 91620d7339fSgww * expflag TRUE if password expiration information to be written, 9177c478bd9Sstevel@tonic-gate * FALSE otherwise 9187c478bd9Sstevel@tonic-gate * 9197c478bd9Sstevel@tonic-gate * Returns: void 9207c478bd9Sstevel@tonic-gate */ 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate static void 92320d7339fSgww writeformatted(struct display *current, int xtndflag, int expflag) 9247c478bd9Sstevel@tonic-gate { 9257c478bd9Sstevel@tonic-gate struct secgrp *psecgrp; /* Secondary group info */ 9267c478bd9Sstevel@tonic-gate struct pwdinfo *pwdinfo; /* Password aging info */ 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate /* Write general information */ 9297c478bd9Sstevel@tonic-gate (void) fprintf(stdout, "%-14s %-6ld %-14s %-6ld %s\n", 9307c478bd9Sstevel@tonic-gate current->loginID, current->userID, 93120d7339fSgww current->groupname == NULL ? "" : current->groupname, 9327c478bd9Sstevel@tonic-gate current->groupID, current->freefield); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * Write information about secondary groups if the info exists 9367c478bd9Sstevel@tonic-gate * (it only exists if it is to be written) 9377c478bd9Sstevel@tonic-gate */ 93820d7339fSgww for (psecgrp = current->secgrplist; psecgrp; psecgrp = psecgrp->next) { 9397c478bd9Sstevel@tonic-gate (void) fprintf(stdout, " %-14s %-6ld\n", 9407c478bd9Sstevel@tonic-gate psecgrp->groupname, psecgrp->groupID); 94120d7339fSgww } 9427c478bd9Sstevel@tonic-gate 94320d7339fSgww /* 94420d7339fSgww * If the extended information flag is TRUE, 94520d7339fSgww * write the extended information 94620d7339fSgww */ 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate if (xtndflag) { 9497c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo; 95020d7339fSgww (void) fprintf(stdout, " %s\n", 95120d7339fSgww current->iwd); 95220d7339fSgww (void) fprintf(stdout, " %s\n", 95320d7339fSgww current->shell); 95420d7339fSgww (void) fprintf(stdout, " %s " 95520d7339fSgww "%6.6ld %ld %ld %ld\n", 9567c478bd9Sstevel@tonic-gate pwdinfo->passwdstatus, 9577c478bd9Sstevel@tonic-gate pwdinfo->datechg, pwdinfo->mindaystilchg, 9587c478bd9Sstevel@tonic-gate pwdinfo->maxdaystilchg, 9597c478bd9Sstevel@tonic-gate pwdinfo->warninterval); 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate 96220d7339fSgww /* 96320d7339fSgww * If the password expiration info flag is TRUE, 96420d7339fSgww * write that information 96520d7339fSgww */ 9667c478bd9Sstevel@tonic-gate if (expflag) { 9677c478bd9Sstevel@tonic-gate pwdinfo = current->passwdinfo; 9687c478bd9Sstevel@tonic-gate (void) fprintf(stdout, " %ld %6.6ld\n", 9697c478bd9Sstevel@tonic-gate pwdinfo->inactive, pwdinfo->expdate); 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate } 97220d7339fSgww 97320d7339fSgww 9747c478bd9Sstevel@tonic-gate /* 9757c478bd9Sstevel@tonic-gate * void genuidreport(pipeflag, xtndflag, expflag) 9767c478bd9Sstevel@tonic-gate * int pipeflag 9777c478bd9Sstevel@tonic-gate * int xtndflag 9787c478bd9Sstevel@tonic-gate * int expflag 9797c478bd9Sstevel@tonic-gate * 9807c478bd9Sstevel@tonic-gate * This function generates a report on the standard output 9817c478bd9Sstevel@tonic-gate * stream (stdout) containing the login-IDs in the list of 9827c478bd9Sstevel@tonic-gate * logins built by this command. The list is ordered based 9837c478bd9Sstevel@tonic-gate * on user-ID. If the <pipeflag> variable is not zero, it 9847c478bd9Sstevel@tonic-gate * will generate a report containing parsable records. 9857c478bd9Sstevel@tonic-gate * Otherwise, it will generate a columnarized report. If 9867c478bd9Sstevel@tonic-gate * the <xtndflag> variable is not zero, it will include the 9877c478bd9Sstevel@tonic-gate * extended set of information (password aging info, home 9887c478bd9Sstevel@tonic-gate * directory, shell process, etc.). If <expflag> is not 9897c478bd9Sstevel@tonic-gate * zero, it will display password expiration information. 9907c478bd9Sstevel@tonic-gate * 9917c478bd9Sstevel@tonic-gate * Arguments: 9927c478bd9Sstevel@tonic-gate * pipeflag int 9937c478bd9Sstevel@tonic-gate * TRUE if a parsable report is needed, 9947c478bd9Sstevel@tonic-gate * FALSE if a columnar report is needed 9957c478bd9Sstevel@tonic-gate * xtndflag int 9967c478bd9Sstevel@tonic-gate * TRUE if extended set of info is to be displayed, 9977c478bd9Sstevel@tonic-gate * FALSE otherwise 9987c478bd9Sstevel@tonic-gate * expflag int 9997c478bd9Sstevel@tonic-gate * TRUE if password expiration information is to be 10007c478bd9Sstevel@tonic-gate * displayed, FALSE otherwise 10017c478bd9Sstevel@tonic-gate * 10027c478bd9Sstevel@tonic-gate * Returns: void 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate static void 100620d7339fSgww genuidreport(int pipeflag, int xtndflag, int expflag) 10077c478bd9Sstevel@tonic-gate { 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate struct display *current; /* Data being displayed */ 10107c478bd9Sstevel@tonic-gate 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate /* 10137c478bd9Sstevel@tonic-gate * Initialization for loop. 101420d7339fSgww * (NOTE: The first element in the list of logins to display is 101520d7339fSgww * a dummy element.) 10167c478bd9Sstevel@tonic-gate */ 10177c478bd9Sstevel@tonic-gate current = displayhead; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * Display elements in the list 10217c478bd9Sstevel@tonic-gate */ 102220d7339fSgww if (pipeflag) { 102320d7339fSgww for (current = displayhead->nextuid; current; 102420d7339fSgww current = current->nextuid) { 10257c478bd9Sstevel@tonic-gate writeunformatted(current, xtndflag, expflag); 102620d7339fSgww } 102720d7339fSgww } else { 102820d7339fSgww for (current = displayhead->nextuid; current; 102920d7339fSgww current = current->nextuid) { 10307c478bd9Sstevel@tonic-gate writeformatted(current, xtndflag, expflag); 10317c478bd9Sstevel@tonic-gate } 103220d7339fSgww } 103320d7339fSgww } 103420d7339fSgww 103520d7339fSgww 10367c478bd9Sstevel@tonic-gate /* 10377c478bd9Sstevel@tonic-gate * void genlogreport(pipeflag, xtndflag, expflag) 10387c478bd9Sstevel@tonic-gate * int pipeflag 10397c478bd9Sstevel@tonic-gate * int xtndflag 10407c478bd9Sstevel@tonic-gate * int expflag 10417c478bd9Sstevel@tonic-gate * 10427c478bd9Sstevel@tonic-gate * This function generates a report on the standard output 10437c478bd9Sstevel@tonic-gate * stream (stdout) containing the login-IDs in the list of 10447c478bd9Sstevel@tonic-gate * logins built by this command. The list is ordered based 10457c478bd9Sstevel@tonic-gate * on user name. If the <pipeflag> variable is not zero, it 10467c478bd9Sstevel@tonic-gate * will generate a report containing parsable records. 10477c478bd9Sstevel@tonic-gate * Otherwise, it will generate a columnarized report. If 10487c478bd9Sstevel@tonic-gate * the <xtndflag> variable is not zero, it will include the 10497c478bd9Sstevel@tonic-gate * extended set of information (password aging info, home 10507c478bd9Sstevel@tonic-gate * directory, shell process, etc.). If <expflag> is not 10517c478bd9Sstevel@tonic-gate * zero, it will include password expiration information. 10527c478bd9Sstevel@tonic-gate * 10537c478bd9Sstevel@tonic-gate * Arguments: 10547c478bd9Sstevel@tonic-gate * pipeflag int 10557c478bd9Sstevel@tonic-gate * TRUE if a parsable report is needed, 10567c478bd9Sstevel@tonic-gate * FALSE if a columnar report is needed 10577c478bd9Sstevel@tonic-gate * xtndflag int 10587c478bd9Sstevel@tonic-gate * TRUE if extended set of info is to be displayed, 10597c478bd9Sstevel@tonic-gate * FALSE otherwise 10607c478bd9Sstevel@tonic-gate * expflag int 10617c478bd9Sstevel@tonic-gate * TRUE if password expiration information is to 10627c478bd9Sstevel@tonic-gate * be displayed, FALSE otherwise 10637c478bd9Sstevel@tonic-gate * 10647c478bd9Sstevel@tonic-gate * Returns: void 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate static void 106820d7339fSgww genlogreport(int pipeflag, int xtndflag, int expflag) 10697c478bd9Sstevel@tonic-gate { 10707c478bd9Sstevel@tonic-gate struct display *p; /* Value being displayed */ 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * Initialization for loop. 107520d7339fSgww * (NOTE: The first element in the list of logins to display is 107620d7339fSgww * a dummy element.) 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate p = displayhead; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* 10817c478bd9Sstevel@tonic-gate * Display elements in the list 10827c478bd9Sstevel@tonic-gate */ 108320d7339fSgww if (pipeflag) { 108420d7339fSgww for (p = displayhead->nextlogin; p; p = p->nextlogin) { 10857c478bd9Sstevel@tonic-gate writeunformatted(p, xtndflag, expflag); 108620d7339fSgww } 108720d7339fSgww } else { 108820d7339fSgww for (p = displayhead->nextlogin; p; p = p->nextlogin) { 10897c478bd9Sstevel@tonic-gate writeformatted(p, xtndflag, expflag); 10907c478bd9Sstevel@tonic-gate } 109120d7339fSgww } 109220d7339fSgww } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate struct localpw { 10957c478bd9Sstevel@tonic-gate struct localpw *next; 10967c478bd9Sstevel@tonic-gate struct passwd pw; 10977c478bd9Sstevel@tonic-gate }; 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate struct localpw *pwtable = NULL; 11007c478bd9Sstevel@tonic-gate 110120d7339fSgww /* Local passwd pointer for getpwent() -- -1 means not in use, NULL for EOF */ 110220d7339fSgww struct localpw *pwptr; 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate int in_localgetpwent = 0; /* Set if in local_getpwent */ 11057c478bd9Sstevel@tonic-gate 1106*b816ddf8Sgww static struct localpw * 1107*b816ddf8Sgww fill_localpw(struct localpw *lpw, struct passwd *pw) { 1108*b816ddf8Sgww struct localpw *cur; 1109*b816ddf8Sgww 1110*b816ddf8Sgww /* 1111*b816ddf8Sgww * Copy the data -- we have to alloc areas for it all 1112*b816ddf8Sgww */ 1113*b816ddf8Sgww lpw->pw.pw_name = strdup(pw->pw_name); 1114*b816ddf8Sgww lpw->pw.pw_passwd = strdup(pw->pw_passwd); 1115*b816ddf8Sgww lpw->pw.pw_uid = pw->pw_uid; 1116*b816ddf8Sgww lpw->pw.pw_gid = pw->pw_gid; 1117*b816ddf8Sgww lpw->pw.pw_age = strdup(pw->pw_age); 1118*b816ddf8Sgww lpw->pw.pw_comment = strdup(pw->pw_comment); 1119*b816ddf8Sgww lpw->pw.pw_gecos = strdup(pw->pw_gecos); 1120*b816ddf8Sgww lpw->pw.pw_dir = strdup(pw->pw_dir); 1121*b816ddf8Sgww lpw->pw.pw_shell = strdup(pw->pw_shell); 1122*b816ddf8Sgww 1123*b816ddf8Sgww cur = lpw; 1124*b816ddf8Sgww lpw->next = malloc(sizeof (struct localpw)); 1125*b816ddf8Sgww return (cur); 1126*b816ddf8Sgww } 1127*b816ddf8Sgww 11287c478bd9Sstevel@tonic-gate void 1129*b816ddf8Sgww build_localpw(struct reqlogin *req_head) 11307c478bd9Sstevel@tonic-gate { 11317c478bd9Sstevel@tonic-gate struct localpw *next, *cur; 11327c478bd9Sstevel@tonic-gate struct passwd *pw; 1133*b816ddf8Sgww struct reqlogin *req_next; 11347c478bd9Sstevel@tonic-gate 1135*b816ddf8Sgww next = malloc(sizeof (struct localpw)); 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate pwtable = next; 11387c478bd9Sstevel@tonic-gate 1139*b816ddf8Sgww req_next = req_head; 1140*b816ddf8Sgww 1141*b816ddf8Sgww while (req_next != NULL) { 1142*b816ddf8Sgww if ((pw = getpwnam(req_next->loginname)) != NULL) { 1143*b816ddf8Sgww /* 1144*b816ddf8Sgww * Copy the data -- we have to alloc areas for it all 1145*b816ddf8Sgww */ 1146*b816ddf8Sgww cur = fill_localpw(next, pw); 1147*b816ddf8Sgww req_next->found = TRUE; 1148*b816ddf8Sgww next = cur->next; 1149*b816ddf8Sgww } 1150*b816ddf8Sgww 1151*b816ddf8Sgww req_next = req_next->next; 1152*b816ddf8Sgww } 1153*b816ddf8Sgww 1154*b816ddf8Sgww if (req_head == NULL) { 11557c478bd9Sstevel@tonic-gate while ((pw = getpwent()) != NULL) { 11567c478bd9Sstevel@tonic-gate /* 11577c478bd9Sstevel@tonic-gate * Copy the data -- we have to alloc areas for it all 11587c478bd9Sstevel@tonic-gate */ 1159*b816ddf8Sgww cur = fill_localpw(next, pw); 1160*b816ddf8Sgww next = cur->next; 11617c478bd9Sstevel@tonic-gate } 1162*b816ddf8Sgww } 11637c478bd9Sstevel@tonic-gate 116420d7339fSgww if (pwtable == next) { 11657c478bd9Sstevel@tonic-gate pwtable = NULL; 116620d7339fSgww } else { 1167*b816ddf8Sgww free(next); 11687c478bd9Sstevel@tonic-gate cur->next = NULL; 116920d7339fSgww } 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate endpwent(); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate struct passwd * 117520d7339fSgww local_getpwent(void) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate if (!in_localgetpwent) { 11787c478bd9Sstevel@tonic-gate in_localgetpwent = 1; 11797c478bd9Sstevel@tonic-gate pwptr = pwtable; 118020d7339fSgww } else if (pwptr != NULL) { 11817c478bd9Sstevel@tonic-gate pwptr = pwptr->next; 118220d7339fSgww } 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate if (pwptr != NULL) 118520d7339fSgww return (&(pwptr->pw)); 11867c478bd9Sstevel@tonic-gate else 118720d7339fSgww return (NULL); 11887c478bd9Sstevel@tonic-gate } 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate void 119120d7339fSgww local_endpwent(void) 11927c478bd9Sstevel@tonic-gate { 11937c478bd9Sstevel@tonic-gate in_localgetpwent = 0; 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate long 119720d7339fSgww local_pwtell(void) 11987c478bd9Sstevel@tonic-gate { 119920d7339fSgww return ((long)pwptr); 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate void 120320d7339fSgww local_pwseek(long ptr) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate pwptr = (struct localpw *)ptr; 12067c478bd9Sstevel@tonic-gate } 120720d7339fSgww 12087c478bd9Sstevel@tonic-gate /* 12097c478bd9Sstevel@tonic-gate * logins [-admopstux] [-l logins] [-g groups] 12107c478bd9Sstevel@tonic-gate * 12117c478bd9Sstevel@tonic-gate * This command generates a report of logins administered on 12127c478bd9Sstevel@tonic-gate * the system. The list will contain logins that meet criteria 12137c478bd9Sstevel@tonic-gate * described by the options in the list. If there are no options, 12147c478bd9Sstevel@tonic-gate * it will list all logins administered. It is intended to be used 12157c478bd9Sstevel@tonic-gate * only by administrators. 12167c478bd9Sstevel@tonic-gate * 12177c478bd9Sstevel@tonic-gate * Options: 12187c478bd9Sstevel@tonic-gate * -a Display password expiration information. 12197c478bd9Sstevel@tonic-gate * -d list all logins that share user-IDs with another 12207c478bd9Sstevel@tonic-gate * login. 12217c478bd9Sstevel@tonic-gate * -g groups specifies the names of the groups to which a login 12227c478bd9Sstevel@tonic-gate * must belong before it is included in the generated 12237c478bd9Sstevel@tonic-gate * list. "groups" is a comma-list of group names. 12247c478bd9Sstevel@tonic-gate * -l logins specifies the logins to display. "logins" is a 12257c478bd9Sstevel@tonic-gate * comma-list of login names. 12267c478bd9Sstevel@tonic-gate * -m in addition to the usual information, for each 12277c478bd9Sstevel@tonic-gate * login displayed, list all groups to which that 12287c478bd9Sstevel@tonic-gate * login is member. 12297c478bd9Sstevel@tonic-gate * -o generate a report as a colon-list instead of in a 12307c478bd9Sstevel@tonic-gate * columnar format 12317c478bd9Sstevel@tonic-gate * -p list all logins that have no password. 12327c478bd9Sstevel@tonic-gate * -s list all system logins 12337c478bd9Sstevel@tonic-gate * -t sort the report lexicographically by login name 12347c478bd9Sstevel@tonic-gate * instead of by user-ID 12357c478bd9Sstevel@tonic-gate * -u list all user logins 12367c478bd9Sstevel@tonic-gate * -x in addition to the usual information, display an 12377c478bd9Sstevel@tonic-gate * extended set of information that includes the home 12387c478bd9Sstevel@tonic-gate * directory, initial process, and password status and 12397c478bd9Sstevel@tonic-gate * aging information 12407c478bd9Sstevel@tonic-gate * 12417c478bd9Sstevel@tonic-gate * Exit Codes: 12427c478bd9Sstevel@tonic-gate * 0 All's well that ends well 12437c478bd9Sstevel@tonic-gate * 1 Usage error 12447c478bd9Sstevel@tonic-gate */ 12457c478bd9Sstevel@tonic-gate 124620d7339fSgww int 124720d7339fSgww main(int argc, char *argv[]) 12487c478bd9Sstevel@tonic-gate { 12497c478bd9Sstevel@tonic-gate struct passwd *plookpwd; /* Ptr to searcher pw (-d) */ 12507c478bd9Sstevel@tonic-gate struct reqgrp *reqgrphead; /* Head of the req'd group list */ 12517c478bd9Sstevel@tonic-gate struct reqgrp *pgrp; /* Current item in req'd group list */ 12527c478bd9Sstevel@tonic-gate struct reqgrp *qgrp; /* Prev item in the req'd group list */ 12537c478bd9Sstevel@tonic-gate struct reqlogin *reqloginhead; /* Head of req'd login list */ 125420d7339fSgww struct reqlogin *plogin; /* Current item in req'd login list */ 125520d7339fSgww struct reqlogin *qlogin; /* Prev item in req'd login list */ 12567c478bd9Sstevel@tonic-gate struct passwd *pwent; /* /etc/passwd entry */ 12577c478bd9Sstevel@tonic-gate struct group *grent; /* /etc/group entry */ 12587c478bd9Sstevel@tonic-gate char *token; /* Token extracted by strtok() */ 12597c478bd9Sstevel@tonic-gate char **pp; /* Group member */ 12607c478bd9Sstevel@tonic-gate char *g_arg; /* -g option's argument */ 12617c478bd9Sstevel@tonic-gate char *l_arg; /* -l option's argument */ 12627c478bd9Sstevel@tonic-gate long lookpos; /* File pos'n, rec we're looking for */ 12637c478bd9Sstevel@tonic-gate int a_seen; /* Is -a requested? */ 12647c478bd9Sstevel@tonic-gate int d_seen; /* Is -d requested? */ 12657c478bd9Sstevel@tonic-gate int g_seen; /* Is -g requested? */ 12667c478bd9Sstevel@tonic-gate int l_seen; /* Is -l requested? */ 12677c478bd9Sstevel@tonic-gate int m_seen; /* Is -m requested? */ 12687c478bd9Sstevel@tonic-gate int o_seen; /* Is -o requested? */ 12697c478bd9Sstevel@tonic-gate int p_seen; /* Is -p requested? */ 12707c478bd9Sstevel@tonic-gate int s_seen; /* Is -s requested? */ 12717c478bd9Sstevel@tonic-gate int t_seen; /* Is -t requested? */ 12727c478bd9Sstevel@tonic-gate int u_seen; /* Is -u requested? */ 12737c478bd9Sstevel@tonic-gate int x_seen; /* Is -x requested? */ 12747c478bd9Sstevel@tonic-gate int errflg; /* Is there a command-line problem */ 12757c478bd9Sstevel@tonic-gate int done; /* Is the process (?) is complete */ 127620d7339fSgww int groupcount; /* Number of groups specified */ 12777c478bd9Sstevel@tonic-gate int doall; /* Are all logins to be reported */ 12787c478bd9Sstevel@tonic-gate int c; /* Character returned from getopt() */ 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 12837c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 12847c478bd9Sstevel@tonic-gate #endif 12857c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate /* Initializations */ 12887c478bd9Sstevel@tonic-gate initmsg(argv[0]); 12897c478bd9Sstevel@tonic-gate 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate 129220d7339fSgww /* Command-line processing */ 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* Initializations */ 12957c478bd9Sstevel@tonic-gate a_seen = FALSE; 12967c478bd9Sstevel@tonic-gate d_seen = FALSE; 12977c478bd9Sstevel@tonic-gate g_seen = FALSE; 12987c478bd9Sstevel@tonic-gate l_seen = FALSE; 12997c478bd9Sstevel@tonic-gate m_seen = FALSE; 13007c478bd9Sstevel@tonic-gate o_seen = FALSE; 13017c478bd9Sstevel@tonic-gate p_seen = FALSE; 13027c478bd9Sstevel@tonic-gate s_seen = FALSE; 13037c478bd9Sstevel@tonic-gate t_seen = FALSE; 13047c478bd9Sstevel@tonic-gate u_seen = FALSE; 13057c478bd9Sstevel@tonic-gate x_seen = FALSE; 13067c478bd9Sstevel@tonic-gate errflg = FALSE; 13077c478bd9Sstevel@tonic-gate opterr = 0; 13087c478bd9Sstevel@tonic-gate while (!errflg && ((c = getopt(argc, argv, OPTSTR)) != EOF)) { 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* Case on the option character */ 13117c478bd9Sstevel@tonic-gate switch (c) { 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate /* 13147c478bd9Sstevel@tonic-gate * -a option: 13157c478bd9Sstevel@tonic-gate * Display password expiration information 13167c478bd9Sstevel@tonic-gate */ 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate case 'a': 131920d7339fSgww if (a_seen) 132020d7339fSgww errflg = TRUE; 132120d7339fSgww else 132220d7339fSgww a_seen = TRUE; 13237c478bd9Sstevel@tonic-gate break; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate /* 13267c478bd9Sstevel@tonic-gate * -d option: 13277c478bd9Sstevel@tonic-gate * Display logins which share user-IDs with other logins 13287c478bd9Sstevel@tonic-gate */ 13297c478bd9Sstevel@tonic-gate 13307c478bd9Sstevel@tonic-gate case 'd': 133120d7339fSgww if (d_seen) 133220d7339fSgww errflg = TRUE; 133320d7339fSgww else 133420d7339fSgww d_seen = TRUE; 13357c478bd9Sstevel@tonic-gate break; 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate /* 13387c478bd9Sstevel@tonic-gate * -g <groups> option: 13397c478bd9Sstevel@tonic-gate * Display the specified groups 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate case 'g': 134320d7339fSgww if (g_seen) { 134420d7339fSgww errflg = TRUE; 134520d7339fSgww } else { 13467c478bd9Sstevel@tonic-gate g_seen = TRUE; 13477c478bd9Sstevel@tonic-gate g_arg = optarg; 13487c478bd9Sstevel@tonic-gate } 13497c478bd9Sstevel@tonic-gate break; 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate /* 13527c478bd9Sstevel@tonic-gate * -l <logins> option: 13537c478bd9Sstevel@tonic-gate * Display the specified logins 13547c478bd9Sstevel@tonic-gate */ 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate case 'l': 135720d7339fSgww if (l_seen) { 135820d7339fSgww errflg = TRUE; 135920d7339fSgww } else { 13607c478bd9Sstevel@tonic-gate l_seen = TRUE; 13617c478bd9Sstevel@tonic-gate l_arg = optarg; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate break; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate /* 13667c478bd9Sstevel@tonic-gate * -m option: 13677c478bd9Sstevel@tonic-gate * Display multiple group information 13687c478bd9Sstevel@tonic-gate */ 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate case 'm': 137120d7339fSgww if (m_seen) 137220d7339fSgww errflg = TRUE; 137320d7339fSgww else 137420d7339fSgww m_seen = TRUE; 13757c478bd9Sstevel@tonic-gate break; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate /* 13787c478bd9Sstevel@tonic-gate * -o option: 13797c478bd9Sstevel@tonic-gate * Display information as a colon-list 13807c478bd9Sstevel@tonic-gate */ 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate case 'o': 138320d7339fSgww if (o_seen) 138420d7339fSgww errflg = TRUE; 138520d7339fSgww else 138620d7339fSgww o_seen = TRUE; 13877c478bd9Sstevel@tonic-gate break; 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * -p option: 13917c478bd9Sstevel@tonic-gate * Select logins that have no password 13927c478bd9Sstevel@tonic-gate */ 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate case 'p': 139520d7339fSgww if (p_seen) 139620d7339fSgww errflg = TRUE; 139720d7339fSgww else 139820d7339fSgww p_seen = TRUE; 13997c478bd9Sstevel@tonic-gate break; 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate /* 14027c478bd9Sstevel@tonic-gate * -s option: 14037c478bd9Sstevel@tonic-gate * Select system logins 14047c478bd9Sstevel@tonic-gate */ 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate case 's': 140720d7339fSgww if (s_seen) 140820d7339fSgww errflg = TRUE; 140920d7339fSgww else 141020d7339fSgww s_seen = TRUE; 14117c478bd9Sstevel@tonic-gate break; 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate /* 14147c478bd9Sstevel@tonic-gate * -t option: 14157c478bd9Sstevel@tonic-gate * Sort alphabetically by login-ID instead of numerically 14167c478bd9Sstevel@tonic-gate * by user-ID 14177c478bd9Sstevel@tonic-gate */ 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate case 't': 142020d7339fSgww if (t_seen) 142120d7339fSgww errflg = TRUE; 142220d7339fSgww else 142320d7339fSgww t_seen = TRUE; 14247c478bd9Sstevel@tonic-gate break; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * -u option: 14287c478bd9Sstevel@tonic-gate * Select user logins 14297c478bd9Sstevel@tonic-gate */ 14307c478bd9Sstevel@tonic-gate 14317c478bd9Sstevel@tonic-gate case 'u': 143220d7339fSgww if (u_seen) 143320d7339fSgww errflg = TRUE; 143420d7339fSgww else 143520d7339fSgww u_seen = TRUE; 14367c478bd9Sstevel@tonic-gate break; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate /* 14397c478bd9Sstevel@tonic-gate * -x option: 14407c478bd9Sstevel@tonic-gate * Display extended info (init working dir, shell, pwd info) 14417c478bd9Sstevel@tonic-gate */ 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate case 'x': 144420d7339fSgww if (x_seen) 144520d7339fSgww errflg = TRUE; 144620d7339fSgww else 144720d7339fSgww x_seen = TRUE; 14487c478bd9Sstevel@tonic-gate break; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate default: /* Oops.... */ 14517c478bd9Sstevel@tonic-gate errflg = TRUE; 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate } 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* Write out a usage message if necessary and quit */ 14567c478bd9Sstevel@tonic-gate if (errflg || (optind != argc)) { 14577c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(USAGE_MSG)); 14587c478bd9Sstevel@tonic-gate exit(1); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate /* 14627c478bd9Sstevel@tonic-gate * The following section does preparation work, setting up for 14637c478bd9Sstevel@tonic-gate * building the list of logins to display 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* 14687c478bd9Sstevel@tonic-gate * If -l logins is on the command line, build a list of 14697c478bd9Sstevel@tonic-gate * logins we're to generate reports for. 14707c478bd9Sstevel@tonic-gate */ 14717c478bd9Sstevel@tonic-gate 14727c478bd9Sstevel@tonic-gate if (l_seen) { 147320d7339fSgww reqloginhead = NULL; 14747c478bd9Sstevel@tonic-gate if (token = strtok(l_arg, ",")) { 1475*b816ddf8Sgww plogin = malloc(sizeof (struct reqlogin)); 14767c478bd9Sstevel@tonic-gate plogin->loginname = token; 14777c478bd9Sstevel@tonic-gate plogin->found = FALSE; 147820d7339fSgww plogin->next = NULL; 14797c478bd9Sstevel@tonic-gate reqloginhead = plogin; 14807c478bd9Sstevel@tonic-gate qlogin = plogin; 14817c478bd9Sstevel@tonic-gate while (token = strtok(NULL, ",")) { 1482*b816ddf8Sgww plogin = malloc(sizeof (struct reqlogin)); 14837c478bd9Sstevel@tonic-gate plogin->loginname = token; 14847c478bd9Sstevel@tonic-gate plogin->found = FALSE; 148520d7339fSgww plogin->next = NULL; 14867c478bd9Sstevel@tonic-gate qlogin->next = plogin; 14877c478bd9Sstevel@tonic-gate qlogin = plogin; 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate } 1490*b816ddf8Sgww /* 1491*b816ddf8Sgww * Build an in-core structure of just the passwd database 1492*b816ddf8Sgww * entries requested. This greatly reduces the time 1493*b816ddf8Sgww * to get all entries and filter later. 1494*b816ddf8Sgww */ 1495*b816ddf8Sgww build_localpw(reqloginhead); 1496*b816ddf8Sgww } else { 1497*b816ddf8Sgww /* 1498*b816ddf8Sgww * Build an in-core structure of all passwd database 1499*b816ddf8Sgww * entries. This is important since we have to assume that 1500*b816ddf8Sgww * getpwent() is going out to one or more network name 1501*b816ddf8Sgww * services that could be changing on the fly. This will 1502*b816ddf8Sgww * limit us to one pass through the network data. 1503*b816ddf8Sgww */ 1504*b816ddf8Sgww build_localpw(NULL); 1505*b816ddf8Sgww } 1506*b816ddf8Sgww 1507*b816ddf8Sgww /* 1508*b816ddf8Sgww * If the -g groups option was on the command line, build a 1509*b816ddf8Sgww * list containing groups we're to list logins for. 1510*b816ddf8Sgww */ 1511*b816ddf8Sgww 1512*b816ddf8Sgww if (g_seen) { 1513*b816ddf8Sgww groupcount = 0; 1514*b816ddf8Sgww reqgrphead = NULL; 1515*b816ddf8Sgww if (token = strtok(g_arg, ",")) { 1516*b816ddf8Sgww pgrp = malloc(sizeof (struct reqgrp)); 1517*b816ddf8Sgww pgrp->groupname = token; 1518*b816ddf8Sgww pgrp->next = NULL; 1519*b816ddf8Sgww groupcount++; 1520*b816ddf8Sgww reqgrphead = pgrp; 1521*b816ddf8Sgww qgrp = pgrp; 1522*b816ddf8Sgww while (token = strtok(NULL, ",")) { 1523*b816ddf8Sgww pgrp = malloc(sizeof (struct reqgrp)); 1524*b816ddf8Sgww pgrp->groupname = token; 1525*b816ddf8Sgww pgrp->next = NULL; 1526*b816ddf8Sgww groupcount++; 1527*b816ddf8Sgww qgrp->next = pgrp; 1528*b816ddf8Sgww qgrp = pgrp; 15297c478bd9Sstevel@tonic-gate } 15307c478bd9Sstevel@tonic-gate } 15317c478bd9Sstevel@tonic-gate } 1532*b816ddf8Sgww 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * Generate the list of login information to display 15367c478bd9Sstevel@tonic-gate */ 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate /* Initialize the login list */ 1539*b816ddf8Sgww membershead = NULL; 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate /* 15437c478bd9Sstevel@tonic-gate * If -g groups was specified, generate a list of members 15447c478bd9Sstevel@tonic-gate * of the specified groups 15457c478bd9Sstevel@tonic-gate */ 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate if (g_seen) { 15487c478bd9Sstevel@tonic-gate /* For each group mentioned with the -g option ... */ 154920d7339fSgww for (pgrp = reqgrphead; (groupcount > 0) && pgrp; 155020d7339fSgww pgrp = pgrp->next) { 1551*b816ddf8Sgww if ((grent = getgrnam(pgrp->groupname)) != NULL) { 15527c478bd9Sstevel@tonic-gate /* 1553*b816ddf8Sgww * Remembering the group-ID for later 15547c478bd9Sstevel@tonic-gate */ 15557c478bd9Sstevel@tonic-gate 15567c478bd9Sstevel@tonic-gate groupcount--; 15577c478bd9Sstevel@tonic-gate pgrp->groupID = grent->gr_gid; 1558*b816ddf8Sgww for (pp = grent->gr_mem; *pp; pp++) { 155920d7339fSgww addmember(*pp); 15607c478bd9Sstevel@tonic-gate } 1561*b816ddf8Sgww } else { 156220d7339fSgww wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, 156320d7339fSgww gettext("%s was not found"), 156420d7339fSgww pgrp->groupname); 156520d7339fSgww } 15667c478bd9Sstevel@tonic-gate } 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate /* Initialize the list of logins to display */ 15717c478bd9Sstevel@tonic-gate initdisp(); 15727c478bd9Sstevel@tonic-gate 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Add logins that have user-IDs that are used more than once, 15767c478bd9Sstevel@tonic-gate * if requested. This command is pretty slow, since the algorithm 15777c478bd9Sstevel@tonic-gate * reads from the /etc/passwd file 1+2+3+...+n times where n is the 15787c478bd9Sstevel@tonic-gate * number of login-IDs in the /etc/passwd file. (Actually, this 15797c478bd9Sstevel@tonic-gate * can be optimized so it's not quite that bad, but the order or 15807c478bd9Sstevel@tonic-gate * magnitude stays the same.) 15817c478bd9Sstevel@tonic-gate * 15827c478bd9Sstevel@tonic-gate * Note: This processing needs to be done before any other options 15837c478bd9Sstevel@tonic-gate * are processed -- the algorithm contains an optimization 15847c478bd9Sstevel@tonic-gate * that insists on the display list being empty before this 15857c478bd9Sstevel@tonic-gate * option is processed. 15867c478bd9Sstevel@tonic-gate */ 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate if (d_seen) { 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate /* 15917c478bd9Sstevel@tonic-gate * The following code is a quick&dirty reimplementation of the 15927c478bd9Sstevel@tonic-gate * original algorithm, which opened the password file twice (to 15937c478bd9Sstevel@tonic-gate * get two file pointer into the data) and then used fgetpwent() 15947c478bd9Sstevel@tonic-gate * in undocumented ways to scan through the file, checking for 15957c478bd9Sstevel@tonic-gate * duplicates. This does not work when getpwent() is used to 15967c478bd9Sstevel@tonic-gate * go out over the network, since there is not file pointer. 15977c478bd9Sstevel@tonic-gate * 159820d7339fSgww * Instead an in-memory list of passwd structures is built, 159920d7339fSgww * and then this list is scanned. The routines 160020d7339fSgww * Local_getpwent(), etc., are designed to mimic the standard 160120d7339fSgww * library routines, so this code does not have to be 160220d7339fSgww * extensively modified. 16037c478bd9Sstevel@tonic-gate */ 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* 16067c478bd9Sstevel@tonic-gate * For reference, here is the original comment about the next 160720d7339fSgww * section of code. Some of the code has changed, but the 160820d7339fSgww * algorithm is the same: 16097c478bd9Sstevel@tonic-gate * 16107c478bd9Sstevel@tonic-gate * Open the system password file once. This instance will be 16117c478bd9Sstevel@tonic-gate * used to leaf through the file once, reading each entry once, 16127c478bd9Sstevel@tonic-gate * and searching the remainder of the file for another login-ID 16137c478bd9Sstevel@tonic-gate * that has the same user-ID. Note that there are lots of 16147c478bd9Sstevel@tonic-gate * contortions one has to go through when reading two instances 16157c478bd9Sstevel@tonic-gate * of the /etc/passwd file. That's why there's some seeking, 16167c478bd9Sstevel@tonic-gate * re-reading of the same record, and other junk. Luckily, this 16177c478bd9Sstevel@tonic-gate * feature won't be requested very often, and still isn't too 16187c478bd9Sstevel@tonic-gate * slow... 16197c478bd9Sstevel@tonic-gate */ 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* For each entry in the passwd database ... */ 16227c478bd9Sstevel@tonic-gate while (plookpwd = local_getpwent()) { 16237c478bd9Sstevel@tonic-gate /* 162420d7339fSgww * Optimization -- If the login's user-ID is already 162520d7339fSgww * in the display list, there's no reason to process 162620d7339fSgww * this entry -- it's already there. 16277c478bd9Sstevel@tonic-gate */ 16287c478bd9Sstevel@tonic-gate if (!isuidindisp(plookpwd)) { 16297c478bd9Sstevel@tonic-gate /* 163020d7339fSgww * Rememeber the current entry's position, 163120d7339fSgww * so when we finish scanning through the 163220d7339fSgww * database looking for duplicates we can 163320d7339fSgww * return to the current place, so that the 163420d7339fSgww * enclosing loop will march in an orderly 163520d7339fSgww * fashion through the passwd database. 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate done = FALSE; 16387c478bd9Sstevel@tonic-gate lookpos = local_pwtell(); 16397c478bd9Sstevel@tonic-gate 16407c478bd9Sstevel@tonic-gate /* 164120d7339fSgww * For each record in the passwd database 164220d7339fSgww * beyond the searching record ... 16437c478bd9Sstevel@tonic-gate */ 16447c478bd9Sstevel@tonic-gate while (pwent = local_getpwent()) { 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* 164720d7339fSgww * If there's a match between the 164820d7339fSgww * searcher's user-ID and the 164920d7339fSgww * searchee's user-ID ... 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate if (pwent->pw_uid == plookpwd->pw_uid) { 16527c478bd9Sstevel@tonic-gate /* 165320d7339fSgww * If this is the first 165420d7339fSgww * duplicate of this searcher 16557c478bd9Sstevel@tonic-gate * that we find, 165620d7339fSgww * add the searcher's 165720d7339fSgww * record to the display list 165820d7339fSgww * (It wants to be on the 165920d7339fSgww * list first to avoid 166020d7339fSgww * ordering "flakeyness") 16617c478bd9Sstevel@tonic-gate */ 16627c478bd9Sstevel@tonic-gate if (done == FALSE) { 16637c478bd9Sstevel@tonic-gate adddisp(plookpwd); 166420d7339fSgww done = TRUE; 16657c478bd9Sstevel@tonic-gate } 16667c478bd9Sstevel@tonic-gate 16677c478bd9Sstevel@tonic-gate /* 166820d7339fSgww * Now add the searchee's 166920d7339fSgww * record 16707c478bd9Sstevel@tonic-gate */ 16717c478bd9Sstevel@tonic-gate adddisp(pwent); 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate } 16747c478bd9Sstevel@tonic-gate } 16757c478bd9Sstevel@tonic-gate /* Reposition to searcher record */ 16767c478bd9Sstevel@tonic-gate local_pwseek(lookpos); 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate } 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate local_endpwent(); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate /* 16857c478bd9Sstevel@tonic-gate * Loop through the passwd database squirelling away the 16867c478bd9Sstevel@tonic-gate * information we need for the display. 16877c478bd9Sstevel@tonic-gate * 16887c478bd9Sstevel@tonic-gate * NOTE: Once a login is added to the list, the rest of the 16897c478bd9Sstevel@tonic-gate * body of the loop is bypassed (via a continue statement). 16907c478bd9Sstevel@tonic-gate */ 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate doall = !(s_seen || u_seen || p_seen || d_seen || l_seen || g_seen); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate if (doall || s_seen || u_seen || p_seen || l_seen || g_seen) { 16957c478bd9Sstevel@tonic-gate 16967c478bd9Sstevel@tonic-gate while (pwent = local_getpwent()) { 16977c478bd9Sstevel@tonic-gate done = FALSE; 16987c478bd9Sstevel@tonic-gate 169920d7339fSgww /* 170020d7339fSgww * If no user-specific options were specified, 170120d7339fSgww * include this login-ID 170220d7339fSgww */ 17037c478bd9Sstevel@tonic-gate if (doall) { 17047c478bd9Sstevel@tonic-gate adddisp(pwent); 17057c478bd9Sstevel@tonic-gate continue; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 170820d7339fSgww /* 170920d7339fSgww * If the user specified system login-IDs, 171020d7339fSgww * and this is a system ID, include it 171120d7339fSgww */ 171220d7339fSgww if (s_seen) { 171320d7339fSgww if (isasystemlogin(pwent)) { 17147c478bd9Sstevel@tonic-gate adddisp(pwent); 17157c478bd9Sstevel@tonic-gate continue; 17167c478bd9Sstevel@tonic-gate } 171720d7339fSgww } 17187c478bd9Sstevel@tonic-gate 171920d7339fSgww /* 172020d7339fSgww * If the user specified user login-IDs, 172120d7339fSgww * and this is a user ID, include it 172220d7339fSgww */ 172320d7339fSgww if (u_seen) { 172420d7339fSgww if (isauserlogin(pwent)) { 17257c478bd9Sstevel@tonic-gate adddisp(pwent); 17267c478bd9Sstevel@tonic-gate continue; 17277c478bd9Sstevel@tonic-gate } 172820d7339fSgww } 17297c478bd9Sstevel@tonic-gate 173020d7339fSgww /* 173120d7339fSgww * If the user is asking for login-IDs that have 173220d7339fSgww * no password, and this one has no password, include it 173320d7339fSgww */ 173420d7339fSgww if (p_seen) { 173520d7339fSgww if (hasnopasswd(pwent)) { 17367c478bd9Sstevel@tonic-gate adddisp(pwent); 17377c478bd9Sstevel@tonic-gate continue; 17387c478bd9Sstevel@tonic-gate } 173920d7339fSgww } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate /* 17427c478bd9Sstevel@tonic-gate * If specific logins were requested, leaf through 17437c478bd9Sstevel@tonic-gate * the list of logins they requested. If this login 17447c478bd9Sstevel@tonic-gate * is on the list, include it. 17457c478bd9Sstevel@tonic-gate */ 17467c478bd9Sstevel@tonic-gate if (l_seen) { 174720d7339fSgww for (plogin = reqloginhead; !done && plogin; 174820d7339fSgww plogin = plogin->next) { 174920d7339fSgww if (strcmp(pwent->pw_name, 175020d7339fSgww plogin->loginname) == 0) { 17517c478bd9Sstevel@tonic-gate plogin->found = TRUE; 17527c478bd9Sstevel@tonic-gate adddisp(pwent); 17537c478bd9Sstevel@tonic-gate done = TRUE; 17547c478bd9Sstevel@tonic-gate } 17557c478bd9Sstevel@tonic-gate } 175620d7339fSgww if (done) 175720d7339fSgww continue; 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate /* 17617c478bd9Sstevel@tonic-gate * If specific groups were requested, leaf through the 176220d7339fSgww * list of login-IDs that belong to those groups. 176320d7339fSgww * If this login-ID is in that list, or its primary 176420d7339fSgww * group is one of those requested, include it. 17657c478bd9Sstevel@tonic-gate */ 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate if (g_seen) { 176820d7339fSgww for (pgrp = reqgrphead; !done && pgrp; 176920d7339fSgww pgrp = pgrp->next) { 17707c478bd9Sstevel@tonic-gate if (pwent->pw_gid == pgrp->groupID) { 17717c478bd9Sstevel@tonic-gate adddisp(pwent); 17727c478bd9Sstevel@tonic-gate done = TRUE; 17737c478bd9Sstevel@tonic-gate } 177420d7339fSgww } 17757c478bd9Sstevel@tonic-gate if (!done && isamember(pwent->pw_name)) { 17767c478bd9Sstevel@tonic-gate adddisp(pwent); 17777c478bd9Sstevel@tonic-gate done = TRUE; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate } 178020d7339fSgww if (done) 178120d7339fSgww continue; 17827c478bd9Sstevel@tonic-gate } 178320d7339fSgww 17847c478bd9Sstevel@tonic-gate local_endpwent(); 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate 178720d7339fSgww /* Let the user know about logins they requested that don't exist */ 178820d7339fSgww if (l_seen) { 178920d7339fSgww for (plogin = reqloginhead; plogin; plogin = plogin->next) { 179020d7339fSgww if (!plogin->found) { 179120d7339fSgww wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, 179220d7339fSgww gettext("%s was not found"), 179320d7339fSgww plogin->loginname); 179420d7339fSgww } 179520d7339fSgww } 179620d7339fSgww } 17977c478bd9Sstevel@tonic-gate 179820d7339fSgww /* Apply group information */ 17997c478bd9Sstevel@tonic-gate applygroup(m_seen); 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate 18027c478bd9Sstevel@tonic-gate /* 18037c478bd9Sstevel@tonic-gate * Apply password information (only needed if the extended 18047c478bd9Sstevel@tonic-gate * set of information has been requested) 18057c478bd9Sstevel@tonic-gate */ 180620d7339fSgww if (x_seen || a_seen) 180720d7339fSgww applypasswd(); 18087c478bd9Sstevel@tonic-gate 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate /* 181120d7339fSgww * Generate a report from this display items we've squirreled away 18127c478bd9Sstevel@tonic-gate */ 18137c478bd9Sstevel@tonic-gate 181420d7339fSgww if (t_seen) 181520d7339fSgww genlogreport(o_seen, x_seen, a_seen); 181620d7339fSgww else 181720d7339fSgww genuidreport(o_seen, x_seen, a_seen); 18187c478bd9Sstevel@tonic-gate 181920d7339fSgww /* We're through! */ 18207c478bd9Sstevel@tonic-gate return (0); 18217c478bd9Sstevel@tonic-gate } 1822