util.c revision 1.14.6.1 1 1.14.6.1 wrstuden /* $NetBSD: util.c,v 1.14.6.1 1999/12/27 18:36:55 wrstuden Exp $ */
2 1.9 tls
3 1.1 cgd /*
4 1.11 mrg * Copyright (c) 1989, 1993
5 1.11 mrg * The Regents of the University of California. All rights reserved.
6 1.7 lukem * Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman
7 1.1 cgd *
8 1.1 cgd * This code is derived from software contributed to Berkeley by
9 1.1 cgd * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
10 1.1 cgd *
11 1.1 cgd * Redistribution and use in source and binary forms, with or without
12 1.1 cgd * modification, are permitted provided that the following conditions
13 1.1 cgd * are met:
14 1.1 cgd * 1. Redistributions of source code must retain the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer.
16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 cgd * notice, this list of conditions and the following disclaimer in the
18 1.1 cgd * documentation and/or other materials provided with the distribution.
19 1.1 cgd * 3. All advertising materials mentioning features or use of this software
20 1.1 cgd * must display the following acknowledgement:
21 1.1 cgd * This product includes software developed by the University of
22 1.1 cgd * California, Berkeley and its contributors.
23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
24 1.1 cgd * may be used to endorse or promote products derived from this software
25 1.1 cgd * without specific prior written permission.
26 1.1 cgd *
27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.1 cgd * SUCH DAMAGE.
38 1.1 cgd */
39 1.1 cgd
40 1.11 mrg #include <sys/cdefs.h>
41 1.1 cgd #ifndef lint
42 1.11 mrg #if 0
43 1.11 mrg static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
44 1.11 mrg #else
45 1.14.6.1 wrstuden __RCSID("$NetBSD: util.c,v 1.14.6.1 1999/12/27 18:36:55 wrstuden Exp $");
46 1.11 mrg #endif
47 1.1 cgd #endif /* not lint */
48 1.1 cgd
49 1.1 cgd #include <sys/param.h>
50 1.1 cgd #include <sys/stat.h>
51 1.11 mrg
52 1.11 mrg #include <db.h>
53 1.11 mrg #include <ctype.h>
54 1.11 mrg #include <err.h>
55 1.11 mrg #include <errno.h>
56 1.11 mrg #include <fcntl.h>
57 1.11 mrg #include <paths.h>
58 1.11 mrg #include <pwd.h>
59 1.1 cgd #include <stdio.h>
60 1.5 cgd #include <stdlib.h>
61 1.1 cgd #include <string.h>
62 1.7 lukem #include <unistd.h>
63 1.11 mrg #include <utmp.h>
64 1.11 mrg
65 1.1 cgd #include "finger.h"
66 1.7 lukem #include "extern.h"
67 1.1 cgd
68 1.11 mrg static void find_idle_and_ttywrite __P((WHERE *));
69 1.11 mrg static void userinfo __P((PERSON *, struct passwd *));
70 1.11 mrg static WHERE *walloc __P((PERSON *));
71 1.1 cgd
72 1.7 lukem int
73 1.1 cgd match(pw, user)
74 1.1 cgd struct passwd *pw;
75 1.1 cgd char *user;
76 1.1 cgd {
77 1.12 mycroft char *p;
78 1.12 mycroft char *bp, name[1024];
79 1.1 cgd
80 1.11 mrg if (!strcasecmp(pw->pw_name, user))
81 1.11 mrg return(1);
82 1.11 mrg
83 1.12 mycroft (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
84 1.1 cgd
85 1.11 mrg /* Ampersands get replaced by the login name. */
86 1.12 mycroft if (!(p = strsep(&bp, ",")))
87 1.1 cgd return(0);
88 1.11 mrg
89 1.7 lukem expandusername(p, pw->pw_name, name, sizeof(name));
90 1.12 mycroft bp = name;
91 1.12 mycroft while ((p = strsep(&bp, "\t ")))
92 1.1 cgd if (!strcasecmp(p, user))
93 1.1 cgd return(1);
94 1.1 cgd return(0);
95 1.1 cgd }
96 1.1 cgd
97 1.7 lukem /* inspired by usr.sbin/sendmail/util.c::buildfname */
98 1.7 lukem void
99 1.7 lukem expandusername(gecos, login, buf, buflen)
100 1.12 mycroft const char *gecos;
101 1.12 mycroft const char *login;
102 1.7 lukem char *buf;
103 1.7 lukem int buflen;
104 1.7 lukem {
105 1.12 mycroft const char *p;
106 1.12 mycroft char *bp;
107 1.7 lukem
108 1.7 lukem /* why do we skip asterisks!?!? */
109 1.7 lukem if (*gecos == '*')
110 1.7 lukem gecos++;
111 1.7 lukem bp = buf;
112 1.7 lukem
113 1.7 lukem /* copy gecos, interpolating & to be full name */
114 1.7 lukem for (p = gecos; *p != '\0'; p++) {
115 1.7 lukem if (bp >= &buf[buflen - 1]) {
116 1.7 lukem /* buffer overflow - just use login name */
117 1.7 lukem snprintf(buf, buflen, "%s", login);
118 1.7 lukem buf[buflen - 1] = '\0';
119 1.7 lukem return;
120 1.7 lukem }
121 1.7 lukem if (*p == '&') {
122 1.7 lukem /* interpolate full name */
123 1.7 lukem snprintf(bp, buflen - (bp - buf), "%s", login);
124 1.7 lukem *bp = toupper(*bp);
125 1.7 lukem bp += strlen(bp);
126 1.7 lukem }
127 1.7 lukem else
128 1.7 lukem *bp++ = *p;
129 1.7 lukem }
130 1.7 lukem *bp = '\0';
131 1.7 lukem }
132 1.7 lukem
133 1.7 lukem void
134 1.1 cgd enter_lastlog(pn)
135 1.7 lukem PERSON *pn;
136 1.1 cgd {
137 1.7 lukem WHERE *w;
138 1.1 cgd static int opened, fd;
139 1.1 cgd struct lastlog ll;
140 1.1 cgd char doit = 0;
141 1.1 cgd
142 1.1 cgd /* some systems may not maintain lastlog, don't report errors. */
143 1.1 cgd if (!opened) {
144 1.1 cgd fd = open(_PATH_LASTLOG, O_RDONLY, 0);
145 1.1 cgd opened = 1;
146 1.1 cgd }
147 1.1 cgd if (fd == -1 ||
148 1.11 mrg lseek(fd, (off_t)pn->uid * sizeof(ll), SEEK_SET) !=
149 1.1 cgd (long)pn->uid * sizeof(ll) ||
150 1.1 cgd read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
151 1.1 cgd /* as if never logged in */
152 1.10 pk ll.ll_line[0] = ll.ll_host[0] = '\0';
153 1.1 cgd ll.ll_time = 0;
154 1.1 cgd }
155 1.1 cgd if ((w = pn->whead) == NULL)
156 1.1 cgd doit = 1;
157 1.1 cgd else if (ll.ll_time != 0) {
158 1.1 cgd /* if last login is earlier than some current login */
159 1.1 cgd for (; !doit && w != NULL; w = w->next)
160 1.1 cgd if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
161 1.1 cgd doit = 1;
162 1.1 cgd /*
163 1.1 cgd * and if it's not any of the current logins
164 1.1 cgd * can't use time comparison because there may be a small
165 1.1 cgd * discrepency since login calls time() twice
166 1.1 cgd */
167 1.1 cgd for (w = pn->whead; doit && w != NULL; w = w->next)
168 1.1 cgd if (w->info == LOGGEDIN &&
169 1.1 cgd strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
170 1.1 cgd doit = 0;
171 1.1 cgd }
172 1.1 cgd if (doit) {
173 1.1 cgd w = walloc(pn);
174 1.1 cgd w->info = LASTLOG;
175 1.13 perry memcpy(w->tty, ll.ll_line, UT_LINESIZE);
176 1.1 cgd w->tty[UT_LINESIZE] = 0;
177 1.13 perry memcpy(w->host, ll.ll_host, UT_HOSTSIZE);
178 1.1 cgd w->host[UT_HOSTSIZE] = 0;
179 1.1 cgd w->loginat = ll.ll_time;
180 1.1 cgd }
181 1.1 cgd }
182 1.1 cgd
183 1.7 lukem void
184 1.1 cgd enter_where(ut, pn)
185 1.1 cgd struct utmp *ut;
186 1.1 cgd PERSON *pn;
187 1.1 cgd {
188 1.11 mrg WHERE *w;
189 1.1 cgd
190 1.11 mrg w = walloc(pn);
191 1.1 cgd w->info = LOGGEDIN;
192 1.13 perry memcpy(w->tty, ut->ut_line, UT_LINESIZE);
193 1.1 cgd w->tty[UT_LINESIZE] = 0;
194 1.13 perry memcpy(w->host, ut->ut_host, UT_HOSTSIZE);
195 1.1 cgd w->host[UT_HOSTSIZE] = 0;
196 1.1 cgd w->loginat = (time_t)ut->ut_time;
197 1.1 cgd find_idle_and_ttywrite(w);
198 1.1 cgd }
199 1.1 cgd
200 1.1 cgd PERSON *
201 1.1 cgd enter_person(pw)
202 1.7 lukem struct passwd *pw;
203 1.1 cgd {
204 1.11 mrg DBT data, key;
205 1.11 mrg PERSON *pn;
206 1.1 cgd
207 1.11 mrg if (db == NULL &&
208 1.11 mrg (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
209 1.11 mrg err(1, NULL);
210 1.11 mrg
211 1.12 mycroft key.data = (char *)pw->pw_name;
212 1.11 mrg key.size = strlen(pw->pw_name);
213 1.11 mrg
214 1.11 mrg switch ((*db->get)(db, &key, &data, 0)) {
215 1.11 mrg case 0:
216 1.11 mrg memmove(&pn, data.data, sizeof pn);
217 1.11 mrg return (pn);
218 1.11 mrg default:
219 1.11 mrg case -1:
220 1.11 mrg err(1, "db get");
221 1.11 mrg /* NOTREACHED */
222 1.11 mrg case 1:
223 1.11 mrg ++entries;
224 1.1 cgd pn = palloc();
225 1.1 cgd userinfo(pn, pw);
226 1.1 cgd pn->whead = NULL;
227 1.11 mrg
228 1.11 mrg data.size = sizeof(PERSON *);
229 1.11 mrg data.data = &pn;
230 1.11 mrg if ((*db->put)(db, &key, &data, 0))
231 1.11 mrg err(1, "db put");
232 1.11 mrg return (pn);
233 1.1 cgd }
234 1.1 cgd }
235 1.1 cgd
236 1.1 cgd PERSON *
237 1.1 cgd find_person(name)
238 1.1 cgd char *name;
239 1.1 cgd {
240 1.11 mrg int cnt;
241 1.11 mrg DBT data, key;
242 1.11 mrg PERSON *p;
243 1.11 mrg char buf[UT_NAMESIZE + 1];
244 1.1 cgd
245 1.11 mrg if (!db)
246 1.11 mrg return(NULL);
247 1.1 cgd
248 1.11 mrg /* Name may be only UT_NAMESIZE long and not NUL terminated. */
249 1.11 mrg for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
250 1.11 mrg buf[cnt] = *name;
251 1.11 mrg buf[cnt] = '\0';
252 1.11 mrg key.data = buf;
253 1.11 mrg key.size = cnt;
254 1.11 mrg
255 1.11 mrg if ((*db->get)(db, &key, &data, 0))
256 1.11 mrg return (NULL);
257 1.11 mrg memmove(&p, data.data, sizeof p);
258 1.11 mrg return (p);
259 1.1 cgd }
260 1.1 cgd
261 1.1 cgd PERSON *
262 1.1 cgd palloc()
263 1.1 cgd {
264 1.1 cgd PERSON *p;
265 1.1 cgd
266 1.11 mrg if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
267 1.11 mrg err(1, NULL);
268 1.1 cgd return(p);
269 1.1 cgd }
270 1.1 cgd
271 1.11 mrg static WHERE *
272 1.1 cgd walloc(pn)
273 1.7 lukem PERSON *pn;
274 1.1 cgd {
275 1.7 lukem WHERE *w;
276 1.1 cgd
277 1.11 mrg if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
278 1.11 mrg err(1, NULL);
279 1.1 cgd if (pn->whead == NULL)
280 1.1 cgd pn->whead = pn->wtail = w;
281 1.1 cgd else {
282 1.1 cgd pn->wtail->next = w;
283 1.1 cgd pn->wtail = w;
284 1.1 cgd }
285 1.1 cgd w->next = NULL;
286 1.1 cgd return(w);
287 1.1 cgd }
288 1.1 cgd
289 1.1 cgd char *
290 1.1 cgd prphone(num)
291 1.1 cgd char *num;
292 1.1 cgd {
293 1.7 lukem char *p;
294 1.1 cgd int len;
295 1.1 cgd static char pbuf[15];
296 1.1 cgd
297 1.1 cgd /* don't touch anything if the user has their own formatting */
298 1.1 cgd for (p = num; *p; ++p)
299 1.14 christos if (!isdigit((unsigned char)*p))
300 1.1 cgd return(num);
301 1.1 cgd len = p - num;
302 1.1 cgd p = pbuf;
303 1.1 cgd switch(len) {
304 1.1 cgd case 11: /* +0-123-456-7890 */
305 1.1 cgd *p++ = '+';
306 1.1 cgd *p++ = *num++;
307 1.1 cgd *p++ = '-';
308 1.1 cgd /* FALLTHROUGH */
309 1.1 cgd case 10: /* 012-345-6789 */
310 1.1 cgd *p++ = *num++;
311 1.1 cgd *p++ = *num++;
312 1.1 cgd *p++ = *num++;
313 1.1 cgd *p++ = '-';
314 1.1 cgd /* FALLTHROUGH */
315 1.1 cgd case 7: /* 012-3456 */
316 1.1 cgd *p++ = *num++;
317 1.1 cgd *p++ = *num++;
318 1.1 cgd *p++ = *num++;
319 1.1 cgd break;
320 1.1 cgd case 5: /* x0-1234 */
321 1.3 brezak case 4: /* x1234 */
322 1.1 cgd *p++ = 'x';
323 1.1 cgd *p++ = *num++;
324 1.1 cgd break;
325 1.1 cgd default:
326 1.1 cgd return(num);
327 1.1 cgd }
328 1.3 brezak if (len != 4) {
329 1.3 brezak *p++ = '-';
330 1.3 brezak *p++ = *num++;
331 1.3 brezak }
332 1.1 cgd *p++ = *num++;
333 1.1 cgd *p++ = *num++;
334 1.1 cgd *p++ = *num++;
335 1.1 cgd *p = '\0';
336 1.1 cgd return(pbuf);
337 1.11 mrg }
338 1.11 mrg
339 1.11 mrg static void
340 1.11 mrg find_idle_and_ttywrite(w)
341 1.11 mrg WHERE *w;
342 1.11 mrg {
343 1.11 mrg extern time_t now;
344 1.11 mrg struct stat sb;
345 1.11 mrg
346 1.11 mrg (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
347 1.11 mrg if (stat(tbuf, &sb) < 0) {
348 1.11 mrg warn(tbuf);
349 1.11 mrg return;
350 1.11 mrg }
351 1.11 mrg w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
352 1.11 mrg
353 1.11 mrg #define TALKABLE 0220 /* tty is writable if 220 mode */
354 1.11 mrg w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
355 1.11 mrg }
356 1.11 mrg
357 1.11 mrg static void
358 1.11 mrg userinfo(pn, pw)
359 1.11 mrg PERSON *pn;
360 1.11 mrg struct passwd *pw;
361 1.11 mrg {
362 1.11 mrg char *p;
363 1.11 mrg char *bp, name[1024];
364 1.11 mrg struct stat sb;
365 1.11 mrg
366 1.11 mrg pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
367 1.11 mrg
368 1.11 mrg pn->uid = pw->pw_uid;
369 1.11 mrg pn->name = strdup(pw->pw_name);
370 1.11 mrg pn->dir = strdup(pw->pw_dir);
371 1.11 mrg pn->shell = strdup(pw->pw_shell);
372 1.11 mrg
373 1.11 mrg (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
374 1.11 mrg tbuf[sizeof(tbuf) - 1] = '\0';
375 1.11 mrg
376 1.11 mrg /* ampersands get replaced by the login name */
377 1.11 mrg if (!(p = strsep(&bp, ",")))
378 1.11 mrg return;
379 1.11 mrg expandusername(p, pw->pw_name, name, sizeof(name));
380 1.11 mrg pn->realname = strdup(name);
381 1.11 mrg pn->office = ((p = strsep(&bp, ",")) && *p) ?
382 1.11 mrg strdup(p) : NULL;
383 1.11 mrg pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
384 1.11 mrg strdup(p) : NULL;
385 1.11 mrg pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
386 1.11 mrg strdup(p) : NULL;
387 1.11 mrg (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILSPOOL,
388 1.11 mrg pw->pw_name);
389 1.11 mrg pn->mailrecv = -1; /* -1 == not_valid */
390 1.11 mrg if (stat(tbuf, &sb) < 0) {
391 1.11 mrg if (errno != ENOENT) {
392 1.11 mrg (void)fprintf(stderr,
393 1.11 mrg "finger: %s: %s\n", tbuf, strerror(errno));
394 1.11 mrg return;
395 1.11 mrg }
396 1.11 mrg } else if (sb.st_size != 0) {
397 1.11 mrg pn->mailrecv = sb.st_mtime;
398 1.11 mrg pn->mailread = sb.st_atime;
399 1.11 mrg }
400 1.1 cgd }
401