util.c revision 1591
1126700Sdes/* 2228991Suqs * Copyright (c) 1989, 1993 3126700Sdes * The Regents of the University of California. All rights reserved. 4126700Sdes * 5126700Sdes * This code is derived from software contributed to Berkeley by 6126700Sdes * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7126700Sdes * 8126700Sdes * Redistribution and use in source and binary forms, with or without 9126700Sdes * modification, are permitted provided that the following conditions 10126700Sdes * are met: 11126700Sdes * 1. Redistributions of source code must retain the above copyright 12126700Sdes * notice, this list of conditions and the following disclaimer. 13126700Sdes * 2. Redistributions in binary form must reproduce the above copyright 14126700Sdes * notice, this list of conditions and the following disclaimer in the 15126700Sdes * documentation and/or other materials provided with the distribution. 16126700Sdes * 3. All advertising materials mentioning features or use of this software 17126700Sdes * must display the following acknowledgement: 18126700Sdes * This product includes software developed by the University of 19126700Sdes * California, Berkeley and its contributors. 20126700Sdes * 4. Neither the name of the University nor the names of its contributors 21126700Sdes * may be used to endorse or promote products derived from this software 22126700Sdes * without specific prior written permission. 23126700Sdes * 24126700Sdes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25126700Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26126700Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27126700Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28126700Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29126700Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30126700Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31126700Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32126700Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33126700Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34126700Sdes * SUCH DAMAGE. 35126700Sdes */ 36126700Sdes 37126700Sdes#ifndef lint 38126700Sdesstatic char sccsid[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; 39126700Sdes#endif /* not lint */ 40126700Sdes 41126700Sdes#include <sys/param.h> 42126700Sdes#include <sys/stat.h> 43126700Sdes#include <fcntl.h> 44126700Sdes#include <db.h> 45126700Sdes#include <pwd.h> 46126700Sdes#include <utmp.h> 47126700Sdes#include <errno.h> 48126700Sdes#include <unistd.h> 49126700Sdes#include <stdio.h> 50126700Sdes#include <ctype.h> 51126700Sdes#include <stdlib.h> 52126700Sdes#include <string.h> 53126700Sdes#include <paths.h> 54126700Sdes#include "finger.h" 55126700Sdes 56126700Sdesstatic void find_idle_and_ttywrite __P((WHERE *)); 57126700Sdesstatic void userinfo __P((PERSON *, struct passwd *)); 58126700Sdesstatic WHERE *walloc __P((PERSON *)); 59126700Sdes 60126700Sdesint 61126700Sdesmatch(pw, user) 62126700Sdes struct passwd *pw; 63126700Sdes char *user; 64126700Sdes{ 65126700Sdes register char *p, *t; 66126700Sdes char name[1024]; 67126700Sdes 68126700Sdes if (!strcasecmp(pw->pw_name, user)) 69126700Sdes return(1); 70126700Sdes 71126700Sdes /* 72126700Sdes * XXX 73126700Sdes * Why do we skip asterisks!?!? 74126700Sdes */ 75126700Sdes (void)strcpy(p = tbuf, pw->pw_gecos); 76126700Sdes if (*p == '*') 77126700Sdes ++p; 78126700Sdes 79126700Sdes /* Ampersands get replaced by the login name. */ 80126700Sdes if ((p = strtok(p, ",")) == NULL) 81126700Sdes return(0); 82126700Sdes 83126700Sdes for (t = name; *t = *p; ++p) 84126700Sdes if (*t == '&') { 85126700Sdes (void)strcpy(t, pw->pw_name); 86126700Sdes while (*++t); 87126700Sdes } 88126700Sdes else 89126700Sdes ++t; 90126700Sdes for (t = name; p = strtok(t, "\t "); t = NULL) 91126700Sdes if (!strcasecmp(p, user)) 92126700Sdes return(1); 93126700Sdes return(0); 94126700Sdes} 95126700Sdes 96126700Sdesvoid 97126700Sdesenter_lastlog(pn) 98126700Sdes register PERSON *pn; 99126700Sdes{ 100126700Sdes register WHERE *w; 101126700Sdes static int opened, fd; 102126700Sdes struct lastlog ll; 103126700Sdes char doit = 0; 104126700Sdes 105126700Sdes /* some systems may not maintain lastlog, don't report errors. */ 106126700Sdes if (!opened) { 107126700Sdes fd = open(_PATH_LASTLOG, O_RDONLY, 0); 108126700Sdes opened = 1; 109126700Sdes } 110126700Sdes if (fd == -1 || 111126700Sdes lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 112126700Sdes (long)pn->uid * sizeof(ll) || 113126700Sdes read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 114126700Sdes /* as if never logged in */ 115126700Sdes ll.ll_line[0] = ll.ll_host[0] = NULL; 116126700Sdes ll.ll_time = 0; 117126700Sdes } 118126700Sdes if ((w = pn->whead) == NULL) 119126700Sdes doit = 1; 120126700Sdes else if (ll.ll_time != 0) { 121126700Sdes /* if last login is earlier than some current login */ 122126700Sdes for (; !doit && w != NULL; w = w->next) 123126700Sdes if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 124126700Sdes doit = 1; 125126700Sdes /* 126126700Sdes * and if it's not any of the current logins 127126700Sdes * can't use time comparison because there may be a small 128126700Sdes * discrepency since login calls time() twice 129126700Sdes */ 130126700Sdes for (w = pn->whead; doit && w != NULL; w = w->next) 131126700Sdes if (w->info == LOGGEDIN && 132126700Sdes strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 133126700Sdes doit = 0; 134126700Sdes } 135126700Sdes if (doit) { 136126700Sdes w = walloc(pn); 137126700Sdes w->info = LASTLOG; 138126700Sdes bcopy(ll.ll_line, w->tty, UT_LINESIZE); 139126700Sdes w->tty[UT_LINESIZE] = 0; 140126700Sdes bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 141126700Sdes w->host[UT_HOSTSIZE] = 0; 142126700Sdes w->loginat = ll.ll_time; 143126700Sdes } 144126700Sdes} 145126700Sdes 146126700Sdesvoid 147126700Sdesenter_where(ut, pn) 148126700Sdes struct utmp *ut; 149126700Sdes PERSON *pn; 150126700Sdes{ 151126700Sdes register WHERE *w; 152126700Sdes 153126700Sdes w = walloc(pn); 154126700Sdes w->info = LOGGEDIN; 155126700Sdes bcopy(ut->ut_line, w->tty, UT_LINESIZE); 156126700Sdes w->tty[UT_LINESIZE] = 0; 157126700Sdes bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 158126700Sdes w->host[UT_HOSTSIZE] = 0; 159126700Sdes w->loginat = (time_t)ut->ut_time; 160126700Sdes find_idle_and_ttywrite(w); 161126700Sdes} 162126700Sdes 163126700SdesPERSON * 164126700Sdesenter_person(pw) 165126700Sdes register struct passwd *pw; 166126700Sdes{ 167126700Sdes DBT data, key; 168126700Sdes PERSON *pn; 169126700Sdes 170126700Sdes if (db == NULL && 171126700Sdes (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 172126700Sdes err("%s", strerror(errno)); 173126700Sdes 174126700Sdes key.data = pw->pw_name; 175126700Sdes key.size = strlen(pw->pw_name); 176126700Sdes 177126700Sdes switch((*db->get)(db, &key, &data, 0)) { 178126700Sdes case 0: 179126700Sdes return(*(PERSON **)data.data); 180126700Sdes default: 181126700Sdes case -1: 182126700Sdes err("db get: %s", strerror(errno)); 183126700Sdes /* NOTREACHED */ 184126700Sdes case 1: 185126700Sdes ++entries; 186126700Sdes pn = palloc(); 187126700Sdes userinfo(pn, pw); 188126700Sdes pn->whead = NULL; 189126700Sdes 190126700Sdes data.size = sizeof(PERSON *); 191126700Sdes data.data = &pn; 192126700Sdes if ((*db->put)(db, &key, &data, 0)) 193126700Sdes err("%s", strerror(errno)); 194126700Sdes return(pn); 195126700Sdes } 196126700Sdes} 197126700Sdes 198126700SdesPERSON * 199126700Sdesfind_person(name) 200126700Sdes char *name; 201126700Sdes{ 202126700Sdes register int cnt; 203126700Sdes DBT data, key; 204126700Sdes char buf[UT_NAMESIZE + 1]; 205126700Sdes 206126700Sdes if (!db) 207126700Sdes return(NULL); 208126700Sdes 209126700Sdes /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 210126700Sdes for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 211126700Sdes buf[cnt] = *name; 212126700Sdes buf[cnt] = '\0'; 213126700Sdes key.data = buf; 214126700Sdes key.size = cnt; 215126700Sdes 216126700Sdes return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 217126700Sdes} 218126700Sdes 219126700SdesPERSON * 220126700Sdespalloc() 221126700Sdes{ 222126700Sdes PERSON *p; 223126700Sdes 224126700Sdes if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 225126700Sdes err("%s", strerror(errno)); 226126700Sdes return(p); 227126700Sdes} 228126700Sdes 229126700Sdesstatic WHERE * 230126700Sdeswalloc(pn) 231126700Sdes register PERSON *pn; 232126700Sdes{ 233126700Sdes register WHERE *w; 234126700Sdes 235126700Sdes if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 236126700Sdes err("%s", strerror(errno)); 237126700Sdes if (pn->whead == NULL) 238126700Sdes pn->whead = pn->wtail = w; 239126700Sdes else { 240126700Sdes pn->wtail->next = w; 241126700Sdes pn->wtail = w; 242126700Sdes } 243126700Sdes w->next = NULL; 244126700Sdes return(w); 245126700Sdes} 246126700Sdes 247126700Sdeschar * 248126700Sdesprphone(num) 249126700Sdes char *num; 250126700Sdes{ 251126700Sdes register char *p; 252126700Sdes int len; 253126700Sdes static char pbuf[15]; 254126700Sdes 255126700Sdes /* don't touch anything if the user has their own formatting */ 256126700Sdes for (p = num; *p; ++p) 257126700Sdes if (!isdigit(*p)) 258126700Sdes return(num); 259126700Sdes len = p - num; 260126700Sdes p = pbuf; 261126700Sdes switch(len) { 262126700Sdes case 11: /* +0-123-456-7890 */ 263126700Sdes *p++ = '+'; 264126700Sdes *p++ = *num++; 265126700Sdes *p++ = '-'; 266126700Sdes /* FALLTHROUGH */ 267126700Sdes case 10: /* 012-345-6789 */ 268126700Sdes *p++ = *num++; 269126700Sdes *p++ = *num++; 270126700Sdes *p++ = *num++; 271126700Sdes *p++ = '-'; 272126700Sdes /* FALLTHROUGH */ 273126700Sdes case 7: /* 012-3456 */ 274126700Sdes *p++ = *num++; 275126700Sdes *p++ = *num++; 276126700Sdes *p++ = *num++; 277126700Sdes break; 278126700Sdes case 5: /* x0-1234 */ 279126700Sdes *p++ = 'x'; 280126700Sdes *p++ = *num++; 281126700Sdes break; 282126700Sdes default: 283126700Sdes return(num); 284126700Sdes } 285126700Sdes *p++ = '-'; 286126700Sdes *p++ = *num++; 287126700Sdes *p++ = *num++; 288126700Sdes *p++ = *num++; 289126700Sdes *p++ = *num++; 290126700Sdes *p = '\0'; 291126700Sdes return(pbuf); 292126700Sdes} 293126700Sdes 294126700Sdesstatic void 295126700Sdesfind_idle_and_ttywrite(w) 296126700Sdes register WHERE *w; 297126700Sdes{ 298126700Sdes extern time_t now; 299126700Sdes struct stat sb; 300126700Sdes 301126700Sdes (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 302126700Sdes if (stat(tbuf, &sb) < 0) { 303126700Sdes (void)fprintf(stderr, 304126700Sdes "finger: %s: %s\n", tbuf, strerror(errno)); 305126700Sdes return; 306126700Sdes } 307126700Sdes w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 308126700Sdes 309126700Sdes#define TALKABLE 0220 /* tty is writable if 220 mode */ 310126700Sdes w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 311126700Sdes} 312126700Sdes 313126700Sdesstatic void 314126700Sdesuserinfo(pn, pw) 315126700Sdes register PERSON *pn; 316126700Sdes register struct passwd *pw; 317126700Sdes{ 318126700Sdes register char *p, *t; 319126700Sdes char *bp, name[1024]; 320126700Sdes 321126700Sdes pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 322126700Sdes 323126700Sdes pn->uid = pw->pw_uid; 324126700Sdes pn->name = strdup(pw->pw_name); 325126700Sdes pn->dir = strdup(pw->pw_dir); 326126700Sdes pn->shell = strdup(pw->pw_shell); 327126700Sdes 328126700Sdes /* why do we skip asterisks!?!? */ 329126700Sdes (void)strcpy(bp = tbuf, pw->pw_gecos); 330126700Sdes if (*bp == '*') 331126700Sdes ++bp; 332126700Sdes 333126700Sdes /* ampersands get replaced by the login name */ 334126700Sdes if (!(p = strsep(&bp, ","))) 335126700Sdes return; 336126700Sdes for (t = name; *t = *p; ++p) 337126700Sdes if (*t == '&') { 338126700Sdes (void)strcpy(t, pw->pw_name); 339126700Sdes if (islower(*t)) 340126700Sdes *t = toupper(*t); 341126700Sdes while (*++t); 342126700Sdes } 343126700Sdes else 344126700Sdes ++t; 345126700Sdes pn->realname = strdup(name); 346126700Sdes pn->office = ((p = strsep(&bp, ",")) && *p) ? 347126700Sdes strdup(p) : NULL; 348126700Sdes pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 349126700Sdes strdup(p) : NULL; 350126700Sdes pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 351126700Sdes strdup(p) : NULL; 352126700Sdes} 353126700Sdes 354126700Sdes#if __STDC__ 355126700Sdes#include <stdarg.h> 356126700Sdes#else 357126700Sdes#include <varargs.h> 358126700Sdes#endif 359126700Sdes 360126700Sdesvoid 361126700Sdes#if __STDC__ 362126700Sdeserr(const char *fmt, ...) 363126700Sdes#else 364126700Sdeserr(fmt, va_alist) 365126700Sdes char *fmt; 366126700Sdes va_dcl 367126700Sdes#endif 368126700Sdes{ 369126700Sdes va_list ap; 370126700Sdes#if __STDC__ 371126700Sdes va_start(ap, fmt); 372126700Sdes#else 373126700Sdes va_start(ap); 374126700Sdes#endif 375126700Sdes (void)fprintf(stderr, "finger: "); 376126700Sdes (void)vfprintf(stderr, fmt, ap); 377126700Sdes va_end(ap); 378126700Sdes (void)fprintf(stderr, "\n"); 379126700Sdes exit(1); 380126700Sdes /* NOTREACHED */ 381126700Sdes} 382126700Sdes