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