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 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char copyright[] = 39 "@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 static char sccsid[] = "@(#)finger.c 8.2 (Berkeley) 9/30/93"; 45 #endif /* not lint */ 46 47 /* 48 * Finger prints out information about users. It is not portable since 49 * certain fields (e.g. the full user name, office, and phone numbers) are 50 * extracted from the gecos field of the passwd file which other UNIXes 51 * may not have or may use for other things. 52 * 53 * There are currently two output formats; the short format is one line 54 * per user and displays login name, tty, login time, real name, idle time, 55 * and office location/phone number. The long format gives the same 56 * information (in a more legible format) as well as home directory, shell, 57 * mail info, and .plan/.project files. 58 */ 59 60 #include <sys/param.h> 61 #include <fcntl.h> 62 #include <time.h> 63 #include <pwd.h> 64 #include <utmp.h> 65 #include <errno.h> 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 #include <db.h> 70 #include "finger.h" 71 72 DB *db; 73 time_t now; 74 int entries, lflag, mflag, pplan, sflag; 75 char tbuf[1024]; 76 77 static void loginlist __P((void)); 78 static void userlist __P((int, char **)); 79 80 main(argc, argv) 81 int argc; 82 char **argv; 83 { 84 int ch; 85 86 while ((ch = getopt(argc, argv, "lmps")) != EOF) 87 switch(ch) { 88 case 'l': 89 lflag = 1; /* long format */ 90 break; 91 case 'm': 92 mflag = 1; /* force exact match of names */ 93 break; 94 case 'p': 95 pplan = 1; /* don't show .plan/.project */ 96 break; 97 case 's': 98 sflag = 1; /* short format */ 99 break; 100 case '?': 101 default: 102 (void)fprintf(stderr, 103 "usage: finger [-lmps] [login ...]\n"); 104 exit(1); 105 } 106 argc -= optind; 107 argv += optind; 108 109 (void)time(&now); 110 setpassent(1); 111 if (!*argv) { 112 /* 113 * Assign explicit "small" format if no names given and -l 114 * not selected. Force the -s BEFORE we get names so proper 115 * screening will be done. 116 */ 117 if (!lflag) 118 sflag = 1; /* if -l not explicit, force -s */ 119 loginlist(); 120 if (entries == 0) 121 (void)printf("No one logged on.\n"); 122 } else { 123 userlist(argc, argv); 124 /* 125 * Assign explicit "large" format if names given and -s not 126 * explicitly stated. Force the -l AFTER we get names so any 127 * remote finger attempts specified won't be mishandled. 128 */ 129 if (!sflag) 130 lflag = 1; /* if -s not explicit, force -l */ 131 } 132 if (entries) 133 if (lflag) 134 lflag_print(); 135 else 136 sflag_print(); 137 exit(0); 138 } 139 140 static void 141 loginlist() 142 { 143 register PERSON *pn; 144 DBT data, key; 145 struct passwd *pw; 146 struct utmp user; 147 int r, sflag; 148 char name[UT_NAMESIZE + 1]; 149 150 if (!freopen(_PATH_UTMP, "r", stdin)) 151 err("%s: %s", _PATH_UTMP, strerror(errno)); 152 name[UT_NAMESIZE] = NULL; 153 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 154 if (!user.ut_name[0]) 155 continue; 156 if ((pn = find_person(user.ut_name)) == NULL) { 157 bcopy(user.ut_name, name, UT_NAMESIZE); 158 if ((pw = getpwnam(name)) == NULL) 159 continue; 160 pn = enter_person(pw); 161 } 162 enter_where(&user, pn); 163 } 164 if (db && lflag) 165 for (sflag = R_FIRST;; sflag = R_NEXT) { 166 r = (*db->seq)(db, &key, &data, sflag); 167 if (r == -1) 168 err("db seq: %s", strerror(errno)); 169 if (r == 1) 170 break; 171 enter_lastlog(*(PERSON **)data.data); 172 } 173 } 174 175 static void 176 userlist(argc, argv) 177 register int argc; 178 register char **argv; 179 { 180 register PERSON *pn; 181 DBT data, key; 182 struct utmp user; 183 struct passwd *pw; 184 int r, sflag, *used, *ip; 185 char **ap, **nargv, **np, **p; 186 187 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 188 (used = calloc(argc, sizeof(int))) == NULL) 189 err("%s", strerror(errno)); 190 191 /* Pull out all network requests. */ 192 for (ap = p = argv, np = nargv; *p; ++p) 193 if (index(*p, '@')) 194 *np++ = *p; 195 else 196 *ap++ = *p; 197 198 *np++ = NULL; 199 *ap++ = NULL; 200 201 if (!*argv) 202 goto net; 203 204 /* 205 * Traverse the list of possible login names and check the login name 206 * and real name against the name specified by the user. 207 */ 208 if (mflag) 209 for (p = argv; *p; ++p) 210 if (pw = getpwnam(*p)) 211 enter_person(pw); 212 else 213 (void)fprintf(stderr, 214 "finger: %s: no such user\n", *p); 215 else { 216 while (pw = getpwent()) 217 for (p = argv, ip = used; *p; ++p, ++ip) 218 if (match(pw, *p)) { 219 enter_person(pw); 220 *ip = 1; 221 } 222 for (p = argv, ip = used; *p; ++p, ++ip) 223 if (!*ip) 224 (void)fprintf(stderr, 225 "finger: %s: no such user\n", *p); 226 } 227 228 /* Handle network requests. */ 229 net: for (p = nargv; *p;) 230 netfinger(*p++); 231 232 if (entries == 0) 233 return; 234 235 /* 236 * Scan thru the list of users currently logged in, saving 237 * appropriate data whenever a match occurs. 238 */ 239 if (!freopen(_PATH_UTMP, "r", stdin)) 240 err("%s: %s", _PATH_UTMP, strerror(errno)); 241 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 242 if (!user.ut_name[0]) 243 continue; 244 if ((pn = find_person(user.ut_name)) == NULL) 245 continue; 246 enter_where(&user, pn); 247 } 248 if (db) 249 for (sflag = R_FIRST;; sflag = R_NEXT) { 250 r = (*db->seq)(db, &key, &data, sflag); 251 if (r == -1) 252 err("db seq: %s", strerror(errno)); 253 if (r == 1) 254 break; 255 enter_lastlog(*(PERSON **)data.data); 256 } 257 } 258