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