util.c revision 72109
1169689Skan/* 2169689Skan * Copyright (c) 1989, 1993 3171825Skan * The Regents of the University of California. All rights reserved. 4169689Skan * 5169689Skan * This code is derived from software contributed to Berkeley by 6169689Skan * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 7169689Skan * 8169689Skan * Redistribution and use in source and binary forms, with or without 9169689Skan * modification, are permitted provided that the following conditions 10169689Skan * are met: 11169689Skan * 1. Redistributions of source code must retain the above copyright 12169689Skan * notice, this list of conditions and the following disclaimer. 13169689Skan * 2. Redistributions in binary form must reproduce the above copyright 14169689Skan * notice, this list of conditions and the following disclaimer in the 15169689Skan * documentation and/or other materials provided with the distribution. 16169689Skan * 3. All advertising materials mentioning features or use of this software 17169689Skan * must display the following acknowledgement: 18169689Skan * This product includes software developed by the University of 19169689Skan * California, Berkeley and its contributors. 20169689Skan * 4. Neither the name of the University nor the names of its contributors 21169689Skan * may be used to endorse or promote products derived from this software 22169689Skan * without specific prior written permission. 23169689Skan * 24169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34169689Skan * SUCH DAMAGE. 35169689Skan */ 36169689Skan 37169689Skan#ifndef lint 38169689Skan#if 0 39169689Skanstatic char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; 40169689Skan#endif 41169689Skanstatic const char rcsid[] = 42169689Skan "$FreeBSD: head/usr.bin/finger/util.c 72109 2001-02-06 20:13:48Z charnier $"; 43169689Skan#endif /* not lint */ 44169689Skan 45169689Skan#include <sys/param.h> 46169689Skan#include <sys/stat.h> 47169689Skan#include <ctype.h> 48169689Skan#include <db.h> 49169689Skan#include <err.h> 50169689Skan#include <errno.h> 51169689Skan#include <fcntl.h> 52169689Skan#include <paths.h> 53169689Skan#include <pwd.h> 54169689Skan#include <stdio.h> 55169689Skan#include <stdlib.h> 56169689Skan#include <string.h> 57169689Skan#include <unistd.h> 58169689Skan#include <utmp.h> 59169689Skan#include "finger.h" 60169689Skan 61169689Skanstatic void find_idle_and_ttywrite __P((WHERE *)); 62169689Skanstatic void userinfo __P((PERSON *, struct passwd *)); 63169689Skanstatic WHERE *walloc __P((PERSON *)); 64169689Skan 65169689Skanint 66169689Skanmatch(pw, user) 67169689Skan struct passwd *pw; 68169689Skan char *user; 69169689Skan{ 70169689Skan register char *p, *t; 71169689Skan char name[1024]; 72169689Skan 73169689Skan if (!strcasecmp(pw->pw_name, user)) 74169689Skan return(1); 75169689Skan 76169689Skan /* 77169689Skan * XXX 78169689Skan * Why do we skip asterisks!?!? 79169689Skan */ 80169689Skan (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf)); 81169689Skan tbuf[sizeof(tbuf) - 1] = '\0'; 82169689Skan if (*p == '*') 83169689Skan ++p; 84169689Skan 85169689Skan /* Ampersands get replaced by the login name. */ 86169689Skan if ((p = strtok(p, ",")) == NULL) 87169689Skan return(0); 88169689Skan 89169689Skan for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 90169689Skan if (*t == '&') { 91169689Skan (void)strncpy(t, pw->pw_name, 92169689Skan sizeof(name) - (t - name)); 93169689Skan name[sizeof(name) - 1] = '\0'; 94169689Skan while (t < &name[sizeof(name) - 1] && *++t) 95169689Skan continue; 96169689Skan } else { 97169689Skan ++t; 98169689Skan } 99169689Skan } 100169689Skan *t = '\0'; 101169689Skan for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL) 102169689Skan if (!strcasecmp(p, user)) 103169689Skan return(1); 104169689Skan return(0); 105169689Skan} 106169689Skan 107169689Skanvoid 108169689Skanenter_lastlog(pn) 109169689Skan register PERSON *pn; 110169689Skan{ 111169689Skan register WHERE *w; 112169689Skan static int opened, fd; 113169689Skan struct lastlog ll; 114169689Skan char doit = 0; 115169689Skan 116169689Skan /* some systems may not maintain lastlog, don't report errors. */ 117169689Skan if (!opened) { 118169689Skan fd = open(_PATH_LASTLOG, O_RDONLY, 0); 119169689Skan opened = 1; 120169689Skan } 121169689Skan if (fd == -1 || 122169689Skan lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) != 123169689Skan (long)pn->uid * sizeof(ll) || 124169689Skan read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 125169689Skan /* as if never logged in */ 126169689Skan ll.ll_line[0] = ll.ll_host[0] = '\0'; 127169689Skan ll.ll_time = 0; 128169689Skan } 129169689Skan if ((w = pn->whead) == NULL) 130169689Skan doit = 1; 131169689Skan else if (ll.ll_time != 0) { 132169689Skan /* if last login is earlier than some current login */ 133169689Skan for (; !doit && w != NULL; w = w->next) 134169689Skan if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 135169689Skan doit = 1; 136169689Skan /* 137169689Skan * and if it's not any of the current logins 138169689Skan * can't use time comparison because there may be a small 139169689Skan * discrepancy since login calls time() twice 140169689Skan */ 141169689Skan for (w = pn->whead; doit && w != NULL; w = w->next) 142169689Skan if (w->info == LOGGEDIN && 143169689Skan strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 144169689Skan doit = 0; 145169689Skan } 146169689Skan if (doit) { 147169689Skan w = walloc(pn); 148169689Skan w->info = LASTLOG; 149169689Skan bcopy(ll.ll_line, w->tty, UT_LINESIZE); 150169689Skan w->tty[UT_LINESIZE] = 0; 151169689Skan bcopy(ll.ll_host, w->host, UT_HOSTSIZE); 152169689Skan w->host[UT_HOSTSIZE] = 0; 153169689Skan w->loginat = ll.ll_time; 154169689Skan } 155169689Skan} 156169689Skan 157169689Skanvoid 158169689Skanenter_where(ut, pn) 159169689Skan struct utmp *ut; 160169689Skan PERSON *pn; 161169689Skan{ 162169689Skan register WHERE *w; 163169689Skan 164169689Skan w = walloc(pn); 165169689Skan w->info = LOGGEDIN; 166169689Skan bcopy(ut->ut_line, w->tty, UT_LINESIZE); 167169689Skan w->tty[UT_LINESIZE] = 0; 168169689Skan bcopy(ut->ut_host, w->host, UT_HOSTSIZE); 169169689Skan w->host[UT_HOSTSIZE] = 0; 170169689Skan w->loginat = (time_t)ut->ut_time; 171169689Skan find_idle_and_ttywrite(w); 172169689Skan} 173169689Skan 174169689SkanPERSON * 175169689Skanenter_person(pw) 176169689Skan register struct passwd *pw; 177169689Skan{ 178169689Skan DBT data, key; 179169689Skan PERSON *pn; 180169689Skan 181169689Skan if (db == NULL && 182169689Skan (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 183169689Skan err(1, NULL); 184169689Skan 185169689Skan key.data = pw->pw_name; 186169689Skan key.size = strlen(pw->pw_name); 187169689Skan 188169689Skan switch ((*db->get)(db, &key, &data, 0)) { 189169689Skan case 0: 190169689Skan memmove(&pn, data.data, sizeof pn); 191169689Skan return (pn); 192169689Skan default: 193169689Skan case -1: 194169689Skan err(1, "db get"); 195169689Skan /* NOTREACHED */ 196169689Skan case 1: 197169689Skan ++entries; 198169689Skan pn = palloc(); 199169689Skan userinfo(pn, pw); 200169689Skan pn->whead = NULL; 201169689Skan 202169689Skan data.size = sizeof(PERSON *); 203169689Skan data.data = &pn; 204169689Skan if ((*db->put)(db, &key, &data, 0)) 205169689Skan err(1, "db put"); 206169689Skan return (pn); 207169689Skan } 208169689Skan} 209169689Skan 210169689SkanPERSON * 211169689Skanfind_person(name) 212169689Skan char *name; 213169689Skan{ 214169689Skan struct passwd *pw; 215169689Skan 216169689Skan register int cnt; 217169689Skan DBT data, key; 218169689Skan PERSON *p; 219169689Skan char buf[UT_NAMESIZE + 1]; 220169689Skan 221169689Skan if (!db) 222169689Skan return(NULL); 223169689Skan 224169689Skan if ((pw = getpwnam(name)) && hide(pw)) 225169689Skan return(NULL); 226169689Skan 227169689Skan /* Name may be only UT_NAMESIZE long and not NUL terminated. */ 228169689Skan for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt) 229169689Skan buf[cnt] = *name; 230169689Skan buf[cnt] = '\0'; 231169689Skan key.data = buf; 232169689Skan key.size = cnt; 233169689Skan 234169689Skan if ((*db->get)(db, &key, &data, 0)) 235169689Skan return (NULL); 236169689Skan memmove(&p, data.data, sizeof p); 237169689Skan return (p); 238169689Skan} 239169689Skan 240169689SkanPERSON * 241169689Skanpalloc() 242169689Skan{ 243169689Skan PERSON *p; 244169689Skan 245169689Skan if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 246169689Skan err(1, NULL); 247169689Skan return(p); 248169689Skan} 249169689Skan 250169689Skanstatic WHERE * 251169689Skanwalloc(pn) 252169689Skan register PERSON *pn; 253169689Skan{ 254169689Skan register WHERE *w; 255169689Skan 256169689Skan if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 257169689Skan err(1, NULL); 258169689Skan if (pn->whead == NULL) 259169689Skan pn->whead = pn->wtail = w; 260169689Skan else { 261169689Skan pn->wtail->next = w; 262169689Skan pn->wtail = w; 263169689Skan } 264169689Skan w->next = NULL; 265169689Skan return(w); 266169689Skan} 267169689Skan 268169689Skanchar * 269169689Skanprphone(num) 270169689Skan char *num; 271169689Skan{ 272169689Skan register char *p; 273169689Skan int len; 274169689Skan static char pbuf[20]; 275169689Skan 276169689Skan /* don't touch anything if the user has their own formatting */ 277169689Skan for (p = num; *p; ++p) 278169689Skan if (!isdigit(*p)) 279169689Skan return(num); 280169689Skan len = p - num; 281169689Skan p = pbuf; 282169689Skan switch(len) { 283169689Skan case 11: /* +0-123-456-7890 */ 284169689Skan *p++ = '+'; 285169689Skan *p++ = *num++; 286169689Skan *p++ = '-'; 287169689Skan /* FALLTHROUGH */ 288169689Skan case 10: /* 012-345-6789 */ 289169689Skan *p++ = *num++; 290169689Skan *p++ = *num++; 291169689Skan *p++ = *num++; 292169689Skan *p++ = '-'; 293169689Skan /* FALLTHROUGH */ 294169689Skan case 7: /* 012-3456 */ 295169689Skan *p++ = *num++; 296169689Skan *p++ = *num++; 297169689Skan *p++ = *num++; 298169689Skan break; 299169689Skan case 5: /* x0-1234 */ 300169689Skan case 4: /* x1234 */ 301169689Skan *p++ = 'x'; 302169689Skan *p++ = *num++; 303169689Skan break; 304169689Skan default: 305169689Skan return(num); 306169689Skan } 307169689Skan if (len != 4) { 308169689Skan *p++ = '-'; 309169689Skan *p++ = *num++; 310169689Skan } 311169689Skan *p++ = *num++; 312169689Skan *p++ = *num++; 313169689Skan *p++ = *num++; 314169689Skan *p = '\0'; 315169689Skan return(pbuf); 316169689Skan} 317169689Skan 318169689Skanstatic void 319169689Skanfind_idle_and_ttywrite(w) 320169689Skan register WHERE *w; 321169689Skan{ 322169689Skan extern time_t now; 323169689Skan struct stat sb; 324169689Skan time_t touched; 325169689Skan 326169689Skan (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 327169689Skan if (stat(tbuf, &sb) < 0) { 328169689Skan warn("%s", tbuf); 329169689Skan return; 330169689Skan } 331169689Skan touched = sb.st_atime; 332169689Skan if (touched < w->loginat) { 333169689Skan /* tty untouched since before login */ 334169689Skan touched = w->loginat; 335169689Skan } 336169689Skan w->idletime = now < touched ? 0 : now - touched; 337169689Skan 338169689Skan#define TALKABLE 0220 /* tty is writable if 220 mode */ 339169689Skan w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 340169689Skan} 341169689Skan 342169689Skanstatic void 343169689Skanuserinfo(pn, pw) 344169689Skan register PERSON *pn; 345169689Skan register struct passwd *pw; 346169689Skan{ 347169689Skan register char *p, *t; 348169689Skan char *bp, name[1024]; 349169689Skan struct stat sb; 350169689Skan 351169689Skan pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 352169689Skan 353169689Skan pn->uid = pw->pw_uid; 354169689Skan if ((pn->name = strdup(pw->pw_name)) == NULL) 355169689Skan err(1, "strdup failed"); 356169689Skan if ((pn->dir = strdup(pw->pw_dir)) == NULL) 357169689Skan err(1, "strdup failed"); 358169689Skan if ((pn->shell = strdup(pw->pw_shell)) == NULL) 359169689Skan err(1, "strdup failed"); 360169689Skan 361169689Skan /* why do we skip asterisks!?!? */ 362169689Skan (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 363169689Skan tbuf[sizeof(tbuf) - 1] = '\0'; 364169689Skan if (*bp == '*') 365169689Skan ++bp; 366169689Skan 367169689Skan /* ampersands get replaced by the login name */ 368169689Skan if (!(p = strsep(&bp, ","))) 369169689Skan return; 370169689Skan for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) { 371169689Skan if (*t == '&') { 372169689Skan (void)strncpy(t, pw->pw_name, 373169689Skan sizeof(name) - (t - name)); 374169689Skan name[sizeof(name) - 1] = '\0'; 375169689Skan if (islower(*t)) 376169689Skan *t = toupper(*t); 377169689Skan while (t < &name[sizeof(name) - 1] && *++t) 378169689Skan continue; 379169689Skan } else { 380169689Skan ++t; 381169689Skan } 382169689Skan } 383169689Skan *t = '\0'; 384169689Skan if ((pn->realname = strdup(name)) == NULL) 385169689Skan err(1, "strdup failed"); 386169689Skan pn->office = ((p = strsep(&bp, ",")) && *p) ? 387169689Skan strdup(p) : NULL; 388169689Skan pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 389169689Skan strdup(p) : NULL; 390169689Skan pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 391169689Skan strdup(p) : NULL; 392169689Skan (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name); 393169689Skan pn->mailrecv = -1; /* -1 == not_valid */ 394169689Skan if (stat(tbuf, &sb) < 0) { 395169689Skan if (errno != ENOENT) { 396169689Skan warn("%s", tbuf); 397169689Skan return; 398169689Skan } 399169689Skan } else if (sb.st_size != 0) { 400169689Skan pn->mailrecv = sb.st_mtime; 401169689Skan pn->mailread = sb.st_atime; 402169689Skan } 403169689Skan} 404169689Skan 405169689Skan/* 406169689Skan * Is this user hiding from finger? 407169689Skan * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide). 408169689Skan */ 409169689Skan 410169689Skanint 411169689Skanhide(pw) 412169689Skan struct passwd *pw; 413169689Skan{ 414169689Skan char buf[MAXPATHLEN+1]; 415169689Skan 416169689Skan if (!pw->pw_dir) 417169689Skan return 0; 418169689Skan 419169689Skan snprintf(buf, sizeof(buf), "%s/.nofinger", pw->pw_dir); 420169689Skan buf[sizeof(buf) - 1] = '\0'; 421169689Skan 422169689Skan if (access(buf, F_OK) == 0) 423169689Skan return 1; 424169689Skan 425169689Skan return 0; 426169689Skan} 427169689Skan