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 "finger.h" 82 83 DB *db; 84 time_t now; 85 int entries, lflag, mflag, pplan, sflag, oflag; 86 char tbuf[1024]; 87 88 static void loginlist __P((void)); 89 static void userlist __P((int, char **)); 90 91 int 92 option(argc, argv) 93 int argc; 94 char **argv; 95 { 96 int ch; 97 98 optind = 1; /* reset getopt */ 99 100 while ((ch = getopt(argc, argv, "lmpsho")) != EOF) 101 switch(ch) { 102 case 'l': 103 lflag = 1; /* long format */ 104 break; 105 case 'm': 106 mflag = 1; /* force exact match of names */ 107 break; 108 case 'p': 109 pplan = 1; /* don't show .plan/.project */ 110 break; 111 case 's': 112 sflag = 1; /* short format */ 113 break; 114 case 'h': 115 oflag = 0; /* remote host info */ 116 break; 117 case 'o': 118 oflag = 1; /* office info */ 119 break; 120 case '?': 121 default: 122 (void)fprintf(stderr, 123 "usage: finger [-lmpsho] [login ...]\n"); 124 exit(1); 125 } 126 127 return optind; 128 } 129 130 main(argc, argv) 131 int argc; 132 char **argv; 133 { 134 int ch, envargc, argcnt; 135 char *envargv[3]; 136 137 /* remove this line to get remote host */ 138 oflag = 1; /* default to old "office" behavior */ 139 140 /* 141 * Process environment variables followed by command line arguments. 142 */ 143 if ((envargv[1] = getenv("FINGER"))) { 144 envargc = 2; 145 envargv[0] = "finger"; 146 envargv[2] = NULL; 147 (void) option(envargc, envargv); 148 } 149 150 argcnt = option(argc, argv); 151 argc -= argcnt; 152 argv += argcnt; 153 154 (void)time(&now); 155 setpassent(1); 156 if (!*argv) { 157 /* 158 * Assign explicit "small" format if no names given and -l 159 * not selected. Force the -s BEFORE we get names so proper 160 * screening will be done. 161 */ 162 if (!lflag) 163 sflag = 1; /* if -l not explicit, force -s */ 164 loginlist(); 165 if (entries == 0) 166 (void)printf("No one logged on.\n"); 167 } else { 168 userlist(argc, argv); 169 /* 170 * Assign explicit "large" format if names given and -s not 171 * explicitly stated. Force the -l AFTER we get names so any 172 * remote finger attempts specified won't be mishandled. 173 */ 174 if (!sflag) 175 lflag = 1; /* if -s not explicit, force -l */ 176 } 177 if (entries) 178 if (lflag) 179 lflag_print(); 180 else 181 sflag_print(); 182 exit(0); 183 } 184 185 static void 186 loginlist() 187 { 188 register PERSON *pn; 189 DBT data, key; 190 struct passwd *pw; 191 struct utmp user; 192 int r, sflag; 193 char name[UT_NAMESIZE + 1]; 194 195 if (!freopen(_PATH_UTMP, "r", stdin)) 196 err("%s: %s", _PATH_UTMP, strerror(errno)); 197 name[UT_NAMESIZE] = NULL; 198 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 199 if (!user.ut_name[0]) 200 continue; 201 if ((pn = find_person(user.ut_name)) == NULL) { 202 bcopy(user.ut_name, name, UT_NAMESIZE); 203 if ((pw = getpwnam(name)) == NULL) 204 continue; 205 if (hide(pw)) 206 continue; 207 pn = enter_person(pw); 208 } 209 enter_where(&user, pn); 210 } 211 if (db && lflag) 212 for (sflag = R_FIRST;; sflag = R_NEXT) { 213 r = (*db->seq)(db, &key, &data, sflag); 214 if (r == -1) 215 err("db seq: %s", strerror(errno)); 216 if (r == 1) 217 break; 218 enter_lastlog(*(PERSON **)data.data); 219 } 220 } 221 222 static void 223 userlist(argc, argv) 224 register int argc; 225 register char **argv; 226 { 227 register PERSON *pn; 228 DBT data, key; 229 struct utmp user; 230 struct passwd *pw; 231 int r, sflag, *used, *ip; 232 char **ap, **nargv, **np, **p; 233 234 if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || 235 (used = calloc(argc, sizeof(int))) == NULL) 236 err("%s", strerror(errno)); 237 238 /* Pull out all network requests. */ 239 for (ap = p = argv, np = nargv; *p; ++p) 240 if (index(*p, '@')) 241 *np++ = *p; 242 else 243 *ap++ = *p; 244 245 *np++ = NULL; 246 *ap++ = NULL; 247 248 if (!*argv) 249 goto net; 250 251 /* 252 * Traverse the list of possible login names and check the login name 253 * and real name against the name specified by the user. 254 */ 255 if (mflag) 256 for (p = argv; *p; ++p) 257 if ((pw = getpwnam(*p)) && !hide(pw)) 258 enter_person(pw); 259 else 260 (void)fprintf(stderr, 261 "finger: %s: no such user\n", *p); 262 else { 263 while (pw = getpwent()) { 264 if (hide (pw)) 265 continue; 266 for (p = argv, ip = used; *p; ++p, ++ip) 267 if (match(pw, *p)) { 268 enter_person(pw); 269 *ip = 1; 270 } 271 } 272 for (p = argv, ip = used; *p; ++p, ++ip) 273 if (!*ip) 274 (void)fprintf(stderr, 275 "finger: %s: no such user\n", *p); 276 } 277 278 /* Handle network requests. */ 279 net: for (p = nargv; *p;) { 280 netfinger(*p++); 281 if (*p || entries) 282 printf("\n"); 283 } 284 285 if (entries == 0) 286 return; 287 288 /* 289 * Scan thru the list of users currently logged in, saving 290 * appropriate data whenever a match occurs. 291 */ 292 if (!freopen(_PATH_UTMP, "r", stdin)) 293 err("%s: %s", _PATH_UTMP, strerror(errno)); 294 while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { 295 if (!user.ut_name[0]) 296 continue; 297 if ((pn = find_person(user.ut_name)) == NULL) 298 continue; 299 enter_where(&user, pn); 300 } 301 if (db) 302 for (sflag = R_FIRST;; sflag = R_NEXT) { 303 r = (*db->seq)(db, &key, &data, sflag); 304 if (r == -1) 305 err("db seq: %s", strerror(errno)); 306 if (r == 1) 307 break; 308 enter_lastlog(*(PERSON **)data.data); 309 } 310 } 311