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 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "includes.h" 29 #include "atomicio.h" 30 #include "auth.h" 31 #include "bufaux.h" 32 #include "buffer.h" 33 #include "cipher.h" 34 #include "compat.h" 35 #include "dispatch.h" 36 #include "getput.h" 37 #include "kex.h" 38 #include "log.h" 39 #include "mac.h" 40 #include "packet.h" 41 #include "uidswap.h" 42 #include "ssh2.h" 43 #include "sshlogin.h" 44 #include "xmalloc.h" 45 #include "altprivsep.h" 46 #include <fcntl.h> 47 #include <sys/types.h> 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <sys/socket.h> 51 52 extern Kex *xxx_kex; 53 54 static Buffer to_monitor; 55 static Buffer from_monitor; 56 57 /* 58 * Sun's Alternative Privilege Separation basics: 59 * 60 * Abstract 61 * -------- 62 * 63 * sshd(1M) fork()s and drops privs in the child while retaining privs 64 * in the parent (a.k.a., the monitor). The unprivileged sshd and the 65 * monitor talk over a pipe using a simple protocol. 66 * 67 * The monitor protocol is all about having the monitor carry out the 68 * only operations that require privileges OR access to privileged 69 * resources. These are: utmpx/wtmpx record keeping, auditing, and 70 * SSHv2 re-keying. 71 * 72 * Re-Keying 73 * --------- 74 * 75 * Re-keying is the only protocol version specific aspect of sshd in 76 * which the monitor gets involved. 77 * 78 * The monitor processes all SSHv2 re-key protocol packets, but the 79 * unprivileged sshd process does the transport layer crypto for those 80 * packets. 81 * 82 * The monitor and its unprivileged sshd child process treat 83 * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call 84 * set_newkeys(), but b) the child asks the monitor for the set of 85 * negotiated algorithms, key, IV and what not for the relevant 86 * transport direction and then calls set_newkeys(). 87 * 88 * Monitor Protocol 89 * ---------------- 90 * 91 * Monitor IPC message formats are similar to SSHv2 messages, minus 92 * compression, encryption, padding and MACs: 93 * 94 * - 4 octet message length 95 * - message data 96 * - 1 octet message type 97 * - message data 98 * 99 * In broad strokes: 100 * 101 * - IPC: pipe, exit(2)/wait4(2) 102 * 103 * - threads: the monitor and child are single-threaded 104 * 105 * - monitor main loop: a variant of server_loop2(), for re-keying only 106 * - unpriv child main loop: server_loop2(), as usual 107 * 108 * - protocol: 109 * - key exchange packets are always forwarded as is to the monitor 110 * - newkeys, record_login(), record_logout() are special packets 111 * using the packet type range reserved for local extensions 112 * 113 * - the child drops privs and runs like a normal sshd, except that it 114 * sets dispatch handlers for key exchange packets that forward the 115 * packets to the monitor 116 * 117 * Event loops: 118 * 119 * - all monitor protocols are synchronous: because the SSHv2 rekey 120 * protocols are synchronous and because the other monitor operations 121 * are synchronous (or have no replies), 122 * 123 * - server_loop2() is modified to check the monitor pipe for rekey 124 * packets to forward to the client 125 * 126 * - and dispatch handlers are set, upon receipt of KEXINIT (and reset 127 * when NEWKEYS is sent out) to forward incoming rekey packets to the 128 * monitor. 129 * 130 * - the monitor runs an event loop not unlike server_loop2() and runs 131 * key exchanges almost exactly as a pre-altprivsep sshd would 132 * 133 * - unpriv sshd exit -> monitor cleanup (including audit logout) and exit 134 * 135 * - fatal() in monitor -> forcibly shutdown() socket and kill/wait for 136 * child (so that the audit event for the logout better reflects 137 * reality -- i.e., logged out means logged out, but for bg jobs) 138 * 139 * Message formats: 140 * 141 * - key exchange packets/replies forwarded "as is" 142 * 143 * - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a 144 * sub-type identifier (one octet) 145 * - private request sub-types include: 146 * - get new shared secret from last re-key 147 * - record login (utmpx/wtmpx), request data contains three arguments: 148 * pid, ttyname, program name 149 * - record logout (utmpx/wtmpx), request data contains one argument: pid 150 * 151 * Reply sub-types include: 152 * 153 * - NOP (for record_login/logout) 154 * - new shared secret from last re-key 155 */ 156 157 static int aps_started = 0; 158 static int is_monitor = 0; 159 160 static pid_t monitor_pid, child_pid; 161 static int pipe_fds[2]; 162 static int pipe_fd = -1; 163 static Buffer input_pipe, output_pipe; /* for pipe I/O */ 164 165 static Authctxt *xxx_authctxt; 166 167 /* Monitor functions */ 168 extern void aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid); 169 static void aps_record_login(void); 170 static void aps_record_logout(void); 171 172 /* Altprivsep packet utilities for communication with the monitor */ 173 static void altprivsep_packet_start(u_char); 174 static int altprivsep_packet_send(void); 175 static int altprivsep_fwd_packet(u_char type); 176 177 static int altprivsep_packet_read(void); 178 static void altprivsep_packet_read_expect(int type); 179 180 static void altprivsep_packet_put_char(int ch); 181 static void altprivsep_packet_put_int(u_int value); 182 static void altprivsep_packet_put_cstring(const char *str); 183 static void altprivsep_packet_put_raw(const void *buf, u_int len); 184 185 static u_int altprivsep_packet_get_char(void); 186 static void *altprivsep_packet_get_raw(u_int *length_ptr); 187 static void *altprivsep_packet_get_string(u_int *length_ptr); 188 189 /* 190 * Start monitor from privileged sshd process. 191 * 192 * Return values are like fork(2); the parent is the monitor. The caller should 193 * fatal() on error. 194 * 195 * Privileges are dropped, on the unprivileged side, upon success. 196 */ 197 pid_t 198 altprivsep_start_monitor(Authctxt *authctxt) 199 { 200 pid_t pid; 201 int junk; 202 203 if (aps_started || authctxt == NULL || authctxt->pw == NULL) 204 fatal("Monitor startup failed: missing state"); 205 206 xxx_authctxt = authctxt; 207 208 packet_set_server(); 209 210 buffer_init(&output_pipe); 211 buffer_init(&input_pipe); 212 213 if (pipe(pipe_fds) != 0) { 214 error("Monitor startup failure: could not create pipes: %s", 215 strerror(errno)); 216 return (-1); 217 } 218 219 (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC); 220 (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC); 221 222 monitor_pid = getpid(); 223 224 if ((pid = fork()) > 0) { 225 /* parent */ 226 child_pid = pid; 227 228 debug2("Monitor pid %ld, unprivileged child pid %ld", 229 monitor_pid, child_pid); 230 231 (void) close(pipe_fds[1]); 232 233 pipe_fd = pipe_fds[0]; 234 235 if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 236 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 237 238 /* signal readyness of monitor */ 239 (void) write(pipe_fd, &pid, sizeof (pid)); 240 241 aps_started = 1; 242 is_monitor = 1; 243 244 debug2("Monitor started"); 245 246 set_log_txt_prefix("monitor "); 247 248 return (pid); 249 250 } 251 252 if (pid < 0) { 253 debug2("Monitor startup failure: could not fork unprivileged" 254 " process: %s", strerror(errno)); 255 return (pid); 256 } 257 258 /* caller should drop privs */ 259 260 (void) close(pipe_fds[0]); 261 262 pipe_fd = pipe_fds[1]; 263 264 /* wait for monitor to be ready */ 265 debug2("Waiting for monitor"); 266 (void) read(pipe_fd, &junk, sizeof (junk)); 267 debug2("Monitor signalled readiness"); 268 269 if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 270 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 271 272 buffer_init(&to_monitor); 273 buffer_init(&from_monitor); 274 275 if (compat20) { 276 debug3("Setting handler to forward re-key packets to monitor"); 277 dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 278 &altprivsep_rekey); 279 } 280 281 /* AltPrivSep interfaces are set up */ 282 aps_started = 1; 283 return (pid); 284 } 285 286 int 287 altprivsep_get_pipe_fd(void) 288 { 289 return (pipe_fd); 290 } 291 292 void 293 altprivsep_rekey(int type, u_int32_t seq, void *ctxt) 294 { 295 Kex *kex = (Kex *)ctxt; 296 297 if (kex == NULL) 298 fatal("Missing key exchange context in unprivileged process"); 299 300 debug2("Forwarding re-key packet (%d) to monitor", type); 301 302 if (type != SSH2_MSG_NEWKEYS) 303 if (!altprivsep_fwd_packet(type)) 304 fatal("Monitor not responding"); 305 306 /* tell server_loop2() that we're re-keying */ 307 kex->done = 0; 308 309 /* NEWKEYS is special: get the new keys for client->server direction */ 310 if (type == SSH2_MSG_NEWKEYS) { 311 debug2("Getting new inbound keystate from monitor"); 312 altprivsep_get_newkeys(MODE_IN); 313 kex->done = 1; 314 } 315 } 316 317 void 318 altprivsep_process_input(Kex *kex, fd_set *rset) 319 { 320 void *data; 321 int type; 322 u_int dlen; 323 324 debug2("Reading from pipe to monitor (%d)", pipe_fd); 325 326 if (pipe_fd == -1) 327 return; 328 329 if (!FD_ISSET(pipe_fd, rset)) 330 return; 331 332 if ((type = altprivsep_packet_read()) == -1) 333 fatal("Monitor not responding"); 334 335 if (!compat20) 336 return; /* shouldn't happen! but be safe */ 337 338 if (type == 0) 339 return; /* EOF -- nothing to do here */ 340 341 if (type >= SSH2_MSG_MAX) 342 fatal("Received garbage from monitor"); 343 344 debug2("Read packet type %d from pipe to monitor", (u_int)type); 345 346 if (type == SSH2_PRIV_MSG_ALTPRIVSEP) 347 return; /* shouldn't happen! */ 348 349 /* NEWKEYS is special: get the new keys for server->client direction */ 350 if (type == SSH2_MSG_NEWKEYS) { 351 debug2("Getting new outbound keystate from monitor"); 352 packet_start(SSH2_MSG_NEWKEYS); 353 packet_send(); 354 altprivsep_get_newkeys(MODE_OUT); 355 return; 356 } 357 358 data = altprivsep_packet_get_raw(&dlen); 359 360 packet_start((u_char)type); 361 362 if (data != NULL && dlen > 0) 363 packet_put_raw(data, dlen); 364 365 packet_send(); 366 } 367 368 void 369 altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid) 370 { 371 aps_monitor_loop(authctxt, pipe_fd, child_pid); 372 } 373 374 int 375 altprivsep_started(void) 376 { 377 return (aps_started); 378 } 379 380 int 381 altprivsep_is_monitor(void) 382 { 383 return (is_monitor); 384 } 385 386 /* 387 * A fatal cleanup function to forcibly shutdown the connection socket 388 */ 389 void 390 altprivsep_shutdown_sock(void *arg) 391 { 392 int sock; 393 394 if (arg == NULL) 395 return; 396 397 sock = *(int *)arg; 398 399 (void) shutdown(sock, SHUT_RDWR); 400 } 401 402 /* Calls _to_ monitor from unprivileged process */ 403 static 404 int 405 altprivsep_fwd_packet(u_char type) 406 { 407 u_int len; 408 void *data; 409 410 altprivsep_packet_start(type); 411 data = packet_get_raw(&len); 412 altprivsep_packet_put_raw(data, len); 413 414 /* packet_send()s any replies from the monitor to the client */ 415 return (altprivsep_packet_send()); 416 } 417 418 extern Newkeys *current_keys[MODE_MAX]; 419 420 /* To be called from packet.c:set_newkeys() before referencing current_keys */ 421 void 422 altprivsep_get_newkeys(enum kex_modes mode) 423 { 424 Newkeys *newkeys; 425 Comp *comp; 426 Enc *enc; 427 Mac *mac; 428 u_int len; 429 430 if (!altprivsep_started()) 431 return; 432 433 if (altprivsep_is_monitor()) 434 return; /* shouldn't happen */ 435 436 /* request new keys */ 437 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 438 altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ); 439 altprivsep_packet_put_int((u_int)mode); 440 altprivsep_packet_send(); 441 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 442 if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP) 443 fatal("Received garbage from monitor during re-keying"); 444 445 newkeys = xmalloc(sizeof (*newkeys)); 446 memset(newkeys, 0, sizeof (*newkeys)); 447 448 enc = &newkeys->enc; 449 mac = &newkeys->mac; 450 comp = &newkeys->comp; 451 452 /* Cipher name, key, IV */ 453 enc->name = altprivsep_packet_get_string(NULL); 454 if ((enc->cipher = cipher_by_name(enc->name)) == NULL) 455 fatal("Monitor negotiated an unknown cipher during re-key"); 456 457 enc->key = altprivsep_packet_get_string(&enc->key_len); 458 enc->iv = altprivsep_packet_get_string(&enc->block_size); 459 460 /* MAC name */ 461 mac->name = altprivsep_packet_get_string(NULL); 462 if (mac_init(mac, mac->name) < 0) 463 fatal("Monitor negotiated an unknown MAC algorithm " 464 "during re-key"); 465 466 mac->key = altprivsep_packet_get_string(&len); 467 if (len > mac->key_len) 468 fatal("%s: bad mac key length: %d > %d", __func__, len, 469 mac->key_len); 470 471 /* Compression algorithm name */ 472 comp->name = altprivsep_packet_get_string(NULL); 473 if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0) 474 fatal("Monitor negotiated an unknown compression " 475 "algorithm during re-key"); 476 477 comp->type = 0; 478 comp->enabled = 0; /* forces compression re-init, as per-spec */ 479 if (strcmp(comp->name, "zlib") == 0) 480 comp->type = 1; 481 482 /* 483 * Now install new keys 484 * 485 * For now abuse kex.c/packet.c non-interfaces. Someday, when 486 * the many internal interfaces are parametrized, made reentrant 487 * and thread-safe, made more consistent, and when necessary-but- 488 * currently-missing interfaces are added then this bit of 489 * ugliness can be revisited. 490 * 491 * The ugliness is in the set_newkeys(), its name and the lack 492 * of a (Newkeys *) parameter, which forces us to pass the 493 * newkeys through current_keys[mode]. But this saves us some 494 * lines of code for now, though not comments. 495 * 496 * Also, we've abused, in the code above, knowledge of what 497 * set_newkeys() expects the current_keys[mode] to contain. 498 */ 499 current_keys[mode] = newkeys; 500 set_newkeys(mode); 501 502 } 503 504 void 505 altprivsep_record_login(pid_t pid, const char *ttyname) 506 { 507 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 508 altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN); 509 altprivsep_packet_put_int(pid); 510 altprivsep_packet_put_cstring(ttyname); 511 altprivsep_packet_send(); 512 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 513 } 514 515 void 516 altprivsep_record_logout(pid_t pid) 517 { 518 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 519 altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT); 520 altprivsep_packet_put_int(pid); 521 altprivsep_packet_send(); 522 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 523 } 524 525 static void aps_send_newkeys(void); 526 527 /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */ 528 /* ARGSUSED */ 529 void 530 aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt) 531 { 532 u_char req_type; 533 534 req_type = packet_get_char(); 535 536 switch (req_type) { 537 case APS_MSG_NEWKEYS_REQ: 538 aps_send_newkeys(); 539 break; 540 case APS_MSG_RECORD_LOGIN: 541 aps_record_login(); 542 break; 543 case APS_MSG_RECORD_LOGOUT: 544 aps_record_logout(); 545 break; 546 default: 547 break; 548 } 549 } 550 551 /* Monitor-side handlers for APS_MSG_* */ 552 static 553 void 554 aps_send_newkeys(void) 555 { 556 Newkeys *newkeys; 557 Enc *enc; 558 Mac *mac; 559 Comp *comp; 560 enum kex_modes mode; 561 562 /* get direction for which newkeys are wanted */ 563 mode = (enum kex_modes) packet_get_int(); 564 packet_check_eom(); 565 566 /* get those newkeys */ 567 newkeys = kex_get_newkeys(mode); 568 enc = &newkeys->enc; 569 mac = &newkeys->mac; 570 comp = &newkeys->comp; 571 572 /* 573 * Negotiated algorithms, client->server and server->client, for 574 * cipher, mac and compression. 575 */ 576 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 577 packet_put_char(APS_MSG_NEWKEYS_REP); 578 packet_put_cstring(enc->name); 579 packet_put_string(enc->key, enc->key_len); 580 packet_put_string(enc->iv, enc->block_size); 581 packet_put_cstring(mac->name); 582 packet_put_string(mac->key, mac->key_len); 583 packet_put_cstring(comp->name); 584 585 packet_send(); 586 } 587 588 struct _aps_login_rec { 589 pid_t lr_pid; 590 char *lr_tty; 591 struct _aps_login_rec *next; 592 }; 593 594 typedef struct _aps_login_rec aps_login_rec; 595 596 static aps_login_rec *aps_login_list = NULL; 597 598 static 599 void 600 aps_record_login(void) 601 { 602 aps_login_rec *new_rec; 603 struct stat sbuf; 604 size_t proc_path_len; 605 char *proc_path; 606 607 new_rec = xmalloc(sizeof (aps_login_rec)); 608 memset(new_rec, 0, sizeof (aps_login_rec)); 609 610 new_rec->lr_pid = packet_get_int(); 611 new_rec->lr_tty = packet_get_string(NULL); 612 613 proc_path_len = snprintf(NULL, 0, "/proc/%d", new_rec->lr_pid); 614 proc_path = xmalloc(proc_path_len + 1); 615 (void) snprintf(proc_path, proc_path_len + 1, "/proc/%d", 616 new_rec->lr_pid); 617 618 if (stat(proc_path, &sbuf) || 619 sbuf.st_uid != xxx_authctxt->pw->pw_uid || 620 stat(new_rec->lr_tty, &sbuf) < 0 || 621 sbuf.st_uid != xxx_authctxt->pw->pw_uid) { 622 debug2("Spurious record_login request from unprivileged sshd"); 623 xfree(proc_path); 624 xfree(new_rec->lr_tty); 625 xfree(new_rec); 626 return; 627 } 628 629 /* Insert new record on list */ 630 new_rec->next = aps_login_list; 631 aps_login_list = new_rec; 632 633 record_login(new_rec->lr_pid, new_rec->lr_tty, NULL, 634 xxx_authctxt->user); 635 636 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 637 packet_send(); 638 639 xfree(proc_path); 640 } 641 642 static 643 void 644 aps_record_logout(void) 645 { 646 aps_login_rec **p, *q; 647 pid_t pid; 648 649 pid = packet_get_int(); 650 packet_check_eom(); 651 652 for (p = &aps_login_list; *p != NULL; p = &q->next) { 653 q = *p; 654 if (q->lr_pid == pid) { 655 record_logout(q->lr_pid, q->lr_tty, NULL, 656 xxx_authctxt->user); 657 658 /* dequeue */ 659 *p = q->next; 660 xfree(q->lr_tty); 661 xfree(q); 662 break; 663 } 664 } 665 666 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 667 packet_send(); 668 } 669 670 /* Utilities for communication with the monitor */ 671 static 672 void 673 altprivsep_packet_start(u_char type) 674 { 675 buffer_clear(&to_monitor); 676 buffer_put_char(&to_monitor, type); 677 } 678 static 679 void 680 altprivsep_packet_put_char(int ch) 681 { 682 buffer_put_char(&to_monitor, ch); 683 } 684 static 685 void 686 altprivsep_packet_put_int(u_int value) 687 { 688 buffer_put_int(&to_monitor, value); 689 } 690 static 691 void 692 altprivsep_packet_put_cstring(const char *str) 693 { 694 buffer_put_cstring(&to_monitor, str); 695 } 696 static 697 void 698 altprivsep_packet_put_raw(const void *buf, u_int len) 699 { 700 buffer_append(&to_monitor, buf, len); 701 } 702 703 /* 704 * Send a monitor packet to the monitor. This function is blocking. 705 * 706 * Returns -1 if the monitor pipe has been closed earlier, fatal()s if 707 * there's any other problems. 708 */ 709 static 710 int 711 altprivsep_packet_send(void) 712 { 713 ssize_t len; 714 u_int32_t plen; /* packet length */ 715 u_char plen_buf[sizeof (plen)]; 716 u_char padlen; /* padding length */ 717 fd_set *setp; 718 719 if (pipe_fd == -1) 720 return (-1); 721 722 if ((plen = buffer_len(&to_monitor)) == 0) 723 return (0); 724 725 /* 726 * We talk the SSHv2 binary packet protocol to the monitor, 727 * using the none cipher, mac and compression algorithms. 728 * 729 * But, interestingly, the none cipher has a block size of 8 730 * bytes, thus we must pad the packet. 731 * 732 * Also, encryption includes the packet length, so the padding 733 * must account for that field. I.e., (sizeof (packet length) + 734 * sizeof (padding length) + packet length + padding length) % 735 * block_size must == 0. 736 * 737 * Also, there must be at least four (4) bytes of padding. 738 */ 739 padlen = (8 - ((plen + sizeof (plen) + sizeof (padlen)) % 8)) % 8; 740 if (padlen < 4) 741 padlen += 8; 742 743 /* packet length counts padding and padding length field */ 744 plen += padlen + sizeof (padlen); 745 746 PUT_32BIT(plen_buf, plen); 747 748 setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 749 memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 750 FD_SET(pipe_fd, setp); 751 752 while (select(pipe_fd + 1, NULL, setp, NULL, NULL) == -1) { 753 if (errno == EAGAIN || errno == EINTR) 754 continue; 755 else 756 goto pipe_gone; 757 } 758 759 xfree(setp); 760 761 /* packet length field */ 762 len = atomicio(write, pipe_fd, plen_buf, sizeof (plen)); 763 764 if (len != sizeof (plen)) 765 goto pipe_gone; 766 767 /* padding length field */ 768 len = atomicio(write, pipe_fd, &padlen, sizeof (padlen)); 769 770 if (len != sizeof (padlen)) 771 goto pipe_gone; 772 773 len = atomicio(write, pipe_fd, buffer_ptr(&to_monitor), plen - 1); 774 775 if (len != (plen - 1)) 776 goto pipe_gone; 777 778 buffer_clear(&to_monitor); 779 780 return (1); 781 782 pipe_gone: 783 784 (void) close(pipe_fd); 785 786 pipe_fd = -1; 787 788 fatal("Monitor not responding"); 789 790 /* NOTREACHED */ 791 return (0); 792 } 793 794 /* 795 * Read a monitor packet from the monitor. This function is blocking. 796 */ 797 static 798 int 799 altprivsep_packet_read(void) 800 { 801 ssize_t len = -1; 802 u_int32_t plen; 803 u_char plen_buf[sizeof (plen)]; 804 u_char padlen; 805 fd_set *setp; 806 807 if (pipe_fd == -1) 808 return (-1); 809 810 setp = xmalloc(howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 811 memset(setp, 0, howmany(pipe_fd + 1, NFDBITS) * sizeof (fd_mask)); 812 FD_SET(pipe_fd, setp); 813 814 while (select(pipe_fd + 1, setp, NULL, NULL, NULL) == -1) { 815 if (errno == EAGAIN || errno == EINTR) 816 continue; 817 else 818 goto pipe_gone; 819 } 820 821 xfree(setp); 822 823 /* packet length field */ 824 len = atomicio(read, pipe_fd, plen_buf, sizeof (plen)); 825 826 plen = GET_32BIT(plen_buf); 827 828 if (len != sizeof (plen)) 829 goto pipe_gone; 830 831 /* padding length field */ 832 len = atomicio(read, pipe_fd, &padlen, sizeof (padlen)); 833 834 if (len != sizeof (padlen)) 835 goto pipe_gone; 836 837 plen -= sizeof (padlen); 838 839 buffer_clear(&from_monitor); 840 buffer_append_space(&from_monitor, plen); 841 842 /* packet data + padding */ 843 len = atomicio(read, pipe_fd, buffer_ptr(&from_monitor), plen); 844 845 if (len != plen) 846 goto pipe_gone; 847 848 /* remove padding */ 849 if (padlen > 0) 850 buffer_consume_end(&from_monitor, padlen); 851 852 /* packet type */ 853 return (buffer_get_char(&from_monitor)); 854 855 pipe_gone: 856 857 (void) close(pipe_fd); 858 859 pipe_fd = -1; 860 861 if (len < 0) 862 fatal("Monitor not responding"); 863 864 debug2("Monitor pipe closed by monitor"); 865 return (0); 866 } 867 868 static 869 void 870 altprivsep_packet_read_expect(int expected) 871 { 872 int type; 873 874 type = altprivsep_packet_read(); 875 876 if (type <= 0) 877 fatal("Monitor not responding"); 878 879 if (type != expected) 880 fatal("Protocol error in privilege separation; expected " 881 "packet type %d, got %d", expected, type); 882 } 883 884 static 885 u_int 886 altprivsep_packet_get_char(void) 887 { 888 return (buffer_get_char(&from_monitor)); 889 } 890 void 891 *altprivsep_packet_get_raw(u_int *length_ptr) 892 { 893 if (length_ptr != NULL) 894 *length_ptr = buffer_len(&from_monitor); 895 896 return (buffer_ptr(&from_monitor)); 897 } 898 void 899 *altprivsep_packet_get_string(u_int *length_ptr) 900 { 901 return (buffer_get_string(&from_monitor, length_ptr)); 902 } 903