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