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