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