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