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 (void) close(wfdx); 881 } 882 883 /* 884 * Add record to wtmp (actually wtmpx). If not updating /var/adm/wtmp, 885 * use the old utmp compatibility routine to write a utmp-format 886 * record to the file specified. 887 */ 888 void 889 updwtmp(const char *file, struct utmp *ut) 890 { 891 struct utmpx utmpx; 892 char xfile[MAXFILE + 1]; 893 894 if (strcmp(file, "/var/adm/wtmp") == 0) { 895 (void) strlcpy(xfile, file, sizeof (xfile) - 1); 896 (void) strcat(xfile, "x"); 897 getutmpx(ut, &utmpx); 898 updwtmpx((const char *)&xfile, &utmpx); 899 } else 900 _compat_updwtmp(file, ut); 901 } 902 903 /* 904 * modutx - modify a utmpx entry. Also notify init about new pids or 905 * old pids that it no longer needs to care about 906 * 907 * args: utp- point to utmpx structure to be created 908 */ 909 struct utmpx * 910 modutx(const struct utmpx *utp) 911 { 912 int i; 913 struct utmpx utmp; /* holding area */ 914 struct utmpx *ucp = &utmp; /* and a pointer to it */ 915 struct utmpx *up; /* "current" utmpx entry */ 916 struct futmpx *fup; /* being examined */ 917 918 for (i = 0; i < IDLEN; ++i) { 919 if ((unsigned char)utp->ut_id[i] == SC_WILDC) 920 return (NULL); 921 } 922 923 /* 924 * copy the supplied utmpx structure someplace safe 925 */ 926 (void) memcpy(&utmp, utp, sizeof (utmp)); 927 setutxent(); 928 while ((fup = getutxent_frec()) != NULL) { 929 if (idcmp(ucp->ut_id, fup->ut_id)) 930 continue; 931 932 /* 933 * only get here if ids are the same, i.e. found right entry 934 */ 935 if (ucp->ut_pid != fup->ut_pid) { 936 sendpid(REMPID, (pid_t)fup->ut_pid); 937 sendpid(ADDPID, (pid_t)ucp->ut_pid); 938 } 939 break; 940 } 941 up = pututxline(ucp); 942 if (ucp->ut_type == DEAD_PROCESS) 943 sendpid(REMPID, (pid_t)ucp->ut_pid); 944 if (up) 945 updwtmpx(WTMPX_FILE, up); 946 endutxent(); 947 return (up); 948 } 949 950 /* 951 * modut - modify a utmp entry. Also notify init about new pids or 952 * old pids that it no longer needs to care about 953 * 954 * args: utmp - point to utmp structure to be created 955 */ 956 struct utmp * 957 modut(struct utmp *utp) 958 { 959 struct utmpx utmpx; 960 struct utmpx *utmpx2; 961 962 getutmpx(utp, &utmpx); 963 if ((utmpx2 = modutx(&utmpx)) == NULL) 964 return (NULL); 965 966 getutmp(utmpx2, utp); 967 return (utp); 968 } 969 970 /* 971 * idcmp - compare two id strings, return 0 if same, non-zero if not * 972 * args: s1 - first id string 973 * s2 - second id string 974 */ 975 static int 976 idcmp(const char *s1, const char *s2) 977 { 978 int i; 979 980 for (i = 0; i < IDLEN; ++i) 981 if ((unsigned char) *s1 != SC_WILDC && (*s1++ != *s2++)) 982 return (-1); 983 return (0); 984 } 985 986 987 /* 988 * allocid - allocate an unused id for utmp, either by recycling a 989 * DEAD_PROCESS entry or creating a new one. This routine only 990 * gets called if a wild card character was specified. 991 * 992 * args: srcid - pattern for new id 993 * saveid - last id matching pattern for a non-dead process 994 */ 995 static int 996 allocid(char *srcid, unsigned char *saveid) 997 { 998 int i; /* scratch variable */ 999 int changed; /* flag to indicate that a new id has */ 1000 /* been generated */ 1001 char copyid[IDLEN]; /* work area */ 1002 1003 (void) memcpy(copyid, srcid, IDLEN); 1004 changed = 0; 1005 for (i = 0; i < IDLEN; ++i) { 1006 1007 /* 1008 * if this character isn't wild, it'll be part of the 1009 * generated id 1010 */ 1011 if ((unsigned char) copyid[i] != SC_WILDC) 1012 continue; 1013 1014 /* 1015 * it's a wild character, retrieve the character from the 1016 * saved id 1017 */ 1018 copyid[i] = saveid[i]; 1019 1020 /* 1021 * if we haven't changed anything yet, try to find a new char 1022 * to use 1023 */ 1024 if (!changed && (saveid[i] < MAXVAL)) { 1025 1026 /* 1027 * Note: this algorithm is taking the "last matched" id 1028 * and trying to make a 1 character change to it to create 1029 * a new one. Rather than special-case the first time 1030 * (when no perturbation is really necessary), just don't 1031 * allocate the first valid id. 1032 */ 1033 1034 while (++saveid[i] < MAXVAL) { 1035 /* 1036 * make sure new char is alphanumeric 1037 */ 1038 if (isalnum(saveid[i])) { 1039 copyid[i] = saveid[i]; 1040 changed = 1; 1041 break; 1042 } 1043 } 1044 1045 if (!changed) { 1046 /* 1047 * Then 'reset' the current count at 1048 * this position to it's lowest valid 1049 * value, and propagate the carry to 1050 * the next wild-card slot 1051 * 1052 * See 1113208. 1053 */ 1054 saveid[i] = 0; 1055 while (!isalnum(saveid[i])) 1056 saveid[i]++; 1057 copyid[i] = ++saveid[i]; 1058 } 1059 } 1060 } 1061 /* 1062 * changed is true if we were successful in allocating an id 1063 */ 1064 if (changed) { 1065 (void) memcpy(srcid, copyid, IDLEN); 1066 return (0); 1067 } else { 1068 return (-1); 1069 } 1070 } 1071 1072 1073 /* 1074 * lockutx - lock utmpx file 1075 */ 1076 static int 1077 lockutx(void) 1078 { 1079 int lockfd; 1080 1081 if ((lockfd = open(UTMPX_FILE, O_RDWR|O_CREAT, 0644)) < 0) 1082 return (-1); 1083 1084 if (lockf(lockfd, F_LOCK, 0) < 0) { 1085 (void) close(lockfd); 1086 return (-1); 1087 } 1088 1089 tempfd = fd; 1090 fd = lockfd; 1091 1092 return (0); 1093 1094 } 1095 1096 1097 1098 /* 1099 * unlockutx - unlock utmpx file 1100 */ 1101 static void 1102 unlockutx(void) 1103 { 1104 (void) lockf(fd, F_ULOCK, 0); 1105 (void) close(fd); 1106 fd = tempfd; 1107 } 1108 1109 1110 /* 1111 * sendpid - send message to init to add or remove a pid from the 1112 * "godchild" list 1113 * 1114 * args: cmd - ADDPID or REMPID 1115 * pid - pid of "godchild" 1116 */ 1117 static void 1118 sendpid(int cmd, pid_t pid) 1119 { 1120 int pfd; /* file desc. for init pipe */ 1121 pidrec_t prec; /* place for message to be built */ 1122 1123 /* 1124 * if for some reason init didn't open initpipe, open it read/write 1125 * here to avoid sending SIGPIPE to the calling process 1126 */ 1127 pfd = open(IPIPE, O_RDWR); 1128 if (pfd < 0) 1129 return; 1130 prec.pd_pid = pid; 1131 prec.pd_type = cmd; 1132 (void) write(pfd, &prec, sizeof (pidrec_t)); 1133 (void) close(pfd); 1134 } 1135 1136 /* 1137 * makeutx - create a utmpx entry, recycling an id if a wild card is 1138 * specified. Also notify init about the new pid 1139 * 1140 * args: utmpx - point to utmpx structure to be created 1141 */ 1142 1143 struct utmpx * 1144 makeutx(const struct utmpx *utmp) 1145 { 1146 struct utmpx *utp; 1147 struct futmpx *ut; /* "current" utmpx being examined */ 1148 unsigned char saveid[IDLEN]; /* the last id we matched that was */ 1149 /* NOT a dead proc */ 1150 int falphanum = 0x30; /* first alpha num char */ 1151 off_t offset; 1152 1153 /* 1154 * Are any wild card char's present in the idlen string? 1155 */ 1156 if (memchr(utmp->ut_id, SC_WILDC, IDLEN) != NULL) { 1157 /* 1158 * try to lock the utmpx file, only needed if 1159 * we're doing wildcard matching 1160 */ 1161 if (lockutx()) 1162 return (NULL); 1163 1164 /* 1165 * used in allocid 1166 */ 1167 (void) memset(saveid, falphanum, IDLEN); 1168 1169 while ((ut = getoneutx(&offset)) != NULL) 1170 if (idcmp(utmp->ut_id, ut->ut_id)) { 1171 continue; 1172 } else { 1173 /* 1174 * Found a match. We are done if this is 1175 * a free slot. Else record this id. We 1176 * will need it to generate the next new id. 1177 */ 1178 if (ut->ut_type == DEAD_PROCESS) 1179 break; 1180 else 1181 (void) memcpy(saveid, ut->ut_id, 1182 IDLEN); 1183 } 1184 1185 if (ut) { 1186 1187 /* 1188 * Unused entry, reuse it. We know the offset. So 1189 * just go to that offset utmpx and write it out. 1190 */ 1191 (void) memcpy((caddr_t)utmp->ut_id, ut->ut_id, IDLEN); 1192 1193 putoneutx(utmp, offset); 1194 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1195 unlockutx(); 1196 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1197 return ((struct utmpx *)utmp); 1198 } else { 1199 /* 1200 * nothing available, allocate an id and 1201 * write it out at the end. 1202 */ 1203 1204 if (allocid((char *)utmp->ut_id, saveid)) { 1205 unlockutx(); 1206 return (NULL); 1207 } else { 1208 /* 1209 * Seek to end and write out the entry 1210 * and also update the utmpx file. 1211 */ 1212 (void) lseek(fd, 0L, SEEK_END); 1213 offset = lseek(fd, 0L, SEEK_CUR); 1214 1215 putoneutx(utmp, offset); 1216 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1217 unlockutx(); 1218 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1219 return ((struct utmpx *)utmp); 1220 } 1221 } 1222 } else { 1223 utp = pututxline(utmp); 1224 if (utp) 1225 updwtmpx(WTMPX_FILE, utp); 1226 endutxent(); 1227 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1228 return (utp); 1229 } 1230 } 1231 1232 /* 1233 * makeut - create a utmp entry, recycling an id if a wild card is 1234 * specified. Also notify init about the new pid 1235 * 1236 * args: utmp - point to utmp structure to be created 1237 */ 1238 struct utmp * 1239 makeut(struct utmp *utmp) 1240 { 1241 struct utmpx utmpx; 1242 struct utmpx *utmpx2; 1243 1244 if (compat_utmpflag) 1245 return (_compat_makeut(utmp)); 1246 1247 getutmpx(utmp, &utmpx); 1248 if ((utmpx2 = makeutx(&utmpx)) == NULL) 1249 return (NULL); 1250 1251 getutmp(utmpx2, utmp); 1252 return (utmp); 1253 } 1254 1255 1256 #define UTMPNBUF 200 /* Approx 8k (FS Block) size */ 1257 static struct futmpx *utmpbuf = NULL; 1258 1259 /* 1260 * Buffered read routine to get one entry from utmpx file 1261 */ 1262 static struct futmpx * 1263 getoneutx(off_t *off) 1264 { 1265 static size_t idx = 0; /* Current index in the utmpbuf */ 1266 static size_t nidx = 0; /* Max entries in this utmpbuf */ 1267 static int nbuf = 0; /* number of utmpbufs read from disk */ 1268 ssize_t nbytes, bufsz = sizeof (struct futmpx) * UTMPNBUF; 1269 1270 if (utmpbuf == NULL) 1271 if ((utmpbuf = malloc(bufsz)) == NULL) { 1272 perror("malloc"); 1273 return (NULL); 1274 } 1275 1276 if (idx == nidx) { 1277 /* 1278 * We have read all entries in the utmpbuf. Read 1279 * the buffer from the disk. 1280 */ 1281 if ((nbytes = read(fd, utmpbuf, bufsz)) < bufsz) { 1282 /* 1283 * Partial read only. keep count of the 1284 * number of valid entries in the buffer 1285 */ 1286 nidx = nbytes / sizeof (struct futmpx); 1287 } else { 1288 /* 1289 * We read in the full UTMPNBUF entries 1290 * Great ! 1291 */ 1292 nidx = UTMPNBUF; 1293 } 1294 nbuf++; /* Number of buf we have read in. */ 1295 idx = 0; /* reset index within utmpbuf */ 1296 } 1297 1298 /* 1299 * Current offset of this buffer in the file 1300 */ 1301 *off = (((nbuf - 1) * UTMPNBUF) + idx) * sizeof (struct futmpx); 1302 1303 if (idx < nidx) { 1304 /* 1305 * We still have at least one valid buffer in 1306 * utmpbuf to be passed to the caller. 1307 */ 1308 return (&utmpbuf[idx++]); 1309 } 1310 1311 /* 1312 * Reached EOF. Return NULL. Offset is set correctly 1313 * to append at the end of the file 1314 */ 1315 1316 return (NULL); 1317 } 1318 1319 static void 1320 putoneutx(const struct utmpx *utpx, off_t off) 1321 { 1322 struct futmpx futx; 1323 1324 utmpx_api2frec(utpx, &futx); 1325 (void) lseek(fd, off, SEEK_SET); /* seek in the utmpx file */ 1326 (void) write(fd, &futx, sizeof (futx)); 1327 } 1328 1329 /* 1330 * sendupid - send message to utmpd to add or remove a pid from the 1331 * list of procs to watch 1332 * 1333 * args: cmd - ADDPID or REMPID 1334 * pid - process ID of process to watch 1335 */ 1336 static void 1337 sendupid(int cmd, pid_t pid) 1338 { 1339 int pfd; /* file desc. for utmp pipe */ 1340 pidrec_t prec; /* place for message to be built */ 1341 1342 /* 1343 * if for some reason utmp didn't open utmppipe, open it read/write 1344 * here to avoid sending SIGPIPE to the calling process 1345 */ 1346 1347 pfd = open(UPIPE, O_RDWR | O_NONBLOCK | O_NDELAY); 1348 if (pfd < 0) 1349 return; 1350 prec.pd_pid = pid; 1351 prec.pd_type = cmd; 1352 (void) write(pfd, &prec, sizeof (pidrec_t)); 1353 (void) close(pfd); 1354 } 1355 1356 /* 1357 * getutmpx - convert a utmp record into a utmpx record 1358 */ 1359 void 1360 getutmpx(const struct utmp *ut, struct utmpx *utx) 1361 { 1362 (void) memcpy(utx->ut_user, ut->ut_user, sizeof (ut->ut_user)); 1363 (void) bzero(&utx->ut_user[sizeof (ut->ut_user)], 1364 sizeof (utx->ut_user) - sizeof (ut->ut_user)); 1365 (void) memcpy(utx->ut_line, ut->ut_line, sizeof (ut->ut_line)); 1366 (void) bzero(&utx->ut_line[sizeof (ut->ut_line)], 1367 sizeof (utx->ut_line) - sizeof (ut->ut_line)); 1368 (void) memcpy(utx->ut_id, ut->ut_id, sizeof (ut->ut_id)); 1369 utx->ut_pid = ut->ut_pid; 1370 utx->ut_type = ut->ut_type; 1371 utx->ut_exit = ut->ut_exit; 1372 utx->ut_tv.tv_sec = ut->ut_time; 1373 utx->ut_tv.tv_usec = 0; 1374 utx->ut_session = 0; 1375 bzero(utx->pad, sizeof (utx->pad)); 1376 bzero(utx->ut_host, sizeof (utx->ut_host)); 1377 utx->ut_syslen = 0; 1378 } 1379 1380 /* 1381 * getutmp - convert a utmpx record into a utmp record 1382 */ 1383 void 1384 getutmp(const struct utmpx *utx, struct utmp *ut) 1385 { 1386 (void) memcpy(ut->ut_user, utx->ut_user, sizeof (ut->ut_user)); 1387 (void) memcpy(ut->ut_line, utx->ut_line, sizeof (ut->ut_line)); 1388 (void) memcpy(ut->ut_id, utx->ut_id, sizeof (utx->ut_id)); 1389 ut->ut_pid = utx->ut_pid; 1390 ut->ut_type = utx->ut_type; 1391 ut->ut_exit = utx->ut_exit; 1392 ut->ut_time = utx->ut_tv.tv_sec; 1393 } 1394