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