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