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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * transport layer for audit_remote (handles connection establishment, gss 26 * context initialization, message encryption and verification) 27 * 28 */ 29 30 #include <assert.h> 31 #include <audit_plugin.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <gssapi/gssapi.h> 35 #include <libintl.h> 36 #include <mtmalloc.h> 37 #include <netdb.h> 38 #include <netinet/in.h> 39 #include <netinet/tcp.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <strings.h> 44 #include <syslog.h> 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <unistd.h> 48 #include <poll.h> 49 #include <pthread.h> 50 51 #include "audit_remote.h" 52 53 54 static int sockfd = -1; 55 static struct hostent *current_host; 56 static gss_OID *current_mech_oid; 57 static in_port_t current_port; 58 static boolean_t flush_transq; 59 60 static char *ver_str = "01"; /* supported protocol version */ 61 static char *ver_str_concat; /* concat serv/client version */ 62 63 static gss_ctx_id_t gss_ctx; 64 static boolean_t gss_ctx_initialized; 65 66 pthread_t recv_tid; /* receiving thread */ 67 static pthread_once_t recv_once_control = PTHREAD_ONCE_INIT; 68 69 extern int timeout; /* connection timeout */ 70 71 extern pthread_mutex_t plugin_mutex; 72 transq_hdr_t transq_hdr; 73 74 /* 75 * The three locks synchronize the simultaneous actions on top of transmission 76 * queue, socket, gss_context. 77 */ 78 pthread_mutex_t transq_lock = PTHREAD_MUTEX_INITIALIZER; 79 pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER; 80 pthread_mutex_t gss_ctx_lock = PTHREAD_MUTEX_INITIALIZER; 81 82 /* reset routine synchronization - required by the sending thread */ 83 pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER; 84 static boolean_t reset_in_progress; /* reset routine in progress */ 85 86 #define NP_CLOSE -1 /* notification pipe - close message */ 87 #define NP_EXIT -2 /* notification pipe - exit message */ 88 boolean_t notify_pipe_ready; 89 int notify_pipe[2]; /* notif. pipe - receiving thread */ 90 91 pthread_cond_t reset_cv = PTHREAD_COND_INITIALIZER; 92 static close_rsn_t recv_closure_rsn; 93 94 #define MAX_TOK_LEN (128 * 1000) /* max token length we accept (B) */ 95 96 /* transmission queue helpers */ 97 static void transq_dequeue(transq_node_t *); 98 static boolean_t transq_enqueue(transq_node_t **, gss_buffer_t, 99 uint64_t); 100 static int transq_retransmit(void); 101 102 static boolean_t init_poll(int); 103 static void do_reset(int *, struct pollfd *, boolean_t); 104 static void do_cleanup(int *, struct pollfd *, boolean_t); 105 106 static void init_recv_record(void); 107 static void *recv_record(void *); 108 static int connect_timeout(int, struct sockaddr *, int); 109 static int send_timeout(int, const char *, size_t); 110 static int recv_timeout(int, char *, size_t); 111 static int send_token(int *, gss_buffer_t); 112 static int recv_token(int, gss_buffer_t); 113 114 115 /* 116 * report_err() - wrapper, mainly due to enhance the code readability - report 117 * error to syslog via call to __audit_syslog(). 118 */ 119 static void 120 report_err(char *msg) 121 { 122 __audit_syslog("audit_remote.so", LOG_CONS | LOG_NDELAY, LOG_DAEMON, 123 LOG_ERR, msg); 124 125 } 126 127 128 /* 129 * report_gss_err() - GSS API error reporting 130 */ 131 static void 132 report_gss_err(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) 133 { 134 gss_buffer_desc msg_buf; 135 OM_uint32 _min, msg_ctx; 136 char *err_msg; 137 138 /* major stat */ 139 msg_ctx = 0; 140 do { 141 (void) gss_display_status(&_min, maj_stat, GSS_C_GSS_CODE, 142 *current_mech_oid, &msg_ctx, &msg_buf); 143 (void) asprintf(&err_msg, 144 gettext("GSS API error - %s(%u): %.*s\n"), msg, maj_stat, 145 msg_buf.length, (char *)msg_buf.value); 146 if (err_msg != NULL) { 147 report_err(err_msg); 148 free(err_msg); 149 } 150 (void) gss_release_buffer(&_min, &msg_buf); 151 } while (msg_ctx); 152 153 /* minor stat */ 154 msg_ctx = 0; 155 do { 156 (void) gss_display_status(&_min, min_stat, GSS_C_MECH_CODE, 157 *current_mech_oid, &msg_ctx, &msg_buf); 158 (void) asprintf(&err_msg, 159 gettext("GSS mech error - %s(%u): %.*s\n"), msg, min_stat, 160 msg_buf.length, (char *)msg_buf.value); 161 if (err_msg != NULL) { 162 report_err(err_msg); 163 free(err_msg); 164 } 165 (void) gss_release_buffer(&_min, &msg_buf); 166 } while (msg_ctx); 167 } 168 169 /* 170 * prot_ver_negotiate() - negotiate/acknowledge the protocol version. Currently, 171 * there is only one version supported by the plugin - "01". 172 * Note: connection must be initiated prior version negotiation 173 */ 174 static int 175 prot_ver_negotiate() 176 { 177 gss_buffer_desc out_buf, in_buf; 178 size_t ver_str_concat_sz; 179 180 /* 181 * Set the version proposal string - once we support more than 182 * version "01" this part should be extended to solve the concatenation 183 * of supported version identifiers. 184 */ 185 out_buf.value = (void *)ver_str; 186 out_buf.length = strlen((char *)out_buf.value); 187 DPRINT((dfile, "Protocol version proposal (size=%d): %.*s\n", 188 out_buf.length, out_buf.length, (char *)out_buf.value)); 189 190 if (send_token(&sockfd, &out_buf) < 0) { 191 DPRINT((dfile, "Sending protocol version token failed\n")); 192 return (-1); 193 } 194 195 if (recv_token(sockfd, &in_buf) < 0) { 196 DPRINT((dfile, "Receiving protocol version token failed\n")); 197 return (-1); 198 } 199 200 /* 201 * Verify the sent/received string - memcmp() is sufficient here 202 * because we support only one version and it is represented by 203 * the "01" string. The received version has to be "01" string as well. 204 */ 205 if (out_buf.length != in_buf.length || 206 memcmp(out_buf.value, in_buf.value, out_buf.length) != 0) { 207 DPRINT((dfile, "Verification of the protocol version strings " 208 "failed [%d:%s][%d:%s]\n", out_buf.length, 209 (char *)out_buf.value, in_buf.length, 210 (char *)in_buf.value)); 211 free(in_buf.value); 212 return (-1); 213 } 214 215 /* 216 * Prepare the concatenated client/server version strings later used 217 * as an application_data field in the gss_channel_bindings_struct 218 * structure. 219 */ 220 ver_str_concat_sz = out_buf.length + in_buf.length + 1; 221 ver_str_concat = (char *)calloc(1, ver_str_concat_sz); 222 if (ver_str_concat == NULL) { 223 report_err(gettext("Memory allocation failed")); 224 DPRINT((dfile, "Memory allocation failed: %s\n", 225 strerror(errno))); 226 free(in_buf.value); 227 return (-1); 228 } 229 (void) memcpy(ver_str_concat, out_buf.value, out_buf.length); 230 (void) memcpy(ver_str_concat + out_buf.length, in_buf.value, 231 in_buf.length); 232 DPRINT((dfile, "Concatenated version strings: %s\n", ver_str_concat)); 233 234 DPRINT((dfile, "Protocol version agreed.\n")); 235 free(in_buf.value); 236 return (0); 237 } 238 239 /* 240 * sock_prepare() - creates and connects socket. Function returns 241 * B_FALSE/B_TRUE on failure/success and sets the err_rsn accordingly to the 242 * reason of failure. 243 */ 244 static boolean_t 245 sock_prepare(int *sockfdptr, struct hostent *host, close_rsn_t *err_rsn) 246 { 247 struct sockaddr_storage addr; 248 struct sockaddr_in *sin; 249 struct sockaddr_in6 *sin6; 250 size_t addr_len; 251 int sock; 252 253 DPRINT((dfile, "Creating socket for %s\n", host->h_name)); 254 bzero(&addr, sizeof (addr)); 255 addr.ss_family = host->h_addrtype; 256 switch (host->h_addrtype) { 257 case AF_INET: 258 sin = (struct sockaddr_in *)&addr; 259 addr_len = sizeof (struct sockaddr_in); 260 bcopy(host->h_addr_list[0], 261 &(sin->sin_addr), sizeof (struct in_addr)); 262 sin->sin_port = current_port; 263 break; 264 case AF_INET6: 265 sin6 = (struct sockaddr_in6 *)&addr; 266 addr_len = sizeof (struct sockaddr_in6); 267 bcopy(host->h_addr_list[0], 268 &(sin6->sin6_addr), sizeof (struct in6_addr)); 269 sin6->sin6_port = current_port; 270 break; 271 default: 272 /* unknown address family */ 273 *err_rsn = RSN_UNKNOWN_AF; 274 return (B_FALSE); 275 } 276 if ((sock = socket(addr.ss_family, SOCK_STREAM, 0)) == -1) { 277 *err_rsn = RSN_SOCKET_CREATE; 278 return (B_FALSE); 279 } 280 DPRINT((dfile, "Socket created, fd=%d, connecting..\n", sock)); 281 282 if (connect_timeout(sock, (struct sockaddr *)&addr, addr_len)) { 283 (void) close(sock); 284 *err_rsn = RSN_CONNECTION_CREATE; 285 return (B_FALSE); 286 } 287 *sockfdptr = sock; 288 DPRINT((dfile, "Connected to %s via fd=%d\n", host->h_name, 289 *sockfdptr)); 290 291 return (B_TRUE); 292 } 293 294 /* 295 * establish_context() - establish the client/server GSS context. 296 * 297 * Note: connection must be established and version negotiated (in plain text) 298 * prior to establishing context. 299 */ 300 static int 301 establish_context() 302 { 303 gss_buffer_desc send_tok, recv_tok, *token_ptr; 304 OM_uint32 maj_stat, min_stat; 305 OM_uint32 init_sec_min_stat, ret_flags; 306 gss_name_t gss_name; 307 char *gss_svc_name = "audit"; 308 char *svc_name; 309 struct gss_channel_bindings_struct input_chan_bindings; 310 311 /* GSS service name = gss_svc_name + "@" + remote hostname (fqdn) */ 312 (void) asprintf(&svc_name, "%s@%s", gss_svc_name, current_host->h_name); 313 if (svc_name == NULL) { 314 report_err(gettext("Cannot allocate service name\n")); 315 DPRINT((dfile, "Memory allocation failed: %s\n", 316 strerror(errno))); 317 return (-1); 318 } 319 DPRINT((dfile, "Service name: %s\n", svc_name)); 320 321 send_tok.value = svc_name; 322 send_tok.length = strlen(svc_name); 323 maj_stat = gss_import_name(&min_stat, &send_tok, 324 (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &gss_name); 325 if (maj_stat != GSS_S_COMPLETE) { 326 report_gss_err(gettext("initializing context"), maj_stat, 327 min_stat); 328 free(svc_name); 329 return (-1); 330 } 331 token_ptr = GSS_C_NO_BUFFER; 332 gss_ctx = GSS_C_NO_CONTEXT; 333 334 /* initialize channel binding */ 335 bzero(&input_chan_bindings, sizeof (input_chan_bindings)); 336 input_chan_bindings.initiator_addrtype = GSS_C_AF_NULLADDR; 337 input_chan_bindings.acceptor_addrtype = GSS_C_AF_NULLADDR; 338 input_chan_bindings.application_data.length = strlen(ver_str_concat); 339 input_chan_bindings.application_data.value = ver_str_concat; 340 341 (void) pthread_mutex_lock(&gss_ctx_lock); 342 do { 343 maj_stat = gss_init_sec_context(&init_sec_min_stat, 344 GSS_C_NO_CREDENTIAL, &gss_ctx, gss_name, *current_mech_oid, 345 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG 346 | GSS_C_CONF_FLAG, 0, &input_chan_bindings, token_ptr, 347 NULL, &send_tok, &ret_flags, NULL); 348 349 if (token_ptr != GSS_C_NO_BUFFER) { 350 (void) gss_release_buffer(&min_stat, &recv_tok); 351 } 352 353 if (send_tok.length != 0) { 354 DPRINT((dfile, 355 "Sending init_sec_context token (size=%d)\n", 356 send_tok.length)); 357 if (send_token(&sockfd, &send_tok) < 0) { 358 free(svc_name); 359 (void) gss_release_name(&min_stat, &gss_name); 360 (void) pthread_mutex_unlock(&gss_ctx_lock); 361 return (-1); 362 } 363 } 364 if (send_tok.value != NULL) { 365 free(send_tok.value); /* freeing svc_name */ 366 send_tok.value = NULL; 367 send_tok.length = 0; 368 } 369 370 if (maj_stat != GSS_S_COMPLETE && 371 maj_stat != GSS_S_CONTINUE_NEEDED) { 372 report_gss_err(gettext("initializing context"), 373 maj_stat, init_sec_min_stat); 374 if (gss_ctx == GSS_C_NO_CONTEXT) { 375 (void) gss_delete_sec_context(&min_stat, 376 &gss_ctx, GSS_C_NO_BUFFER); 377 } 378 (void) gss_release_name(&min_stat, &gss_name); 379 (void) pthread_mutex_unlock(&gss_ctx_lock); 380 return (-1); 381 } 382 383 if (maj_stat == GSS_S_CONTINUE_NEEDED) { 384 DPRINT((dfile, "continue needed... ")); 385 if (recv_token(sockfd, &recv_tok) < 0) { 386 (void) gss_release_name(&min_stat, &gss_name); 387 (void) pthread_mutex_unlock(&gss_ctx_lock); 388 return (-1); 389 } 390 token_ptr = &recv_tok; 391 } 392 } while (maj_stat == GSS_S_CONTINUE_NEEDED); 393 (void) gss_release_name(&min_stat, &gss_name); 394 395 DPRINT((dfile, "context established\n")); 396 (void) pthread_mutex_unlock(&gss_ctx_lock); 397 return (0); 398 } 399 400 /* 401 * delete_context() - release GSS context. 402 */ 403 static void 404 delete_context() 405 { 406 OM_uint32 min_stat; 407 408 (void) gss_delete_sec_context(&min_stat, &gss_ctx, GSS_C_NO_BUFFER); 409 DPRINT((dfile, "context deleted\n")); 410 } 411 412 /* 413 * send_token() - send GSS token over the wire. 414 */ 415 static int 416 send_token(int *fdptr, gss_buffer_t tok) 417 { 418 uint32_t len; 419 uint32_t lensz; 420 char *out_buf; 421 int fd; 422 423 (void) pthread_mutex_lock(&sock_lock); 424 if (*fdptr == -1) { 425 (void) pthread_mutex_unlock(&sock_lock); 426 DPRINT((dfile, "Socket detected as closed.\n")); 427 return (-1); 428 } 429 fd = *fdptr; 430 431 len = htonl(tok->length); 432 lensz = sizeof (len); 433 434 out_buf = (char *)malloc((size_t)(lensz + tok->length)); 435 if (out_buf == NULL) { 436 (void) pthread_mutex_unlock(&sock_lock); 437 report_err(gettext("Memory allocation failed")); 438 DPRINT((dfile, "Memory allocation failed: %s\n", 439 strerror(errno))); 440 return (-1); 441 } 442 (void) memcpy((void *)out_buf, (void *)&len, lensz); 443 (void) memcpy((void *)(out_buf + lensz), (void *)tok->value, 444 tok->length); 445 446 if (send_timeout(fd, out_buf, (lensz + tok->length))) { 447 (void) pthread_mutex_unlock(&sock_lock); 448 free(out_buf); 449 return (-1); 450 } 451 452 (void) pthread_mutex_unlock(&sock_lock); 453 free(out_buf); 454 return (0); 455 } 456 457 458 /* 459 * recv_token() - receive GSS token over the wire. 460 */ 461 static int 462 recv_token(int fd, gss_buffer_t tok) 463 { 464 uint32_t len; 465 466 if (recv_timeout(fd, (char *)&len, sizeof (len))) { 467 return (-1); 468 } 469 len = ntohl(len); 470 471 /* simple DOS prevention mechanism */ 472 if (len > MAX_TOK_LEN) { 473 report_err(gettext("Indicated invalid token length")); 474 DPRINT((dfile, "Indicated token length > %dB\n", MAX_TOK_LEN)); 475 return (-1); 476 } 477 478 tok->value = (char *)malloc(len); 479 if (tok->value == NULL) { 480 report_err(gettext("Memory allocation failed")); 481 DPRINT((dfile, "Memory allocation failed: %s\n", 482 strerror(errno))); 483 tok->length = 0; 484 return (-1); 485 } 486 487 if (recv_timeout(fd, tok->value, len)) { 488 free(tok->value); 489 tok->value = NULL; 490 tok->length = 0; 491 return (-1); 492 } 493 494 tok->length = len; 495 return (0); 496 } 497 498 499 /* 500 * I/O functions 501 */ 502 503 /* 504 * connect_timeout() - sets nonblocking I/O on a socket and timeout-connects 505 */ 506 static int 507 connect_timeout(int sockfd, struct sockaddr *name, int namelen) 508 { 509 int flags; 510 struct pollfd fds; 511 int rc; 512 struct sockaddr_storage addr; 513 socklen_t addr_len = sizeof (addr); 514 515 516 flags = fcntl(sockfd, F_GETFL, 0); 517 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) { 518 return (-1); 519 } 520 if (connect(sockfd, name, namelen)) { 521 if (!(errno == EINTR || errno == EINPROGRESS || 522 errno == EWOULDBLOCK)) { 523 return (-1); 524 } 525 } 526 fds.fd = sockfd; 527 fds.events = POLLOUT; 528 for (;;) { 529 fds.revents = 0; 530 rc = poll(&fds, 1, timeout * 1000); 531 if (rc == 0) { /* timeout */ 532 return (-1); 533 } else if (rc < 0) { 534 if (errno == EINTR || errno == EAGAIN) { 535 continue; 536 } else { 537 return (-1); 538 } 539 } 540 if (fds.revents) { 541 if (getpeername(sockfd, (struct sockaddr *)&addr, 542 &addr_len)) 543 return (-1); 544 } else { 545 return (-1); 546 } 547 return (0); 548 } 549 } 550 551 /* 552 * send_timeout() - send data (in chunks if needed, each chunk in timeout secs). 553 */ 554 static int 555 send_timeout(int fd, const char *buf, size_t len) 556 { 557 int bytes; 558 struct pollfd fds; 559 int rc; 560 561 fds.fd = fd; 562 fds.events = POLLOUT; 563 564 while (len) { 565 fds.revents = 0; 566 rc = poll(&fds, 1, timeout * 1000); 567 if (rc == 0) { /* timeout */ 568 return (-1); 569 } else if (rc < 0) { 570 if (errno == EINTR || errno == EAGAIN) { 571 continue; 572 } else { 573 return (-1); 574 } 575 } 576 if (!fds.revents) { 577 return (-1); 578 } 579 580 bytes = write(fd, buf, len); 581 if (bytes < 0) { 582 if (errno == EINTR) { 583 continue; 584 } else { 585 return (-1); 586 } 587 } else if (bytes == 0) { /* eof */ 588 return (-1); 589 } 590 591 len -= bytes; 592 buf += bytes; 593 } 594 595 return (0); 596 } 597 598 /* 599 * recv_timeout() - receive data (in chunks if needed, each chunk in timeout 600 * secs). In case the function is called from receiving thread, the function 601 * cycles the poll() call in timeout seconds (waits for input from server). 602 */ 603 static int 604 recv_timeout(int fd, char *buf, size_t len) 605 { 606 int bytes; 607 struct pollfd fds; 608 int rc; 609 610 fds.fd = fd; 611 fds.events = POLLIN; 612 613 while (len) { 614 fds.revents = 0; 615 rc = poll(&fds, 1, timeout * 1000); 616 if (rc == 0) { /* timeout */ 617 return (-1); 618 } else if (rc < 0) { 619 if (errno == EINTR || errno == EAGAIN) { 620 continue; 621 } else { 622 return (-1); 623 } 624 } 625 626 if (!fds.revents) { 627 return (-1); 628 } 629 630 bytes = read(fd, buf, len); 631 if (bytes < 0) { 632 if (errno == EINTR) { 633 continue; 634 } else { 635 return (-1); 636 } 637 } else if (bytes == 0) { /* eof */ 638 return (-1); 639 } 640 641 len -= bytes; 642 buf += bytes; 643 } 644 645 return (0); 646 } 647 648 /* 649 * read_fd() - reads data of length len from the given file descriptor fd to the 650 * buffer buf, in chunks if needed. Function returns B_FALSE on failure, 651 * otherwise B_TRUE. Function preserves errno, if it was set by the read(2). 652 */ 653 static boolean_t 654 read_fd(int fd, char *buf, size_t len) 655 { 656 int bytes; 657 #ifdef DEBUG 658 size_t len_o = len; 659 #endif 660 661 while (len) { 662 bytes = read(fd, buf, len); 663 if (bytes < 0) { /* err */ 664 if (errno == EINTR || errno == EAGAIN) { 665 continue; 666 } else { 667 return (B_FALSE); 668 } 669 } else if (bytes == 0) { /* eof */ 670 return (B_FALSE); 671 } 672 673 len -= bytes; 674 buf += bytes; 675 } 676 677 DPRINT((dfile, "read_fd: Read %d bytes.\n", len_o - len)); 678 return (B_TRUE); 679 } 680 681 /* 682 * write_fd() - writes buf of length len to the opened file descriptor fd, in 683 * chunks if needed. The data from the pipe are processed in the receiving 684 * thread. Function returns B_FALSE on failure, otherwise B_TRUE. Function 685 * preserves errno, if it was set by the write(2). 686 */ 687 static boolean_t 688 write_fd(int fd, char *buf, size_t len) 689 { 690 int bytes; 691 #ifdef DEBUG 692 size_t len_o = len; 693 #endif 694 695 while (len) { 696 bytes = write(fd, buf, len); 697 if (bytes == -1) { /* err */ 698 if (errno == EINTR || errno == EAGAIN) { 699 continue; 700 } else { 701 return (B_FALSE); 702 } 703 } 704 705 len -= bytes; 706 buf += bytes; 707 } 708 709 DPRINT((dfile, "write_fd: Wrote %d bytes.\n", len_o - len)); 710 return (B_TRUE); 711 } 712 713 /* 714 * Plug-in entry point 715 */ 716 717 /* 718 * send_record() - send an audit record to a host opening a connection, 719 * negotiate version and establish context if necessary. 720 */ 721 send_record_rc_t 722 send_record(struct hostlist_s *hostlptr, const char *input, size_t in_len, 723 uint64_t sequence, close_rsn_t *err_rsn) 724 { 725 gss_buffer_desc in_buf, out_buf; 726 OM_uint32 maj_stat, min_stat; 727 int conf_state; 728 int rc; 729 transq_node_t *node_ptr; 730 uint64_t seq_n; /* sequence in the network byte order */ 731 boolean_t init_sock_poll = B_FALSE; 732 733 /* 734 * We need to grab the reset_lock here, to prevent eventual 735 * unsynchronized cleanup calls within the reset routine (reset caused 736 * by the receiving thread) and the initialization calls in the 737 * send_record() code path. 738 */ 739 (void) pthread_mutex_lock(&reset_lock); 740 741 /* 742 * Check whether the socket was closed by the recv thread prior to call 743 * send_record() and behave accordingly to the reason of the closure. 744 */ 745 if (recv_closure_rsn != RSN_UNDEFINED) { 746 *err_rsn = recv_closure_rsn; 747 if (recv_closure_rsn == RSN_GSS_CTX_EXP) { 748 rc = SEND_RECORD_RETRY; 749 } else { 750 rc = SEND_RECORD_NEXT; 751 } 752 recv_closure_rsn = RSN_UNDEFINED; 753 (void) pthread_mutex_unlock(&reset_lock); 754 return (rc); 755 } 756 757 /* 758 * Send request to other then previously used host. 759 */ 760 if (current_host != hostlptr->host) { 761 DPRINT((dfile, "Set new host: %s\n", hostlptr->host->h_name)); 762 if (sockfd != -1) { 763 (void) pthread_mutex_unlock(&reset_lock); 764 reset_transport(DO_CLOSE, DO_SYNC); 765 return (SEND_RECORD_RETRY); 766 } 767 current_host = (struct hostent *)hostlptr->host; 768 current_mech_oid = &hostlptr->mech; 769 current_port = hostlptr->port; 770 } 771 772 /* initiate the receiving thread */ 773 (void) pthread_once(&recv_once_control, init_recv_record); 774 775 /* create and connect() socket, negotiate the protocol version */ 776 if (sockfd == -1) { 777 /* socket operations */ 778 DPRINT((dfile, "Socket creation and connect\n")); 779 if (!sock_prepare(&sockfd, current_host, err_rsn)) { 780 /* we believe the err_rsn set by sock_prepare() */ 781 (void) pthread_mutex_unlock(&reset_lock); 782 return (SEND_RECORD_NEXT); 783 } 784 785 /* protocol version negotiation */ 786 DPRINT((dfile, "Protocol version negotiation\n")); 787 if (prot_ver_negotiate() != 0) { 788 DPRINT((dfile, 789 "Protocol version negotiation failed\n")); 790 (void) pthread_mutex_unlock(&reset_lock); 791 reset_transport(DO_CLOSE, DO_SYNC); 792 *err_rsn = RSN_PROTOCOL_NEGOTIATE; 793 return (SEND_RECORD_NEXT); 794 } 795 796 /* let the socket be initiated for poll() */ 797 init_sock_poll = B_TRUE; 798 } 799 800 if (!gss_ctx_initialized) { 801 DPRINT((dfile, "Establishing context..\n")); 802 if (establish_context() != 0) { 803 (void) pthread_mutex_unlock(&reset_lock); 804 reset_transport(DO_CLOSE, DO_SYNC); 805 *err_rsn = RSN_GSS_CTX_ESTABLISH; 806 return (SEND_RECORD_NEXT); 807 } 808 gss_ctx_initialized = B_TRUE; 809 } 810 811 /* let the recv thread poll() on the sockfd */ 812 if (init_sock_poll) { 813 init_sock_poll = B_FALSE; 814 if (!init_poll(sockfd)) { 815 *err_rsn = RSN_INIT_POLL; 816 (void) pthread_mutex_unlock(&reset_lock); 817 return (SEND_RECORD_RETRY); 818 } 819 } 820 821 (void) pthread_mutex_unlock(&reset_lock); 822 823 /* if not empty, retransmit contents of the transmission queue */ 824 if (flush_transq) { 825 DPRINT((dfile, "Retransmitting remaining (%ld) tokens from " 826 "the transmission queue\n", transq_hdr.count)); 827 if ((rc = transq_retransmit()) == 2) { /* gss context exp */ 828 reset_transport(DO_CLOSE, DO_SYNC); 829 *err_rsn = RSN_GSS_CTX_EXP; 830 return (SEND_RECORD_RETRY); 831 } else if (rc == 1) { 832 reset_transport(DO_CLOSE, DO_SYNC); 833 *err_rsn = RSN_OTHER_ERR; 834 return (SEND_RECORD_NEXT); 835 } 836 flush_transq = B_FALSE; 837 } 838 839 /* 840 * Concatenate sequence number and the new record. Note, that the 841 * pointer to the chunk of memory allocated for the concatenated values 842 * is later passed to the transq_enqueu() function which stores the 843 * pointer in the transmission queue; subsequently called 844 * transq_dequeue() frees the allocated memory once the MIC is verified 845 * by the recv_record() function. 846 * 847 * If we return earlier than the transq_enqueue() is called, it's 848 * necessary to free the in_buf.value explicitly prior to return. 849 * 850 */ 851 in_buf.length = in_len + sizeof (sequence); 852 in_buf.value = malloc(in_buf.length); 853 if (in_buf.value == NULL) { 854 report_err(gettext("Memory allocation failed")); 855 DPRINT((dfile, "Memory allocation failed: %s\n", 856 strerror(errno))); 857 reset_transport(DO_CLOSE, DO_SYNC); 858 *err_rsn = RSN_MEMORY_ALLOCATE; 859 return (SEND_RECORD_FAIL); 860 } 861 seq_n = htonll(sequence); 862 (void) memcpy(in_buf.value, &seq_n, sizeof (seq_n)); 863 (void) memcpy((char *)in_buf.value + sizeof (seq_n), input, in_len); 864 865 /* wrap sequence number and the new record to the per-message token */ 866 (void) pthread_mutex_lock(&gss_ctx_lock); 867 if (gss_ctx != NULL) { 868 maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT, 869 &in_buf, &conf_state, &out_buf); 870 (void) pthread_mutex_unlock(&gss_ctx_lock); 871 switch (maj_stat) { 872 case GSS_S_COMPLETE: 873 break; 874 case GSS_S_CONTEXT_EXPIRED: 875 reset_transport(DO_CLOSE, DO_SYNC); 876 free(in_buf.value); 877 *err_rsn = RSN_GSS_CTX_EXP; 878 return (SEND_RECORD_RETRY); 879 default: 880 report_gss_err(gettext("gss_wrap message"), maj_stat, 881 min_stat); 882 reset_transport(DO_CLOSE, DO_SYNC); 883 free(in_buf.value); 884 *err_rsn = RSN_OTHER_ERR; 885 return (SEND_RECORD_NEXT); 886 } 887 } else { /* GSS context deleted by the recv thread */ 888 (void) pthread_mutex_unlock(&gss_ctx_lock); 889 reset_transport(DO_CLOSE, DO_SYNC); 890 free(in_buf.value); 891 *err_rsn = RSN_OTHER_ERR; 892 return (SEND_RECORD_NEXT); 893 } 894 895 896 /* enqueue the to-be-sent token into transmission queue */ 897 (void) pthread_mutex_lock(&transq_lock); 898 if (!transq_enqueue(&node_ptr, &in_buf, sequence)) { 899 (void) pthread_mutex_unlock(&transq_lock); 900 reset_transport(DO_CLOSE, DO_SYNC); 901 free(in_buf.value); 902 (void) gss_release_buffer(&min_stat, &out_buf); 903 *err_rsn = RSN_OTHER_ERR; 904 return (SEND_RECORD_RETRY); 905 } 906 DPRINT((dfile, "Token enqueued for later verification\n")); 907 (void) pthread_mutex_unlock(&transq_lock); 908 909 /* send token */ 910 if (send_token(&sockfd, &out_buf) < 0) { 911 DPRINT((dfile, "Token sending failed\n")); 912 reset_transport(DO_CLOSE, DO_SYNC); 913 (void) gss_release_buffer(&min_stat, &out_buf); 914 915 (void) pthread_mutex_lock(&transq_lock); 916 transq_dequeue(node_ptr); 917 (void) pthread_mutex_unlock(&transq_lock); 918 919 *err_rsn = RSN_OTHER_ERR; 920 return (SEND_RECORD_NEXT); 921 } 922 DPRINT((dfile, "Token sent (transq size = %ld)\n", transq_hdr.count)); 923 924 (void) gss_release_buffer(&min_stat, &out_buf); 925 926 return (SEND_RECORD_SUCCESS); 927 } 928 929 /* 930 * init_recv_record() - initialize the receiver thread 931 */ 932 static void 933 init_recv_record() 934 { 935 DPRINT((dfile, "Initiating the recv thread\n")); 936 (void) pthread_create(&recv_tid, NULL, recv_record, NULL); 937 938 } 939 940 941 /* 942 * recv_record() - the receiver thread routine 943 */ 944 static void * 945 recv_record(void *arg __unused) 946 { 947 OM_uint32 maj_stat, min_stat; 948 gss_qop_t qop_state; 949 gss_buffer_desc in_buf = GSS_C_EMPTY_BUFFER; 950 gss_buffer_desc in_buf_mic = GSS_C_EMPTY_BUFFER; 951 transq_node_t *cur_node; 952 uint64_t r_seq_num; /* received sequence number */ 953 boolean_t token_verified; 954 boolean_t break_flag; 955 struct pollfd fds[2]; 956 int fds_cnt; 957 struct pollfd *pipe_fd = &fds[0]; 958 struct pollfd *recv_fd = &fds[1]; 959 uint32_t len; 960 int rc; 961 pipe_msg_t np_data; 962 963 DPRINT((dfile, "Receiver thread initiated\n")); 964 965 /* 966 * Fill in the information in the vector of file descriptors passed 967 * later on to the poll() function. In the initial state, there is only 968 * one struct pollfd in the vector which contains file descriptor of the 969 * notification pipe - notify_pipe[1]. There might be up to two file 970 * descriptors (struct pollfd) in the vector - notify_pipe[1] which 971 * resides in the vector during the entire life of the receiving thread, 972 * and the own file descriptor from which we read data sent by the 973 * remote server application. 974 */ 975 pipe_fd->fd = notify_pipe[1]; 976 pipe_fd->events = POLLIN; 977 recv_fd->fd = -1; 978 recv_fd->events = POLLIN; 979 fds_cnt = 1; 980 981 /* 982 * In the endless loop, try to grab some data from the socket or 983 * notify_pipe[1]. 984 */ 985 for (;;) { 986 987 pipe_fd->revents = 0; 988 recv_fd->revents = 0; 989 recv_closure_rsn = RSN_UNDEFINED; 990 991 /* block on poll, thus rc != 0 */ 992 rc = poll(fds, fds_cnt, -1); 993 if (rc == -1) { 994 if (errno == EAGAIN || errno == EINTR) { 995 /* silently continue on EAGAIN || EINTR */ 996 continue; 997 } else { 998 /* log the debug message in any other case */ 999 DPRINT((dfile, "poll() failed: %s\n", 1000 strerror(errno))); 1001 report_err(gettext("poll() failed.\n")); 1002 continue; 1003 } 1004 } 1005 1006 /* 1007 * Receive a message from the notification pipe. Information 1008 * from the notification pipe takes precedence over the received 1009 * data from the remote server application. 1010 * 1011 * Notification pipe message format - message accepted 1012 * from the notify pipe comprises of two parts (int || 1013 * boolean_t), where if the first part (sizeof (int)) equals 1014 * NP_CLOSE, then the second part (sizeof (boolean_t)) signals 1015 * the necessity of broadcasting (DO_SYNC/DO_NOT_SYNC) the end 1016 * of the reset routine. 1017 */ 1018 if (pipe_fd->revents & POLLIN) { 1019 DPRINT((dfile, "An event on notify pipe detected\n")); 1020 if (!read_fd(pipe_fd->fd, (char *)&np_data, 1021 sizeof (np_data))) { 1022 DPRINT((dfile, "Reading notify pipe failed: " 1023 "%s\n", strerror(errno))); 1024 report_err(gettext("Reading notify pipe " 1025 "failed")); 1026 } else { 1027 switch (np_data.sock_num) { 1028 case NP_EXIT: /* exit receiving thread */ 1029 do_cleanup(&fds_cnt, recv_fd, 1030 np_data.sync); 1031 pthread_exit((void *)NULL); 1032 break; 1033 case NP_CLOSE: /* close and remove recv_fd */ 1034 do_reset(&fds_cnt, recv_fd, 1035 np_data.sync); 1036 continue; 1037 default: /* add rc_pipe to the fds */ 1038 recv_fd->fd = np_data.sock_num; 1039 fds_cnt = 2; 1040 continue; 1041 } 1042 } 1043 } 1044 /* Receive a token from the remote server application */ 1045 if (recv_fd->revents & POLLIN) { 1046 DPRINT((dfile, "An event on fd detected\n")); 1047 if (!read_fd(recv_fd->fd, (char *)&len, sizeof (len))) { 1048 DPRINT((dfile, "Token length recv failed\n")); 1049 recv_closure_rsn = RSN_TOK_RECV_FAILED; 1050 reset_transport(DO_CLOSE, DO_NOT_SYNC); 1051 continue; 1052 } 1053 len = ntohl(len); 1054 1055 /* simple DOS prevention mechanism */ 1056 if (len > MAX_TOK_LEN) { 1057 report_err(gettext("Indicated invalid token " 1058 "length")); 1059 DPRINT((dfile, "Indicated token length > %dB\n", 1060 MAX_TOK_LEN)); 1061 recv_closure_rsn = RSN_TOK_TOO_BIG; 1062 reset_transport(DO_CLOSE, DO_NOT_SYNC); 1063 continue; 1064 } 1065 1066 in_buf.value = (char *)malloc(len); 1067 if (in_buf.value == NULL) { 1068 report_err(gettext("Memory allocation failed")); 1069 DPRINT((dfile, "Memory allocation failed: %s\n", 1070 strerror(errno))); 1071 recv_closure_rsn = RSN_MEMORY_ALLOCATE; 1072 reset_transport(DO_CLOSE, DO_NOT_SYNC); 1073 continue; 1074 } 1075 if (!read_fd(recv_fd->fd, (char *)in_buf.value, len)) { 1076 DPRINT((dfile, "Token value recv failed\n")); 1077 free(in_buf.value); 1078 recv_closure_rsn = RSN_TOK_RECV_FAILED; 1079 reset_transport(DO_CLOSE, DO_NOT_SYNC); 1080 continue; 1081 } 1082 1083 in_buf.length = len; 1084 } 1085 1086 /* 1087 * Extract the sequence number and the MIC from 1088 * the per-message token 1089 */ 1090 (void) memcpy(&r_seq_num, in_buf.value, sizeof (r_seq_num)); 1091 r_seq_num = ntohll(r_seq_num); 1092 in_buf_mic.length = in_buf.length - sizeof (r_seq_num); 1093 in_buf_mic.value = (char *)in_buf.value + sizeof (r_seq_num); 1094 1095 /* 1096 * seq_num/r_seq_num - the sequence number does not need to 1097 * be unique in the transmission queue. Any token in the 1098 * transmission queue with the same seq_num as the acknowledge 1099 * token received from the server is tested. This is due to the 1100 * fact that the plugin cannot influence (in the current 1101 * implementation) sequence numbers generated by the kernel (we 1102 * are reusing record sequence numbers as a transmission queue 1103 * sequence numbers). The probability of having two or more 1104 * tokens in the transmission queue is low and at the same time 1105 * the performance gain due to using sequence numbers is quite 1106 * high. 1107 * 1108 * In case a harder condition with regard to duplicate sequence 1109 * numbers in the transmission queue will be desired over time, 1110 * the break_flag behavior used below should be 1111 * removed/changed_accordingly. 1112 */ 1113 break_flag = B_FALSE; 1114 token_verified = B_FALSE; 1115 (void) pthread_mutex_lock(&transq_lock); 1116 cur_node = transq_hdr.head; 1117 while (cur_node != NULL && !break_flag) { 1118 if (cur_node->seq_num != r_seq_num) { 1119 cur_node = cur_node->next; 1120 continue; 1121 } 1122 1123 (void) pthread_mutex_lock(&gss_ctx_lock); 1124 maj_stat = gss_verify_mic(&min_stat, gss_ctx, 1125 &(cur_node->seq_token), &in_buf_mic, 1126 &qop_state); 1127 (void) pthread_mutex_unlock(&gss_ctx_lock); 1128 1129 if (!GSS_ERROR(maj_stat)) { /* the success case */ 1130 switch (maj_stat) { 1131 /* 1132 * All the GSS_S_OLD_TOKEN, GSS_S_UNSEQ_TOKEN, 1133 * GSS_S_GAP_TOKEN are perceived as correct 1134 * behavior of the server side. The plugin 1135 * implementation is resistant to any of the 1136 * above mention cases of returned status codes. 1137 */ 1138 /*FALLTHRU*/ 1139 case GSS_S_OLD_TOKEN: 1140 case GSS_S_UNSEQ_TOKEN: 1141 case GSS_S_GAP_TOKEN: 1142 case GSS_S_COMPLETE: 1143 /* 1144 * remove the verified record/node from 1145 * the transmission queue 1146 */ 1147 transq_dequeue(cur_node); 1148 DPRINT((dfile, "Recv thread verified " 1149 "the token (transq len = %ld)\n", 1150 transq_hdr.count)); 1151 1152 token_verified = B_TRUE; 1153 break_flag = B_TRUE; 1154 break; 1155 1156 /* 1157 * Both the default case as well as 1158 * GSS_S_DUPLICATE_TOKEN case should never 1159 * occur. It's been left here for the sake of 1160 * completeness. 1161 * If any of the two cases occur, it is 1162 * subsequently cought because we don't set 1163 * the token_verified flag. 1164 */ 1165 /*FALLTHRU*/ 1166 case GSS_S_DUPLICATE_TOKEN: 1167 default: 1168 break_flag = B_TRUE; 1169 break; 1170 } /* switch (maj_stat) */ 1171 1172 } else { /* the failure case */ 1173 report_gss_err( 1174 gettext("signature verification of the " 1175 "received token failed"), 1176 maj_stat, min_stat); 1177 1178 switch (maj_stat) { 1179 case GSS_S_CONTEXT_EXPIRED: 1180 /* retransmission necessary */ 1181 recv_closure_rsn = RSN_GSS_CTX_EXP; 1182 break_flag = B_TRUE; 1183 DPRINT((dfile, "Recv thread detected " 1184 "the GSS context expiration\n")); 1185 break; 1186 case GSS_S_BAD_SIG: 1187 DPRINT((dfile, "Bad signature " 1188 "detected (seq_num = %lld)\n", 1189 cur_node->seq_num)); 1190 cur_node = cur_node->next; 1191 break; 1192 default: 1193 report_gss_err( 1194 gettext("signature verification"), 1195 maj_stat, min_stat); 1196 break_flag = B_TRUE; 1197 break; 1198 } 1199 } 1200 1201 } /* while */ 1202 (void) pthread_mutex_unlock(&transq_lock); 1203 1204 if (in_buf.value != NULL) { 1205 free(in_buf.value); 1206 in_buf.value = NULL; 1207 in_buf.length = 0; 1208 } 1209 1210 if (!token_verified) { 1211 /* 1212 * Received, but unverifiable token is perceived as 1213 * the protocol flow corruption with the penalty of 1214 * reinitializing the client/server connection. 1215 */ 1216 DPRINT((dfile, "received unverifiable token\n")); 1217 report_err(gettext("received unverifiable token\n")); 1218 if (recv_closure_rsn == RSN_UNDEFINED) { 1219 recv_closure_rsn = RSN_TOK_UNVERIFIABLE; 1220 } 1221 reset_transport(DO_CLOSE, DO_NOT_SYNC); 1222 } 1223 1224 } /* for (;;) */ 1225 1226 1227 } 1228 1229 1230 /* 1231 * init_poll() - initiates the polling in the receiving thread via sending the 1232 * appropriate message over the notify pipe. Message format = (int || 1233 * booleant_t), where the first part (sizeof (int)) contains the 1234 * newly_opened/to_be_polled socket file descriptor. The contents of the second 1235 * part (sizeof (boolean_t)) of the message works only as a padding here and no 1236 * action (no recv/send thread synchronisation) is made in the receiving thread 1237 * based on its value. 1238 */ 1239 static boolean_t 1240 init_poll(int fd) 1241 { 1242 pipe_msg_t np_data; 1243 int pipe_in = notify_pipe[0]; 1244 1245 np_data.sock_num = fd; 1246 np_data.sync = B_FALSE; /* padding only */ 1247 1248 if (!write_fd(pipe_in, (char *)&np_data, sizeof (np_data))) { 1249 DPRINT((dfile, "Cannot write to the notify pipe\n")); 1250 report_err(gettext("writing to the notify pipe failed")); 1251 return (B_FALSE); 1252 } 1253 1254 return (B_TRUE); 1255 } 1256 1257 1258 /* 1259 * reset_transport() - locked by the reset_lock initiates the reset of socket, 1260 * GSS security context and (possibly) flags the transq for retransmission; for 1261 * more detailed information see do_reset(). The reset_transport() also allows 1262 * the synchronization - waiting for the reset to be finished. 1263 * 1264 * do_close: DO_SYNC, DO_NOT_SYNC 1265 * sync_on_return: DO_EXIT (DO_NOT_CLOSE), DO_CLOSE (DO_NOT_EXIT) 1266 * 1267 */ 1268 void 1269 reset_transport(boolean_t do_close, boolean_t sync_on_return) 1270 { 1271 int pipe_in = notify_pipe[0]; 1272 pipe_msg_t np_data; 1273 1274 /* 1275 * Check if the reset routine is in progress or whether it was already 1276 * executed by some other thread. 1277 */ 1278 (void) pthread_mutex_lock(&reset_lock); 1279 if (reset_in_progress) { 1280 (void) pthread_mutex_unlock(&reset_lock); 1281 return; 1282 } 1283 reset_in_progress = B_TRUE; 1284 1285 np_data.sock_num = (do_close ? NP_CLOSE : NP_EXIT); 1286 np_data.sync = sync_on_return; 1287 (void) write_fd(pipe_in, (char *)&np_data, sizeof (np_data)); 1288 1289 if (sync_on_return) { 1290 while (reset_in_progress) { 1291 (void) pthread_cond_wait(&reset_cv, &reset_lock); 1292 DPRINT((dfile, "Wait for sync\n")); 1293 } 1294 DPRINT((dfile, "Synced\n")); 1295 } 1296 (void) pthread_mutex_unlock(&reset_lock); 1297 1298 } 1299 1300 1301 /* 1302 * do_reset() - the own reseting routine called from the recv thread. If the 1303 * synchronization was requested, signal the finish via conditional variable. 1304 */ 1305 static void 1306 do_reset(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal) 1307 { 1308 1309 (void) pthread_mutex_lock(&reset_lock); 1310 1311 /* socket */ 1312 (void) pthread_mutex_lock(&sock_lock); 1313 if (sockfd == -1) { 1314 DPRINT((dfile, "socket already closed\n")); 1315 (void) pthread_mutex_unlock(&sock_lock); 1316 goto out; 1317 } else { 1318 (void) close(sockfd); 1319 sockfd = -1; 1320 recv_fd->fd = -1; 1321 (void) pthread_mutex_unlock(&sock_lock); 1322 } 1323 *fds_cnt = 1; 1324 1325 /* context */ 1326 if (gss_ctx_initialized) { 1327 delete_context(); 1328 } 1329 gss_ctx_initialized = B_FALSE; 1330 gss_ctx = NULL; 1331 1332 /* mark transq to be flushed */ 1333 (void) pthread_mutex_lock(&transq_lock); 1334 if (transq_hdr.count > 0) { 1335 flush_transq = B_TRUE; 1336 } 1337 (void) pthread_mutex_unlock(&transq_lock); 1338 1339 out: 1340 reset_in_progress = B_FALSE; 1341 if (do_signal) { 1342 (void) pthread_cond_broadcast(&reset_cv); 1343 } 1344 1345 (void) pthread_mutex_unlock(&reset_lock); 1346 } 1347 1348 /* 1349 * do_cleanup() - removes all the preallocated space by the plugin; prepares the 1350 * plugin/application to be gracefully finished. Even thought the function 1351 * allows execution without signalling the successful finish, it's recommended 1352 * to use it (we usually want to wait for cleanup before exiting). 1353 */ 1354 static void 1355 do_cleanup(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal) 1356 { 1357 1358 (void) pthread_mutex_lock(&reset_lock); 1359 1360 /* 1361 * socket 1362 * note: keeping locking for safety, thought it shouldn't be necessary 1363 * in current implementation - we get here only in case the sending code 1364 * path calls auditd_plugin_close() (thus no socket manipulation) and 1365 * the recv thread is doing the own socket closure. 1366 */ 1367 (void) pthread_mutex_lock(&sock_lock); 1368 if (sockfd != -1) { 1369 DPRINT((dfile, "Closing socket: %d\n", sockfd)); 1370 (void) close(sockfd); 1371 sockfd = -1; 1372 recv_fd->fd = -1; 1373 } 1374 *fds_cnt = 1; 1375 (void) pthread_mutex_unlock(&sock_lock); 1376 1377 /* context */ 1378 if (gss_ctx_initialized) { 1379 DPRINT((dfile, "Deleting context: ")); 1380 delete_context(); 1381 } 1382 gss_ctx_initialized = B_FALSE; 1383 gss_ctx = NULL; 1384 1385 /* transmission queue */ 1386 (void) pthread_mutex_lock(&transq_lock); 1387 if (transq_hdr.count > 0) { 1388 DPRINT((dfile, "Deallocating the transmission queue " 1389 "(len = %ld)\n", transq_hdr.count)); 1390 while (transq_hdr.count > 0) { 1391 transq_dequeue(transq_hdr.head); 1392 } 1393 } 1394 (void) pthread_mutex_unlock(&transq_lock); 1395 1396 /* notification pipe */ 1397 if (notify_pipe_ready) { 1398 (void) close(notify_pipe[0]); 1399 (void) close(notify_pipe[1]); 1400 notify_pipe_ready = B_FALSE; 1401 } 1402 1403 reset_in_progress = B_FALSE; 1404 if (do_signal) { 1405 (void) pthread_cond_broadcast(&reset_cv); 1406 } 1407 (void) pthread_mutex_unlock(&reset_lock); 1408 } 1409 1410 1411 /* 1412 * transq_dequeue() - dequeues given node pointed by the node_ptr from the 1413 * transmission queue. Transmission queue should be locked prior to use of this 1414 * function. 1415 */ 1416 static void 1417 transq_dequeue(transq_node_t *node_ptr) 1418 { 1419 1420 if (node_ptr == NULL) { 1421 DPRINT((dfile, "transq_dequeue(): called with NULL pointer\n")); 1422 return; 1423 } 1424 1425 free(node_ptr->seq_token.value); 1426 1427 if (node_ptr->prev != NULL) { 1428 node_ptr->prev->next = node_ptr->next; 1429 } 1430 if (node_ptr->next != NULL) { 1431 node_ptr->next->prev = node_ptr->prev; 1432 } 1433 1434 1435 /* update the transq_hdr */ 1436 if (node_ptr->next == NULL) { 1437 transq_hdr.end = node_ptr->prev; 1438 } 1439 if (node_ptr->prev == NULL) { 1440 transq_hdr.head = node_ptr->next; 1441 } 1442 1443 transq_hdr.count--; 1444 1445 free(node_ptr); 1446 } 1447 1448 1449 /* 1450 * transq_enqueue() - creates new node in (at the end of) the transmission 1451 * queue. in_ptoken_ptr is a pointer to the plain token in a form of 1452 * gss_buffer_desc. Function returns 0 on success and updates the *node_ptr to 1453 * point to a newly added transmission queue node. In case of any failure 1454 * function returns 1 and sets the *node_ptr to NULL. 1455 * Transmission queue should be locked prior to use of this function. 1456 */ 1457 static boolean_t 1458 transq_enqueue(transq_node_t **node_ptr, gss_buffer_t in_seqtoken_ptr, 1459 uint64_t sequence) 1460 { 1461 1462 *node_ptr = calloc(1, sizeof (transq_node_t)); 1463 if (*node_ptr == NULL) { 1464 report_err(gettext("Memory allocation failed")); 1465 DPRINT((dfile, "Memory allocation failed: %s\n", 1466 strerror(errno))); 1467 goto errout; 1468 } 1469 1470 /* value of the seq_token.value = (sequence number || plain token) */ 1471 (*node_ptr)->seq_num = sequence; 1472 (*node_ptr)->seq_token.length = in_seqtoken_ptr->length; 1473 (*node_ptr)->seq_token.value = in_seqtoken_ptr->value; 1474 1475 /* update the transq_hdr */ 1476 if (transq_hdr.head == NULL) { 1477 transq_hdr.head = *node_ptr; 1478 } 1479 if (transq_hdr.end != NULL) { 1480 (transq_hdr.end)->next = *node_ptr; 1481 (*node_ptr)->prev = transq_hdr.end; 1482 } 1483 transq_hdr.end = *node_ptr; 1484 1485 transq_hdr.count++; 1486 1487 return (B_TRUE); 1488 1489 errout: 1490 if (*node_ptr != NULL) { 1491 if ((*node_ptr)->seq_token.value != NULL) { 1492 free((*node_ptr)->seq_token.value); 1493 } 1494 free(*node_ptr); 1495 *node_ptr = NULL; 1496 } 1497 return (B_FALSE); 1498 } 1499 1500 1501 /* 1502 * transq_retransmit() - traverse the transmission queue and try to, 1 by 1, 1503 * re-wrap the tokens with the recent context information and retransmit the 1504 * tokens from the transmission queue. 1505 * Function returns 2 on GSS context expiration, 1 on any other error, 0 on 1506 * successfully resent transmission queue. 1507 */ 1508 static int 1509 transq_retransmit() 1510 { 1511 1512 OM_uint32 maj_stat, min_stat; 1513 transq_node_t *cur_node = transq_hdr.head; 1514 gss_buffer_desc out_buf; 1515 int conf_state; 1516 1517 DPRINT((dfile, "Retransmission of the remainder in the transqueue\n")); 1518 1519 while (cur_node != NULL) { 1520 1521 (void) pthread_mutex_lock(&transq_lock); 1522 (void) pthread_mutex_lock(&gss_ctx_lock); 1523 maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT, 1524 &(cur_node->seq_token), &conf_state, &out_buf); 1525 (void) pthread_mutex_unlock(&gss_ctx_lock); 1526 1527 switch (maj_stat) { 1528 case GSS_S_COMPLETE: 1529 break; 1530 case GSS_S_CONTEXT_EXPIRED: 1531 DPRINT((dfile, "Context expired.\n")); 1532 report_gss_err(gettext("gss_wrap message"), maj_stat, 1533 min_stat); 1534 (void) pthread_mutex_unlock(&transq_lock); 1535 return (2); 1536 default: 1537 report_gss_err(gettext("gss_wrap message"), maj_stat, 1538 min_stat); 1539 (void) pthread_mutex_unlock(&transq_lock); 1540 return (1); 1541 } 1542 1543 DPRINT((dfile, "Sending transmission queue token (seq=%lld, " 1544 "size=%d, transq len=%ld)\n", cur_node->seq_num, 1545 out_buf.length, transq_hdr.count)); 1546 if (send_token(&sockfd, &out_buf) < 0) { 1547 (void) gss_release_buffer(&min_stat, &out_buf); 1548 (void) pthread_mutex_unlock(&transq_lock); 1549 return (1); 1550 } 1551 (void) gss_release_buffer(&min_stat, &out_buf); 1552 1553 cur_node = cur_node->next; 1554 (void) pthread_mutex_unlock(&transq_lock); 1555 1556 } /* while */ 1557 1558 return (0); 1559 } 1560