util.c revision 5369
1279430Srstone/*
2279430Srstone * Copyright (c) 1989, 1993
3279430Srstone *	The Regents of the University of California.  All rights reserved.
4279430Srstone *
5279430Srstone * This code is derived from software contributed to Berkeley by
6279430Srstone * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7279430Srstone *
8279430Srstone * Redistribution and use in source and binary forms, with or without
9279430Srstone * modification, are permitted provided that the following conditions
10279430Srstone * are met:
11279430Srstone * 1. Redistributions of source code must retain the above copyright
12279430Srstone *    notice, this list of conditions and the following disclaimer.
13279430Srstone * 2. Redistributions in binary form must reproduce the above copyright
14279430Srstone *    notice, this list of conditions and the following disclaimer in the
15279430Srstone *    documentation and/or other materials provided with the distribution.
16279430Srstone * 3. All advertising materials mentioning features or use of this software
17279430Srstone *    must display the following acknowledgement:
18279430Srstone *	This product includes software developed by the University of
19279430Srstone *	California, Berkeley and its contributors.
20279430Srstone * 4. Neither the name of the University nor the names of its contributors
21279430Srstone *    may be used to endorse or promote products derived from this software
22279430Srstone *    without specific prior written permission.
23279430Srstone *
24279430Srstone * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25279430Srstone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26279430Srstone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27279430Srstone * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28279430Srstone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29279430Srstone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30279430Srstone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31279430Srstone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32279430Srstone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33279430Srstone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34279430Srstone * SUCH DAMAGE.
35279430Srstone */
36279430Srstone
37279430Srstone#ifndef lint
38279430Srstonestatic char sccsid[] = "@(#)util.c	8.1 (Berkeley) 6/6/93";
39279430Srstone#endif /* not lint */
40279430Srstone
41279430Srstone#include <sys/param.h>
42279430Srstone#include <sys/stat.h>
43279430Srstone#include <fcntl.h>
44279430Srstone#include <db.h>
45279430Srstone#include <pwd.h>
46279430Srstone#include <utmp.h>
47279430Srstone#include <errno.h>
48292637Sngie#include <unistd.h>
49279430Srstone#include <stdio.h>
50279430Srstone#include <ctype.h>
51279430Srstone#include <stdlib.h>
52279430Srstone#include <string.h>
53279430Srstone#include <paths.h>
54279430Srstone#include <errno.h>
55279430Srstone#include "finger.h"
56279430Srstone
57279430Srstonestatic void	 find_idle_and_ttywrite __P((WHERE *));
58279430Srstonestatic void	 userinfo __P((PERSON *, struct passwd *));
59279430Srstonestatic WHERE	*walloc __P((PERSON *));
60279430Srstone
61279430Srstoneint
62279430Srstonematch(pw, user)
63292637Sngie	struct passwd *pw;
64279430Srstone	char *user;
65279430Srstone{
66279430Srstone	register char *p, *t;
67279430Srstone	char name[1024];
68292637Sngie
69279430Srstone	if (!strcasecmp(pw->pw_name, user))
70279430Srstone		return(1);
71279430Srstone
72279430Srstone	/*
73279430Srstone	 * XXX
74279430Srstone	 * Why do we skip asterisks!?!?
75279430Srstone	 */
76279430Srstone	(void)strcpy(p = tbuf, pw->pw_gecos);
77279430Srstone	if (*p == '*')
78279430Srstone		++p;
79279430Srstone
80279430Srstone	/* Ampersands get replaced by the login name. */
81279430Srstone	if ((p = strtok(p, ",")) == NULL)
82279430Srstone		return(0);
83279430Srstone
84279430Srstone	for (t = name; *t = *p; ++p)
85279430Srstone		if (*t == '&') {
86279430Srstone			(void)strcpy(t, pw->pw_name);
87292637Sngie			while (*++t);
88279430Srstone		}
89279430Srstone		else
90279430Srstone			++t;
91279430Srstone	for (t = name; p = strtok(t, "\t "); t = NULL)
92279430Srstone		if (!strcasecmp(p, user))
93279430Srstone			return(1);
94279430Srstone	return(0);
95279430Srstone}
96279430Srstone
97279430Srstonevoid
98279430Srstoneenter_lastlog(pn)
99279430Srstone	register PERSON *pn;
100279430Srstone{
101279430Srstone	register WHERE *w;
102292637Sngie	static int opened, fd;
103279430Srstone	struct lastlog ll;
104279430Srstone	char doit = 0;
105279430Srstone
106292637Sngie	/* some systems may not maintain lastlog, don't report errors. */
107279430Srstone	if (!opened) {
108279430Srstone		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
109279430Srstone		opened = 1;
110279430Srstone	}
111279430Srstone	if (fd == -1 ||
112279430Srstone	    lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
113279430Srstone	    (long)pn->uid * sizeof(ll) ||
114279430Srstone	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
115279430Srstone			/* as if never logged in */
116279430Srstone			ll.ll_line[0] = ll.ll_host[0] = NULL;
117279430Srstone			ll.ll_time = 0;
118279430Srstone		}
119279430Srstone	if ((w = pn->whead) == NULL)
120279430Srstone		doit = 1;
121279430Srstone	else if (ll.ll_time != 0) {
122279430Srstone		/* if last login is earlier than some current login */
123279430Srstone		for (; !doit && w != NULL; w = w->next)
124279430Srstone			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
125279430Srstone				doit = 1;
126292637Sngie		/*
127279430Srstone		 * and if it's not any of the current logins
128279430Srstone		 * can't use time comparison because there may be a small
129279430Srstone		 * discrepency since login calls time() twice
130279430Srstone		 */
131279430Srstone		for (w = pn->whead; doit && w != NULL; w = w->next)
132279430Srstone			if (w->info == LOGGEDIN &&
133279430Srstone			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
134279430Srstone				doit = 0;
135279430Srstone	}
136279430Srstone	if (doit) {
137279430Srstone		w = walloc(pn);
138279430Srstone		w->info = LASTLOG;
139279430Srstone		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
140279430Srstone		w->tty[UT_LINESIZE] = 0;
141279430Srstone		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
142279430Srstone		w->host[UT_HOSTSIZE] = 0;
143279430Srstone		w->loginat = ll.ll_time;
144292637Sngie	}
145279430Srstone}
146279430Srstone
147279430Srstonevoid
148279430Srstoneenter_where(ut, pn)
149279430Srstone	struct utmp *ut;
150292637Sngie	PERSON *pn;
151319370Sngie{
152279430Srstone	register WHERE *w;
153279430Srstone
154279430Srstone	w = walloc(pn);
155279430Srstone	w->info = LOGGEDIN;
156279430Srstone	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
157279430Srstone	w->tty[UT_LINESIZE] = 0;
158279430Srstone	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
159279430Srstone	w->host[UT_HOSTSIZE] = 0;
160279430Srstone	w->loginat = (time_t)ut->ut_time;
161279430Srstone	find_idle_and_ttywrite(w);
162279430Srstone}
163279430Srstone
164279430SrstonePERSON *
165279430Srstoneenter_person(pw)
166279430Srstone	register struct passwd *pw;
167279430Srstone{
168279430Srstone	DBT data, key;
169279430Srstone	PERSON *pn;
170279430Srstone
171279430Srstone	if (db == NULL &&
172279430Srstone	    (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
173279430Srstone		err("%s", strerror(errno));
174279430Srstone
175279430Srstone	key.data = pw->pw_name;
176279430Srstone	key.size = strlen(pw->pw_name);
177279430Srstone
178279430Srstone	switch((*db->get)(db, &key, &data, 0)) {
179279430Srstone	case 0:
180279430Srstone		return(*(PERSON **)data.data);
181279430Srstone	default:
182279430Srstone	case -1:
183279430Srstone		err("db get: %s", strerror(errno));
184279430Srstone		/* NOTREACHED */
185279430Srstone	case 1:
186279430Srstone		++entries;
187279430Srstone		pn = palloc();
188279430Srstone		userinfo(pn, pw);
189279430Srstone		pn->whead = NULL;
190279430Srstone
191279430Srstone		data.size = sizeof(PERSON *);
192292637Sngie		data.data = &pn;
193279430Srstone		if ((*db->put)(db, &key, &data, 0))
194279430Srstone			err("%s", strerror(errno));
195279430Srstone		return(pn);
196279430Srstone	}
197279430Srstone}
198279430Srstone
199279430SrstonePERSON *
200279430Srstonefind_person(name)
201279430Srstone	char *name;
202279430Srstone{
203279430Srstone	struct passwd *pw;
204279430Srstone
205279430Srstone	register int cnt;
206279430Srstone	DBT data, key;
207279430Srstone	char buf[UT_NAMESIZE + 1];
208279430Srstone
209279430Srstone	if (!db)
210279430Srstone		return(NULL);
211279430Srstone
212279430Srstone	if ((pw = getpwnam(name)) && hide(pw))
213279430Srstone		return(NULL);
214279430Srstone
215279430Srstone	/* Name may be only UT_NAMESIZE long and not NUL terminated. */
216279430Srstone	for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
217279430Srstone		buf[cnt] = *name;
218279430Srstone	buf[cnt] = '\0';
219279430Srstone	key.data = buf;
220279430Srstone	key.size = cnt;
221279430Srstone
222279430Srstone	return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data);
223279430Srstone}
224279430Srstone
225279430SrstonePERSON *
226279430Srstonepalloc()
227279430Srstone{
228279430Srstone	PERSON *p;
229279430Srstone
230279430Srstone	if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
231279430Srstone		err("%s", strerror(errno));
232279430Srstone	return(p);
233279430Srstone}
234279430Srstone
235279430Srstonestatic WHERE *
236279430Srstonewalloc(pn)
237279430Srstone	register PERSON *pn;
238279430Srstone{
239279430Srstone	register WHERE *w;
240279430Srstone
241279430Srstone	if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
242279430Srstone		err("%s", strerror(errno));
243279430Srstone	if (pn->whead == NULL)
244292637Sngie		pn->whead = pn->wtail = w;
245292637Sngie	else {
246279430Srstone		pn->wtail->next = w;
247279430Srstone		pn->wtail = w;
248279430Srstone	}
249279430Srstone	w->next = NULL;
250279430Srstone	return(w);
251279430Srstone}
252279430Srstone
253279430Srstonechar *
254279430Srstoneprphone(num)
255279430Srstone	char *num;
256279430Srstone{
257279430Srstone	register char *p;
258279430Srstone	int len;
259292637Sngie	static char pbuf[15];
260292637Sngie
261279430Srstone	/* don't touch anything if the user has their own formatting */
262279430Srstone	for (p = num; *p; ++p)
263279430Srstone		if (!isdigit(*p))
264279430Srstone			return(num);
265279430Srstone	len = p - num;
266279430Srstone	p = pbuf;
267292634Sngie	switch(len) {
268292634Sngie	case 11:			/* +0-123-456-7890 */
269292634Sngie		*p++ = '+';
270292634Sngie		*p++ = *num++;
271292634Sngie		*p++ = '-';
272292634Sngie		/* FALLTHROUGH */
273292634Sngie	case 10:			/* 012-345-6789 */
274292634Sngie		*p++ = *num++;
275292634Sngie		*p++ = *num++;
276292634Sngie		*p++ = *num++;
277292634Sngie		*p++ = '-';
278292634Sngie		/* FALLTHROUGH */
279292634Sngie	case 7:				/* 012-3456 */
280292634Sngie		*p++ = *num++;
281292634Sngie		*p++ = *num++;
282292634Sngie		*p++ = *num++;
283292634Sngie		break;
284292634Sngie	case 5:				/* x0-1234 */
285292634Sngie	case 4:				/* x1234 */
286292634Sngie		*p++ = 'x';
287292634Sngie		*p++ = *num++;
288292634Sngie		break;
289292634Sngie	default:
290292634Sngie		return(num);
291292634Sngie	}
292292634Sngie	if (len != 4) {
293292634Sngie	    *p++ = '-';
294292634Sngie	    *p++ = *num++;
295292634Sngie	}
296292634Sngie	*p++ = *num++;
297292634Sngie	*p++ = *num++;
298292634Sngie	*p++ = *num++;
299292634Sngie	*p = '\0';
300292634Sngie	return(pbuf);
301292634Sngie}
302292634Sngie
303292634Sngiestatic void
304292634Sngiefind_idle_and_ttywrite(w)
305292634Sngie	register WHERE *w;
306292634Sngie{
307292634Sngie	extern time_t now;
308292634Sngie	struct stat sb;
309292634Sngie
310292634Sngie	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
311292634Sngie	if (stat(tbuf, &sb) < 0) {
312292634Sngie		(void)fprintf(stderr,
313292634Sngie		    "finger: %s: %s\n", tbuf, strerror(errno));
314292634Sngie		return;
315292634Sngie	}
316292634Sngie	w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
317292634Sngie
318292634Sngie#define	TALKABLE	0220		/* tty is writable if 220 mode */
319292634Sngie	w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
320292634Sngie}
321292634Sngie
322292634Sngiestatic void
323292634Sngieuserinfo(pn, pw)
324292634Sngie	register PERSON *pn;
325292634Sngie	register struct passwd *pw;
326292634Sngie{
327292634Sngie	register char *p, *t;
328292634Sngie	char *bp, name[1024];
329292634Sngie	struct stat sb;
330292634Sngie
331292634Sngie	pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
332292634Sngie
333292634Sngie	pn->uid = pw->pw_uid;
334292634Sngie	pn->name = strdup(pw->pw_name);
335292634Sngie	pn->dir = strdup(pw->pw_dir);
336292634Sngie	pn->shell = strdup(pw->pw_shell);
337292634Sngie
338292634Sngie	/* why do we skip asterisks!?!? */
339292634Sngie	(void)strcpy(bp = tbuf, pw->pw_gecos);
340292634Sngie	if (*bp == '*')
341292634Sngie		++bp;
342292634Sngie
343292634Sngie	/* ampersands get replaced by the login name */
344292634Sngie	if (!(p = strsep(&bp, ",")))
345292634Sngie		return;
346292634Sngie	for (t = name; *t = *p; ++p)
347292634Sngie		if (*t == '&') {
348292634Sngie			(void)strcpy(t, pw->pw_name);
349292634Sngie			if (islower(*t))
350292634Sngie				*t = toupper(*t);
351292634Sngie			while (*++t);
352292634Sngie		}
353292634Sngie		else
354292634Sngie			++t;
355292634Sngie	pn->realname = strdup(name);
356292634Sngie	pn->office = ((p = strsep(&bp, ",")) && *p) ?
357292634Sngie	    strdup(p) : NULL;
358292634Sngie	pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
359292634Sngie	    strdup(p) : NULL;
360292634Sngie	pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
361292634Sngie	    strdup(p) : NULL;
362292634Sngie	(void)sprintf(tbuf,"%s/%s", _PATH_MAILDIR, pw->pw_name);
363292634Sngie	pn->mailrecv = -1;		/* -1 == not_valid */
364292634Sngie	if (stat(tbuf, &sb) < 0) {
365292634Sngie		if (errno != ENOENT) {
366292634Sngie			(void)fprintf(stderr,
367292634Sngie			    "finger: %s: %s\n", tbuf, strerror(errno));
368292634Sngie			return;
369292634Sngie		}
370292634Sngie	} else if (sb.st_size != 0) {
371292634Sngie		pn->mailrecv = sb.st_mtime;
372292634Sngie		pn->mailread = sb.st_atime;
373292634Sngie	}
374292634Sngie}
375292634Sngie
376292634Sngie#if __STDC__
377292634Sngie#include <stdarg.h>
378292634Sngie#else
379292634Sngie#include <varargs.h>
380292634Sngie#endif
381292634Sngie
382292634Sngievoid
383292634Sngie#if __STDC__
384292634Sngieerr(const char *fmt, ...)
385292634Sngie#else
386292634Sngieerr(fmt, va_alist)
387292634Sngie	char *fmt;
388292634Sngie	va_dcl
389292634Sngie#endif
390292634Sngie{
391292634Sngie	va_list ap;
392292634Sngie#if __STDC__
393292634Sngie	va_start(ap, fmt);
394292634Sngie#else
395292634Sngie	va_start(ap);
396292634Sngie#endif
397292634Sngie	(void)fprintf(stderr, "finger: ");
398292634Sngie	(void)vfprintf(stderr, fmt, ap);
399292634Sngie	va_end(ap);
400292634Sngie	(void)fprintf(stderr, "\n");
401292634Sngie	exit(1);
402292634Sngie	/* NOTREACHED */
403292634Sngie}
404292634Sngie
405292634Sngie/*
406292634Sngie * Is this user hiding from finger?
407292634Sngie * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
408292634Sngie */
409292634Sngie
410292634Sngieint
411292634Sngiehide(pw)
412292634Sngie	struct passwd *pw;
413292634Sngie{
414292634Sngie	int fd;
415292634Sngie	char buf[MAXPATHLEN+1];
416292634Sngie
417292634Sngie	if (!pw->pw_dir)
418292634Sngie		return 0;
419292634Sngie
420292634Sngie	sprintf (buf, "%s/.nofinger", pw->pw_dir);
421292634Sngie
422292634Sngie	if (access (buf, F_OK) == 0)
423292634Sngie		return 1;
424292634Sngie
425292634Sngie	return 0;
426292634Sngie}
427292634Sngie