xref: /openbsd/usr.bin/finger/util.c (revision 07ea8d15)
1 /*	$OpenBSD: util.c,v 1.4 1996/08/30 11:39:36 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1989 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #ifndef lint
40 /*static char sccsid[] = "from: @(#)util.c	5.14 (Berkeley) 1/17/91";*/
41 static char rcsid[] = "$OpenBSD: util.c,v 1.4 1996/08/30 11:39:36 deraadt Exp $";
42 #endif /* not lint */
43 
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <sys/file.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <string.h>
51 #include <paths.h>
52 #include <errno.h>
53 #include "finger.h"
54 
55 find_idle_and_ttywrite(w)
56 	register WHERE *w;
57 {
58 	extern time_t now;
59 	extern int errno;
60 	struct stat sb;
61 
62 	(void)sprintf(tbuf, "%s%s", _PATH_DEV, w->tty);
63 	if (stat(tbuf, &sb) < 0) {
64 		/* Don't bitch about it, just handle it... */
65 		w->idletime = 0;
66 		w->writable = 0;
67 
68 		return;
69 	}
70 	w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
71 
72 #define	TALKABLE	0220		/* tty is writable if 220 mode */
73 	w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
74 }
75 
76 userinfo(pn, pw)
77 	register PERSON *pn;
78 	register struct passwd *pw;
79 {
80 	extern time_t now;
81 	register char *p, *t;
82 	struct stat sb;
83 	extern int errno;
84 	char *mbp, *bp, *name;
85 	int len;
86 
87 	pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
88 
89 	pn->uid = pw->pw_uid;
90 	pn->name = strdup(pw->pw_name);
91 	pn->dir = strdup(pw->pw_dir);
92 	pn->shell = strdup(pw->pw_shell);
93 
94 	/* why do we skip asterisks!?!? */
95 	mbp = bp = (char *)malloc(strlen(pw->pw_gecos)+1);
96 	strcpy(bp, pw->pw_gecos);
97 	if (*bp == '*')
98 		++bp;
99 
100 	/* ampersands get replaced by the login name */
101 	if (!(p = strsep(&bp, ","))) {
102 		free(mbp);
103 		return;
104 	}
105 	for (len = 0, t = p; *p; ++p) {
106 		len++;
107 		if (*p == '&')
108 			len += strlen(pw->pw_name);
109 	}
110 	name = (char *)malloc(len + 1);
111 	for (p = t, t = name; *t = *p; ++p)
112 		if (*t == '&') {
113 			(void)strcpy(t, pw->pw_name);
114 			if (islower(*t))
115 				*t = toupper(*t);
116 			while (*++t);
117 		} else
118 			++t;
119 	*t = '\0';
120 	pn->realname = strdup(name);
121 	pn->office = ((p = strsep(&bp, ",")) && *p) ?
122 	    strdup(p) : NULL;
123 	pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
124 	    strdup(p) : NULL;
125 	pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
126 	    strdup(p) : NULL;
127 	(void)sprintf(tbuf, "%s/%s", _PATH_MAILSPOOL, pw->pw_name);
128 	pn->mailrecv = -1;		/* -1 == not_valid */
129 	if (stat(tbuf, &sb) < 0) {
130 		if (errno != ENOENT) {
131 			(void)fprintf(stderr,
132 			    "finger: %s: %s\n", tbuf, strerror(errno));
133 			free(name);
134 			free(mbp);
135 			return;
136 		}
137 	} else if (sb.st_size != 0) {
138 		pn->mailrecv = sb.st_mtime;
139 		pn->mailread = sb.st_atime;
140 	}
141 	free(name);
142 	free(mbp);
143 }
144 
145 match(pw, user)
146 	struct passwd *pw;
147 	char *user;
148 {
149 	register char *p, *t;
150 	char name[1024];
151 
152 	/* why do we skip asterisks!?!? */
153 	(void)strcpy(p = tbuf, pw->pw_gecos);
154 	if (*p == '*')
155 		++p;
156 
157 	/* ampersands get replaced by the login name */
158 	if (!(p = strtok(p, ",")))
159 		return(0);
160 	for (t = name; *t = *p; ++p)
161 		if (*t == '&') {
162 			(void)strcpy(t, pw->pw_name);
163 			while (*++t);
164 		}
165 		else
166 			++t;
167 	for (t = name; p = strtok(t, "\t "); t = (char *)NULL)
168 		if (!strcasecmp(p, user))
169 			return(1);
170 	return(0);
171 }
172 
173 enter_lastlog(pn)
174 	register PERSON *pn;
175 {
176 	register WHERE *w;
177 	static int opened, fd;
178 	struct lastlog ll;
179 	char doit = 0;
180 
181 	/* some systems may not maintain lastlog, don't report errors. */
182 	if (!opened) {
183 		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
184 		opened = 1;
185 	}
186 	if (fd == -1 ||
187 	    lseek(fd, (off_t)(pn->uid * sizeof(ll)), SEEK_SET) !=
188 	    (long)pn->uid * sizeof(ll) ||
189 	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
190 			/* as if never logged in */
191 			ll.ll_line[0] = ll.ll_host[0] = NULL;
192 			ll.ll_time = 0;
193 		}
194 	if ((w = pn->whead) == NULL)
195 		doit = 1;
196 	else if (ll.ll_time != 0) {
197 		/* if last login is earlier than some current login */
198 		for (; !doit && w != NULL; w = w->next)
199 			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
200 				doit = 1;
201 		/*
202 		 * and if it's not any of the current logins
203 		 * can't use time comparison because there may be a small
204 		 * discrepency since login calls time() twice
205 		 */
206 		for (w = pn->whead; doit && w != NULL; w = w->next)
207 			if (w->info == LOGGEDIN &&
208 			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
209 				doit = 0;
210 	}
211 	if (doit) {
212 		w = walloc(pn);
213 		w->info = LASTLOG;
214 		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
215 		w->tty[UT_LINESIZE] = 0;
216 		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
217 		w->host[UT_HOSTSIZE] = 0;
218 		w->loginat = ll.ll_time;
219 	}
220 }
221 
222 enter_where(ut, pn)
223 	struct utmp *ut;
224 	PERSON *pn;
225 {
226 	register WHERE *w = walloc(pn);
227 
228 	w->info = LOGGEDIN;
229 	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
230 	w->tty[UT_LINESIZE] = 0;
231 	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
232 	w->host[UT_HOSTSIZE] = 0;
233 	w->loginat = (time_t)ut->ut_time;
234 	find_idle_and_ttywrite(w);
235 }
236 
237 PERSON *
238 enter_person(pw)
239 	register struct passwd *pw;
240 {
241 	register PERSON *pn, **pp;
242 
243 	for (pp = htab + hash(pw->pw_name);
244 	     *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
245 	     pp = &(*pp)->hlink)
246 		;
247 	if ((pn = *pp) == NULL) {
248 		pn = palloc();
249 		entries++;
250 		if (phead == NULL)
251 			phead = ptail = pn;
252 		else {
253 			ptail->next = pn;
254 			ptail = pn;
255 		}
256 		pn->next = NULL;
257 		pn->hlink = NULL;
258 		*pp = pn;
259 		userinfo(pn, pw);
260 		pn->whead = NULL;
261 	}
262 	return(pn);
263 }
264 
265 PERSON *
266 find_person(name)
267 	char *name;
268 {
269 	register PERSON *pn;
270 
271 	/* name may be only UT_NAMESIZE long and not terminated */
272 	for (pn = htab[hash(name)];
273 	     pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
274 	     pn = pn->hlink)
275 		;
276 	return(pn);
277 }
278 
279 hash(name)
280 	register char *name;
281 {
282 	register int h, i;
283 
284 	h = 0;
285 	/* name may be only UT_NAMESIZE long and not terminated */
286 	for (i = UT_NAMESIZE; --i >= 0 && *name;)
287 		h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK;
288 	return(h);
289 }
290 
291 PERSON *
292 palloc()
293 {
294 	PERSON *p;
295 
296 	if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
297 		(void)fprintf(stderr, "finger: out of space.\n");
298 		exit(1);
299 	}
300 	return(p);
301 }
302 
303 WHERE *
304 walloc(pn)
305 	register PERSON *pn;
306 {
307 	register WHERE *w;
308 
309 	if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
310 		(void)fprintf(stderr, "finger: out of space.\n");
311 		exit(1);
312 	}
313 	if (pn->whead == NULL)
314 		pn->whead = pn->wtail = w;
315 	else {
316 		pn->wtail->next = w;
317 		pn->wtail = w;
318 	}
319 	w->next = NULL;
320 	return(w);
321 }
322 
323 char *
324 prphone(num)
325 	char *num;
326 {
327 	register char *p;
328 	int len;
329 	static char pbuf[15];
330 
331 	/* don't touch anything if the user has their own formatting */
332 	for (p = num; *p; ++p)
333 		if (!isdigit(*p))
334 			return(num);
335 	len = p - num;
336 	p = pbuf;
337 	switch(len) {
338 	case 11:			/* +0-123-456-7890 */
339 		*p++ = '+';
340 		*p++ = *num++;
341 		*p++ = '-';
342 		/* FALLTHROUGH */
343 	case 10:			/* 012-345-6789 */
344 		*p++ = *num++;
345 		*p++ = *num++;
346 		*p++ = *num++;
347 		*p++ = '-';
348 		/* FALLTHROUGH */
349 	case 7:				/* 012-3456 */
350 		*p++ = *num++;
351 		*p++ = *num++;
352 		*p++ = *num++;
353 		break;
354 	case 5:				/* x0-1234 */
355 	case 4:				/* x1234 */
356 		*p++ = 'x';
357 		*p++ = *num++;
358 		break;
359 	default:
360 		return(num);
361 	}
362 	if (len != 4) {
363 		*p++ = '-';
364 		*p++ = *num++;
365 	}
366 	*p++ = *num++;
367 	*p++ = *num++;
368 	*p++ = *num++;
369 	*p = '\0';
370 	return(pbuf);
371 }
372