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