1 /* $NetBSD: util.c,v 1.23 2004/11/12 21:48:58 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman 37 * 38 * This code is derived from software contributed to Berkeley by 39 * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Berkeley and its contributors. 53 * 4. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 */ 69 70 #include <sys/cdefs.h> 71 #ifndef lint 72 #if 0 73 static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; 74 #else 75 __RCSID("$NetBSD: util.c,v 1.23 2004/11/12 21:48:58 christos Exp $"); 76 #endif 77 #endif /* not lint */ 78 79 #include <sys/param.h> 80 #include <sys/stat.h> 81 82 #include <db.h> 83 #include <ctype.h> 84 #include <err.h> 85 #include <errno.h> 86 #include <fcntl.h> 87 #include <paths.h> 88 #include <pwd.h> 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <string.h> 92 #include <unistd.h> 93 #include <utmp.h> 94 95 #include "utmpentry.h" 96 97 #include "finger.h" 98 #include "extern.h" 99 100 static void find_idle_and_ttywrite __P((WHERE *)); 101 static void userinfo __P((PERSON *, struct passwd *)); 102 static WHERE *walloc __P((PERSON *)); 103 104 int 105 match(pw, user) 106 struct passwd *pw; 107 char *user; 108 { 109 char *p; 110 char *bp, name[1024]; 111 112 if (!strcasecmp(pw->pw_name, user)) 113 return(1); 114 115 (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 116 117 /* Ampersands get replaced by the login name. */ 118 if (!(p = strsep(&bp, ","))) 119 return(0); 120 121 expandusername(p, pw->pw_name, name, sizeof(name)); 122 bp = name; 123 while ((p = strsep(&bp, "\t "))) 124 if (!strcasecmp(p, user)) 125 return(1); 126 return(0); 127 } 128 129 /* inspired by usr.sbin/sendmail/util.c::buildfname */ 130 void 131 expandusername(gecos, login, buf, buflen) 132 const char *gecos; 133 const char *login; 134 char *buf; 135 int buflen; 136 { 137 const char *p; 138 char *bp; 139 140 /* why do we skip asterisks!?!? */ 141 if (*gecos == '*') 142 gecos++; 143 bp = buf; 144 145 /* copy gecos, interpolating & to be full name */ 146 for (p = gecos; *p != '\0'; p++) { 147 if (bp >= &buf[buflen - 1]) { 148 /* buffer overflow - just use login name */ 149 snprintf(buf, buflen, "%s", login); 150 buf[buflen - 1] = '\0'; 151 return; 152 } 153 if (*p == '&') { 154 /* interpolate full name */ 155 snprintf(bp, buflen - (bp - buf), "%s", login); 156 *bp = toupper((unsigned char)*bp); 157 bp += strlen(bp); 158 } 159 else 160 *bp++ = *p; 161 } 162 *bp = '\0'; 163 } 164 165 void 166 enter_lastlog(pn) 167 PERSON *pn; 168 { 169 WHERE *w; 170 static int opened, fd; 171 struct lastlog ll; 172 char doit = 0; 173 174 /* some systems may not maintain lastlog, don't report errors. */ 175 if (!opened) { 176 fd = open(_PATH_LASTLOG, O_RDONLY, 0); 177 opened = 1; 178 } 179 if (fd == -1 || 180 lseek(fd, (off_t)pn->uid * sizeof(ll), SEEK_SET) != 181 (long)pn->uid * sizeof(ll) || 182 read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { 183 /* as if never logged in */ 184 ll.ll_line[0] = ll.ll_host[0] = '\0'; 185 ll.ll_time = 0; 186 } 187 if ((w = pn->whead) == NULL) 188 doit = 1; 189 else if (ll.ll_time != 0) { 190 /* if last login is earlier than some current login */ 191 for (; !doit && w != NULL; w = w->next) 192 if (w->info == LOGGEDIN && w->loginat < ll.ll_time) 193 doit = 1; 194 /* 195 * and if it's not any of the current logins 196 * can't use time comparison because there may be a small 197 * discrepency since login calls time() twice 198 */ 199 for (w = pn->whead; doit && w != NULL; w = w->next) 200 if (w->info == LOGGEDIN && 201 strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) 202 doit = 0; 203 } 204 if (doit) { 205 w = walloc(pn); 206 w->info = LASTLOG; 207 memcpy(w->tty = malloc(UT_LINESIZE + 1), 208 ll.ll_line, UT_LINESIZE); 209 w->tty[UT_LINESIZE + 1] = '\0'; 210 memcpy(w->host = malloc(UT_HOSTSIZE + 1), 211 ll.ll_host, UT_HOSTSIZE); 212 w->host[UT_HOSTSIZE + 1] = '\0'; 213 w->loginat = ll.ll_time; 214 } 215 } 216 217 void 218 enter_where(ep, pn) 219 struct utmpentry *ep; 220 PERSON *pn; 221 { 222 WHERE *w = walloc(pn); 223 224 w->info = LOGGEDIN; 225 w->tty = ep->line; 226 w->host = ep->host; 227 w->loginat = (time_t)ep->tv.tv_sec; 228 find_idle_and_ttywrite(w); 229 } 230 231 PERSON * 232 enter_person(pw) 233 struct passwd *pw; 234 { 235 DBT data, key; 236 PERSON *pn; 237 238 if (db == NULL && 239 (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) 240 err(1, NULL); 241 242 key.data = (char *)pw->pw_name; 243 key.size = strlen(pw->pw_name); 244 245 switch ((*db->get)(db, &key, &data, 0)) { 246 case 0: 247 memmove(&pn, data.data, sizeof pn); 248 return (pn); 249 default: 250 case -1: 251 err(1, "db get"); 252 /* NOTREACHED */ 253 case 1: 254 ++entries; 255 pn = palloc(); 256 userinfo(pn, pw); 257 pn->whead = NULL; 258 259 data.size = sizeof(PERSON *); 260 data.data = &pn; 261 if ((*db->put)(db, &key, &data, 0)) 262 err(1, "db put"); 263 return (pn); 264 } 265 } 266 267 PERSON * 268 find_person(name) 269 char *name; 270 { 271 DBT data, key; 272 PERSON *p; 273 274 if (!db) 275 return(NULL); 276 277 key.data = name; 278 key.size = strlen(name); 279 280 if ((*db->get)(db, &key, &data, 0)) 281 return (NULL); 282 memmove(&p, data.data, sizeof p); 283 return (p); 284 } 285 286 PERSON * 287 palloc() 288 { 289 PERSON *p; 290 291 if ((p = malloc((u_int) sizeof(PERSON))) == NULL) 292 err(1, NULL); 293 return(p); 294 } 295 296 static WHERE * 297 walloc(pn) 298 PERSON *pn; 299 { 300 WHERE *w; 301 302 if ((w = malloc((u_int) sizeof(WHERE))) == NULL) 303 err(1, NULL); 304 if (pn->whead == NULL) 305 pn->whead = pn->wtail = w; 306 else { 307 pn->wtail->next = w; 308 pn->wtail = w; 309 } 310 w->next = NULL; 311 return(w); 312 } 313 314 char * 315 prphone(num) 316 char *num; 317 { 318 char *p; 319 int len; 320 static char pbuf[15]; 321 322 /* don't touch anything if the user has their own formatting */ 323 for (p = num; *p; ++p) 324 if (!isdigit((unsigned char)*p)) 325 return(num); 326 len = p - num; 327 p = pbuf; 328 switch(len) { 329 case 11: /* +0-123-456-7890 */ 330 *p++ = '+'; 331 *p++ = *num++; 332 *p++ = '-'; 333 /* FALLTHROUGH */ 334 case 10: /* 012-345-6789 */ 335 *p++ = *num++; 336 *p++ = *num++; 337 *p++ = *num++; 338 *p++ = '-'; 339 /* FALLTHROUGH */ 340 case 7: /* 012-3456 */ 341 *p++ = *num++; 342 *p++ = *num++; 343 *p++ = *num++; 344 break; 345 case 5: /* x0-1234 */ 346 case 4: /* x1234 */ 347 *p++ = 'x'; 348 *p++ = *num++; 349 break; 350 default: 351 return(num); 352 } 353 if (len != 4) { 354 *p++ = '-'; 355 *p++ = *num++; 356 } 357 *p++ = *num++; 358 *p++ = *num++; 359 *p++ = *num++; 360 *p = '\0'; 361 return(pbuf); 362 } 363 364 static void 365 find_idle_and_ttywrite(w) 366 WHERE *w; 367 { 368 struct stat sb; 369 370 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); 371 if (stat(tbuf, &sb) < 0) { 372 warn("%s", tbuf); 373 return; 374 } 375 w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; 376 377 #define TALKABLE 0220 /* tty is writable if 220 mode */ 378 w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); 379 } 380 381 static void 382 userinfo(pn, pw) 383 PERSON *pn; 384 struct passwd *pw; 385 { 386 char *p; 387 char *bp, name[1024]; 388 struct stat sb; 389 390 pn->realname = pn->office = pn->officephone = pn->homephone = NULL; 391 392 pn->uid = pw->pw_uid; 393 pn->name = strdup(pw->pw_name); 394 pn->dir = strdup(pw->pw_dir); 395 pn->shell = strdup(pw->pw_shell); 396 397 (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); 398 399 /* ampersands get replaced by the login name */ 400 if (!(p = strsep(&bp, ","))) 401 return; 402 expandusername(p, pw->pw_name, name, sizeof(name)); 403 pn->realname = strdup(name); 404 pn->office = ((p = strsep(&bp, ",")) && *p) ? 405 strdup(p) : NULL; 406 pn->officephone = ((p = strsep(&bp, ",")) && *p) ? 407 strdup(p) : NULL; 408 pn->homephone = ((p = strsep(&bp, ",")) && *p) ? 409 strdup(p) : NULL; 410 (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILSPOOL, 411 pw->pw_name); 412 pn->mailrecv = -1; /* -1 == not_valid */ 413 if (stat(tbuf, &sb) < 0) { 414 if (errno != ENOENT) { 415 (void)fprintf(stderr, 416 "finger: %s: %s\n", tbuf, strerror(errno)); 417 return; 418 } 419 } else if (sb.st_size != 0) { 420 pn->mailrecv = sb.st_mtime; 421 pn->mailread = sb.st_atime; 422 } 423 } 424