137660Sbostic /* 237660Sbostic * Copyright (c) 1989 The Regents of the University of California. 337660Sbostic * 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*52851Sbostic static char sccsid[] = "@(#)util.c 5.19 (Berkeley) 03/06/92"; 1337660Sbostic #endif /* not lint */ 1437660Sbostic 1537660Sbostic #include <sys/param.h> 1637660Sbostic #include <sys/stat.h> 1750596Sbostic #include <fcntl.h> 1850613Sbostic #include <db.h> 1950596Sbostic #include <pwd.h> 2050596Sbostic #include <utmp.h> 2150596Sbostic #include <errno.h> 2250596Sbostic #include <unistd.h> 2337660Sbostic #include <stdio.h> 2437660Sbostic #include <ctype.h> 2550596Sbostic #include <stdlib.h> 2642053Sbostic #include <string.h> 2743857Sbostic #include <paths.h> 2837660Sbostic #include "finger.h" 2937660Sbostic 3050596Sbostic static void find_idle_and_ttywrite __P((WHERE *)); 3150596Sbostic static void userinfo __P((PERSON *, struct passwd *)); 3250596Sbostic static WHERE *walloc __P((PERSON *)); 3350596Sbostic 3451423Sbostic int 3537660Sbostic match(pw, user) 3637660Sbostic struct passwd *pw; 3737660Sbostic char *user; 3837660Sbostic { 3937660Sbostic register char *p, *t; 4041568Smarc char name[1024]; 4137660Sbostic 42*52851Sbostic if (!strcasecmp(pw->pw_name, user)) 43*52851Sbostic return(1); 44*52851Sbostic 45*52851Sbostic /* 46*52851Sbostic * XXX 47*52851Sbostic * Why do we skip asterisks!?!? 48*52851Sbostic */ 4937660Sbostic (void)strcpy(p = tbuf, pw->pw_gecos); 5037660Sbostic if (*p == '*') 5137660Sbostic ++p; 5237660Sbostic 53*52851Sbostic /* Ampersands get replaced by the login name. */ 54*52851Sbostic if ((p = strtok(p, ",")) == NULL) 5537660Sbostic return(0); 56*52851Sbostic 5737660Sbostic for (t = name; *t = *p; ++p) 5837660Sbostic if (*t == '&') { 5937660Sbostic (void)strcpy(t, pw->pw_name); 6037660Sbostic while (*++t); 6137660Sbostic } 6237660Sbostic else 6337660Sbostic ++t; 64*52851Sbostic for (t = name; p = strtok(t, "\t "); t = NULL) 6537660Sbostic if (!strcasecmp(p, user)) 6637660Sbostic return(1); 6737660Sbostic return(0); 6837660Sbostic } 6937660Sbostic 7050596Sbostic void 7137664Sedward enter_lastlog(pn) 7237660Sbostic register PERSON *pn; 7337660Sbostic { 7437664Sedward register WHERE *w; 7537683Sedward static int opened, fd; 7637660Sbostic struct lastlog ll; 7737664Sedward char doit = 0; 7837660Sbostic 7937665Sbostic /* some systems may not maintain lastlog, don't report errors. */ 8037665Sbostic if (!opened) { 8137664Sedward fd = open(_PATH_LASTLOG, O_RDONLY, 0); 8237665Sbostic opened = 1; 8337660Sbostic } 8437665Sbostic if (fd == -1 || 8550596Sbostic lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 8637665Sbostic (long)pn->uid * sizeof(ll) || 8737665Sbostic read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 8837665Sbostic /* as if never logged in */ 8937665Sbostic ll.ll_line[0] = ll.ll_host[0] = NULL; 9037665Sbostic ll.ll_time = 0; 9137665Sbostic } 9237664Sedward if ((w = pn->whead) == NULL) 9337664Sedward doit = 1; 9437683Sedward else if (ll.ll_time != 0) { 9537664Sedward /* if last login is earlier than some current login */ 9637664Sedward for (; !doit && w != NULL; w = w->next) 9737664Sedward if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 9837664Sedward doit = 1; 9937664Sedward /* 10037664Sedward * and if it's not any of the current logins 10137664Sedward * can't use time comparison because there may be a small 10237664Sedward * discrepency since login calls time() twice 10337664Sedward */ 10437664Sedward for (w = pn->whead; doit && w != NULL; w = w->next) 10537664Sedward if (w->info == LOGGEDIN && 10637664Sedward strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 10737664Sedward doit = 0; 10837660Sbostic } 10937664Sedward if (doit) { 11037664Sedward w = walloc(pn); 11137664Sedward w->info = LASTLOG; 11237664Sedward bcopy(ll.ll_line, w->tty, UT_LINESIZE); 11337664Sedward w->tty[UT_LINESIZE] = 0; 11437664Sedward bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 11537664Sedward w->host[UT_HOSTSIZE] = 0; 11637664Sedward w->loginat = ll.ll_time; 11737664Sedward } 11837660Sbostic } 11937660Sbostic 12050596Sbostic void 12137664Sedward enter_where(ut, pn) 12237660Sbostic struct utmp *ut; 12337660Sbostic PERSON *pn; 12437660Sbostic { 12550596Sbostic register WHERE *w; 12637664Sedward 12750596Sbostic w = walloc(pn); 12837664Sedward w->info = LOGGEDIN; 12937664Sedward bcopy(ut->ut_line, w->tty, UT_LINESIZE); 13037664Sedward w->tty[UT_LINESIZE] = 0; 13137664Sedward bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 13237664Sedward w->host[UT_HOSTSIZE] = 0; 13337664Sedward w->loginat = (time_t)ut->ut_time; 13437664Sedward find_idle_and_ttywrite(w); 13537660Sbostic } 13637664Sedward 13737664Sedward PERSON * 13837664Sedward enter_person(pw) 13937664Sedward register struct passwd *pw; 14037664Sedward { 14151423Sbostic DBT data, key; 14250613Sbostic PERSON *pn; 14337664Sedward 14451423Sbostic if (db == NULL && 14551423Sbostic (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 14650613Sbostic err("%s", strerror(errno)); 14750613Sbostic 14850613Sbostic key.data = pw->pw_name; 14950613Sbostic key.size = strlen(pw->pw_name); 15050613Sbostic 15150613Sbostic switch((*db->get)(db, &key, &data, 0)) { 15250613Sbostic case 0: 15350613Sbostic return(*(PERSON **)data.data); 15450613Sbostic default: 15550613Sbostic case -1: 15650613Sbostic err("db get: %s", strerror(errno)); 15750613Sbostic /* NOTREACHED */ 15850613Sbostic case 1: 15950613Sbostic ++entries; 16037664Sedward pn = palloc(); 16137664Sedward userinfo(pn, pw); 16237664Sedward pn->whead = NULL; 16350613Sbostic 16450613Sbostic data.size = sizeof(PERSON *); 16550613Sbostic data.data = &pn; 16651178Sbostic if ((*db->put)(db, &key, &data, 0)) 16750613Sbostic err("%s", strerror(errno)); 16850613Sbostic return(pn); 16937664Sedward } 17037664Sedward } 17137664Sedward 17237664Sedward PERSON * 17337664Sedward find_person(name) 17437664Sedward char *name; 17537664Sedward { 17650613Sbostic register int cnt; 17750613Sbostic DBT data, key; 17850613Sbostic char buf[UT_NAMESIZE + 1]; 17937664Sedward 18050613Sbostic if (!db) 18150613Sbostic return(NULL); 18237664Sedward 18350613Sbostic /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 18450613Sbostic for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 18550613Sbostic buf[cnt] = *name; 18650613Sbostic buf[cnt] = '\0'; 18750613Sbostic key.data = buf; 18850613Sbostic key.size = cnt; 18937664Sedward 19050613Sbostic return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 19137664Sedward } 19237664Sedward 19337664Sedward PERSON * 19437664Sedward palloc() 19537664Sedward { 19637664Sedward PERSON *p; 19737664Sedward 19850596Sbostic if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 19950596Sbostic err("%s", strerror(errno)); 20037664Sedward return(p); 20137664Sedward } 20237664Sedward 20350596Sbostic static WHERE * 20437664Sedward walloc(pn) 20537664Sedward register PERSON *pn; 20637664Sedward { 20737664Sedward register WHERE *w; 20837664Sedward 20950613Sbostic if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 21050613Sbostic err("%s", strerror(errno)); 21137664Sedward if (pn->whead == NULL) 21237664Sedward pn->whead = pn->wtail = w; 21337664Sedward else { 21437664Sedward pn->wtail->next = w; 21537664Sedward pn->wtail = w; 21637664Sedward } 21737664Sedward w->next = NULL; 21837664Sedward return(w); 21937664Sedward } 22038052Sbostic 22138052Sbostic char * 22238052Sbostic prphone(num) 22338052Sbostic char *num; 22438052Sbostic { 22538052Sbostic register char *p; 22638052Sbostic int len; 22738052Sbostic static char pbuf[15]; 22838052Sbostic 22938052Sbostic /* don't touch anything if the user has their own formatting */ 23038052Sbostic for (p = num; *p; ++p) 23138052Sbostic if (!isdigit(*p)) 23238052Sbostic return(num); 23338052Sbostic len = p - num; 23438052Sbostic p = pbuf; 23538052Sbostic switch(len) { 23638052Sbostic case 11: /* +0-123-456-7890 */ 23738052Sbostic *p++ = '+'; 23838052Sbostic *p++ = *num++; 23938052Sbostic *p++ = '-'; 24038052Sbostic /* FALLTHROUGH */ 24138052Sbostic case 10: /* 012-345-6789 */ 24238052Sbostic *p++ = *num++; 24338052Sbostic *p++ = *num++; 24438052Sbostic *p++ = *num++; 24538052Sbostic *p++ = '-'; 24638052Sbostic /* FALLTHROUGH */ 24738052Sbostic case 7: /* 012-3456 */ 24838052Sbostic *p++ = *num++; 24938052Sbostic *p++ = *num++; 25038052Sbostic *p++ = *num++; 25138052Sbostic break; 25238052Sbostic case 5: /* x0-1234 */ 25338052Sbostic *p++ = 'x'; 25438052Sbostic *p++ = *num++; 25538052Sbostic break; 25638052Sbostic default: 25738052Sbostic return(num); 25838052Sbostic } 25938052Sbostic *p++ = '-'; 26038052Sbostic *p++ = *num++; 26138052Sbostic *p++ = *num++; 26238052Sbostic *p++ = *num++; 26338052Sbostic *p++ = *num++; 26438052Sbostic *p = '\0'; 26538052Sbostic return(pbuf); 26638052Sbostic } 26750596Sbostic 26850613Sbostic static void 26950613Sbostic find_idle_and_ttywrite(w) 27050613Sbostic register WHERE *w; 27150613Sbostic { 27250613Sbostic extern time_t now; 27350613Sbostic struct stat sb; 27450613Sbostic 27550613Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 27650613Sbostic if (stat(tbuf, &sb) < 0) { 27750613Sbostic (void)fprintf(stderr, 27850613Sbostic "finger: %s: %s\n", tbuf, strerror(errno)); 27950613Sbostic return; 28050613Sbostic } 28150613Sbostic w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 28250613Sbostic 28350613Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */ 28450613Sbostic w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 28550613Sbostic } 28650613Sbostic 28750613Sbostic static void 28850613Sbostic userinfo(pn, pw) 28950613Sbostic register PERSON *pn; 29050613Sbostic register struct passwd *pw; 29150613Sbostic { 29250613Sbostic register char *p, *t; 29350613Sbostic char *bp, name[1024]; 29450613Sbostic 29550613Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 29650613Sbostic 29750613Sbostic pn->uid = pw->pw_uid; 29850613Sbostic pn->name = strdup(pw->pw_name); 29950613Sbostic pn->dir = strdup(pw->pw_dir); 30050613Sbostic pn->shell = strdup(pw->pw_shell); 30150613Sbostic 30250613Sbostic /* why do we skip asterisks!?!? */ 30350613Sbostic (void)strcpy(bp = tbuf, pw->pw_gecos); 30450613Sbostic if (*bp == '*') 30550613Sbostic ++bp; 30650613Sbostic 30750613Sbostic /* ampersands get replaced by the login name */ 30850613Sbostic if (!(p = strsep(&bp, ","))) 30950613Sbostic return; 31050613Sbostic for (t = name; *t = *p; ++p) 31150613Sbostic if (*t == '&') { 31250613Sbostic (void)strcpy(t, pw->pw_name); 31350613Sbostic if (islower(*t)) 31450613Sbostic *t = toupper(*t); 31550613Sbostic while (*++t); 31650613Sbostic } 31750613Sbostic else 31850613Sbostic ++t; 31950613Sbostic pn->realname = strdup(name); 32050613Sbostic pn->office = ((p = strsep(&bp, ",")) && *p) ? 32150613Sbostic strdup(p) : NULL; 32250613Sbostic pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 32350613Sbostic strdup(p) : NULL; 32450613Sbostic pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 32550613Sbostic strdup(p) : NULL; 32650613Sbostic } 32750613Sbostic 32850596Sbostic #if __STDC__ 32950596Sbostic #include <stdarg.h> 33050596Sbostic #else 33150596Sbostic #include <varargs.h> 33250596Sbostic #endif 33350596Sbostic 33450596Sbostic void 33550596Sbostic #if __STDC__ 33650596Sbostic err(const char *fmt, ...) 33750596Sbostic #else 33850596Sbostic err(fmt, va_alist) 33950596Sbostic char *fmt; 34050596Sbostic va_dcl 34150596Sbostic #endif 34250596Sbostic { 34350596Sbostic va_list ap; 34450596Sbostic #if __STDC__ 34550596Sbostic va_start(ap, fmt); 34650596Sbostic #else 34750596Sbostic va_start(ap); 34850596Sbostic #endif 34950596Sbostic (void)fprintf(stderr, "finger: "); 35050596Sbostic (void)vfprintf(stderr, fmt, ap); 35150596Sbostic va_end(ap); 35250596Sbostic (void)fprintf(stderr, "\n"); 35350596Sbostic exit(1); 35450596Sbostic /* NOTREACHED */ 35550596Sbostic } 356