xref: /original-bsd/usr.bin/finger/util.c (revision 0842ddeb)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)util.c	8.3 (Berkeley) 04/28/95";
13 #endif /* not lint */
14 
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <db.h>
19 #include <err.h>
20 #include <pwd.h>
21 #include <utmp.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <paths.h>
29 #include "finger.h"
30 
31 static void	 find_idle_and_ttywrite __P((WHERE *));
32 static void	 userinfo __P((PERSON *, struct passwd *));
33 static WHERE	*walloc __P((PERSON *));
34 
35 int
36 match(pw, user)
37 	struct passwd *pw;
38 	char *user;
39 {
40 	register char *p, *t;
41 	char name[1024];
42 
43 	if (!strcasecmp(pw->pw_name, user))
44 		return(1);
45 
46 	/*
47 	 * XXX
48 	 * Why do we skip asterisks!?!?
49 	 */
50 	(void)strcpy(p = tbuf, pw->pw_gecos);
51 	if (*p == '*')
52 		++p;
53 
54 	/* Ampersands get replaced by the login name. */
55 	if ((p = strtok(p, ",")) == NULL)
56 		return(0);
57 
58 	for (t = name; (*t = *p) != '\0'; ++p)
59 		if (*t == '&') {
60 			(void)strcpy(t, pw->pw_name);
61 			while (*++t);
62 		}
63 		else
64 			++t;
65 	for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
66 		if (!strcasecmp(p, user))
67 			return(1);
68 	return(0);
69 }
70 
71 void
72 enter_lastlog(pn)
73 	register PERSON *pn;
74 {
75 	register WHERE *w;
76 	static int opened, fd;
77 	struct lastlog ll;
78 	char doit = 0;
79 
80 	/* some systems may not maintain lastlog, don't report errors. */
81 	if (!opened) {
82 		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
83 		opened = 1;
84 	}
85 	if (fd == -1 ||
86 	    lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
87 	    (long)pn->uid * sizeof(ll) ||
88 	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
89 			/* as if never logged in */
90 			ll.ll_line[0] = ll.ll_host[0] = NULL;
91 			ll.ll_time = 0;
92 		}
93 	if ((w = pn->whead) == NULL)
94 		doit = 1;
95 	else if (ll.ll_time != 0) {
96 		/* if last login is earlier than some current login */
97 		for (; !doit && w != NULL; w = w->next)
98 			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
99 				doit = 1;
100 		/*
101 		 * and if it's not any of the current logins
102 		 * can't use time comparison because there may be a small
103 		 * discrepency since login calls time() twice
104 		 */
105 		for (w = pn->whead; doit && w != NULL; w = w->next)
106 			if (w->info == LOGGEDIN &&
107 			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
108 				doit = 0;
109 	}
110 	if (doit) {
111 		w = walloc(pn);
112 		w->info = LASTLOG;
113 		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
114 		w->tty[UT_LINESIZE] = 0;
115 		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
116 		w->host[UT_HOSTSIZE] = 0;
117 		w->loginat = ll.ll_time;
118 	}
119 }
120 
121 void
122 enter_where(ut, pn)
123 	struct utmp *ut;
124 	PERSON *pn;
125 {
126 	register WHERE *w;
127 
128 	w = walloc(pn);
129 	w->info = LOGGEDIN;
130 	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
131 	w->tty[UT_LINESIZE] = 0;
132 	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
133 	w->host[UT_HOSTSIZE] = 0;
134 	w->loginat = (time_t)ut->ut_time;
135 	find_idle_and_ttywrite(w);
136 }
137 
138 PERSON *
139 enter_person(pw)
140 	register struct passwd *pw;
141 {
142 	DBT data, key;
143 	PERSON *pn;
144 
145 	if (db == NULL &&
146 	    (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
147 		err(1, NULL);
148 
149 	key.data = pw->pw_name;
150 	key.size = strlen(pw->pw_name);
151 
152 	switch ((*db->get)(db, &key, &data, 0)) {
153 	case 0:
154 		memmove(&pn, data.data, sizeof pn);
155 		return (pn);
156 	default:
157 	case -1:
158 		err(1, "db get");
159 		/* NOTREACHED */
160 	case 1:
161 		++entries;
162 		pn = palloc();
163 		userinfo(pn, pw);
164 		pn->whead = NULL;
165 
166 		data.size = sizeof(PERSON *);
167 		data.data = &pn;
168 		if ((*db->put)(db, &key, &data, 0))
169 			err(1, "db put");
170 		return (pn);
171 	}
172 }
173 
174 PERSON *
175 find_person(name)
176 	char *name;
177 {
178 	register int cnt;
179 	DBT data, key;
180 	PERSON *p;
181 	char buf[UT_NAMESIZE + 1];
182 
183 	if (!db)
184 		return(NULL);
185 
186 	/* Name may be only UT_NAMESIZE long and not NUL terminated. */
187 	for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
188 		buf[cnt] = *name;
189 	buf[cnt] = '\0';
190 	key.data = buf;
191 	key.size = cnt;
192 
193 	if ((*db->get)(db, &key, &data, 0))
194 		return (NULL);
195 	memmove(&p, data.data, sizeof p);
196 	return (p);
197 }
198 
199 PERSON *
200 palloc()
201 {
202 	PERSON *p;
203 
204 	if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
205 		err(1, NULL);
206 	return(p);
207 }
208 
209 static WHERE *
210 walloc(pn)
211 	register PERSON *pn;
212 {
213 	register WHERE *w;
214 
215 	if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
216 		err(1, NULL);
217 	if (pn->whead == NULL)
218 		pn->whead = pn->wtail = w;
219 	else {
220 		pn->wtail->next = w;
221 		pn->wtail = w;
222 	}
223 	w->next = NULL;
224 	return(w);
225 }
226 
227 char *
228 prphone(num)
229 	char *num;
230 {
231 	register char *p;
232 	int len;
233 	static char pbuf[15];
234 
235 	/* don't touch anything if the user has their own formatting */
236 	for (p = num; *p; ++p)
237 		if (!isdigit(*p))
238 			return(num);
239 	len = p - num;
240 	p = pbuf;
241 	switch(len) {
242 	case 11:			/* +0-123-456-7890 */
243 		*p++ = '+';
244 		*p++ = *num++;
245 		*p++ = '-';
246 		/* FALLTHROUGH */
247 	case 10:			/* 012-345-6789 */
248 		*p++ = *num++;
249 		*p++ = *num++;
250 		*p++ = *num++;
251 		*p++ = '-';
252 		/* FALLTHROUGH */
253 	case 7:				/* 012-3456 */
254 		*p++ = *num++;
255 		*p++ = *num++;
256 		*p++ = *num++;
257 		break;
258 	case 5:				/* x0-1234 */
259 		*p++ = 'x';
260 		*p++ = *num++;
261 		break;
262 	default:
263 		return(num);
264 	}
265 	*p++ = '-';
266 	*p++ = *num++;
267 	*p++ = *num++;
268 	*p++ = *num++;
269 	*p++ = *num++;
270 	*p = '\0';
271 	return(pbuf);
272 }
273 
274 static void
275 find_idle_and_ttywrite(w)
276 	register WHERE *w;
277 {
278 	extern time_t now;
279 	struct stat sb;
280 
281 	(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
282 	if (stat(tbuf, &sb) < 0) {
283 		warn(tbuf);
284 		return;
285 	}
286 	w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
287 
288 #define	TALKABLE	0220		/* tty is writable if 220 mode */
289 	w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
290 }
291 
292 static void
293 userinfo(pn, pw)
294 	register PERSON *pn;
295 	register struct passwd *pw;
296 {
297 	register char *p, *t;
298 	char *bp, name[1024];
299 
300 	pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
301 
302 	pn->uid = pw->pw_uid;
303 	pn->name = strdup(pw->pw_name);
304 	pn->dir = strdup(pw->pw_dir);
305 	pn->shell = strdup(pw->pw_shell);
306 
307 	/* why do we skip asterisks!?!? */
308 	(void)strcpy(bp = tbuf, pw->pw_gecos);
309 	if (*bp == '*')
310 		++bp;
311 
312 	/* ampersands get replaced by the login name */
313 	if (!(p = strsep(&bp, ",")))
314 		return;
315 	for (t = name; (*t = *p) != '\0'; ++p)
316 		if (*t == '&') {
317 			(void)strcpy(t, pw->pw_name);
318 			if (islower(*t))
319 				*t = toupper(*t);
320 			while (*++t);
321 		}
322 		else
323 			++t;
324 	pn->realname = strdup(name);
325 	pn->office = ((p = strsep(&bp, ",")) && *p) ?
326 	    strdup(p) : NULL;
327 	pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
328 	    strdup(p) : NULL;
329 	pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
330 	    strdup(p) : NULL;
331 }
332