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 2007 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 "/var/run/initpipe" /* FIFO to send pids to init */ 95 #define UPIPE "/var/run/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, "rF")) == 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+F")) == 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 posix_spawnattr_t attr; 510 int status; 511 pid_t child; 512 pid_t w; 513 int i; 514 char user[STRSZ], id[STRSZ], line[STRSZ], pid[STRSZ], type[STRSZ], 515 term[STRSZ], exit[STRSZ], time[STRSZ], time_usec[STRSZ], 516 session_id[STRSZ], syslen[32]; 517 char pad[sizeof (entryx->pad) * 2 + 1]; 518 char host[sizeof (entryx->ut_host) + 1]; 519 struct utmpx *curx = NULL; 520 char bin2hex[] = "0123456789ABCDEF"; 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 * No SIGCHLD, please, and let no one else reap our child. 570 */ 571 error = posix_spawnattr_init(&attr); 572 if (error) { 573 errno = error; 574 goto out; 575 } 576 error = posix_spawnattr_setflags(&attr, 577 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP); 578 if (error) { 579 (void) posix_spawnattr_destroy(&attr); 580 errno = error; 581 goto out; 582 } 583 error = posix_spawn(&child, UTMP_UPDATE, NULL, &attr, argvec, environ); 584 (void) posix_spawnattr_destroy(&attr); 585 if (error) { 586 errno = error; 587 goto out; 588 } 589 590 do { 591 w = waitpid(child, &status, 0); 592 } while (w == -1 && errno == EINTR); 593 594 /* 595 * We can get ECHILD if the process is ignoring SIGCLD. 596 */ 597 if (!(w == -1 && errno == ECHILD) && 598 (w == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)) { 599 /* 600 * The child encountered an error, 601 */ 602 goto out; 603 } 604 605 /* 606 * Normal termination. Return a pointer to the entry we just made. 607 */ 608 setutxent(); /* Reset file pointer */ 609 610 while ((curx = getutxent()) != NULL) { 611 if (curx->ut_type != EMPTY && 612 (curx->ut_type == LOGIN_PROCESS || 613 curx->ut_type == USER_PROCESS || 614 curx->ut_type == DEAD_PROCESS) && 615 strncmp(&entryx->ut_line[0], &curx->ut_line[0], 616 sizeof (curx->ut_line)) == 0) 617 break; 618 } 619 620 out: 621 return (curx); 622 } 623 624 /* 625 * "pututxline" writes the structure sent into the utmpx file. 626 * If there is already an entry with the same id, then it is 627 * overwritten, otherwise a new entry is made at the end of the 628 * utmpx file. 629 */ 630 631 struct utmpx * 632 pututxline(const struct utmpx *entry) 633 { 634 struct utmpx *answer; 635 int lock = 0; 636 struct utmpx tmpxbuf; 637 struct futmpx ftmpxbuf; 638 639 /* 640 * Copy the user supplied entry into our temporary buffer to 641 * avoid the possibility that the user is actually passing us 642 * the address of "ubuf". 643 */ 644 if (entry == NULL) 645 return (NULL); 646 647 (void) memcpy(&tmpxbuf, entry, sizeof (tmpxbuf)); 648 utmpx_api2frec(entry, &ftmpxbuf); 649 650 if (fd < 0) { 651 (void) getutxent_frec(); 652 if (fd < 0) 653 return ((struct utmpx *)NULL); 654 } 655 656 /* 657 * If we are not the superuser than we can't write to /etc/utmp, 658 * so invoke update_utmp(8) to write the entry for us. 659 */ 660 if (changed_name == 0 && geteuid() != 0) 661 return (invoke_utmp_update(entry)); 662 663 /* 664 * Find the proper entry in the utmpx file. Start at the current 665 * location. If it isn't found from here to the end of the 666 * file, then reset to the beginning of the file and try again. 667 * If it still isn't found, then write a new entry at the end of 668 * the file. (Making sure the location is an integral number of 669 * utmp structures into the file incase the file is scribbled.) 670 */ 671 672 if (getutxid(&tmpxbuf) == NULL) { 673 674 setutxent(); 675 676 /* 677 * Lock the the entire file from here onwards. 678 */ 679 if (getutxid(&tmpxbuf) == NULL) { 680 lock++; 681 if (lockf(fd, F_LOCK, 0) < NULL) 682 return (NULL); 683 (void) fseek(fp, 0, SEEK_END); 684 } else 685 (void) fseek(fp, -(long)sizeof (struct futmpx), 686 SEEK_CUR); 687 } else 688 (void) fseek(fp, -(long)sizeof (struct futmpx), SEEK_CUR); 689 690 /* 691 * Write out the user supplied structure. If the write fails, 692 * then the user probably doesn't have permission to write the 693 * utmpx file. 694 */ 695 if (fwrite(&ftmpxbuf, sizeof (ftmpxbuf), 1, fp) != 1) { 696 answer = (struct utmpx *)NULL; 697 } else { 698 /* 699 * Save the new user structure into ubuf and fubuf so that 700 * it will be up to date in the future. 701 */ 702 (void) fflush(fp); 703 (void) memcpy(&fubuf, &ftmpxbuf, sizeof (fubuf)); 704 utmpx_frec2api(&fubuf, &ubuf); 705 answer = &ubuf; 706 } 707 708 if (lock) 709 (void) lockf(fd, F_ULOCK, 0); 710 711 if (answer != NULL && (tmpxbuf.ut_type == USER_PROCESS || 712 tmpxbuf.ut_type == DEAD_PROCESS)) 713 sendupid(tmpxbuf.ut_type == USER_PROCESS ? ADDPID : REMPID, 714 (pid_t)tmpxbuf.ut_pid); 715 return (answer); 716 } 717 /* 718 * "pututline" is a wrapper that calls pututxline after converting 719 * the utmp record to a utmpx record. 720 */ 721 struct utmp * 722 pututline(const struct utmp *entry) 723 { 724 struct utmpx utmpx; 725 struct utmpx *utmpx2; 726 727 if (compat_utmpflag) 728 return (_compat_pututline(entry)); 729 730 getutmpx(entry, &utmpx); 731 if ((utmpx2 = pututxline(&utmpx)) == NULL) 732 return (NULL); 733 getutmp(utmpx2, &utmpcompat); 734 return (&utmpcompat); 735 } 736 737 /* 738 * "setutxent" just resets the utmpx file back to the beginning. 739 */ 740 void 741 setutxent(void) 742 { 743 if (fd != -1) 744 (void) lseek(fd, 0L, SEEK_SET); 745 746 if (fp != NULL) 747 (void) fseek(fp, 0L, SEEK_SET); 748 749 /* 750 * Zero the stored copy of the last entry read, since we are 751 * resetting to the beginning of the file. 752 */ 753 bzero(&ubuf, sizeof (ubuf)); 754 bzero(&fubuf, sizeof (fubuf)); 755 } 756 757 /* 758 * "setutent" is a wrapper that calls setutxent 759 */ 760 void 761 setutent(void) 762 { 763 if (compat_utmpflag) { 764 _compat_setutent(); 765 return; 766 } 767 768 setutxent(); 769 } 770 771 /* 772 * "endutxent" closes the utmpx file. 773 */ 774 void 775 endutxent(void) 776 { 777 if (fd != -1) 778 (void) close(fd); 779 fd = -1; 780 781 if (fp != NULL) 782 (void) fclose(fp); 783 fp = NULL; 784 785 bzero(&ubuf, sizeof (ubuf)); 786 bzero(&fubuf, sizeof (fubuf)); 787 } 788 789 /* 790 * "endutent" is a wrapper that calls endutxent 791 * and clears the utmp compatibility buffer. 792 */ 793 void 794 endutent(void) 795 { 796 if (compat_utmpflag) { 797 _compat_endutent(); 798 return; 799 } 800 801 endutxent(); 802 bzero(&utmpcompat, sizeof (utmpcompat)); 803 } 804 805 /* 806 * "utmpxname" allows the user to read a file other than the 807 * normal "utmpx" file. 808 */ 809 int 810 utmpxname(const char *newfile) 811 { 812 size_t len; 813 814 /* 815 * Determine if the new filename will fit. If not, return 0. 816 */ 817 if ((len = strlen(newfile)) > MAXFILE-1) 818 return (0); 819 820 /* 821 * The name of the utmpx file has to end with 'x' 822 */ 823 if (newfile[len-1] != 'x') 824 return (0); 825 826 /* 827 * Otherwise copy in the new file name. 828 */ 829 else 830 (void) strcpy(&utmpxfile[0], newfile); 831 /* 832 * Make sure everything is reset to the beginning state. 833 */ 834 endutxent(); 835 836 /* 837 * If the file is being changed to /etc/utmpx or /var/adm/utmpx then 838 * we clear the flag so pututxline invokes utmp_update. Otherwise 839 * we set the flag indicating that they changed to another name. 840 */ 841 if (strcmp(utmpxfile, UTMPX_FILE) == 0 || 842 strcmp(utmpxfile, VAR_UTMPX_FILE) == 0) 843 changed_name = 0; 844 else 845 changed_name = 1; 846 847 return (1); 848 } 849 850 /* 851 * "utmpname" allows the user to read a file other than the 852 * normal "utmp" file. If the file specified is "/var/adm/utmp" 853 * or "/var/adm/wtmp", it is translated to the corresponding "utmpx" 854 * format name, and all "utmp" operations become wrapped calls 855 * to the equivalent "utmpx" routines, with data conversions 856 * as appropriate. In the event the application wishes to read 857 * an actual "old" utmp file (named something other than /var/adm/utmp), 858 * calling this function with that name enables backward compatibility 859 * mode, where we actually call the old utmp routines to operate on 860 * the old file. 861 */ 862 int 863 utmpname(const char *newfile) 864 { 865 char name[MAXFILE+1]; 866 867 if (strlen(newfile) > MAXFILE) 868 return (0); 869 870 if (strcmp(newfile, "/var/adm/utmp") == 0 || 871 strcmp(newfile, "/var/adm/wtmp") == 0) { 872 (void) strcpy(name, newfile); 873 (void) strcat(name, "x"); 874 compat_utmpflag = 0; /* turn off old compat mode */ 875 return (utmpxname(name)); 876 } else { 877 (void) strcpy(_compat_utmpfile, newfile); 878 compat_utmpflag = 1; 879 return (1); 880 } 881 } 882 883 /* 884 * Add the record to wtmpx. 885 */ 886 void 887 updwtmpx(const char *filex, struct utmpx *utx) 888 { 889 struct futmpx futx; 890 int wfdx; 891 892 if ((wfdx = open(filex, O_WRONLY | O_APPEND)) < 0) 893 return; 894 895 (void) lseek(wfdx, 0, SEEK_END); 896 897 utmpx_api2frec(utx, &futx); 898 (void) write(wfdx, &futx, sizeof (futx)); 899 900 done: 901 (void) close(wfdx); 902 } 903 904 /* 905 * Add record to wtmp (actually wtmpx). If not updating /var/adm/wtmp, 906 * use the old utmp compatibility routine to write a utmp-format 907 * record to the file specified. 908 */ 909 void 910 updwtmp(const char *file, struct utmp *ut) 911 { 912 struct utmpx utmpx; 913 char xfile[MAXFILE + 1]; 914 915 if (strcmp(file, "/var/adm/wtmp") == 0) { 916 (void) strlcpy(xfile, file, sizeof (xfile) - 1); 917 (void) strcat(xfile, "x"); 918 getutmpx(ut, &utmpx); 919 updwtmpx((const char *)&xfile, &utmpx); 920 } else 921 _compat_updwtmp(file, ut); 922 } 923 924 /* 925 * modutx - modify a utmpx entry. Also notify init about new pids or 926 * old pids that it no longer needs to care about 927 * 928 * args: utp- point to utmpx structure to be created 929 */ 930 struct utmpx * 931 modutx(const struct utmpx *utp) 932 { 933 int i; 934 struct utmpx utmp; /* holding area */ 935 struct utmpx *ucp = &utmp; /* and a pointer to it */ 936 struct utmpx *up; /* "current" utmpx entry */ 937 struct futmpx *fup; /* being examined */ 938 939 for (i = 0; i < IDLEN; ++i) { 940 if ((unsigned char)utp->ut_id[i] == SC_WILDC) 941 return (NULL); 942 } 943 944 /* 945 * copy the supplied utmpx structure someplace safe 946 */ 947 (void) memcpy(&utmp, utp, sizeof (utmp)); 948 setutxent(); 949 while (fup = getutxent_frec()) { 950 if (idcmp(ucp->ut_id, fup->ut_id)) 951 continue; 952 953 /* 954 * only get here if ids are the same, i.e. found right entry 955 */ 956 if (ucp->ut_pid != fup->ut_pid) { 957 sendpid(REMPID, (pid_t)fup->ut_pid); 958 sendpid(ADDPID, (pid_t)ucp->ut_pid); 959 } 960 break; 961 } 962 up = pututxline(ucp); 963 if (ucp->ut_type == DEAD_PROCESS) 964 sendpid(REMPID, (pid_t)ucp->ut_pid); 965 if (up) 966 updwtmpx(WTMPX_FILE, up); 967 endutxent(); 968 return (up); 969 } 970 971 /* 972 * modut - modify a utmp entry. Also notify init about new pids or 973 * old pids that it no longer needs to care about 974 * 975 * args: utmp - point to utmp structure to be created 976 */ 977 struct utmp * 978 modut(struct utmp *utp) 979 { 980 struct utmpx utmpx; 981 struct utmpx *utmpx2; 982 983 getutmpx(utp, &utmpx); 984 if ((utmpx2 = modutx(&utmpx)) == NULL) 985 return (NULL); 986 987 getutmp(utmpx2, utp); 988 return (utp); 989 } 990 991 /* 992 * idcmp - compare two id strings, return 0 if same, non-zero if not * 993 * args: s1 - first id string 994 * s2 - second id string 995 */ 996 static int 997 idcmp(const char *s1, const char *s2) 998 { 999 int i; 1000 1001 for (i = 0; i < IDLEN; ++i) 1002 if ((unsigned char) *s1 != SC_WILDC && (*s1++ != *s2++)) 1003 return (-1); 1004 return (0); 1005 } 1006 1007 1008 /* 1009 * allocid - allocate an unused id for utmp, either by recycling a 1010 * DEAD_PROCESS entry or creating a new one. This routine only 1011 * gets called if a wild card character was specified. 1012 * 1013 * args: srcid - pattern for new id 1014 * saveid - last id matching pattern for a non-dead process 1015 */ 1016 static int 1017 allocid(char *srcid, unsigned char *saveid) 1018 { 1019 int i; /* scratch variable */ 1020 int changed; /* flag to indicate that a new id has */ 1021 /* been generated */ 1022 char copyid[IDLEN]; /* work area */ 1023 1024 (void) memcpy(copyid, srcid, IDLEN); 1025 changed = 0; 1026 for (i = 0; i < IDLEN; ++i) { 1027 1028 /* 1029 * if this character isn't wild, it'll be part of the 1030 * generated id 1031 */ 1032 if ((unsigned char) copyid[i] != SC_WILDC) 1033 continue; 1034 1035 /* 1036 * it's a wild character, retrieve the character from the 1037 * saved id 1038 */ 1039 copyid[i] = saveid[i]; 1040 1041 /* 1042 * if we haven't changed anything yet, try to find a new char 1043 * to use 1044 */ 1045 if (!changed && (saveid[i] < MAXVAL)) { 1046 1047 /* 1048 * Note: this algorithm is taking the "last matched" id 1049 * and trying to make a 1 character change to it to create 1050 * a new one. Rather than special-case the first time 1051 * (when no perturbation is really necessary), just don't 1052 * allocate the first valid id. 1053 */ 1054 1055 while (++saveid[i] < MAXVAL) { 1056 /* 1057 * make sure new char is alphanumeric 1058 */ 1059 if (isalnum(saveid[i])) { 1060 copyid[i] = saveid[i]; 1061 changed = 1; 1062 break; 1063 } 1064 } 1065 1066 if (!changed) { 1067 /* 1068 * Then 'reset' the current count at 1069 * this position to it's lowest valid 1070 * value, and propagate the carry to 1071 * the next wild-card slot 1072 * 1073 * See 1113208. 1074 */ 1075 saveid[i] = 0; 1076 while (!isalnum(saveid[i])) 1077 saveid[i]++; 1078 copyid[i] = ++saveid[i]; 1079 } 1080 } 1081 } 1082 /* 1083 * changed is true if we were successful in allocating an id 1084 */ 1085 if (changed) { 1086 (void) memcpy(srcid, copyid, IDLEN); 1087 return (0); 1088 } else { 1089 return (-1); 1090 } 1091 } 1092 1093 1094 /* 1095 * lockutx - lock utmpx file 1096 */ 1097 static int 1098 lockutx(void) 1099 { 1100 int lockfd; 1101 1102 if ((lockfd = open(UTMPX_FILE, O_RDWR|O_CREAT, 0644)) < 0) 1103 return (-1); 1104 1105 if (lockf(lockfd, F_LOCK, 0) < 0) { 1106 (void) close(lockfd); 1107 return (-1); 1108 } 1109 1110 tempfd = fd; 1111 fd = lockfd; 1112 1113 return (0); 1114 1115 } 1116 1117 1118 1119 /* 1120 * unlockutx - unlock utmpx file 1121 */ 1122 static void 1123 unlockutx(void) 1124 { 1125 (void) lockf(fd, F_ULOCK, 0); 1126 (void) close(fd); 1127 fd = tempfd; 1128 } 1129 1130 1131 /* 1132 * sendpid - send message to init to add or remove a pid from the 1133 * "godchild" list 1134 * 1135 * args: cmd - ADDPID or REMPID 1136 * pid - pid of "godchild" 1137 */ 1138 static void 1139 sendpid(int cmd, pid_t pid) 1140 { 1141 int pfd; /* file desc. for init pipe */ 1142 pidrec_t prec; /* place for message to be built */ 1143 1144 /* 1145 * if for some reason init didn't open initpipe, open it read/write 1146 * here to avoid sending SIGPIPE to the calling process 1147 */ 1148 pfd = open(IPIPE, O_RDWR); 1149 if (pfd < 0) 1150 return; 1151 prec.pd_pid = pid; 1152 prec.pd_type = cmd; 1153 (void) write(pfd, &prec, sizeof (pidrec_t)); 1154 (void) close(pfd); 1155 } 1156 1157 /* 1158 * makeutx - create a utmpx entry, recycling an id if a wild card is 1159 * specified. Also notify init about the new pid 1160 * 1161 * args: utmpx - point to utmpx structure to be created 1162 */ 1163 1164 struct utmpx * 1165 makeutx(const struct utmpx *utmp) 1166 { 1167 struct utmpx *utp; 1168 struct futmpx *ut; /* "current" utmpx being examined */ 1169 unsigned char saveid[IDLEN]; /* the last id we matched that was */ 1170 /* NOT a dead proc */ 1171 int falphanum = 0x30; /* first alpha num char */ 1172 off_t offset; 1173 1174 /* 1175 * Are any wild card char's present in the idlen string? 1176 */ 1177 if (memchr(utmp->ut_id, SC_WILDC, IDLEN) != NULL) { 1178 /* 1179 * try to lock the utmpx file, only needed if 1180 * we're doing wildcard matching 1181 */ 1182 if (lockutx()) 1183 return (NULL); 1184 1185 /* 1186 * used in allocid 1187 */ 1188 (void) memset(saveid, falphanum, IDLEN); 1189 1190 while (ut = getoneutx(&offset)) 1191 if (idcmp(utmp->ut_id, ut->ut_id)) { 1192 continue; 1193 } else { 1194 /* 1195 * Found a match. We are done if this is 1196 * a free slot. Else record this id. We 1197 * will need it to generate the next new id. 1198 */ 1199 if (ut->ut_type == DEAD_PROCESS) 1200 break; 1201 else 1202 (void) memcpy(saveid, ut->ut_id, 1203 IDLEN); 1204 } 1205 1206 if (ut) { 1207 1208 /* 1209 * Unused entry, reuse it. We know the offset. So 1210 * just go to that offset utmpx and write it out. 1211 */ 1212 (void) memcpy((caddr_t)utmp->ut_id, ut->ut_id, IDLEN); 1213 1214 putoneutx(utmp, offset); 1215 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1216 unlockutx(); 1217 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1218 return ((struct utmpx *)utmp); 1219 } else { 1220 /* 1221 * nothing available, allocate an id and 1222 * write it out at the end. 1223 */ 1224 1225 if (allocid((char *)utmp->ut_id, saveid)) { 1226 unlockutx(); 1227 return (NULL); 1228 } else { 1229 /* 1230 * Seek to end and write out the entry 1231 * and also update the utmpx file. 1232 */ 1233 (void) lseek(fd, 0L, SEEK_END); 1234 offset = lseek(fd, 0L, SEEK_CUR); 1235 1236 putoneutx(utmp, offset); 1237 updwtmpx(WTMPX_FILE, (struct utmpx *)utmp); 1238 unlockutx(); 1239 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1240 return ((struct utmpx *)utmp); 1241 } 1242 } 1243 } else { 1244 utp = pututxline(utmp); 1245 if (utp) 1246 updwtmpx(WTMPX_FILE, utp); 1247 endutxent(); 1248 sendpid(ADDPID, (pid_t)utmp->ut_pid); 1249 return (utp); 1250 } 1251 } 1252 1253 /* 1254 * makeut - create a utmp entry, recycling an id if a wild card is 1255 * specified. Also notify init about the new pid 1256 * 1257 * args: utmp - point to utmp structure to be created 1258 */ 1259 struct utmp * 1260 makeut(struct utmp *utmp) 1261 { 1262 struct utmpx utmpx; 1263 struct utmpx *utmpx2; 1264 1265 if (compat_utmpflag) 1266 return (_compat_makeut(utmp)); 1267 1268 getutmpx(utmp, &utmpx); 1269 if ((utmpx2 = makeutx(&utmpx)) == NULL) 1270 return (NULL); 1271 1272 getutmp(utmpx2, utmp); 1273 return (utmp); 1274 } 1275 1276 1277 #define UTMPNBUF 200 /* Approx 8k (FS Block) size */ 1278 static struct futmpx *utmpbuf = NULL; 1279 1280 /* 1281 * Buffered read routine to get one entry from utmpx file 1282 */ 1283 static struct futmpx * 1284 getoneutx(off_t *off) 1285 { 1286 static size_t idx = 0; /* Current index in the utmpbuf */ 1287 static size_t nidx = 0; /* Max entries in this utmpbuf */ 1288 static int nbuf = 0; /* number of utmpbufs read from disk */ 1289 ssize_t nbytes, bufsz = sizeof (struct futmpx) * UTMPNBUF; 1290 1291 if (utmpbuf == NULL) 1292 if ((utmpbuf = malloc(bufsz)) == NULL) { 1293 perror("malloc"); 1294 return (NULL); 1295 } 1296 1297 if (idx == nidx) { 1298 /* 1299 * We have read all entries in the utmpbuf. Read 1300 * the buffer from the disk. 1301 */ 1302 if ((nbytes = read(fd, utmpbuf, bufsz)) < bufsz) { 1303 /* 1304 * Partial read only. keep count of the 1305 * number of valid entries in the buffer 1306 */ 1307 nidx = nbytes / sizeof (struct futmpx); 1308 } else { 1309 /* 1310 * We read in the full UTMPNBUF entries 1311 * Great ! 1312 */ 1313 nidx = UTMPNBUF; 1314 } 1315 nbuf++; /* Number of buf we have read in. */ 1316 idx = 0; /* reset index within utmpbuf */ 1317 } 1318 1319 /* 1320 * Current offset of this buffer in the file 1321 */ 1322 *off = (((nbuf - 1) * UTMPNBUF) + idx) * sizeof (struct futmpx); 1323 1324 if (idx < nidx) { 1325 /* 1326 * We still have at least one valid buffer in 1327 * utmpbuf to be passed to the caller. 1328 */ 1329 return (&utmpbuf[idx++]); 1330 } 1331 1332 /* 1333 * Reached EOF. Return NULL. Offset is set correctly 1334 * to append at the end of the file 1335 */ 1336 1337 return (NULL); 1338 } 1339 1340 static void 1341 putoneutx(const struct utmpx *utpx, off_t off) 1342 { 1343 struct futmpx futx; 1344 1345 utmpx_api2frec(utpx, &futx); 1346 (void) lseek(fd, off, SEEK_SET); /* seek in the utmpx file */ 1347 (void) write(fd, &futx, sizeof (futx)); 1348 } 1349 1350 /* 1351 * sendupid - send message to utmpd to add or remove a pid from the 1352 * list of procs to watch 1353 * 1354 * args: cmd - ADDPID or REMPID 1355 * pid - process ID of process to watch 1356 */ 1357 static void 1358 sendupid(int cmd, pid_t pid) 1359 { 1360 int pfd; /* file desc. for utmp pipe */ 1361 pidrec_t prec; /* place for message to be built */ 1362 1363 /* 1364 * if for some reason utmp didn't open utmppipe, open it read/write 1365 * here to avoid sending SIGPIPE to the calling process 1366 */ 1367 1368 pfd = open(UPIPE, O_RDWR | O_NONBLOCK | O_NDELAY); 1369 if (pfd < 0) 1370 return; 1371 prec.pd_pid = pid; 1372 prec.pd_type = cmd; 1373 (void) write(pfd, &prec, sizeof (pidrec_t)); 1374 (void) close(pfd); 1375 } 1376 1377 /* 1378 * getutmpx - convert a utmp record into a utmpx record 1379 */ 1380 void 1381 getutmpx(const struct utmp *ut, struct utmpx *utx) 1382 { 1383 (void) memcpy(utx->ut_user, ut->ut_user, sizeof (ut->ut_user)); 1384 (void) bzero(&utx->ut_user[sizeof (ut->ut_user)], 1385 sizeof (utx->ut_user) - sizeof (ut->ut_user)); 1386 (void) memcpy(utx->ut_line, ut->ut_line, sizeof (ut->ut_line)); 1387 (void) bzero(&utx->ut_line[sizeof (ut->ut_line)], 1388 sizeof (utx->ut_line) - sizeof (ut->ut_line)); 1389 (void) memcpy(utx->ut_id, ut->ut_id, sizeof (ut->ut_id)); 1390 utx->ut_pid = ut->ut_pid; 1391 utx->ut_type = ut->ut_type; 1392 utx->ut_exit = ut->ut_exit; 1393 utx->ut_tv.tv_sec = ut->ut_time; 1394 utx->ut_tv.tv_usec = 0; 1395 utx->ut_session = 0; 1396 bzero(utx->pad, sizeof (utx->pad)); 1397 bzero(utx->ut_host, sizeof (utx->ut_host)); 1398 utx->ut_syslen = 0; 1399 } 1400 1401 /* 1402 * getutmp - convert a utmpx record into a utmp record 1403 */ 1404 void 1405 getutmp(const struct utmpx *utx, struct utmp *ut) 1406 { 1407 (void) memcpy(ut->ut_user, utx->ut_user, sizeof (ut->ut_user)); 1408 (void) memcpy(ut->ut_line, utx->ut_line, sizeof (ut->ut_line)); 1409 (void) memcpy(ut->ut_id, utx->ut_id, sizeof (utx->ut_id)); 1410 ut->ut_pid = utx->ut_pid; 1411 ut->ut_type = utx->ut_type; 1412 ut->ut_exit = utx->ut_exit; 1413 ut->ut_time = utx->ut_tv.tv_sec; 1414 } 1415