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