xref: /original-bsd/usr.bin/finger/util.c (revision fbc8b8c6)
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.5 (Berkeley) 05/08/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, ",")) ? strdup(p) : NULL;
84 	pn->officephone = (p = strsep((char *)NULL, ",")) ? strdup(p) : NULL;
85 	pn->homephone = (p = strsep((char *)NULL, ",")) ? strdup(p) : NULL;
86 }
87 
88 match(pw, user)
89 	struct passwd *pw;
90 	char *user;
91 {
92 	register char *p, *t;
93 	char name[256];
94 
95 	/* why do we skip asterisks!?!? */
96 	(void)strcpy(p = tbuf, pw->pw_gecos);
97 	if (*p == '*')
98 		++p;
99 
100 	/* ampersands get replaced by the login name */
101 	if (!(p = strtok(p, ",")))
102 		return(0);
103 	for (t = name; *t = *p; ++p)
104 		if (*t == '&') {
105 			(void)strcpy(t, pw->pw_name);
106 			while (*++t);
107 		}
108 		else
109 			++t;
110 	for (t = name; p = strtok(t, "\t "); t = (char *)NULL)
111 		if (!strcasecmp(p, user))
112 			return(1);
113 	return(0);
114 }
115 
116 enter_lastlog(pn)
117 	register PERSON *pn;
118 {
119 	register WHERE *w;
120 	static int opened, fd;
121 	struct lastlog ll;
122 	char doit = 0;
123 	off_t lseek();
124 
125 	/* some systems may not maintain lastlog, don't report errors. */
126 	if (!opened) {
127 		fd = open(_PATH_LASTLOG, O_RDONLY, 0);
128 		opened = 1;
129 	}
130 	if (fd == -1 ||
131 	    lseek(fd, (long)pn->uid * sizeof(ll), L_SET) !=
132 	    (long)pn->uid * sizeof(ll) ||
133 	    read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
134 			/* as if never logged in */
135 			ll.ll_line[0] = ll.ll_host[0] = NULL;
136 			ll.ll_time = 0;
137 		}
138 	if ((w = pn->whead) == NULL)
139 		doit = 1;
140 	else if (ll.ll_time != 0) {
141 		/* if last login is earlier than some current login */
142 		for (; !doit && w != NULL; w = w->next)
143 			if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
144 				doit = 1;
145 		/*
146 		 * and if it's not any of the current logins
147 		 * can't use time comparison because there may be a small
148 		 * discrepency since login calls time() twice
149 		 */
150 		for (w = pn->whead; doit && w != NULL; w = w->next)
151 			if (w->info == LOGGEDIN &&
152 			    strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
153 				doit = 0;
154 	}
155 	if (doit) {
156 		w = walloc(pn);
157 		w->info = LASTLOG;
158 		bcopy(ll.ll_line, w->tty, UT_LINESIZE);
159 		w->tty[UT_LINESIZE] = 0;
160 		bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
161 		w->host[UT_HOSTSIZE] = 0;
162 		w->loginat = ll.ll_time;
163 	}
164 }
165 
166 enter_where(ut, pn)
167 	struct utmp *ut;
168 	PERSON *pn;
169 {
170 	register WHERE *w = walloc(pn);
171 
172 	w->info = LOGGEDIN;
173 	bcopy(ut->ut_line, w->tty, UT_LINESIZE);
174 	w->tty[UT_LINESIZE] = 0;
175 	bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
176 	w->host[UT_HOSTSIZE] = 0;
177 	w->loginat = (time_t)ut->ut_time;
178 	find_idle_and_ttywrite(w);
179 }
180 
181 PERSON *
182 enter_person(pw)
183 	register struct passwd *pw;
184 {
185 	register PERSON *pn, **pp;
186 
187 	for (pp = htab + hash(pw->pw_name);
188 	     *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
189 	     pp = &(*pp)->hlink)
190 		;
191 	if ((pn = *pp) == NULL) {
192 		pn = palloc();
193 		entries++;
194 		if (phead == NULL)
195 			phead = ptail = pn;
196 		else {
197 			ptail->next = pn;
198 			ptail = pn;
199 		}
200 		pn->next = NULL;
201 		pn->hlink = NULL;
202 		*pp = pn;
203 		userinfo(pn, pw);
204 		pn->whead = NULL;
205 	}
206 	return(pn);
207 }
208 
209 PERSON *
210 find_person(name)
211 	char *name;
212 {
213 	register PERSON *pn;
214 
215 	/* name may be only UT_NAMESIZE long and not terminated */
216 	for (pn = htab[hash(name)];
217 	     pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
218 	     pn = pn->hlink)
219 		;
220 	return(pn);
221 }
222 
223 hash(name)
224 	register char *name;
225 {
226 	register int h, i;
227 
228 	h = 0;
229 	/* name may be only UT_NAMESIZE long and not terminated */
230 	for (i = UT_NAMESIZE; --i >= 0 && *name;)
231 		h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK;
232 	return(h);
233 }
234 
235 PERSON *
236 palloc()
237 {
238 	PERSON *p;
239 
240 	if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
241 		(void)fprintf(stderr, "finger: out of space.\n");
242 		exit(1);
243 	}
244 	return(p);
245 }
246 
247 WHERE *
248 walloc(pn)
249 	register PERSON *pn;
250 {
251 	register WHERE *w;
252 
253 	if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
254 		(void)fprintf(stderr, "finger: out of space.\n");
255 		exit(1);
256 	}
257 	if (pn->whead == NULL)
258 		pn->whead = pn->wtail = w;
259 	else {
260 		pn->wtail->next = w;
261 		pn->wtail = w;
262 	}
263 	w->next = NULL;
264 	return(w);
265 }
266