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