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*51178Sbostic static char sccsid[] = "@(#)util.c 5.17 (Berkeley) 09/23/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 3437660Sbostic match(pw, user) 3537660Sbostic struct passwd *pw; 3637660Sbostic char *user; 3737660Sbostic { 3837660Sbostic register char *p, *t; 3941568Smarc char name[1024]; 4037660Sbostic 4137660Sbostic /* why do we skip asterisks!?!? */ 4237660Sbostic (void)strcpy(p = tbuf, pw->pw_gecos); 4337660Sbostic if (*p == '*') 4437660Sbostic ++p; 4537660Sbostic 4637660Sbostic /* ampersands get replaced by the login name */ 4737660Sbostic if (!(p = strtok(p, ","))) 4837660Sbostic return(0); 4937660Sbostic for (t = name; *t = *p; ++p) 5037660Sbostic if (*t == '&') { 5137660Sbostic (void)strcpy(t, pw->pw_name); 5237660Sbostic while (*++t); 5337660Sbostic } 5437660Sbostic else 5537660Sbostic ++t; 5637660Sbostic for (t = name; p = strtok(t, "\t "); t = (char *)NULL) 5737660Sbostic if (!strcasecmp(p, user)) 5837660Sbostic return(1); 5937660Sbostic return(0); 6037660Sbostic } 6137660Sbostic 6250596Sbostic void 6337664Sedward enter_lastlog(pn) 6437660Sbostic register PERSON *pn; 6537660Sbostic { 6637664Sedward register WHERE *w; 6737683Sedward static int opened, fd; 6837660Sbostic struct lastlog ll; 6937664Sedward char doit = 0; 7037660Sbostic 7137665Sbostic /* some systems may not maintain lastlog, don't report errors. */ 7237665Sbostic if (!opened) { 7337664Sedward fd = open(_PATH_LASTLOG, O_RDONLY, 0); 7437665Sbostic opened = 1; 7537660Sbostic } 7637665Sbostic if (fd == -1 || 7750596Sbostic lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 7837665Sbostic (long)pn->uid * sizeof(ll) || 7937665Sbostic read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 8037665Sbostic /* as if never logged in */ 8137665Sbostic ll.ll_line[0] = ll.ll_host[0] = NULL; 8237665Sbostic ll.ll_time = 0; 8337665Sbostic } 8437664Sedward if ((w = pn->whead) == NULL) 8537664Sedward doit = 1; 8637683Sedward else if (ll.ll_time != 0) { 8737664Sedward /* if last login is earlier than some current login */ 8837664Sedward for (; !doit && w != NULL; w = w->next) 8937664Sedward if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 9037664Sedward doit = 1; 9137664Sedward /* 9237664Sedward * and if it's not any of the current logins 9337664Sedward * can't use time comparison because there may be a small 9437664Sedward * discrepency since login calls time() twice 9537664Sedward */ 9637664Sedward for (w = pn->whead; doit && w != NULL; w = w->next) 9737664Sedward if (w->info == LOGGEDIN && 9837664Sedward strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 9937664Sedward doit = 0; 10037660Sbostic } 10137664Sedward if (doit) { 10237664Sedward w = walloc(pn); 10337664Sedward w->info = LASTLOG; 10437664Sedward bcopy(ll.ll_line, w->tty, UT_LINESIZE); 10537664Sedward w->tty[UT_LINESIZE] = 0; 10637664Sedward bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 10737664Sedward w->host[UT_HOSTSIZE] = 0; 10837664Sedward w->loginat = ll.ll_time; 10937664Sedward } 11037660Sbostic } 11137660Sbostic 11250596Sbostic void 11337664Sedward enter_where(ut, pn) 11437660Sbostic struct utmp *ut; 11537660Sbostic PERSON *pn; 11637660Sbostic { 11750596Sbostic register WHERE *w; 11837664Sedward 11950596Sbostic w = walloc(pn); 12037664Sedward w->info = LOGGEDIN; 12137664Sedward bcopy(ut->ut_line, w->tty, UT_LINESIZE); 12237664Sedward w->tty[UT_LINESIZE] = 0; 12337664Sedward bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 12437664Sedward w->host[UT_HOSTSIZE] = 0; 12537664Sedward w->loginat = (time_t)ut->ut_time; 12637664Sedward find_idle_and_ttywrite(w); 12737660Sbostic } 12837664Sedward 12937664Sedward PERSON * 13037664Sedward enter_person(pw) 13137664Sedward register struct passwd *pw; 13237664Sedward { 13350613Sbostic PERSON *pn; 13450613Sbostic DBT data, key; 13537664Sedward 136*51178Sbostic if (db == NULL && (db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL) 13750613Sbostic err("%s", strerror(errno)); 13850613Sbostic 13950613Sbostic key.data = pw->pw_name; 14050613Sbostic key.size = strlen(pw->pw_name); 14150613Sbostic 14250613Sbostic switch((*db->get)(db, &key, &data, 0)) { 14350613Sbostic case 0: 14450613Sbostic return(*(PERSON **)data.data); 14550613Sbostic default: 14650613Sbostic case -1: 14750613Sbostic err("db get: %s", strerror(errno)); 14850613Sbostic /* NOTREACHED */ 14950613Sbostic case 1: 15050613Sbostic ++entries; 15137664Sedward pn = palloc(); 15237664Sedward userinfo(pn, pw); 15337664Sedward pn->whead = NULL; 15450613Sbostic 15550613Sbostic data.size = sizeof(PERSON *); 15650613Sbostic data.data = &pn; 157*51178Sbostic if ((*db->put)(db, &key, &data, 0)) 15850613Sbostic err("%s", strerror(errno)); 15950613Sbostic return(pn); 16037664Sedward } 16137664Sedward } 16237664Sedward 16337664Sedward PERSON * 16437664Sedward find_person(name) 16537664Sedward char *name; 16637664Sedward { 16750613Sbostic register int cnt; 16850613Sbostic DBT data, key; 16950613Sbostic char buf[UT_NAMESIZE + 1]; 17037664Sedward 17150613Sbostic if (!db) 17250613Sbostic return(NULL); 17337664Sedward 17450613Sbostic /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 17550613Sbostic for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 17650613Sbostic buf[cnt] = *name; 17750613Sbostic buf[cnt] = '\0'; 17850613Sbostic key.data = buf; 17950613Sbostic key.size = cnt; 18037664Sedward 18150613Sbostic return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 18237664Sedward } 18337664Sedward 18437664Sedward PERSON * 18537664Sedward palloc() 18637664Sedward { 18737664Sedward PERSON *p; 18837664Sedward 18950596Sbostic if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 19050596Sbostic err("%s", strerror(errno)); 19137664Sedward return(p); 19237664Sedward } 19337664Sedward 19450596Sbostic static WHERE * 19537664Sedward walloc(pn) 19637664Sedward register PERSON *pn; 19737664Sedward { 19837664Sedward register WHERE *w; 19937664Sedward 20050613Sbostic if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 20150613Sbostic err("%s", strerror(errno)); 20237664Sedward if (pn->whead == NULL) 20337664Sedward pn->whead = pn->wtail = w; 20437664Sedward else { 20537664Sedward pn->wtail->next = w; 20637664Sedward pn->wtail = w; 20737664Sedward } 20837664Sedward w->next = NULL; 20937664Sedward return(w); 21037664Sedward } 21138052Sbostic 21238052Sbostic char * 21338052Sbostic prphone(num) 21438052Sbostic char *num; 21538052Sbostic { 21638052Sbostic register char *p; 21738052Sbostic int len; 21838052Sbostic static char pbuf[15]; 21938052Sbostic 22038052Sbostic /* don't touch anything if the user has their own formatting */ 22138052Sbostic for (p = num; *p; ++p) 22238052Sbostic if (!isdigit(*p)) 22338052Sbostic return(num); 22438052Sbostic len = p - num; 22538052Sbostic p = pbuf; 22638052Sbostic switch(len) { 22738052Sbostic case 11: /* +0-123-456-7890 */ 22838052Sbostic *p++ = '+'; 22938052Sbostic *p++ = *num++; 23038052Sbostic *p++ = '-'; 23138052Sbostic /* FALLTHROUGH */ 23238052Sbostic case 10: /* 012-345-6789 */ 23338052Sbostic *p++ = *num++; 23438052Sbostic *p++ = *num++; 23538052Sbostic *p++ = *num++; 23638052Sbostic *p++ = '-'; 23738052Sbostic /* FALLTHROUGH */ 23838052Sbostic case 7: /* 012-3456 */ 23938052Sbostic *p++ = *num++; 24038052Sbostic *p++ = *num++; 24138052Sbostic *p++ = *num++; 24238052Sbostic break; 24338052Sbostic case 5: /* x0-1234 */ 24438052Sbostic *p++ = 'x'; 24538052Sbostic *p++ = *num++; 24638052Sbostic break; 24738052Sbostic default: 24838052Sbostic return(num); 24938052Sbostic } 25038052Sbostic *p++ = '-'; 25138052Sbostic *p++ = *num++; 25238052Sbostic *p++ = *num++; 25338052Sbostic *p++ = *num++; 25438052Sbostic *p++ = *num++; 25538052Sbostic *p = '\0'; 25638052Sbostic return(pbuf); 25738052Sbostic } 25850596Sbostic 25950613Sbostic static void 26050613Sbostic find_idle_and_ttywrite(w) 26150613Sbostic register WHERE *w; 26250613Sbostic { 26350613Sbostic extern time_t now; 26450613Sbostic struct stat sb; 26550613Sbostic 26650613Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 26750613Sbostic if (stat(tbuf, &sb) < 0) { 26850613Sbostic (void)fprintf(stderr, 26950613Sbostic "finger: %s: %s\n", tbuf, strerror(errno)); 27050613Sbostic return; 27150613Sbostic } 27250613Sbostic w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 27350613Sbostic 27450613Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */ 27550613Sbostic w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 27650613Sbostic } 27750613Sbostic 27850613Sbostic static void 27950613Sbostic userinfo(pn, pw) 28050613Sbostic register PERSON *pn; 28150613Sbostic register struct passwd *pw; 28250613Sbostic { 28350613Sbostic register char *p, *t; 28450613Sbostic char *bp, name[1024]; 28550613Sbostic 28650613Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 28750613Sbostic 28850613Sbostic pn->uid = pw->pw_uid; 28950613Sbostic pn->name = strdup(pw->pw_name); 29050613Sbostic pn->dir = strdup(pw->pw_dir); 29150613Sbostic pn->shell = strdup(pw->pw_shell); 29250613Sbostic 29350613Sbostic /* why do we skip asterisks!?!? */ 29450613Sbostic (void)strcpy(bp = tbuf, pw->pw_gecos); 29550613Sbostic if (*bp == '*') 29650613Sbostic ++bp; 29750613Sbostic 29850613Sbostic /* ampersands get replaced by the login name */ 29950613Sbostic if (!(p = strsep(&bp, ","))) 30050613Sbostic return; 30150613Sbostic for (t = name; *t = *p; ++p) 30250613Sbostic if (*t == '&') { 30350613Sbostic (void)strcpy(t, pw->pw_name); 30450613Sbostic if (islower(*t)) 30550613Sbostic *t = toupper(*t); 30650613Sbostic while (*++t); 30750613Sbostic } 30850613Sbostic else 30950613Sbostic ++t; 31050613Sbostic pn->realname = strdup(name); 31150613Sbostic pn->office = ((p = strsep(&bp, ",")) && *p) ? 31250613Sbostic strdup(p) : NULL; 31350613Sbostic pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 31450613Sbostic strdup(p) : NULL; 31550613Sbostic pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 31650613Sbostic strdup(p) : NULL; 31750613Sbostic } 31850613Sbostic 31950596Sbostic #if __STDC__ 32050596Sbostic #include <stdarg.h> 32150596Sbostic #else 32250596Sbostic #include <varargs.h> 32350596Sbostic #endif 32450596Sbostic 32550596Sbostic void 32650596Sbostic #if __STDC__ 32750596Sbostic err(const char *fmt, ...) 32850596Sbostic #else 32950596Sbostic err(fmt, va_alist) 33050596Sbostic char *fmt; 33150596Sbostic va_dcl 33250596Sbostic #endif 33350596Sbostic { 33450596Sbostic va_list ap; 33550596Sbostic #if __STDC__ 33650596Sbostic va_start(ap, fmt); 33750596Sbostic #else 33850596Sbostic va_start(ap); 33950596Sbostic #endif 34050596Sbostic (void)fprintf(stderr, "finger: "); 34150596Sbostic (void)vfprintf(stderr, fmt, ap); 34250596Sbostic va_end(ap); 34350596Sbostic (void)fprintf(stderr, "\n"); 34450596Sbostic exit(1); 34550596Sbostic /* NOTREACHED */ 34650596Sbostic } 347