1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. 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, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 static char sccsid[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include <db.h> 45 #include <pwd.h> 46 #include <utmp.h> 47 #include <errno.h> 48 #include <unistd.h> 49 #include <stdio.h> 50 #include <ctype.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <paths.h> 54 #include "finger.h" 55 56 static void find_idle_and_ttywrite __P((WHERE *)); 57 static void userinfo __P((PERSON *, struct passwd *)); 58 static WHERE *walloc __P((PERSON *)); 59 60 int 61 match(pw, user) 62 struct passwd *pw; 63 char *user; 64 { 65 register char *p, *t; 66 char name[1024]; 67 68 if (!strcasecmp(pw->pw_name, user)) 69 return(1); 70 71 /* 72 * XXX 73 * Why do we skip asterisks!?!? 74 */ 75 (void)strcpy(p = tbuf, pw->pw_gecos); 76 if (*p == '*') 77 ++p; 78 79 /* Ampersands get replaced by the login name. */ 80 if ((p = strtok(p, ",")) == NULL) 81 return(0); 82 83 for (t = name; *t = *p; ++p) 84 if (*t == '&') { 85 (void)strcpy(t, pw->pw_name); 86 while (*++t); 87 } 88 else 89 ++t; 90 for (t = name; p = strtok(t, "\t "); t = NULL) 91 if (!strcasecmp(p, user)) 92 return(1); 93 return(0); 94 } 95 96 void 97 enter_lastlog(pn) 98 register PERSON *pn; 99 { 100 register WHERE *w; 101 static int opened, fd; 102 struct lastlog ll; 103 char doit = 0; 104 105 /* some systems may not maintain lastlog, don't report errors. */ 106 if (!opened) { 107 fd = open(_PATH_LASTLOG, O_RDONLY, 0); 108 opened = 1; 109 } 110 if (fd == -1 || 111 lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 112 (long)pn->uid * sizeof(ll) || 113 read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 114 /* as if never logged in */ 115 ll.ll_line[0] = ll.ll_host[0] = NULL; 116 ll.ll_time = 0; 117 } 118 if ((w = pn->whead) == NULL) 119 doit = 1; 120 else if (ll.ll_time != 0) { 121 /* if last login is earlier than some current login */ 122 for (; !doit && w != NULL; w = w->next) 123 if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 124 doit = 1; 125 /* 126 * and if it's not any of the current logins 127 * can't use time comparison because there may be a small 128 * discrepency since login calls time() twice 129 */ 130 for (w = pn->whead; doit && w != NULL; w = w->next) 131 if (w->info == LOGGEDIN && 132 strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 133 doit = 0; 134 } 135 if (doit) { 136 w = walloc(pn); 137 w->info = LASTLOG; 138 bcopy(ll.ll_line, w->tty, UT_LINESIZE); 139 w->tty[UT_LINESIZE] = 0; 140 bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 141 w->host[UT_HOSTSIZE] = 0; 142 w->loginat = ll.ll_time; 143 } 144 } 145 146 void 147 enter_where(ut, pn) 148 struct utmp *ut; 149 PERSON *pn; 150 { 151 register WHERE *w; 152 153 w = walloc(pn); 154 w->info = LOGGEDIN; 155 bcopy(ut->ut_line, w->tty, UT_LINESIZE); 156 w->tty[UT_LINESIZE] = 0; 157 bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 158 w->host[UT_HOSTSIZE] = 0; 159 w->loginat = (time_t)ut->ut_time; 160 find_idle_and_ttywrite(w); 161 } 162 163 PERSON * 164 enter_person(pw) 165 register struct passwd *pw; 166 { 167 DBT data, key; 168 PERSON *pn; 169 170 if (db == NULL && 171 (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 172 err("%s", strerror(errno)); 173 174 key.data = pw->pw_name; 175 key.size = strlen(pw->pw_name); 176 177 switch((*db->get)(db, &key, &data, 0)) { 178 case 0: 179 return(*(PERSON **)data.data); 180 default: 181 case -1: 182 err("db get: %s", strerror(errno)); 183 /* NOTREACHED */ 184 case 1: 185 ++entries; 186 pn = palloc(); 187 userinfo(pn, pw); 188 pn->whead = NULL; 189 190 data.size = sizeof(PERSON *); 191 data.data = &pn; 192 if ((*db->put)(db, &key, &data, 0)) 193 err("%s", strerror(errno)); 194 return(pn); 195 } 196 } 197 198 PERSON * 199 find_person(name) 200 char *name; 201 { 202 register int cnt; 203 DBT data, key; 204 char buf[UT_NAMESIZE + 1]; 205 206 if (!db) 207 return(NULL); 208 209 /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 210 for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 211 buf[cnt] = *name; 212 buf[cnt] = '\0'; 213 key.data = buf; 214 key.size = cnt; 215 216 return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 217 } 218 219 PERSON * 220 palloc() 221 { 222 PERSON *p; 223 224 if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 225 err("%s", strerror(errno)); 226 return(p); 227 } 228 229 static WHERE * 230 walloc(pn) 231 register PERSON *pn; 232 { 233 register WHERE *w; 234 235 if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 236 err("%s", strerror(errno)); 237 if (pn->whead == NULL) 238 pn->whead = pn->wtail = w; 239 else { 240 pn->wtail->next = w; 241 pn->wtail = w; 242 } 243 w->next = NULL; 244 return(w); 245 } 246 247 char * 248 prphone(num) 249 char *num; 250 { 251 register char *p; 252 int len; 253 static char pbuf[15]; 254 255 /* don't touch anything if the user has their own formatting */ 256 for (p = num; *p; ++p) 257 if (!isdigit(*p)) 258 return(num); 259 len = p - num; 260 p = pbuf; 261 switch(len) { 262 case 11: /* +0-123-456-7890 */ 263 *p++ = '+'; 264 *p++ = *num++; 265 *p++ = '-'; 266 /* FALLTHROUGH */ 267 case 10: /* 012-345-6789 */ 268 *p++ = *num++; 269 *p++ = *num++; 270 *p++ = *num++; 271 *p++ = '-'; 272 /* FALLTHROUGH */ 273 case 7: /* 012-3456 */ 274 *p++ = *num++; 275 *p++ = *num++; 276 *p++ = *num++; 277 break; 278 case 5: /* x0-1234 */ 279 *p++ = 'x'; 280 *p++ = *num++; 281 break; 282 default: 283 return(num); 284 } 285 *p++ = '-'; 286 *p++ = *num++; 287 *p++ = *num++; 288 *p++ = *num++; 289 *p++ = *num++; 290 *p = '\0'; 291 return(pbuf); 292 } 293 294 static void 295 find_idle_and_ttywrite(w) 296 register WHERE *w; 297 { 298 extern time_t now; 299 struct stat sb; 300 301 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 302 if (stat(tbuf, &sb) < 0) { 303 (void)fprintf(stderr, 304 "finger: %s: %s\n", tbuf, strerror(errno)); 305 return; 306 } 307 w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 308 309 #define TALKABLE 0220 /* tty is writable if 220 mode */ 310 w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 311 } 312 313 static void 314 userinfo(pn, pw) 315 register PERSON *pn; 316 register struct passwd *pw; 317 { 318 register char *p, *t; 319 char *bp, name[1024]; 320 321 pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 322 323 pn->uid = pw->pw_uid; 324 pn->name = strdup(pw->pw_name); 325 pn->dir = strdup(pw->pw_dir); 326 pn->shell = strdup(pw->pw_shell); 327 328 /* why do we skip asterisks!?!? */ 329 (void)strcpy(bp = tbuf, pw->pw_gecos); 330 if (*bp == '*') 331 ++bp; 332 333 /* ampersands get replaced by the login name */ 334 if (!(p = strsep(&bp, ","))) 335 return; 336 for (t = name; *t = *p; ++p) 337 if (*t == '&') { 338 (void)strcpy(t, pw->pw_name); 339 if (islower(*t)) 340 *t = toupper(*t); 341 while (*++t); 342 } 343 else 344 ++t; 345 pn->realname = strdup(name); 346 pn->office = ((p = strsep(&bp, ",")) && *p) ? 347 strdup(p) : NULL; 348 pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 349 strdup(p) : NULL; 350 pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 351 strdup(p) : NULL; 352 } 353 354 #if __STDC__ 355 #include <stdarg.h> 356 #else 357 #include <varargs.h> 358 #endif 359 360 void 361 #if __STDC__ 362 err(const char *fmt, ...) 363 #else 364 err(fmt, va_alist) 365 char *fmt; 366 va_dcl 367 #endif 368 { 369 va_list ap; 370 #if __STDC__ 371 va_start(ap, fmt); 372 #else 373 va_start(ap); 374 #endif 375 (void)fprintf(stderr, "finger: "); 376 (void)vfprintf(stderr, fmt, ap); 377 va_end(ap); 378 (void)fprintf(stderr, "\n"); 379 exit(1); 380 /* NOTREACHED */ 381 } 382