util.c revision 62891
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1989, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * This code is derived from software contributed to Berkeley by 61590Srgrimes * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 71590Srgrimes * 81590Srgrimes * Redistribution and use in source and binary forms, with or without 91590Srgrimes * modification, are permitted provided that the following conditions 101590Srgrimes * are met: 111590Srgrimes * 1. Redistributions of source code must retain the above copyright 121590Srgrimes * notice, this list of conditions and the following disclaimer. 131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141590Srgrimes * notice, this list of conditions and the following disclaimer in the 151590Srgrimes * documentation and/or other materials provided with the distribution. 161590Srgrimes * 3. All advertising materials mentioning features or use of this software 171590Srgrimes * must display the following acknowledgement: 181590Srgrimes * This product includes software developed by the University of 191590Srgrimes * California, Berkeley and its contributors. 201590Srgrimes * 4. Neither the name of the University nor the names of its contributors 211590Srgrimes * may be used to endorse or promote products derived from this software 221590Srgrimes * without specific prior written permission. 231590Srgrimes * 241590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341590Srgrimes * SUCH DAMAGE. 351590Srgrimes */ 361590Srgrimes 371590Srgrimes#ifndef lint 3827169Scharnier#if 0 3923693Speterstatic char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; 4027169Scharnier#else 4127169Scharnierstatic const char rcsid[] = 4250477Speter "$FreeBSD: head/usr.bin/finger/util.c 62891 2000-07-10 08:49:28Z kris $"; 4327169Scharnier#endif 441590Srgrimes#endif /* not lint */ 451590Srgrimes 461590Srgrimes#include <sys/param.h> 471590Srgrimes#include <sys/stat.h> 481590Srgrimes#include <fcntl.h> 491590Srgrimes#include <db.h> 5023693Speter#include <err.h> 511590Srgrimes#include <pwd.h> 521590Srgrimes#include <utmp.h> 531590Srgrimes#include <errno.h> 541590Srgrimes#include <unistd.h> 551590Srgrimes#include <stdio.h> 561590Srgrimes#include <ctype.h> 571590Srgrimes#include <stdlib.h> 581590Srgrimes#include <string.h> 591590Srgrimes#include <paths.h> 602537Spst#include <errno.h> 611590Srgrimes#include "finger.h" 621590Srgrimes 631590Srgrimesstatic void find_idle_and_ttywrite __P((WHERE *)); 641590Srgrimesstatic void userinfo __P((PERSON *, struct passwd *)); 651590Srgrimesstatic WHERE *walloc __P((PERSON *)); 661590Srgrimes 671590Srgrimesint 681590Srgrimesmatch(pw, user) 691590Srgrimes struct passwd *pw; 701590Srgrimes char *user; 711590Srgrimes{ 721590Srgrimes register char *p, *t; 731590Srgrimes char name[1024]; 741590Srgrimes 751590Srgrimes if (!strcasecmp(pw->pw_name, user)) 761590Srgrimes return(1); 771590Srgrimes 781590Srgrimes /* 791590Srgrimes * XXX 801590Srgrimes * Why do we skip asterisks!?!? 811590Srgrimes */ 8250127Simp (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); 8350167Simp tbuf[sizeof(tbuf) - 1] = '\0'; 841590Srgrimes if (*p == '*') 851590Srgrimes ++p; 861590Srgrimes 871590Srgrimes /* Ampersands get replaced by the login name. */ 881590Srgrimes if ((p = strtok(p, ",")) == NULL) 891590Srgrimes return(0); 901590Srgrimes 9150167Simp for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 9250127Simp if (*t == '&') { 9350127Simp (void)strncpy(t, pw->pw_name, 9450127Simp sizeof(name) - (t - name)); 9550127Simp name[sizeof(name) - 1] = '\0'; 9650167Simp while (t < &name[sizeof(name) - 1] && *++t) 9750167Simp continue; 9850127Simp } else { 9950127Simp ++t; 1001590Srgrimes } 10150127Simp } 10250127Simp *t = '\0'; 10323693Speter for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) 1041590Srgrimes if (!strcasecmp(p, user)) 1051590Srgrimes return(1); 1061590Srgrimes return(0); 1071590Srgrimes} 1081590Srgrimes 1091590Srgrimesvoid 1101590Srgrimesenter_lastlog(pn) 1111590Srgrimes register PERSON *pn; 1121590Srgrimes{ 1131590Srgrimes register WHERE *w; 1141590Srgrimes static int opened, fd; 1151590Srgrimes struct lastlog ll; 1161590Srgrimes char doit = 0; 1171590Srgrimes 1181590Srgrimes /* some systems may not maintain lastlog, don't report errors. */ 1191590Srgrimes if (!opened) { 1201590Srgrimes fd = open(_PATH_LASTLOG, O_RDONLY, 0); 1211590Srgrimes opened = 1; 1221590Srgrimes } 1231590Srgrimes if (fd == -1 || 1241590Srgrimes lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 1251590Srgrimes (long)pn->uid * sizeof(ll) || 1261590Srgrimes read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 1271590Srgrimes /* as if never logged in */ 12827169Scharnier ll.ll_line[0] = ll.ll_host[0] = '\0'; 1291590Srgrimes ll.ll_time = 0; 1301590Srgrimes } 1311590Srgrimes if ((w = pn->whead) == NULL) 1321590Srgrimes doit = 1; 1331590Srgrimes else if (ll.ll_time != 0) { 1341590Srgrimes /* if last login is earlier than some current login */ 1351590Srgrimes for (; !doit && w != NULL; w = w->next) 1361590Srgrimes if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 1371590Srgrimes doit = 1; 1381590Srgrimes /* 1391590Srgrimes * and if it's not any of the current logins 1401590Srgrimes * can't use time comparison because there may be a small 1411590Srgrimes * discrepency since login calls time() twice 1421590Srgrimes */ 1431590Srgrimes for (w = pn->whead; doit && w != NULL; w = w->next) 1441590Srgrimes if (w->info == LOGGEDIN && 1451590Srgrimes strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 1461590Srgrimes doit = 0; 1471590Srgrimes } 1481590Srgrimes if (doit) { 1491590Srgrimes w = walloc(pn); 1501590Srgrimes w->info = LASTLOG; 1511590Srgrimes bcopy(ll.ll_line, w->tty, UT_LINESIZE); 1521590Srgrimes w->tty[UT_LINESIZE] = 0; 1531590Srgrimes bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 1541590Srgrimes w->host[UT_HOSTSIZE] = 0; 1551590Srgrimes w->loginat = ll.ll_time; 1561590Srgrimes } 1571590Srgrimes} 1581590Srgrimes 1591590Srgrimesvoid 1601590Srgrimesenter_where(ut, pn) 1611590Srgrimes struct utmp *ut; 1621590Srgrimes PERSON *pn; 1631590Srgrimes{ 1641590Srgrimes register WHERE *w; 1651590Srgrimes 1661590Srgrimes w = walloc(pn); 1671590Srgrimes w->info = LOGGEDIN; 1681590Srgrimes bcopy(ut->ut_line, w->tty, UT_LINESIZE); 1691590Srgrimes w->tty[UT_LINESIZE] = 0; 1701590Srgrimes bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 1711590Srgrimes w->host[UT_HOSTSIZE] = 0; 1721590Srgrimes w->loginat = (time_t)ut->ut_time; 1731590Srgrimes find_idle_and_ttywrite(w); 1741590Srgrimes} 1751590Srgrimes 1761590SrgrimesPERSON * 1771590Srgrimesenter_person(pw) 1781590Srgrimes register struct passwd *pw; 1791590Srgrimes{ 1801590Srgrimes DBT data, key; 1811590Srgrimes PERSON *pn; 1821590Srgrimes 1831590Srgrimes if (db == NULL && 1841590Srgrimes (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 18523693Speter err(1, NULL); 1861590Srgrimes 1871590Srgrimes key.data = pw->pw_name; 1881590Srgrimes key.size = strlen(pw->pw_name); 1891590Srgrimes 19023693Speter switch ((*db->get)(db, &key, &data, 0)) { 1911590Srgrimes case 0: 19223693Speter memmove(&pn, data.data, sizeof pn); 19323693Speter return (pn); 1941590Srgrimes default: 1951590Srgrimes case -1: 19623693Speter err(1, "db get"); 1971590Srgrimes /* NOTREACHED */ 1981590Srgrimes case 1: 1991590Srgrimes ++entries; 2001590Srgrimes pn = palloc(); 2011590Srgrimes userinfo(pn, pw); 2021590Srgrimes pn->whead = NULL; 2031590Srgrimes 2041590Srgrimes data.size = sizeof(PERSON *); 2051590Srgrimes data.data = &pn; 2061590Srgrimes if ((*db->put)(db, &key, &data, 0)) 20723693Speter err(1, "db put"); 20823693Speter return (pn); 2091590Srgrimes } 2101590Srgrimes} 2111590Srgrimes 2121590SrgrimesPERSON * 2131590Srgrimesfind_person(name) 2141590Srgrimes char *name; 2151590Srgrimes{ 2165369Sjkh struct passwd *pw; 2175369Sjkh 2181590Srgrimes register int cnt; 2191590Srgrimes DBT data, key; 22023693Speter PERSON *p; 2211590Srgrimes char buf[UT_NAMESIZE + 1]; 2221590Srgrimes 2231590Srgrimes if (!db) 2241590Srgrimes return(NULL); 2251590Srgrimes 2265369Sjkh if ((pw = getpwnam(name)) && hide(pw)) 2275369Sjkh return(NULL); 2285369Sjkh 2291590Srgrimes /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 2301590Srgrimes for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 2311590Srgrimes buf[cnt] = *name; 2321590Srgrimes buf[cnt] = '\0'; 2331590Srgrimes key.data = buf; 2341590Srgrimes key.size = cnt; 2351590Srgrimes 23623693Speter if ((*db->get)(db, &key, &data, 0)) 23723693Speter return (NULL); 23823693Speter memmove(&p, data.data, sizeof p); 23923693Speter return (p); 2401590Srgrimes} 2411590Srgrimes 2421590SrgrimesPERSON * 2431590Srgrimespalloc() 2441590Srgrimes{ 2451590Srgrimes PERSON *p; 2461590Srgrimes 2471590Srgrimes if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 24823693Speter err(1, NULL); 2491590Srgrimes return(p); 2501590Srgrimes} 2511590Srgrimes 2521590Srgrimesstatic WHERE * 2531590Srgrimeswalloc(pn) 2541590Srgrimes register PERSON *pn; 2551590Srgrimes{ 2561590Srgrimes register WHERE *w; 2571590Srgrimes 2581590Srgrimes if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 25923693Speter err(1, NULL); 2601590Srgrimes if (pn->whead == NULL) 2611590Srgrimes pn->whead = pn->wtail = w; 2621590Srgrimes else { 2631590Srgrimes pn->wtail->next = w; 2641590Srgrimes pn->wtail = w; 2651590Srgrimes } 2661590Srgrimes w->next = NULL; 2671590Srgrimes return(w); 2681590Srgrimes} 2691590Srgrimes 2701590Srgrimeschar * 2711590Srgrimesprphone(num) 2721590Srgrimes char *num; 2731590Srgrimes{ 2741590Srgrimes register char *p; 2751590Srgrimes int len; 27650127Simp static char pbuf[20]; 2771590Srgrimes 2781590Srgrimes /* don't touch anything if the user has their own formatting */ 2791590Srgrimes for (p = num; *p; ++p) 2801590Srgrimes if (!isdigit(*p)) 2811590Srgrimes return(num); 2821590Srgrimes len = p - num; 2831590Srgrimes p = pbuf; 2841590Srgrimes switch(len) { 2851590Srgrimes case 11: /* +0-123-456-7890 */ 2861590Srgrimes *p++ = '+'; 2871590Srgrimes *p++ = *num++; 2881590Srgrimes *p++ = '-'; 2891590Srgrimes /* FALLTHROUGH */ 2901590Srgrimes case 10: /* 012-345-6789 */ 2911590Srgrimes *p++ = *num++; 2921590Srgrimes *p++ = *num++; 2931590Srgrimes *p++ = *num++; 2941590Srgrimes *p++ = '-'; 2951590Srgrimes /* FALLTHROUGH */ 2961590Srgrimes case 7: /* 012-3456 */ 2971590Srgrimes *p++ = *num++; 2981590Srgrimes *p++ = *num++; 2991590Srgrimes *p++ = *num++; 3001590Srgrimes break; 3011590Srgrimes case 5: /* x0-1234 */ 3022537Spst case 4: /* x1234 */ 3031590Srgrimes *p++ = 'x'; 3041590Srgrimes *p++ = *num++; 3051590Srgrimes break; 3061590Srgrimes default: 3071590Srgrimes return(num); 3081590Srgrimes } 3092537Spst if (len != 4) { 3102537Spst *p++ = '-'; 3112537Spst *p++ = *num++; 3122537Spst } 3131590Srgrimes *p++ = *num++; 3141590Srgrimes *p++ = *num++; 3151590Srgrimes *p++ = *num++; 3161590Srgrimes *p = '\0'; 3171590Srgrimes return(pbuf); 3181590Srgrimes} 3191590Srgrimes 3201590Srgrimesstatic void 3211590Srgrimesfind_idle_and_ttywrite(w) 3221590Srgrimes register WHERE *w; 3231590Srgrimes{ 3241590Srgrimes extern time_t now; 3251590Srgrimes struct stat sb; 3261590Srgrimes 3271590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 3281590Srgrimes if (stat(tbuf, &sb) < 0) { 32962891Skris warn("%s", tbuf); 3301590Srgrimes return; 3311590Srgrimes } 3321590Srgrimes w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 3331590Srgrimes 3341590Srgrimes#define TALKABLE 0220 /* tty is writable if 220 mode */ 3351590Srgrimes w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 3361590Srgrimes} 3371590Srgrimes 3381590Srgrimesstatic void 3391590Srgrimesuserinfo(pn, pw) 3401590Srgrimes register PERSON *pn; 3411590Srgrimes register struct passwd *pw; 3421590Srgrimes{ 3431590Srgrimes register char *p, *t; 3441590Srgrimes char *bp, name[1024]; 3452537Spst struct stat sb; 3461590Srgrimes 3471590Srgrimes pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 3481590Srgrimes 3491590Srgrimes pn->uid = pw->pw_uid; 3501590Srgrimes pn->name = strdup(pw->pw_name); 3511590Srgrimes pn->dir = strdup(pw->pw_dir); 3521590Srgrimes pn->shell = strdup(pw->pw_shell); 3531590Srgrimes 3541590Srgrimes /* why do we skip asterisks!?!? */ 35550127Simp (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 35650167Simp tbuf[sizeof(tbuf) - 1] = '\0'; 3571590Srgrimes if (*bp == '*') 3581590Srgrimes ++bp; 3591590Srgrimes 3601590Srgrimes /* ampersands get replaced by the login name */ 3611590Srgrimes if (!(p = strsep(&bp, ","))) 3621590Srgrimes return; 36350167Simp for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 3641590Srgrimes if (*t == '&') { 36550127Simp (void)strncpy(t, pw->pw_name, 36650127Simp sizeof(name) - (t - name)); 36750127Simp name[sizeof(name) - 1] = '\0'; 3681590Srgrimes if (islower(*t)) 3691590Srgrimes *t = toupper(*t); 37050167Simp while (t < &name[sizeof(name) - 1] && *++t) 37150167Simp continue; 37250127Simp } else { 37350127Simp ++t; 3741590Srgrimes } 37550127Simp } 37650127Simp *t = '\0'; 3771590Srgrimes pn->realname = strdup(name); 3781590Srgrimes pn->office = ((p = strsep(&bp, ",")) && *p) ? 3791590Srgrimes strdup(p) : NULL; 3801590Srgrimes pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 3811590Srgrimes strdup(p) : NULL; 3821590Srgrimes pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 3831590Srgrimes strdup(p) : NULL; 38450127Simp (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name); 3852537Spst pn->mailrecv = -1; /* -1 == not_valid */ 3862537Spst if (stat(tbuf, &sb) < 0) { 3872537Spst if (errno != ENOENT) { 38827169Scharnier warn("%s", tbuf); 3892537Spst return; 3902537Spst } 3912537Spst } else if (sb.st_size != 0) { 3922537Spst pn->mailrecv = sb.st_mtime; 3932537Spst pn->mailread = sb.st_atime; 3942537Spst } 3951590Srgrimes} 3961590Srgrimes 3975369Sjkh/* 3985369Sjkh * Is this user hiding from finger? 3995369Sjkh * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 4005369Sjkh */ 4015369Sjkh 4025369Sjkhint 4035369Sjkhhide(pw) 4045369Sjkh struct passwd *pw; 4055369Sjkh{ 4065369Sjkh char buf[MAXPATHLEN+1]; 4075369Sjkh 4085369Sjkh if (!pw->pw_dir) 4095369Sjkh return 0; 4105369Sjkh 41150127Simp snprintf(buf, sizeof(buf), "%s/.nofinger", pw->pw_dir); 41250127Simp buf[sizeof(buf) - 1] = '\0'; 4135369Sjkh 41450127Simp if (access(buf, F_OK) == 0) 4155369Sjkh return 1; 4165369Sjkh 4175369Sjkh return 0; 4185369Sjkh} 419