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