1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)finger.c 5.16 (Berkeley) 05/11/89"; 26 #endif /* not lint */ 27 28 /* 29 * Finger prints out information about users. It is not portable since 30 * certain fields (e.g. the full user name, office, and phone numbers) are 31 * extracted from the gecos field of the passwd file which other UNIXes 32 * may not have or may use for other things. 33 * 34 * There are currently two output formats; the short format is one line 35 * per user and displays login name, tty, login time, real name, idle time, 36 * and office location/phone number. The long format gives the same 37 * information (in a more legible format) as well as home directory, shell, 38 * mail info, and .plan/.project files. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/file.h> 43 #include <stdio.h> 44 #include "finger.h" 45 #include "pathnames.h" 46 47 time_t now; 48 int lflag, sflag, mflag, pplan; 49 char tbuf[1024]; 50 51 main(argc, argv) 52 int argc; 53 char **argv; 54 { 55 extern int optind; 56 int ch; 57 time_t time(); 58 59 while ((ch = getopt(argc, argv, "lmps")) != EOF) 60 switch(ch) { 61 case 'l': 62 lflag = 1; /* long format */ 63 break; 64 case 'm': 65 mflag = 1; /* force exact match of names */ 66 break; 67 case 'p': 68 pplan = 1; /* don't show .plan/.project */ 69 break; 70 case 's': 71 sflag = 1; /* short format */ 72 break; 73 case '?': 74 default: 75 (void)fprintf(stderr, 76 "usage: finger [-lmps] [login ...]\n"); 77 exit(1); 78 } 79 argc -= optind; 80 argv += optind; 81 82 (void)time(&now); 83 setpassent(1); 84 if (!*argv) { 85 /* 86 * Assign explicit "small" format if no names given and -l 87 * not selected. Force the -s BEFORE we get names so proper 88 * screening will be done. 89 */ 90 if (!lflag) 91 sflag = 1; /* if -l not explicit, force -s */ 92 loginlist(); 93 if (entries == 0) 94 (void)printf("No one logged on.\n"); 95 } else { 96 userlist(argv); 97 /* 98 * Assign explicit "large" format if names given and -s not 99 * explicitly stated. Force the -l AFTER we get names so any 100 * remote finger attempts specified won't be mishandled. 101 */ 102 if (!sflag) 103 lflag = 1; /* if -s not explicit, force -l */ 104 } 105 if (entries != 0) { 106 if (lflag) 107 lflag_print(); 108 else 109 sflag_print(); 110 } 111 exit(0); 112 } 113 114 loginlist() 115 { 116 register PERSON *pn; 117 register int fd; 118 struct passwd *pw; 119 struct utmp user; 120 char name[UT_NAMESIZE + 1]; 121 122 if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 123 (void)fprintf(stderr, "finger: can't read %s.\n", _PATH_UTMP); 124 exit(2); 125 } 126 name[UT_NAMESIZE] = NULL; 127 while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) { 128 if (!user.ut_name[0]) 129 continue; 130 if ((pn = find_person(user.ut_name)) == NULL) { 131 bcopy(user.ut_name, name, UT_NAMESIZE); 132 if ((pw = getpwnam(name)) == NULL) 133 continue; 134 pn = enter_person(pw); 135 } 136 enter_where(&user, pn); 137 } 138 (void)close(fd); 139 for (pn = phead; lflag && pn != NULL; pn = pn->next) 140 enter_lastlog(pn); 141 } 142 143 #define ARGIGNORE (char *)0x01 144 145 userlist(argv) 146 char **argv; 147 { 148 register char **ap; 149 register PERSON *pn; 150 PERSON *nethead; 151 struct utmp user; 152 struct passwd *pw; 153 int fd, dolocal, *used, *index(); 154 155 /* pull out all network requests */ 156 for (ap = argv, dolocal = 0, nethead = NULL; *ap; ap++) { 157 if (!index(*ap, '@')) { 158 dolocal = 1; 159 continue; 160 } 161 pn = palloc(); 162 pn->next = nethead; 163 nethead = pn; 164 pn->name = *ap; 165 *ap = ARGIGNORE; 166 } 167 168 if (!dolocal) 169 goto net; 170 171 if (!(used = (int *)calloc((u_int)(ap - argv), (u_int)sizeof(int)))) { 172 (void)fprintf(stderr, "finger: out of space.\n"); 173 exit(1); 174 } 175 176 /* 177 * traverse the list of possible login names and check the login name 178 * and real name against the name specified by the user. 179 */ 180 if (mflag) { 181 for (ap = argv; *ap; ap++) 182 if (*ap != ARGIGNORE && (pw = getpwnam(*ap))) { 183 enter_person(pw); 184 used[ap - argv] = 1; 185 } 186 } else while (pw = getpwent()) 187 for (ap = argv; *ap; ap++) 188 if (*ap != ARGIGNORE && 189 (!strcasecmp(pw->pw_name, *ap) || match(pw, *ap))) { 190 enter_person(pw); 191 used[ap - argv] = 1; 192 } 193 194 /* list errors */ 195 for (ap = argv; *ap; ap++) 196 if (*ap != ARGIGNORE && !used[ap - argv]) 197 (void)fprintf(stderr, 198 "finger: %s: no such user.\n", *ap); 199 200 /* handle network requests */ 201 net: for (pn = nethead; pn; pn = pn->next) { 202 netfinger(pn->name); 203 if (pn->next || entries) 204 putchar('\n'); 205 } 206 207 if (entries == 0) 208 return; 209 210 /* 211 * Scan thru the list of users currently logged in, saving 212 * appropriate data whenever a match occurs. 213 */ 214 if ((fd = open(_PATH_UTMP, O_RDONLY, 0)) < 0) { 215 (void)fprintf( stderr, "finger: can't read %s.\n", _PATH_UTMP); 216 exit(1); 217 } 218 while (read(fd, (char *)&user, sizeof(user)) == sizeof(user)) { 219 if (!user.ut_name[0]) 220 continue; 221 if ((pn = find_person(user.ut_name)) == NULL) 222 continue; 223 enter_where(&user, pn); 224 } 225 (void)close(fd); 226 for (pn = phead; pn != NULL; pn = pn->next) 227 enter_lastlog(pn); 228 } 229