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.4 (Berkeley) 04/28/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 #include <fcntl.h> 36 #include <time.h> 37 #include <pwd.h> 38 #include <utmp.h> 39 #include <errno.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <db.h> 44 #include <err.h> 45 #include "finger.h" 46 47 DB *db; 48 time_t now; 49 int entries, lflag, mflag, pplan, sflag; 50 char tbuf[1024]; 51 52 static void loginlist __P((void)); 53 static void userlist __P((int, char **)); 54 55 int 56 main(argc, argv) 57 int argc; 58 char **argv; 59 { 60 int ch; 61 62 while ((ch = getopt(argc, argv, "lmps")) != EOF) 63 switch(ch) { 64 case 'l': 65 lflag = 1; /* long format */ 66 break; 67 case 'm': 68 mflag = 1; /* force exact match of names */ 69 break; 70 case 'p': 71 pplan = 1; /* don't show .plan/.project */ 72 break; 73 case 's': 74 sflag = 1; /* short format */ 75 break; 76 case '?': 77 default: 78 (void)fprintf(stderr, 79 "usage: finger [-lmps] [login ...]\n"); 80 exit(1); 81 } 82 argc -= optind; 83 argv += optind; 84 85 (void)time(&now); 86 setpassent(1); 87 if (!*argv) { 88 /* 89 * Assign explicit "small" format if no names given and -l 90 * not selected. Force the -s BEFORE we get names so proper 91 * screening will be done. 92 */ 93 if (!lflag) 94 sflag = 1; /* if -l not explicit, force -s */ 95 loginlist(); 96 if (entries == 0) 97 (void)printf("No one logged on.\n"); 98 } else { 99 userlist(argc, argv); 100 /* 101 * Assign explicit "large" format if names given and -s not 102 * explicitly stated. Force the -l AFTER we get names so any 103 * remote finger attempts specified won't be mishandled. 104 */ 105 if (!sflag) 106 lflag = 1; /* if -s not explicit, force -l */ 107 } 108 if (entries) 109 if (lflag) 110 lflag_print(); 111 else 112 sflag_print(); 113 return (0); 114 } 115 116 static void 117 loginlist() 118 { 119 register PERSON *pn; 120 DBT data, key; 121 struct passwd *pw; 122 struct utmp user; 123 int r, sflag; 124 char name[UT_NAMESIZE + 1]; 125 126 if (!freopen(_PATH_UTMP, "r", stdin)) 127 err(1, "%s", _PATH_UTMP); 128 name[UT_NAMESIZE] = NULL; 129 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 130 if (!user.ut_name[0]) 131 continue; 132 if ((pn = find_person(user.ut_name)) == NULL) { 133 bcopy(user.ut_name, name, UT_NAMESIZE); 134 if ((pw = getpwnam(name)) == NULL) 135 continue; 136 pn = enter_person(pw); 137 } 138 enter_where(&user, pn); 139 } 140 if (db && lflag) 141 for (sflag = R_FIRST;; sflag = R_NEXT) { 142 PERSON *tmp; 143 144 r = (*db->seq)(db, &key, &data, sflag); 145 if (r == -1) 146 err(1, "db seq"); 147 if (r == 1) 148 break; 149 memmove(&tmp, data.data, sizeof tmp); 150 enter_lastlog(tmp); 151 } 152 } 153 154 static void 155 userlist(argc, argv) 156 register int argc; 157 register char **argv; 158 { 159 register PERSON *pn; 160 DBT data, key; 161 struct utmp user; 162 struct passwd *pw; 163 int r, sflag, *used, *ip; 164 char **ap, **nargv, **np, **p; 165 166 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 167 (used = calloc(argc, sizeof(int))) == NULL) 168 err(1, NULL); 169 170 /* Pull out all network requests. */ 171 for (ap = p = argv, np = nargv; *p; ++p) 172 if (index(*p, '@')) 173 *np++ = *p; 174 else 175 *ap++ = *p; 176 177 *np++ = NULL; 178 *ap++ = NULL; 179 180 if (!*argv) 181 goto net; 182 183 /* 184 * Traverse the list of possible login names and check the login name 185 * and real name against the name specified by the user. 186 */ 187 if (mflag) 188 for (p = argv; *p; ++p) 189 if ((pw = getpwnam(*p)) != NULL) 190 enter_person(pw); 191 else 192 (void)fprintf(stderr, 193 "finger: %s: no such user\n", *p); 194 else { 195 while ((pw = getpwent()) != NULL) 196 for (p = argv, ip = used; *p; ++p, ++ip) 197 if (match(pw, *p)) { 198 enter_person(pw); 199 *ip = 1; 200 } 201 for (p = argv, ip = used; *p; ++p, ++ip) 202 if (!*ip) 203 (void)fprintf(stderr, 204 "finger: %s: no such user\n", *p); 205 } 206 207 /* Handle network requests. */ 208 net: for (p = nargv; *p;) 209 netfinger(*p++); 210 211 if (entries == 0) 212 return; 213 214 /* 215 * Scan thru the list of users currently logged in, saving 216 * appropriate data whenever a match occurs. 217 */ 218 if (!freopen(_PATH_UTMP, "r", stdin)) 219 err(1, "%s", _PATH_UTMP); 220 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 221 if (!user.ut_name[0]) 222 continue; 223 if ((pn = find_person(user.ut_name)) == NULL) 224 continue; 225 enter_where(&user, pn); 226 } 227 if (db) 228 for (sflag = R_FIRST;; sflag = R_NEXT) { 229 PERSON *tmp; 230 231 r = (*db->seq)(db, &key, &data, sflag); 232 if (r == -1) 233 err(1, "db seq"); 234 if (r == 1) 235 break; 236 memmove(&tmp, data.data, sizeof tmp); 237 enter_lastlog(tmp); 238 } 239 } 240