util.c revision 50167
154359Sroberto/* 2285612Sdelphij * Copyright (c) 1989, 1993 3285612Sdelphij * The Regents of the University of California. All rights reserved. 454359Sroberto * 575202Sphk * This code is derived from software contributed to Berkeley by 654359Sroberto * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7285612Sdelphij * 854359Sroberto * Redistribution and use in source and binary forms, with or without 954359Sroberto * modification, are permitted provided that the following conditions 10285612Sdelphij * are met: 11285612Sdelphij * 1. Redistributions of source code must retain the above copyright 12285612Sdelphij * notice, this list of conditions and the following disclaimer. 13285612Sdelphij * 2. Redistributions in binary form must reproduce the above copyright 14285612Sdelphij * notice, this list of conditions and the following disclaimer in the 15285612Sdelphij * documentation and/or other materials provided with the distribution. 16285612Sdelphij * 3. All advertising materials mentioning features or use of this software 17285612Sdelphij * must display the following acknowledgement: 18285612Sdelphij * This product includes software developed by the University of 1954359Sroberto * California, Berkeley and its contributors. 2054359Sroberto * 4. Neither the name of the University nor the names of its contributors 2154359Sroberto * may be used to endorse or promote products derived from this software 2254359Sroberto * without specific prior written permission. 23182007Sroberto * 2454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25285612Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26285612Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27285612Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28285612Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29285612Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30285612Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31289997Sglebius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32285612Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33285612Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34285612Sdelphij * SUCH DAMAGE. 3554359Sroberto */ 3654359Sroberto 3754359Sroberto#ifndef lint 3854359Sroberto#if 0 3954359Srobertostatic char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; 4054359Sroberto#else 4182502Srobertostatic const char rcsid[] = 42285612Sdelphij "$Id: util.c,v 1.6 1999/08/21 18:25:38 imp Exp $"; 4382502Sroberto#endif 44285612Sdelphij#endif /* not lint */ 4554359Sroberto 4654359Sroberto#include <sys/param.h> 47285612Sdelphij#include <sys/stat.h> 48285612Sdelphij#include <fcntl.h> 4954359Sroberto#include <db.h> 50285612Sdelphij#include <err.h> 5154359Sroberto#include <pwd.h> 5254359Sroberto#include <utmp.h> 5354359Sroberto#include <errno.h> 54285612Sdelphij#include <unistd.h> 55132455Sroberto#include <stdio.h> 56285612Sdelphij#include <ctype.h> 57132455Sroberto#include <stdlib.h> 58285612Sdelphij#include <string.h> 59285612Sdelphij#include <paths.h> 60285612Sdelphij#include <errno.h> 61285612Sdelphij#include "finger.h" 62285612Sdelphij 63285612Sdelphijstatic void find_idle_and_ttywrite __P((WHERE *)); 64285612Sdelphijstatic void userinfo __P((PERSON *, struct passwd *)); 65285612Sdelphijstatic WHERE *walloc __P((PERSON *)); 66285612Sdelphij 67285612Sdelphijint 68285612Sdelphijmatch(pw, user) 69285612Sdelphij struct passwd *pw; 70285612Sdelphij char *user; 71285612Sdelphij{ 72285612Sdelphij register char *p, *t; 73285612Sdelphij char name[1024]; 74285612Sdelphij 75285612Sdelphij if (!strcasecmp(pw->pw_name, user)) 76285612Sdelphij return(1); 77294569Sdelphij 7854359Sroberto /* 79285612Sdelphij * XXX 8054359Sroberto * Why do we skip asterisks!?!? 81285612Sdelphij */ 82285612Sdelphij (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); 83285612Sdelphij tbuf[sizeof(tbuf) - 1] = '\0'; 84285612Sdelphij if (*p == '*') 85285612Sdelphij ++p; 86285612Sdelphij 87285612Sdelphij /* Ampersands get replaced by the login name. */ 88285612Sdelphij if ((p = strtok(p, ",")) == NULL) 89285612Sdelphij return(0); 90285612Sdelphij 91285612Sdelphij for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 92285612Sdelphij if (*t == '&') { 93285612Sdelphij (void)strncpy(t, pw->pw_name, 94285612Sdelphij sizeof(name) - (t - name)); 95285612Sdelphij name[sizeof(name) - 1] = '\0'; 96285612Sdelphij while (t < &name[sizeof(name) - 1] && *++t) 97285612Sdelphij continue; 98285612Sdelphij } else { 99285612Sdelphij ++t; 100285612Sdelphij } 101285612Sdelphij } 102285612Sdelphij *t = '\0'; 103285612Sdelphij for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) 104285612Sdelphij if (!strcasecmp(p, user)) 105285612Sdelphij return(1); 106285612Sdelphij return(0); 107285612Sdelphij} 108285612Sdelphij 109285612Sdelphijvoid 110285612Sdelphijenter_lastlog(pn) 111285612Sdelphij register PERSON *pn; 112285612Sdelphij{ 11354359Sroberto register WHERE *w; 114294569Sdelphij static int opened, fd; 115294569Sdelphij struct lastlog ll; 116285612Sdelphij char doit = 0; 117285612Sdelphij 118285612Sdelphij /* some systems may not maintain lastlog, don't report errors. */ 119285612Sdelphij if (!opened) { 120285612Sdelphij fd = open(_PATH_LASTLOG, O_RDONLY, 0); 121285612Sdelphij opened = 1; 122309008Sdelphij } 123309008Sdelphij if (fd == -1 || 124285612Sdelphij lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 125285612Sdelphij (long)pn->uid * sizeof(ll) || 126285612Sdelphij read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 127285612Sdelphij /* as if never logged in */ 128285612Sdelphij ll.ll_line[0] = ll.ll_host[0] = '\0'; 129309008Sdelphij ll.ll_time = 0; 130285612Sdelphij } 13154359Sroberto if ((w = pn->whead) == NULL) 13254359Sroberto doit = 1; 13354359Sroberto else if (ll.ll_time != 0) { 134285612Sdelphij /* if last login is earlier than some current login */ 135285612Sdelphij for (; !doit && w != NULL; w = w->next) 136285612Sdelphij if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 137285612Sdelphij doit = 1; 138285612Sdelphij /* 139285612Sdelphij * and if it's not any of the current logins 140285612Sdelphij * can't use time comparison because there may be a small 141285612Sdelphij * discrepency since login calls time() twice 142285612Sdelphij */ 143285612Sdelphij for (w = pn->whead; doit && w != NULL; w = w->next) 144285612Sdelphij if (w->info == LOGGEDIN && 145285612Sdelphij strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 146285612Sdelphij doit = 0; 147285612Sdelphij } 148285612Sdelphij if (doit) { 149285612Sdelphij w = walloc(pn); 150285612Sdelphij w->info = LASTLOG; 151285612Sdelphij bcopy(ll.ll_line, w->tty, UT_LINESIZE); 152285612Sdelphij w->tty[UT_LINESIZE] = 0; 153285612Sdelphij bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 154285612Sdelphij w->host[UT_HOSTSIZE] = 0; 155285612Sdelphij w->loginat = ll.ll_time; 156285612Sdelphij } 157285612Sdelphij} 158285612Sdelphij 159285612Sdelphijvoid 160285612Sdelphijenter_where(ut, pn) 161285612Sdelphij struct utmp *ut; 162285612Sdelphij PERSON *pn; 163285612Sdelphij{ 164285612Sdelphij register WHERE *w; 165285612Sdelphij 166285612Sdelphij w = walloc(pn); 167285612Sdelphij w->info = LOGGEDIN; 168285612Sdelphij bcopy(ut->ut_line, w->tty, UT_LINESIZE); 169285612Sdelphij w->tty[UT_LINESIZE] = 0; 170285612Sdelphij bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 171285612Sdelphij w->host[UT_HOSTSIZE] = 0; 172285612Sdelphij w->loginat = (time_t)ut->ut_time; 173285612Sdelphij find_idle_and_ttywrite(w); 174285612Sdelphij} 175285612Sdelphij 176285612SdelphijPERSON * 177285612Sdelphijenter_person(pw) 178285612Sdelphij register struct passwd *pw; 179330141Sdelphij{ 180330141Sdelphij DBT data, key; 181330141Sdelphij PERSON *pn; 182330141Sdelphij 183330141Sdelphij if (db == NULL && 184330141Sdelphij (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 185330141Sdelphij err(1, NULL); 186330141Sdelphij 187330141Sdelphij key.data = pw->pw_name; 188330141Sdelphij key.size = strlen(pw->pw_name); 189330141Sdelphij 190330141Sdelphij switch ((*db->get)(db, &key, &data, 0)) { 191330141Sdelphij case 0: 192330141Sdelphij memmove(&pn, data.data, sizeof pn); 193330141Sdelphij return (pn); 194330141Sdelphij default: 195330141Sdelphij case -1: 196330141Sdelphij err(1, "db get"); 197330141Sdelphij /* NOTREACHED */ 198330141Sdelphij case 1: 199330141Sdelphij ++entries; 200330141Sdelphij pn = palloc(); 201330141Sdelphij userinfo(pn, pw); 202330141Sdelphij pn->whead = NULL; 203330141Sdelphij 204330141Sdelphij data.size = sizeof(PERSON *); 205330141Sdelphij data.data = &pn; 206330141Sdelphij if ((*db->put)(db, &key, &data, 0)) 207330141Sdelphij err(1, "db put"); 208330141Sdelphij return (pn); 209330141Sdelphij } 210285612Sdelphij} 211285612Sdelphij 212330141SdelphijPERSON * 213330141Sdelphijfind_person(name) 214330141Sdelphij char *name; 215330141Sdelphij{ 216330141Sdelphij struct passwd *pw; 217330141Sdelphij 218330141Sdelphij register int cnt; 219330141Sdelphij DBT data, key; 220330141Sdelphij PERSON *p; 221330141Sdelphij char buf[UT_NAMESIZE + 1]; 222330141Sdelphij 223330141Sdelphij if (!db) 224330141Sdelphij return(NULL); 225330141Sdelphij 226330141Sdelphij if ((pw = getpwnam(name)) && hide(pw)) 227330141Sdelphij return(NULL); 228330141Sdelphij 229330141Sdelphij /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 230330141Sdelphij for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 231285612Sdelphij buf[cnt] = *name; 232285612Sdelphij buf[cnt] = '\0'; 233285612Sdelphij key.data = buf; 234285612Sdelphij key.size = cnt; 235285612Sdelphij 236285612Sdelphij if ((*db->get)(db, &key, &data, 0)) 237285612Sdelphij return (NULL); 238285612Sdelphij memmove(&p, data.data, sizeof p); 239285612Sdelphij return (p); 240285612Sdelphij} 241285612Sdelphij 242285612SdelphijPERSON * 243285612Sdelphijpalloc() 244285612Sdelphij{ 245285612Sdelphij PERSON *p; 246285612Sdelphij 247285612Sdelphij if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 248285612Sdelphij err(1, NULL); 249285612Sdelphij return(p); 250285612Sdelphij} 251285612Sdelphij 252285612Sdelphijstatic WHERE * 253285612Sdelphijwalloc(pn) 254285612Sdelphij register PERSON *pn; 255285612Sdelphij{ 256285612Sdelphij register WHERE *w; 257285612Sdelphij 258285612Sdelphij if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 259285612Sdelphij err(1, NULL); 260285612Sdelphij if (pn->whead == NULL) 261285612Sdelphij pn->whead = pn->wtail = w; 262285612Sdelphij else { 263285612Sdelphij pn->wtail->next = w; 264285612Sdelphij pn->wtail = w; 265285612Sdelphij } 266285612Sdelphij w->next = NULL; 267285612Sdelphij return(w); 268285612Sdelphij} 269285612Sdelphij 270285612Sdelphijchar * 271285612Sdelphijprphone(num) 272285612Sdelphij char *num; 273285612Sdelphij{ 274285612Sdelphij register char *p; 275285612Sdelphij int len; 276285612Sdelphij static char pbuf[20]; 277285612Sdelphij 278285612Sdelphij /* don't touch anything if the user has their own formatting */ 279285612Sdelphij for (p = num; *p; ++p) 280285612Sdelphij if (!isdigit(*p)) 281285612Sdelphij return(num); 282285612Sdelphij len = p - num; 283285612Sdelphij p = pbuf; 284285612Sdelphij switch(len) { 285285612Sdelphij case 11: /* +0-123-456-7890 */ 286285612Sdelphij *p++ = '+'; 287285612Sdelphij *p++ = *num++; 288285612Sdelphij *p++ = '-'; 289285612Sdelphij /* FALLTHROUGH */ 290285612Sdelphij case 10: /* 012-345-6789 */ 291285612Sdelphij *p++ = *num++; 292285612Sdelphij *p++ = *num++; 293285612Sdelphij *p++ = *num++; 294285612Sdelphij *p++ = '-'; 295285612Sdelphij /* FALLTHROUGH */ 296285612Sdelphij case 7: /* 012-3456 */ 297285612Sdelphij *p++ = *num++; 298285612Sdelphij *p++ = *num++; 299285612Sdelphij *p++ = *num++; 300285612Sdelphij break; 301285612Sdelphij case 5: /* x0-1234 */ 302285612Sdelphij case 4: /* x1234 */ 303285612Sdelphij *p++ = 'x'; 304285612Sdelphij *p++ = *num++; 305285612Sdelphij break; 306285612Sdelphij default: 307285612Sdelphij return(num); 308285612Sdelphij } 309285612Sdelphij if (len != 4) { 310285612Sdelphij *p++ = '-'; 311285612Sdelphij *p++ = *num++; 312285612Sdelphij } 313285612Sdelphij *p++ = *num++; 314285612Sdelphij *p++ = *num++; 315285612Sdelphij *p++ = *num++; 316285612Sdelphij *p = '\0'; 317285612Sdelphij return(pbuf); 318285612Sdelphij} 319285612Sdelphij 320285612Sdelphijstatic void 321285612Sdelphijfind_idle_and_ttywrite(w) 322285612Sdelphij register WHERE *w; 323285612Sdelphij{ 324285612Sdelphij extern time_t now; 325285612Sdelphij struct stat sb; 326285612Sdelphij 327285612Sdelphij (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 328285612Sdelphij if (stat(tbuf, &sb) < 0) { 329285612Sdelphij warn(tbuf); 330285612Sdelphij return; 331285612Sdelphij } 332285612Sdelphij w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 33382502Sroberto 33482502Sroberto#define TALKABLE 0220 /* tty is writable if 220 mode */ 33554359Sroberto w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 336285612Sdelphij} 33754359Sroberto 33854359Srobertostatic void 33954359Srobertouserinfo(pn, pw) 34054359Sroberto register PERSON *pn; 34154359Sroberto register struct passwd *pw; 342285612Sdelphij{ 34354359Sroberto register char *p, *t; 34454359Sroberto char *bp, name[1024]; 345285612Sdelphij struct stat sb; 34654359Sroberto 347285612Sdelphij pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 348285612Sdelphij 349285612Sdelphij pn->uid = pw->pw_uid; 350285612Sdelphij pn->name = strdup(pw->pw_name); 351285612Sdelphij pn->dir = strdup(pw->pw_dir); 352285612Sdelphij pn->shell = strdup(pw->pw_shell); 353285612Sdelphij 354285612Sdelphij /* why do we skip asterisks!?!? */ 355285612Sdelphij (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 356285612Sdelphij tbuf[sizeof(tbuf) - 1] = '\0'; 357285612Sdelphij if (*bp == '*') 358285612Sdelphij ++bp; 359285612Sdelphij 360285612Sdelphij /* ampersands get replaced by the login name */ 361285612Sdelphij if (!(p = strsep(&bp, ","))) 362285612Sdelphij return; 363285612Sdelphij for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 364285612Sdelphij if (*t == '&') { 365285612Sdelphij (void)strncpy(t, pw->pw_name, 366285612Sdelphij sizeof(name) - (t - name)); 367285612Sdelphij name[sizeof(name) - 1] = '\0'; 368285612Sdelphij if (islower(*t)) 369285612Sdelphij *t = toupper(*t); 370285612Sdelphij while (t < &name[sizeof(name) - 1] && *++t) 371285612Sdelphij continue; 372285612Sdelphij } else { 373285612Sdelphij ++t; 374285612Sdelphij } 375285612Sdelphij } 376285612Sdelphij *t = '\0'; 377285612Sdelphij pn->realname = strdup(name); 378285612Sdelphij pn->office = ((p = strsep(&bp, ",")) && *p) ? 379285612Sdelphij strdup(p) : NULL; 380285612Sdelphij pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 381330141Sdelphij strdup(p) : NULL; 382330141Sdelphij pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 383330141Sdelphij strdup(p) : NULL; 384330141Sdelphij (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name); 385330141Sdelphij pn->mailrecv = -1; /* -1 == not_valid */ 386330141Sdelphij if (stat(tbuf, &sb) < 0) { 387330141Sdelphij if (errno != ENOENT) { 388330141Sdelphij warn("%s", tbuf); 389330141Sdelphij return; 390330141Sdelphij } 391330141Sdelphij } else if (sb.st_size != 0) { 392330141Sdelphij pn->mailrecv = sb.st_mtime; 393330141Sdelphij pn->mailread = sb.st_atime; 394330141Sdelphij } 395330141Sdelphij} 396330141Sdelphij 397330141Sdelphij/* 398330141Sdelphij * Is this user hiding from finger? 399330141Sdelphij * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 400330141Sdelphij */ 401330141Sdelphij 402330141Sdelphijint 403330141Sdelphijhide(pw) 404330141Sdelphij struct passwd *pw; 405330141Sdelphij{ 406330141Sdelphij char buf[MAXPATHLEN+1]; 407330141Sdelphij 408330141Sdelphij if (!pw->pw_dir) 409330141Sdelphij return 0; 410330141Sdelphij 411330141Sdelphij snprintf(buf, sizeof(buf), "%s/.nofinger", pw->pw_dir); 412330141Sdelphij buf[sizeof(buf) - 1] = '\0'; 413330141Sdelphij 414330141Sdelphij if (access(buf, F_OK) == 0) 415330141Sdelphij return 1; 416330141Sdelphij 417330141Sdelphij return 0; 418330141Sdelphij} 419330141Sdelphij