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