xref: /csrg-svn/usr.bin/finger/util.c (revision 50596)
137660Sbostic /*
237660Sbostic  * Copyright (c) 1989 The Regents of the University of California.
337660Sbostic  * All rights reserved.
437660Sbostic  *
540027Sbostic  * This code is derived from software contributed to Berkeley by
640027Sbostic  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
740027Sbostic  *
842731Sbostic  * %sccs.include.redist.c%
937660Sbostic  */
1037660Sbostic 
1137660Sbostic #ifndef lint
12*50596Sbostic static char sccsid[] = "@(#)util.c	5.15 (Berkeley) 07/27/91";
1337660Sbostic #endif /* not lint */
1437660Sbostic 
1537660Sbostic #include <sys/param.h>
1637660Sbostic #include <sys/stat.h>
17*50596Sbostic #include <fcntl.h>
18*50596Sbostic #include <pwd.h>
19*50596Sbostic #include <utmp.h>
20*50596Sbostic #include <errno.h>
21*50596Sbostic #include <unistd.h>
2237660Sbostic #include <stdio.h>
2337660Sbostic #include <ctype.h>
24*50596Sbostic #include <stdlib.h>
2542053Sbostic #include <string.h>
2643857Sbostic #include <paths.h>
2737660Sbostic #include "finger.h"
2837660Sbostic 
29*50596Sbostic static void	 find_idle_and_ttywrite __P((WHERE *));
30*50596Sbostic static int	 hash __P((char *));
31*50596Sbostic static void	 userinfo __P((PERSON *, struct passwd *));
32*50596Sbostic static WHERE	*walloc __P((PERSON *));
33*50596Sbostic 
34*50596Sbostic static void
3537664Sedward find_idle_and_ttywrite(w)
3637664Sedward 	register WHERE *w;
3737660Sbostic {
3837660Sbostic 	extern time_t now;
3937660Sbostic 	struct stat sb;
4037660Sbostic 
41*50596Sbostic 	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
4237660Sbostic 	if (stat(tbuf, &sb) < 0) {
4337660Sbostic 		(void)fprintf(stderr,
4437660Sbostic 		    "finger: %s: %s\n", tbuf, strerror(errno));
4545972Sbostic 		return;
4637660Sbostic 	}
4737664Sedward 	w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
4837660Sbostic 
4937660Sbostic #define	TALKABLE	0220		/* tty is writable if 220 mode */
5037664Sedward 	w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
5137660Sbostic }
5237660Sbostic 
53*50596Sbostic static void
5437660Sbostic userinfo(pn, pw)
5537660Sbostic 	register PERSON *pn;
5637660Sbostic 	register struct passwd *pw;
5737660Sbostic {
5837660Sbostic 	register char *p, *t;
5941568Smarc 	char *bp, name[1024];
6037660Sbostic 
6137660Sbostic 	pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
6237660Sbostic 
6337660Sbostic 	pn->uid = pw->pw_uid;
6437660Sbostic 	pn->name = strdup(pw->pw_name);
6537660Sbostic 	pn->dir = strdup(pw->pw_dir);
6637660Sbostic 	pn->shell = strdup(pw->pw_shell);
6737660Sbostic 
6837660Sbostic 	/* why do we skip asterisks!?!? */
6941553Smarc 	(void)strcpy(bp = tbuf, pw->pw_gecos);
7041553Smarc 	if (*bp == '*')
7141553Smarc 		++bp;
7237660Sbostic 
7337660Sbostic 	/* ampersands get replaced by the login name */
7441553Smarc 	if (!(p = strsep(&bp, ",")))
7537660Sbostic 		return;
7637660Sbostic 	for (t = name; *t = *p; ++p)
7737660Sbostic 		if (*t == '&') {
7837660Sbostic 			(void)strcpy(t, pw->pw_name);
7937660Sbostic 			if (islower(*t))
8037660Sbostic 				*t = toupper(*t);
8137660Sbostic 			while (*++t);
8237660Sbostic 		}
8337660Sbostic 		else
8437660Sbostic 			++t;
8537660Sbostic 	pn->realname = strdup(name);
8641553Smarc 	pn->office = ((p = strsep(&bp, ",")) && *p) ?
8738600Sbostic 	    strdup(p) : NULL;
8841553Smarc 	pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
8938600Sbostic 	    strdup(p) : NULL;
9041553Smarc 	pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
9138600Sbostic 	    strdup(p) : NULL;
9237660Sbostic }
9337660Sbostic 
9437660Sbostic match(pw, user)
9537660Sbostic 	struct passwd *pw;
9637660Sbostic 	char *user;
9737660Sbostic {
9837660Sbostic 	register char *p, *t;
9941568Smarc 	char name[1024];
10037660Sbostic 
10137660Sbostic 	/* why do we skip asterisks!?!? */
10237660Sbostic 	(void)strcpy(p = tbuf, pw->pw_gecos);
10337660Sbostic 	if (*p == '*')
10437660Sbostic 		++p;
10537660Sbostic 
10637660Sbostic 	/* ampersands get replaced by the login name */
10737660Sbostic 	if (!(p = strtok(p, ",")))
10837660Sbostic 		return(0);
10937660Sbostic 	for (t = name; *t = *p; ++p)
11037660Sbostic 		if (*t == '&') {
11137660Sbostic 			(void)strcpy(t, pw->pw_name);
11237660Sbostic 			while (*++t);
11337660Sbostic 		}
11437660Sbostic 		else
11537660Sbostic 			++t;
11637660Sbostic 	for (t = name; p = strtok(t, "\t "); t = (char *)NULL)
11737660Sbostic 		if (!strcasecmp(p, user))
11837660Sbostic 			return(1);
11937660Sbostic 	return(0);
12037660Sbostic }
12137660Sbostic 
122*50596Sbostic void
12337664Sedward enter_lastlog(pn)
12437660Sbostic 	register PERSON *pn;
12537660Sbostic {
12637664Sedward 	register WHERE *w;
12737683Sedward 	static int opened, fd;
12837660Sbostic 	struct lastlog ll;
12937664Sedward 	char doit = 0;
13037660Sbostic 
13137665Sbostic 	/* some systems may not maintain lastlog, don't report errors. */
13237665Sbostic 	if (!opened) {
13337664Sedward 		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
13437665Sbostic 		opened = 1;
13537660Sbostic 	}
13637665Sbostic 	if (fd == -1 ||
137*50596Sbostic 	    lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
13837665Sbostic 	    (long)pn->uid * sizeof(ll) ||
13937665Sbostic 	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
14037665Sbostic 			/* as if never logged in */
14137665Sbostic 			ll.ll_line[0] = ll.ll_host[0] = NULL;
14237665Sbostic 			ll.ll_time = 0;
14337665Sbostic 		}
14437664Sedward 	if ((w = pn->whead) == NULL)
14537664Sedward 		doit = 1;
14637683Sedward 	else if (ll.ll_time != 0) {
14737664Sedward 		/* if last login is earlier than some current login */
14837664Sedward 		for (; !doit && w != NULL; w = w->next)
14937664Sedward 			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
15037664Sedward 				doit = 1;
15137664Sedward 		/*
15237664Sedward 		 * and if it's not any of the current logins
15337664Sedward 		 * can't use time comparison because there may be a small
15437664Sedward 		 * discrepency since login calls time() twice
15537664Sedward 		 */
15637664Sedward 		for (w = pn->whead; doit && w != NULL; w = w->next)
15737664Sedward 			if (w->info == LOGGEDIN &&
15837664Sedward 			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
15937664Sedward 				doit = 0;
16037660Sbostic 	}
16137664Sedward 	if (doit) {
16237664Sedward 		w = walloc(pn);
16337664Sedward 		w->info = LASTLOG;
16437664Sedward 		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
16537664Sedward 		w->tty[UT_LINESIZE] = 0;
16637664Sedward 		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
16737664Sedward 		w->host[UT_HOSTSIZE] = 0;
16837664Sedward 		w->loginat = ll.ll_time;
16937664Sedward 	}
17037660Sbostic }
17137660Sbostic 
172*50596Sbostic void
17337664Sedward enter_where(ut, pn)
17437660Sbostic 	struct utmp *ut;
17537660Sbostic 	PERSON *pn;
17637660Sbostic {
177*50596Sbostic 	register WHERE *w;
17837664Sedward 
179*50596Sbostic 	w = walloc(pn);
18037664Sedward 	w->info = LOGGEDIN;
18137664Sedward 	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
18237664Sedward 	w->tty[UT_LINESIZE] = 0;
18337664Sedward 	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
18437664Sedward 	w->host[UT_HOSTSIZE] = 0;
18537664Sedward 	w->loginat = (time_t)ut->ut_time;
18637664Sedward 	find_idle_and_ttywrite(w);
18737660Sbostic }
18837664Sedward 
18937664Sedward PERSON *
19037664Sedward enter_person(pw)
19137664Sedward 	register struct passwd *pw;
19237664Sedward {
19337664Sedward 	register PERSON *pn, **pp;
19437664Sedward 
19537664Sedward 	for (pp = htab + hash(pw->pw_name);
19637664Sedward 	     *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
19737664Sedward 	     pp = &(*pp)->hlink)
19837664Sedward 		;
19937664Sedward 	if ((pn = *pp) == NULL) {
20037664Sedward 		pn = palloc();
20137664Sedward 		entries++;
20237664Sedward 		if (phead == NULL)
20337664Sedward 			phead = ptail = pn;
20437664Sedward 		else {
20537664Sedward 			ptail->next = pn;
20637664Sedward 			ptail = pn;
20737664Sedward 		}
20837664Sedward 		pn->next = NULL;
20937664Sedward 		pn->hlink = NULL;
21037664Sedward 		*pp = pn;
21137664Sedward 		userinfo(pn, pw);
21237664Sedward 		pn->whead = NULL;
21337664Sedward 	}
21437664Sedward 	return(pn);
21537664Sedward }
21637664Sedward 
21737664Sedward PERSON *
21837664Sedward find_person(name)
21937664Sedward 	char *name;
22037664Sedward {
22137664Sedward 	register PERSON *pn;
22237664Sedward 
22337664Sedward 	/* name may be only UT_NAMESIZE long and not terminated */
22437664Sedward 	for (pn = htab[hash(name)];
22537664Sedward 	     pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
22637664Sedward 	     pn = pn->hlink)
22737664Sedward 		;
22837664Sedward 	return(pn);
22937664Sedward }
23037664Sedward 
231*50596Sbostic static
23237664Sedward hash(name)
23337664Sedward 	register char *name;
23437664Sedward {
23537664Sedward 	register int h, i;
23637664Sedward 
23737664Sedward 	h = 0;
23837664Sedward 	/* name may be only UT_NAMESIZE long and not terminated */
23937664Sedward 	for (i = UT_NAMESIZE; --i >= 0 && *name;)
24037664Sedward 		h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK;
24137664Sedward 	return(h);
24237664Sedward }
24337664Sedward 
24437664Sedward PERSON *
24537664Sedward palloc()
24637664Sedward {
24737664Sedward 	PERSON *p;
24837664Sedward 
249*50596Sbostic 	if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
250*50596Sbostic 		err("%s", strerror(errno));
25137664Sedward 	return(p);
25237664Sedward }
25337664Sedward 
254*50596Sbostic static WHERE *
25537664Sedward walloc(pn)
25637664Sedward 	register PERSON *pn;
25737664Sedward {
25837664Sedward 	register WHERE *w;
25937664Sedward 
26037664Sedward 	if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
26137664Sedward 		(void)fprintf(stderr, "finger: out of space.\n");
26237664Sedward 		exit(1);
26337664Sedward 	}
26437664Sedward 	if (pn->whead == NULL)
26537664Sedward 		pn->whead = pn->wtail = w;
26637664Sedward 	else {
26737664Sedward 		pn->wtail->next = w;
26837664Sedward 		pn->wtail = w;
26937664Sedward 	}
27037664Sedward 	w->next = NULL;
27137664Sedward 	return(w);
27237664Sedward }
27338052Sbostic 
27438052Sbostic char *
27538052Sbostic prphone(num)
27638052Sbostic 	char *num;
27738052Sbostic {
27838052Sbostic 	register char *p;
27938052Sbostic 	int len;
28038052Sbostic 	static char pbuf[15];
28138052Sbostic 
28238052Sbostic 	/* don't touch anything if the user has their own formatting */
28338052Sbostic 	for (p = num; *p; ++p)
28438052Sbostic 		if (!isdigit(*p))
28538052Sbostic 			return(num);
28638052Sbostic 	len = p - num;
28738052Sbostic 	p = pbuf;
28838052Sbostic 	switch(len) {
28938052Sbostic 	case 11:			/* +0-123-456-7890 */
29038052Sbostic 		*p++ = '+';
29138052Sbostic 		*p++ = *num++;
29238052Sbostic 		*p++ = '-';
29338052Sbostic 		/* FALLTHROUGH */
29438052Sbostic 	case 10:			/* 012-345-6789 */
29538052Sbostic 		*p++ = *num++;
29638052Sbostic 		*p++ = *num++;
29738052Sbostic 		*p++ = *num++;
29838052Sbostic 		*p++ = '-';
29938052Sbostic 		/* FALLTHROUGH */
30038052Sbostic 	case 7:				/* 012-3456 */
30138052Sbostic 		*p++ = *num++;
30238052Sbostic 		*p++ = *num++;
30338052Sbostic 		*p++ = *num++;
30438052Sbostic 		break;
30538052Sbostic 	case 5:				/* x0-1234 */
30638052Sbostic 		*p++ = 'x';
30738052Sbostic 		*p++ = *num++;
30838052Sbostic 		break;
30938052Sbostic 	default:
31038052Sbostic 		return(num);
31138052Sbostic 	}
31238052Sbostic 	*p++ = '-';
31338052Sbostic 	*p++ = *num++;
31438052Sbostic 	*p++ = *num++;
31538052Sbostic 	*p++ = *num++;
31638052Sbostic 	*p++ = *num++;
31738052Sbostic 	*p = '\0';
31838052Sbostic 	return(pbuf);
31938052Sbostic }
320*50596Sbostic 
321*50596Sbostic #if __STDC__
322*50596Sbostic #include <stdarg.h>
323*50596Sbostic #else
324*50596Sbostic #include <varargs.h>
325*50596Sbostic #endif
326*50596Sbostic 
327*50596Sbostic void
328*50596Sbostic #if __STDC__
329*50596Sbostic err(const char *fmt, ...)
330*50596Sbostic #else
331*50596Sbostic err(fmt, va_alist)
332*50596Sbostic 	char *fmt;
333*50596Sbostic 	va_dcl
334*50596Sbostic #endif
335*50596Sbostic {
336*50596Sbostic 	va_list ap;
337*50596Sbostic #if __STDC__
338*50596Sbostic 	va_start(ap, fmt);
339*50596Sbostic #else
340*50596Sbostic 	va_start(ap);
341*50596Sbostic #endif
342*50596Sbostic 	(void)fprintf(stderr, "finger: ");
343*50596Sbostic 	(void)vfprintf(stderr, fmt, ap);
344*50596Sbostic 	va_end(ap);
345*50596Sbostic 	(void)fprintf(stderr, "\n");
346*50596Sbostic 	exit(1);
347*50596Sbostic 	/* NOTREACHED */
348*50596Sbostic }
349