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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include "includes.h" 28 #include "atomicio.h" 29 #include "auth.h" 30 #include "bufaux.h" 31 #include "buffer.h" 32 #include "cipher.h" 33 #include "compat.h" 34 #include "dispatch.h" 35 #include "getput.h" 36 #include "kex.h" 37 #include "log.h" 38 #include "mac.h" 39 #include "packet.h" 40 #include "uidswap.h" 41 #include "ssh2.h" 42 #include "sshlogin.h" 43 #include "xmalloc.h" 44 #include "altprivsep.h" 45 #include <fcntl.h> 46 #include <sys/types.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <sys/socket.h> 50 51 extern Kex *xxx_kex; 52 53 static Buffer to_monitor; 54 static Buffer from_monitor; 55 56 /* 57 * Sun's Alternative Privilege Separation basics: 58 * 59 * Abstract 60 * -------- 61 * 62 * sshd(1M) fork()s and drops privs in the child while retaining privs 63 * in the parent (a.k.a., the monitor). The unprivileged sshd and the 64 * monitor talk over a pipe using a simple protocol. 65 * 66 * The monitor protocol is all about having the monitor carry out the 67 * only operations that require privileges OR access to privileged 68 * resources. These are: utmpx/wtmpx record keeping, auditing, and 69 * SSHv2 re-keying. 70 * 71 * Re-Keying 72 * --------- 73 * 74 * Re-keying is the only protocol version specific aspect of sshd in 75 * which the monitor gets involved. 76 * 77 * The monitor processes all SSHv2 re-key protocol packets, but the 78 * unprivileged sshd process does the transport layer crypto for those 79 * packets. 80 * 81 * The monitor and its unprivileged sshd child process treat 82 * SSH_MSG_NEWKEYS SSH2 messages specially: a) the monitor does not call 83 * set_newkeys(), but b) the child asks the monitor for the set of 84 * negotiated algorithms, key, IV and what not for the relevant 85 * transport direction and then calls set_newkeys(). 86 * 87 * Monitor Protocol 88 * ---------------- 89 * 90 * Monitor IPC message formats are similar to SSHv2 messages, minus 91 * compression, encryption, padding and MACs: 92 * 93 * - 4 octet message length 94 * - message data 95 * - 1 octet message type 96 * - message data 97 * 98 * In broad strokes: 99 * 100 * - IPC: pipe, exit(2)/wait4(2) 101 * 102 * - threads: the monitor and child are single-threaded 103 * 104 * - monitor main loop: a variant of server_loop2(), for re-keying only 105 * - unpriv child main loop: server_loop2(), as usual 106 * 107 * - protocol: 108 * - key exchange packets are always forwarded as is to the monitor 109 * - newkeys, record_login(), record_logout() are special packets 110 * using the packet type range reserved for local extensions 111 * 112 * - the child drops privs and runs like a normal sshd, except that it 113 * sets dispatch handlers for key exchange packets that forward the 114 * packets to the monitor 115 * 116 * Event loops: 117 * 118 * - all monitor protocols are synchronous: because the SSHv2 rekey 119 * protocols are synchronous and because the other monitor operations 120 * are synchronous (or have no replies), 121 * 122 * - server_loop2() is modified to check the monitor pipe for rekey 123 * packets to forward to the client 124 * 125 * - and dispatch handlers are set, upon receipt of KEXINIT (and reset 126 * when NEWKEYS is sent out) to forward incoming rekey packets to the 127 * monitor. 128 * 129 * - the monitor runs an event loop not unlike server_loop2() and runs 130 * key exchanges almost exactly as a pre-altprivsep sshd would 131 * 132 * - unpriv sshd exit -> monitor cleanup (including audit logout) and exit 133 * 134 * - fatal() in monitor -> forcibly shutdown() socket and kill/wait for 135 * child (so that the audit event for the logout better reflects 136 * reality -- i.e., logged out means logged out, but for bg jobs) 137 * 138 * Message formats: 139 * 140 * - key exchange packets/replies forwarded "as is" 141 * 142 * - all other monitor requests are sent as SSH2_PRIV_MSG_ALTPRIVSEP and have a 143 * sub-type identifier (one octet) 144 * - private request sub-types include: 145 * - get new shared secret from last re-key 146 * - record login (utmpx/wtmpx), request data contains three arguments: 147 * pid, ttyname, program name 148 * - record logout (utmpx/wtmpx), request data contains one argument: pid 149 * 150 * Reply sub-types include: 151 * 152 * - NOP (for record_login/logout) 153 * - new shared secret from last re-key 154 */ 155 156 static int aps_started = 0; 157 static int is_monitor = 0; 158 159 static pid_t monitor_pid, child_pid; 160 static int pipe_fds[2]; 161 static int pipe_fd = -1; 162 static Buffer input_pipe, output_pipe; /* for pipe I/O */ 163 164 static Authctxt *xxx_authctxt; 165 166 /* Monitor functions */ 167 extern void aps_monitor_loop(Authctxt *authctxt, int pipe, pid_t child_pid); 168 static void aps_record_login(void); 169 static void aps_record_logout(void); 170 171 /* Altprivsep packet utilities for communication with the monitor */ 172 static void altprivsep_packet_start(u_char); 173 static int altprivsep_packet_send(void); 174 static int altprivsep_fwd_packet(u_char type); 175 176 static int altprivsep_packet_read(void); 177 static void altprivsep_packet_read_expect(int type); 178 179 static void altprivsep_packet_put_char(int ch); 180 static void altprivsep_packet_put_int(u_int value); 181 static void altprivsep_packet_put_cstring(const char *str); 182 static void altprivsep_packet_put_raw(const void *buf, u_int len); 183 184 static u_int altprivsep_packet_get_char(void); 185 static void *altprivsep_packet_get_raw(u_int *length_ptr); 186 static void *altprivsep_packet_get_string(u_int *length_ptr); 187 188 /* 189 * Start monitor from privileged sshd process. 190 * 191 * Return values are like fork(2); the parent is the monitor. The caller should 192 * fatal() on error. 193 * 194 * Privileges are dropped, on the unprivileged side, upon success. 195 */ 196 pid_t 197 altprivsep_start_monitor(Authctxt *authctxt) 198 { 199 pid_t pid; 200 int junk; 201 202 if (aps_started || authctxt == NULL || authctxt->pw == NULL) 203 fatal("Monitor startup failed: missing state"); 204 205 xxx_authctxt = authctxt; 206 207 packet_set_server(); 208 209 buffer_init(&output_pipe); 210 buffer_init(&input_pipe); 211 212 if (pipe(pipe_fds) != 0) { 213 error("Monitor startup failure: could not create pipes: %s", 214 strerror(errno)); 215 return (-1); 216 } 217 218 (void) fcntl(pipe_fds[0], F_SETFD, FD_CLOEXEC); 219 (void) fcntl(pipe_fds[1], F_SETFD, FD_CLOEXEC); 220 221 monitor_pid = getpid(); 222 223 if ((pid = fork()) > 0) { 224 /* parent */ 225 child_pid = pid; 226 227 debug2("Monitor pid %ld, unprivileged child pid %ld", 228 monitor_pid, child_pid); 229 230 (void) close(pipe_fds[1]); 231 232 pipe_fd = pipe_fds[0]; 233 234 if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 235 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 236 237 /* signal readiness of monitor */ 238 (void) write(pipe_fd, &pid, sizeof (pid)); 239 240 aps_started = 1; 241 is_monitor = 1; 242 243 debug2("Monitor started"); 244 245 set_log_txt_prefix("monitor "); 246 247 return (pid); 248 249 } 250 251 if (pid < 0) { 252 debug2("Monitor startup failure: could not fork unprivileged" 253 " process: %s", strerror(errno)); 254 return (pid); 255 } 256 257 /* caller should drop privs */ 258 259 (void) close(pipe_fds[0]); 260 261 pipe_fd = pipe_fds[1]; 262 263 /* wait for monitor to be ready */ 264 debug2("Waiting for monitor"); 265 (void) read(pipe_fd, &junk, sizeof (junk)); 266 debug2("Monitor signalled readiness"); 267 268 if (fcntl(pipe_fd, F_SETFL, O_NONBLOCK) < 0) 269 error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 270 271 buffer_init(&to_monitor); 272 buffer_init(&from_monitor); 273 274 if (compat20) { 275 debug3("Setting handler to forward re-key packets to monitor"); 276 dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 277 &altprivsep_rekey); 278 } 279 280 /* AltPrivSep interfaces are set up */ 281 aps_started = 1; 282 return (pid); 283 } 284 285 int 286 altprivsep_get_pipe_fd(void) 287 { 288 return (pipe_fd); 289 } 290 291 void 292 altprivsep_rekey(int type, u_int32_t seq, void *ctxt) 293 { 294 Kex *kex = (Kex *)ctxt; 295 296 if (kex == NULL) 297 fatal("Missing key exchange context in unprivileged process"); 298 299 debug2("Forwarding re-key packet (%d) to monitor", type); 300 301 if (type != SSH2_MSG_NEWKEYS) 302 if (!altprivsep_fwd_packet(type)) 303 fatal("Monitor not responding"); 304 305 /* tell server_loop2() that we're re-keying */ 306 kex->done = 0; 307 308 /* NEWKEYS is special: get the new keys for client->server direction */ 309 if (type == SSH2_MSG_NEWKEYS) { 310 debug2("Getting new inbound keystate from monitor"); 311 altprivsep_get_newkeys(MODE_IN); 312 kex->done = 1; 313 } 314 } 315 316 void 317 altprivsep_process_input(Kex *kex, fd_set *rset) 318 { 319 void *data; 320 int type; 321 u_int dlen; 322 323 debug2("Reading from pipe to monitor (%d)", pipe_fd); 324 325 if (pipe_fd == -1) 326 return; 327 328 if (!FD_ISSET(pipe_fd, rset)) 329 return; 330 331 if ((type = altprivsep_packet_read()) == -1) 332 fatal("Monitor not responding"); 333 334 if (!compat20) 335 return; /* shouldn't happen! but be safe */ 336 337 if (type == 0) 338 return; /* EOF -- nothing to do here */ 339 340 if (type >= SSH2_MSG_MAX) 341 fatal("Received garbage from monitor"); 342 343 debug2("Read packet type %d from pipe to monitor", (u_int)type); 344 345 if (type == SSH2_PRIV_MSG_ALTPRIVSEP) 346 return; /* shouldn't happen! */ 347 348 /* NEWKEYS is special: get the new keys for server->client direction */ 349 if (type == SSH2_MSG_NEWKEYS) { 350 debug2("Getting new outbound keystate from monitor"); 351 packet_start(SSH2_MSG_NEWKEYS); 352 packet_send(); 353 altprivsep_get_newkeys(MODE_OUT); 354 return; 355 } 356 357 data = altprivsep_packet_get_raw(&dlen); 358 359 packet_start((u_char)type); 360 361 if (data != NULL && dlen > 0) 362 packet_put_raw(data, dlen); 363 364 packet_send(); 365 } 366 367 void 368 altprivsep_do_monitor(Authctxt *authctxt, pid_t child_pid) 369 { 370 aps_monitor_loop(authctxt, pipe_fd, child_pid); 371 } 372 373 int 374 altprivsep_started(void) 375 { 376 return (aps_started); 377 } 378 379 int 380 altprivsep_is_monitor(void) 381 { 382 return (is_monitor); 383 } 384 385 /* 386 * A fatal cleanup function to forcibly shutdown the connection socket 387 */ 388 void 389 altprivsep_shutdown_sock(void *arg) 390 { 391 int sock; 392 393 if (arg == NULL) 394 return; 395 396 sock = *(int *)arg; 397 398 (void) shutdown(sock, SHUT_RDWR); 399 } 400 401 /* Calls _to_ monitor from unprivileged process */ 402 static 403 int 404 altprivsep_fwd_packet(u_char type) 405 { 406 u_int len; 407 void *data; 408 409 altprivsep_packet_start(type); 410 data = packet_get_raw(&len); 411 altprivsep_packet_put_raw(data, len); 412 413 /* packet_send()s any replies from the monitor to the client */ 414 return (altprivsep_packet_send()); 415 } 416 417 extern Newkeys *current_keys[MODE_MAX]; 418 419 /* To be called from packet.c:set_newkeys() before referencing current_keys */ 420 void 421 altprivsep_get_newkeys(enum kex_modes mode) 422 { 423 Newkeys *newkeys; 424 Comp *comp; 425 Enc *enc; 426 Mac *mac; 427 u_int len; 428 429 if (!altprivsep_started()) 430 return; 431 432 if (altprivsep_is_monitor()) 433 return; /* shouldn't happen */ 434 435 /* request new keys */ 436 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 437 altprivsep_packet_put_char(APS_MSG_NEWKEYS_REQ); 438 altprivsep_packet_put_int((u_int)mode); 439 altprivsep_packet_send(); 440 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 441 if (altprivsep_packet_get_char() != APS_MSG_NEWKEYS_REP) 442 fatal("Received garbage from monitor during re-keying"); 443 444 newkeys = xmalloc(sizeof (*newkeys)); 445 memset(newkeys, 0, sizeof (*newkeys)); 446 447 enc = &newkeys->enc; 448 mac = &newkeys->mac; 449 comp = &newkeys->comp; 450 451 /* Cipher name, key, IV */ 452 enc->name = altprivsep_packet_get_string(NULL); 453 if ((enc->cipher = cipher_by_name(enc->name)) == NULL) 454 fatal("Monitor negotiated an unknown cipher during re-key"); 455 456 enc->key = altprivsep_packet_get_string(&enc->key_len); 457 enc->iv = altprivsep_packet_get_string(&enc->block_size); 458 459 /* MAC name */ 460 mac->name = altprivsep_packet_get_string(NULL); 461 if (mac_init(mac, mac->name) < 0) 462 fatal("Monitor negotiated an unknown MAC algorithm " 463 "during re-key"); 464 465 mac->key = altprivsep_packet_get_string(&len); 466 if (len > mac->key_len) 467 fatal("%s: bad mac key length: %d > %d", __func__, len, 468 mac->key_len); 469 470 /* Compression algorithm name */ 471 comp->name = altprivsep_packet_get_string(NULL); 472 if (strcmp(comp->name, "zlib") != 0 && strcmp(comp->name, "none") != 0) 473 fatal("Monitor negotiated an unknown compression " 474 "algorithm during re-key"); 475 476 comp->type = 0; 477 comp->enabled = 0; /* forces compression re-init, as per-spec */ 478 if (strcmp(comp->name, "zlib") == 0) 479 comp->type = 1; 480 481 /* 482 * Now install new keys 483 * 484 * For now abuse kex.c/packet.c non-interfaces. Someday, when 485 * the many internal interfaces are parametrized, made reentrant 486 * and thread-safe, made more consistent, and when necessary-but- 487 * currently-missing interfaces are added then this bit of 488 * ugliness can be revisited. 489 * 490 * The ugliness is in the set_newkeys(), its name and the lack 491 * of a (Newkeys *) parameter, which forces us to pass the 492 * newkeys through current_keys[mode]. But this saves us some 493 * lines of code for now, though not comments. 494 * 495 * Also, we've abused, in the code above, knowledge of what 496 * set_newkeys() expects the current_keys[mode] to contain. 497 */ 498 current_keys[mode] = newkeys; 499 set_newkeys(mode); 500 501 } 502 503 void 504 altprivsep_record_login(pid_t pid, const char *ttyname) 505 { 506 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 507 altprivsep_packet_put_char(APS_MSG_RECORD_LOGIN); 508 altprivsep_packet_put_int(pid); 509 altprivsep_packet_put_cstring(ttyname); 510 altprivsep_packet_send(); 511 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 512 } 513 514 void 515 altprivsep_record_logout(pid_t pid) 516 { 517 altprivsep_packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 518 altprivsep_packet_put_char(APS_MSG_RECORD_LOGOUT); 519 altprivsep_packet_put_int(pid); 520 altprivsep_packet_send(); 521 altprivsep_packet_read_expect(SSH2_PRIV_MSG_ALTPRIVSEP); 522 } 523 524 static void aps_send_newkeys(void); 525 526 /* Monitor side dispatch handler for SSH2_PRIV_MSG_ALTPRIVSEP */ 527 /* ARGSUSED */ 528 void 529 aps_input_altpriv_msg(int type, u_int32_t seq, void *ctxt) 530 { 531 u_char req_type; 532 533 req_type = packet_get_char(); 534 535 switch (req_type) { 536 case APS_MSG_NEWKEYS_REQ: 537 aps_send_newkeys(); 538 break; 539 case APS_MSG_RECORD_LOGIN: 540 aps_record_login(); 541 break; 542 case APS_MSG_RECORD_LOGOUT: 543 aps_record_logout(); 544 break; 545 default: 546 break; 547 } 548 } 549 550 /* Monitor-side handlers for APS_MSG_* */ 551 static 552 void 553 aps_send_newkeys(void) 554 { 555 Newkeys *newkeys; 556 Enc *enc; 557 Mac *mac; 558 Comp *comp; 559 enum kex_modes mode; 560 561 /* get direction for which newkeys are wanted */ 562 mode = (enum kex_modes) packet_get_int(); 563 packet_check_eom(); 564 565 /* get those newkeys */ 566 newkeys = kex_get_newkeys(mode); 567 enc = &newkeys->enc; 568 mac = &newkeys->mac; 569 comp = &newkeys->comp; 570 571 /* 572 * Negotiated algorithms, client->server and server->client, for 573 * cipher, mac and compression. 574 */ 575 packet_start(SSH2_PRIV_MSG_ALTPRIVSEP); 576 packet_put_char(APS_MSG_NEWKEYS_REP); 577 packet_put_cstring(enc->name); 578 packet_put_string(enc->key, enc->key_len); 579 packet_put_string(enc->iv, enc->block_size); 580 packet_put_cstring(mac->name); 581 packet_put_string(mac->key, mac->key_len); 582 packet_put_cstring(comp->name); 583 584 packet_send(); 585 free_keys(newkeys); 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