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