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