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