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