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