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*50613Sbostic static char sccsid[] = "@(#)util.c 5.16 (Berkeley) 07/27/91"; 1337660Sbostic #endif /* not lint */ 1437660Sbostic 1537660Sbostic #include <sys/param.h> 1637660Sbostic #include <sys/stat.h> 1750596Sbostic #include <fcntl.h> 18*50613Sbostic #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 { 133*50613Sbostic PERSON *pn; 134*50613Sbostic DBT data, key; 13537664Sedward 136*50613Sbostic if (db == NULL && (db = hash_open(NULL, O_RDWR, 0, NULL)) == NULL) 137*50613Sbostic err("%s", strerror(errno)); 138*50613Sbostic 139*50613Sbostic key.data = pw->pw_name; 140*50613Sbostic key.size = strlen(pw->pw_name); 141*50613Sbostic 142*50613Sbostic switch((*db->get)(db, &key, &data, 0)) { 143*50613Sbostic case 0: 144*50613Sbostic return(*(PERSON **)data.data); 145*50613Sbostic default: 146*50613Sbostic case -1: 147*50613Sbostic err("db get: %s", strerror(errno)); 148*50613Sbostic /* NOTREACHED */ 149*50613Sbostic case 1: 150*50613Sbostic ++entries; 15137664Sedward pn = palloc(); 15237664Sedward userinfo(pn, pw); 15337664Sedward pn->whead = NULL; 154*50613Sbostic 155*50613Sbostic data.size = sizeof(PERSON *); 156*50613Sbostic data.data = &pn; 157*50613Sbostic if ((*db->put)(db, &key, &data, R_PUT)) 158*50613Sbostic err("%s", strerror(errno)); 159*50613Sbostic return(pn); 16037664Sedward } 16137664Sedward } 16237664Sedward 16337664Sedward PERSON * 16437664Sedward find_person(name) 16537664Sedward char *name; 16637664Sedward { 167*50613Sbostic register int cnt; 168*50613Sbostic DBT data, key; 169*50613Sbostic char buf[UT_NAMESIZE + 1]; 17037664Sedward 171*50613Sbostic if (!db) 172*50613Sbostic return(NULL); 17337664Sedward 174*50613Sbostic /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 175*50613Sbostic for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 176*50613Sbostic buf[cnt] = *name; 177*50613Sbostic buf[cnt] = '\0'; 178*50613Sbostic key.data = buf; 179*50613Sbostic key.size = cnt; 18037664Sedward 181*50613Sbostic 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 200*50613Sbostic if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 201*50613Sbostic 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 259*50613Sbostic static void 260*50613Sbostic find_idle_and_ttywrite(w) 261*50613Sbostic register WHERE *w; 262*50613Sbostic { 263*50613Sbostic extern time_t now; 264*50613Sbostic struct stat sb; 265*50613Sbostic 266*50613Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 267*50613Sbostic if (stat(tbuf, &sb) < 0) { 268*50613Sbostic (void)fprintf(stderr, 269*50613Sbostic "finger: %s: %s\n", tbuf, strerror(errno)); 270*50613Sbostic return; 271*50613Sbostic } 272*50613Sbostic w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 273*50613Sbostic 274*50613Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */ 275*50613Sbostic w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 276*50613Sbostic } 277*50613Sbostic 278*50613Sbostic static void 279*50613Sbostic userinfo(pn, pw) 280*50613Sbostic register PERSON *pn; 281*50613Sbostic register struct passwd *pw; 282*50613Sbostic { 283*50613Sbostic register char *p, *t; 284*50613Sbostic char *bp, name[1024]; 285*50613Sbostic 286*50613Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 287*50613Sbostic 288*50613Sbostic pn->uid = pw->pw_uid; 289*50613Sbostic pn->name = strdup(pw->pw_name); 290*50613Sbostic pn->dir = strdup(pw->pw_dir); 291*50613Sbostic pn->shell = strdup(pw->pw_shell); 292*50613Sbostic 293*50613Sbostic /* why do we skip asterisks!?!? */ 294*50613Sbostic (void)strcpy(bp = tbuf, pw->pw_gecos); 295*50613Sbostic if (*bp == '*') 296*50613Sbostic ++bp; 297*50613Sbostic 298*50613Sbostic /* ampersands get replaced by the login name */ 299*50613Sbostic if (!(p = strsep(&bp, ","))) 300*50613Sbostic return; 301*50613Sbostic for (t = name; *t = *p; ++p) 302*50613Sbostic if (*t == '&') { 303*50613Sbostic (void)strcpy(t, pw->pw_name); 304*50613Sbostic if (islower(*t)) 305*50613Sbostic *t = toupper(*t); 306*50613Sbostic while (*++t); 307*50613Sbostic } 308*50613Sbostic else 309*50613Sbostic ++t; 310*50613Sbostic pn->realname = strdup(name); 311*50613Sbostic pn->office = ((p = strsep(&bp, ",")) && *p) ? 312*50613Sbostic strdup(p) : NULL; 313*50613Sbostic pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 314*50613Sbostic strdup(p) : NULL; 315*50613Sbostic pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 316*50613Sbostic strdup(p) : NULL; 317*50613Sbostic } 318*50613Sbostic 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