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