1: /* 2: * Copyright (c) 1989 The Regents of the University of California. 3: * All rights reserved. 4: * 5: * This code is derived from software contributed to Berkeley by 6: * Tony Nardo. 7: * 8: * Redistribution and use in source and binary forms are permitted 9: * provided that the above copyright notice and this paragraph are 10: * duplicated in all such forms and that any documentation, 11: * advertising materials, and other materials related to such 12: * distribution and use acknowledge that the software was developed 13: * by the University of California, Berkeley. The name of the 14: * University may not be used to endorse or promote products derived 15: * from this software without specific prior written permission. 16: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19: */ 20: 21: #if !defined(lint) && defined(DOSCCS) 22: static char sccsid[] = "@(#)util.c 5.8.1 (2.11BSD) 1996/1/12"; 23: #endif /* not lint */ 24: 25: #include <sys/param.h> 26: #include <sys/stat.h> 27: #include <sys/file.h> 28: #include <stdio.h> 29: #include <ctype.h> 30: #include <strings.h> 31: #include <lastlog.h> 32: #include "finger.h" 33: #include "pathnames.h" 34: 35: find_idle_and_ttywrite(w) 36: register WHERE *w; 37: { 38: extern time_t now; 39: extern int errno; 40: struct stat sb; 41: 42: (void)sprintf(tbuf, "%s/%s", _PATH_DEV, w->tty); 43: if (stat(tbuf, &sb) < 0) { 44: (void)fprintf(stderr, 45: "finger: %s: %s\n", tbuf, strerror(errno)); 46: exit(1); 47: } 48: w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 49: 50: #define TALKABLE 0220 /* tty is writable if 220 mode */ 51: w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 52: } 53: 54: userinfo(pn, pw) 55: register PERSON *pn; 56: register struct passwd *pw; 57: { 58: register char *p, *t; 59: char *bp; 60: char name[256]; 61: 62: pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 63: 64: pn->uid = pw->pw_uid; 65: pn->name = strdup(pw->pw_name); 66: pn->dir = strdup(pw->pw_dir); 67: pn->shell = strdup(pw->pw_shell); 68: 69: /* why do we skip asterisks!?!? */ 70: (void)strcpy(bp = tbuf, pw->pw_gecos); 71: if (*bp == '*') 72: ++bp; 73: 74: /* ampersands get replaced by the login name */ 75: if (!(p = strsep(&bp, ","))) 76: return; 77: for (t = name; *t = *p; ++p) 78: if (*t == '&') { 79: (void)strcpy(t, pw->pw_name); 80: if (islower(*t)) 81: *t = toupper(*t); 82: while (*++t); 83: } 84: else 85: ++t; 86: pn->realname = strdup(name); 87: pn->office = ((p = strsep(&bp, ",")) && *p) ? 88: strdup(p) : NULL; 89: pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 90: strdup(p) : NULL; 91: pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 92: strdup(p) : NULL; 93: } 94: 95: match(pw, user) 96: struct passwd *pw; 97: char *user; 98: { 99: register char *p, *t; 100: char name[256]; 101: 102: /* why do we skip asterisks!?!? */ 103: (void)strcpy(p = tbuf, pw->pw_gecos); 104: if (*p == '*') 105: ++p; 106: 107: /* ampersands get replaced by the login name */ 108: if (!(p = strtok(p, ","))) 109: return(0); 110: for (t = name; *t = *p; ++p) 111: if (*t == '&') { 112: (void)strcpy(t, pw->pw_name); 113: while (*++t); 114: } 115: else 116: ++t; 117: for (t = name; p = strtok(t, "\t "); t = (char *)NULL) 118: if (!strcasecmp(p, user)) 119: return(1); 120: return(0); 121: } 122: 123: enter_lastlog(pn) 124: register PERSON *pn; 125: { 126: register WHERE *w; 127: static int opened, fd; 128: struct lastlog ll; 129: char doit = 0; 130: off_t lseek(); 131: 132: /* some systems may not maintain lastlog, don't report errors. */ 133: if (!opened) { 134: fd = open(_PATH_LASTLOG, O_RDONLY, 0); 135: opened = 1; 136: } 137: if (fd == -1 || 138: lseek(fd, (long)pn->uid * sizeof(ll), L_SET) != 139: (long)pn->uid * sizeof(ll) || 140: read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 141: /* as if never logged in */ 142: ll.ll_line[0] = ll.ll_host[0] = NULL; 143: ll.ll_time = 0; 144: } 145: if ((w = pn->whead) == NULL) 146: doit = 1; 147: else if (ll.ll_time != 0) { 148: /* if last login is earlier than some current login */ 149: for (; !doit && w != NULL; w = w->next) 150: if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 151: doit = 1; 152: /* 153: * and if it's not any of the current logins 154: * can't use time comparison because there may be a small 155: * discrepency since login calls time() twice 156: */ 157: for (w = pn->whead; doit && w != NULL; w = w->next) 158: if (w->info == LOGGEDIN && 159: strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 160: doit = 0; 161: } 162: if (doit) { 163: w = walloc(pn); 164: w->info = LASTLOG; 165: bcopy(ll.ll_line, w->tty, UT_LINESIZE); 166: w->tty[UT_LINESIZE] = 0; 167: bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 168: w->host[UT_HOSTSIZE] = 0; 169: w->loginat = ll.ll_time; 170: } 171: } 172: 173: enter_where(ut, pn) 174: struct utmp *ut; 175: PERSON *pn; 176: { 177: register WHERE *w = walloc(pn); 178: 179: w->info = LOGGEDIN; 180: bcopy(ut->ut_line, w->tty, UT_LINESIZE); 181: w->tty[UT_LINESIZE] = 0; 182: bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 183: w->host[UT_HOSTSIZE] = 0; 184: w->loginat = (time_t)ut->ut_time; 185: find_idle_and_ttywrite(w); 186: } 187: 188: PERSON * 189: enter_person(pw) 190: register struct passwd *pw; 191: { 192: register PERSON *pn, **pp; 193: 194: for (pp = htab + hash(pw->pw_name); 195: *pp != NULL && strcmp((*pp)->name, pw->pw_name) != 0; 196: pp = &(*pp)->hlink) 197: ; 198: if ((pn = *pp) == NULL) { 199: pn = palloc(); 200: entries++; 201: if (phead == NULL) 202: phead = ptail = pn; 203: else { 204: ptail->next = pn; 205: ptail = pn; 206: } 207: pn->next = NULL; 208: pn->hlink = NULL; 209: *pp = pn; 210: userinfo(pn, pw); 211: pn->whead = NULL; 212: } 213: return(pn); 214: } 215: 216: PERSON * 217: find_person(name) 218: char *name; 219: { 220: register PERSON *pn; 221: 222: /* name may be only UT_NAMESIZE long and not terminated */ 223: for (pn = htab[hash(name)]; 224: pn != NULL && strncmp(pn->name, name, UT_NAMESIZE) != 0; 225: pn = pn->hlink) 226: ; 227: return(pn); 228: } 229: 230: hash(name) 231: register char *name; 232: { 233: register int h, i; 234: 235: h = 0; 236: /* name may be only UT_NAMESIZE long and not terminated */ 237: for (i = UT_NAMESIZE; --i >= 0 && *name;) 238: h = ((h << 2 | h >> HBITS - 2) ^ *name++) & HMASK; 239: return(h); 240: } 241: 242: PERSON * 243: palloc() 244: { 245: PERSON *p; 246: 247: if ((p = (PERSON *)malloc((u_int) sizeof(PERSON))) == NULL) { 248: (void)fprintf(stderr, "finger: out of space.\n"); 249: exit(1); 250: } 251: return(p); 252: } 253: 254: WHERE * 255: walloc(pn) 256: register PERSON *pn; 257: { 258: register WHERE *w; 259: 260: if ((w = (WHERE *)malloc((u_int) sizeof(WHERE))) == NULL) { 261: (void)fprintf(stderr, "finger: out of space.\n"); 262: exit(1); 263: } 264: if (pn->whead == NULL) 265: pn->whead = pn->wtail = w; 266: else { 267: pn->wtail->next = w; 268: pn->wtail = w; 269: } 270: w->next = NULL; 271: return(w); 272: } 273: 274: char * 275: prphone(num) 276: char *num; 277: { 278: register char *p; 279: int len; 280: static char pbuf[15]; 281: 282: /* don't touch anything if the user has their own formatting */ 283: for (p = num; *p; ++p) 284: if (!isdigit(*p)) 285: return(num); 286: len = p - num; 287: p = pbuf; 288: switch(len) { 289: case 11: /* +0-123-456-7890 */ 290: *p++ = '+'; 291: *p++ = *num++; 292: *p++ = '-'; 293: /* FALLTHROUGH */ 294: case 10: /* 012-345-6789 */ 295: *p++ = *num++; 296: *p++ = *num++; 297: *p++ = *num++; 298: *p++ = '-'; 299: /* FALLTHROUGH */ 300: case 7: /* 012-3456 */ 301: *p++ = *num++; 302: *p++ = *num++; 303: *p++ = *num++; 304: break; 305: case 5: /* x0-1234 */ 306: *p++ = 'x'; 307: *p++ = *num++; 308: break; 309: default: 310: return(num); 311: } 312: *p++ = '-'; 313: *p++ = *num++; 314: *p++ = *num++; 315: *p++ = *num++; 316: *p++ = *num++; 317: *p = '\0'; 318: return(pbuf); 319: }