1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /* 34*7c478bd9Sstevel@tonic-gate * users.c 35*7c478bd9Sstevel@tonic-gate * 36*7c478bd9Sstevel@tonic-gate * This file contains the source for the administrative command 37*7c478bd9Sstevel@tonic-gate * "listusers" (available to the general user population) that 38*7c478bd9Sstevel@tonic-gate * produces a report containing user login-IDs and their "free 39*7c478bd9Sstevel@tonic-gate * field" (typically contains the user's name and other information). 40*7c478bd9Sstevel@tonic-gate */ 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate /* 43*7c478bd9Sstevel@tonic-gate * Header files referenced: 44*7c478bd9Sstevel@tonic-gate * sys/types.h System type definitions 45*7c478bd9Sstevel@tonic-gate * stdio.h Definitions for standard I/O functions and constants 46*7c478bd9Sstevel@tonic-gate * string.h Definitions for string-handling functions 47*7c478bd9Sstevel@tonic-gate * grp.h Definitions for referencing the /etc/group file 48*7c478bd9Sstevel@tonic-gate * pwd.h Definitions for referencing the /etc/passwd file 49*7c478bd9Sstevel@tonic-gate * varargs.h Definitions for using a variable argument list 50*7c478bd9Sstevel@tonic-gate * fmtmsg.h Definitions for using the standard message formatting 51*7c478bd9Sstevel@tonic-gate * facility 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 55*7c478bd9Sstevel@tonic-gate #include <stdio.h> 56*7c478bd9Sstevel@tonic-gate #include <string.h> 57*7c478bd9Sstevel@tonic-gate #include <string.h> 58*7c478bd9Sstevel@tonic-gate #include <grp.h> 59*7c478bd9Sstevel@tonic-gate #include <pwd.h> 60*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 61*7c478bd9Sstevel@tonic-gate #include <fmtmsg.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * Externals referenced (and not defined by a header file): 66*7c478bd9Sstevel@tonic-gate * malloc Allocate memory from main memory 67*7c478bd9Sstevel@tonic-gate * getopt Extract the next option from the command line 68*7c478bd9Sstevel@tonic-gate * optind The argument count of the next option to extract from 69*7c478bd9Sstevel@tonic-gate * the command line 70*7c478bd9Sstevel@tonic-gate * optarg A pointer to the argument of the option just extracted 71*7c478bd9Sstevel@tonic-gate * from the command line 72*7c478bd9Sstevel@tonic-gate * opterr FLAG: !0 tells getopt() to write an error message if 73*7c478bd9Sstevel@tonic-gate * it detects an error 74*7c478bd9Sstevel@tonic-gate * getpwent Get next entry from the /etc/passwd file 75*7c478bd9Sstevel@tonic-gate * getgrent Get next entry from the /etc/group file 76*7c478bd9Sstevel@tonic-gate * fmtmsg Standard message generation facility 77*7c478bd9Sstevel@tonic-gate * putenv Modify the environment 78*7c478bd9Sstevel@tonic-gate * exit Exit the program 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate extern void *malloc(); 82*7c478bd9Sstevel@tonic-gate extern int getopt(); 83*7c478bd9Sstevel@tonic-gate extern char *optarg; 84*7c478bd9Sstevel@tonic-gate extern int optind; 85*7c478bd9Sstevel@tonic-gate extern int opterr; 86*7c478bd9Sstevel@tonic-gate extern struct passwd *getpwent(); 87*7c478bd9Sstevel@tonic-gate extern struct group *getgrent(); 88*7c478bd9Sstevel@tonic-gate extern int fmtmsg(); 89*7c478bd9Sstevel@tonic-gate extern int putenv(); 90*7c478bd9Sstevel@tonic-gate extern void exit(); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * Local constant definitions 94*7c478bd9Sstevel@tonic-gate */ 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate #ifndef FALSE 97*7c478bd9Sstevel@tonic-gate #define FALSE 0 98*7c478bd9Sstevel@tonic-gate #endif 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate #ifndef TRUE 101*7c478bd9Sstevel@tonic-gate #define TRUE ('t') 102*7c478bd9Sstevel@tonic-gate #endif 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate #define USAGE_MSG "usage: listusers [-g groups] [-l logins]" 105*7c478bd9Sstevel@tonic-gate #define MAXLOGINSIZE 14 106*7c478bd9Sstevel@tonic-gate #define LOGINFIELDSZ MAXLOGINSIZE+2 107*7c478bd9Sstevel@tonic-gate 108*7c478bd9Sstevel@tonic-gate #define isauserlogin(uid) (uid >= 100) 109*7c478bd9Sstevel@tonic-gate #define isasystemlogin(uid) (uid < 100) 110*7c478bd9Sstevel@tonic-gate #define isausergroup(gid) (gid >= 100) 111*7c478bd9Sstevel@tonic-gate #define isasystemgroup(gid) (gid < 100) 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* 114*7c478bd9Sstevel@tonic-gate * Local datatype definitions 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * This structure describes a specified group name 119*7c478bd9Sstevel@tonic-gate * (from the -g groups option) 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate struct reqgrp { 123*7c478bd9Sstevel@tonic-gate char *groupname; 124*7c478bd9Sstevel@tonic-gate struct reqgrp *next; 125*7c478bd9Sstevel@tonic-gate int found; 126*7c478bd9Sstevel@tonic-gate gid_t groupID; 127*7c478bd9Sstevel@tonic-gate }; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* 130*7c478bd9Sstevel@tonic-gate * This structure describes a specified login name 131*7c478bd9Sstevel@tonic-gate * (from the -l logins option) 132*7c478bd9Sstevel@tonic-gate */ 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate struct reqlogin { 135*7c478bd9Sstevel@tonic-gate char *loginname; 136*7c478bd9Sstevel@tonic-gate struct reqlogin *next; 137*7c478bd9Sstevel@tonic-gate int found; 138*7c478bd9Sstevel@tonic-gate }; 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate * These functions handle error and warning message writing. 142*7c478bd9Sstevel@tonic-gate * (This deals with UNIX(r) standard message generation, so 143*7c478bd9Sstevel@tonic-gate * the rest of the code doesn't have to.) 144*7c478bd9Sstevel@tonic-gate * 145*7c478bd9Sstevel@tonic-gate * Functions included: 146*7c478bd9Sstevel@tonic-gate * initmsg Initialize the message handling functions. 147*7c478bd9Sstevel@tonic-gate * wrtmsg Write the message using the standard message 148*7c478bd9Sstevel@tonic-gate * generation facility. 149*7c478bd9Sstevel@tonic-gate * 150*7c478bd9Sstevel@tonic-gate * Static data included: 151*7c478bd9Sstevel@tonic-gate * fcnlbl The label for standard messages 152*7c478bd9Sstevel@tonic-gate * msgbuf A buffer to contain the edited message 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate static char fcnlbl[MM_MXLABELLN+1]; /* Buffer for message label */ 156*7c478bd9Sstevel@tonic-gate static char msgbuf[MM_MXTXTLN+1]; /* Buffer for message text */ 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate /* 159*7c478bd9Sstevel@tonic-gate * void initmsg(p) 160*7c478bd9Sstevel@tonic-gate * 161*7c478bd9Sstevel@tonic-gate * This function initializes the message handling functions. 162*7c478bd9Sstevel@tonic-gate * 163*7c478bd9Sstevel@tonic-gate * Arguments: 164*7c478bd9Sstevel@tonic-gate * p A pointer to a character string that is the name of the 165*7c478bd9Sstevel@tonic-gate * command, used to generate the label on messages. If this 166*7c478bd9Sstevel@tonic-gate * string contains a slash ('/'), it only uses the characters 167*7c478bd9Sstevel@tonic-gate * beyond the last slash in the string (this permits argv[0] 168*7c478bd9Sstevel@tonic-gate * to be used). 169*7c478bd9Sstevel@tonic-gate * 170*7c478bd9Sstevel@tonic-gate * Returns: Void 171*7c478bd9Sstevel@tonic-gate */ 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate static void 174*7c478bd9Sstevel@tonic-gate initmsg(p) 175*7c478bd9Sstevel@tonic-gate char *p; /* Ptr to command name */ 176*7c478bd9Sstevel@tonic-gate { 177*7c478bd9Sstevel@tonic-gate /* Automatic data */ 178*7c478bd9Sstevel@tonic-gate char *q; /* Local multi-use pointer */ 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* Use only the simple filename if there is a slash in the name */ 181*7c478bd9Sstevel@tonic-gate if ((q = strrchr(p, '/')) == (char *) NULL) q = p; 182*7c478bd9Sstevel@tonic-gate else q++; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* Build the label for messages */ 185*7c478bd9Sstevel@tonic-gate (void) snprintf(fcnlbl, sizeof (fcnlbl), "UX:%s", q); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Now that we've done all of that work, set things up so that 189*7c478bd9Sstevel@tonic-gate * only the text-component of a message is printed. (This piece 190*7c478bd9Sstevel@tonic-gate * of code will most probably go away in SVR4.1. 191*7c478bd9Sstevel@tonic-gate */ 192*7c478bd9Sstevel@tonic-gate (void) putenv("MSGVERB=text"); 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* 196*7c478bd9Sstevel@tonic-gate * void wrtmsg(severity, action, tag, text[, txtarg1[, txtarg2[, ...]]]) 197*7c478bd9Sstevel@tonic-gate * 198*7c478bd9Sstevel@tonic-gate * This function writes a message using the standard message 199*7c478bd9Sstevel@tonic-gate * generation facility. 200*7c478bd9Sstevel@tonic-gate * 201*7c478bd9Sstevel@tonic-gate * Arguments: 202*7c478bd9Sstevel@tonic-gate * severity The severity-component of the message 203*7c478bd9Sstevel@tonic-gate * action The action-string used to generate the action- 204*7c478bd9Sstevel@tonic-gate * component of the message 205*7c478bd9Sstevel@tonic-gate * tag Tag-component of the message 206*7c478bd9Sstevel@tonic-gate * text The text-string used to generate the text-component 207*7c478bd9Sstevel@tonic-gate * of the message 208*7c478bd9Sstevel@tonic-gate * txtarg Arguments to be inserted into the "text" string using 209*7c478bd9Sstevel@tonic-gate * vsnprintf() 210*7c478bd9Sstevel@tonic-gate * 211*7c478bd9Sstevel@tonic-gate * Returns: Void 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate 214*7c478bd9Sstevel@tonic-gate /* VARARGS4 */ 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate static void 217*7c478bd9Sstevel@tonic-gate wrtmsg(int severity, char *action, char *tag, char *text, ...) 218*7c478bd9Sstevel@tonic-gate { 219*7c478bd9Sstevel@tonic-gate /* Automatic data */ 220*7c478bd9Sstevel@tonic-gate int errorflg; /* FLAG: True if error writing msg */ 221*7c478bd9Sstevel@tonic-gate va_list argp; /* Pointer into vararg list */ 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate errorflg = FALSE; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* Generate the error message */ 226*7c478bd9Sstevel@tonic-gate va_start(argp, text); 227*7c478bd9Sstevel@tonic-gate if (text != MM_NULLTXT) 228*7c478bd9Sstevel@tonic-gate { 229*7c478bd9Sstevel@tonic-gate errorflg = vsnprintf(msgbuf, sizeof (msgbuf), text, argp) > 230*7c478bd9Sstevel@tonic-gate MM_MXTXTLN; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, severity, 233*7c478bd9Sstevel@tonic-gate (text == MM_NULLTXT) ? MM_NULLTXT : msgbuf, 234*7c478bd9Sstevel@tonic-gate action, tag); 235*7c478bd9Sstevel@tonic-gate va_end(argp); 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * If there would have been a buffer overflow generating the error 239*7c478bd9Sstevel@tonic-gate * message, the message will be truncated, so write a message and quit. 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate if (errorflg) { 243*7c478bd9Sstevel@tonic-gate (void) fmtmsg(MM_PRINT, fcnlbl, MM_WARNING, 244*7c478bd9Sstevel@tonic-gate "Internal message buffer overflow", 245*7c478bd9Sstevel@tonic-gate MM_NULLACT, MM_NULLTAG); 246*7c478bd9Sstevel@tonic-gate exit(100); 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * These functions allocate space for the information we gather. 253*7c478bd9Sstevel@tonic-gate * It works by having a memory heap with strings allocated from 254*7c478bd9Sstevel@tonic-gate * the end of the heap and structures (aligned data) allocated 255*7c478bd9Sstevel@tonic-gate * from the beginning of the heap. It begins with a 4k block of 256*7c478bd9Sstevel@tonic-gate * memory then allocates memory in 4k chunks. These functions 257*7c478bd9Sstevel@tonic-gate * should never fail. If they do, they report the problem and 258*7c478bd9Sstevel@tonic-gate * exit with an exit code of 101. 259*7c478bd9Sstevel@tonic-gate * 260*7c478bd9Sstevel@tonic-gate * Functions contained: 261*7c478bd9Sstevel@tonic-gate * allocblk Allocates a block of memory, aligned on a 262*7c478bd9Sstevel@tonic-gate * 4-byte (double-word) boundary. 263*7c478bd9Sstevel@tonic-gate * allocstr Allocates a block of memory with no particular 264*7c478bd9Sstevel@tonic-gate * alignment 265*7c478bd9Sstevel@tonic-gate * 266*7c478bd9Sstevel@tonic-gate * Constant definitions: 267*7c478bd9Sstevel@tonic-gate * ALLOCBLKSZ Size of a chunk of main memory allocated using 268*7c478bd9Sstevel@tonic-gate * malloc() 269*7c478bd9Sstevel@tonic-gate * 270*7c478bd9Sstevel@tonic-gate * Static data: 271*7c478bd9Sstevel@tonic-gate * nextblkaddr Address of the next available chunk of aligned 272*7c478bd9Sstevel@tonic-gate * space in the heap 273*7c478bd9Sstevel@tonic-gate * laststraddr Address of the last chunk of unaligned space 274*7c478bd9Sstevel@tonic-gate * allocated from the heap 275*7c478bd9Sstevel@tonic-gate * toomuchspace Message to write if someone attempts to allocate 276*7c478bd9Sstevel@tonic-gate * too much space (>ALLOCBLKSZ bytes) 277*7c478bd9Sstevel@tonic-gate * memallocdif Message to write if there is a problem allocating 278*7c478bd9Sstevel@tonic-gate * main memory. 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate #define ALLOCBLKSZ 4096 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate static char *nextblkaddr = (char *) NULL; 284*7c478bd9Sstevel@tonic-gate static char *laststraddr = (char *) NULL; 285*7c478bd9Sstevel@tonic-gate static char *memallocdif = "Memory allocation difficulty. Command terminates"; 286*7c478bd9Sstevel@tonic-gate static char *toomuchspace = "Internal space allocation error. Command terminates"; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate /* 289*7c478bd9Sstevel@tonic-gate * void *allocblk(size) 290*7c478bd9Sstevel@tonic-gate * unsigned int size 291*7c478bd9Sstevel@tonic-gate * 292*7c478bd9Sstevel@tonic-gate * This function allocates a block of aligned (4-byte or double- 293*7c478bd9Sstevel@tonic-gate * word boundary) memory from the program's heap. It returns a 294*7c478bd9Sstevel@tonic-gate * pointer to that block of allocated memory. 295*7c478bd9Sstevel@tonic-gate * 296*7c478bd9Sstevel@tonic-gate * Arguments: 297*7c478bd9Sstevel@tonic-gate * size Minimum number of bytes to allocate (will 298*7c478bd9Sstevel@tonic-gate * round up to multiple of 4) 299*7c478bd9Sstevel@tonic-gate * 300*7c478bd9Sstevel@tonic-gate * Returns: void * 301*7c478bd9Sstevel@tonic-gate * Pointer to the allocated block of memory 302*7c478bd9Sstevel@tonic-gate */ 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate static void * 305*7c478bd9Sstevel@tonic-gate allocblk(size) 306*7c478bd9Sstevel@tonic-gate unsigned int size; 307*7c478bd9Sstevel@tonic-gate { 308*7c478bd9Sstevel@tonic-gate /* Automatic data */ 309*7c478bd9Sstevel@tonic-gate char *rtnval; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate /* Make sure the sizes are aligned correctly */ 313*7c478bd9Sstevel@tonic-gate if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) { 314*7c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace); 315*7c478bd9Sstevel@tonic-gate exit(101); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate /* Set up the value we're going to return */ 319*7c478bd9Sstevel@tonic-gate rtnval = nextblkaddr; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* Get the space we need off of the heap */ 322*7c478bd9Sstevel@tonic-gate if ((nextblkaddr += size) >= laststraddr) { 323*7c478bd9Sstevel@tonic-gate if ((rtnval = (char *) malloc(ALLOCBLKSZ)) == (char *) NULL) { 324*7c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif); 325*7c478bd9Sstevel@tonic-gate exit(101); 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate laststraddr = rtnval + ALLOCBLKSZ; 328*7c478bd9Sstevel@tonic-gate nextblkaddr = rtnval + size; 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* We're through */ 332*7c478bd9Sstevel@tonic-gate return((void *) rtnval); 333*7c478bd9Sstevel@tonic-gate } 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * char *allocstr(nbytes) 337*7c478bd9Sstevel@tonic-gate * unsigned int nbytes 338*7c478bd9Sstevel@tonic-gate * 339*7c478bd9Sstevel@tonic-gate * This function allocates a block of unaligned memory from the 340*7c478bd9Sstevel@tonic-gate * program's heap. It returns a pointer to that block of allocated 341*7c478bd9Sstevel@tonic-gate * memory. 342*7c478bd9Sstevel@tonic-gate * 343*7c478bd9Sstevel@tonic-gate * Arguments: 344*7c478bd9Sstevel@tonic-gate * nbytes Number of bytes to allocate 345*7c478bd9Sstevel@tonic-gate * 346*7c478bd9Sstevel@tonic-gate * Returns: char * 347*7c478bd9Sstevel@tonic-gate * Pointer to the allocated block of memory 348*7c478bd9Sstevel@tonic-gate */ 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate static char * 351*7c478bd9Sstevel@tonic-gate allocstr(nchars) 352*7c478bd9Sstevel@tonic-gate unsigned int nchars; 353*7c478bd9Sstevel@tonic-gate { 354*7c478bd9Sstevel@tonic-gate if (nchars > ALLOCBLKSZ) { 355*7c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, toomuchspace); 356*7c478bd9Sstevel@tonic-gate exit(101); 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate if ((laststraddr -= nchars) < nextblkaddr) { 359*7c478bd9Sstevel@tonic-gate if ((nextblkaddr = (char *) malloc(ALLOCBLKSZ)) == (char *) NULL) { 360*7c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, memallocdif); 361*7c478bd9Sstevel@tonic-gate exit(101); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate laststraddr = nextblkaddr + ALLOCBLKSZ - nchars; 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate return(laststraddr); 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * These functions control the group membership list, as found in the 370*7c478bd9Sstevel@tonic-gate * /etc/group file. 371*7c478bd9Sstevel@tonic-gate * 372*7c478bd9Sstevel@tonic-gate * Functions included: 373*7c478bd9Sstevel@tonic-gate * initmembers Initialize the membership list (to NULL) 374*7c478bd9Sstevel@tonic-gate * addmember Adds a member to the membership list 375*7c478bd9Sstevel@tonic-gate * isamember Looks for a particular login-ID in the list 376*7c478bd9Sstevel@tonic-gate * of members 377*7c478bd9Sstevel@tonic-gate * 378*7c478bd9Sstevel@tonic-gate * Datatype Definitions: 379*7c478bd9Sstevel@tonic-gate * struct grpmember Describes a group member 380*7c478bd9Sstevel@tonic-gate * 381*7c478bd9Sstevel@tonic-gate * Static Data: 382*7c478bd9Sstevel@tonic-gate * membershead Pointer to the head of the list of group members 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate struct grpmember { 386*7c478bd9Sstevel@tonic-gate char *membername; 387*7c478bd9Sstevel@tonic-gate struct grpmember *next; 388*7c478bd9Sstevel@tonic-gate }; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate static struct grpmember *membershead; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate /* 393*7c478bd9Sstevel@tonic-gate * void initmembers() 394*7c478bd9Sstevel@tonic-gate * 395*7c478bd9Sstevel@tonic-gate * This function initializes the list of members of specified groups. 396*7c478bd9Sstevel@tonic-gate * 397*7c478bd9Sstevel@tonic-gate * Arguments: None 398*7c478bd9Sstevel@tonic-gate * 399*7c478bd9Sstevel@tonic-gate * Returns: Void 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate static void 403*7c478bd9Sstevel@tonic-gate initmembers() 404*7c478bd9Sstevel@tonic-gate { 405*7c478bd9Sstevel@tonic-gate /* Set up the members list to be a null member's list */ 406*7c478bd9Sstevel@tonic-gate membershead = (struct grpmember *) NULL; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * void addmember(p) 411*7c478bd9Sstevel@tonic-gate * char *p 412*7c478bd9Sstevel@tonic-gate * 413*7c478bd9Sstevel@tonic-gate * This function adds a member to the group member's list. The 414*7c478bd9Sstevel@tonic-gate * group members list is a list of structures containing a pointer 415*7c478bd9Sstevel@tonic-gate * to the member-name and a pointer to the next item in the structure. 416*7c478bd9Sstevel@tonic-gate * The structure is not ordered in any particular way. 417*7c478bd9Sstevel@tonic-gate * 418*7c478bd9Sstevel@tonic-gate * Arguments: 419*7c478bd9Sstevel@tonic-gate * p Pointer to the member name 420*7c478bd9Sstevel@tonic-gate * 421*7c478bd9Sstevel@tonic-gate * Returns: Void 422*7c478bd9Sstevel@tonic-gate */ 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate static void 425*7c478bd9Sstevel@tonic-gate addmember(p) 426*7c478bd9Sstevel@tonic-gate char *p; 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate /* Automatic data */ 429*7c478bd9Sstevel@tonic-gate struct grpmember *new; /* Member being added */ 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate new = (struct grpmember *) allocblk(sizeof(struct grpmember)); 432*7c478bd9Sstevel@tonic-gate new->membername = strcpy(allocstr((unsigned int) strlen(p)+1), p); 433*7c478bd9Sstevel@tonic-gate new->next = membershead; 434*7c478bd9Sstevel@tonic-gate membershead = new; 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate /* 438*7c478bd9Sstevel@tonic-gate * init isamember(p) 439*7c478bd9Sstevel@tonic-gate * char *p 440*7c478bd9Sstevel@tonic-gate * 441*7c478bd9Sstevel@tonic-gate * This function examines the list of group-members for the string 442*7c478bd9Sstevel@tonic-gate * referenced by 'p'. If 'p' is a member of the members list, the 443*7c478bd9Sstevel@tonic-gate * function returns TRUE. Otherwise it returns FALSE. 444*7c478bd9Sstevel@tonic-gate * 445*7c478bd9Sstevel@tonic-gate * Arguments: 446*7c478bd9Sstevel@tonic-gate * p Pointer to the name to search for. 447*7c478bd9Sstevel@tonic-gate * 448*7c478bd9Sstevel@tonic-gate * Returns: int 449*7c478bd9Sstevel@tonic-gate * TRUE If 'p' is found in the members list, 450*7c478bd9Sstevel@tonic-gate * FALSE otherwise 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate static int 454*7c478bd9Sstevel@tonic-gate isamember(p) 455*7c478bd9Sstevel@tonic-gate char *p; 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate /* Automatic Data */ 458*7c478bd9Sstevel@tonic-gate int found; /* FLAG: TRUE if login found */ 459*7c478bd9Sstevel@tonic-gate struct grpmember *pmem; /* Pointer to group member */ 460*7c478bd9Sstevel@tonic-gate 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate /* Search the membership list for the 'p' */ 463*7c478bd9Sstevel@tonic-gate found = FALSE; 464*7c478bd9Sstevel@tonic-gate for (pmem = membershead ; !found && pmem ; pmem = pmem->next) { 465*7c478bd9Sstevel@tonic-gate if (strcmp(p, pmem->membername) == 0) found = TRUE; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate return (found); 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate /* 472*7c478bd9Sstevel@tonic-gate * These functions handle the display list. The display list contains 473*7c478bd9Sstevel@tonic-gate * all of the information we're to display. The list contains a pointer 474*7c478bd9Sstevel@tonic-gate * to the login-name, a pointer to the free-field (comment), and a pointer 475*7c478bd9Sstevel@tonic-gate * to the next item in the list. The list is ordered alphabetically 476*7c478bd9Sstevel@tonic-gate * (ascending) on the login-name field. The list initially contains a 477*7c478bd9Sstevel@tonic-gate * dummy field (to make insertion easier) that contains a login-name of "". 478*7c478bd9Sstevel@tonic-gate * 479*7c478bd9Sstevel@tonic-gate * Functions included: 480*7c478bd9Sstevel@tonic-gate * initdisp Initializes the display list 481*7c478bd9Sstevel@tonic-gate * adddisp Adds information to the display list 482*7c478bd9Sstevel@tonic-gate * genreport Generates a report from the items in the display list 483*7c478bd9Sstevel@tonic-gate * 484*7c478bd9Sstevel@tonic-gate * Datatypes Defined: 485*7c478bd9Sstevel@tonic-gate * struct display Describes the structure that contains the 486*7c478bd9Sstevel@tonic-gate * information to be displayed. Includes pointers 487*7c478bd9Sstevel@tonic-gate * to the login-ID, free-field (comment), and the 488*7c478bd9Sstevel@tonic-gate * next structure in the list. 489*7c478bd9Sstevel@tonic-gate * 490*7c478bd9Sstevel@tonic-gate * Static Data: 491*7c478bd9Sstevel@tonic-gate * displayhead Pointer to the head of the list of login-IDs to 492*7c478bd9Sstevel@tonic-gate * be displayed. Initially references the null-item 493*7c478bd9Sstevel@tonic-gate * on the head of the list. 494*7c478bd9Sstevel@tonic-gate */ 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate struct display { 497*7c478bd9Sstevel@tonic-gate char *loginID; 498*7c478bd9Sstevel@tonic-gate char *freefield; 499*7c478bd9Sstevel@tonic-gate struct display *next; 500*7c478bd9Sstevel@tonic-gate }; 501*7c478bd9Sstevel@tonic-gate 502*7c478bd9Sstevel@tonic-gate static struct display *displayhead; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * void initdisp() 506*7c478bd9Sstevel@tonic-gate * 507*7c478bd9Sstevel@tonic-gate * Initializes the display list. An empty display list contains a 508*7c478bd9Sstevel@tonic-gate * single element, the dummy element. 509*7c478bd9Sstevel@tonic-gate * 510*7c478bd9Sstevel@tonic-gate * Arguments: None 511*7c478bd9Sstevel@tonic-gate * 512*7c478bd9Sstevel@tonic-gate * Returns: Void 513*7c478bd9Sstevel@tonic-gate */ 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate static void 516*7c478bd9Sstevel@tonic-gate initdisp() 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate displayhead = (struct display *) allocblk(sizeof(struct display)); 519*7c478bd9Sstevel@tonic-gate displayhead->next = (struct display *) NULL; 520*7c478bd9Sstevel@tonic-gate displayhead->loginID = ""; 521*7c478bd9Sstevel@tonic-gate displayhead->freefield = ""; 522*7c478bd9Sstevel@tonic-gate } 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* 525*7c478bd9Sstevel@tonic-gate * void adddisp(pwent) 526*7c478bd9Sstevel@tonic-gate * struct passwd *pwent 527*7c478bd9Sstevel@tonic-gate * 528*7c478bd9Sstevel@tonic-gate * This function adds the appropriate information from the login 529*7c478bd9Sstevel@tonic-gate * description referenced by 'pwent' to the list if information 530*7c478bd9Sstevel@tonic-gate * to be displayed. It only adds the information if the login-ID 531*7c478bd9Sstevel@tonic-gate * (user-name) is unique. It inserts the information in the list 532*7c478bd9Sstevel@tonic-gate * in such a way that the list remains ordered alphabetically 533*7c478bd9Sstevel@tonic-gate * (ascending) according to the login-ID (user-name). 534*7c478bd9Sstevel@tonic-gate * 535*7c478bd9Sstevel@tonic-gate * Arguments: 536*7c478bd9Sstevel@tonic-gate * pwent Points to the (struct passwd) structure that 537*7c478bd9Sstevel@tonic-gate * contains all of the login information on the 538*7c478bd9Sstevel@tonic-gate * login being added to the list. The only 539*7c478bd9Sstevel@tonic-gate * information that this function uses is the 540*7c478bd9Sstevel@tonic-gate * login-ID (user-name) and the free-field 541*7c478bd9Sstevel@tonic-gate * (comment field). 542*7c478bd9Sstevel@tonic-gate * 543*7c478bd9Sstevel@tonic-gate * Returns: Void 544*7c478bd9Sstevel@tonic-gate */ 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate static void 547*7c478bd9Sstevel@tonic-gate adddisp(pwent) 548*7c478bd9Sstevel@tonic-gate struct passwd *pwent; 549*7c478bd9Sstevel@tonic-gate { 550*7c478bd9Sstevel@tonic-gate /* Automatic data */ 551*7c478bd9Sstevel@tonic-gate struct display *new; /* Display item being added */ 552*7c478bd9Sstevel@tonic-gate struct display *prev; /* Previous display item */ 553*7c478bd9Sstevel@tonic-gate struct display *current; /* Next display item */ 554*7c478bd9Sstevel@tonic-gate int found; /* FLAG, insertion point found */ 555*7c478bd9Sstevel@tonic-gate int compare = 1; /* strcmp() compare value */ 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate /* Find where this value belongs in the list */ 559*7c478bd9Sstevel@tonic-gate prev = displayhead; 560*7c478bd9Sstevel@tonic-gate current = displayhead->next; 561*7c478bd9Sstevel@tonic-gate found = FALSE; 562*7c478bd9Sstevel@tonic-gate while (!found && current) { 563*7c478bd9Sstevel@tonic-gate if ((compare = strcmp(current->loginID, pwent->pw_name)) >= 0) 564*7c478bd9Sstevel@tonic-gate found = TRUE; 565*7c478bd9Sstevel@tonic-gate else { 566*7c478bd9Sstevel@tonic-gate prev = current; 567*7c478bd9Sstevel@tonic-gate current = current->next; 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* Insert this value in the list, only if it is unique though */ 572*7c478bd9Sstevel@tonic-gate if (compare != 0) { 573*7c478bd9Sstevel@tonic-gate /* Build a display structure containing the value to add to the list, and add to the list */ 574*7c478bd9Sstevel@tonic-gate new = (struct display *) allocblk(sizeof(struct display)); 575*7c478bd9Sstevel@tonic-gate new->loginID = strcpy(allocstr((unsigned int) strlen(pwent->pw_name)+1), pwent->pw_name); 576*7c478bd9Sstevel@tonic-gate if (pwent->pw_comment && pwent->pw_comment[0] != '\0') 577*7c478bd9Sstevel@tonic-gate new->freefield = 578*7c478bd9Sstevel@tonic-gate strcpy(allocstr((unsigned int) 579*7c478bd9Sstevel@tonic-gate strlen(pwent->pw_comment)+1), 580*7c478bd9Sstevel@tonic-gate pwent->pw_comment); 581*7c478bd9Sstevel@tonic-gate else 582*7c478bd9Sstevel@tonic-gate new->freefield = 583*7c478bd9Sstevel@tonic-gate strcpy(allocstr((unsigned int) 584*7c478bd9Sstevel@tonic-gate strlen(pwent->pw_gecos)+1), 585*7c478bd9Sstevel@tonic-gate pwent->pw_gecos); 586*7c478bd9Sstevel@tonic-gate new->next = current; 587*7c478bd9Sstevel@tonic-gate prev->next = new; 588*7c478bd9Sstevel@tonic-gate } 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate * void genreport() 593*7c478bd9Sstevel@tonic-gate * 594*7c478bd9Sstevel@tonic-gate * This function generates a report on the standard output stream 595*7c478bd9Sstevel@tonic-gate * (stdout) containing the login-IDs and the free-fields of the 596*7c478bd9Sstevel@tonic-gate * logins that match the list criteria (-g and -l options) 597*7c478bd9Sstevel@tonic-gate * 598*7c478bd9Sstevel@tonic-gate * Arguments: None 599*7c478bd9Sstevel@tonic-gate * 600*7c478bd9Sstevel@tonic-gate * Returns: Void 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate static void 604*7c478bd9Sstevel@tonic-gate genreport() 605*7c478bd9Sstevel@tonic-gate { 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate /* Automatic data */ 608*7c478bd9Sstevel@tonic-gate struct display *current; /* Value to display */ 609*7c478bd9Sstevel@tonic-gate int i; /* Counter of characters */ 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * Initialization for loop. 613*7c478bd9Sstevel@tonic-gate * (NOTE: The first element in the list of logins to display 614*7c478bd9Sstevel@tonic-gate * is a dummy element.) 615*7c478bd9Sstevel@tonic-gate */ 616*7c478bd9Sstevel@tonic-gate current = displayhead; 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* 619*7c478bd9Sstevel@tonic-gate * Display elements in the list 620*7c478bd9Sstevel@tonic-gate */ 621*7c478bd9Sstevel@tonic-gate for (current = displayhead->next ; current ; current = current->next) { 622*7c478bd9Sstevel@tonic-gate (void) fputs(current->loginID, stdout); 623*7c478bd9Sstevel@tonic-gate for (i = LOGINFIELDSZ - strlen(current->loginID) ; --i >= 0 ; (void) putc(' ', stdout)) ; 624*7c478bd9Sstevel@tonic-gate (void) fputs(current->freefield, stdout); 625*7c478bd9Sstevel@tonic-gate (void) putc('\n', stdout); 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate 629*7c478bd9Sstevel@tonic-gate /* 630*7c478bd9Sstevel@tonic-gate * listusers [-l logins] [-g groups] 631*7c478bd9Sstevel@tonic-gate * 632*7c478bd9Sstevel@tonic-gate * This command generates a list of user login-IDs. Specific login-IDs 633*7c478bd9Sstevel@tonic-gate * can be listed, as can logins belonging in specific groups. 634*7c478bd9Sstevel@tonic-gate * 635*7c478bd9Sstevel@tonic-gate * -l logins specifies the login-IDs to display. "logins" is a 636*7c478bd9Sstevel@tonic-gate * comma-list of login-IDs. 637*7c478bd9Sstevel@tonic-gate * -g groups specifies the names of the groups to which a login-ID 638*7c478bd9Sstevel@tonic-gate * must belong before it is included in the generated list. 639*7c478bd9Sstevel@tonic-gate * "groups" is a comma-list of group names. 640*7c478bd9Sstevel@tonic-gate * Exit Codes: 641*7c478bd9Sstevel@tonic-gate * 0 All's well that ends well 642*7c478bd9Sstevel@tonic-gate * 1 Usage error 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate main(argc, argv) 646*7c478bd9Sstevel@tonic-gate int argc; 647*7c478bd9Sstevel@tonic-gate char *argv[]; 648*7c478bd9Sstevel@tonic-gate { 649*7c478bd9Sstevel@tonic-gate 650*7c478bd9Sstevel@tonic-gate /* Automatic data */ 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate struct reqgrp *reqgrphead; /* Head of the req'd group list */ 653*7c478bd9Sstevel@tonic-gate struct reqgrp *pgrp; /* Current item in the req'd group list */ 654*7c478bd9Sstevel@tonic-gate struct reqgrp *qgrp; /* Prev item in the req'd group list */ 655*7c478bd9Sstevel@tonic-gate struct reqgrp *rgrp; /* Running ptr for scanning group list */ 656*7c478bd9Sstevel@tonic-gate struct reqlogin *reqloginhead; /* Head of req'd login list */ 657*7c478bd9Sstevel@tonic-gate struct reqlogin *plogin; /* Current item in the req'd login list */ 658*7c478bd9Sstevel@tonic-gate struct reqlogin *qlogin; /* Previous item in the req'd login list */ 659*7c478bd9Sstevel@tonic-gate struct reqlogin *rlogin; /* Running ptr for scanning login list */ 660*7c478bd9Sstevel@tonic-gate struct passwd *pwent; /* Ptr to an /etc/passwd entry */ 661*7c478bd9Sstevel@tonic-gate struct group *grent; /* Ptr to an /etc/group entry */ 662*7c478bd9Sstevel@tonic-gate char *token; /* Ptr to a token extracted by strtok() */ 663*7c478bd9Sstevel@tonic-gate char **pp; /* Ptr to a member of a group */ 664*7c478bd9Sstevel@tonic-gate char *g_arg; /* Ptr to the -g option's argument */ 665*7c478bd9Sstevel@tonic-gate char *l_arg; /* Ptr to the -l option's argument */ 666*7c478bd9Sstevel@tonic-gate int g_seen; /* FLAG, true if -g on cmd */ 667*7c478bd9Sstevel@tonic-gate int l_seen; /* FLAG, TRUE if -l is on the command line */ 668*7c478bd9Sstevel@tonic-gate int errflg; /* FLAG, TRUE if there is a command-line problem */ 669*7c478bd9Sstevel@tonic-gate int done; /* FLAG, TRUE if the process (?) is complete */ 670*7c478bd9Sstevel@tonic-gate int groupcount; /* Number of groups specified by the user */ 671*7c478bd9Sstevel@tonic-gate int rc; /* Return code from strcmp() */ 672*7c478bd9Sstevel@tonic-gate int c; /* Character returned from getopt() */ 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* Initializations */ 676*7c478bd9Sstevel@tonic-gate initmsg(argv[0]); 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate /* Command-line processing */ 679*7c478bd9Sstevel@tonic-gate g_seen = FALSE; 680*7c478bd9Sstevel@tonic-gate l_seen = FALSE; 681*7c478bd9Sstevel@tonic-gate errflg = FALSE; 682*7c478bd9Sstevel@tonic-gate opterr = 0; 683*7c478bd9Sstevel@tonic-gate while (!errflg && ((c = getopt(argc, argv, "g:l:")) != EOF)) { 684*7c478bd9Sstevel@tonic-gate 685*7c478bd9Sstevel@tonic-gate /* Case on the option character */ 686*7c478bd9Sstevel@tonic-gate switch(c) { 687*7c478bd9Sstevel@tonic-gate 688*7c478bd9Sstevel@tonic-gate case 'g': 689*7c478bd9Sstevel@tonic-gate if (g_seen) errflg = TRUE; 690*7c478bd9Sstevel@tonic-gate else { 691*7c478bd9Sstevel@tonic-gate g_seen = TRUE; 692*7c478bd9Sstevel@tonic-gate g_arg = optarg; 693*7c478bd9Sstevel@tonic-gate } 694*7c478bd9Sstevel@tonic-gate break; 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate case 'l': 697*7c478bd9Sstevel@tonic-gate if (l_seen) errflg = TRUE; 698*7c478bd9Sstevel@tonic-gate else { 699*7c478bd9Sstevel@tonic-gate l_seen = TRUE; 700*7c478bd9Sstevel@tonic-gate l_arg = optarg; 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate break; 703*7c478bd9Sstevel@tonic-gate 704*7c478bd9Sstevel@tonic-gate default: 705*7c478bd9Sstevel@tonic-gate errflg = TRUE; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate /* Write out a usage message if necessary and quit */ 710*7c478bd9Sstevel@tonic-gate if (errflg || (optind != argc)) { 711*7c478bd9Sstevel@tonic-gate wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, USAGE_MSG); 712*7c478bd9Sstevel@tonic-gate exit(1); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate /* 717*7c478bd9Sstevel@tonic-gate * If the -g groups option was on the command line, build a 718*7c478bd9Sstevel@tonic-gate * list containing groups we're to list logins for. 719*7c478bd9Sstevel@tonic-gate */ 720*7c478bd9Sstevel@tonic-gate if (g_seen) { 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* Begin with an empty list */ 723*7c478bd9Sstevel@tonic-gate groupcount = 0; 724*7c478bd9Sstevel@tonic-gate reqgrphead = (struct reqgrp *) NULL; 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate /* Extract the first token putting an element on the list */ 727*7c478bd9Sstevel@tonic-gate if ((token = strtok(g_arg, ",")) != (char *) NULL) { 728*7c478bd9Sstevel@tonic-gate pgrp = (struct reqgrp *) allocblk(sizeof(struct reqgrp)); 729*7c478bd9Sstevel@tonic-gate pgrp->groupname = token; 730*7c478bd9Sstevel@tonic-gate pgrp->found = FALSE; 731*7c478bd9Sstevel@tonic-gate pgrp->next = (struct reqgrp *) NULL; 732*7c478bd9Sstevel@tonic-gate groupcount++; 733*7c478bd9Sstevel@tonic-gate reqgrphead = pgrp; 734*7c478bd9Sstevel@tonic-gate qgrp = pgrp; 735*7c478bd9Sstevel@tonic-gate 736*7c478bd9Sstevel@tonic-gate /* 737*7c478bd9Sstevel@tonic-gate * Extract subsequent tokens (group names), avoiding duplicate 738*7c478bd9Sstevel@tonic-gate * names (note, list is NOT empty) 739*7c478bd9Sstevel@tonic-gate */ 740*7c478bd9Sstevel@tonic-gate while (token = strtok((char *) NULL, ",")) { 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate /* Check for duplication */ 743*7c478bd9Sstevel@tonic-gate rgrp = reqgrphead; 744*7c478bd9Sstevel@tonic-gate while (rgrp && (rc = strcmp(token, rgrp->groupname))) rgrp = rgrp->next; 745*7c478bd9Sstevel@tonic-gate if (rc != 0) { 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* Not a duplicate. Add on the list */ 748*7c478bd9Sstevel@tonic-gate pgrp = (struct reqgrp *) allocblk(sizeof(struct reqgrp)); 749*7c478bd9Sstevel@tonic-gate pgrp->groupname = token; 750*7c478bd9Sstevel@tonic-gate pgrp->found = FALSE; 751*7c478bd9Sstevel@tonic-gate pgrp->next = (struct reqgrp *) NULL; 752*7c478bd9Sstevel@tonic-gate groupcount++; 753*7c478bd9Sstevel@tonic-gate qgrp->next = pgrp; 754*7c478bd9Sstevel@tonic-gate qgrp = pgrp; 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate /* 761*7c478bd9Sstevel@tonic-gate * If -l logins is on the command line, build a list of logins 762*7c478bd9Sstevel@tonic-gate * we're to generate reports for. 763*7c478bd9Sstevel@tonic-gate */ 764*7c478bd9Sstevel@tonic-gate if (l_seen) { 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate /* Begin with a null list */ 767*7c478bd9Sstevel@tonic-gate reqloginhead = (struct reqlogin *) NULL; 768*7c478bd9Sstevel@tonic-gate 769*7c478bd9Sstevel@tonic-gate /* Extract the first token from the argument to the -l option */ 770*7c478bd9Sstevel@tonic-gate if (token = strtok(l_arg, ",")) { 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate /* Put the first element in the list */ 773*7c478bd9Sstevel@tonic-gate plogin = (struct reqlogin *) allocblk(sizeof(struct reqlogin)); 774*7c478bd9Sstevel@tonic-gate plogin->loginname = token; 775*7c478bd9Sstevel@tonic-gate plogin->found = FALSE; 776*7c478bd9Sstevel@tonic-gate plogin->next = (struct reqlogin *) NULL; 777*7c478bd9Sstevel@tonic-gate reqloginhead = plogin; 778*7c478bd9Sstevel@tonic-gate qlogin = plogin; 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate /* 781*7c478bd9Sstevel@tonic-gate * For each subsequent token in the -l argument's 782*7c478bd9Sstevel@tonic-gate * comma list ... 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate while (token = strtok((char *) NULL, ",")) { 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* Check for duplication (list is not empty) */ 788*7c478bd9Sstevel@tonic-gate rlogin = reqloginhead; 789*7c478bd9Sstevel@tonic-gate while (rlogin && (rc = strcmp(token, rlogin->loginname))) 790*7c478bd9Sstevel@tonic-gate rlogin = rlogin->next; 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* If it's not a duplicate, add it to the list */ 793*7c478bd9Sstevel@tonic-gate if (rc != 0) { 794*7c478bd9Sstevel@tonic-gate plogin = (struct reqlogin *) allocblk(sizeof(struct reqlogin)); 795*7c478bd9Sstevel@tonic-gate plogin->loginname = token; 796*7c478bd9Sstevel@tonic-gate plogin->found = FALSE; 797*7c478bd9Sstevel@tonic-gate plogin->next = (struct reqlogin *) NULL; 798*7c478bd9Sstevel@tonic-gate qlogin->next = plogin; 799*7c478bd9Sstevel@tonic-gate qlogin = plogin; 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate } 802*7c478bd9Sstevel@tonic-gate } 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate /* 807*7c478bd9Sstevel@tonic-gate * If the user requested that only logins be listed in that belong 808*7c478bd9Sstevel@tonic-gate * to certain groups, compile a list of logins that belong in that 809*7c478bd9Sstevel@tonic-gate * group. If the user also requested specific logins, that list 810*7c478bd9Sstevel@tonic-gate * will be limited to those logins. 811*7c478bd9Sstevel@tonic-gate */ 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate /* Initialize the login list */ 814*7c478bd9Sstevel@tonic-gate initmembers(); 815*7c478bd9Sstevel@tonic-gate if (g_seen) { 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* For each group in the /etc/group file ... */ 818*7c478bd9Sstevel@tonic-gate while (grent = getgrent()) { 819*7c478bd9Sstevel@tonic-gate 820*7c478bd9Sstevel@tonic-gate /* For each group mentioned with the -g option ... */ 821*7c478bd9Sstevel@tonic-gate for (pgrp = reqgrphead ; (groupcount > 0) && pgrp ; pgrp = pgrp->next) { 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate if (pgrp->found == FALSE) { 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate /* 826*7c478bd9Sstevel@tonic-gate * If the mentioned group is found in the 827*7c478bd9Sstevel@tonic-gate * /etc/group file ... 828*7c478bd9Sstevel@tonic-gate */ 829*7c478bd9Sstevel@tonic-gate if (strcmp(grent->gr_name, pgrp->groupname) == 0) { 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate /* Mark the entry is found, remembering the 832*7c478bd9Sstevel@tonic-gate * group-ID for later */ 833*7c478bd9Sstevel@tonic-gate pgrp->found = TRUE; 834*7c478bd9Sstevel@tonic-gate groupcount--; 835*7c478bd9Sstevel@tonic-gate pgrp->groupID = grent->gr_gid; 836*7c478bd9Sstevel@tonic-gate if (isausergroup(pgrp->groupID)) 837*7c478bd9Sstevel@tonic-gate for (pp = grent->gr_mem ; *pp ; pp++) addmember(*pp); 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate } 842*7c478bd9Sstevel@tonic-gate 843*7c478bd9Sstevel@tonic-gate /* If any groups weren't found, write a message 844*7c478bd9Sstevel@tonic-gate * indicating such, then continue */ 845*7c478bd9Sstevel@tonic-gate qgrp = (struct reqgrp *) NULL; 846*7c478bd9Sstevel@tonic-gate for (pgrp = reqgrphead ; pgrp ; pgrp = pgrp->next) { 847*7c478bd9Sstevel@tonic-gate if (!pgrp->found) { 848*7c478bd9Sstevel@tonic-gate wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, "%s was not found", pgrp->groupname); 849*7c478bd9Sstevel@tonic-gate if (!qgrp) reqgrphead = pgrp->next; 850*7c478bd9Sstevel@tonic-gate else qgrp->next = pgrp->next; 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate else if (isasystemgroup(pgrp->groupID)) { 853*7c478bd9Sstevel@tonic-gate wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, "%s is not a user group", pgrp->groupname); 854*7c478bd9Sstevel@tonic-gate if (!qgrp) reqgrphead = pgrp->next; 855*7c478bd9Sstevel@tonic-gate else qgrp->next = pgrp->next; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate else qgrp = pgrp; 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate /* Initialize the list of logins to display */ 863*7c478bd9Sstevel@tonic-gate initdisp(); 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate /* 867*7c478bd9Sstevel@tonic-gate * Loop through the /etc/passwd file squirelling away the 868*7c478bd9Sstevel@tonic-gate * information we need for the display. 869*7c478bd9Sstevel@tonic-gate */ 870*7c478bd9Sstevel@tonic-gate while (pwent = getpwent()) { 871*7c478bd9Sstevel@tonic-gate 872*7c478bd9Sstevel@tonic-gate /* The login from /etc/passwd hasn't been included in 873*7c478bd9Sstevel@tonic-gate * the display yet */ 874*7c478bd9Sstevel@tonic-gate done = FALSE; 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate /* 878*7c478bd9Sstevel@tonic-gate * If the login was explicitly requested, include it in 879*7c478bd9Sstevel@tonic-gate * the display if it is a user login 880*7c478bd9Sstevel@tonic-gate */ 881*7c478bd9Sstevel@tonic-gate 882*7c478bd9Sstevel@tonic-gate if (l_seen) { 883*7c478bd9Sstevel@tonic-gate for (plogin = reqloginhead ; !done && plogin ; plogin = plogin->next) { 884*7c478bd9Sstevel@tonic-gate if (strcmp(pwent->pw_name, plogin->loginname) == 0) { 885*7c478bd9Sstevel@tonic-gate plogin->found = TRUE; 886*7c478bd9Sstevel@tonic-gate if (isauserlogin(pwent->pw_uid)) adddisp(pwent); 887*7c478bd9Sstevel@tonic-gate else 888*7c478bd9Sstevel@tonic-gate wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, 889*7c478bd9Sstevel@tonic-gate "%s is not a user login", plogin->loginname); 890*7c478bd9Sstevel@tonic-gate done = TRUE; 891*7c478bd9Sstevel@tonic-gate } 892*7c478bd9Sstevel@tonic-gate } 893*7c478bd9Sstevel@tonic-gate } 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* 897*7c478bd9Sstevel@tonic-gate * If the login-ID isn't already on the list, if its primary 898*7c478bd9Sstevel@tonic-gate * group-ID is one of those groups requested, or it is a member 899*7c478bd9Sstevel@tonic-gate * of the groups requested, include it in the display if it is 900*7c478bd9Sstevel@tonic-gate * a user login (uid >= 100). 901*7c478bd9Sstevel@tonic-gate */ 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate if (isauserlogin(pwent->pw_uid)) { 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate if (!done && g_seen) { 906*7c478bd9Sstevel@tonic-gate for (pgrp = reqgrphead ; !done && pgrp ; pgrp = pgrp->next) 907*7c478bd9Sstevel@tonic-gate if (pwent->pw_gid == pgrp->groupID) { 908*7c478bd9Sstevel@tonic-gate adddisp(pwent); 909*7c478bd9Sstevel@tonic-gate done = TRUE; 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate if (!done && isamember(pwent->pw_name)) { 912*7c478bd9Sstevel@tonic-gate adddisp(pwent); 913*7c478bd9Sstevel@tonic-gate done = TRUE; 914*7c478bd9Sstevel@tonic-gate } 915*7c478bd9Sstevel@tonic-gate } 916*7c478bd9Sstevel@tonic-gate 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate /* 919*7c478bd9Sstevel@tonic-gate * If neither -l nor -g is on the command-line and the login-ID 920*7c478bd9Sstevel@tonic-gate * is a user login, include it in the display. 921*7c478bd9Sstevel@tonic-gate */ 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate if (!l_seen && !g_seen) adddisp(pwent); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate } 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate /* Let the user know about logins they requested that don't exist */ 928*7c478bd9Sstevel@tonic-gate if (l_seen) for (plogin = reqloginhead ; plogin ; plogin = plogin->next) 929*7c478bd9Sstevel@tonic-gate if (!plogin->found) 930*7c478bd9Sstevel@tonic-gate wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG, "%s was not found", plogin->loginname); 931*7c478bd9Sstevel@tonic-gate 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate /* 934*7c478bd9Sstevel@tonic-gate * Generate a report from this display items we've squirreled away 935*7c478bd9Sstevel@tonic-gate */ 936*7c478bd9Sstevel@tonic-gate genreport(); 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate /* 939*7c478bd9Sstevel@tonic-gate * We're through! 940*7c478bd9Sstevel@tonic-gate */ 941*7c478bd9Sstevel@tonic-gate exit(0); 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate #ifdef lint 944*7c478bd9Sstevel@tonic-gate return(0); 945*7c478bd9Sstevel@tonic-gate #endif 946*7c478bd9Sstevel@tonic-gate } 947