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