1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Routines to read and write the /etc/utmpx file. Also contains 44 * binary compatibility routines to support the old utmp interfaces 45 * on systems with MAXPID <= SHRT_MAX. 46 */ 47 48 #include "lint.h" 49 #include <sys/types.h> 50 #include <stdio.h> 51 #include <sys/param.h> 52 #include <sys/stat.h> 53 #include <utmpx.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <string.h> 57 #include <strings.h> 58 #include <unistd.h> 59 #include <ctype.h> 60 #include <stdlib.h> 61 #include <sys/wait.h> 62 #include <pthread.h> 63 #include <limits.h> 64 #include <signal.h> 65 #include <spawn.h> 66 67 #define IDLEN 4 /* length of id field in utmp */ 68 #define SC_WILDC 0xff /* wild char for utmp ids */ 69 #define MAXFILE 79 /* Maximum pathname length for "utmpx" file */ 70 71 #define MAXVAL 255 /* max value for an id `character' */ 72 #define IPIPE "/var/run/initpipe" /* FIFO to send pids to init */ 73 #define UPIPE "/var/run/utmppipe" /* FIFO to send pids to utmpd */ 74 75 #define VAR_UTMPX_FILE "/var/adm/utmpx" /* for sanity check only */ 76 77 78 /* 79 * format of message sent to init 80 */ 81 82 typedef struct pidrec { 83 int pd_type; /* command type */ 84 pid_t pd_pid; /* pid */ 85 } pidrec_t; 86 87 /* 88 * pd_type's 89 */ 90 #define ADDPID 1 /* add a pid to "godchild" list */ 91 #define REMPID 2 /* remove a pid to "godchild" list */ 92 93 static void utmpx_frec2api(const struct futmpx *, struct utmpx *); 94 static void utmpx_api2frec(const struct utmpx *, struct futmpx *); 95 96 static void unlockutx(void); 97 static void sendpid(int, pid_t); 98 static void sendupid(int, pid_t); 99 static int idcmp(const char *, const char *); 100 static int allocid(char *, unsigned char *); 101 static int lockutx(void); 102 103 static struct utmpx *invoke_utmp_update(const struct utmpx *); 104 static struct futmpx *getoneutx(off_t *); 105 static void putoneutx(const struct utmpx *, off_t); 106 static int big_pids_in_use(void); 107 108 /* 109 * prototypes for utmp compatibility routines (in getut.c) 110 */ 111 extern struct utmp *_compat_getutent(void); 112 extern struct utmp *_compat_getutid(const struct utmp *); 113 extern struct utmp *_compat_getutline(const struct utmp *); 114 extern struct utmp *_compat_pututline(const struct utmp *); 115 extern void _compat_setutent(void); 116 extern void _compat_endutent(void); 117 extern void _compat_updwtmp(const char *, struct utmp *); 118 extern struct utmp *_compat_makeut(struct utmp *); 119 120 static int fd = -1; /* File descriptor for the utmpx file. */ 121 static int ut_got_maxpid = 0; /* Flag set when sysconf(_SC_MAXPID) called */ 122 static pid_t ut_maxpid = 0; /* Value of MAXPID from sysconf */ 123 static int tempfd = -1; /* To store fd between lockutx() and unlockutx() */ 124 125 static FILE *fp = NULL; /* Buffered file descriptior for utmpx file */ 126 static int changed_name = 0; /* Flag set when not using utmpx file */ 127 static char utmpxfile[MAXFILE+1] = UTMPX_FILE; /* Name of the current */ 128 char _compat_utmpfile[MAXFILE+1]; 129 static int compat_utmpflag = 0; /* old compat mode flag */ 130 131 static struct futmpx fubuf; /* Copy of last entry read in. */ 132 static struct utmpx ubuf; /* Last entry returned to client */ 133 134 static struct utmp utmpcompat; /* Buffer for returning utmp-format data */ 135 /* 136 * In the 64-bit world, the utmpx data structure grows because of 137 * the ut_time field (a struct timeval) grows in the middle of it. 138 */ 139 static void 140 utmpx_frec2api(const struct futmpx *src, struct utmpx *dst) 141 { 142 if (src == NULL) 143 return; 144 145 (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user)); 146 (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line)); 147 (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id)); 148 dst->ut_pid = src->ut_pid; 149 dst->ut_type = src->ut_type; 150 dst->ut_exit.e_termination = src->ut_exit.e_termination; 151 dst->ut_exit.e_exit = src->ut_exit.e_exit; 152 dst->ut_tv.tv_sec = (time_t)src->ut_tv.tv_sec; 153 dst->ut_tv.tv_usec = (suseconds_t)src->ut_tv.tv_usec; 154 dst->ut_session = src->ut_session; 155 bzero(dst->pad, sizeof (dst->pad)); 156 dst->ut_syslen = src->ut_syslen; 157 (void) memcpy(dst->ut_host, src->ut_host, sizeof (dst->ut_host)); 158 } 159 160 static void 161 utmpx_api2frec(const struct utmpx *src, struct futmpx *dst) 162 { 163 if (src == NULL) 164 return; 165 166 (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user)); 167 (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line)); 168 (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id)); 169 dst->ut_pid = src->ut_pid; 170 dst->ut_type = src->ut_type; 171 dst->ut_exit.e_termination = src->ut_exit.e_termination; 172 dst->ut_exit.e_exit = src->ut_exit.e_exit; 173 dst->ut_tv.tv_sec = (time32_t)src->ut_tv.tv_sec; 174 dst->ut_tv.tv_usec = (int32_t)src->ut_tv.tv_usec; 175 dst->ut_session = src->ut_session; 176 bzero(dst->pad, sizeof (dst->pad)); 177 dst->ut_syslen = src->ut_syslen; 178 (void) memcpy(dst->ut_host, src->ut_host, sizeof (dst->ut_host)); 179 } 180 181 /* 182 * "getutxent_frec" gets the raw version of the next entry in the utmpx file. 183 */ 184 static struct futmpx * 185 getutxent_frec(void) 186 { 187 /* 188 * If the "utmpx" file is not open, attempt to open it for 189 * reading. If there is no file, attempt to create one. If 190 * both attempts fail, return NULL. If the file exists, but 191 * isn't readable and writeable, do not attempt to create. 192 */ 193 if (fd < 0) { 194 195 if ((fd = open(utmpxfile, O_RDWR|O_CREAT, 0644)) < 0) { 196 197 /* 198 * If the open failed for permissions, try opening 199 * it only for reading. All "pututxline()" later 200 * will fail the writes. 201 */ 202 203 if ((fd = open(utmpxfile, O_RDONLY)) < 0) 204 return (NULL); 205 206 if ((fp = fopen(utmpxfile, "rF")) == NULL) { 207 (void) close(fd); 208 fd = -1; 209 return (NULL); 210 } 211 212 } else { 213 /* 214 * Get the stream pointer 215 */ 216 if ((fp = fopen(utmpxfile, "r+F")) == NULL) { 217 (void) close(fd); 218 fd = -1; 219 return (NULL); 220 } 221 } 222 } 223 224 /* 225 * Try to read in the next entry from the utmpx file. 226 */ 227 if (fread(&fubuf, sizeof (fubuf), 1, fp) != 1) { 228 /* 229 * Make sure fubuf is zeroed. 230 */ 231 bzero(&fubuf, sizeof (fubuf)); 232 return (NULL); 233 } 234 235 return (&fubuf); 236 } 237 238 /* 239 * "big_pids_in_use" determines whether large pid numbers are in use 240 * or not. If MAXPID won't fit in a signed short, the utmp.ut_pid 241 * field will overflow. 242 * 243 * Returns 0 if small pids are in use, 1 otherwise 244 */ 245 static int 246 big_pids_in_use(void) 247 { 248 if (!ut_got_maxpid) { 249 ut_got_maxpid++; 250 ut_maxpid = sysconf(_SC_MAXPID); 251 } 252 return (ut_maxpid > SHRT_MAX ? 1 : 0); 253 } 254 255 /* 256 * "getutxent" gets the next entry in the utmpx file. 257 */ 258 struct utmpx * 259 getutxent(void) 260 { 261 struct futmpx *futxp; 262 263 futxp = getutxent_frec(); 264 utmpx_frec2api(&fubuf, &ubuf); 265 if (futxp == NULL) 266 return (NULL); 267 return (&ubuf); 268 } 269 /* 270 * "getutent" gets the next entry in the utmp file. 271 */ 272 struct utmp * 273 getutent(void) 274 { 275 struct utmpx *utmpx; 276 277 if (compat_utmpflag) 278 return (_compat_getutent()); 279 280 /* fail if we can't represent maxpid properly */ 281 if (big_pids_in_use()) { 282 errno = EOVERFLOW; 283 return (NULL); 284 } 285 286 if ((utmpx = getutxent()) == NULL) 287 return (NULL); 288 289 getutmp(utmpx, &utmpcompat); 290 return (&utmpcompat); 291 } 292 293 /* 294 * "getutxid" finds the specified entry in the utmpx file. If 295 * it can't find it, it returns NULL. 296 */ 297 struct utmpx * 298 getutxid(const struct utmpx *entry) 299 { 300 short type; 301 302 /* 303 * From XPG5: "The getutxid() or getutxline() may cache data. 304 * For this reason, to use getutxline() to search for multiple 305 * occurrences, it is necessary to zero out the static data after 306 * each success, or getutxline() could just return a pointer to 307 * the same utmpx structure over and over again." 308 */ 309 utmpx_api2frec(&ubuf, &fubuf); 310 311 /* 312 * Start looking for entry. Look in our current buffer before 313 * reading in new entries. 314 */ 315 do { 316 /* 317 * If there is no entry in "fubuf", skip to the read. 318 */ 319 if (fubuf.ut_type != EMPTY) { 320 switch (entry->ut_type) { 321 322 /* 323 * Do not look for an entry if the user sent 324 * us an EMPTY entry. 325 */ 326 case EMPTY: 327 return (NULL); 328 329 /* 330 * For RUN_LVL, BOOT_TIME, OLD_TIME, and NEW_TIME 331 * entries, only the types have to match. If they do, 332 * return the address of internal buffer. 333 */ 334 case RUN_LVL: 335 case BOOT_TIME: 336 case DOWN_TIME: 337 case OLD_TIME: 338 case NEW_TIME: 339 if (entry->ut_type == fubuf.ut_type) { 340 utmpx_frec2api(&fubuf, &ubuf); 341 return (&ubuf); 342 } 343 break; 344 345 /* 346 * For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, 347 * and DEAD_PROCESS the type of the entry in "fubuf", 348 * must be one of the above and id's must match. 349 */ 350 case INIT_PROCESS: 351 case LOGIN_PROCESS: 352 case USER_PROCESS: 353 case DEAD_PROCESS: 354 if (((type = fubuf.ut_type) == INIT_PROCESS || 355 type == LOGIN_PROCESS || 356 type == USER_PROCESS || 357 type == DEAD_PROCESS) && 358 (fubuf.ut_id[0] == entry->ut_id[0]) && 359 (fubuf.ut_id[1] == entry->ut_id[1]) && 360 (fubuf.ut_id[2] == entry->ut_id[2]) && 361 (fubuf.ut_id[3] == entry->ut_id[3])) { 362 utmpx_frec2api(&fubuf, &ubuf); 363 return (&ubuf); 364 } 365 break; 366 367 /* 368 * Do not search for illegal types of entry. 369 */ 370 default: 371 return (NULL); 372 } 373 } 374 } while (getutxent_frec() != NULL); 375 376 /* 377 * Return NULL since the proper entry wasn't found. 378 */ 379 utmpx_frec2api(&fubuf, &ubuf); 380 return (NULL); 381 } 382 383 /* 384 * "getutid" finds the specified entry in the utmp file. If 385 * it can't find it, it returns NULL. 386 */ 387 struct utmp * 388 getutid(const struct utmp *entry) 389 { 390 struct utmpx utmpx; 391 struct utmpx *utmpx2; 392 393 if (compat_utmpflag) 394 return (_compat_getutid(entry)); 395 396 /* fail if we can't represent maxpid properly */ 397 if (big_pids_in_use()) { 398 errno = EOVERFLOW; 399 return (NULL); 400 } 401 getutmpx(entry, &utmpx); 402 if ((utmpx2 = getutxid(&utmpx)) == NULL) 403 return (NULL); 404 getutmp(utmpx2, &utmpcompat); 405 return (&utmpcompat); 406 } 407 408 /* 409 * "getutxline" searches the "utmpx" file for a LOGIN_PROCESS or 410 * USER_PROCESS with the same "line" as the specified "entry". 411 */ 412 struct utmpx * 413 getutxline(const struct utmpx *entry) 414 { 415 /* 416 * From XPG5: "The getutxid() or getutxline() may cache data. 417 * For this reason, to use getutxline() to search for multiple 418 * occurrences, it is necessary to zero out the static data after 419 * each success, or getutxline() could just return a pointer to 420 * the same utmpx structure over and over again." 421 */ 422 utmpx_api2frec(&ubuf, &fubuf); 423 424 do { 425 /* 426 * If the current entry is the one we are interested in, 427 * return a pointer to it. 428 */ 429 if (fubuf.ut_type != EMPTY && 430 (fubuf.ut_type == LOGIN_PROCESS || 431 fubuf.ut_type == USER_PROCESS) && 432 strncmp(&entry->ut_line[0], &fubuf.ut_line[0], 433 sizeof (fubuf.ut_line)) == 0) { 434 utmpx_frec2api(&fubuf, &ubuf); 435 return (&ubuf); 436 } 437 } while (getutxent_frec() != NULL); 438 439 /* 440 * Since entry wasn't found, return NULL. 441 */ 442 utmpx_frec2api(&fubuf, &ubuf); 443 return (NULL); 444 } 445 446 /* 447 * "getutline" searches the "utmp" file for a LOGIN_PROCESS or 448 * USER_PROCESS with the same "line" as the specified "entry". 449 */ 450 struct utmp * 451 getutline(const struct utmp *entry) 452 { 453 struct utmpx utmpx; 454 struct utmpx *utmpx2; 455 456 if (compat_utmpflag) 457 return (_compat_getutline(entry)); 458 459 /* fail if we can't represent maxpid properly */ 460 if (big_pids_in_use()) { 461 errno = EOVERFLOW; 462 return (NULL); 463 } 464 /* call getutxline */ 465 getutmpx(entry, &utmpx); 466 if ((utmpx2 = getutxline(&utmpx)) == NULL) 467 return (NULL); 468 getutmp(utmpx2, &utmpcompat); 469 return (&utmpcompat); 470 } 471 472 /* 473 * invoke_utmp_update 474 * 475 * Invokes the utmp_update program which has the privilege to write 476 * to the /etc/utmp file. 477 */ 478 479 #define UTMP_UPDATE "/usr/lib/utmp_update" 480 #define STRSZ 64 /* Size of char buffer for argument strings */ 481 482 static struct utmpx * 483 invoke_utmp_update(const struct utmpx *entryx) 484 { 485 extern char **_environ; 486 487 posix_spawnattr_t attr; 488 int status; 489 int cancel_state; 490 pid_t child; 491 pid_t w; 492 int i; 493 char user[STRSZ], id[STRSZ], line[STRSZ], pid[STRSZ], type[STRSZ], 494 term[STRSZ], exit[STRSZ], time[STRSZ], time_usec[STRSZ], 495 session_id[STRSZ], syslen[32]; 496 char pad[sizeof (entryx->pad) * 2 + 1]; 497 char host[sizeof (entryx->ut_host) + 1]; 498 struct utmpx *curx = NULL; 499 char bin2hex[] = "0123456789ABCDEF"; 500 unsigned char *cp; 501 char *argvec[15]; 502 int error; 503 504 /* 505 * Convert the utmp struct to strings for command line arguments. 506 */ 507 (void) strncpy(user, entryx->ut_user, sizeof (entryx->ut_user)); 508 user[sizeof (entryx->ut_user)] = '\0'; 509 (void) strncpy(id, entryx->ut_id, sizeof (entryx->ut_id)); 510 id[sizeof (entryx->ut_id)] = '\0'; 511 (void) strncpy(line, entryx->ut_line, sizeof (entryx->ut_line)); 512 line[sizeof (entryx->ut_line)] = '\0'; 513 (void) sprintf(pid, "%d", entryx->ut_pid); 514 (void) sprintf(type, "%d", entryx->ut_type); 515 (void) sprintf(term, "%d", entryx->ut_exit.e_termination); 516 (void) sprintf(exit, "%d", entryx->ut_exit.e_exit); 517 (void) sprintf(time, "%ld", entryx->ut_tv.tv_sec); 518 (void) sprintf(time_usec, "%ld", entryx->ut_tv.tv_usec); 519 (void) sprintf(session_id, "%d", entryx->ut_session); 520 521 cp = (unsigned char *)entryx->pad; 522 for (i = 0; i < sizeof (entryx->pad); ++i) { 523 pad[i << 1] = bin2hex[(cp[i] >> 4) & 0xF]; 524 pad[(i << 1) + 1] = bin2hex[cp[i] & 0xF]; 525 } 526 pad[sizeof (pad) - 1] = '\0'; 527 528 (void) sprintf(syslen, "%d", entryx->ut_syslen); 529 (void) strlcpy(host, entryx->ut_host, sizeof (host)); 530 531 argvec[0] = UTMP_UPDATE; 532 argvec[1] = user; 533 argvec[2] = id; 534 argvec[3] = line; 535 argvec[4] = pid; 536 argvec[5] = type; 537 argvec[6] = term; 538 argvec[7] = exit; 539 argvec[8] = time; 540 argvec[9] = time_usec; 541 argvec[10] = session_id; 542 argvec[11] = pad; 543 argvec[12] = syslen; 544 argvec[13] = host; 545 argvec[14] = NULL; 546 547 /* 548 * No SIGCHLD, please, and let no one else reap our child. 549 */ 550 error = posix_spawnattr_init(&attr); 551 if (error) { 552 errno = error; 553 goto out; 554 } 555 error = posix_spawnattr_setflags(&attr, 556 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP); 557 if (error) { 558 (void) posix_spawnattr_destroy(&attr); 559 errno = error; 560 goto out; 561 } 562 error = posix_spawn(&child, UTMP_UPDATE, NULL, &attr, argvec, _environ); 563 (void) posix_spawnattr_destroy(&attr); 564 if (error) { 565 errno = error; 566 goto out; 567 } 568 569 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); 570 do { 571 w = waitpid(child, &status, 0); 572 } while (w == -1 && errno == EINTR); 573 (void) pthread_setcancelstate(cancel_state, NULL); 574 575 /* 576 * We can get ECHILD if the process is ignoring SIGCLD. 577 */ 578 if (!(w == -1 && errno == ECHILD) && 579 (w == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)) { 580 /* 581 * The child encountered an error, 582 */ 583 goto out; 584 } 585 586 /* 587 * Normal termination. Return a pointer to the entry we just made. 588 */ 589 setutxent(); /* Reset file pointer */ 590 591 while ((curx = getutxent()) != NULL) { 592 if (curx->ut_type != EMPTY && 593 (curx->ut_type == LOGIN_PROCESS || 594 curx->ut_type == USER_PROCESS || 595 curx->ut_type == DEAD_PROCESS) && 596 strncmp(&entryx->ut_line[0], &curx->ut_line[0], 597 sizeof (curx->ut_line)) == 0) 598 break; 599 } 600 601 out: 602 return (curx); 603 } 604 605 /* 606 * "pututxline" writes the structure sent into the utmpx file. 607 * If there is already an entry with the same id, then it is 608 * overwritten, otherwise a new entry is made at the end of the 609 * utmpx file. 610 */ 611 612 struct utmpx * 613 pututxline(const struct utmpx *entry) 614 { 615 struct utmpx *answer; 616 int lock = 0; 617 struct utmpx tmpxbuf; 618 struct futmpx ftmpxbuf; 619 620 /* 621 * Copy the user supplied entry into our temporary buffer to 622 * avoid the possibility that the user is actually passing us 623 * the address of "ubuf". 624 */ 625 if (entry == NULL) 626 return (NULL); 627 628 (void) memcpy(&tmpxbuf, entry, sizeof (tmpxbuf)); 629 utmpx_api2frec(entry, &ftmpxbuf); 630 631 if (fd < 0) { 632 (void) getutxent_frec(); 633 if (fd < 0) 634 return ((struct utmpx *)NULL); 635 } 636 637 /* 638 * If we are not the superuser than we can't write to /etc/utmp, 639 * so invoke update_utmp(8) to write the entry for us. 640 */ 641 if (changed_name == 0 && geteuid() != 0) 642 return (invoke_utmp_update(entry)); 643 644 /* 645 * Find the proper entry in the utmpx file. Start at the current 646 * location. If it isn't found from here to the end of the 647 * file, then reset to the beginning of the file and try again. 648 * If it still isn't found, then write a new entry at the end of 649 * the file. (Making sure the location is an integral number of 650 * utmp structures into the file incase the file is scribbled.) 651 */ 652 653 if (getutxid(&tmpxbuf) == NULL) { 654 655 setutxent(); 656 657 /* 658 * Lock the the entire file from here onwards. 659 */ 660 if (getutxid(&tmpxbuf) == NULL) { 661 lock++; 662 if (lockf(fd, F_LOCK, 0) < NULL) 663 return (NULL); 664 (void) fseek(fp, 0, SEEK_END); 665 } else 666 (void) fseek(fp, -(long)sizeof (struct futmpx), 667 SEEK_CUR); 668 } else 669 (void) fseek(fp, -(long)sizeof (struct futmpx), SEEK_CUR); 670 671 /* 672 * Write out the user supplied structure. If the write fails, 673 * then the user probably doesn't have permission to write the 674 * utmpx file. 675 */ 676 if (fwrite(&ftmpxbuf, sizeof (ftmpxbuf), 1, fp) != 1) { 677 answer = (struct utmpx *)NULL; 678 } else { 679 /* 680 * Save the new user structure into ubuf and fubuf so that 681 * it will be up to date in the future. 682 */ 683 (void) fflush(fp); 684 (void) memcpy(&fubuf, &ftmpxbuf, sizeof (fubuf)); 685 utmpx_frec2api(&fubuf, &ubuf); 686 answer = &ubuf; 687 } 688 689 if (lock) 690 (void) lockf(fd, F_ULOCK, 0); 691 692 if (answer != NULL && (tmpxbuf.ut_type == USER_PROCESS || 693 tmpxbuf.ut_type == DEAD_PROCESS)) 694 sendupid(tmpxbuf.ut_type == USER_PROCESS ? ADDPID : REMPID, 695 (pid_t)tmpxbuf.ut_pid); 696 return (answer); 697 } 698 /* 699 * "pututline" is a wrapper that calls pututxline after converting 700 * the utmp record to a utmpx record. 701 */ 702 struct utmp * 703 pututline(const struct utmp *entry) 704 { 705 struct utmpx utmpx; 706 struct utmpx *utmpx2; 707 708 if (compat_utmpflag) 709 return (_compat_pututline(entry)); 710 711 getutmpx(entry, &utmpx); 712 if ((utmpx2 = pututxline(&utmpx)) == NULL) 713 return (NULL); 714 getutmp(utmpx2, &utmpcompat); 715 return (&utmpcompat); 716 } 717 718 /* 719 * "setutxent" just resets the utmpx file back to the beginning. 720 */ 721 void 722 setutxent(void) 723 { 724 if (fd != -1) 725 (void) lseek(fd, 0L, SEEK_SET); 726 727 if (fp != NULL) 728 (void) fseek(fp, 0L, SEEK_SET); 729 730 /* 731 * Zero the stored copy of the last entry read, since we are 732 * resetting to the beginning of the file. 733 */ 734 bzero(&ubuf, sizeof (ubuf)); 735 bzero(&fubuf, sizeof (fubuf)); 736 } 737 738 /* 739 * "setutent" is a wrapper that calls setutxent 740 */ 741 void 742 setutent(void) 743 { 744 if (compat_utmpflag) { 745 _compat_setutent(); 746 return; 747 } 748 749 setutxent(); 750 } 751 752 /* 753 * "endutxent" closes the utmpx file. 754 */ 755 void 756 endutxent(void) 757 { 758 if (fd != -1) 759 (void) close(fd); 760 fd = -1; 761 762 if (fp != NULL) 763 (void) fclose(fp); 764 fp = NULL; 765 766 bzero(&ubuf, sizeof (ubuf)); 767 bzero(&fubuf, sizeof (fubuf)); 768 } 769 770 /* 771 * "endutent" is a wrapper that calls endutxent 772 * and clears the utmp compatibility buffer. 773 */ 774 void 775 endutent(void) 776 { 777 if (compat_utmpflag) { 778 _compat_endutent(); 779 return; 780 } 781 782 endutxent(); 783 bzero(&utmpcompat, sizeof (utmpcompat)); 784 } 785 786 /* 787 * "utmpxname" allows the user to read a file other than the 788 * normal "utmpx" file. 789 */ 790 int 791 utmpxname(const char *newfile) 792 { 793 size_t len; 794 795 /* 796 * Determine if the new filename will fit. If not, return 0. 797 */ 798 if ((len = strlen(newfile)) > MAXFILE-1) 799 return (0); 800 801 /* 802 * The name of the utmpx file has to end with 'x' 803 */ 804 if (newfile[len-1] != 'x') 805 return (0); 806 807 /* 808 * Otherwise copy in the new file name. 809 */ 810 else 811 (void) strcpy(&utmpxfile[0], newfile); 812 /* 813 * Make sure everything is reset to the beginning state. 814 */ 815 endutxent(); 816 817 /* 818 * If the file is being changed to /etc/utmpx or /var/adm/utmpx then 819 * we clear the flag so pututxline invokes utmp_update. Otherwise 820 * we set the flag indicating that they changed to another name. 821 */ 822 if (strcmp(utmpxfile, UTMPX_FILE) == 0 || 823 strcmp(utmpxfile, VAR_UTMPX_FILE) == 0) 824 changed_name = 0; 825 else 826 changed_name = 1; 827 828 return (1); 829 } 830 831 /* 832 * "utmpname" allows the user to read a file other than the 833 * normal "utmp" file. If the file specified is "/var/adm/utmp" 834 * or "/var/adm/wtmp", it is translated to the corresponding "utmpx" 835 * format name, and all "utmp" operations become wrapped calls 836 * to the equivalent "utmpx" routines, with data conversions 837 * as appropriate. In the event the application wishes to read 838 * an actual "old" utmp file (named something other than /var/adm/utmp), 839 * calling this function with that name enables backward compatibility 840 * mode, where we actually call the old utmp routines to operate on 841 * the old file. 842 */ 843 int 844 utmpname(const char *newfile) 845 { 846 char name[MAXFILE+1]; 847 848 if (strlen(newfile) > MAXFILE) 849 return (0); 850 851 if (strcmp(newfile, "/var/adm/utmp") == 0 || 852 strcmp(newfile, "/var/adm/wtmp") == 0) { 853 (void) strcpy(name, newfile); 854 (void) strcat(name, "x"); 855 compat_utmpflag = 0; /* turn off old compat mode */ 856 return (utmpxname(name)); 857 } else { 858 (void) strcpy(_compat_utmpfile, newfile); 859 compat_utmpflag = 1; 860 return (1); 861 } 862 } 863 864 /* 865 * Add the record to wtmpx. 866 */ 867 void 868 updwtmpx(const char *filex, struct utmpx *utx) 869 { 870 struct futmpx futx; 871 int wfdx; 872 873 if ((wfdx = open(filex, O_WRONLY | O_APPEND)) < 0) 874 return; 875 876 (void) lseek(wfdx, 0, SEEK_END); 877 878 utmpx_api2frec(utx, &futx); 879 (void) write(wfdx, &futx, sizeof (futx)); 880 881 done: 882 (void) close(wfdx); 883 } 884 885 /* 886 * Add record to wtmp (actually wtmpx). If not updating /var/adm/wtmp, 887 * use the old utmp compatibility routine to write a utmp-format 888 * record to the file specified. 889 */ 890 void 891 updwtmp(const char *file, struct utmp *ut) 892 { 893 struct utmpx utmpx; 894 char xfile[MAXFILE + 1]; 895 896 if (strcmp(file, "/var/adm/wtmp") == 0) { 897 (void) strlcpy(xfile, file, sizeof (xfile) - 1); 898 (void) strcat(xfile, "x"); 899 getutmpx(ut, &utmpx); 900 updwtmpx((const char *)&xfile, &utmpx); 901 } else 902 _compat_updwtmp(file, ut); 903 } 904 905 /* 906 * modutx - modify a utmpx entry. Also notify init about new pids or 907 * old pids that it no longer needs to care about 908 * 909 * args: utp- point to utmpx structure to be created 910 */ 911 struct utmpx * 912 modutx(const struct utmpx *utp) 913 { 914 int i; 915 struct utmpx utmp; /* holding area */ 916 struct utmpx *ucp = &utmp; /* and a pointer to it */ 917 struct utmpx *up; /* "current" utmpx entry */ 918 struct futmpx *fup; /* being examined */ 919 920 for (i = 0; i < IDLEN; ++i) { 921 if ((unsigned char)utp->ut_id[i] == SC_WILDC) 922 return (NULL); 923 } 924 925 /* 926 * copy the supplied utmpx structure someplace safe 927 */ 928 (void) memcpy(&utmp, utp, sizeof (utmp)); 929 setutxent(); 930 while (fup = getutxent_frec()) { 931 if (idcmp(ucp->ut_id, fup->ut_id)) 932 continue; 933 934 /* 935 * only get here if ids are the same, i.e. found right entry 936 */ 937 if (ucp->ut_pid != fup->ut_pid) { 938 sendpid(REMPID, (pid_t)fup->ut_pid); 939 sendpid(ADDPID, (pid_t)ucp->ut_pid); 940 } 941 break; 942 } 943 up = pututxline(ucp); 944 if (ucp->ut_type == DEAD_PROCESS) 945 sendpid(REMPID, (pid_t)ucp->ut_pid); 946 if (up) 947 updwtmpx(WTMPX_FILE, up); 948 endutxent(); 949 return (up); 950 } 951 952 /* 953 * modut - modify a utmp entry. Also notify init about new pids or 954 * old pids that it no longer needs to care about 955 * 956 * args: utmp - point to utmp structure to be created 957 */ 958 struct utmp * 959 modut(struct utmp *utp) 960 { 961 struct utmpx utmpx; 962 struct utmpx *utmpx2; 963 964 getutmpx(utp, &utmpx); 965 if ((utmpx2 = modutx(&utmpx)) == NULL) 966 return (NULL); 967 968 getutmp(utmpx2, utp); 969 return (utp); 970 } 971 972 /* 973 * idcmp - compare two id strings, return 0 if same, non-zero if not * 974 * args: s1 - first id string 975 * s2 - second id string 976 */ 977 static int 978 idcmp(const char *s1, const char *s2) 979 { 980 int i; 981 982 for (i = 0; i < IDLEN; ++i) 983 if ((unsigned char) *s1 != SC_WILDC && (*s1++ != *s2++)) 984 return (-1); 985 return (0); 986 } 987 988 989 /* 990 * allocid - allocate an unused id for utmp, either by recycling a 991 * DEAD_PROCESS entry or creating a new one. This routine only 992 * gets called if a wild card character was specified. 993 * 994 * args: srcid - pattern for new id 995 * saveid - last id matching pattern for a non-dead process 996 */ 997 static int 998 allocid(char *srcid, unsigned char *saveid) 999 { 1000 int i; /* scratch variable */ 1001 int changed; /* flag to indicate that a new id has */ 1002 /* been generated */ 1003 char copyid[IDLEN]; /* work area */ 1004 1005 (void) memcpy(copyid, srcid, IDLEN); 1006 changed = 0; 1007 for (i = 0; i < IDLEN; ++i) { 1008 1009 /* 1010 * if this character isn't wild, it'll be part of the 1011 * generated id 1012 */ 1013 if ((unsigned char) copyid[i] != SC_WILDC) 1014 continue; 1015 1016 /* 1017 * it's a wild character, retrieve the character from the 1018 * saved id 1019 */ 1020 copyid[i] = saveid[i]; 1021 1022 /* 1023 * if we haven't changed anything yet, try to find a new char 1024 * to use 1025 */ 1026 if (!changed && (saveid[i] < MAXVAL)) { 1027 1028 /* 1029 * Note: this algorithm is taking the "last matched" id 1030 * and trying to make a 1 character change to it to create 1031 * a new one. Rather than special-case the first time 1032 * (when no perturbation is really necessary), just don't 1033 * allocate the first valid id. 1034 */ 1035 1036 while (++saveid[i] < MAXVAL) { 1037 /* 1038 * make sure new char is alphanumeric 1039 */ 1040 if (isalnum(saveid[i])) { 1041 copyid[i] = saveid[i]; 1042 changed = 1; 1043 break; 1044 } 1045 } 1046 1047 if (!changed) { 1048 /* 1049 * Then 'reset' the current count at 1050 * this position to it's lowest valid 1051 * value, and propagate the carry to 1052 * the next wild-card slot 1053 * 1054 * See 1113208. 1055 */ 1056 saveid[i] = 0; 1057 while (!isalnum(saveid[i])) 1058 saveid[i]++; 1059 copyid[i] = ++saveid[i]; 1060 } 1061 } 1062 } 1063 /* 1064 * changed is true if we were successful in allocating an id 1065 */ 1066 if (changed) { 1067 (void) memcpy(srcid, copyid, IDLEN); 1068 return (0); 1069 } else { 1070 return (-1); 1071 } 1072 } 1073 1074 1075 /* 1076 * lockutx - lock utmpx file 1077 */ 1078 static int 1079 lockutx(void) 1080 { 1081 int lockfd; 1082 1083 if ((lockfd = open(UTMPX_FILE, O_RDWR|O_CREAT, 0644)) < 0) 1084 return (-1); 1085 1086 if (lockf(lockfd, F_LOCK, 0) < 0) { 1087 (void) close(lockfd); 1088 return (-1); 1089 } 1090 1091 tempfd = fd; 1092 fd = lockfd; 1093 1094 return (0); 1095 1096 } 1097 1098 1099 1100 /* 1101 * unlockutx - unlock utmpx file 1102 */ 1103 static void 1104 unlockutx(void) 1105 { 1106 (void) lockf(fd, F_ULOCK, 0); 1107 (void) close(fd); 1108 fd = tempfd; 1109 } 1110 1111 1112 /* 1113 * sendpid - send message to init to add or remove a pid from the 1114 * "godchild" list 1115 * 1116 * args: cmd - ADDPID or REMPID 1117 * pid - pid of "godchild" 1118 */ 1119 static void 1120 sendpid(int cmd, pid_t pid) 1121 { 1122 int pfd; /* file desc. for init pipe */ 1123 pidrec_t prec; /* place for message to be built */ 1124 1125 /* 1126 * if for some reason init didn't open initpipe, open it read/write 1127 * here to avoid sending SIGPIPE to the calling process 1128 */ 1129 pfd = open(IPIPE, O_RDWR); 1130 if (pfd < 0) 1131 return; 1132 prec.pd_pid = pid; 1133 prec.pd_type = cmd; 1134 (void) write(pfd, &prec, sizeof (pidrec_t)); 1135 (void) close(pfd); 1136 } 1137 1138 /* 1139 * makeutx - create a utmpx entry, recycling an id if a wild card is 1140 * specified. Also notify init about the new pid 1141 * 1142 * args: utmpx - point to utmpx structure to be created 1143 */ 1144 1145 struct utmpx * 1146 makeutx(const struct utmpx *utmp) 1147 { 1148 struct utmpx *utp; 1149 struct futmpx *ut; /* "current" utmpx being examined */ 1150 unsigned char saveid[IDLEN]; /* the last id we matched that was */ 1151 /* NOT a dead proc */ 1152 int falphanum = 0x30; /* first alpha num char */ 1153 off_t offset; 1154 1155 /* 1156 * Are any wild card char's present in the idlen string? 1157 */ 1158 if (memchr(utmp->ut_id, SC_WILDC, IDLEN) != NULL) { 1159 /* 1160 * try to lock the utmpx file, only needed if 1161 * we're doing wildcard matching 1162 */ 1163 if (lockutx()) 1164 return (NULL); 1165 1166 /* 1167 * used in allocid 1168 */ 1169 (void) memset(saveid, falphanum, IDLEN); 1170 1171 while (ut = getoneutx(&offset)) 1172 if (idcmp(utmp->ut_id, ut->ut_id)) { 1173 continue; 1174 } else { 1175 /* 1176 * Found a match. We are done if this is 1177 * a free slot. Else record this id. We 1178 * will need it to generate the next new id. 1179 */ 1180 if (ut->ut_type == DEAD_PROCESS) 1181 break; 1182 else 1183 (void) memcpy(saveid, ut->ut_id, 1184 IDLEN); 1185 } 1186 1187 if (ut) { 1188 1189 /* 1190 * Unused entry, reuse it. We know the offset. So 1191 * just go to that offset utmpx and write it out. 1192 */ 1193 (void) memcpy((caddr_t)utmp->ut_id, ut->ut_id, IDLEN); 1194 1195 putoneutx(utmp, offset); 1196 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1197 unlockutx(); 1198 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1199 return ((struct utmpx *)utmp); 1200 } else { 1201 /* 1202 * nothing available, allocate an id and 1203 * write it out at the end. 1204 */ 1205 1206 if (allocid((char *)utmp->ut_id, saveid)) { 1207 unlockutx(); 1208 return (NULL); 1209 } else { 1210 /* 1211 * Seek to end and write out the entry 1212 * and also update the utmpx file. 1213 */ 1214 (void) lseek(fd, 0L, SEEK_END); 1215 offset = lseek(fd, 0L, SEEK_CUR); 1216 1217 putoneutx(utmp, offset); 1218 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1219 unlockutx(); 1220 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1221 return ((struct utmpx *)utmp); 1222 } 1223 } 1224 } else { 1225 utp = pututxline(utmp); 1226 if (utp) 1227 updwtmpx(WTMPX_FILE, utp); 1228 endutxent(); 1229 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1230 return (utp); 1231 } 1232 } 1233 1234 /* 1235 * makeut - create a utmp entry, recycling an id if a wild card is 1236 * specified. Also notify init about the new pid 1237 * 1238 * args: utmp - point to utmp structure to be created 1239 */ 1240 struct utmp * 1241 makeut(struct utmp *utmp) 1242 { 1243 struct utmpx utmpx; 1244 struct utmpx *utmpx2; 1245 1246 if (compat_utmpflag) 1247 return (_compat_makeut(utmp)); 1248 1249 getutmpx(utmp, &utmpx); 1250 if ((utmpx2 = makeutx(&utmpx)) == NULL) 1251 return (NULL); 1252 1253 getutmp(utmpx2, utmp); 1254 return (utmp); 1255 } 1256 1257 1258 #define UTMPNBUF 200 /* Approx 8k (FS Block) size */ 1259 static struct futmpx *utmpbuf = NULL; 1260 1261 /* 1262 * Buffered read routine to get one entry from utmpx file 1263 */ 1264 static struct futmpx * 1265 getoneutx(off_t *off) 1266 { 1267 static size_t idx = 0; /* Current index in the utmpbuf */ 1268 static size_t nidx = 0; /* Max entries in this utmpbuf */ 1269 static int nbuf = 0; /* number of utmpbufs read from disk */ 1270 ssize_t nbytes, bufsz = sizeof (struct futmpx) * UTMPNBUF; 1271 1272 if (utmpbuf == NULL) 1273 if ((utmpbuf = malloc(bufsz)) == NULL) { 1274 perror("malloc"); 1275 return (NULL); 1276 } 1277 1278 if (idx == nidx) { 1279 /* 1280 * We have read all entries in the utmpbuf. Read 1281 * the buffer from the disk. 1282 */ 1283 if ((nbytes = read(fd, utmpbuf, bufsz)) < bufsz) { 1284 /* 1285 * Partial read only. keep count of the 1286 * number of valid entries in the buffer 1287 */ 1288 nidx = nbytes / sizeof (struct futmpx); 1289 } else { 1290 /* 1291 * We read in the full UTMPNBUF entries 1292 * Great ! 1293 */ 1294 nidx = UTMPNBUF; 1295 } 1296 nbuf++; /* Number of buf we have read in. */ 1297 idx = 0; /* reset index within utmpbuf */ 1298 } 1299 1300 /* 1301 * Current offset of this buffer in the file 1302 */ 1303 *off = (((nbuf - 1) * UTMPNBUF) + idx) * sizeof (struct futmpx); 1304 1305 if (idx < nidx) { 1306 /* 1307 * We still have at least one valid buffer in 1308 * utmpbuf to be passed to the caller. 1309 */ 1310 return (&utmpbuf[idx++]); 1311 } 1312 1313 /* 1314 * Reached EOF. Return NULL. Offset is set correctly 1315 * to append at the end of the file 1316 */ 1317 1318 return (NULL); 1319 } 1320 1321 static void 1322 putoneutx(const struct utmpx *utpx, off_t off) 1323 { 1324 struct futmpx futx; 1325 1326 utmpx_api2frec(utpx, &futx); 1327 (void) lseek(fd, off, SEEK_SET); /* seek in the utmpx file */ 1328 (void) write(fd, &futx, sizeof (futx)); 1329 } 1330 1331 /* 1332 * sendupid - send message to utmpd to add or remove a pid from the 1333 * list of procs to watch 1334 * 1335 * args: cmd - ADDPID or REMPID 1336 * pid - process ID of process to watch 1337 */ 1338 static void 1339 sendupid(int cmd, pid_t pid) 1340 { 1341 int pfd; /* file desc. for utmp pipe */ 1342 pidrec_t prec; /* place for message to be built */ 1343 1344 /* 1345 * if for some reason utmp didn't open utmppipe, open it read/write 1346 * here to avoid sending SIGPIPE to the calling process 1347 */ 1348 1349 pfd = open(UPIPE, O_RDWR | O_NONBLOCK | O_NDELAY); 1350 if (pfd < 0) 1351 return; 1352 prec.pd_pid = pid; 1353 prec.pd_type = cmd; 1354 (void) write(pfd, &prec, sizeof (pidrec_t)); 1355 (void) close(pfd); 1356 } 1357 1358 /* 1359 * getutmpx - convert a utmp record into a utmpx record 1360 */ 1361 void 1362 getutmpx(const struct utmp *ut, struct utmpx *utx) 1363 { 1364 (void) memcpy(utx->ut_user, ut->ut_user, sizeof (ut->ut_user)); 1365 (void) bzero(&utx->ut_user[sizeof (ut->ut_user)], 1366 sizeof (utx->ut_user) - sizeof (ut->ut_user)); 1367 (void) memcpy(utx->ut_line, ut->ut_line, sizeof (ut->ut_line)); 1368 (void) bzero(&utx->ut_line[sizeof (ut->ut_line)], 1369 sizeof (utx->ut_line) - sizeof (ut->ut_line)); 1370 (void) memcpy(utx->ut_id, ut->ut_id, sizeof (ut->ut_id)); 1371 utx->ut_pid = ut->ut_pid; 1372 utx->ut_type = ut->ut_type; 1373 utx->ut_exit = ut->ut_exit; 1374 utx->ut_tv.tv_sec = ut->ut_time; 1375 utx->ut_tv.tv_usec = 0; 1376 utx->ut_session = 0; 1377 bzero(utx->pad, sizeof (utx->pad)); 1378 bzero(utx->ut_host, sizeof (utx->ut_host)); 1379 utx->ut_syslen = 0; 1380 } 1381 1382 /* 1383 * getutmp - convert a utmpx record into a utmp record 1384 */ 1385 void 1386 getutmp(const struct utmpx *utx, struct utmp *ut) 1387 { 1388 (void) memcpy(ut->ut_user, utx->ut_user, sizeof (ut->ut_user)); 1389 (void) memcpy(ut->ut_line, utx->ut_line, sizeof (ut->ut_line)); 1390 (void) memcpy(ut->ut_id, utx->ut_id, sizeof (utx->ut_id)); 1391 ut->ut_pid = utx->ut_pid; 1392 ut->ut_type = utx->ut_type; 1393 ut->ut_exit = utx->ut_exit; 1394 ut->ut_time = utx->ut_tv.tv_sec; 1395 } 1396