657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * CDDL HEADER START
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * The contents of this file are subject to the terms of the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Common Development and Distribution License (the "License").
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * You may not use this file except in compliance with the License.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * See the License for the specific language governing permissions
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * and limitations under the License.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * When distributing Covered Code, include this CDDL HEADER in each
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * If applicable, add the following below this CDDL HEADER, with the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * fields enclosed by brackets "[]" replaced with your own identifying
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * information: Portions Copyright [yyyy] [name of copyright owner]
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * CDDL HEADER END
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Use is subject to license terms.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transport layer for audit_remote (handles connection establishment, gss
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * context initialization, message encryption and verification)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic char *ver_str = "01"; /* supported protocol version */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic char *ver_str_concat; /* concat serv/client version */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic pthread_once_t recv_once_control = PTHREAD_ONCE_INIT;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * The three locks synchronize the simultaneous actions on top of transmission
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * queue, socket, gss_context.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelpthread_mutex_t transq_lock = PTHREAD_MUTEX_INITIALIZER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelpthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelpthread_mutex_t gss_ctx_lock = PTHREAD_MUTEX_INITIALIZER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel/* reset routine synchronization - required by the sending thread */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelpthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic boolean_t reset_in_progress; /* reset routine in progress */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel#define NP_CLOSE -1 /* notification pipe - close message */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel#define NP_EXIT -2 /* notification pipe - exit message */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelint notify_pipe[2]; /* notif. pipe - receiving thread */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelpthread_cond_t reset_cv = PTHREAD_COND_INITIALIZER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel#define MAX_TOK_LEN (128 * 1000) /* max token length we accept (B) */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel/* transmission queue helpers */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic boolean_t transq_enqueue(transq_node_t **, gss_buffer_t,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic int transq_retransmit(void);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic void do_reset(int *, struct pollfd *, boolean_t);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic void do_cleanup(int *, struct pollfd *, boolean_t);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic void init_recv_record(void);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic int connect_timeout(int, struct sockaddr *, int);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelstatic int send_timeout(int, const char *, size_t);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * report_err() - wrapper, mainly due to enhance the code readability - report
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * error to syslog via call to __audit_syslog().
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel __audit_syslog("audit_remote.so", LOG_CONS | LOG_NDELAY, LOG_DAEMON,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * report_gss_err() - GSS API error reporting
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelreport_gss_err(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* major stat */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) gss_display_status(&_min, maj_stat, GSS_C_GSS_CODE,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel gettext("GSS API error - %s(%u): %.*s\n"), msg, maj_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* minor stat */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) gss_display_status(&_min, min_stat, GSS_C_MECH_CODE,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel gettext("GSS mech error - %s(%u): %.*s\n"), msg, min_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * prot_ver_negotiate() - negotiate/acknowledge the protocol version. Currently,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * there is only one version supported by the plugin - "01".
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Note: connection must be initiated prior version negotiation
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Set the version proposal string - once we support more than
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * version "01" this part should be extended to solve the concatenation
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * of supported version identifiers.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Protocol version proposal (size=%d): %.*s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel out_buf.length, out_buf.length, (char *)out_buf.value));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Sending protocol version token failed\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Receiving protocol version token failed\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Verify the sent/received string - memcmp() is sufficient here
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * because we support only one version and it is represented by
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the "01" string. The received version has to be "01" string as well.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel memcmp(out_buf.value, in_buf.value, out_buf.length) != 0) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Verification of the protocol version strings "
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Prepare the concatenated client/server version strings later used
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * as an application_data field in the gss_channel_bindings_struct
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * structure.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel ver_str_concat_sz = out_buf.length + in_buf.length + 1;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel ver_str_concat = (char *)calloc(1, ver_str_concat_sz);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy(ver_str_concat, out_buf.value, out_buf.length);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy(ver_str_concat + out_buf.length, in_buf.value,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Concatenated version strings: %s\n", ver_str_concat));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * sock_prepare() - creates and connects socket. Function returns
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * B_FALSE/B_TRUE on failure/success and sets the err_rsn accordingly to the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * reason of failure.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelsock_prepare(int *sockfdptr, struct hostent *host, close_rsn_t *err_rsn)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Creating socket for %s\n", host->h_name));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* unknown address family */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if ((sock = socket(addr.ss_family, SOCK_STREAM, 0)) == -1) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Socket created, fd=%d, connecting..\n", sock));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (connect_timeout(sock, (struct sockaddr *)&addr, addr_len)) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Connected to %s via fd=%d\n", host->h_name,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * establish_context() - establish the client/server GSS context.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Note: connection must be established and version negotiated (in plain text)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * prior to establishing context.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel struct gss_channel_bindings_struct input_chan_bindings;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* GSS service name = gss_svc_name + "@" + remote hostname (fqdn) */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) asprintf(&svc_name, "%s@%s", gss_svc_name, current_host->h_name);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Cannot allocate service name\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Service name: %s\n", svc_name));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel maj_stat = gss_import_name(&min_stat, &send_tok,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &gss_name);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_gss_err(gettext("initializing context"), maj_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* initialize channel binding */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel bzero(&input_chan_bindings, sizeof (input_chan_bindings));
bf515db2f8b506f788f69875fa1319cfbf177c9dJan Friedel input_chan_bindings.initiator_addrtype = GSS_C_AF_NULLADDR;
bf515db2f8b506f788f69875fa1319cfbf177c9dJan Friedel input_chan_bindings.acceptor_addrtype = GSS_C_AF_NULLADDR;
c7bef3b16d3d2a0b09ff75fbbd724283ef1ee7e7Jan Friedel input_chan_bindings.application_data.length = strlen(ver_str_concat);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel input_chan_bindings.application_data.value = ver_str_concat;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel maj_stat = gss_init_sec_context(&init_sec_min_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel GSS_C_NO_CREDENTIAL, &gss_ctx, gss_name, *current_mech_oid,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel | GSS_C_CONF_FLAG, 0, &input_chan_bindings, token_ptr,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) gss_release_buffer(&min_stat, &recv_tok);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "Sending init_sec_context token (size=%d)\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * delete_context() - release GSS context.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) gss_delete_sec_context(&min_stat, &gss_ctx, GSS_C_NO_BUFFER);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * send_token() - send GSS token over the wire.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Socket detected as closed.\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel out_buf = (char *)malloc((size_t)(lensz + tok->length));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy((void *)out_buf, (void *)&len, lensz);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy((void *)(out_buf + lensz), (void *)tok->value,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (send_timeout(fd, out_buf, (lensz + tok->length))) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * recv_token() - receive GSS token over the wire.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (recv_timeout(fd, (char *)&len, sizeof (len))) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* simple DOS prevention mechanism */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Indicated invalid token length"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Indicated token length > %dB\n", MAX_TOK_LEN));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * I/O functions
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * connect_timeout() - sets nonblocking I/O on a socket and timeout-connects
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelconnect_timeout(int sockfd, struct sockaddr *name, int namelen)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } else if (rc < 0) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (getpeername(sockfd, (struct sockaddr *)&addr,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * send_timeout() - send data (in chunks if needed, each chunk in timeout secs).
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelsend_timeout(int fd, const char *buf, size_t len)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } else if (rc < 0) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * recv_timeout() - receive data (in chunks if needed, each chunk in timeout
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * secs). In case the function is called from receiving thread, the function
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * cycles the poll() call in timeout seconds (waits for input from server).
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } else if (rc < 0) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel return (-1);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * read_fd() - reads data of length len from the given file descriptor fd to the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * buffer buf, in chunks if needed. Function returns B_FALSE on failure,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * otherwise B_TRUE. Function preserves errno, if it was set by the read(2).
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "read_fd: Read %d bytes.\n", len_o - len));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * write_fd() - writes buf of length len to the opened file descriptor fd, in
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * chunks if needed. The data from the pipe are processed in the receiving
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * thread. Function returns B_FALSE on failure, otherwise B_TRUE. Function
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * preserves errno, if it was set by the write(2).
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "write_fd: Wrote %d bytes.\n", len_o - len));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Plug-in entry point
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * send_record() - send an audit record to a host opening a connection,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * negotiate version and establish context if necessary.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelsend_record(struct hostlist_s *hostlptr, const char *input, size_t in_len,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel uint64_t seq_n; /* sequence in the network byte order */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * We need to grab the reset_lock here, to prevent eventual
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * unsynchronized cleanup calls within the reset routine (reset caused
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * by the receiving thread) and the initialization calls in the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * send_record() code path.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Check whether the socket was closed by the recv thread prior to call
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * send_record() and behave accordingly to the reason of the closure.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Send request to other then previously used host.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Set new host: %s\n", hostlptr->host->h_name));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel current_host = (struct hostent *)hostlptr->host;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* initiate the receiving thread */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) pthread_once(&recv_once_control, init_recv_record);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* create and connect() socket, negotiate the protocol version */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* socket operations */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Socket creation and connect\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!sock_prepare(&sockfd, current_host, err_rsn)) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* we believe the err_rsn set by sock_prepare() */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* protocol version negotiation */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Protocol version negotiation\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "Protocol version negotiation failed\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* let the socket be initiated for poll() */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* let the recv thread poll() on the sockfd */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* if not empty, retransmit contents of the transmission queue */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Retransmitting remaining (%ld) tokens from "
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if ((rc = transq_retransmit()) == 2) { /* gss context exp */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Concatenate sequence number and the new record. Note, that the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * pointer to the chunk of memory allocated for the concatenated values
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * is later passed to the transq_enqueu() function which stores the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * pointer in the transmission queue; subsequently called
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transq_dequeue() frees the allocated memory once the MIC is verified
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * by the recv_record() function.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * If we return earlier than the transq_enqueue() is called, it's
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * necessary to free the in_buf.value explicitly prior to return.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy(in_buf.value, &seq_n, sizeof (seq_n));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy((char *)in_buf.value + sizeof (seq_n), input, in_len);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* wrap sequence number and the new record to the per-message token */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_gss_err(gettext("gss_wrap message"), maj_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } else { /* GSS context deleted by the recv thread */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* enqueue the to-be-sent token into transmission queue */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!transq_enqueue(&node_ptr, &in_buf, sequence)) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Token enqueued for later verification\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* send token */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Token sent (transq size = %ld)\n", transq_hdr.count));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * init_recv_record() - initialize the receiver thread
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Initiating the recv thread\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) pthread_create(&recv_tid, NULL, (void *(*)(void *))recv_record,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * recv_record() - the receiver thread routine
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel gss_buffer_desc in_buf_mic = GSS_C_EMPTY_BUFFER;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel uint64_t r_seq_num; /* received sequence number */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Fill in the information in the vector of file descriptors passed
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * later on to the poll() function. In the initial state, there is only
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * one struct pollfd in the vector which contains file descriptor of the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * notification pipe - notify_pipe[1]. There might be up to two file
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * descriptors (struct pollfd) in the vector - notify_pipe[1] which
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * resides in the vector during the entire life of the receiving thread,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * and the own file descriptor from which we read data sent by the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * remote server application.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * In the endless loop, try to grab some data from the socket or
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * notify_pipe[1].
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* block on poll, thus rc != 0 */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* silently continue on EAGAIN || EINTR */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* log the debug message in any other case */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Receive a message from the notification pipe. Information
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * from the notification pipe takes precedence over the received
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * data from the remote server application.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Notification pipe message format - message accepted
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * from the notify pipe comprises of two parts (int ||
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * boolean_t), where if the first part (sizeof (int)) equals
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * NP_CLOSE, then the second part (sizeof (boolean_t)) signals
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the necessity of broadcasting (DO_SYNC/DO_NOT_SYNC) the end
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * of the reset routine.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "An event on notify pipe detected\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel default: /* add rc_pipe to the fds */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* Receive a token from the remote server application */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!read_fd(recv_fd->fd, (char *)&len, sizeof (len))) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* simple DOS prevention mechanism */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Indicated token length > %dB\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!read_fd(recv_fd->fd, (char *)in_buf.value, len)) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Extract the sequence number and the MIC from
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the per-message token
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) memcpy(&r_seq_num, in_buf.value, sizeof (r_seq_num));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel in_buf_mic.length = in_buf.length - sizeof (r_seq_num);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel in_buf_mic.value = (char *)in_buf.value + sizeof (r_seq_num);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * seq_num/r_seq_num - the sequence number does not need to
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * be unique in the transmission queue. Any token in the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transmission queue with the same seq_num as the acknowledge
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * token received from the server is tested. This is due to the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * fact that the plugin cannot influence (in the current
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * implementation) sequence numbers generated by the kernel (we
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * are reusing record sequence numbers as a transmission queue
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * sequence numbers). The probability of having two or more
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * tokens in the transmission queue is low and at the same time
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the performance gain due to using sequence numbers is quite
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * In case a harder condition with regard to duplicate sequence
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * numbers in the transmission queue will be desired over time,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the break_flag behavior used below should be
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!GSS_ERROR(maj_stat)) { /* the success case */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * All the GSS_S_OLD_TOKEN, GSS_S_UNSEQ_TOKEN,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * GSS_S_GAP_TOKEN are perceived as correct
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * behavior of the server side. The plugin
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * implementation is resistant to any of the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * above mention cases of returned status codes.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /*FALLTHRU*/
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * remove the verified record/node from
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the transmission queue
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "the token (transq len = %ld)\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Both the default case as well as
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * GSS_S_DUPLICATE_TOKEN case should never
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * occur. It's been left here for the sake of
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * completeness.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * If any of the two cases occur, it is
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * subsequently cought because we don't set
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the token_verified flag.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /*FALLTHRU*/
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } /* switch (maj_stat) */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } else { /* the failure case */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "received token failed"),
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* retransmission necessary */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "the GSS context expiration\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "detected (seq_num = %lld)\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } /* while */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Received, but unverifiable token is perceived as
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the protocol flow corruption with the penalty of
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * reinitializing the client/server connection.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "received unverifiable token\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("received unverifiable token\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } /* for (;;) */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * init_poll() - initiates the polling in the receiving thread via sending the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * appropriate message over the notify pipe. Message format = (int ||
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * booleant_t), where the first part (sizeof (int)) contains the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * newly_opened/to_be_polled socket file descriptor. The contents of the second
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * part (sizeof (boolean_t)) of the message works only as a padding here and no
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * action (no recv/send thread synchronisation) is made in the receiving thread
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * based on its value.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel if (!write_fd(pipe_in, (char *)&np_data, sizeof (np_data))) {
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Cannot write to the notify pipe\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("writing to the notify pipe failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * reset_transport() - locked by the reset_lock initiates the reset of socket,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * GSS security context and (possibly) flags the transq for retransmission; for
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * more detailed information see do_reset(). The reset_transport() also allows
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the synchronization - waiting for the reset to be finished.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * do_close: DO_SYNC, DO_NOT_SYNC
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * sync_on_return: DO_EXIT (DO_NOT_CLOSE), DO_CLOSE (DO_NOT_EXIT)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedelreset_transport(boolean_t do_close, boolean_t sync_on_return)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Check if the reset routine is in progress or whether it was already
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * executed by some other thread.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel np_data.sock_num = (do_close ? NP_CLOSE : NP_EXIT);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) write_fd(pipe_in, (char *)&np_data, sizeof (np_data));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (void) pthread_cond_wait(&reset_cv, &reset_lock);
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * do_reset() - the own reseting routine called from the recv thread. If the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * synchronization was requested, signal the finish via conditional variable.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedeldo_reset(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* socket */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* context */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* mark transq to be flushed */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * do_cleanup() - removes all the preallocated space by the plugin; prepares the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * plugin/application to be gracefully finished. Even thought the function
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * allows execution without signalling the successful finish, it's recommended
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * to use it (we usually want to wait for cleanup before exiting).
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedeldo_cleanup(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal)
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * note: keeping locking for safety, thought it shouldn't be necessary
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * in current implementation - we get here only in case the sending code
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * path calls auditd_plugin_close() (thus no socket manipulation) and
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * the recv thread is doing the own socket closure.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Closing socket: %d\n", sockfd));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* context */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* transmission queue */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Deallocating the transmission queue "
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* notification pipe */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transq_dequeue() - dequeues given node pointed by the node_ptr from the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transmission queue. Transmission queue should be locked prior to use of this
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "transq_dequeue(): called with NULL pointer\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* update the transq_hdr */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transq_enqueue() - creates new node in (at the end of) the transmission
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * queue. in_ptoken_ptr is a pointer to the plain token in a form of
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * gss_buffer_desc. Function returns 0 on success and updates the *node_ptr to
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * point to a newly added transmission queue node. In case of any failure
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * function returns 1 and sets the *node_ptr to NULL.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Transmission queue should be locked prior to use of this function.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedeltransq_enqueue(transq_node_t **node_ptr, gss_buffer_t in_seqtoken_ptr,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_err(gettext("Memory allocation failed"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Memory allocation failed: %s\n",
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* value of the seq_token.value = (sequence number || plain token) */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (*node_ptr)->seq_token.length = in_seqtoken_ptr->length;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel (*node_ptr)->seq_token.value = in_seqtoken_ptr->value;
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel /* update the transq_hdr */
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * transq_retransmit() - traverse the transmission queue and try to, 1 by 1,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * re-wrap the tokens with the recent context information and retransmit the
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * tokens from the transmission queue.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * Function returns 2 on GSS context expiration, 1 on any other error, 0 on
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel * successfully resent transmission queue.
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Retransmission of the remainder in the transqueue\n"));
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_gss_err(gettext("gss_wrap message"), maj_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel report_gss_err(gettext("gss_wrap message"), maj_stat,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel DPRINT((dfile, "Sending transmission queue token (seq=%lld, "
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel "size=%d, transq len=%ld)\n", cur_node->seq_num,
657a8c206b913d1ee578fd725f0b25eca5b77253Jan Friedel } /* while */