util.c revision 5369
1279430Srstone/* 2279430Srstone * Copyright (c) 1989, 1993 3279430Srstone * The Regents of the University of California. All rights reserved. 4279430Srstone * 5279430Srstone * This code is derived from software contributed to Berkeley by 6279430Srstone * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7279430Srstone * 8279430Srstone * Redistribution and use in source and binary forms, with or without 9279430Srstone * modification, are permitted provided that the following conditions 10279430Srstone * are met: 11279430Srstone * 1. Redistributions of source code must retain the above copyright 12279430Srstone * notice, this list of conditions and the following disclaimer. 13279430Srstone * 2. Redistributions in binary form must reproduce the above copyright 14279430Srstone * notice, this list of conditions and the following disclaimer in the 15279430Srstone * documentation and/or other materials provided with the distribution. 16279430Srstone * 3. All advertising materials mentioning features or use of this software 17279430Srstone * must display the following acknowledgement: 18279430Srstone * This product includes software developed by the University of 19279430Srstone * California, Berkeley and its contributors. 20279430Srstone * 4. Neither the name of the University nor the names of its contributors 21279430Srstone * may be used to endorse or promote products derived from this software 22279430Srstone * without specific prior written permission. 23279430Srstone * 24279430Srstone * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25279430Srstone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26279430Srstone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27279430Srstone * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28279430Srstone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29279430Srstone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30279430Srstone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31279430Srstone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32279430Srstone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33279430Srstone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34279430Srstone * SUCH DAMAGE. 35279430Srstone */ 36279430Srstone 37279430Srstone#ifndef lint 38279430Srstonestatic char sccsid[] = "@(#)util.c 8.1 (Berkeley) 6/6/93"; 39279430Srstone#endif /* not lint */ 40279430Srstone 41279430Srstone#include <sys/param.h> 42279430Srstone#include <sys/stat.h> 43279430Srstone#include <fcntl.h> 44279430Srstone#include <db.h> 45279430Srstone#include <pwd.h> 46279430Srstone#include <utmp.h> 47279430Srstone#include <errno.h> 48292637Sngie#include <unistd.h> 49279430Srstone#include <stdio.h> 50279430Srstone#include <ctype.h> 51279430Srstone#include <stdlib.h> 52279430Srstone#include <string.h> 53279430Srstone#include <paths.h> 54279430Srstone#include <errno.h> 55279430Srstone#include "finger.h" 56279430Srstone 57279430Srstonestatic void find_idle_and_ttywrite __P((WHERE *)); 58279430Srstonestatic void userinfo __P((PERSON *, struct passwd *)); 59279430Srstonestatic WHERE *walloc __P((PERSON *)); 60279430Srstone 61279430Srstoneint 62279430Srstonematch(pw, user) 63292637Sngie struct passwd *pw; 64279430Srstone char *user; 65279430Srstone{ 66279430Srstone register char *p, *t; 67279430Srstone char name[1024]; 68292637Sngie 69279430Srstone if (!strcasecmp(pw->pw_name, user)) 70279430Srstone return(1); 71279430Srstone 72279430Srstone /* 73279430Srstone * XXX 74279430Srstone * Why do we skip asterisks!?!? 75279430Srstone */ 76279430Srstone (void)strcpy(p = tbuf, pw->pw_gecos); 77279430Srstone if (*p == '*') 78279430Srstone ++p; 79279430Srstone 80279430Srstone /* Ampersands get replaced by the login name. */ 81279430Srstone if ((p = strtok(p, ",")) == NULL) 82279430Srstone return(0); 83279430Srstone 84279430Srstone for (t = name; *t = *p; ++p) 85279430Srstone if (*t == '&') { 86279430Srstone (void)strcpy(t, pw->pw_name); 87292637Sngie while (*++t); 88279430Srstone } 89279430Srstone else 90279430Srstone ++t; 91279430Srstone for (t = name; p = strtok(t, "\t "); t = NULL) 92279430Srstone if (!strcasecmp(p, user)) 93279430Srstone return(1); 94279430Srstone return(0); 95279430Srstone} 96279430Srstone 97279430Srstonevoid 98279430Srstoneenter_lastlog(pn) 99279430Srstone register PERSON *pn; 100279430Srstone{ 101279430Srstone register WHERE *w; 102292637Sngie static int opened, fd; 103279430Srstone struct lastlog ll; 104279430Srstone char doit = 0; 105279430Srstone 106292637Sngie /* some systems may not maintain lastlog, don't report errors. */ 107279430Srstone if (!opened) { 108279430Srstone fd = open(_PATH_LASTLOG, O_RDONLY, 0); 109279430Srstone opened = 1; 110279430Srstone } 111279430Srstone if (fd == -1 || 112279430Srstone lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 113279430Srstone (long)pn->uid * sizeof(ll) || 114279430Srstone read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 115279430Srstone /* as if never logged in */ 116279430Srstone ll.ll_line[0] = ll.ll_host[0] = NULL; 117279430Srstone ll.ll_time = 0; 118279430Srstone } 119279430Srstone if ((w = pn->whead) == NULL) 120279430Srstone doit = 1; 121279430Srstone else if (ll.ll_time != 0) { 122279430Srstone /* if last login is earlier than some current login */ 123279430Srstone for (; !doit && w != NULL; w = w->next) 124279430Srstone if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 125279430Srstone doit = 1; 126292637Sngie /* 127279430Srstone * and if it's not any of the current logins 128279430Srstone * can't use time comparison because there may be a small 129279430Srstone * discrepency since login calls time() twice 130279430Srstone */ 131279430Srstone for (w = pn->whead; doit && w != NULL; w = w->next) 132279430Srstone if (w->info == LOGGEDIN && 133279430Srstone strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 134279430Srstone doit = 0; 135279430Srstone } 136279430Srstone if (doit) { 137279430Srstone w = walloc(pn); 138279430Srstone w->info = LASTLOG; 139279430Srstone bcopy(ll.ll_line, w->tty, UT_LINESIZE); 140279430Srstone w->tty[UT_LINESIZE] = 0; 141279430Srstone bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 142279430Srstone w->host[UT_HOSTSIZE] = 0; 143279430Srstone w->loginat = ll.ll_time; 144292637Sngie } 145279430Srstone} 146279430Srstone 147279430Srstonevoid 148279430Srstoneenter_where(ut, pn) 149279430Srstone struct utmp *ut; 150292637Sngie PERSON *pn; 151319370Sngie{ 152279430Srstone register WHERE *w; 153279430Srstone 154279430Srstone w = walloc(pn); 155279430Srstone w->info = LOGGEDIN; 156279430Srstone bcopy(ut->ut_line, w->tty, UT_LINESIZE); 157279430Srstone w->tty[UT_LINESIZE] = 0; 158279430Srstone bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 159279430Srstone w->host[UT_HOSTSIZE] = 0; 160279430Srstone w->loginat = (time_t)ut->ut_time; 161279430Srstone find_idle_and_ttywrite(w); 162279430Srstone} 163279430Srstone 164279430SrstonePERSON * 165279430Srstoneenter_person(pw) 166279430Srstone register struct passwd *pw; 167279430Srstone{ 168279430Srstone DBT data, key; 169279430Srstone PERSON *pn; 170279430Srstone 171279430Srstone if (db == NULL && 172279430Srstone (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 173279430Srstone err("%s", strerror(errno)); 174279430Srstone 175279430Srstone key.data = pw->pw_name; 176279430Srstone key.size = strlen(pw->pw_name); 177279430Srstone 178279430Srstone switch((*db->get)(db, &key, &data, 0)) { 179279430Srstone case 0: 180279430Srstone return(*(PERSON **)data.data); 181279430Srstone default: 182279430Srstone case -1: 183279430Srstone err("db get: %s", strerror(errno)); 184279430Srstone /* NOTREACHED */ 185279430Srstone case 1: 186279430Srstone ++entries; 187279430Srstone pn = palloc(); 188279430Srstone userinfo(pn, pw); 189279430Srstone pn->whead = NULL; 190279430Srstone 191279430Srstone data.size = sizeof(PERSON *); 192292637Sngie data.data = &pn; 193279430Srstone if ((*db->put)(db, &key, &data, 0)) 194279430Srstone err("%s", strerror(errno)); 195279430Srstone return(pn); 196279430Srstone } 197279430Srstone} 198279430Srstone 199279430SrstonePERSON * 200279430Srstonefind_person(name) 201279430Srstone char *name; 202279430Srstone{ 203279430Srstone struct passwd *pw; 204279430Srstone 205279430Srstone register int cnt; 206279430Srstone DBT data, key; 207279430Srstone char buf[UT_NAMESIZE + 1]; 208279430Srstone 209279430Srstone if (!db) 210279430Srstone return(NULL); 211279430Srstone 212279430Srstone if ((pw = getpwnam(name)) && hide(pw)) 213279430Srstone return(NULL); 214279430Srstone 215279430Srstone /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 216279430Srstone for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 217279430Srstone buf[cnt] = *name; 218279430Srstone buf[cnt] = '\0'; 219279430Srstone key.data = buf; 220279430Srstone key.size = cnt; 221279430Srstone 222279430Srstone return((*db->get)(db, &key, &data, 0) ? NULL : *(PERSON **)data.data); 223279430Srstone} 224279430Srstone 225279430SrstonePERSON * 226279430Srstonepalloc() 227279430Srstone{ 228279430Srstone PERSON *p; 229279430Srstone 230279430Srstone if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 231279430Srstone err("%s", strerror(errno)); 232279430Srstone return(p); 233279430Srstone} 234279430Srstone 235279430Srstonestatic WHERE * 236279430Srstonewalloc(pn) 237279430Srstone register PERSON *pn; 238279430Srstone{ 239279430Srstone register WHERE *w; 240279430Srstone 241279430Srstone if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 242279430Srstone err("%s", strerror(errno)); 243279430Srstone if (pn->whead == NULL) 244292637Sngie pn->whead = pn->wtail = w; 245292637Sngie else { 246279430Srstone pn->wtail->next = w; 247279430Srstone pn->wtail = w; 248279430Srstone } 249279430Srstone w->next = NULL; 250279430Srstone return(w); 251279430Srstone} 252279430Srstone 253279430Srstonechar * 254279430Srstoneprphone(num) 255279430Srstone char *num; 256279430Srstone{ 257279430Srstone register char *p; 258279430Srstone int len; 259292637Sngie static char pbuf[15]; 260292637Sngie 261279430Srstone /* don't touch anything if the user has their own formatting */ 262279430Srstone for (p = num; *p; ++p) 263279430Srstone if (!isdigit(*p)) 264279430Srstone return(num); 265279430Srstone len = p - num; 266279430Srstone p = pbuf; 267292634Sngie switch(len) { 268292634Sngie case 11: /* +0-123-456-7890 */ 269292634Sngie *p++ = '+'; 270292634Sngie *p++ = *num++; 271292634Sngie *p++ = '-'; 272292634Sngie /* FALLTHROUGH */ 273292634Sngie case 10: /* 012-345-6789 */ 274292634Sngie *p++ = *num++; 275292634Sngie *p++ = *num++; 276292634Sngie *p++ = *num++; 277292634Sngie *p++ = '-'; 278292634Sngie /* FALLTHROUGH */ 279292634Sngie case 7: /* 012-3456 */ 280292634Sngie *p++ = *num++; 281292634Sngie *p++ = *num++; 282292634Sngie *p++ = *num++; 283292634Sngie break; 284292634Sngie case 5: /* x0-1234 */ 285292634Sngie case 4: /* x1234 */ 286292634Sngie *p++ = 'x'; 287292634Sngie *p++ = *num++; 288292634Sngie break; 289292634Sngie default: 290292634Sngie return(num); 291292634Sngie } 292292634Sngie if (len != 4) { 293292634Sngie *p++ = '-'; 294292634Sngie *p++ = *num++; 295292634Sngie } 296292634Sngie *p++ = *num++; 297292634Sngie *p++ = *num++; 298292634Sngie *p++ = *num++; 299292634Sngie *p = '\0'; 300292634Sngie return(pbuf); 301292634Sngie} 302292634Sngie 303292634Sngiestatic void 304292634Sngiefind_idle_and_ttywrite(w) 305292634Sngie register WHERE *w; 306292634Sngie{ 307292634Sngie extern time_t now; 308292634Sngie struct stat sb; 309292634Sngie 310292634Sngie (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 311292634Sngie if (stat(tbuf, &sb) < 0) { 312292634Sngie (void)fprintf(stderr, 313292634Sngie "finger: %s: %s\n", tbuf, strerror(errno)); 314292634Sngie return; 315292634Sngie } 316292634Sngie w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 317292634Sngie 318292634Sngie#define TALKABLE 0220 /* tty is writable if 220 mode */ 319292634Sngie w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 320292634Sngie} 321292634Sngie 322292634Sngiestatic void 323292634Sngieuserinfo(pn, pw) 324292634Sngie register PERSON *pn; 325292634Sngie register struct passwd *pw; 326292634Sngie{ 327292634Sngie register char *p, *t; 328292634Sngie char *bp, name[1024]; 329292634Sngie struct stat sb; 330292634Sngie 331292634Sngie pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 332292634Sngie 333292634Sngie pn->uid = pw->pw_uid; 334292634Sngie pn->name = strdup(pw->pw_name); 335292634Sngie pn->dir = strdup(pw->pw_dir); 336292634Sngie pn->shell = strdup(pw->pw_shell); 337292634Sngie 338292634Sngie /* why do we skip asterisks!?!? */ 339292634Sngie (void)strcpy(bp = tbuf, pw->pw_gecos); 340292634Sngie if (*bp == '*') 341292634Sngie ++bp; 342292634Sngie 343292634Sngie /* ampersands get replaced by the login name */ 344292634Sngie if (!(p = strsep(&bp, ","))) 345292634Sngie return; 346292634Sngie for (t = name; *t = *p; ++p) 347292634Sngie if (*t == '&') { 348292634Sngie (void)strcpy(t, pw->pw_name); 349292634Sngie if (islower(*t)) 350292634Sngie *t = toupper(*t); 351292634Sngie while (*++t); 352292634Sngie } 353292634Sngie else 354292634Sngie ++t; 355292634Sngie pn->realname = strdup(name); 356292634Sngie pn->office = ((p = strsep(&bp, ",")) && *p) ? 357292634Sngie strdup(p) : NULL; 358292634Sngie pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 359292634Sngie strdup(p) : NULL; 360292634Sngie pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 361292634Sngie strdup(p) : NULL; 362292634Sngie (void)sprintf(tbuf,"%s/%s", _PATH_MAILDIR, pw->pw_name); 363292634Sngie pn->mailrecv = -1; /* -1 == not_valid */ 364292634Sngie if (stat(tbuf, &sb) < 0) { 365292634Sngie if (errno != ENOENT) { 366292634Sngie (void)fprintf(stderr, 367292634Sngie "finger: %s: %s\n", tbuf, strerror(errno)); 368292634Sngie return; 369292634Sngie } 370292634Sngie } else if (sb.st_size != 0) { 371292634Sngie pn->mailrecv = sb.st_mtime; 372292634Sngie pn->mailread = sb.st_atime; 373292634Sngie } 374292634Sngie} 375292634Sngie 376292634Sngie#if __STDC__ 377292634Sngie#include <stdarg.h> 378292634Sngie#else 379292634Sngie#include <varargs.h> 380292634Sngie#endif 381292634Sngie 382292634Sngievoid 383292634Sngie#if __STDC__ 384292634Sngieerr(const char *fmt, ...) 385292634Sngie#else 386292634Sngieerr(fmt, va_alist) 387292634Sngie char *fmt; 388292634Sngie va_dcl 389292634Sngie#endif 390292634Sngie{ 391292634Sngie va_list ap; 392292634Sngie#if __STDC__ 393292634Sngie va_start(ap, fmt); 394292634Sngie#else 395292634Sngie va_start(ap); 396292634Sngie#endif 397292634Sngie (void)fprintf(stderr, "finger: "); 398292634Sngie (void)vfprintf(stderr, fmt, ap); 399292634Sngie va_end(ap); 400292634Sngie (void)fprintf(stderr, "\n"); 401292634Sngie exit(1); 402292634Sngie /* NOTREACHED */ 403292634Sngie} 404292634Sngie 405292634Sngie/* 406292634Sngie * Is this user hiding from finger? 407292634Sngie * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 408292634Sngie */ 409292634Sngie 410292634Sngieint 411292634Sngiehide(pw) 412292634Sngie struct passwd *pw; 413292634Sngie{ 414292634Sngie int fd; 415292634Sngie char buf[MAXPATHLEN+1]; 416292634Sngie 417292634Sngie if (!pw->pw_dir) 418292634Sngie return 0; 419292634Sngie 420292634Sngie sprintf (buf, "%s/.nofinger", pw->pw_dir); 421292634Sngie 422292634Sngie if (access (buf, F_OK) == 0) 423292634Sngie return 1; 424292634Sngie 425292634Sngie return 0; 426292634Sngie} 427292634Sngie