1 /*- 2 * Copyright (c) 2002 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Christos Zoulas. 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "namespace.h" 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/socket.h> 34 #include <sys/stat.h> 35 #include <sys/time.h> 36 #include <sys/wait.h> 37 38 #include <assert.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <pwd.h> 46 #include <utmpx.h> 47 #include <vis.h> 48 #include "un-namespace.h" 49 50 #include <db.h> 51 52 static FILE *fp; 53 static int readonly = 0; 54 static struct utmpx ut; 55 static char utfile[MAXPATHLEN] = _PATH_UTMPX; 56 57 static struct utmpx *utmp_update(const struct utmpx *); 58 59 static const char vers[] = "utmpx-2.00"; 60 static utx_db_t dbtype = UTX_DB_UTMPX; 61 DB *lastlogx_db = NULL; 62 63 void past_getutmp(void *, void *); 64 void past_getutmpx(void *, void *); 65 66 static int 67 _open_db(const char *fname) 68 { 69 struct stat st; 70 71 if ((fp = fopen(fname, "re+")) == NULL) 72 if ((fp = fopen(fname, "we+")) == NULL) { 73 if ((fp = fopen(fname, "re")) == NULL) 74 goto fail; 75 else 76 readonly = 1; 77 } 78 79 /* get file size in order to check if new file */ 80 if (_fstat(fileno(fp), &st) == -1) 81 goto failclose; 82 83 if (st.st_size == 0) { 84 /* new file, add signature record */ 85 (void)memset(&ut, 0, sizeof(ut)); 86 ut.ut_type = SIGNATURE; 87 (void)memcpy(ut.ut_user, vers, sizeof(vers)); 88 if (fwrite(&ut, sizeof(ut), 1, fp) != 1) 89 goto failclose; 90 } else { 91 /* old file, read signature record */ 92 if (fread(&ut, sizeof(ut), 1, fp) != 1) 93 goto failclose; 94 if (memcmp(ut.ut_user, vers, 5) != 0 || 95 ut.ut_type != SIGNATURE) { 96 errno = EINVAL; 97 goto failclose; 98 } 99 } 100 101 return 0; 102 failclose: 103 (void)fclose(fp); 104 fail: 105 (void)memset(&ut, 0, sizeof(ut)); 106 return -1; 107 } 108 109 int 110 setutxdb(utx_db_t db_type, const char *fname) 111 { 112 switch (db_type) { 113 case UTX_DB_UTMPX: 114 if (fname == NULL) 115 fname = _PATH_UTMPX; 116 break; 117 118 case UTX_DB_WTMPX: 119 if (fname == NULL) 120 fname = _PATH_WTMPX; 121 break; 122 123 default: 124 errno = EINVAL; 125 return -1; 126 } 127 128 /* A previous db file is still open */ 129 if (fp != NULL) { 130 fclose(fp); 131 fp = NULL; 132 } 133 if ((_open_db(fname)) == -1) 134 return -1; 135 136 dbtype = db_type; 137 return 0; 138 } 139 140 void 141 setutxent(void) 142 { 143 (void)memset(&ut, 0, sizeof(ut)); 144 if (fp == NULL) 145 return; 146 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET); 147 } 148 149 void 150 endutxent(void) 151 { 152 (void)memset(&ut, 0, sizeof(ut)); 153 154 if (fp != NULL) { 155 (void)fclose(fp); 156 fp = NULL; 157 readonly = 0; 158 } 159 } 160 161 struct utmpx * 162 getutxent(void) 163 { 164 if (fp == NULL) { 165 if ((_open_db(utfile)) == -1) 166 goto fail; 167 } 168 169 if (fread(&ut, sizeof(ut), 1, fp) != 1) 170 goto fail; 171 172 return &ut; 173 fail: 174 (void)memset(&ut, 0, sizeof(ut)); 175 return NULL; 176 } 177 178 struct utmpx * 179 getutxid(const struct utmpx *utx) 180 { 181 182 _DIAGASSERT(utx != NULL); 183 184 if (utx->ut_type == EMPTY) 185 return NULL; 186 187 do { 188 if (ut.ut_type == EMPTY) 189 continue; 190 switch (utx->ut_type) { 191 case EMPTY: 192 return NULL; 193 case RUN_LVL: 194 case BOOT_TIME: 195 case OLD_TIME: 196 case NEW_TIME: 197 if (ut.ut_type == utx->ut_type) 198 return &ut; 199 break; 200 case INIT_PROCESS: 201 case LOGIN_PROCESS: 202 case USER_PROCESS: 203 case DEAD_PROCESS: 204 switch (ut.ut_type) { 205 case INIT_PROCESS: 206 case LOGIN_PROCESS: 207 case USER_PROCESS: 208 case DEAD_PROCESS: 209 if (memcmp(ut.ut_id, utx->ut_id, 210 sizeof(ut.ut_id)) == 0) 211 return &ut; 212 break; 213 default: 214 break; 215 } 216 break; 217 default: 218 return NULL; 219 } 220 } while (getutxent() != NULL); 221 return NULL; 222 } 223 224 struct utmpx * 225 getutxline(const struct utmpx *utx) 226 { 227 228 _DIAGASSERT(utx != NULL); 229 230 do { 231 switch (ut.ut_type) { 232 case EMPTY: 233 break; 234 case LOGIN_PROCESS: 235 case USER_PROCESS: 236 if (strncmp(ut.ut_line, utx->ut_line, 237 sizeof(ut.ut_line)) == 0) 238 return &ut; 239 break; 240 default: 241 break; 242 } 243 } while (getutxent() != NULL); 244 return NULL; 245 } 246 247 struct utmpx * 248 getutxuser(const char *user) 249 { 250 _DIAGASSERT(utx != NULL); 251 252 do { 253 switch (ut.ut_type) { 254 case EMPTY: 255 break; 256 case USER_PROCESS: 257 if (strncmp(ut.ut_user, user, sizeof(ut.ut_user)) == 0) 258 return &ut; 259 break; 260 default: 261 break; 262 } 263 } while (getutxent() != NULL); 264 return NULL; 265 } 266 267 struct utmpx * 268 pututxline(const struct utmpx *utx) 269 { 270 struct passwd *pw; 271 struct lastlogx ll; 272 struct utmpx temp, *u = NULL; 273 int gotlock = 0; 274 275 _DIAGASSERT(utx != NULL); 276 277 if (utx == NULL) 278 return NULL; 279 280 if (utx->ut_type == USER_PROCESS) { 281 ll.ll_tv = utx->ut_tv; 282 strcpy(ll.ll_host, utx->ut_host); 283 strcpy(ll.ll_line, utx->ut_line); 284 pw = getpwnam(utx->ut_name); 285 if (pw != NULL) 286 updlastlogx(_PATH_LASTLOGX, pw->pw_uid, &ll); 287 } 288 289 if (strcmp(_PATH_UTMPX, utfile) == 0) 290 if ((fp != NULL && readonly) || (fp == NULL && geteuid() != 0)) 291 return utmp_update(utx); 292 293 294 (void)memcpy(&temp, utx, sizeof(temp)); 295 296 if (fp == NULL) { 297 (void)getutxent(); 298 if (fp == NULL || readonly) 299 return NULL; 300 } 301 302 if (getutxid(&temp) == NULL) { 303 setutxent(); 304 if (getutxid(&temp) == NULL) { 305 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1) 306 return NULL; 307 gotlock++; 308 if (fseeko(fp, (off_t)0, SEEK_END) == -1) 309 goto fail; 310 } 311 } 312 313 if (!gotlock) { 314 /* we are not appending */ 315 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1) 316 return NULL; 317 } 318 319 if (fwrite(&temp, sizeof (temp), 1, fp) != 1) 320 goto fail; 321 322 if (fflush(fp) == -1) 323 goto fail; 324 325 u = memcpy(&ut, &temp, sizeof(ut)); 326 fail: 327 if (gotlock) { 328 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1) 329 return NULL; 330 } 331 return u; 332 } 333 334 static struct utmpx * 335 utmp_update(const struct utmpx *utx) 336 { 337 char buf[sizeof(*utx) * 4 + 1]; 338 pid_t pid; 339 int status; 340 341 _DIAGASSERT(utx != NULL); 342 343 (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx), 344 VIS_WHITE | VIS_NOLOCALE); 345 switch (pid = fork()) { 346 case 0: 347 (void)execl(_PATH_UTMP_UPDATE, 348 strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf, NULL); 349 _exit(1); 350 /*NOTREACHED*/ 351 case -1: 352 return NULL; 353 default: 354 if (_waitpid(pid, &status, 0) == -1) 355 return NULL; 356 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 357 return memcpy(&ut, utx, sizeof(ut)); 358 return NULL; 359 } 360 361 } 362 363 /* 364 * The following are extensions and not part of the X/Open spec. 365 */ 366 void 367 updwtmpx(const char *file, const struct utmpx *utx) 368 { 369 (void)_updwtmpx(file, utx); 370 } 371 372 int 373 _updwtmpx(const char *file, const struct utmpx *utx) 374 { 375 int fd; 376 int saved_errno; 377 struct stat st; 378 379 _DIAGASSERT(file != NULL); 380 _DIAGASSERT(utx != NULL); 381 382 fd = _open(file, O_WRONLY|O_APPEND|O_SHLOCK|O_CLOEXEC); 383 384 if (fd == -1) { 385 if ((fd = _open(file, O_CREAT|O_WRONLY|O_EXLOCK|O_CLOEXEC, 0644)) == -1) 386 goto fail; 387 } 388 if (_fstat(fd, &st) == -1) 389 goto failclose; 390 if (st.st_size == 0) { 391 /* new file, add signature record */ 392 (void)memset(&ut, 0, sizeof(ut)); 393 ut.ut_type = SIGNATURE; 394 (void)memcpy(ut.ut_user, vers, sizeof(vers)); 395 if (_write(fd, &ut, sizeof(ut)) == -1) 396 goto failclose; 397 } 398 if (_write(fd, utx, sizeof(*utx)) == -1) 399 goto failclose; 400 if (_close(fd) == -1) 401 return -1; 402 return 0; 403 404 failclose: 405 saved_errno = errno; 406 (void) _close(fd); 407 errno = saved_errno; 408 fail: 409 return -1; 410 } 411 412 int 413 utmpxname(const char *fname) 414 { 415 size_t len; 416 417 _DIAGASSERT(fname != NULL); 418 419 len = strlen(fname); 420 421 if (len >= sizeof(utfile)) 422 return 0; 423 424 /* must end in x! */ 425 if (fname[len - 1] != 'x') 426 return 0; 427 428 (void)strlcpy(utfile, fname, sizeof(utfile)); 429 endutxent(); 430 return 1; 431 } 432 433 434 __sym_compat(getutmp, past_getutmp, DF404.0); 435 void 436 past_getutmp(void *ux __unused, void *u __unused) 437 { 438 } 439 440 __sym_compat(getutmpx, past_getutmpx, DF404.0); 441 void 442 past_getutmpx(void *u __unused, void *ux __unused) 443 { 444 } 445 446 struct lastlogx * 447 getlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) 448 { 449 DBT key, data; 450 DB *db; 451 452 _DIAGASSERT(fname != NULL); 453 _DIAGASSERT(ll != NULL); 454 455 db = dbopen(fname, O_RDONLY|O_SHLOCK|O_CLOEXEC, 0, DB_HASH, NULL); 456 457 if (db == NULL) 458 return NULL; 459 460 key.data = &uid; 461 key.size = sizeof(uid); 462 463 if ((db->get)(db, &key, &data, 0) != 0) 464 goto error; 465 466 if (data.size != sizeof(*ll)) { 467 errno = EFTYPE; 468 goto error; 469 } 470 471 if (ll == NULL) 472 if ((ll = malloc(sizeof(*ll))) == NULL) 473 goto done; 474 475 (void)memcpy(ll, data.data, sizeof(*ll)); 476 goto done; 477 error: 478 ll = NULL; 479 done: 480 (db->close)(db); 481 return ll; 482 } 483 484 int 485 updlastlogx(const char *fname, uid_t uid, struct lastlogx *ll) 486 { 487 DBT key, data; 488 int error = 0; 489 DB *db; 490 491 _DIAGASSERT(fname != NULL); 492 _DIAGASSERT(ll != NULL); 493 494 db = dbopen(fname, O_RDWR|O_CREAT|O_EXLOCK|O_CLOEXEC, 0644, DB_HASH, NULL); 495 496 if (db == NULL) 497 return -1; 498 499 key.data = &uid; 500 key.size = sizeof(uid); 501 data.data = ll; 502 data.size = sizeof(*ll); 503 if ((db->put)(db, &key, &data, 0) != 0) 504 error = -1; 505 506 (db->close)(db); 507 return error; 508 } 509