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 sccsid[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include <db.h> 45 #include <pwd.h> 46 #include <utmp.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <stdio.h> 50 #include <ctype.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <paths.h> 54 #include <errno.h> 55 #include "finger.h" 56 57 static void find_idle_and_ttywrite __P((WHERE *)); 58 static void userinfo __P((PERSON *, struct passwd *)); 59 static WHERE *walloc __P((PERSON *)); 60 61 int 62 match(pw, user) 63 struct passwd *pw; 64 char *user; 65 { 66 register char *p, *t; 67 char name[1024]; 68 69 if (!strcasecmp(pw->pw_name, user)) 70 return(1); 71 72 /* 73 * XXX 74 * Why do we skip asterisks!?!? 75 */ 76 (void)strcpy(p = tbuf, pw->pw_gecos); 77 if (*p == '*') 78 ++p; 79 80 /* Ampersands get replaced by the login name. */ 81 if ((p = strtok(p, ",")) == NULL) 82 return(0); 83 84 for (t = name; *t = *p; ++p) 85 if (*t == '&') { 86 (void)strcpy(t, pw->pw_name); 87 while (*++t); 88 } 89 else 90 ++t; 91 for (t = name; p = strtok(t, "\t "); t = NULL) 92 if (!strcasecmp(p, user)) 93 return(1); 94 return(0); 95 } 96 97 void 98 enter_lastlog(pn) 99 register PERSON *pn; 100 { 101 register WHERE *w; 102 static int opened, fd; 103 struct lastlog ll; 104 char doit = 0; 105 106 /* some systems may not maintain lastlog, don't report errors. */ 107 if (!opened) { 108 fd = open(_PATH_LASTLOG, O_RDONLY, 0); 109 opened = 1; 110 } 111 if (fd == -1 || 112 lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 113 (long)pn->uid * sizeof(ll) || 114 read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 115 /* as if never logged in */ 116 ll.ll_line[0] = ll.ll_host[0] = NULL; 117 ll.ll_time = 0; 118 } 119 if ((w = pn->whead) == NULL) 120 doit = 1; 121 else if (ll.ll_time != 0) { 122 /* if last login is earlier than some current login */ 123 for (; !doit && w != NULL; w = w->next) 124 if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 125 doit = 1; 126 /* 127 * and if it's not any of the current logins 128 * can't use time comparison because there may be a small 129 * discrepency since login calls time() twice 130 */ 131 for (w = pn->whead; doit && w != NULL; w = w->next) 132 if (w->info == LOGGEDIN && 133 strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 134 doit = 0; 135 } 136 if (doit) { 137 w = walloc(pn); 138 w->info = LASTLOG; 139 bcopy(ll.ll_line, w->tty, UT_LINESIZE); 140 w->tty[UT_LINESIZE] = 0; 141 bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 142 w->host[UT_HOSTSIZE] = 0; 143 w->loginat = ll.ll_time; 144 } 145 } 146 147 void 148 enter_where(ut, pn) 149 struct utmp *ut; 150 PERSON *pn; 151 { 152 register WHERE *w; 153 154 w = walloc(pn); 155 w->info = LOGGEDIN; 156 bcopy(ut->ut_line, w->tty, UT_LINESIZE); 157 w->tty[UT_LINESIZE] = 0; 158 bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 159 w->host[UT_HOSTSIZE] = 0; 160 w->loginat = (time_t)ut->ut_time; 161 find_idle_and_ttywrite(w); 162 } 163 164 PERSON * 165 enter_person(pw) 166 register struct passwd *pw; 167 { 168 DBT data, key; 169 PERSON *pn; 170 171 if (db == NULL && 172 (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 173 err("%s", strerror(errno)); 174 175 key.data = pw->pw_name; 176 key.size = strlen(pw->pw_name); 177 178 switch((*db->get)(db, &key, &data, 0)) { 179 case 0: 180 return(*(PERSON **)data.data); 181 default: 182 case -1: 183 err("db get: %s", strerror(errno)); 184 /* NOTREACHED */ 185 case 1: 186 ++entries; 187 pn = palloc(); 188 userinfo(pn, pw); 189 pn->whead = NULL; 190 191 data.size = sizeof(PERSON *); 192 data.data = &pn; 193 if ((*db->put)(db, &key, &data, 0)) 194 err("%s", strerror(errno)); 195 return(pn); 196 } 197 } 198 199 PERSON * 200 find_person(name) 201 char *name; 202 { 203 struct passwd *pw; 204 205 register int cnt; 206 DBT data, key; 207 char buf[UT_NAMESIZE + 1]; 208 209 if (!db) 210 return(NULL); 211 212 if ((pw = getpwnam(name)) && hide(pw)) 213 return(NULL); 214 215 /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 216 for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 217 buf[cnt] = *name; 218 buf[cnt] = '\0'; 219 key.data = buf; 220 key.size = cnt; 221 222 return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 223 } 224 225 PERSON * 226 palloc() 227 { 228 PERSON *p; 229 230 if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 231 err("%s", strerror(errno)); 232 return(p); 233 } 234 235 static WHERE * 236 walloc(pn) 237 register PERSON *pn; 238 { 239 register WHERE *w; 240 241 if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 242 err("%s", strerror(errno)); 243 if (pn->whead == NULL) 244 pn->whead = pn->wtail = w; 245 else { 246 pn->wtail->next = w; 247 pn->wtail = w; 248 } 249 w->next = NULL; 250 return(w); 251 } 252 253 char * 254 prphone(num) 255 char *num; 256 { 257 register char *p; 258 int len; 259 static char pbuf[15]; 260 261 /* don't touch anything if the user has their own formatting */ 262 for (p = num; *p; ++p) 263 if (!isdigit(*p)) 264 return(num); 265 len = p - num; 266 p = pbuf; 267 switch(len) { 268 case 11: /* +0-123-456-7890 */ 269 *p++ = '+'; 270 *p++ = *num++; 271 *p++ = '-'; 272 /* FALLTHROUGH */ 273 case 10: /* 012-345-6789 */ 274 *p++ = *num++; 275 *p++ = *num++; 276 *p++ = *num++; 277 *p++ = '-'; 278 /* FALLTHROUGH */ 279 case 7: /* 012-3456 */ 280 *p++ = *num++; 281 *p++ = *num++; 282 *p++ = *num++; 283 break; 284 case 5: /* x0-1234 */ 285 case 4: /* x1234 */ 286 *p++ = 'x'; 287 *p++ = *num++; 288 break; 289 default: 290 return(num); 291 } 292 if (len != 4) { 293 *p++ = '-'; 294 *p++ = *num++; 295 } 296 *p++ = *num++; 297 *p++ = *num++; 298 *p++ = *num++; 299 *p = '\0'; 300 return(pbuf); 301 } 302 303 static void 304 find_idle_and_ttywrite(w) 305 register WHERE *w; 306 { 307 extern time_t now; 308 struct stat sb; 309 310 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 311 if (stat(tbuf, &sb) < 0) { 312 (void)fprintf(stderr, 313 "finger: %s: %s\n", tbuf, strerror(errno)); 314 return; 315 } 316 w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 317 318 #define TALKABLE 0220 /* tty is writable if 220 mode */ 319 w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 320 } 321 322 static void 323 userinfo(pn, pw) 324 register PERSON *pn; 325 register struct passwd *pw; 326 { 327 register char *p, *t; 328 char *bp, name[1024]; 329 struct stat sb; 330 331 pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 332 333 pn->uid = pw->pw_uid; 334 pn->name = strdup(pw->pw_name); 335 pn->dir = strdup(pw->pw_dir); 336 pn->shell = strdup(pw->pw_shell); 337 338 /* why do we skip asterisks!?!? */ 339 (void)strcpy(bp = tbuf, pw->pw_gecos); 340 if (*bp == '*') 341 ++bp; 342 343 /* ampersands get replaced by the login name */ 344 if (!(p = strsep(&bp, ","))) 345 return; 346 for (t = name; *t = *p; ++p) 347 if (*t == '&') { 348 (void)strcpy(t, pw->pw_name); 349 if (islower(*t)) 350 *t = toupper(*t); 351 while (*++t); 352 } 353 else 354 ++t; 355 pn->realname = strdup(name); 356 pn->office = ((p = strsep(&bp, ",")) && *p) ? 357 strdup(p) : NULL; 358 pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 359 strdup(p) : NULL; 360 pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 361 strdup(p) : NULL; 362 (void)sprintf(tbuf,"%s/%s", _PATH_MAILDIR, pw->pw_name); 363 pn->mailrecv = -1; /* -1 == not_valid */ 364 if (stat(tbuf, &sb) < 0) { 365 if (errno != ENOENT) { 366 (void)fprintf(stderr, 367 "finger: %s: %s\n", tbuf, strerror(errno)); 368 return; 369 } 370 } else if (sb.st_size != 0) { 371 pn->mailrecv = sb.st_mtime; 372 pn->mailread = sb.st_atime; 373 } 374 } 375 376 #if __STDC__ 377 #include <stdarg.h> 378 #else 379 #include <varargs.h> 380 #endif 381 382 void 383 #if __STDC__ 384 err(const char *fmt, ...) 385 #else 386 err(fmt, va_alist) 387 char *fmt; 388 va_dcl 389 #endif 390 { 391 va_list ap; 392 #if __STDC__ 393 va_start(ap, fmt); 394 #else 395 va_start(ap); 396 #endif 397 (void)fprintf(stderr, "finger: "); 398 (void)vfprintf(stderr, fmt, ap); 399 va_end(ap); 400 (void)fprintf(stderr, "\n"); 401 exit(1); 402 /* NOTREACHED */ 403 } 404 405 /* 406 * Is this user hiding from finger? 407 * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 408 */ 409 410 int 411 hide(pw) 412 struct passwd *pw; 413 { 414 int fd; 415 char buf[MAXPATHLEN+1]; 416 417 if (!pw->pw_dir) 418 return 0; 419 420 sprintf (buf, "%s/.nofinger", pw->pw_dir); 421 422 if (access (buf, F_OK) == 0) 423 return 1; 424 425 return 0; 426 } 427