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