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