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 * 4. Neither the name of the University nor the names of its contributors 171590Srgrimes * may be used to endorse or promote products derived from this software 181590Srgrimes * without specific prior written permission. 191590Srgrimes * 201590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301590Srgrimes * SUCH DAMAGE. 311590Srgrimes */ 321590Srgrimes 3387628Sdwmalone#if 0 3487628Sdwmalone#ifndef lint 3587628Sdwmalonestatic char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; 3687628Sdwmalone#endif 3787628Sdwmalone#endif 3887628Sdwmalone 3987229Smarkm#include <sys/cdefs.h> 4087229Smarkm__FBSDID("$FreeBSD$"); 4187229Smarkm 421590Srgrimes#include <sys/param.h> 43102944Sdwmalone#include <sys/socket.h> 441590Srgrimes#include <sys/stat.h> 4572109Scharnier#include <ctype.h> 461590Srgrimes#include <db.h> 4723693Speter#include <err.h> 4872109Scharnier#include <errno.h> 4972109Scharnier#include <fcntl.h> 5072109Scharnier#include <paths.h> 511590Srgrimes#include <pwd.h> 521590Srgrimes#include <stdio.h> 531590Srgrimes#include <stdlib.h> 541590Srgrimes#include <string.h> 5572109Scharnier#include <unistd.h> 56202191Sed#include <utmpx.h> 571590Srgrimes#include "finger.h" 5880649Syar#include "pathnames.h" 591590Srgrimes 6092920Simpstatic void find_idle_and_ttywrite(WHERE *); 6192920Simpstatic void userinfo(PERSON *, struct passwd *); 6292920Simpstatic WHERE *walloc(PERSON *); 631590Srgrimes 641590Srgrimesint 65102944Sdwmalonematch(struct passwd *pw, const char *user) 661590Srgrimes{ 6787229Smarkm char *p, *t; 681590Srgrimes char name[1024]; 691590Srgrimes 701590Srgrimes if (!strcasecmp(pw->pw_name, user)) 711590Srgrimes return(1); 721590Srgrimes 731590Srgrimes /* 741590Srgrimes * XXX 751590Srgrimes * Why do we skip asterisks!?!? 761590Srgrimes */ 7750127Simp (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); 7850167Simp tbuf[sizeof(tbuf) - 1] = '\0'; 791590Srgrimes if (*p == '*') 801590Srgrimes ++p; 811590Srgrimes 821590Srgrimes /* Ampersands get replaced by the login name. */ 831590Srgrimes if ((p = strtok(p, ",")) == NULL) 841590Srgrimes return(0); 851590Srgrimes 8650167Simp for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 8750127Simp if (*t == '&') { 8850127Simp (void)strncpy(t, pw->pw_name, 8950127Simp sizeof(name) - (t - name)); 9050127Simp name[sizeof(name) - 1] = '\0'; 9150167Simp while (t < &name[sizeof(name) - 1] && *++t) 9250167Simp continue; 9350127Simp } else { 9450127Simp ++t; 951590Srgrimes } 9650127Simp } 9750127Simp *t = '\0'; 9823693Speter for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) 991590Srgrimes if (!strcasecmp(p, user)) 1001590Srgrimes return(1); 1011590Srgrimes return(0); 1021590Srgrimes} 1031590Srgrimes 1041590Srgrimesvoid 105102944Sdwmaloneenter_lastlog(PERSON *pn) 1061590Srgrimes{ 10787229Smarkm WHERE *w; 108202191Sed struct utmpx *ut = NULL; 1091590Srgrimes char doit = 0; 1101590Srgrimes 111202191Sed if (setutxdb(UTXDB_LASTLOGIN, NULL) == 0) 112202191Sed ut = getutxuser(pn->name); 1131590Srgrimes if ((w = pn->whead) == NULL) 1141590Srgrimes doit = 1; 115201140Sed else if (ut != NULL && ut->ut_type == USER_PROCESS) { 1161590Srgrimes /* if last login is earlier than some current login */ 1171590Srgrimes for (; !doit && w != NULL; w = w->next) 118201140Sed if (w->info == LOGGEDIN && 119201140Sed w->loginat < ut->ut_tv.tv_sec) 1201590Srgrimes doit = 1; 1211590Srgrimes /* 1221590Srgrimes * and if it's not any of the current logins 1231590Srgrimes * can't use time comparison because there may be a small 12472109Scharnier * discrepancy since login calls time() twice 1251590Srgrimes */ 1261590Srgrimes for (w = pn->whead; doit && w != NULL; w = w->next) 1271590Srgrimes if (w->info == LOGGEDIN && 128201140Sed strcmp(w->tty, ut->ut_line) == 0) 1291590Srgrimes doit = 0; 1301590Srgrimes } 131201140Sed if (ut != NULL && doit) { 1321590Srgrimes w = walloc(pn); 1331590Srgrimes w->info = LASTLOG; 134201140Sed strcpy(w->tty, ut->ut_line); 135201140Sed strcpy(w->host, ut->ut_host); 136201140Sed w->loginat = ut->ut_tv.tv_sec; 1371590Srgrimes } 138202191Sed endutxent(); 1391590Srgrimes} 1401590Srgrimes 1411590Srgrimesvoid 142201140Sedenter_where(struct utmpx *ut, PERSON *pn) 1431590Srgrimes{ 14487229Smarkm WHERE *w; 1451590Srgrimes 1461590Srgrimes w = walloc(pn); 1471590Srgrimes w->info = LOGGEDIN; 148201140Sed strcpy(w->tty, ut->ut_line); 149201140Sed strcpy(w->host, ut->ut_host); 150201140Sed w->loginat = ut->ut_tv.tv_sec; 1511590Srgrimes find_idle_and_ttywrite(w); 1521590Srgrimes} 1531590Srgrimes 1541590SrgrimesPERSON * 155102944Sdwmaloneenter_person(struct passwd *pw) 1561590Srgrimes{ 1571590Srgrimes DBT data, key; 1581590Srgrimes PERSON *pn; 1591590Srgrimes 1601590Srgrimes if (db == NULL && 1611590Srgrimes (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 16223693Speter err(1, NULL); 1631590Srgrimes 1641590Srgrimes key.data = pw->pw_name; 1651590Srgrimes key.size = strlen(pw->pw_name); 1661590Srgrimes 16723693Speter switch ((*db->get)(db, &key, &data, 0)) { 1681590Srgrimes case 0: 16923693Speter memmove(&pn, data.data, sizeof pn); 17023693Speter return (pn); 1711590Srgrimes default: 1721590Srgrimes case -1: 17323693Speter err(1, "db get"); 1741590Srgrimes /* NOTREACHED */ 1751590Srgrimes case 1: 1761590Srgrimes ++entries; 1771590Srgrimes pn = palloc(); 1781590Srgrimes userinfo(pn, pw); 1791590Srgrimes pn->whead = NULL; 1801590Srgrimes 1811590Srgrimes data.size = sizeof(PERSON *); 1821590Srgrimes data.data = &pn; 1831590Srgrimes if ((*db->put)(db, &key, &data, 0)) 18423693Speter err(1, "db put"); 18523693Speter return (pn); 1861590Srgrimes } 1871590Srgrimes} 1881590Srgrimes 1891590SrgrimesPERSON * 190201140Sedfind_person(char *name) 1911590Srgrimes{ 1925369Sjkh struct passwd *pw; 1935369Sjkh 1941590Srgrimes DBT data, key; 19523693Speter PERSON *p; 1961590Srgrimes 1971590Srgrimes if (!db) 1981590Srgrimes return(NULL); 1991590Srgrimes 2005369Sjkh if ((pw = getpwnam(name)) && hide(pw)) 2015369Sjkh return(NULL); 2025369Sjkh 203201140Sed key.data = name; 204201140Sed key.size = strlen(name); 2051590Srgrimes 20623693Speter if ((*db->get)(db, &key, &data, 0)) 20723693Speter return (NULL); 20823693Speter memmove(&p, data.data, sizeof p); 20923693Speter return (p); 2101590Srgrimes} 2111590Srgrimes 2121590SrgrimesPERSON * 213102944Sdwmalonepalloc(void) 2141590Srgrimes{ 2151590Srgrimes PERSON *p; 2161590Srgrimes 21796785Sjmallett if ((p = malloc(sizeof(PERSON))) == NULL) 21823693Speter err(1, NULL); 2191590Srgrimes return(p); 2201590Srgrimes} 2211590Srgrimes 2221590Srgrimesstatic WHERE * 223102944Sdwmalonewalloc(PERSON *pn) 2241590Srgrimes{ 22587229Smarkm WHERE *w; 2261590Srgrimes 22796785Sjmallett if ((w = malloc(sizeof(WHERE))) == NULL) 22823693Speter err(1, NULL); 2291590Srgrimes if (pn->whead == NULL) 2301590Srgrimes pn->whead = pn->wtail = w; 2311590Srgrimes else { 2321590Srgrimes pn->wtail->next = w; 2331590Srgrimes pn->wtail = w; 2341590Srgrimes } 2351590Srgrimes w->next = NULL; 2361590Srgrimes return(w); 2371590Srgrimes} 2381590Srgrimes 2391590Srgrimeschar * 240102944Sdwmaloneprphone(char *num) 2411590Srgrimes{ 24287229Smarkm char *p; 2431590Srgrimes int len; 24450127Simp static char pbuf[20]; 2451590Srgrimes 2461590Srgrimes /* don't touch anything if the user has their own formatting */ 2471590Srgrimes for (p = num; *p; ++p) 2481590Srgrimes if (!isdigit(*p)) 2491590Srgrimes return(num); 2501590Srgrimes len = p - num; 2511590Srgrimes p = pbuf; 2521590Srgrimes switch(len) { 2531590Srgrimes case 11: /* +0-123-456-7890 */ 2541590Srgrimes *p++ = '+'; 2551590Srgrimes *p++ = *num++; 2561590Srgrimes *p++ = '-'; 2571590Srgrimes /* FALLTHROUGH */ 2581590Srgrimes case 10: /* 012-345-6789 */ 2591590Srgrimes *p++ = *num++; 2601590Srgrimes *p++ = *num++; 2611590Srgrimes *p++ = *num++; 2621590Srgrimes *p++ = '-'; 2631590Srgrimes /* FALLTHROUGH */ 2641590Srgrimes case 7: /* 012-3456 */ 2651590Srgrimes *p++ = *num++; 2661590Srgrimes *p++ = *num++; 2671590Srgrimes *p++ = *num++; 2681590Srgrimes break; 2691590Srgrimes case 5: /* x0-1234 */ 2702537Spst case 4: /* x1234 */ 2711590Srgrimes *p++ = 'x'; 2721590Srgrimes *p++ = *num++; 2731590Srgrimes break; 2741590Srgrimes default: 2751590Srgrimes return(num); 2761590Srgrimes } 2772537Spst if (len != 4) { 2782537Spst *p++ = '-'; 2792537Spst *p++ = *num++; 2802537Spst } 2811590Srgrimes *p++ = *num++; 2821590Srgrimes *p++ = *num++; 2831590Srgrimes *p++ = *num++; 2841590Srgrimes *p = '\0'; 2851590Srgrimes return(pbuf); 2861590Srgrimes} 2871590Srgrimes 2881590Srgrimesstatic void 289102944Sdwmalonefind_idle_and_ttywrite(WHERE *w) 2901590Srgrimes{ 2911590Srgrimes struct stat sb; 29270242Sbrian time_t touched; 293112987Srwatson int error; 2941590Srgrimes 2951590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 296112987Srwatson 297112987Srwatson error = stat(tbuf, &sb); 298112987Srwatson if (error < 0 && errno == ENOENT) { 299112987Srwatson /* 300112987Srwatson * The terminal listed is not actually a terminal (i.e., 301112987Srwatson * ":0"). This is a failure, so we'll skip printing 302112987Srwatson * out the idle time, which is non-ideal but better 303112987Srwatson * than a bogus warning and idle time. 304112987Srwatson */ 305112987Srwatson w->idletime = -1; 306112987Srwatson return; 307112987Srwatson } else if (error < 0) { 30862891Skris warn("%s", tbuf); 309112987Srwatson w->idletime = -1; 3101590Srgrimes return; 3111590Srgrimes } 31270242Sbrian touched = sb.st_atime; 31370242Sbrian if (touched < w->loginat) { 31470242Sbrian /* tty untouched since before login */ 31570242Sbrian touched = w->loginat; 31670242Sbrian } 31770242Sbrian w->idletime = now < touched ? 0 : now - touched; 3181590Srgrimes 3191590Srgrimes#define TALKABLE 0220 /* tty is writable if 220 mode */ 3201590Srgrimes w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 3211590Srgrimes} 3221590Srgrimes 3231590Srgrimesstatic void 324102944Sdwmaloneuserinfo(PERSON *pn, struct passwd *pw) 3251590Srgrimes{ 32687229Smarkm char *p, *t; 3271590Srgrimes char *bp, name[1024]; 3282537Spst struct stat sb; 3291590Srgrimes 3301590Srgrimes pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 3311590Srgrimes 3321590Srgrimes pn->uid = pw->pw_uid; 33371273Sjedgar if ((pn->name = strdup(pw->pw_name)) == NULL) 33471273Sjedgar err(1, "strdup failed"); 33571273Sjedgar if ((pn->dir = strdup(pw->pw_dir)) == NULL) 33671273Sjedgar err(1, "strdup failed"); 33771273Sjedgar if ((pn->shell = strdup(pw->pw_shell)) == NULL) 33871273Sjedgar err(1, "strdup failed"); 3391590Srgrimes 3401590Srgrimes /* why do we skip asterisks!?!? */ 34150127Simp (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 34250167Simp tbuf[sizeof(tbuf) - 1] = '\0'; 3431590Srgrimes if (*bp == '*') 3441590Srgrimes ++bp; 3451590Srgrimes 3461590Srgrimes /* ampersands get replaced by the login name */ 3471590Srgrimes if (!(p = strsep(&bp, ","))) 3481590Srgrimes return; 34950167Simp for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 3501590Srgrimes if (*t == '&') { 35150127Simp (void)strncpy(t, pw->pw_name, 35250127Simp sizeof(name) - (t - name)); 35350127Simp name[sizeof(name) - 1] = '\0'; 3541590Srgrimes if (islower(*t)) 3551590Srgrimes *t = toupper(*t); 35650167Simp while (t < &name[sizeof(name) - 1] && *++t) 35750167Simp continue; 35850127Simp } else { 35950127Simp ++t; 3601590Srgrimes } 36150127Simp } 36250127Simp *t = '\0'; 36371273Sjedgar if ((pn->realname = strdup(name)) == NULL) 36471273Sjedgar err(1, "strdup failed"); 3651590Srgrimes pn->office = ((p = strsep(&bp, ",")) && *p) ? 3661590Srgrimes strdup(p) : NULL; 3671590Srgrimes pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 3681590Srgrimes strdup(p) : NULL; 3691590Srgrimes pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 3701590Srgrimes strdup(p) : NULL; 37150127Simp (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name); 3722537Spst pn->mailrecv = -1; /* -1 == not_valid */ 3732537Spst if (stat(tbuf, &sb) < 0) { 3742537Spst if (errno != ENOENT) { 37527169Scharnier warn("%s", tbuf); 3762537Spst return; 3772537Spst } 3782537Spst } else if (sb.st_size != 0) { 3792537Spst pn->mailrecv = sb.st_mtime; 3802537Spst pn->mailread = sb.st_atime; 3812537Spst } 3821590Srgrimes} 3831590Srgrimes 3845369Sjkh/* 3855369Sjkh * Is this user hiding from finger? 3865369Sjkh * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 387150316Sdds * Nobody can hide from root. 3885369Sjkh */ 3895369Sjkh 3905369Sjkhint 391102944Sdwmalonehide(struct passwd *pw) 3925369Sjkh{ 39381309Syar struct stat st; 39473260Simp char buf[MAXPATHLEN]; 3955369Sjkh 396150316Sdds if (invoker_root || !pw->pw_dir) 3975369Sjkh return 0; 3985369Sjkh 39980649Syar snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, _PATH_NOFINGER); 4005369Sjkh 40181309Syar if (stat(buf, &st) == 0) 4025369Sjkh return 1; 4035369Sjkh 4045369Sjkh return 0; 4055369Sjkh} 406