Annotation of src/usr.bin/finger/util.c, Revision 1.7
1.7 ! kstailey 1: /* $OpenBSD: util.c,v 1.6 1997/06/02 21:33:28 kstailey 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.7 ! kstailey 42: static char rcsid[] = "$OpenBSD: util.c,v 1.6 1997/06/02 21:33:28 kstailey 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>
49: #include <sys/file.h>
1.6 kstailey 50: #include <err.h>
1.1 deraadt 51: #include <stdio.h>
52: #include <stdlib.h>
53: #include <ctype.h>
54: #include <string.h>
55: #include <paths.h>
56: #include <errno.h>
1.5 kstailey 57: #include <unistd.h>
1.6 kstailey 58: #include <vis.h>
1.1 deraadt 59: #include "finger.h"
1.5 kstailey 60: #include "extern.h"
1.1 deraadt 61:
1.5 kstailey 62: void
1.1 deraadt 63: find_idle_and_ttywrite(w)
1.5 kstailey 64: WHERE *w;
1.1 deraadt 65: {
66: struct stat sb;
67:
1.5 kstailey 68: (void)snprintf(tbuf, sizeof(tbuf), "%s%s", _PATH_DEV, w->tty);
1.1 deraadt 69: if (stat(tbuf, &sb) < 0) {
1.3 downsj 70: /* Don't bitch about it, just handle it... */
71: w->idletime = 0;
72: w->writable = 0;
73:
1.1 deraadt 74: return;
75: }
76: w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
77:
78: #define TALKABLE 0220 /* tty is writable if 220 mode */
79: w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
80: }
81:
1.5 kstailey 82: void
1.1 deraadt 83: userinfo(pn, pw)
1.5 kstailey 84: PERSON *pn;
85: struct passwd *pw;
1.1 deraadt 86: {
1.5 kstailey 87: char *p;
88: char *bp, name[1024];
1.1 deraadt 89: struct stat sb;
90:
91: pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
92:
93: pn->uid = pw->pw_uid;
94: pn->name = strdup(pw->pw_name);
95: pn->dir = strdup(pw->pw_dir);
96: pn->shell = strdup(pw->pw_shell);
97:
1.5 kstailey 98: (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
1.1 deraadt 99:
100: /* ampersands get replaced by the login name */
1.5 kstailey 101: if (!(p = strsep(&bp, ",")))
1.1 deraadt 102: return;
1.5 kstailey 103: expandusername(p, pw->pw_name, name, sizeof(name));
1.1 deraadt 104: pn->realname = strdup(name);
105: pn->office = ((p = strsep(&bp, ",")) && *p) ?
106: strdup(p) : NULL;
107: pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
108: strdup(p) : NULL;
109: pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
110: strdup(p) : NULL;
1.5 kstailey 111: (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILSPOOL,
112: pw->pw_name);
1.1 deraadt 113: pn->mailrecv = -1; /* -1 == not_valid */
114: if (stat(tbuf, &sb) < 0) {
115: if (errno != ENOENT) {
116: (void)fprintf(stderr,
117: "finger: %s: %s\n", tbuf, strerror(errno));
118: return;
119: }
120: } else if (sb.st_size != 0) {
121: pn->mailrecv = sb.st_mtime;
122: pn->mailread = sb.st_atime;
123: }
124: }
125:
1.5 kstailey 126: int
1.1 deraadt 127: match(pw, user)
128: struct passwd *pw;
129: char *user;
130: {
1.5 kstailey 131: char *p, *t;
1.1 deraadt 132: char name[1024];
133:
1.5 kstailey 134: (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf));
1.1 deraadt 135:
136: /* ampersands get replaced by the login name */
137: if (!(p = strtok(p, ",")))
138: return(0);
1.5 kstailey 139: expandusername(p, pw->pw_name, name, sizeof(name));
1.7 ! kstailey 140: for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
1.1 deraadt 141: if (!strcasecmp(p, user))
142: return(1);
143: return(0);
144: }
145:
1.5 kstailey 146: /* inspired by usr.sbin/sendmail/util.c::buildfname */
147: void
148: expandusername(gecos, login, buf, buflen)
149: char *gecos;
150: char *login;
151: char *buf;
152: int buflen;
153: {
154: char *p, *bp;
155:
156: /* why do we skip asterisks!?!? */
157: if (*gecos == '*')
158: gecos++;
159: bp = buf;
160:
161: /* copy gecos, interpolating & to be full name */
162: for (p = gecos; *p != '\0'; p++) {
163: if (bp >= &buf[buflen - 1]) {
164: /* buffer overflow - just use login name */
165: snprintf(buf, buflen, "%s", login);
166: buf[buflen - 1] = '\0';
167: return;
168: }
169: if (*p == '&') {
170: /* interpolate full name */
171: snprintf(bp, buflen - (bp - buf), "%s", login);
172: *bp = toupper(*bp);
173: bp += strlen(bp);
174: }
175: else
176: *bp++ = *p;
177: }
178: *bp = '\0';
179: }
180:
181: void
1.1 deraadt 182: enter_lastlog(pn)
1.5 kstailey 183: PERSON *pn;
1.1 deraadt 184: {
1.5 kstailey 185: WHERE *w;
1.1 deraadt 186: static int opened, fd;
187: struct lastlog ll;
188: char doit = 0;
189:
190: /* some systems may not maintain lastlog, don't report errors. */
191: if (!opened) {
192: fd = open(_PATH_LASTLOG, O_RDONLY, 0);
193: opened = 1;
194: }
195: if (fd == -1 ||
196: lseek(fd, (off_t)(pn->uid * sizeof(ll)), SEEK_SET) !=
197: (long)pn->uid * sizeof(ll) ||
198: read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
199: /* as if never logged in */
1.5 kstailey 200: ll.ll_line[0] = ll.ll_host[0] = '\0';
1.1 deraadt 201: ll.ll_time = 0;
202: }
203: if ((w = pn->whead) == NULL)
204: doit = 1;
205: else if (ll.ll_time != 0) {
206: /* if last login is earlier than some current login */
207: for (; !doit && w != NULL; w = w->next)
208: if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
209: doit = 1;
210: /*
211: * and if it's not any of the current logins
212: * can't use time comparison because there may be a small
213: * discrepency since login calls time() twice
214: */
215: for (w = pn->whead; doit && w != NULL; w = w->next)
216: if (w->info == LOGGEDIN &&
217: strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
218: doit = 0;
219: }
220: if (doit) {
221: w = walloc(pn);
222: w->info = LASTLOG;
223: bcopy(ll.ll_line, w->tty, UT_LINESIZE);
224: w->tty[UT_LINESIZE] = 0;
225: bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
226: w->host[UT_HOSTSIZE] = 0;
227: w->loginat = ll.ll_time;
228: }
229: }
230:
1.5 kstailey 231: void
1.1 deraadt 232: enter_where(ut, pn)
233: struct utmp *ut;
234: PERSON *pn;
235: {
1.5 kstailey 236: WHERE *w = walloc(pn);
1.1 deraadt 237:
238: w->info = LOGGEDIN;
239: bcopy(ut->ut_line, w->tty, UT_LINESIZE);
240: w->tty[UT_LINESIZE] = 0;
241: bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
242: w->host[UT_HOSTSIZE] = 0;
243: w->loginat = (time_t)ut->ut_time;
244: find_idle_and_ttywrite(w);
245: }
246:
247: PERSON *
248: enter_person(pw)
1.5 kstailey 249: struct passwd *pw;
1.1 deraadt 250: {
1.5 kstailey 251: PERSON *pn, **pp;
1.1 deraadt 252:
253: for (pp = htab + hash(pw->pw_name);
254: *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0;
255: pp = &(*pp)->hlink)
256: ;
257: if ((pn = *pp) == NULL) {
258: pn = palloc();
259: entries++;
260: if (phead == NULL)
261: phead = ptail = pn;
262: else {
263: ptail->next = pn;
264: ptail = pn;
265: }
266: pn->next = NULL;
267: pn->hlink = NULL;
268: *pp = pn;
269: userinfo(pn, pw);
270: pn->whead = NULL;
271: }
272: return(pn);
273: }
274:
275: PERSON *
276: find_person(name)
277: char *name;
278: {
1.5 kstailey 279: PERSON *pn;
1.1 deraadt 280:
281: /* name may be only UT_NAMESIZE long and not terminated */
282: for (pn = htab[hash(name)];
283: pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0;
284: pn = pn->hlink)
285: ;
286: return(pn);
287: }
288:
1.5 kstailey 289: int
1.1 deraadt 290: hash(name)
1.5 kstailey 291: char *name;
1.1 deraadt 292: {
1.5 kstailey 293: int h, i;
1.1 deraadt 294:
295: h = 0;
296: /* name may be only UT_NAMESIZE long and not terminated */
297: for (i = UT_NAMESIZE; --i >= 0 && *name;)
1.5 kstailey 298: h = ((h << 2 | h >> (HBITS - 2)) ^ *name++) & HMASK;
1.1 deraadt 299: return(h);
300: }
301:
302: PERSON *
303: palloc()
304: {
305: PERSON *p;
306:
307: if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) {
308: (void)fprintf(stderr, "finger: out of space.\n");
309: exit(1);
310: }
311: return(p);
312: }
313:
314: WHERE *
315: walloc(pn)
1.5 kstailey 316: PERSON *pn;
1.1 deraadt 317: {
1.5 kstailey 318: WHERE *w;
1.1 deraadt 319:
320: if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) {
321: (void)fprintf(stderr, "finger: out of space.\n");
322: exit(1);
323: }
324: if (pn->whead == NULL)
325: pn->whead = pn->wtail = w;
326: else {
327: pn->wtail->next = w;
328: pn->wtail = w;
329: }
330: w->next = NULL;
331: return(w);
332: }
333:
334: char *
335: prphone(num)
336: char *num;
337: {
1.5 kstailey 338: char *p;
1.1 deraadt 339: int len;
340: static char pbuf[15];
341:
342: /* don't touch anything if the user has their own formatting */
343: for (p = num; *p; ++p)
344: if (!isdigit(*p))
345: return(num);
346: len = p - num;
347: p = pbuf;
348: switch(len) {
349: case 11: /* +0-123-456-7890 */
350: *p++ = '+';
351: *p++ = *num++;
352: *p++ = '-';
353: /* FALLTHROUGH */
354: case 10: /* 012-345-6789 */
355: *p++ = *num++;
356: *p++ = *num++;
357: *p++ = *num++;
358: *p++ = '-';
359: /* FALLTHROUGH */
360: case 7: /* 012-3456 */
361: *p++ = *num++;
362: *p++ = *num++;
363: *p++ = *num++;
364: break;
365: case 5: /* x0-1234 */
366: case 4: /* x1234 */
367: *p++ = 'x';
368: *p++ = *num++;
369: break;
370: default:
371: return(num);
372: }
373: if (len != 4) {
374: *p++ = '-';
375: *p++ = *num++;
376: }
377: *p++ = *num++;
378: *p++ = *num++;
379: *p++ = *num++;
380: *p = '\0';
381: return(pbuf);
1.6 kstailey 382: }
383:
384: /* Like strvis(), but use malloc() to get the space and return a pointer
385: * to the beginning of the converted string, not the end.
386: *
387: * Recycle the malloc()ed area on each call. This leads to a leak which
388: * does not grow.
389: */
390: char *
391: vs(src)
392: char *src;
393: {
394: static char *dst = NULL;
395:
396: if (dst != NULL)
397: free(dst);
398: if ((dst = malloc((4 * strlen(src)) + 1)) == NULL)
399: err(1, "malloc failed");
400:
401: strvis(dst, src, VIS_SAFE|VIS_NOSLASH);
402: return(dst);
1.1 deraadt 403: }