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*50596Sbostic static char sccsid[] = "@(#)util.c 5.15 (Berkeley) 07/27/91"; 1337660Sbostic #endif /* not lint */ 1437660Sbostic 1537660Sbostic #include <sys/param.h> 1637660Sbostic #include <sys/stat.h> 17*50596Sbostic #include <fcntl.h> 18*50596Sbostic #include <pwd.h> 19*50596Sbostic #include <utmp.h> 20*50596Sbostic #include <errno.h> 21*50596Sbostic #include <unistd.h> 2237660Sbostic #include <stdio.h> 2337660Sbostic #include <ctype.h> 24*50596Sbostic #include <stdlib.h> 2542053Sbostic #include <string.h> 2643857Sbostic #include <paths.h> 2737660Sbostic #include "finger.h" 2837660Sbostic 29*50596Sbostic static void find_idle_and_ttywrite __P((WHERE *)); 30*50596Sbostic static int hash __P((char *)); 31*50596Sbostic static void userinfo __P((PERSON *, struct passwd *)); 32*50596Sbostic static WHERE *walloc __P((PERSON *)); 33*50596Sbostic 34*50596Sbostic static void 3537664Sedward find_idle_and_ttywrite(w) 3637664Sedward register WHERE *w; 3737660Sbostic { 3837660Sbostic extern time_t now; 3937660Sbostic struct stat sb; 4037660Sbostic 41*50596Sbostic (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 4237660Sbostic if (stat(tbuf, &sb) < 0) { 4337660Sbostic (void)fprintf(stderr, 4437660Sbostic "finger: %s: %s\n", tbuf, strerror(errno)); 4545972Sbostic return; 4637660Sbostic } 4737664Sedward w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 4837660Sbostic 4937660Sbostic #define TALKABLE 0220 /* tty is writable if 220 mode */ 5037664Sedward w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 5137660Sbostic } 5237660Sbostic 53*50596Sbostic static void 5437660Sbostic userinfo(pn, pw) 5537660Sbostic register PERSON *pn; 5637660Sbostic register struct passwd *pw; 5737660Sbostic { 5837660Sbostic register char *p, *t; 5941568Smarc char *bp, name[1024]; 6037660Sbostic 6137660Sbostic pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 6237660Sbostic 6337660Sbostic pn->uid = pw->pw_uid; 6437660Sbostic pn->name = strdup(pw->pw_name); 6537660Sbostic pn->dir = strdup(pw->pw_dir); 6637660Sbostic pn->shell = strdup(pw->pw_shell); 6737660Sbostic 6837660Sbostic /* why do we skip asterisks!?!? */ 6941553Smarc (void)strcpy(bp = tbuf, pw->pw_gecos); 7041553Smarc if (*bp == '*') 7141553Smarc ++bp; 7237660Sbostic 7337660Sbostic /* ampersands get replaced by the login name */ 7441553Smarc if (!(p = strsep(&bp, ","))) 7537660Sbostic return; 7637660Sbostic for (t = name; *t = *p; ++p) 7737660Sbostic if (*t == '&') { 7837660Sbostic (void)strcpy(t, pw->pw_name); 7937660Sbostic if (islower(*t)) 8037660Sbostic *t = toupper(*t); 8137660Sbostic while (*++t); 8237660Sbostic } 8337660Sbostic else 8437660Sbostic ++t; 8537660Sbostic pn->realname = strdup(name); 8641553Smarc pn->office = ((p = strsep(&bp, ",")) && *p) ? 8738600Sbostic strdup(p) : NULL; 8841553Smarc pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 8938600Sbostic strdup(p) : NULL; 9041553Smarc pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 9138600Sbostic strdup(p) : NULL; 9237660Sbostic } 9337660Sbostic 9437660Sbostic match(pw, user) 9537660Sbostic struct passwd *pw; 9637660Sbostic char *user; 9737660Sbostic { 9837660Sbostic register char *p, *t; 9941568Smarc char name[1024]; 10037660Sbostic 10137660Sbostic /* why do we skip asterisks!?!? */ 10237660Sbostic (void)strcpy(p = tbuf, pw->pw_gecos); 10337660Sbostic if (*p == '*') 10437660Sbostic ++p; 10537660Sbostic 10637660Sbostic /* ampersands get replaced by the login name */ 10737660Sbostic if (!(p = strtok(p, ","))) 10837660Sbostic return(0); 10937660Sbostic for (t = name; *t = *p; ++p) 11037660Sbostic if (*t == '&') { 11137660Sbostic (void)strcpy(t, pw->pw_name); 11237660Sbostic while (*++t); 11337660Sbostic } 11437660Sbostic else 11537660Sbostic ++t; 11637660Sbostic for (t = name; p = strtok(t, "\t "); t = (char *)NULL) 11737660Sbostic if (!strcasecmp(p, user)) 11837660Sbostic return(1); 11937660Sbostic return(0); 12037660Sbostic } 12137660Sbostic 122*50596Sbostic void 12337664Sedward enter_lastlog(pn) 12437660Sbostic register PERSON *pn; 12537660Sbostic { 12637664Sedward register WHERE *w; 12737683Sedward static int opened, fd; 12837660Sbostic struct lastlog ll; 12937664Sedward char doit = 0; 13037660Sbostic 13137665Sbostic /* some systems may not maintain lastlog, don't report errors. */ 13237665Sbostic if (!opened) { 13337664Sedward fd = open(_PATH_LASTLOG, O_RDONLY, 0); 13437665Sbostic opened = 1; 13537660Sbostic } 13637665Sbostic if (fd == -1 || 137*50596Sbostic lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 13837665Sbostic (long)pn->uid * sizeof(ll) || 13937665Sbostic read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 14037665Sbostic /* as if never logged in */ 14137665Sbostic ll.ll_line[0] = ll.ll_host[0] = NULL; 14237665Sbostic ll.ll_time = 0; 14337665Sbostic } 14437664Sedward if ((w = pn->whead) == NULL) 14537664Sedward doit = 1; 14637683Sedward else if (ll.ll_time != 0) { 14737664Sedward /* if last login is earlier than some current login */ 14837664Sedward for (; !doit && w != NULL; w = w->next) 14937664Sedward if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 15037664Sedward doit = 1; 15137664Sedward /* 15237664Sedward * and if it's not any of the current logins 15337664Sedward * can't use time comparison because there may be a small 15437664Sedward * discrepency since login calls time() twice 15537664Sedward */ 15637664Sedward for (w = pn->whead; doit && w != NULL; w = w->next) 15737664Sedward if (w->info == LOGGEDIN && 15837664Sedward strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 15937664Sedward doit = 0; 16037660Sbostic } 16137664Sedward if (doit) { 16237664Sedward w = walloc(pn); 16337664Sedward w->info = LASTLOG; 16437664Sedward bcopy(ll.ll_line, w->tty, UT_LINESIZE); 16537664Sedward w->tty[UT_LINESIZE] = 0; 16637664Sedward bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 16737664Sedward w->host[UT_HOSTSIZE] = 0; 16837664Sedward w->loginat = ll.ll_time; 16937664Sedward } 17037660Sbostic } 17137660Sbostic 172*50596Sbostic void 17337664Sedward enter_where(ut, pn) 17437660Sbostic struct utmp *ut; 17537660Sbostic PERSON *pn; 17637660Sbostic { 177*50596Sbostic register WHERE *w; 17837664Sedward 179*50596Sbostic w = walloc(pn); 18037664Sedward w->info = LOGGEDIN; 18137664Sedward bcopy(ut->ut_line, w->tty, UT_LINESIZE); 18237664Sedward w->tty[UT_LINESIZE] = 0; 18337664Sedward bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 18437664Sedward w->host[UT_HOSTSIZE] = 0; 18537664Sedward w->loginat = (time_t)ut->ut_time; 18637664Sedward find_idle_and_ttywrite(w); 18737660Sbostic } 18837664Sedward 18937664Sedward PERSON * 19037664Sedward enter_person(pw) 19137664Sedward register struct passwd *pw; 19237664Sedward { 19337664Sedward register PERSON *pn, **pp; 19437664Sedward 19537664Sedward for (pp = htab + hash(pw->pw_name); 19637664Sedward *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0; 19737664Sedward pp = &(*pp)->hlink) 19837664Sedward ; 19937664Sedward if ((pn = *pp) == NULL) { 20037664Sedward pn = palloc(); 20137664Sedward entries++; 20237664Sedward if (phead == NULL) 20337664Sedward phead = ptail = pn; 20437664Sedward else { 20537664Sedward ptail->next = pn; 20637664Sedward ptail = pn; 20737664Sedward } 20837664Sedward pn->next = NULL; 20937664Sedward pn->hlink = NULL; 21037664Sedward *pp = pn; 21137664Sedward userinfo(pn, pw); 21237664Sedward pn->whead = NULL; 21337664Sedward } 21437664Sedward return(pn); 21537664Sedward } 21637664Sedward 21737664Sedward PERSON * 21837664Sedward find_person(name) 21937664Sedward char *name; 22037664Sedward { 22137664Sedward register PERSON *pn; 22237664Sedward 22337664Sedward /* name may be only UT_NAMESIZE long and not terminated */ 22437664Sedward for (pn = htab[hash(name)]; 22537664Sedward pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0; 22637664Sedward pn = pn->hlink) 22737664Sedward ; 22837664Sedward return(pn); 22937664Sedward } 23037664Sedward 231*50596Sbostic static 23237664Sedward hash(name) 23337664Sedward register char *name; 23437664Sedward { 23537664Sedward register int h, i; 23637664Sedward 23737664Sedward h = 0; 23837664Sedward /* name may be only UT_NAMESIZE long and not terminated */ 23937664Sedward for (i = UT_NAMESIZE; --i >= 0 && *name;) 24037664Sedward h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK; 24137664Sedward return(h); 24237664Sedward } 24337664Sedward 24437664Sedward PERSON * 24537664Sedward palloc() 24637664Sedward { 24737664Sedward PERSON *p; 24837664Sedward 249*50596Sbostic if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 250*50596Sbostic err("%s", strerror(errno)); 25137664Sedward return(p); 25237664Sedward } 25337664Sedward 254*50596Sbostic static WHERE * 25537664Sedward walloc(pn) 25637664Sedward register PERSON *pn; 25737664Sedward { 25837664Sedward register WHERE *w; 25937664Sedward 26037664Sedward if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) { 26137664Sedward (void)fprintf(stderr, "finger: out of space.\n"); 26237664Sedward exit(1); 26337664Sedward } 26437664Sedward if (pn->whead == NULL) 26537664Sedward pn->whead = pn->wtail = w; 26637664Sedward else { 26737664Sedward pn->wtail->next = w; 26837664Sedward pn->wtail = w; 26937664Sedward } 27037664Sedward w->next = NULL; 27137664Sedward return(w); 27237664Sedward } 27338052Sbostic 27438052Sbostic char * 27538052Sbostic prphone(num) 27638052Sbostic char *num; 27738052Sbostic { 27838052Sbostic register char *p; 27938052Sbostic int len; 28038052Sbostic static char pbuf[15]; 28138052Sbostic 28238052Sbostic /* don't touch anything if the user has their own formatting */ 28338052Sbostic for (p = num; *p; ++p) 28438052Sbostic if (!isdigit(*p)) 28538052Sbostic return(num); 28638052Sbostic len = p - num; 28738052Sbostic p = pbuf; 28838052Sbostic switch(len) { 28938052Sbostic case 11: /* +0-123-456-7890 */ 29038052Sbostic *p++ = '+'; 29138052Sbostic *p++ = *num++; 29238052Sbostic *p++ = '-'; 29338052Sbostic /* FALLTHROUGH */ 29438052Sbostic case 10: /* 012-345-6789 */ 29538052Sbostic *p++ = *num++; 29638052Sbostic *p++ = *num++; 29738052Sbostic *p++ = *num++; 29838052Sbostic *p++ = '-'; 29938052Sbostic /* FALLTHROUGH */ 30038052Sbostic case 7: /* 012-3456 */ 30138052Sbostic *p++ = *num++; 30238052Sbostic *p++ = *num++; 30338052Sbostic *p++ = *num++; 30438052Sbostic break; 30538052Sbostic case 5: /* x0-1234 */ 30638052Sbostic *p++ = 'x'; 30738052Sbostic *p++ = *num++; 30838052Sbostic break; 30938052Sbostic default: 31038052Sbostic return(num); 31138052Sbostic } 31238052Sbostic *p++ = '-'; 31338052Sbostic *p++ = *num++; 31438052Sbostic *p++ = *num++; 31538052Sbostic *p++ = *num++; 31638052Sbostic *p++ = *num++; 31738052Sbostic *p = '\0'; 31838052Sbostic return(pbuf); 31938052Sbostic } 320*50596Sbostic 321*50596Sbostic #if __STDC__ 322*50596Sbostic #include <stdarg.h> 323*50596Sbostic #else 324*50596Sbostic #include <varargs.h> 325*50596Sbostic #endif 326*50596Sbostic 327*50596Sbostic void 328*50596Sbostic #if __STDC__ 329*50596Sbostic err(const char *fmt, ...) 330*50596Sbostic #else 331*50596Sbostic err(fmt, va_alist) 332*50596Sbostic char *fmt; 333*50596Sbostic va_dcl 334*50596Sbostic #endif 335*50596Sbostic { 336*50596Sbostic va_list ap; 337*50596Sbostic #if __STDC__ 338*50596Sbostic va_start(ap, fmt); 339*50596Sbostic #else 340*50596Sbostic va_start(ap); 341*50596Sbostic #endif 342*50596Sbostic (void)fprintf(stderr, "finger: "); 343*50596Sbostic (void)vfprintf(stderr, fmt, ap); 344*50596Sbostic va_end(ap); 345*50596Sbostic (void)fprintf(stderr, "\n"); 346*50596Sbostic exit(1); 347*50596Sbostic /* NOTREACHED */ 348*50596Sbostic } 349