util.c revision 1590
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 381590Srgrimesstatic char sccsid[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; 391590Srgrimes#endif /* not lint */ 401590Srgrimes 411590Srgrimes#include <sys/param.h> 421590Srgrimes#include <sys/stat.h> 431590Srgrimes#include <fcntl.h> 441590Srgrimes#include <db.h> 451590Srgrimes#include <pwd.h> 461590Srgrimes#include <utmp.h> 471590Srgrimes#include <errno.h> 481590Srgrimes#include <unistd.h> 491590Srgrimes#include <stdio.h> 501590Srgrimes#include <ctype.h> 511590Srgrimes#include <stdlib.h> 521590Srgrimes#include <string.h> 531590Srgrimes#include <paths.h> 541590Srgrimes#include "finger.h" 551590Srgrimes 561590Srgrimesstatic void find_idle_and_ttywrite __P((WHERE *)); 571590Srgrimesstatic void userinfo __P((PERSON *, struct passwd *)); 581590Srgrimesstatic WHERE *walloc __P((PERSON *)); 591590Srgrimes 601590Srgrimesint 611590Srgrimesmatch(pw, user) 621590Srgrimes struct passwd *pw; 631590Srgrimes char *user; 641590Srgrimes{ 651590Srgrimes register char *p, *t; 661590Srgrimes char name[1024]; 671590Srgrimes 681590Srgrimes if (!strcasecmp(pw->pw_name, user)) 691590Srgrimes return(1); 701590Srgrimes 711590Srgrimes /* 721590Srgrimes * XXX 731590Srgrimes * Why do we skip asterisks!?!? 741590Srgrimes */ 751590Srgrimes (void)strcpy(p = tbuf, pw->pw_gecos); 761590Srgrimes if (*p == '*') 771590Srgrimes ++p; 781590Srgrimes 791590Srgrimes /* Ampersands get replaced by the login name. */ 801590Srgrimes if ((p = strtok(p, ",")) == NULL) 811590Srgrimes return(0); 821590Srgrimes 831590Srgrimes for (t = name; *t = *p; ++p) 841590Srgrimes if (*t == '&') { 851590Srgrimes (void)strcpy(t, pw->pw_name); 861590Srgrimes while (*++t); 871590Srgrimes } 881590Srgrimes else 891590Srgrimes ++t; 901590Srgrimes for (t = name; p = strtok(t, "\t "); t = NULL) 911590Srgrimes if (!strcasecmp(p, user)) 921590Srgrimes return(1); 931590Srgrimes return(0); 941590Srgrimes} 951590Srgrimes 961590Srgrimesvoid 971590Srgrimesenter_lastlog(pn) 981590Srgrimes register PERSON *pn; 991590Srgrimes{ 1001590Srgrimes register WHERE *w; 1011590Srgrimes static int opened, fd; 1021590Srgrimes struct lastlog ll; 1031590Srgrimes char doit = 0; 1041590Srgrimes 1051590Srgrimes /* some systems may not maintain lastlog, don't report errors. */ 1061590Srgrimes if (!opened) { 1071590Srgrimes fd = open(_PATH_LASTLOG, O_RDONLY, 0); 1081590Srgrimes opened = 1; 1091590Srgrimes } 1101590Srgrimes if (fd == -1 || 1111590Srgrimes lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 1121590Srgrimes (long)pn->uid * sizeof(ll) || 1131590Srgrimes read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 1141590Srgrimes /* as if never logged in */ 1151590Srgrimes ll.ll_line[0] = ll.ll_host[0] = NULL; 1161590Srgrimes ll.ll_time = 0; 1171590Srgrimes } 1181590Srgrimes if ((w = pn->whead) == NULL) 1191590Srgrimes doit = 1; 1201590Srgrimes else if (ll.ll_time != 0) { 1211590Srgrimes /* if last login is earlier than some current login */ 1221590Srgrimes for (; !doit && w != NULL; w = w->next) 1231590Srgrimes if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 1241590Srgrimes doit = 1; 1251590Srgrimes /* 1261590Srgrimes * and if it's not any of the current logins 1271590Srgrimes * can't use time comparison because there may be a small 1281590Srgrimes * discrepency since login calls time() twice 1291590Srgrimes */ 1301590Srgrimes for (w = pn->whead; doit && w != NULL; w = w->next) 1311590Srgrimes if (w->info == LOGGEDIN && 1321590Srgrimes strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 1331590Srgrimes doit = 0; 1341590Srgrimes } 1351590Srgrimes if (doit) { 1361590Srgrimes w = walloc(pn); 1371590Srgrimes w->info = LASTLOG; 1381590Srgrimes bcopy(ll.ll_line, w->tty, UT_LINESIZE); 1391590Srgrimes w->tty[UT_LINESIZE] = 0; 1401590Srgrimes bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 1411590Srgrimes w->host[UT_HOSTSIZE] = 0; 1421590Srgrimes w->loginat = ll.ll_time; 1431590Srgrimes } 1441590Srgrimes} 1451590Srgrimes 1461590Srgrimesvoid 1471590Srgrimesenter_where(ut, pn) 1481590Srgrimes struct utmp *ut; 1491590Srgrimes PERSON *pn; 1501590Srgrimes{ 1511590Srgrimes register WHERE *w; 1521590Srgrimes 1531590Srgrimes w = walloc(pn); 1541590Srgrimes w->info = LOGGEDIN; 1551590Srgrimes bcopy(ut->ut_line, w->tty, UT_LINESIZE); 1561590Srgrimes w->tty[UT_LINESIZE] = 0; 1571590Srgrimes bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 1581590Srgrimes w->host[UT_HOSTSIZE] = 0; 1591590Srgrimes w->loginat = (time_t)ut->ut_time; 1601590Srgrimes find_idle_and_ttywrite(w); 1611590Srgrimes} 1621590Srgrimes 1631590SrgrimesPERSON * 1641590Srgrimesenter_person(pw) 1651590Srgrimes register struct passwd *pw; 1661590Srgrimes{ 1671590Srgrimes DBT data, key; 1681590Srgrimes PERSON *pn; 1691590Srgrimes 1701590Srgrimes if (db == NULL && 1711590Srgrimes (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 1721590Srgrimes err("%s", strerror(errno)); 1731590Srgrimes 1741590Srgrimes key.data = pw->pw_name; 1751590Srgrimes key.size = strlen(pw->pw_name); 1761590Srgrimes 1771590Srgrimes switch((*db->get)(db, &key, &data, 0)) { 1781590Srgrimes case 0: 1791590Srgrimes return(*(PERSON **)data.data); 1801590Srgrimes default: 1811590Srgrimes case -1: 1821590Srgrimes err("db get: %s", strerror(errno)); 1831590Srgrimes /* NOTREACHED */ 1841590Srgrimes case 1: 1851590Srgrimes ++entries; 1861590Srgrimes pn = palloc(); 1871590Srgrimes userinfo(pn, pw); 1881590Srgrimes pn->whead = NULL; 1891590Srgrimes 1901590Srgrimes data.size = sizeof(PERSON *); 1911590Srgrimes data.data = &pn; 1921590Srgrimes if ((*db->put)(db, &key, &data, 0)) 1931590Srgrimes err("%s", strerror(errno)); 1941590Srgrimes return(pn); 1951590Srgrimes } 1961590Srgrimes} 1971590Srgrimes 1981590SrgrimesPERSON * 1991590Srgrimesfind_person(name) 2001590Srgrimes char *name; 2011590Srgrimes{ 2021590Srgrimes register int cnt; 2031590Srgrimes DBT data, key; 2041590Srgrimes char buf[UT_NAMESIZE + 1]; 2051590Srgrimes 2061590Srgrimes if (!db) 2071590Srgrimes return(NULL); 2081590Srgrimes 2091590Srgrimes /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 2101590Srgrimes for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 2111590Srgrimes buf[cnt] = *name; 2121590Srgrimes buf[cnt] = '\0'; 2131590Srgrimes key.data = buf; 2141590Srgrimes key.size = cnt; 2151590Srgrimes 2161590Srgrimes return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 2171590Srgrimes} 2181590Srgrimes 2191590SrgrimesPERSON * 2201590Srgrimespalloc() 2211590Srgrimes{ 2221590Srgrimes PERSON *p; 2231590Srgrimes 2241590Srgrimes if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 2251590Srgrimes err("%s", strerror(errno)); 2261590Srgrimes return(p); 2271590Srgrimes} 2281590Srgrimes 2291590Srgrimesstatic WHERE * 2301590Srgrimeswalloc(pn) 2311590Srgrimes register PERSON *pn; 2321590Srgrimes{ 2331590Srgrimes register WHERE *w; 2341590Srgrimes 2351590Srgrimes if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 2361590Srgrimes err("%s", strerror(errno)); 2371590Srgrimes if (pn->whead == NULL) 2381590Srgrimes pn->whead = pn->wtail = w; 2391590Srgrimes else { 2401590Srgrimes pn->wtail->next = w; 2411590Srgrimes pn->wtail = w; 2421590Srgrimes } 2431590Srgrimes w->next = NULL; 2441590Srgrimes return(w); 2451590Srgrimes} 2461590Srgrimes 2471590Srgrimeschar * 2481590Srgrimesprphone(num) 2491590Srgrimes char *num; 2501590Srgrimes{ 2511590Srgrimes register char *p; 2521590Srgrimes int len; 2531590Srgrimes static char pbuf[15]; 2541590Srgrimes 2551590Srgrimes /* don't touch anything if the user has their own formatting */ 2561590Srgrimes for (p = num; *p; ++p) 2571590Srgrimes if (!isdigit(*p)) 2581590Srgrimes return(num); 2591590Srgrimes len = p - num; 2601590Srgrimes p = pbuf; 2611590Srgrimes switch(len) { 2621590Srgrimes case 11: /* +0-123-456-7890 */ 2631590Srgrimes *p++ = '+'; 2641590Srgrimes *p++ = *num++; 2651590Srgrimes *p++ = '-'; 2661590Srgrimes /* FALLTHROUGH */ 2671590Srgrimes case 10: /* 012-345-6789 */ 2681590Srgrimes *p++ = *num++; 2691590Srgrimes *p++ = *num++; 2701590Srgrimes *p++ = *num++; 2711590Srgrimes *p++ = '-'; 2721590Srgrimes /* FALLTHROUGH */ 2731590Srgrimes case 7: /* 012-3456 */ 2741590Srgrimes *p++ = *num++; 2751590Srgrimes *p++ = *num++; 2761590Srgrimes *p++ = *num++; 2771590Srgrimes break; 2781590Srgrimes case 5: /* x0-1234 */ 2791590Srgrimes *p++ = 'x'; 2801590Srgrimes *p++ = *num++; 2811590Srgrimes break; 2821590Srgrimes default: 2831590Srgrimes return(num); 2841590Srgrimes } 2851590Srgrimes *p++ = '-'; 2861590Srgrimes *p++ = *num++; 2871590Srgrimes *p++ = *num++; 2881590Srgrimes *p++ = *num++; 2891590Srgrimes *p++ = *num++; 2901590Srgrimes *p = '\0'; 2911590Srgrimes return(pbuf); 2921590Srgrimes} 2931590Srgrimes 2941590Srgrimesstatic void 2951590Srgrimesfind_idle_and_ttywrite(w) 2961590Srgrimes register WHERE *w; 2971590Srgrimes{ 2981590Srgrimes extern time_t now; 2991590Srgrimes struct stat sb; 3001590Srgrimes 3011590Srgrimes (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 3021590Srgrimes if (stat(tbuf, &sb) < 0) { 3031590Srgrimes (void)fprintf(stderr, 3041590Srgrimes "finger: %s: %s\n", tbuf, strerror(errno)); 3051590Srgrimes return; 3061590Srgrimes } 3071590Srgrimes w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 3081590Srgrimes 3091590Srgrimes#define TALKABLE 0220 /* tty is writable if 220 mode */ 3101590Srgrimes w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 3111590Srgrimes} 3121590Srgrimes 3131590Srgrimesstatic void 3141590Srgrimesuserinfo(pn, pw) 3151590Srgrimes register PERSON *pn; 3161590Srgrimes register struct passwd *pw; 3171590Srgrimes{ 3181590Srgrimes register char *p, *t; 3191590Srgrimes char *bp, name[1024]; 3201590Srgrimes 3211590Srgrimes pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 3221590Srgrimes 3231590Srgrimes pn->uid = pw->pw_uid; 3241590Srgrimes pn->name = strdup(pw->pw_name); 3251590Srgrimes pn->dir = strdup(pw->pw_dir); 3261590Srgrimes pn->shell = strdup(pw->pw_shell); 3271590Srgrimes 3281590Srgrimes /* why do we skip asterisks!?!? */ 3291590Srgrimes (void)strcpy(bp = tbuf, pw->pw_gecos); 3301590Srgrimes if (*bp == '*') 3311590Srgrimes ++bp; 3321590Srgrimes 3331590Srgrimes /* ampersands get replaced by the login name */ 3341590Srgrimes if (!(p = strsep(&bp, ","))) 3351590Srgrimes return; 3361590Srgrimes for (t = name; *t = *p; ++p) 3371590Srgrimes if (*t == '&') { 3381590Srgrimes (void)strcpy(t, pw->pw_name); 3391590Srgrimes if (islower(*t)) 3401590Srgrimes *t = toupper(*t); 3411590Srgrimes while (*++t); 3421590Srgrimes } 3431590Srgrimes else 3441590Srgrimes ++t; 3451590Srgrimes pn->realname = strdup(name); 3461590Srgrimes pn->office = ((p = strsep(&bp, ",")) && *p) ? 3471590Srgrimes strdup(p) : NULL; 3481590Srgrimes pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 3491590Srgrimes strdup(p) : NULL; 3501590Srgrimes pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 3511590Srgrimes strdup(p) : NULL; 3521590Srgrimes} 3531590Srgrimes 3541590Srgrimes#if __STDC__ 3551590Srgrimes#include <stdarg.h> 3561590Srgrimes#else 3571590Srgrimes#include <varargs.h> 3581590Srgrimes#endif 3591590Srgrimes 3601590Srgrimesvoid 3611590Srgrimes#if __STDC__ 3621590Srgrimeserr(const char *fmt, ...) 3631590Srgrimes#else 3641590Srgrimeserr(fmt, va_alist) 3651590Srgrimes char *fmt; 3661590Srgrimes va_dcl 3671590Srgrimes#endif 3681590Srgrimes{ 3691590Srgrimes va_list ap; 3701590Srgrimes#if __STDC__ 3711590Srgrimes va_start(ap, fmt); 3721590Srgrimes#else 3731590Srgrimes va_start(ap); 3741590Srgrimes#endif 3751590Srgrimes (void)fprintf(stderr, "finger: "); 3761590Srgrimes (void)vfprintf(stderr, fmt, ap); 3771590Srgrimes va_end(ap); 3781590Srgrimes (void)fprintf(stderr, "\n"); 3791590Srgrimes exit(1); 3801590Srgrimes /* NOTREACHED */ 3811590Srgrimes} 382