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