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