137660Sbostic /*
261995Sbostic * Copyright (c) 1989, 1993
361995Sbostic * The Regents of the University of California. All rights reserved.
437660Sbostic *
540027Sbostic * This code is derived from software contributed to Berkeley by
640027Sbostic * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
740027Sbostic *
842731Sbostic * %sccs.include.redist.c%
937660Sbostic */
1037660Sbostic
1137660Sbostic #ifndef lint
12*69102Sbostic static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 04/28/95";
1337660Sbostic #endif /* not lint */
1437660Sbostic
1537660Sbostic #include <sys/param.h>
1637660Sbostic #include <sys/stat.h>
1750596Sbostic #include <fcntl.h>
1850613Sbostic #include <db.h>
1969101Sbostic #include <err.h>
2050596Sbostic #include <pwd.h>
2150596Sbostic #include <utmp.h>
2250596Sbostic #include <errno.h>
2350596Sbostic #include <unistd.h>
2437660Sbostic #include <stdio.h>
2537660Sbostic #include <ctype.h>
2650596Sbostic #include <stdlib.h>
2742053Sbostic #include <string.h>
2843857Sbostic #include <paths.h>
2937660Sbostic #include "finger.h"
3037660Sbostic
3150596Sbostic static void find_idle_and_ttywrite __P((WHERE *));
3250596Sbostic static void userinfo __P((PERSON *, struct passwd *));
3350596Sbostic static WHERE *walloc __P((PERSON *));
3450596Sbostic
3551423Sbostic int
match(pw,user)3637660Sbostic match(pw, user)
3737660Sbostic struct passwd *pw;
3837660Sbostic char *user;
3937660Sbostic {
4037660Sbostic register char *p, *t;
4141568Smarc char name[1024];
4237660Sbostic
4352851Sbostic if (!strcasecmp(pw->pw_name, user))
4452851Sbostic return(1);
4552851Sbostic
4652851Sbostic /*
4752851Sbostic * XXX
4852851Sbostic * Why do we skip asterisks!?!?
4952851Sbostic */
5037660Sbostic (void)strcpy(p = tbuf, pw->pw_gecos);
5137660Sbostic if (*p == '*')
5237660Sbostic ++p;
5337660Sbostic
5452851Sbostic /* Ampersands get replaced by the login name. */
5552851Sbostic if ((p = strtok(p, ",")) == NULL)
5637660Sbostic return(0);
5752851Sbostic
5869101Sbostic for (t = name; (*t = *p) != '\0'; ++p)
5937660Sbostic if (*t == '&') {
6037660Sbostic (void)strcpy(t, pw->pw_name);
6137660Sbostic while (*++t);
6237660Sbostic }
6337660Sbostic else
6437660Sbostic ++t;
6569101Sbostic for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
6637660Sbostic if (!strcasecmp(p, user))
6737660Sbostic return(1);
6837660Sbostic return(0);
6937660Sbostic }
7037660Sbostic
7150596Sbostic void
enter_lastlog(pn)7237664Sedward enter_lastlog(pn)
7337660Sbostic register PERSON *pn;
7437660Sbostic {
7537664Sedward register WHERE *w;
7637683Sedward static int opened, fd;
7737660Sbostic struct lastlog ll;
7837664Sedward char doit = 0;
7937660Sbostic
8037665Sbostic /* some systems may not maintain lastlog, don't report errors. */
8137665Sbostic if (!opened) {
8237664Sedward fd = open(_PATH_LASTLOG, O_RDONLY, 0);
8337665Sbostic opened = 1;
8437660Sbostic }
8537665Sbostic if (fd == -1 ||
8650596Sbostic lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
8737665Sbostic (long)pn->uid * sizeof(ll) ||
8837665Sbostic read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
8937665Sbostic /* as if never logged in */
9037665Sbostic ll.ll_line[0] = ll.ll_host[0] = NULL;
9137665Sbostic ll.ll_time = 0;
9237665Sbostic }
9337664Sedward if ((w = pn->whead) == NULL)
9437664Sedward doit = 1;
9537683Sedward else if (ll.ll_time != 0) {
9637664Sedward /* if last login is earlier than some current login */
9737664Sedward for (; !doit && w != NULL; w = w->next)
9837664Sedward if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
9937664Sedward doit = 1;
10037664Sedward /*
10137664Sedward * and if it's not any of the current logins
10237664Sedward * can't use time comparison because there may be a small
10337664Sedward * discrepency since login calls time() twice
10437664Sedward */
10537664Sedward for (w = pn->whead; doit && w != NULL; w = w->next)
10637664Sedward if (w->info == LOGGEDIN &&
10737664Sedward strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
10837664Sedward doit = 0;
10937660Sbostic }
11037664Sedward if (doit) {
11137664Sedward w = walloc(pn);
11237664Sedward w->info = LASTLOG;
11337664Sedward bcopy(ll.ll_line, w->tty, UT_LINESIZE);
11437664Sedward w->tty[UT_LINESIZE] = 0;
11537664Sedward bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
11637664Sedward w->host[UT_HOSTSIZE] = 0;
11737664Sedward w->loginat = ll.ll_time;
11837664Sedward }
11937660Sbostic }
12037660Sbostic
12150596Sbostic void
enter_where(ut,pn)12237664Sedward enter_where(ut, pn)
12337660Sbostic struct utmp *ut;
12437660Sbostic PERSON *pn;
12537660Sbostic {
12650596Sbostic register WHERE *w;
12737664Sedward
12850596Sbostic w = walloc(pn);
12937664Sedward w->info = LOGGEDIN;
13037664Sedward bcopy(ut->ut_line, w->tty, UT_LINESIZE);
13137664Sedward w->tty[UT_LINESIZE] = 0;
13237664Sedward bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
13337664Sedward w->host[UT_HOSTSIZE] = 0;
13437664Sedward w->loginat = (time_t)ut->ut_time;
13537664Sedward find_idle_and_ttywrite(w);
13637660Sbostic }
13737664Sedward
13837664Sedward PERSON *
enter_person(pw)13937664Sedward enter_person(pw)
14037664Sedward register struct passwd *pw;
14137664Sedward {
14251423Sbostic DBT data, key;
14350613Sbostic PERSON *pn;
14437664Sedward
14551423Sbostic if (db == NULL &&
14651423Sbostic (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
14769101Sbostic err(1, NULL);
14850613Sbostic
14950613Sbostic key.data = pw->pw_name;
15050613Sbostic key.size = strlen(pw->pw_name);
15150613Sbostic
15269101Sbostic switch ((*db->get)(db, &key, &data, 0)) {
15350613Sbostic case 0:
154*69102Sbostic memmove(&pn, data.data, sizeof pn);
15569101Sbostic return (pn);
15650613Sbostic default:
15750613Sbostic case -1:
15869101Sbostic err(1, "db get");
15950613Sbostic /* NOTREACHED */
16050613Sbostic case 1:
16150613Sbostic ++entries;
16237664Sedward pn = palloc();
16337664Sedward userinfo(pn, pw);
16437664Sedward pn->whead = NULL;
16550613Sbostic
16650613Sbostic data.size = sizeof(PERSON *);
16750613Sbostic data.data = &pn;
16851178Sbostic if ((*db->put)(db, &key, &data, 0))
16969101Sbostic err(1, "db put");
17069101Sbostic return (pn);
17137664Sedward }
17237664Sedward }
17337664Sedward
17437664Sedward PERSON *
find_person(name)17537664Sedward find_person(name)
17637664Sedward char *name;
17737664Sedward {
17850613Sbostic register int cnt;
17950613Sbostic DBT data, key;
18069101Sbostic PERSON *p;
18150613Sbostic char buf[UT_NAMESIZE + 1];
18237664Sedward
18350613Sbostic if (!db)
18450613Sbostic return(NULL);
18537664Sedward
18650613Sbostic /* Name may be only UT_NAMESIZE long and not NUL terminated. */
18750613Sbostic for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
18850613Sbostic buf[cnt] = *name;
18950613Sbostic buf[cnt] = '\0';
19050613Sbostic key.data = buf;
19150613Sbostic key.size = cnt;
19237664Sedward
19369101Sbostic if ((*db->get)(db, &key, &data, 0))
19469101Sbostic return (NULL);
195*69102Sbostic memmove(&p, data.data, sizeof p);
19669101Sbostic return (p);
19737664Sedward }
19837664Sedward
19937664Sedward PERSON *
palloc()20037664Sedward palloc()
20137664Sedward {
20237664Sedward PERSON *p;
20337664Sedward
20450596Sbostic if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
20569101Sbostic err(1, NULL);
20637664Sedward return(p);
20737664Sedward }
20837664Sedward
20950596Sbostic static WHERE *
walloc(pn)21037664Sedward walloc(pn)
21137664Sedward register PERSON *pn;
21237664Sedward {
21337664Sedward register WHERE *w;
21437664Sedward
21550613Sbostic if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
21669101Sbostic err(1, NULL);
21737664Sedward if (pn->whead == NULL)
21837664Sedward pn->whead = pn->wtail = w;
21937664Sedward else {
22037664Sedward pn->wtail->next = w;
22137664Sedward pn->wtail = w;
22237664Sedward }
22337664Sedward w->next = NULL;
22437664Sedward return(w);
22537664Sedward }
22638052Sbostic
22738052Sbostic char *
prphone(num)22838052Sbostic prphone(num)
22938052Sbostic char *num;
23038052Sbostic {
23138052Sbostic register char *p;
23238052Sbostic int len;
23338052Sbostic static char pbuf[15];
23438052Sbostic
23538052Sbostic /* don't touch anything if the user has their own formatting */
23638052Sbostic for (p = num; *p; ++p)
23738052Sbostic if (!isdigit(*p))
23838052Sbostic return(num);
23938052Sbostic len = p - num;
24038052Sbostic p = pbuf;
24138052Sbostic switch(len) {
24238052Sbostic case 11: /* +0-123-456-7890 */
24338052Sbostic *p++ = '+';
24438052Sbostic *p++ = *num++;
24538052Sbostic *p++ = '-';
24638052Sbostic /* FALLTHROUGH */
24738052Sbostic case 10: /* 012-345-6789 */
24838052Sbostic *p++ = *num++;
24938052Sbostic *p++ = *num++;
25038052Sbostic *p++ = *num++;
25138052Sbostic *p++ = '-';
25238052Sbostic /* FALLTHROUGH */
25338052Sbostic case 7: /* 012-3456 */
25438052Sbostic *p++ = *num++;
25538052Sbostic *p++ = *num++;
25638052Sbostic *p++ = *num++;
25738052Sbostic break;
25838052Sbostic case 5: /* x0-1234 */
25938052Sbostic *p++ = 'x';
26038052Sbostic *p++ = *num++;
26138052Sbostic break;
26238052Sbostic default:
26338052Sbostic return(num);
26438052Sbostic }
26538052Sbostic *p++ = '-';
26638052Sbostic *p++ = *num++;
26738052Sbostic *p++ = *num++;
26838052Sbostic *p++ = *num++;
26938052Sbostic *p++ = *num++;
27038052Sbostic *p = '\0';
27138052Sbostic return(pbuf);
27238052Sbostic }
27350596Sbostic
27450613Sbostic static void
find_idle_and_ttywrite(w)27550613Sbostic find_idle_and_ttywrite(w)
27650613Sbostic register WHERE *w;
27750613Sbostic {
27850613Sbostic extern time_t now;
27950613Sbostic struct stat sb;
28050613Sbostic
28150613Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
28250613Sbostic if (stat(tbuf, &sb) < 0) {
28369101Sbostic warn(tbuf);
28450613Sbostic return;
28550613Sbostic }
28650613Sbostic w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
28750613Sbostic
28850613Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */
28950613Sbostic w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
29050613Sbostic }
29150613Sbostic
29250613Sbostic static void
userinfo(pn,pw)29350613Sbostic userinfo(pn, pw)
29450613Sbostic register PERSON *pn;
29550613Sbostic register struct passwd *pw;
29650613Sbostic {
29750613Sbostic register char *p, *t;
29850613Sbostic char *bp, name[1024];
29950613Sbostic
30050613Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
30150613Sbostic
30250613Sbostic pn->uid = pw->pw_uid;
30350613Sbostic pn->name = strdup(pw->pw_name);
30450613Sbostic pn->dir = strdup(pw->pw_dir);
30550613Sbostic pn->shell = strdup(pw->pw_shell);
30650613Sbostic
30750613Sbostic /* why do we skip asterisks!?!? */
30850613Sbostic (void)strcpy(bp = tbuf, pw->pw_gecos);
30950613Sbostic if (*bp == '*')
31050613Sbostic ++bp;
31150613Sbostic
31250613Sbostic /* ampersands get replaced by the login name */
31350613Sbostic if (!(p = strsep(&bp, ",")))
31450613Sbostic return;
31569101Sbostic for (t = name; (*t = *p) != '\0'; ++p)
31650613Sbostic if (*t == '&') {
31750613Sbostic (void)strcpy(t, pw->pw_name);
31850613Sbostic if (islower(*t))
31950613Sbostic *t = toupper(*t);
32050613Sbostic while (*++t);
32150613Sbostic }
32250613Sbostic else
32350613Sbostic ++t;
32450613Sbostic pn->realname = strdup(name);
32550613Sbostic pn->office = ((p = strsep(&bp, ",")) && *p) ?
32650613Sbostic strdup(p) : NULL;
32750613Sbostic pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
32850613Sbostic strdup(p) : NULL;
32950613Sbostic pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
33050613Sbostic strdup(p) : NULL;
33150613Sbostic }
332