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