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