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*51423Sbostic static char sccsid[] = "@(#)util.c 5.18 (Berkeley) 10/27/91"; 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 34*51423Sbostic int 3537660Sbostic match(pw, user) 3637660Sbostic struct passwd *pw; 3737660Sbostic char *user; 3837660Sbostic { 3937660Sbostic register char *p, *t; 4041568Smarc char name[1024]; 4137660Sbostic 4237660Sbostic /* why do we skip asterisks!?!? */ 4337660Sbostic (void)strcpy(p = tbuf, pw->pw_gecos); 4437660Sbostic if (*p == '*') 4537660Sbostic ++p; 4637660Sbostic 4737660Sbostic /* ampersands get replaced by the login name */ 4837660Sbostic if (!(p = strtok(p, ","))) 4937660Sbostic return(0); 5037660Sbostic for (t = name; *t = *p; ++p) 5137660Sbostic if (*t == '&') { 5237660Sbostic (void)strcpy(t, pw->pw_name); 5337660Sbostic while (*++t); 5437660Sbostic } 5537660Sbostic else 5637660Sbostic ++t; 5737660Sbostic for (t = name; p = strtok(t, "\t "); t = (char *)NULL) 5837660Sbostic if (!strcasecmp(p, user)) 5937660Sbostic return(1); 6037660Sbostic return(0); 6137660Sbostic } 6237660Sbostic 6350596Sbostic void 6437664Sedward enter_lastlog(pn) 6537660Sbostic register PERSON *pn; 6637660Sbostic { 6737664Sedward register WHERE *w; 6837683Sedward static int opened, fd; 6937660Sbostic struct lastlog ll; 7037664Sedward char doit = 0; 7137660Sbostic 7237665Sbostic /* some systems may not maintain lastlog, don't report errors. */ 7337665Sbostic if (!opened) { 7437664Sedward fd = open(_PATH_LASTLOG, O_RDONLY, 0); 7537665Sbostic opened = 1; 7637660Sbostic } 7737665Sbostic if (fd == -1 || 7850596Sbostic lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 7937665Sbostic (long)pn->uid * sizeof(ll) || 8037665Sbostic read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 8137665Sbostic /* as if never logged in */ 8237665Sbostic ll.ll_line[0] = ll.ll_host[0] = NULL; 8337665Sbostic ll.ll_time = 0; 8437665Sbostic } 8537664Sedward if ((w = pn->whead) == NULL) 8637664Sedward doit = 1; 8737683Sedward else if (ll.ll_time != 0) { 8837664Sedward /* if last login is earlier than some current login */ 8937664Sedward for (; !doit && w != NULL; w = w->next) 9037664Sedward if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 9137664Sedward doit = 1; 9237664Sedward /* 9337664Sedward * and if it's not any of the current logins 9437664Sedward * can't use time comparison because there may be a small 9537664Sedward * discrepency since login calls time() twice 9637664Sedward */ 9737664Sedward for (w = pn->whead; doit && w != NULL; w = w->next) 9837664Sedward if (w->info == LOGGEDIN && 9937664Sedward strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 10037664Sedward doit = 0; 10137660Sbostic } 10237664Sedward if (doit) { 10337664Sedward w = walloc(pn); 10437664Sedward w->info = LASTLOG; 10537664Sedward bcopy(ll.ll_line, w->tty, UT_LINESIZE); 10637664Sedward w->tty[UT_LINESIZE] = 0; 10737664Sedward bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 10837664Sedward w->host[UT_HOSTSIZE] = 0; 10937664Sedward w->loginat = ll.ll_time; 11037664Sedward } 11137660Sbostic } 11237660Sbostic 11350596Sbostic void 11437664Sedward enter_where(ut, pn) 11537660Sbostic struct utmp *ut; 11637660Sbostic PERSON *pn; 11737660Sbostic { 11850596Sbostic register WHERE *w; 11937664Sedward 12050596Sbostic w = walloc(pn); 12137664Sedward w->info = LOGGEDIN; 12237664Sedward bcopy(ut->ut_line, w->tty, UT_LINESIZE); 12337664Sedward w->tty[UT_LINESIZE] = 0; 12437664Sedward bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 12537664Sedward w->host[UT_HOSTSIZE] = 0; 12637664Sedward w->loginat = (time_t)ut->ut_time; 12737664Sedward find_idle_and_ttywrite(w); 12837660Sbostic } 12937664Sedward 13037664Sedward PERSON * 13137664Sedward enter_person(pw) 13237664Sedward register struct passwd *pw; 13337664Sedward { 134*51423Sbostic DBT data, key; 13550613Sbostic PERSON *pn; 13637664Sedward 137*51423Sbostic if (db == NULL && 138*51423Sbostic (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 13950613Sbostic err("%s", strerror(errno)); 14050613Sbostic 14150613Sbostic key.data = pw->pw_name; 14250613Sbostic key.size = strlen(pw->pw_name); 14350613Sbostic 14450613Sbostic switch((*db->get)(db, &key, &data, 0)) { 14550613Sbostic case 0: 14650613Sbostic return(*(PERSON **)data.data); 14750613Sbostic default: 14850613Sbostic case -1: 14950613Sbostic err("db get: %s", strerror(errno)); 15050613Sbostic /* NOTREACHED */ 15150613Sbostic case 1: 15250613Sbostic ++entries; 15337664Sedward pn = palloc(); 15437664Sedward userinfo(pn, pw); 15537664Sedward pn->whead = NULL; 15650613Sbostic 15750613Sbostic data.size = sizeof(PERSON *); 15850613Sbostic data.data = &pn; 15951178Sbostic if ((*db->put)(db, &key, &data, 0)) 16050613Sbostic err("%s", strerror(errno)); 16150613Sbostic return(pn); 16237664Sedward } 16337664Sedward } 16437664Sedward 16537664Sedward PERSON * 16637664Sedward find_person(name) 16737664Sedward char *name; 16837664Sedward { 16950613Sbostic register int cnt; 17050613Sbostic DBT data, key; 17150613Sbostic char buf[UT_NAMESIZE + 1]; 17237664Sedward 17350613Sbostic if (!db) 17450613Sbostic return(NULL); 17537664Sedward 17650613Sbostic /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 17750613Sbostic for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 17850613Sbostic buf[cnt] = *name; 17950613Sbostic buf[cnt] = '\0'; 18050613Sbostic key.data = buf; 18150613Sbostic key.size = cnt; 18237664Sedward 18350613Sbostic return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 18437664Sedward } 18537664Sedward 18637664Sedward PERSON * 18737664Sedward palloc() 18837664Sedward { 18937664Sedward PERSON *p; 19037664Sedward 19150596Sbostic if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 19250596Sbostic err("%s", strerror(errno)); 19337664Sedward return(p); 19437664Sedward } 19537664Sedward 19650596Sbostic static WHERE * 19737664Sedward walloc(pn) 19837664Sedward register PERSON *pn; 19937664Sedward { 20037664Sedward register WHERE *w; 20137664Sedward 20250613Sbostic if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 20350613Sbostic err("%s", strerror(errno)); 20437664Sedward if (pn->whead == NULL) 20537664Sedward pn->whead = pn->wtail = w; 20637664Sedward else { 20737664Sedward pn->wtail->next = w; 20837664Sedward pn->wtail = w; 20937664Sedward } 21037664Sedward w->next = NULL; 21137664Sedward return(w); 21237664Sedward } 21338052Sbostic 21438052Sbostic char * 21538052Sbostic prphone(num) 21638052Sbostic char *num; 21738052Sbostic { 21838052Sbostic register char *p; 21938052Sbostic int len; 22038052Sbostic static char pbuf[15]; 22138052Sbostic 22238052Sbostic /* don't touch anything if the user has their own formatting */ 22338052Sbostic for (p = num; *p; ++p) 22438052Sbostic if (!isdigit(*p)) 22538052Sbostic return(num); 22638052Sbostic len = p - num; 22738052Sbostic p = pbuf; 22838052Sbostic switch(len) { 22938052Sbostic case 11: /* +0-123-456-7890 */ 23038052Sbostic *p++ = '+'; 23138052Sbostic *p++ = *num++; 23238052Sbostic *p++ = '-'; 23338052Sbostic /* FALLTHROUGH */ 23438052Sbostic case 10: /* 012-345-6789 */ 23538052Sbostic *p++ = *num++; 23638052Sbostic *p++ = *num++; 23738052Sbostic *p++ = *num++; 23838052Sbostic *p++ = '-'; 23938052Sbostic /* FALLTHROUGH */ 24038052Sbostic case 7: /* 012-3456 */ 24138052Sbostic *p++ = *num++; 24238052Sbostic *p++ = *num++; 24338052Sbostic *p++ = *num++; 24438052Sbostic break; 24538052Sbostic case 5: /* x0-1234 */ 24638052Sbostic *p++ = 'x'; 24738052Sbostic *p++ = *num++; 24838052Sbostic break; 24938052Sbostic default: 25038052Sbostic return(num); 25138052Sbostic } 25238052Sbostic *p++ = '-'; 25338052Sbostic *p++ = *num++; 25438052Sbostic *p++ = *num++; 25538052Sbostic *p++ = *num++; 25638052Sbostic *p++ = *num++; 25738052Sbostic *p = '\0'; 25838052Sbostic return(pbuf); 25938052Sbostic } 26050596Sbostic 26150613Sbostic static void 26250613Sbostic find_idle_and_ttywrite(w) 26350613Sbostic register WHERE *w; 26450613Sbostic { 26550613Sbostic extern time_t now; 26650613Sbostic struct stat sb; 26750613Sbostic 26850613Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 26950613Sbostic if (stat(tbuf, &sb) < 0) { 27050613Sbostic (void)fprintf(stderr, 27150613Sbostic "finger: %s: %s\n", tbuf, strerror(errno)); 27250613Sbostic return; 27350613Sbostic } 27450613Sbostic w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 27550613Sbostic 27650613Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */ 27750613Sbostic w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 27850613Sbostic } 27950613Sbostic 28050613Sbostic static void 28150613Sbostic userinfo(pn, pw) 28250613Sbostic register PERSON *pn; 28350613Sbostic register struct passwd *pw; 28450613Sbostic { 28550613Sbostic register char *p, *t; 28650613Sbostic char *bp, name[1024]; 28750613Sbostic 28850613Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 28950613Sbostic 29050613Sbostic pn->uid = pw->pw_uid; 29150613Sbostic pn->name = strdup(pw->pw_name); 29250613Sbostic pn->dir = strdup(pw->pw_dir); 29350613Sbostic pn->shell = strdup(pw->pw_shell); 29450613Sbostic 29550613Sbostic /* why do we skip asterisks!?!? */ 29650613Sbostic (void)strcpy(bp = tbuf, pw->pw_gecos); 29750613Sbostic if (*bp == '*') 29850613Sbostic ++bp; 29950613Sbostic 30050613Sbostic /* ampersands get replaced by the login name */ 30150613Sbostic if (!(p = strsep(&bp, ","))) 30250613Sbostic return; 30350613Sbostic for (t = name; *t = *p; ++p) 30450613Sbostic if (*t == '&') { 30550613Sbostic (void)strcpy(t, pw->pw_name); 30650613Sbostic if (islower(*t)) 30750613Sbostic *t = toupper(*t); 30850613Sbostic while (*++t); 30950613Sbostic } 31050613Sbostic else 31150613Sbostic ++t; 31250613Sbostic pn->realname = strdup(name); 31350613Sbostic pn->office = ((p = strsep(&bp, ",")) && *p) ? 31450613Sbostic strdup(p) : NULL; 31550613Sbostic pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 31650613Sbostic strdup(p) : NULL; 31750613Sbostic pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 31850613Sbostic strdup(p) : NULL; 31950613Sbostic } 32050613Sbostic 32150596Sbostic #if __STDC__ 32250596Sbostic #include <stdarg.h> 32350596Sbostic #else 32450596Sbostic #include <varargs.h> 32550596Sbostic #endif 32650596Sbostic 32750596Sbostic void 32850596Sbostic #if __STDC__ 32950596Sbostic err(const char *fmt, ...) 33050596Sbostic #else 33150596Sbostic err(fmt, va_alist) 33250596Sbostic char *fmt; 33350596Sbostic va_dcl 33450596Sbostic #endif 33550596Sbostic { 33650596Sbostic va_list ap; 33750596Sbostic #if __STDC__ 33850596Sbostic va_start(ap, fmt); 33950596Sbostic #else 34050596Sbostic va_start(ap); 34150596Sbostic #endif 34250596Sbostic (void)fprintf(stderr, "finger: "); 34350596Sbostic (void)vfprintf(stderr, fmt, ap); 34450596Sbostic va_end(ap); 34550596Sbostic (void)fprintf(stderr, "\n"); 34650596Sbostic exit(1); 34750596Sbostic /* NOTREACHED */ 34850596Sbostic } 349