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