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 /* 38 * Luke Mewburn <lm@rmit.edu.au> added the following on 940622: 39 * - mail status ("No Mail", "Mail read:...", or "New Mail ..., 40 * Unread since ...".) 41 * - 4 digit phone extensions (3210 is printed as x3210.) 42 * - host/office toggling in short format with -h & -o. 43 * - short day names (`Tue' printed instead of `Jun 21' if the 44 * login time is < 6 days. 45 */ 46 47 #ifndef lint 48 static char copyright[] = 49 "@(#) Copyright (c) 1989, 1993\n\ 50 The Regents of the University of California. All rights reserved.\n"; 51 #endif /* not lint */ 52 53 #ifndef lint 54 static char sccsid[] = "@(#)finger.c 8.2 (Berkeley) 9/30/93"; 55 #endif /* not lint */ 56 57 /* 58 * Finger prints out information about users. It is not portable since 59 * certain fields (e.g. the full user name, office, and phone numbers) are 60 * extracted from the gecos field of the passwd file which other UNIXes 61 * may not have or may use for other things. 62 * 63 * There are currently two output formats; the short format is one line 64 * per user and displays login name, tty, login time, real name, idle time, 65 * and either remote host information (default) or office location/phone 66 * number, depending on if -h or -o is used respectively. 67 * The long format gives the same information (in a more legible format) as 68 * well as home directory, shell, mail info, and .plan/.project files. 69 */ 70 71 #include <sys/param.h> 72 #include <fcntl.h> 73 #include <time.h> 74 #include <pwd.h> 75 #include <utmp.h> 76 #include <errno.h> 77 #include <stdio.h> 78 #include <stdlib.h> 79 #include <string.h> 80 #include <db.h> 81 #include <locale.h> 82 #include "finger.h" 83 84 DB *db; 85 time_t now; 86 int entries, lflag, mflag, pplan, sflag, oflag, Tflag; 87 char tbuf[1024]; 88 89 static void loginlist __P((void)); 90 static void userlist __P((int, char **)); 91 92 int 93 option(argc, argv) 94 int argc; 95 char **argv; 96 { 97 int ch; 98 99 optind = 1; /* reset getopt */ 100 101 while ((ch = getopt(argc, argv, "lmpshoT")) != EOF) 102 switch(ch) { 103 case 'l': 104 lflag = 1; /* long format */ 105 break; 106 case 'm': 107 mflag = 1; /* force exact match of names */ 108 break; 109 case 'p': 110 pplan = 1; /* don't show .plan/.project */ 111 break; 112 case 's': 113 sflag = 1; /* short format */ 114 break; 115 case 'h': 116 oflag = 0; /* remote host info */ 117 break; 118 case 'o': 119 oflag = 1; /* office info */ 120 break; 121 case 'T': 122 Tflag = 1; /* disable T/TCP */ 123 break; 124 case '?': 125 default: 126 (void)fprintf(stderr, 127 "usage: finger [-lmpshoT] [login ...]\n"); 128 exit(1); 129 } 130 131 return optind; 132 } 133 134 main(argc, argv) 135 int argc; 136 char **argv; 137 { 138 int ch, envargc, argcnt; 139 char *envargv[3]; 140 141 (void) setlocale(LC_ALL, ""); 142 143 /* remove this line to get remote host */ 144 oflag = 1; /* default to old "office" behavior */ 145 146 /* 147 * Process environment variables followed by command line arguments. 148 */ 149 if ((envargv[1] = getenv("FINGER"))) { 150 envargc = 2; 151 envargv[0] = "finger"; 152 envargv[2] = NULL; 153 (void) option(envargc, envargv); 154 } 155 156 argcnt = option(argc, argv); 157 argc -= argcnt; 158 argv += argcnt; 159 160 (void)time(&now); 161 setpassent(1); 162 if (!*argv) { 163 /* 164 * Assign explicit "small" format if no names given and -l 165 * not selected. Force the -s BEFORE we get names so proper 166 * screening will be done. 167 */ 168 if (!lflag) 169 sflag = 1; /* if -l not explicit, force -s */ 170 loginlist(); 171 if (entries == 0) 172 (void)printf("No one logged on.\n"); 173 } else { 174 userlist(argc, argv); 175 /* 176 * Assign explicit "large" format if names given and -s not 177 * explicitly stated. Force the -l AFTER we get names so any 178 * remote finger attempts specified won't be mishandled. 179 */ 180 if (!sflag) 181 lflag = 1; /* if -s not explicit, force -l */ 182 } 183 if (entries) 184 if (lflag) 185 lflag_print(); 186 else 187 sflag_print(); 188 exit(0); 189 } 190 191 static void 192 loginlist() 193 { 194 register PERSON *pn; 195 DBT data, key; 196 struct passwd *pw; 197 struct utmp user; 198 int r, sflag; 199 char name[UT_NAMESIZE + 1]; 200 201 if (!freopen(_PATH_UTMP, "r", stdin)) 202 err("%s: %s", _PATH_UTMP, strerror(errno)); 203 name[UT_NAMESIZE] = NULL; 204 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 205 if (!user.ut_name[0]) 206 continue; 207 if ((pn = find_person(user.ut_name)) == NULL) { 208 bcopy(user.ut_name, name, UT_NAMESIZE); 209 if ((pw = getpwnam(name)) == NULL) 210 continue; 211 if (hide(pw)) 212 continue; 213 pn = enter_person(pw); 214 } 215 enter_where(&user, pn); 216 } 217 if (db && lflag) 218 for (sflag = R_FIRST;; sflag = R_NEXT) { 219 r = (*db->seq)(db, &key, &data, sflag); 220 if (r == -1) 221 err("db seq: %s", strerror(errno)); 222 if (r == 1) 223 break; 224 enter_lastlog(*(PERSON **)data.data); 225 } 226 } 227 228 static void 229 userlist(argc, argv) 230 register int argc; 231 register char **argv; 232 { 233 register PERSON *pn; 234 DBT data, key; 235 struct utmp user; 236 struct passwd *pw; 237 int r, sflag, *used, *ip; 238 char **ap, **nargv, **np, **p; 239 240 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 241 (used = calloc(argc, sizeof(int))) == NULL) 242 err("%s", strerror(errno)); 243 244 /* Pull out all network requests. */ 245 for (ap = p = argv, np = nargv; *p; ++p) 246 if (index(*p, '@')) 247 *np++ = *p; 248 else 249 *ap++ = *p; 250 251 *np++ = NULL; 252 *ap++ = NULL; 253 254 if (!*argv) 255 goto net; 256 257 /* 258 * Traverse the list of possible login names and check the login name 259 * and real name against the name specified by the user. 260 */ 261 if (mflag) 262 for (p = argv; *p; ++p) 263 if ((pw = getpwnam(*p)) && !hide(pw)) 264 enter_person(pw); 265 else 266 (void)fprintf(stderr, 267 "finger: %s: no such user\n", *p); 268 else { 269 while (pw = getpwent()) { 270 for (p = argv, ip = used; *p; ++p, ++ip) 271 if (match(pw, *p) && !hide(pw)) { 272 enter_person(pw); 273 *ip = 1; 274 } 275 } 276 for (p = argv, ip = used; *p; ++p, ++ip) 277 if (!*ip) 278 (void)fprintf(stderr, 279 "finger: %s: no such user\n", *p); 280 } 281 282 /* Handle network requests. */ 283 net: for (p = nargv; *p;) { 284 netfinger(*p++); 285 if (*p || entries) 286 printf("\n"); 287 } 288 289 if (entries == 0) 290 return; 291 292 /* 293 * Scan thru the list of users currently logged in, saving 294 * appropriate data whenever a match occurs. 295 */ 296 if (!freopen(_PATH_UTMP, "r", stdin)) 297 err("%s: %s", _PATH_UTMP, strerror(errno)); 298 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 299 if (!user.ut_name[0]) 300 continue; 301 if ((pn = find_person(user.ut_name)) == NULL) 302 continue; 303 enter_where(&user, pn); 304 } 305 if (db) 306 for (sflag = R_FIRST;; sflag = R_NEXT) { 307 r = (*db->seq)(db, &key, &data, sflag); 308 if (r == -1) 309 err("db seq: %s", strerror(errno)); 310 if (r == 1) 311 break; 312 enter_lastlog(*(PERSON **)data.data); 313 } 314 } 315