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