1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char copyright[] = 13 "@(#) Copyright (c) 1989, 1993\n\ 14 The Regents of the University of California. All rights reserved.\n"; 15 #endif /* not lint */ 16 17 #ifndef lint 18 static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 05/04/95"; 19 #endif /* not lint */ 20 21 /* 22 * Finger prints out information about users. It is not portable since 23 * certain fields (e.g. the full user name, office, and phone numbers) are 24 * extracted from the gecos field of the passwd file which other UNIXes 25 * may not have or may use for other things. 26 * 27 * There are currently two output formats; the short format is one line 28 * per user and displays login name, tty, login time, real name, idle time, 29 * and office location/phone number. The long format gives the same 30 * information (in a more legible format) as well as home directory, shell, 31 * mail info, and .plan/.project files. 32 */ 33 34 #include <sys/param.h> 35 36 #include <db.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <pwd.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <time.h> 45 #include <unistd.h> 46 #include <utmp.h> 47 48 #include "finger.h" 49 50 DB *db; 51 time_t now; 52 int entries, lflag, mflag, pplan, sflag; 53 char tbuf[1024]; 54 55 static void loginlist __P((void)); 56 static void userlist __P((int, char **)); 57 58 int 59 main(argc, argv) 60 int argc; 61 char **argv; 62 { 63 int ch; 64 65 while ((ch = getopt(argc, argv, "lmps")) != EOF) 66 switch(ch) { 67 case 'l': 68 lflag = 1; /* long format */ 69 break; 70 case 'm': 71 mflag = 1; /* force exact match of names */ 72 break; 73 case 'p': 74 pplan = 1; /* don't show .plan/.project */ 75 break; 76 case 's': 77 sflag = 1; /* short format */ 78 break; 79 case '?': 80 default: 81 (void)fprintf(stderr, 82 "usage: finger [-lmps] [login ...]\n"); 83 exit(1); 84 } 85 argc -= optind; 86 argv += optind; 87 88 (void)time(&now); 89 setpassent(1); 90 if (!*argv) { 91 /* 92 * Assign explicit "small" format if no names given and -l 93 * not selected. Force the -s BEFORE we get names so proper 94 * screening will be done. 95 */ 96 if (!lflag) 97 sflag = 1; /* if -l not explicit, force -s */ 98 loginlist(); 99 if (entries == 0) 100 (void)printf("No one logged on.\n"); 101 } else { 102 userlist(argc, argv); 103 /* 104 * Assign explicit "large" format if names given and -s not 105 * explicitly stated. Force the -l AFTER we get names so any 106 * remote finger attempts specified won't be mishandled. 107 */ 108 if (!sflag) 109 lflag = 1; /* if -s not explicit, force -l */ 110 } 111 if (entries) 112 if (lflag) 113 lflag_print(); 114 else 115 sflag_print(); 116 return (0); 117 } 118 119 static void 120 loginlist() 121 { 122 register PERSON *pn; 123 DBT data, key; 124 struct passwd *pw; 125 struct utmp user; 126 int r, sflag; 127 char name[UT_NAMESIZE + 1]; 128 129 if (!freopen(_PATH_UTMP, "r", stdin)) 130 err(1, "%s", _PATH_UTMP); 131 name[UT_NAMESIZE] = NULL; 132 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 133 if (!user.ut_name[0]) 134 continue; 135 if ((pn = find_person(user.ut_name)) == NULL) { 136 bcopy(user.ut_name, name, UT_NAMESIZE); 137 if ((pw = getpwnam(name)) == NULL) 138 continue; 139 pn = enter_person(pw); 140 } 141 enter_where(&user, pn); 142 } 143 if (db && lflag) 144 for (sflag = R_FIRST;; sflag = R_NEXT) { 145 PERSON *tmp; 146 147 r = (*db->seq)(db, &key, &data, sflag); 148 if (r == -1) 149 err(1, "db seq"); 150 if (r == 1) 151 break; 152 memmove(&tmp, data.data, sizeof tmp); 153 enter_lastlog(tmp); 154 } 155 } 156 157 static void 158 userlist(argc, argv) 159 register int argc; 160 register char **argv; 161 { 162 register PERSON *pn; 163 DBT data, key; 164 struct utmp user; 165 struct passwd *pw; 166 int r, sflag, *used, *ip; 167 char **ap, **nargv, **np, **p; 168 169 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 170 (used = calloc(argc, sizeof(int))) == NULL) 171 err(1, NULL); 172 173 /* Pull out all network requests. */ 174 for (ap = p = argv, np = nargv; *p; ++p) 175 if (index(*p, '@')) 176 *np++ = *p; 177 else 178 *ap++ = *p; 179 180 *np++ = NULL; 181 *ap++ = NULL; 182 183 if (!*argv) 184 goto net; 185 186 /* 187 * Traverse the list of possible login names and check the login name 188 * and real name against the name specified by the user. 189 */ 190 if (mflag) 191 for (p = argv; *p; ++p) 192 if ((pw = getpwnam(*p)) != NULL) 193 enter_person(pw); 194 else 195 (void)fprintf(stderr, 196 "finger: %s: no such user\n", *p); 197 else { 198 while ((pw = getpwent()) != NULL) 199 for (p = argv, ip = used; *p; ++p, ++ip) 200 if (match(pw, *p)) { 201 enter_person(pw); 202 *ip = 1; 203 } 204 for (p = argv, ip = used; *p; ++p, ++ip) 205 if (!*ip) 206 (void)fprintf(stderr, 207 "finger: %s: no such user\n", *p); 208 } 209 210 /* Handle network requests. */ 211 net: for (p = nargv; *p;) 212 netfinger(*p++); 213 214 if (entries == 0) 215 return; 216 217 /* 218 * Scan thru the list of users currently logged in, saving 219 * appropriate data whenever a match occurs. 220 */ 221 if (!freopen(_PATH_UTMP, "r", stdin)) 222 err(1, "%s", _PATH_UTMP); 223 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 224 if (!user.ut_name[0]) 225 continue; 226 if ((pn = find_person(user.ut_name)) == NULL) 227 continue; 228 enter_where(&user, pn); 229 } 230 if (db) 231 for (sflag = R_FIRST;; sflag = R_NEXT) { 232 PERSON *tmp; 233 234 r = (*db->seq)(db, &key, &data, sflag); 235 if (r == -1) 236 err(1, "db seq"); 237 if (r == 1) 238 break; 239 memmove(&tmp, data.data, sizeof tmp); 240 enter_lastlog(tmp); 241 } 242 } 243