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