util.c revision 50167
154359Sroberto/*
2285612Sdelphij * Copyright (c) 1989, 1993
3285612Sdelphij *	The Regents of the University of California.  All rights reserved.
454359Sroberto *
575202Sphk * This code is derived from software contributed to Berkeley by
654359Sroberto * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7285612Sdelphij *
854359Sroberto * Redistribution and use in source and binary forms, with or without
954359Sroberto * modification, are permitted provided that the following conditions
10285612Sdelphij * are met:
11285612Sdelphij * 1. Redistributions of source code must retain the above copyright
12285612Sdelphij *    notice, this list of conditions and the following disclaimer.
13285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
14285612Sdelphij *    notice, this list of conditions and the following disclaimer in the
15285612Sdelphij *    documentation and/or other materials provided with the distribution.
16285612Sdelphij * 3. All advertising materials mentioning features or use of this software
17285612Sdelphij *    must display the following acknowledgement:
18285612Sdelphij *	This product includes software developed by the University of
1954359Sroberto *	California, Berkeley and its contributors.
2054359Sroberto * 4. Neither the name of the University nor the names of its contributors
2154359Sroberto *    may be used to endorse or promote products derived from this software
2254359Sroberto *    without specific prior written permission.
23182007Sroberto *
2454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25285612Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27285612Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28285612Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29285612Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30285612Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31289997Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32285612Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33285612Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34285612Sdelphij * SUCH DAMAGE.
3554359Sroberto */
3654359Sroberto
3754359Sroberto#ifndef lint
3854359Sroberto#if 0
3954359Srobertostatic char sccsid[] = "@(#)util.c	8.3 (Berkeley) 4/28/95";
4054359Sroberto#else
4182502Srobertostatic const char rcsid[] =
42285612Sdelphij	"$Id: util.c,v 1.6 1999/08/21 18:25:38 imp Exp $";
4382502Sroberto#endif
44285612Sdelphij#endif /* not lint */
4554359Sroberto
4654359Sroberto#include <sys/param.h>
47285612Sdelphij#include <sys/stat.h>
48285612Sdelphij#include <fcntl.h>
4954359Sroberto#include <db.h>
50285612Sdelphij#include <err.h>
5154359Sroberto#include <pwd.h>
5254359Sroberto#include <utmp.h>
5354359Sroberto#include <errno.h>
54285612Sdelphij#include <unistd.h>
55132455Sroberto#include <stdio.h>
56285612Sdelphij#include <ctype.h>
57132455Sroberto#include <stdlib.h>
58285612Sdelphij#include <string.h>
59285612Sdelphij#include <paths.h>
60285612Sdelphij#include <errno.h>
61285612Sdelphij#include "finger.h"
62285612Sdelphij
63285612Sdelphijstatic void	 find_idle_and_ttywrite __P((WHERE *));
64285612Sdelphijstatic void	 userinfo __P((PERSON *, struct passwd *));
65285612Sdelphijstatic WHERE	*walloc __P((PERSON *));
66285612Sdelphij
67285612Sdelphijint
68285612Sdelphijmatch(pw, user)
69285612Sdelphij	struct passwd *pw;
70285612Sdelphij	char *user;
71285612Sdelphij{
72285612Sdelphij	register char *p, *t;
73285612Sdelphij	char name[1024];
74285612Sdelphij
75285612Sdelphij	if (!strcasecmp(pw->pw_name, user))
76285612Sdelphij		return(1);
77294569Sdelphij
7854359Sroberto	/*
79285612Sdelphij	 * XXX
8054359Sroberto	 * Why do we skip asterisks!?!?
81285612Sdelphij	 */
82285612Sdelphij	(void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf));
83285612Sdelphij	tbuf[sizeof(tbuf) - 1] = '\0';
84285612Sdelphij	if (*p == '*')
85285612Sdelphij		++p;
86285612Sdelphij
87285612Sdelphij	/* Ampersands get replaced by the login name. */
88285612Sdelphij	if ((p = strtok(p, ",")) == NULL)
89285612Sdelphij		return(0);
90285612Sdelphij
91285612Sdelphij	for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
92285612Sdelphij		if (*t == '&') {
93285612Sdelphij			(void)strncpy(t, pw->pw_name,
94285612Sdelphij			    sizeof(name) - (t - name));
95285612Sdelphij			name[sizeof(name) - 1] = '\0';
96285612Sdelphij			while (t < &name[sizeof(name) - 1] && *++t)
97285612Sdelphij				continue;
98285612Sdelphij		} else {
99285612Sdelphij			++t;
100285612Sdelphij		}
101285612Sdelphij	}
102285612Sdelphij	*t = '\0';
103285612Sdelphij	for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
104285612Sdelphij		if (!strcasecmp(p, user))
105285612Sdelphij			return(1);
106285612Sdelphij	return(0);
107285612Sdelphij}
108285612Sdelphij
109285612Sdelphijvoid
110285612Sdelphijenter_lastlog(pn)
111285612Sdelphij	register PERSON *pn;
112285612Sdelphij{
11354359Sroberto	register WHERE *w;
114294569Sdelphij	static int opened, fd;
115294569Sdelphij	struct lastlog ll;
116285612Sdelphij	char doit = 0;
117285612Sdelphij
118285612Sdelphij	/* some systems may not maintain lastlog, don't report errors. */
119285612Sdelphij	if (!opened) {
120285612Sdelphij		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
121285612Sdelphij		opened = 1;
122309008Sdelphij	}
123309008Sdelphij	if (fd == -1 ||
124285612Sdelphij	    lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
125285612Sdelphij	    (long)pn->uid * sizeof(ll) ||
126285612Sdelphij	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
127285612Sdelphij			/* as if never logged in */
128285612Sdelphij			ll.ll_line[0] = ll.ll_host[0] = '\0';
129309008Sdelphij			ll.ll_time = 0;
130285612Sdelphij		}
13154359Sroberto	if ((w = pn->whead) == NULL)
13254359Sroberto		doit = 1;
13354359Sroberto	else if (ll.ll_time != 0) {
134285612Sdelphij		/* if last login is earlier than some current login */
135285612Sdelphij		for (; !doit && w != NULL; w = w->next)
136285612Sdelphij			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
137285612Sdelphij				doit = 1;
138285612Sdelphij		/*
139285612Sdelphij		 * and if it's not any of the current logins
140285612Sdelphij		 * can't use time comparison because there may be a small
141285612Sdelphij		 * discrepency since login calls time() twice
142285612Sdelphij		 */
143285612Sdelphij		for (w = pn->whead; doit && w != NULL; w = w->next)
144285612Sdelphij			if (w->info == LOGGEDIN &&
145285612Sdelphij			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
146285612Sdelphij				doit = 0;
147285612Sdelphij	}
148285612Sdelphij	if (doit) {
149285612Sdelphij		w = walloc(pn);
150285612Sdelphij		w->info = LASTLOG;
151285612Sdelphij		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
152285612Sdelphij		w->tty[UT_LINESIZE] = 0;
153285612Sdelphij		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
154285612Sdelphij		w->host[UT_HOSTSIZE] = 0;
155285612Sdelphij		w->loginat = ll.ll_time;
156285612Sdelphij	}
157285612Sdelphij}
158285612Sdelphij
159285612Sdelphijvoid
160285612Sdelphijenter_where(ut, pn)
161285612Sdelphij	struct utmp *ut;
162285612Sdelphij	PERSON *pn;
163285612Sdelphij{
164285612Sdelphij	register WHERE *w;
165285612Sdelphij
166285612Sdelphij	w = walloc(pn);
167285612Sdelphij	w->info = LOGGEDIN;
168285612Sdelphij	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
169285612Sdelphij	w->tty[UT_LINESIZE] = 0;
170285612Sdelphij	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
171285612Sdelphij	w->host[UT_HOSTSIZE] = 0;
172285612Sdelphij	w->loginat = (time_t)ut->ut_time;
173285612Sdelphij	find_idle_and_ttywrite(w);
174285612Sdelphij}
175285612Sdelphij
176285612SdelphijPERSON *
177285612Sdelphijenter_person(pw)
178285612Sdelphij	register struct passwd *pw;
179330141Sdelphij{
180330141Sdelphij	DBT data, key;
181330141Sdelphij	PERSON *pn;
182330141Sdelphij
183330141Sdelphij	if (db == NULL &&
184330141Sdelphij	    (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
185330141Sdelphij		err(1, NULL);
186330141Sdelphij
187330141Sdelphij	key.data = pw->pw_name;
188330141Sdelphij	key.size = strlen(pw->pw_name);
189330141Sdelphij
190330141Sdelphij	switch ((*db->get)(db, &key, &data, 0)) {
191330141Sdelphij	case 0:
192330141Sdelphij		memmove(&pn, data.data, sizeof pn);
193330141Sdelphij		return (pn);
194330141Sdelphij	default:
195330141Sdelphij	case -1:
196330141Sdelphij		err(1, "db get");
197330141Sdelphij		/* NOTREACHED */
198330141Sdelphij	case 1:
199330141Sdelphij		++entries;
200330141Sdelphij		pn = palloc();
201330141Sdelphij		userinfo(pn, pw);
202330141Sdelphij		pn->whead = NULL;
203330141Sdelphij
204330141Sdelphij		data.size = sizeof(PERSON *);
205330141Sdelphij		data.data = &pn;
206330141Sdelphij		if ((*db->put)(db, &key, &data, 0))
207330141Sdelphij			err(1, "db put");
208330141Sdelphij		return (pn);
209330141Sdelphij	}
210285612Sdelphij}
211285612Sdelphij
212330141SdelphijPERSON *
213330141Sdelphijfind_person(name)
214330141Sdelphij	char *name;
215330141Sdelphij{
216330141Sdelphij	struct passwd *pw;
217330141Sdelphij
218330141Sdelphij	register int cnt;
219330141Sdelphij	DBT data, key;
220330141Sdelphij	PERSON *p;
221330141Sdelphij	char buf[UT_NAMESIZE + 1];
222330141Sdelphij
223330141Sdelphij	if (!db)
224330141Sdelphij		return(NULL);
225330141Sdelphij
226330141Sdelphij	if ((pw = getpwnam(name)) && hide(pw))
227330141Sdelphij		return(NULL);
228330141Sdelphij
229330141Sdelphij	/* Name may be only UT_NAMESIZE long and not NUL terminated. */
230330141Sdelphij	for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
231285612Sdelphij		buf[cnt] = *name;
232285612Sdelphij	buf[cnt] = '\0';
233285612Sdelphij	key.data = buf;
234285612Sdelphij	key.size = cnt;
235285612Sdelphij
236285612Sdelphij	if ((*db->get)(db, &key, &data, 0))
237285612Sdelphij		return (NULL);
238285612Sdelphij	memmove(&p, data.data, sizeof p);
239285612Sdelphij	return (p);
240285612Sdelphij}
241285612Sdelphij
242285612SdelphijPERSON *
243285612Sdelphijpalloc()
244285612Sdelphij{
245285612Sdelphij	PERSON *p;
246285612Sdelphij
247285612Sdelphij	if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
248285612Sdelphij		err(1, NULL);
249285612Sdelphij	return(p);
250285612Sdelphij}
251285612Sdelphij
252285612Sdelphijstatic WHERE *
253285612Sdelphijwalloc(pn)
254285612Sdelphij	register PERSON *pn;
255285612Sdelphij{
256285612Sdelphij	register WHERE *w;
257285612Sdelphij
258285612Sdelphij	if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
259285612Sdelphij		err(1, NULL);
260285612Sdelphij	if (pn->whead == NULL)
261285612Sdelphij		pn->whead = pn->wtail = w;
262285612Sdelphij	else {
263285612Sdelphij		pn->wtail->next = w;
264285612Sdelphij		pn->wtail = w;
265285612Sdelphij	}
266285612Sdelphij	w->next = NULL;
267285612Sdelphij	return(w);
268285612Sdelphij}
269285612Sdelphij
270285612Sdelphijchar *
271285612Sdelphijprphone(num)
272285612Sdelphij	char *num;
273285612Sdelphij{
274285612Sdelphij	register char *p;
275285612Sdelphij	int len;
276285612Sdelphij	static char pbuf[20];
277285612Sdelphij
278285612Sdelphij	/* don't touch anything if the user has their own formatting */
279285612Sdelphij	for (p = num; *p; ++p)
280285612Sdelphij		if (!isdigit(*p))
281285612Sdelphij			return(num);
282285612Sdelphij	len = p - num;
283285612Sdelphij	p = pbuf;
284285612Sdelphij	switch(len) {
285285612Sdelphij	case 11:			/* +0-123-456-7890 */
286285612Sdelphij		*p++ = '+';
287285612Sdelphij		*p++ = *num++;
288285612Sdelphij		*p++ = '-';
289285612Sdelphij		/* FALLTHROUGH */
290285612Sdelphij	case 10:			/* 012-345-6789 */
291285612Sdelphij		*p++ = *num++;
292285612Sdelphij		*p++ = *num++;
293285612Sdelphij		*p++ = *num++;
294285612Sdelphij		*p++ = '-';
295285612Sdelphij		/* FALLTHROUGH */
296285612Sdelphij	case 7:				/* 012-3456 */
297285612Sdelphij		*p++ = *num++;
298285612Sdelphij		*p++ = *num++;
299285612Sdelphij		*p++ = *num++;
300285612Sdelphij		break;
301285612Sdelphij	case 5:				/* x0-1234 */
302285612Sdelphij	case 4:				/* x1234 */
303285612Sdelphij		*p++ = 'x';
304285612Sdelphij		*p++ = *num++;
305285612Sdelphij		break;
306285612Sdelphij	default:
307285612Sdelphij		return(num);
308285612Sdelphij	}
309285612Sdelphij	if (len != 4) {
310285612Sdelphij	    *p++ = '-';
311285612Sdelphij	    *p++ = *num++;
312285612Sdelphij	}
313285612Sdelphij	*p++ = *num++;
314285612Sdelphij	*p++ = *num++;
315285612Sdelphij	*p++ = *num++;
316285612Sdelphij	*p = '\0';
317285612Sdelphij	return(pbuf);
318285612Sdelphij}
319285612Sdelphij
320285612Sdelphijstatic void
321285612Sdelphijfind_idle_and_ttywrite(w)
322285612Sdelphij	register WHERE *w;
323285612Sdelphij{
324285612Sdelphij	extern time_t now;
325285612Sdelphij	struct stat sb;
326285612Sdelphij
327285612Sdelphij	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
328285612Sdelphij	if (stat(tbuf, &sb) < 0) {
329285612Sdelphij		warn(tbuf);
330285612Sdelphij		return;
331285612Sdelphij	}
332285612Sdelphij	w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
33382502Sroberto
33482502Sroberto#define	TALKABLE	0220		/* tty is writable if 220 mode */
33554359Sroberto	w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
336285612Sdelphij}
33754359Sroberto
33854359Srobertostatic void
33954359Srobertouserinfo(pn, pw)
34054359Sroberto	register PERSON *pn;
34154359Sroberto	register struct passwd *pw;
342285612Sdelphij{
34354359Sroberto	register char *p, *t;
34454359Sroberto	char *bp, name[1024];
345285612Sdelphij	struct stat sb;
34654359Sroberto
347285612Sdelphij	pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
348285612Sdelphij
349285612Sdelphij	pn->uid = pw->pw_uid;
350285612Sdelphij	pn->name = strdup(pw->pw_name);
351285612Sdelphij	pn->dir = strdup(pw->pw_dir);
352285612Sdelphij	pn->shell = strdup(pw->pw_shell);
353285612Sdelphij
354285612Sdelphij	/* why do we skip asterisks!?!? */
355285612Sdelphij	(void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
356285612Sdelphij	tbuf[sizeof(tbuf) - 1] = '\0';
357285612Sdelphij	if (*bp == '*')
358285612Sdelphij		++bp;
359285612Sdelphij
360285612Sdelphij	/* ampersands get replaced by the login name */
361285612Sdelphij	if (!(p = strsep(&bp, ",")))
362285612Sdelphij		return;
363285612Sdelphij	for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
364285612Sdelphij		if (*t == '&') {
365285612Sdelphij			(void)strncpy(t, pw->pw_name,
366285612Sdelphij			    sizeof(name) - (t - name));
367285612Sdelphij			name[sizeof(name) - 1] = '\0';
368285612Sdelphij			if (islower(*t))
369285612Sdelphij				*t = toupper(*t);
370285612Sdelphij			while (t < &name[sizeof(name) - 1] && *++t)
371285612Sdelphij				continue;
372285612Sdelphij		} else {
373285612Sdelphij			++t;
374285612Sdelphij		}
375285612Sdelphij	}
376285612Sdelphij	*t = '\0';
377285612Sdelphij	pn->realname = strdup(name);
378285612Sdelphij	pn->office = ((p = strsep(&bp, ",")) && *p) ?
379285612Sdelphij	    strdup(p) : NULL;
380285612Sdelphij	pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
381330141Sdelphij	    strdup(p) : NULL;
382330141Sdelphij	pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
383330141Sdelphij	    strdup(p) : NULL;
384330141Sdelphij	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name);
385330141Sdelphij	pn->mailrecv = -1;		/* -1 == not_valid */
386330141Sdelphij	if (stat(tbuf, &sb) < 0) {
387330141Sdelphij		if (errno != ENOENT) {
388330141Sdelphij			warn("%s", tbuf);
389330141Sdelphij			return;
390330141Sdelphij		}
391330141Sdelphij	} else if (sb.st_size != 0) {
392330141Sdelphij		pn->mailrecv = sb.st_mtime;
393330141Sdelphij		pn->mailread = sb.st_atime;
394330141Sdelphij	}
395330141Sdelphij}
396330141Sdelphij
397330141Sdelphij/*
398330141Sdelphij * Is this user hiding from finger?
399330141Sdelphij * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
400330141Sdelphij */
401330141Sdelphij
402330141Sdelphijint
403330141Sdelphijhide(pw)
404330141Sdelphij	struct passwd *pw;
405330141Sdelphij{
406330141Sdelphij	char buf[MAXPATHLEN+1];
407330141Sdelphij
408330141Sdelphij	if (!pw->pw_dir)
409330141Sdelphij		return 0;
410330141Sdelphij
411330141Sdelphij	snprintf(buf, sizeof(buf), "%s/.nofinger", pw->pw_dir);
412330141Sdelphij	buf[sizeof(buf) - 1] = '\0';
413330141Sdelphij
414330141Sdelphij	if (access(buf, F_OK) == 0)
415330141Sdelphij		return 1;
416330141Sdelphij
417330141Sdelphij	return 0;
418330141Sdelphij}
419330141Sdelphij