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