110188SJan.Friedel@Sun.COM /*
210188SJan.Friedel@Sun.COM * CDDL HEADER START
310188SJan.Friedel@Sun.COM *
410188SJan.Friedel@Sun.COM * The contents of this file are subject to the terms of the
510188SJan.Friedel@Sun.COM * Common Development and Distribution License (the "License").
610188SJan.Friedel@Sun.COM * You may not use this file except in compliance with the License.
710188SJan.Friedel@Sun.COM *
810188SJan.Friedel@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910188SJan.Friedel@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010188SJan.Friedel@Sun.COM * See the License for the specific language governing permissions
1110188SJan.Friedel@Sun.COM * and limitations under the License.
1210188SJan.Friedel@Sun.COM *
1310188SJan.Friedel@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410188SJan.Friedel@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510188SJan.Friedel@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610188SJan.Friedel@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710188SJan.Friedel@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810188SJan.Friedel@Sun.COM *
1910188SJan.Friedel@Sun.COM * CDDL HEADER END
2010188SJan.Friedel@Sun.COM */
2110188SJan.Friedel@Sun.COM /*
2210188SJan.Friedel@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2310188SJan.Friedel@Sun.COM * Use is subject to license terms.
2410188SJan.Friedel@Sun.COM *
2510188SJan.Friedel@Sun.COM * transport layer for audit_remote (handles connection establishment, gss
2610188SJan.Friedel@Sun.COM * context initialization, message encryption and verification)
2710188SJan.Friedel@Sun.COM *
2810188SJan.Friedel@Sun.COM */
2910188SJan.Friedel@Sun.COM
3010188SJan.Friedel@Sun.COM #include <assert.h>
3110188SJan.Friedel@Sun.COM #include <audit_plugin.h>
3210188SJan.Friedel@Sun.COM #include <errno.h>
3310188SJan.Friedel@Sun.COM #include <fcntl.h>
3410188SJan.Friedel@Sun.COM #include <gssapi/gssapi.h>
3510188SJan.Friedel@Sun.COM #include <libintl.h>
3610188SJan.Friedel@Sun.COM #include <mtmalloc.h>
3710188SJan.Friedel@Sun.COM #include <netdb.h>
3810188SJan.Friedel@Sun.COM #include <netinet/in.h>
3910188SJan.Friedel@Sun.COM #include <netinet/tcp.h>
4010188SJan.Friedel@Sun.COM #include <stdio.h>
4110188SJan.Friedel@Sun.COM #include <stdlib.h>
4210188SJan.Friedel@Sun.COM #include <string.h>
4310188SJan.Friedel@Sun.COM #include <strings.h>
4410188SJan.Friedel@Sun.COM #include <syslog.h>
4510188SJan.Friedel@Sun.COM #include <sys/types.h>
4610188SJan.Friedel@Sun.COM #include <sys/socket.h>
4710188SJan.Friedel@Sun.COM #include <unistd.h>
4810188SJan.Friedel@Sun.COM #include <poll.h>
4910188SJan.Friedel@Sun.COM #include <pthread.h>
5010188SJan.Friedel@Sun.COM
5110188SJan.Friedel@Sun.COM #include "audit_remote.h"
5210188SJan.Friedel@Sun.COM
5310188SJan.Friedel@Sun.COM
5410188SJan.Friedel@Sun.COM static int sockfd = -1;
5510188SJan.Friedel@Sun.COM static struct hostent *current_host;
5610188SJan.Friedel@Sun.COM static gss_OID *current_mech_oid;
5710188SJan.Friedel@Sun.COM static in_port_t current_port;
5810188SJan.Friedel@Sun.COM static boolean_t flush_transq;
5910188SJan.Friedel@Sun.COM
6010188SJan.Friedel@Sun.COM static char *ver_str = "01"; /* supported protocol version */
6110188SJan.Friedel@Sun.COM static char *ver_str_concat; /* concat serv/client version */
6210188SJan.Friedel@Sun.COM
6310188SJan.Friedel@Sun.COM static gss_ctx_id_t gss_ctx;
6410188SJan.Friedel@Sun.COM static boolean_t gss_ctx_initialized;
6510188SJan.Friedel@Sun.COM
6610188SJan.Friedel@Sun.COM pthread_t recv_tid; /* receiving thread */
6710188SJan.Friedel@Sun.COM static pthread_once_t recv_once_control = PTHREAD_ONCE_INIT;
6810188SJan.Friedel@Sun.COM
6910188SJan.Friedel@Sun.COM extern int timeout; /* connection timeout */
7010188SJan.Friedel@Sun.COM
7110188SJan.Friedel@Sun.COM extern pthread_mutex_t plugin_mutex;
7210188SJan.Friedel@Sun.COM transq_hdr_t transq_hdr;
7310188SJan.Friedel@Sun.COM
7410188SJan.Friedel@Sun.COM /*
7510188SJan.Friedel@Sun.COM * The three locks synchronize the simultaneous actions on top of transmission
7610188SJan.Friedel@Sun.COM * queue, socket, gss_context.
7710188SJan.Friedel@Sun.COM */
7810188SJan.Friedel@Sun.COM pthread_mutex_t transq_lock = PTHREAD_MUTEX_INITIALIZER;
7910188SJan.Friedel@Sun.COM pthread_mutex_t sock_lock = PTHREAD_MUTEX_INITIALIZER;
8010188SJan.Friedel@Sun.COM pthread_mutex_t gss_ctx_lock = PTHREAD_MUTEX_INITIALIZER;
8110188SJan.Friedel@Sun.COM
8210188SJan.Friedel@Sun.COM /* reset routine synchronization - required by the sending thread */
8310188SJan.Friedel@Sun.COM pthread_mutex_t reset_lock = PTHREAD_MUTEX_INITIALIZER;
8410188SJan.Friedel@Sun.COM static boolean_t reset_in_progress; /* reset routine in progress */
8510188SJan.Friedel@Sun.COM
8610188SJan.Friedel@Sun.COM #define NP_CLOSE -1 /* notification pipe - close message */
8710188SJan.Friedel@Sun.COM #define NP_EXIT -2 /* notification pipe - exit message */
8810188SJan.Friedel@Sun.COM boolean_t notify_pipe_ready;
8910188SJan.Friedel@Sun.COM int notify_pipe[2]; /* notif. pipe - receiving thread */
9010188SJan.Friedel@Sun.COM
9110188SJan.Friedel@Sun.COM pthread_cond_t reset_cv = PTHREAD_COND_INITIALIZER;
9210188SJan.Friedel@Sun.COM static close_rsn_t recv_closure_rsn;
9310188SJan.Friedel@Sun.COM
9410188SJan.Friedel@Sun.COM #define MAX_TOK_LEN (128 * 1000) /* max token length we accept (B) */
9510188SJan.Friedel@Sun.COM
9610188SJan.Friedel@Sun.COM /* transmission queue helpers */
9710188SJan.Friedel@Sun.COM static void transq_dequeue(transq_node_t *);
9810188SJan.Friedel@Sun.COM static boolean_t transq_enqueue(transq_node_t **, gss_buffer_t,
9910188SJan.Friedel@Sun.COM uint64_t);
10010188SJan.Friedel@Sun.COM static int transq_retransmit(void);
10110188SJan.Friedel@Sun.COM
10210188SJan.Friedel@Sun.COM static boolean_t init_poll(int);
10310188SJan.Friedel@Sun.COM static void do_reset(int *, struct pollfd *, boolean_t);
10410188SJan.Friedel@Sun.COM static void do_cleanup(int *, struct pollfd *, boolean_t);
10510188SJan.Friedel@Sun.COM
10610188SJan.Friedel@Sun.COM static void init_recv_record(void);
10710188SJan.Friedel@Sun.COM static void recv_record();
10810188SJan.Friedel@Sun.COM static int connect_timeout(int, struct sockaddr *, int);
10910188SJan.Friedel@Sun.COM static int send_timeout(int, const char *, size_t);
11010188SJan.Friedel@Sun.COM static int recv_timeout(int, char *, size_t);
11110188SJan.Friedel@Sun.COM static int send_token(int *, gss_buffer_t);
11210188SJan.Friedel@Sun.COM static int recv_token(int, gss_buffer_t);
11310188SJan.Friedel@Sun.COM
11410188SJan.Friedel@Sun.COM
11510188SJan.Friedel@Sun.COM /*
11610188SJan.Friedel@Sun.COM * report_err() - wrapper, mainly due to enhance the code readability - report
11710188SJan.Friedel@Sun.COM * error to syslog via call to __audit_syslog().
11810188SJan.Friedel@Sun.COM */
11910188SJan.Friedel@Sun.COM static void
report_err(char * msg)12010188SJan.Friedel@Sun.COM report_err(char *msg)
12110188SJan.Friedel@Sun.COM {
12210188SJan.Friedel@Sun.COM __audit_syslog("audit_remote.so", LOG_CONS | LOG_NDELAY, LOG_DAEMON,
12310188SJan.Friedel@Sun.COM LOG_ERR, msg);
12410188SJan.Friedel@Sun.COM
12510188SJan.Friedel@Sun.COM }
12610188SJan.Friedel@Sun.COM
12710188SJan.Friedel@Sun.COM
12810188SJan.Friedel@Sun.COM /*
12910188SJan.Friedel@Sun.COM * report_gss_err() - GSS API error reporting
13010188SJan.Friedel@Sun.COM */
13110188SJan.Friedel@Sun.COM static void
report_gss_err(char * msg,OM_uint32 maj_stat,OM_uint32 min_stat)13210188SJan.Friedel@Sun.COM report_gss_err(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat)
13310188SJan.Friedel@Sun.COM {
13410188SJan.Friedel@Sun.COM gss_buffer_desc msg_buf;
13510188SJan.Friedel@Sun.COM OM_uint32 _min, msg_ctx;
13610188SJan.Friedel@Sun.COM char *err_msg;
13710188SJan.Friedel@Sun.COM
13810188SJan.Friedel@Sun.COM /* major stat */
13910188SJan.Friedel@Sun.COM msg_ctx = 0;
14010188SJan.Friedel@Sun.COM do {
14110188SJan.Friedel@Sun.COM (void) gss_display_status(&_min, maj_stat, GSS_C_GSS_CODE,
14210188SJan.Friedel@Sun.COM *current_mech_oid, &msg_ctx, &msg_buf);
14310188SJan.Friedel@Sun.COM (void) asprintf(&err_msg,
14410188SJan.Friedel@Sun.COM gettext("GSS API error - %s(%u): %.*s\n"), msg, maj_stat,
14510188SJan.Friedel@Sun.COM msg_buf.length, (char *)msg_buf.value);
14610188SJan.Friedel@Sun.COM if (err_msg != NULL) {
14710188SJan.Friedel@Sun.COM report_err(err_msg);
14810188SJan.Friedel@Sun.COM free(err_msg);
14910188SJan.Friedel@Sun.COM }
15010188SJan.Friedel@Sun.COM (void) gss_release_buffer(&_min, &msg_buf);
15110188SJan.Friedel@Sun.COM } while (msg_ctx);
15210188SJan.Friedel@Sun.COM
15310188SJan.Friedel@Sun.COM /* minor stat */
15410188SJan.Friedel@Sun.COM msg_ctx = 0;
15510188SJan.Friedel@Sun.COM do {
15610188SJan.Friedel@Sun.COM (void) gss_display_status(&_min, min_stat, GSS_C_MECH_CODE,
15710188SJan.Friedel@Sun.COM *current_mech_oid, &msg_ctx, &msg_buf);
15810188SJan.Friedel@Sun.COM (void) asprintf(&err_msg,
15910188SJan.Friedel@Sun.COM gettext("GSS mech error - %s(%u): %.*s\n"), msg, min_stat,
16010188SJan.Friedel@Sun.COM msg_buf.length, (char *)msg_buf.value);
16110188SJan.Friedel@Sun.COM if (err_msg != NULL) {
16210188SJan.Friedel@Sun.COM report_err(err_msg);
16310188SJan.Friedel@Sun.COM free(err_msg);
16410188SJan.Friedel@Sun.COM }
16510188SJan.Friedel@Sun.COM (void) gss_release_buffer(&_min, &msg_buf);
16610188SJan.Friedel@Sun.COM } while (msg_ctx);
16710188SJan.Friedel@Sun.COM }
16810188SJan.Friedel@Sun.COM
16910188SJan.Friedel@Sun.COM /*
17010188SJan.Friedel@Sun.COM * prot_ver_negotiate() - negotiate/acknowledge the protocol version. Currently,
17110188SJan.Friedel@Sun.COM * there is only one version supported by the plugin - "01".
17210188SJan.Friedel@Sun.COM * Note: connection must be initiated prior version negotiation
17310188SJan.Friedel@Sun.COM */
17410188SJan.Friedel@Sun.COM static int
prot_ver_negotiate()17510188SJan.Friedel@Sun.COM prot_ver_negotiate()
17610188SJan.Friedel@Sun.COM {
17710188SJan.Friedel@Sun.COM gss_buffer_desc out_buf, in_buf;
17810188SJan.Friedel@Sun.COM size_t ver_str_concat_sz;
17910188SJan.Friedel@Sun.COM
18010188SJan.Friedel@Sun.COM /*
18110188SJan.Friedel@Sun.COM * Set the version proposal string - once we support more than
18210188SJan.Friedel@Sun.COM * version "01" this part should be extended to solve the concatenation
18310188SJan.Friedel@Sun.COM * of supported version identifiers.
18410188SJan.Friedel@Sun.COM */
18510188SJan.Friedel@Sun.COM out_buf.value = (void *)ver_str;
18610188SJan.Friedel@Sun.COM out_buf.length = strlen((char *)out_buf.value);
18710188SJan.Friedel@Sun.COM DPRINT((dfile, "Protocol version proposal (size=%d): %.*s\n",
18810188SJan.Friedel@Sun.COM out_buf.length, out_buf.length, (char *)out_buf.value));
18910188SJan.Friedel@Sun.COM
19010188SJan.Friedel@Sun.COM if (send_token(&sockfd, &out_buf) < 0) {
19110188SJan.Friedel@Sun.COM DPRINT((dfile, "Sending protocol version token failed\n"));
19210188SJan.Friedel@Sun.COM return (-1);
19310188SJan.Friedel@Sun.COM }
19410188SJan.Friedel@Sun.COM
19510188SJan.Friedel@Sun.COM if (recv_token(sockfd, &in_buf) < 0) {
19610188SJan.Friedel@Sun.COM DPRINT((dfile, "Receiving protocol version token failed\n"));
19710188SJan.Friedel@Sun.COM return (-1);
19810188SJan.Friedel@Sun.COM }
19910188SJan.Friedel@Sun.COM
20010188SJan.Friedel@Sun.COM /*
20110188SJan.Friedel@Sun.COM * Verify the sent/received string - memcmp() is sufficient here
20210188SJan.Friedel@Sun.COM * because we support only one version and it is represented by
20310188SJan.Friedel@Sun.COM * the "01" string. The received version has to be "01" string as well.
20410188SJan.Friedel@Sun.COM */
20510188SJan.Friedel@Sun.COM if (out_buf.length != in_buf.length ||
20610188SJan.Friedel@Sun.COM memcmp(out_buf.value, in_buf.value, out_buf.length) != 0) {
20710188SJan.Friedel@Sun.COM DPRINT((dfile, "Verification of the protocol version strings "
20810188SJan.Friedel@Sun.COM "failed [%d:%s][%d:%s]\n", out_buf.length,
20910188SJan.Friedel@Sun.COM (char *)out_buf.value, in_buf.length,
21010188SJan.Friedel@Sun.COM (char *)in_buf.value));
21110188SJan.Friedel@Sun.COM free(in_buf.value);
21210188SJan.Friedel@Sun.COM return (-1);
21310188SJan.Friedel@Sun.COM }
21410188SJan.Friedel@Sun.COM
21510188SJan.Friedel@Sun.COM /*
21610188SJan.Friedel@Sun.COM * Prepare the concatenated client/server version strings later used
21710188SJan.Friedel@Sun.COM * as an application_data field in the gss_channel_bindings_struct
21810188SJan.Friedel@Sun.COM * structure.
21910188SJan.Friedel@Sun.COM */
22010188SJan.Friedel@Sun.COM ver_str_concat_sz = out_buf.length + in_buf.length + 1;
22110188SJan.Friedel@Sun.COM ver_str_concat = (char *)calloc(1, ver_str_concat_sz);
22210188SJan.Friedel@Sun.COM if (ver_str_concat == NULL) {
22310188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
22410188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
22510188SJan.Friedel@Sun.COM strerror(errno)));
22610188SJan.Friedel@Sun.COM free(in_buf.value);
22710188SJan.Friedel@Sun.COM return (-1);
22810188SJan.Friedel@Sun.COM }
22910188SJan.Friedel@Sun.COM (void) memcpy(ver_str_concat, out_buf.value, out_buf.length);
23010188SJan.Friedel@Sun.COM (void) memcpy(ver_str_concat + out_buf.length, in_buf.value,
23110188SJan.Friedel@Sun.COM in_buf.length);
23210188SJan.Friedel@Sun.COM DPRINT((dfile, "Concatenated version strings: %s\n", ver_str_concat));
23310188SJan.Friedel@Sun.COM
23410188SJan.Friedel@Sun.COM DPRINT((dfile, "Protocol version agreed.\n"));
23510188SJan.Friedel@Sun.COM free(in_buf.value);
23610188SJan.Friedel@Sun.COM return (0);
23710188SJan.Friedel@Sun.COM }
23810188SJan.Friedel@Sun.COM
23910188SJan.Friedel@Sun.COM /*
24010188SJan.Friedel@Sun.COM * sock_prepare() - creates and connects socket. Function returns
24110188SJan.Friedel@Sun.COM * B_FALSE/B_TRUE on failure/success and sets the err_rsn accordingly to the
24210188SJan.Friedel@Sun.COM * reason of failure.
24310188SJan.Friedel@Sun.COM */
24410188SJan.Friedel@Sun.COM static boolean_t
sock_prepare(int * sockfdptr,struct hostent * host,close_rsn_t * err_rsn)24510188SJan.Friedel@Sun.COM sock_prepare(int *sockfdptr, struct hostent *host, close_rsn_t *err_rsn)
24610188SJan.Friedel@Sun.COM {
24710188SJan.Friedel@Sun.COM struct sockaddr_storage addr;
24810188SJan.Friedel@Sun.COM struct sockaddr_in *sin;
24910188SJan.Friedel@Sun.COM struct sockaddr_in6 *sin6;
25010188SJan.Friedel@Sun.COM size_t addr_len;
25110188SJan.Friedel@Sun.COM int sock;
25210188SJan.Friedel@Sun.COM
25310188SJan.Friedel@Sun.COM DPRINT((dfile, "Creating socket for %s\n", host->h_name));
25410188SJan.Friedel@Sun.COM bzero(&addr, sizeof (addr));
25510188SJan.Friedel@Sun.COM addr.ss_family = host->h_addrtype;
25610188SJan.Friedel@Sun.COM switch (host->h_addrtype) {
25710188SJan.Friedel@Sun.COM case AF_INET:
25810188SJan.Friedel@Sun.COM sin = (struct sockaddr_in *)&addr;
25910188SJan.Friedel@Sun.COM addr_len = sizeof (struct sockaddr_in);
26010188SJan.Friedel@Sun.COM bcopy(host->h_addr_list[0],
26110188SJan.Friedel@Sun.COM &(sin->sin_addr), sizeof (struct in_addr));
26210188SJan.Friedel@Sun.COM sin->sin_port = current_port;
26310188SJan.Friedel@Sun.COM break;
26410188SJan.Friedel@Sun.COM case AF_INET6:
26510188SJan.Friedel@Sun.COM sin6 = (struct sockaddr_in6 *)&addr;
26610188SJan.Friedel@Sun.COM addr_len = sizeof (struct sockaddr_in6);
26710188SJan.Friedel@Sun.COM bcopy(host->h_addr_list[0],
26810188SJan.Friedel@Sun.COM &(sin6->sin6_addr), sizeof (struct in6_addr));
26910188SJan.Friedel@Sun.COM sin6->sin6_port = current_port;
27010188SJan.Friedel@Sun.COM break;
27110188SJan.Friedel@Sun.COM default:
27210188SJan.Friedel@Sun.COM /* unknown address family */
27310188SJan.Friedel@Sun.COM *err_rsn = RSN_UNKNOWN_AF;
27410188SJan.Friedel@Sun.COM return (B_FALSE);
27510188SJan.Friedel@Sun.COM }
27610188SJan.Friedel@Sun.COM if ((sock = socket(addr.ss_family, SOCK_STREAM, 0)) == -1) {
27710188SJan.Friedel@Sun.COM *err_rsn = RSN_SOCKET_CREATE;
27810188SJan.Friedel@Sun.COM return (B_FALSE);
27910188SJan.Friedel@Sun.COM }
28010188SJan.Friedel@Sun.COM DPRINT((dfile, "Socket created, fd=%d, connecting..\n", sock));
28110188SJan.Friedel@Sun.COM
28210188SJan.Friedel@Sun.COM if (connect_timeout(sock, (struct sockaddr *)&addr, addr_len)) {
28310188SJan.Friedel@Sun.COM (void) close(sock);
28410188SJan.Friedel@Sun.COM *err_rsn = RSN_CONNECTION_CREATE;
28510188SJan.Friedel@Sun.COM return (B_FALSE);
28610188SJan.Friedel@Sun.COM }
28710188SJan.Friedel@Sun.COM *sockfdptr = sock;
28810188SJan.Friedel@Sun.COM DPRINT((dfile, "Connected to %s via fd=%d\n", host->h_name,
28910188SJan.Friedel@Sun.COM *sockfdptr));
29010188SJan.Friedel@Sun.COM
29110188SJan.Friedel@Sun.COM return (B_TRUE);
29210188SJan.Friedel@Sun.COM }
29310188SJan.Friedel@Sun.COM
29410188SJan.Friedel@Sun.COM /*
29510188SJan.Friedel@Sun.COM * establish_context() - establish the client/server GSS context.
29610188SJan.Friedel@Sun.COM *
29710188SJan.Friedel@Sun.COM * Note: connection must be established and version negotiated (in plain text)
29810188SJan.Friedel@Sun.COM * prior to establishing context.
29910188SJan.Friedel@Sun.COM */
30010188SJan.Friedel@Sun.COM static int
establish_context()30110188SJan.Friedel@Sun.COM establish_context()
30210188SJan.Friedel@Sun.COM {
30310188SJan.Friedel@Sun.COM gss_buffer_desc send_tok, recv_tok, *token_ptr;
30410188SJan.Friedel@Sun.COM OM_uint32 maj_stat, min_stat;
30510188SJan.Friedel@Sun.COM OM_uint32 init_sec_min_stat, ret_flags;
30610188SJan.Friedel@Sun.COM gss_name_t gss_name;
30710188SJan.Friedel@Sun.COM char *gss_svc_name = "audit";
30810188SJan.Friedel@Sun.COM char *svc_name;
30910188SJan.Friedel@Sun.COM struct gss_channel_bindings_struct input_chan_bindings;
31010188SJan.Friedel@Sun.COM
31110188SJan.Friedel@Sun.COM /* GSS service name = gss_svc_name + "@" + remote hostname (fqdn) */
31210188SJan.Friedel@Sun.COM (void) asprintf(&svc_name, "%s@%s", gss_svc_name, current_host->h_name);
31310188SJan.Friedel@Sun.COM if (svc_name == NULL) {
31410188SJan.Friedel@Sun.COM report_err(gettext("Cannot allocate service name\n"));
31510188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
31610188SJan.Friedel@Sun.COM strerror(errno)));
31710188SJan.Friedel@Sun.COM return (-1);
31810188SJan.Friedel@Sun.COM }
31910188SJan.Friedel@Sun.COM DPRINT((dfile, "Service name: %s\n", svc_name));
32010188SJan.Friedel@Sun.COM
32110188SJan.Friedel@Sun.COM send_tok.value = svc_name;
32210188SJan.Friedel@Sun.COM send_tok.length = strlen(svc_name);
32310188SJan.Friedel@Sun.COM maj_stat = gss_import_name(&min_stat, &send_tok,
32410188SJan.Friedel@Sun.COM (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &gss_name);
32510188SJan.Friedel@Sun.COM if (maj_stat != GSS_S_COMPLETE) {
32610188SJan.Friedel@Sun.COM report_gss_err(gettext("initializing context"), maj_stat,
32710188SJan.Friedel@Sun.COM min_stat);
32810188SJan.Friedel@Sun.COM free(svc_name);
32910188SJan.Friedel@Sun.COM return (-1);
33010188SJan.Friedel@Sun.COM }
33110188SJan.Friedel@Sun.COM token_ptr = GSS_C_NO_BUFFER;
33210188SJan.Friedel@Sun.COM gss_ctx = GSS_C_NO_CONTEXT;
33310188SJan.Friedel@Sun.COM
33410188SJan.Friedel@Sun.COM /* initialize channel binding */
33510188SJan.Friedel@Sun.COM bzero(&input_chan_bindings, sizeof (input_chan_bindings));
33610925SJan.Friedel@Sun.COM input_chan_bindings.initiator_addrtype = GSS_C_AF_NULLADDR;
33710925SJan.Friedel@Sun.COM input_chan_bindings.acceptor_addrtype = GSS_C_AF_NULLADDR;
338*10926SJan.Friedel@Sun.COM input_chan_bindings.application_data.length = strlen(ver_str_concat);
33910188SJan.Friedel@Sun.COM input_chan_bindings.application_data.value = ver_str_concat;
34010188SJan.Friedel@Sun.COM
34110188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&gss_ctx_lock);
34210188SJan.Friedel@Sun.COM do {
34310188SJan.Friedel@Sun.COM maj_stat = gss_init_sec_context(&init_sec_min_stat,
34410188SJan.Friedel@Sun.COM GSS_C_NO_CREDENTIAL, &gss_ctx, gss_name, *current_mech_oid,
34510188SJan.Friedel@Sun.COM GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG
34610188SJan.Friedel@Sun.COM | GSS_C_CONF_FLAG, 0, &input_chan_bindings, token_ptr,
34710188SJan.Friedel@Sun.COM NULL, &send_tok, &ret_flags, NULL);
34810188SJan.Friedel@Sun.COM
34910188SJan.Friedel@Sun.COM if (token_ptr != GSS_C_NO_BUFFER) {
35010188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &recv_tok);
35110188SJan.Friedel@Sun.COM }
35210188SJan.Friedel@Sun.COM
35310188SJan.Friedel@Sun.COM if (send_tok.length != 0) {
35410188SJan.Friedel@Sun.COM DPRINT((dfile,
35510188SJan.Friedel@Sun.COM "Sending init_sec_context token (size=%d)\n",
35610188SJan.Friedel@Sun.COM send_tok.length));
35710188SJan.Friedel@Sun.COM if (send_token(&sockfd, &send_tok) < 0) {
35810188SJan.Friedel@Sun.COM free(svc_name);
35910188SJan.Friedel@Sun.COM (void) gss_release_name(&min_stat, &gss_name);
36010188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
36110188SJan.Friedel@Sun.COM return (-1);
36210188SJan.Friedel@Sun.COM }
36310188SJan.Friedel@Sun.COM }
36410188SJan.Friedel@Sun.COM if (send_tok.value != NULL) {
36510188SJan.Friedel@Sun.COM free(send_tok.value); /* freeing svc_name */
36610188SJan.Friedel@Sun.COM send_tok.value = NULL;
36710188SJan.Friedel@Sun.COM send_tok.length = 0;
36810188SJan.Friedel@Sun.COM }
36910188SJan.Friedel@Sun.COM
37010188SJan.Friedel@Sun.COM if (maj_stat != GSS_S_COMPLETE &&
37110188SJan.Friedel@Sun.COM maj_stat != GSS_S_CONTINUE_NEEDED) {
37210188SJan.Friedel@Sun.COM report_gss_err(gettext("initializing context"),
37310188SJan.Friedel@Sun.COM maj_stat, init_sec_min_stat);
37410188SJan.Friedel@Sun.COM if (gss_ctx == GSS_C_NO_CONTEXT) {
37510188SJan.Friedel@Sun.COM (void) gss_delete_sec_context(&min_stat,
37610188SJan.Friedel@Sun.COM &gss_ctx, GSS_C_NO_BUFFER);
37710188SJan.Friedel@Sun.COM }
37810188SJan.Friedel@Sun.COM (void) gss_release_name(&min_stat, &gss_name);
37910188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
38010188SJan.Friedel@Sun.COM return (-1);
38110188SJan.Friedel@Sun.COM }
38210188SJan.Friedel@Sun.COM
38310188SJan.Friedel@Sun.COM if (maj_stat == GSS_S_CONTINUE_NEEDED) {
38410188SJan.Friedel@Sun.COM DPRINT((dfile, "continue needed... "));
38510188SJan.Friedel@Sun.COM if (recv_token(sockfd, &recv_tok) < 0) {
38610188SJan.Friedel@Sun.COM (void) gss_release_name(&min_stat, &gss_name);
38710188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
38810188SJan.Friedel@Sun.COM return (-1);
38910188SJan.Friedel@Sun.COM }
39010188SJan.Friedel@Sun.COM token_ptr = &recv_tok;
39110188SJan.Friedel@Sun.COM }
39210188SJan.Friedel@Sun.COM } while (maj_stat == GSS_S_CONTINUE_NEEDED);
39310188SJan.Friedel@Sun.COM (void) gss_release_name(&min_stat, &gss_name);
39410188SJan.Friedel@Sun.COM
39510188SJan.Friedel@Sun.COM DPRINT((dfile, "context established\n"));
39610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
39710188SJan.Friedel@Sun.COM return (0);
39810188SJan.Friedel@Sun.COM }
39910188SJan.Friedel@Sun.COM
40010188SJan.Friedel@Sun.COM /*
40110188SJan.Friedel@Sun.COM * delete_context() - release GSS context.
40210188SJan.Friedel@Sun.COM */
40310188SJan.Friedel@Sun.COM static void
delete_context()40410188SJan.Friedel@Sun.COM delete_context()
40510188SJan.Friedel@Sun.COM {
40610188SJan.Friedel@Sun.COM OM_uint32 min_stat;
40710188SJan.Friedel@Sun.COM
40810188SJan.Friedel@Sun.COM (void) gss_delete_sec_context(&min_stat, &gss_ctx, GSS_C_NO_BUFFER);
40910188SJan.Friedel@Sun.COM DPRINT((dfile, "context deleted\n"));
41010188SJan.Friedel@Sun.COM }
41110188SJan.Friedel@Sun.COM
41210188SJan.Friedel@Sun.COM /*
41310188SJan.Friedel@Sun.COM * send_token() - send GSS token over the wire.
41410188SJan.Friedel@Sun.COM */
41510188SJan.Friedel@Sun.COM static int
send_token(int * fdptr,gss_buffer_t tok)41610188SJan.Friedel@Sun.COM send_token(int *fdptr, gss_buffer_t tok)
41710188SJan.Friedel@Sun.COM {
41810188SJan.Friedel@Sun.COM uint32_t len;
41910188SJan.Friedel@Sun.COM uint32_t lensz;
42010188SJan.Friedel@Sun.COM char *out_buf;
42110188SJan.Friedel@Sun.COM int fd;
42210188SJan.Friedel@Sun.COM
42310188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&sock_lock);
42410188SJan.Friedel@Sun.COM if (*fdptr == -1) {
42510188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
42610188SJan.Friedel@Sun.COM DPRINT((dfile, "Socket detected as closed.\n"));
42710188SJan.Friedel@Sun.COM return (-1);
42810188SJan.Friedel@Sun.COM }
42910188SJan.Friedel@Sun.COM fd = *fdptr;
43010188SJan.Friedel@Sun.COM
43110188SJan.Friedel@Sun.COM len = htonl(tok->length);
43210188SJan.Friedel@Sun.COM lensz = sizeof (len);
43310188SJan.Friedel@Sun.COM
43410188SJan.Friedel@Sun.COM out_buf = (char *)malloc((size_t)(lensz + tok->length));
43510188SJan.Friedel@Sun.COM if (out_buf == NULL) {
43610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
43710188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
43810188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
43910188SJan.Friedel@Sun.COM strerror(errno)));
44010188SJan.Friedel@Sun.COM return (-1);
44110188SJan.Friedel@Sun.COM }
44210188SJan.Friedel@Sun.COM (void) memcpy((void *)out_buf, (void *)&len, lensz);
44310188SJan.Friedel@Sun.COM (void) memcpy((void *)(out_buf + lensz), (void *)tok->value,
44410188SJan.Friedel@Sun.COM tok->length);
44510188SJan.Friedel@Sun.COM
44610188SJan.Friedel@Sun.COM if (send_timeout(fd, out_buf, (lensz + tok->length))) {
44710188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
44810188SJan.Friedel@Sun.COM free(out_buf);
44910188SJan.Friedel@Sun.COM return (-1);
45010188SJan.Friedel@Sun.COM }
45110188SJan.Friedel@Sun.COM
45210188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
45310188SJan.Friedel@Sun.COM free(out_buf);
45410188SJan.Friedel@Sun.COM return (0);
45510188SJan.Friedel@Sun.COM }
45610188SJan.Friedel@Sun.COM
45710188SJan.Friedel@Sun.COM
45810188SJan.Friedel@Sun.COM /*
45910188SJan.Friedel@Sun.COM * recv_token() - receive GSS token over the wire.
46010188SJan.Friedel@Sun.COM */
46110188SJan.Friedel@Sun.COM static int
recv_token(int fd,gss_buffer_t tok)46210188SJan.Friedel@Sun.COM recv_token(int fd, gss_buffer_t tok)
46310188SJan.Friedel@Sun.COM {
46410188SJan.Friedel@Sun.COM uint32_t len;
46510188SJan.Friedel@Sun.COM
46610188SJan.Friedel@Sun.COM if (recv_timeout(fd, (char *)&len, sizeof (len))) {
46710188SJan.Friedel@Sun.COM return (-1);
46810188SJan.Friedel@Sun.COM }
46910188SJan.Friedel@Sun.COM len = ntohl(len);
47010188SJan.Friedel@Sun.COM
47110188SJan.Friedel@Sun.COM /* simple DOS prevention mechanism */
47210188SJan.Friedel@Sun.COM if (len > MAX_TOK_LEN) {
47310188SJan.Friedel@Sun.COM report_err(gettext("Indicated invalid token length"));
47410188SJan.Friedel@Sun.COM DPRINT((dfile, "Indicated token length > %dB\n", MAX_TOK_LEN));
47510188SJan.Friedel@Sun.COM return (-1);
47610188SJan.Friedel@Sun.COM }
47710188SJan.Friedel@Sun.COM
47810188SJan.Friedel@Sun.COM tok->value = (char *)malloc(len);
47910188SJan.Friedel@Sun.COM if (tok->value == NULL) {
48010188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
48110188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
48210188SJan.Friedel@Sun.COM strerror(errno)));
48310188SJan.Friedel@Sun.COM tok->length = 0;
48410188SJan.Friedel@Sun.COM return (-1);
48510188SJan.Friedel@Sun.COM }
48610188SJan.Friedel@Sun.COM
48710188SJan.Friedel@Sun.COM if (recv_timeout(fd, tok->value, len)) {
48810188SJan.Friedel@Sun.COM free(tok->value);
48910188SJan.Friedel@Sun.COM tok->value = NULL;
49010188SJan.Friedel@Sun.COM tok->length = 0;
49110188SJan.Friedel@Sun.COM return (-1);
49210188SJan.Friedel@Sun.COM }
49310188SJan.Friedel@Sun.COM
49410188SJan.Friedel@Sun.COM tok->length = len;
49510188SJan.Friedel@Sun.COM return (0);
49610188SJan.Friedel@Sun.COM }
49710188SJan.Friedel@Sun.COM
49810188SJan.Friedel@Sun.COM
49910188SJan.Friedel@Sun.COM /*
50010188SJan.Friedel@Sun.COM * I/O functions
50110188SJan.Friedel@Sun.COM */
50210188SJan.Friedel@Sun.COM
50310188SJan.Friedel@Sun.COM /*
50410188SJan.Friedel@Sun.COM * connect_timeout() - sets nonblocking I/O on a socket and timeout-connects
50510188SJan.Friedel@Sun.COM */
50610188SJan.Friedel@Sun.COM static int
connect_timeout(int sockfd,struct sockaddr * name,int namelen)50710188SJan.Friedel@Sun.COM connect_timeout(int sockfd, struct sockaddr *name, int namelen)
50810188SJan.Friedel@Sun.COM {
50910188SJan.Friedel@Sun.COM int flags;
51010188SJan.Friedel@Sun.COM struct pollfd fds;
51110188SJan.Friedel@Sun.COM int rc;
51210188SJan.Friedel@Sun.COM struct sockaddr_storage addr;
51310188SJan.Friedel@Sun.COM socklen_t addr_len = sizeof (addr);
51410188SJan.Friedel@Sun.COM
51510188SJan.Friedel@Sun.COM
51610188SJan.Friedel@Sun.COM flags = fcntl(sockfd, F_GETFL, 0);
51710188SJan.Friedel@Sun.COM if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
51810188SJan.Friedel@Sun.COM return (-1);
51910188SJan.Friedel@Sun.COM }
52010188SJan.Friedel@Sun.COM if (connect(sockfd, name, namelen)) {
52110188SJan.Friedel@Sun.COM if (!(errno == EINTR || errno == EINPROGRESS ||
52210188SJan.Friedel@Sun.COM errno == EWOULDBLOCK)) {
52310188SJan.Friedel@Sun.COM return (-1);
52410188SJan.Friedel@Sun.COM }
52510188SJan.Friedel@Sun.COM }
52610188SJan.Friedel@Sun.COM fds.fd = sockfd;
52710188SJan.Friedel@Sun.COM fds.events = POLLOUT;
52810188SJan.Friedel@Sun.COM for (;;) {
52910188SJan.Friedel@Sun.COM fds.revents = 0;
53010188SJan.Friedel@Sun.COM rc = poll(&fds, 1, timeout * 1000);
53110188SJan.Friedel@Sun.COM if (rc == 0) { /* timeout */
53210188SJan.Friedel@Sun.COM return (-1);
53310188SJan.Friedel@Sun.COM } else if (rc < 0) {
53410188SJan.Friedel@Sun.COM if (errno == EINTR || errno == EAGAIN) {
53510188SJan.Friedel@Sun.COM continue;
53610188SJan.Friedel@Sun.COM } else {
53710188SJan.Friedel@Sun.COM return (-1);
53810188SJan.Friedel@Sun.COM }
53910188SJan.Friedel@Sun.COM }
54010188SJan.Friedel@Sun.COM if (fds.revents) {
54110188SJan.Friedel@Sun.COM if (getpeername(sockfd, (struct sockaddr *)&addr,
54210188SJan.Friedel@Sun.COM &addr_len))
54310188SJan.Friedel@Sun.COM return (-1);
54410188SJan.Friedel@Sun.COM } else {
54510188SJan.Friedel@Sun.COM return (-1);
54610188SJan.Friedel@Sun.COM }
54710188SJan.Friedel@Sun.COM return (0);
54810188SJan.Friedel@Sun.COM }
54910188SJan.Friedel@Sun.COM }
55010188SJan.Friedel@Sun.COM
55110188SJan.Friedel@Sun.COM /*
55210188SJan.Friedel@Sun.COM * send_timeout() - send data (in chunks if needed, each chunk in timeout secs).
55310188SJan.Friedel@Sun.COM */
55410188SJan.Friedel@Sun.COM static int
send_timeout(int fd,const char * buf,size_t len)55510188SJan.Friedel@Sun.COM send_timeout(int fd, const char *buf, size_t len)
55610188SJan.Friedel@Sun.COM {
55710188SJan.Friedel@Sun.COM int bytes;
55810188SJan.Friedel@Sun.COM struct pollfd fds;
55910188SJan.Friedel@Sun.COM int rc;
56010188SJan.Friedel@Sun.COM
56110188SJan.Friedel@Sun.COM fds.fd = fd;
56210188SJan.Friedel@Sun.COM fds.events = POLLOUT;
56310188SJan.Friedel@Sun.COM
56410188SJan.Friedel@Sun.COM while (len) {
56510188SJan.Friedel@Sun.COM fds.revents = 0;
56610188SJan.Friedel@Sun.COM rc = poll(&fds, 1, timeout * 1000);
56710188SJan.Friedel@Sun.COM if (rc == 0) { /* timeout */
56810188SJan.Friedel@Sun.COM return (-1);
56910188SJan.Friedel@Sun.COM } else if (rc < 0) {
57010188SJan.Friedel@Sun.COM if (errno == EINTR || errno == EAGAIN) {
57110188SJan.Friedel@Sun.COM continue;
57210188SJan.Friedel@Sun.COM } else {
57310188SJan.Friedel@Sun.COM return (-1);
57410188SJan.Friedel@Sun.COM }
57510188SJan.Friedel@Sun.COM }
57610188SJan.Friedel@Sun.COM if (!fds.revents) {
57710188SJan.Friedel@Sun.COM return (-1);
57810188SJan.Friedel@Sun.COM }
57910188SJan.Friedel@Sun.COM
58010188SJan.Friedel@Sun.COM bytes = write(fd, buf, len);
58110188SJan.Friedel@Sun.COM if (bytes < 0) {
58210188SJan.Friedel@Sun.COM if (errno == EINTR) {
58310188SJan.Friedel@Sun.COM continue;
58410188SJan.Friedel@Sun.COM } else {
58510188SJan.Friedel@Sun.COM return (-1);
58610188SJan.Friedel@Sun.COM }
58710188SJan.Friedel@Sun.COM } else if (bytes == 0) { /* eof */
58810188SJan.Friedel@Sun.COM return (-1);
58910188SJan.Friedel@Sun.COM }
59010188SJan.Friedel@Sun.COM
59110188SJan.Friedel@Sun.COM len -= bytes;
59210188SJan.Friedel@Sun.COM buf += bytes;
59310188SJan.Friedel@Sun.COM }
59410188SJan.Friedel@Sun.COM
59510188SJan.Friedel@Sun.COM return (0);
59610188SJan.Friedel@Sun.COM }
59710188SJan.Friedel@Sun.COM
59810188SJan.Friedel@Sun.COM /*
59910188SJan.Friedel@Sun.COM * recv_timeout() - receive data (in chunks if needed, each chunk in timeout
60010188SJan.Friedel@Sun.COM * secs). In case the function is called from receiving thread, the function
60110188SJan.Friedel@Sun.COM * cycles the poll() call in timeout seconds (waits for input from server).
60210188SJan.Friedel@Sun.COM */
60310188SJan.Friedel@Sun.COM static int
recv_timeout(int fd,char * buf,size_t len)60410188SJan.Friedel@Sun.COM recv_timeout(int fd, char *buf, size_t len)
60510188SJan.Friedel@Sun.COM {
60610188SJan.Friedel@Sun.COM int bytes;
60710188SJan.Friedel@Sun.COM struct pollfd fds;
60810188SJan.Friedel@Sun.COM int rc;
60910188SJan.Friedel@Sun.COM
61010188SJan.Friedel@Sun.COM fds.fd = fd;
61110188SJan.Friedel@Sun.COM fds.events = POLLIN;
61210188SJan.Friedel@Sun.COM
61310188SJan.Friedel@Sun.COM while (len) {
61410188SJan.Friedel@Sun.COM fds.revents = 0;
61510188SJan.Friedel@Sun.COM rc = poll(&fds, 1, timeout * 1000);
61610188SJan.Friedel@Sun.COM if (rc == 0) { /* timeout */
61710188SJan.Friedel@Sun.COM return (-1);
61810188SJan.Friedel@Sun.COM } else if (rc < 0) {
61910188SJan.Friedel@Sun.COM if (errno == EINTR || errno == EAGAIN) {
62010188SJan.Friedel@Sun.COM continue;
62110188SJan.Friedel@Sun.COM } else {
62210188SJan.Friedel@Sun.COM return (-1);
62310188SJan.Friedel@Sun.COM }
62410188SJan.Friedel@Sun.COM }
62510188SJan.Friedel@Sun.COM
62610188SJan.Friedel@Sun.COM if (!fds.revents) {
62710188SJan.Friedel@Sun.COM return (-1);
62810188SJan.Friedel@Sun.COM }
62910188SJan.Friedel@Sun.COM
63010188SJan.Friedel@Sun.COM bytes = read(fd, buf, len);
63110188SJan.Friedel@Sun.COM if (bytes < 0) {
63210188SJan.Friedel@Sun.COM if (errno == EINTR) {
63310188SJan.Friedel@Sun.COM continue;
63410188SJan.Friedel@Sun.COM } else {
63510188SJan.Friedel@Sun.COM return (-1);
63610188SJan.Friedel@Sun.COM }
63710188SJan.Friedel@Sun.COM } else if (bytes == 0) { /* eof */
63810188SJan.Friedel@Sun.COM return (-1);
63910188SJan.Friedel@Sun.COM }
64010188SJan.Friedel@Sun.COM
64110188SJan.Friedel@Sun.COM len -= bytes;
64210188SJan.Friedel@Sun.COM buf += bytes;
64310188SJan.Friedel@Sun.COM }
64410188SJan.Friedel@Sun.COM
64510188SJan.Friedel@Sun.COM return (0);
64610188SJan.Friedel@Sun.COM }
64710188SJan.Friedel@Sun.COM
64810188SJan.Friedel@Sun.COM /*
64910188SJan.Friedel@Sun.COM * read_fd() - reads data of length len from the given file descriptor fd to the
65010188SJan.Friedel@Sun.COM * buffer buf, in chunks if needed. Function returns B_FALSE on failure,
65110188SJan.Friedel@Sun.COM * otherwise B_TRUE. Function preserves errno, if it was set by the read(2).
65210188SJan.Friedel@Sun.COM */
65310188SJan.Friedel@Sun.COM static boolean_t
read_fd(int fd,char * buf,size_t len)65410188SJan.Friedel@Sun.COM read_fd(int fd, char *buf, size_t len)
65510188SJan.Friedel@Sun.COM {
65610188SJan.Friedel@Sun.COM int bytes;
65710188SJan.Friedel@Sun.COM #ifdef DEBUG
65810188SJan.Friedel@Sun.COM size_t len_o = len;
65910188SJan.Friedel@Sun.COM #endif
66010188SJan.Friedel@Sun.COM
66110188SJan.Friedel@Sun.COM while (len) {
66210188SJan.Friedel@Sun.COM bytes = read(fd, buf, len);
66310188SJan.Friedel@Sun.COM if (bytes < 0) { /* err */
66410188SJan.Friedel@Sun.COM if (errno == EINTR || errno == EAGAIN) {
66510188SJan.Friedel@Sun.COM continue;
66610188SJan.Friedel@Sun.COM } else {
66710188SJan.Friedel@Sun.COM return (B_FALSE);
66810188SJan.Friedel@Sun.COM }
66910188SJan.Friedel@Sun.COM } else if (bytes == 0) { /* eof */
67010188SJan.Friedel@Sun.COM return (B_FALSE);
67110188SJan.Friedel@Sun.COM }
67210188SJan.Friedel@Sun.COM
67310188SJan.Friedel@Sun.COM len -= bytes;
67410188SJan.Friedel@Sun.COM buf += bytes;
67510188SJan.Friedel@Sun.COM }
67610188SJan.Friedel@Sun.COM
67710188SJan.Friedel@Sun.COM DPRINT((dfile, "read_fd: Read %d bytes.\n", len_o - len));
67810188SJan.Friedel@Sun.COM return (B_TRUE);
67910188SJan.Friedel@Sun.COM }
68010188SJan.Friedel@Sun.COM
68110188SJan.Friedel@Sun.COM /*
68210188SJan.Friedel@Sun.COM * write_fd() - writes buf of length len to the opened file descriptor fd, in
68310188SJan.Friedel@Sun.COM * chunks if needed. The data from the pipe are processed in the receiving
68410188SJan.Friedel@Sun.COM * thread. Function returns B_FALSE on failure, otherwise B_TRUE. Function
68510188SJan.Friedel@Sun.COM * preserves errno, if it was set by the write(2).
68610188SJan.Friedel@Sun.COM */
68710188SJan.Friedel@Sun.COM static boolean_t
write_fd(int fd,char * buf,size_t len)68810188SJan.Friedel@Sun.COM write_fd(int fd, char *buf, size_t len)
68910188SJan.Friedel@Sun.COM {
69010188SJan.Friedel@Sun.COM int bytes;
69110188SJan.Friedel@Sun.COM #ifdef DEBUG
69210188SJan.Friedel@Sun.COM size_t len_o = len;
69310188SJan.Friedel@Sun.COM #endif
69410188SJan.Friedel@Sun.COM
69510188SJan.Friedel@Sun.COM while (len) {
69610188SJan.Friedel@Sun.COM bytes = write(fd, buf, len);
69710188SJan.Friedel@Sun.COM if (bytes == -1) { /* err */
69810188SJan.Friedel@Sun.COM if (errno == EINTR || errno == EAGAIN) {
69910188SJan.Friedel@Sun.COM continue;
70010188SJan.Friedel@Sun.COM } else {
70110188SJan.Friedel@Sun.COM return (B_FALSE);
70210188SJan.Friedel@Sun.COM }
70310188SJan.Friedel@Sun.COM }
70410188SJan.Friedel@Sun.COM
70510188SJan.Friedel@Sun.COM len -= bytes;
70610188SJan.Friedel@Sun.COM buf += bytes;
70710188SJan.Friedel@Sun.COM }
70810188SJan.Friedel@Sun.COM
70910188SJan.Friedel@Sun.COM DPRINT((dfile, "write_fd: Wrote %d bytes.\n", len_o - len));
71010188SJan.Friedel@Sun.COM return (B_TRUE);
71110188SJan.Friedel@Sun.COM }
71210188SJan.Friedel@Sun.COM
71310188SJan.Friedel@Sun.COM /*
71410188SJan.Friedel@Sun.COM * Plug-in entry point
71510188SJan.Friedel@Sun.COM */
71610188SJan.Friedel@Sun.COM
71710188SJan.Friedel@Sun.COM /*
71810188SJan.Friedel@Sun.COM * send_record() - send an audit record to a host opening a connection,
71910188SJan.Friedel@Sun.COM * negotiate version and establish context if necessary.
72010188SJan.Friedel@Sun.COM */
72110188SJan.Friedel@Sun.COM send_record_rc_t
send_record(struct hostlist_s * hostlptr,const char * input,size_t in_len,uint64_t sequence,close_rsn_t * err_rsn)72210188SJan.Friedel@Sun.COM send_record(struct hostlist_s *hostlptr, const char *input, size_t in_len,
72310188SJan.Friedel@Sun.COM uint64_t sequence, close_rsn_t *err_rsn)
72410188SJan.Friedel@Sun.COM {
72510188SJan.Friedel@Sun.COM gss_buffer_desc in_buf, out_buf;
72610188SJan.Friedel@Sun.COM OM_uint32 maj_stat, min_stat;
72710188SJan.Friedel@Sun.COM int conf_state;
72810188SJan.Friedel@Sun.COM int rc;
72910188SJan.Friedel@Sun.COM transq_node_t *node_ptr;
73010188SJan.Friedel@Sun.COM uint64_t seq_n; /* sequence in the network byte order */
73110188SJan.Friedel@Sun.COM boolean_t init_sock_poll = B_FALSE;
73210188SJan.Friedel@Sun.COM
73310188SJan.Friedel@Sun.COM /*
73410188SJan.Friedel@Sun.COM * We need to grab the reset_lock here, to prevent eventual
73510188SJan.Friedel@Sun.COM * unsynchronized cleanup calls within the reset routine (reset caused
73610188SJan.Friedel@Sun.COM * by the receiving thread) and the initialization calls in the
73710188SJan.Friedel@Sun.COM * send_record() code path.
73810188SJan.Friedel@Sun.COM */
73910188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&reset_lock);
74010188SJan.Friedel@Sun.COM
74110188SJan.Friedel@Sun.COM /*
74210188SJan.Friedel@Sun.COM * Check whether the socket was closed by the recv thread prior to call
74310188SJan.Friedel@Sun.COM * send_record() and behave accordingly to the reason of the closure.
74410188SJan.Friedel@Sun.COM */
74510188SJan.Friedel@Sun.COM if (recv_closure_rsn != RSN_UNDEFINED) {
74610188SJan.Friedel@Sun.COM *err_rsn = recv_closure_rsn;
74710188SJan.Friedel@Sun.COM if (recv_closure_rsn == RSN_GSS_CTX_EXP) {
74810188SJan.Friedel@Sun.COM rc = SEND_RECORD_RETRY;
74910188SJan.Friedel@Sun.COM } else {
75010188SJan.Friedel@Sun.COM rc = SEND_RECORD_NEXT;
75110188SJan.Friedel@Sun.COM }
75210188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_UNDEFINED;
75310188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
75410188SJan.Friedel@Sun.COM return (rc);
75510188SJan.Friedel@Sun.COM }
75610188SJan.Friedel@Sun.COM
75710188SJan.Friedel@Sun.COM /*
75810188SJan.Friedel@Sun.COM * Send request to other then previously used host.
75910188SJan.Friedel@Sun.COM */
76010188SJan.Friedel@Sun.COM if (current_host != hostlptr->host) {
76110188SJan.Friedel@Sun.COM DPRINT((dfile, "Set new host: %s\n", hostlptr->host->h_name));
76210188SJan.Friedel@Sun.COM if (sockfd != -1) {
76310188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
76410188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
76510188SJan.Friedel@Sun.COM return (SEND_RECORD_RETRY);
76610188SJan.Friedel@Sun.COM }
76710188SJan.Friedel@Sun.COM current_host = (struct hostent *)hostlptr->host;
76810188SJan.Friedel@Sun.COM current_mech_oid = &hostlptr->mech;
76910188SJan.Friedel@Sun.COM current_port = hostlptr->port;
77010188SJan.Friedel@Sun.COM }
77110188SJan.Friedel@Sun.COM
77210188SJan.Friedel@Sun.COM /* initiate the receiving thread */
77310188SJan.Friedel@Sun.COM (void) pthread_once(&recv_once_control, init_recv_record);
77410188SJan.Friedel@Sun.COM
77510188SJan.Friedel@Sun.COM /* create and connect() socket, negotiate the protocol version */
77610188SJan.Friedel@Sun.COM if (sockfd == -1) {
77710188SJan.Friedel@Sun.COM /* socket operations */
77810188SJan.Friedel@Sun.COM DPRINT((dfile, "Socket creation and connect\n"));
77910188SJan.Friedel@Sun.COM if (!sock_prepare(&sockfd, current_host, err_rsn)) {
78010188SJan.Friedel@Sun.COM /* we believe the err_rsn set by sock_prepare() */
78110188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
78210188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
78310188SJan.Friedel@Sun.COM }
78410188SJan.Friedel@Sun.COM
78510188SJan.Friedel@Sun.COM /* protocol version negotiation */
78610188SJan.Friedel@Sun.COM DPRINT((dfile, "Protocol version negotiation\n"));
78710188SJan.Friedel@Sun.COM if (prot_ver_negotiate() != 0) {
78810188SJan.Friedel@Sun.COM DPRINT((dfile,
78910188SJan.Friedel@Sun.COM "Protocol version negotiation failed\n"));
79010188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
79110188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
79210188SJan.Friedel@Sun.COM *err_rsn = RSN_PROTOCOL_NEGOTIATE;
79310188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
79410188SJan.Friedel@Sun.COM }
79510188SJan.Friedel@Sun.COM
79610188SJan.Friedel@Sun.COM /* let the socket be initiated for poll() */
79710188SJan.Friedel@Sun.COM init_sock_poll = B_TRUE;
79810188SJan.Friedel@Sun.COM }
79910188SJan.Friedel@Sun.COM
80010188SJan.Friedel@Sun.COM if (!gss_ctx_initialized) {
80110188SJan.Friedel@Sun.COM DPRINT((dfile, "Establishing context..\n"));
80210188SJan.Friedel@Sun.COM if (establish_context() != 0) {
80310188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
80410188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
80510188SJan.Friedel@Sun.COM *err_rsn = RSN_GSS_CTX_ESTABLISH;
80610188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
80710188SJan.Friedel@Sun.COM }
80810188SJan.Friedel@Sun.COM gss_ctx_initialized = B_TRUE;
80910188SJan.Friedel@Sun.COM }
81010188SJan.Friedel@Sun.COM
81110188SJan.Friedel@Sun.COM /* let the recv thread poll() on the sockfd */
81210188SJan.Friedel@Sun.COM if (init_sock_poll) {
81310188SJan.Friedel@Sun.COM init_sock_poll = B_FALSE;
81410188SJan.Friedel@Sun.COM if (!init_poll(sockfd)) {
81510188SJan.Friedel@Sun.COM *err_rsn = RSN_INIT_POLL;
81610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
81710188SJan.Friedel@Sun.COM return (SEND_RECORD_RETRY);
81810188SJan.Friedel@Sun.COM }
81910188SJan.Friedel@Sun.COM }
82010188SJan.Friedel@Sun.COM
82110188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
82210188SJan.Friedel@Sun.COM
82310188SJan.Friedel@Sun.COM /* if not empty, retransmit contents of the transmission queue */
82410188SJan.Friedel@Sun.COM if (flush_transq) {
82510188SJan.Friedel@Sun.COM DPRINT((dfile, "Retransmitting remaining (%ld) tokens from "
82610188SJan.Friedel@Sun.COM "the transmission queue\n", transq_hdr.count));
82710188SJan.Friedel@Sun.COM if ((rc = transq_retransmit()) == 2) { /* gss context exp */
82810188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
82910188SJan.Friedel@Sun.COM *err_rsn = RSN_GSS_CTX_EXP;
83010188SJan.Friedel@Sun.COM return (SEND_RECORD_RETRY);
83110188SJan.Friedel@Sun.COM } else if (rc == 1) {
83210188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
83310188SJan.Friedel@Sun.COM *err_rsn = RSN_OTHER_ERR;
83410188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
83510188SJan.Friedel@Sun.COM }
83610188SJan.Friedel@Sun.COM flush_transq = B_FALSE;
83710188SJan.Friedel@Sun.COM }
83810188SJan.Friedel@Sun.COM
83910188SJan.Friedel@Sun.COM /*
84010188SJan.Friedel@Sun.COM * Concatenate sequence number and the new record. Note, that the
84110188SJan.Friedel@Sun.COM * pointer to the chunk of memory allocated for the concatenated values
84210188SJan.Friedel@Sun.COM * is later passed to the transq_enqueu() function which stores the
84310188SJan.Friedel@Sun.COM * pointer in the transmission queue; subsequently called
84410188SJan.Friedel@Sun.COM * transq_dequeue() frees the allocated memory once the MIC is verified
84510188SJan.Friedel@Sun.COM * by the recv_record() function.
84610188SJan.Friedel@Sun.COM *
84710188SJan.Friedel@Sun.COM * If we return earlier than the transq_enqueue() is called, it's
84810188SJan.Friedel@Sun.COM * necessary to free the in_buf.value explicitly prior to return.
84910188SJan.Friedel@Sun.COM *
85010188SJan.Friedel@Sun.COM */
85110188SJan.Friedel@Sun.COM in_buf.length = in_len + sizeof (sequence);
85210188SJan.Friedel@Sun.COM in_buf.value = malloc(in_buf.length);
85310188SJan.Friedel@Sun.COM if (in_buf.value == NULL) {
85410188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
85510188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
85610188SJan.Friedel@Sun.COM strerror(errno)));
85710188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
85810188SJan.Friedel@Sun.COM *err_rsn = RSN_MEMORY_ALLOCATE;
85910188SJan.Friedel@Sun.COM return (SEND_RECORD_FAIL);
86010188SJan.Friedel@Sun.COM }
86110188SJan.Friedel@Sun.COM seq_n = htonll(sequence);
86210188SJan.Friedel@Sun.COM (void) memcpy(in_buf.value, &seq_n, sizeof (seq_n));
86310188SJan.Friedel@Sun.COM (void) memcpy((char *)in_buf.value + sizeof (seq_n), input, in_len);
86410188SJan.Friedel@Sun.COM
86510188SJan.Friedel@Sun.COM /* wrap sequence number and the new record to the per-message token */
86610188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&gss_ctx_lock);
86710188SJan.Friedel@Sun.COM if (gss_ctx != NULL) {
86810188SJan.Friedel@Sun.COM maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT,
86910188SJan.Friedel@Sun.COM &in_buf, &conf_state, &out_buf);
87010188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
87110188SJan.Friedel@Sun.COM switch (maj_stat) {
87210188SJan.Friedel@Sun.COM case GSS_S_COMPLETE:
87310188SJan.Friedel@Sun.COM break;
87410188SJan.Friedel@Sun.COM case GSS_S_CONTEXT_EXPIRED:
87510188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
87610188SJan.Friedel@Sun.COM free(in_buf.value);
87710188SJan.Friedel@Sun.COM *err_rsn = RSN_GSS_CTX_EXP;
87810188SJan.Friedel@Sun.COM return (SEND_RECORD_RETRY);
87910188SJan.Friedel@Sun.COM default:
88010188SJan.Friedel@Sun.COM report_gss_err(gettext("gss_wrap message"), maj_stat,
88110188SJan.Friedel@Sun.COM min_stat);
88210188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
88310188SJan.Friedel@Sun.COM free(in_buf.value);
88410188SJan.Friedel@Sun.COM *err_rsn = RSN_OTHER_ERR;
88510188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
88610188SJan.Friedel@Sun.COM }
88710188SJan.Friedel@Sun.COM } else { /* GSS context deleted by the recv thread */
88810188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
88910188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
89010188SJan.Friedel@Sun.COM free(in_buf.value);
89110188SJan.Friedel@Sun.COM *err_rsn = RSN_OTHER_ERR;
89210188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
89310188SJan.Friedel@Sun.COM }
89410188SJan.Friedel@Sun.COM
89510188SJan.Friedel@Sun.COM
89610188SJan.Friedel@Sun.COM /* enqueue the to-be-sent token into transmission queue */
89710188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
89810188SJan.Friedel@Sun.COM if (!transq_enqueue(&node_ptr, &in_buf, sequence)) {
89910188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
90010188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
90110188SJan.Friedel@Sun.COM free(in_buf.value);
90210188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &out_buf);
90310188SJan.Friedel@Sun.COM *err_rsn = RSN_OTHER_ERR;
90410188SJan.Friedel@Sun.COM return (SEND_RECORD_RETRY);
90510188SJan.Friedel@Sun.COM }
90610188SJan.Friedel@Sun.COM DPRINT((dfile, "Token enqueued for later verification\n"));
90710188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
90810188SJan.Friedel@Sun.COM
90910188SJan.Friedel@Sun.COM /* send token */
91010188SJan.Friedel@Sun.COM if (send_token(&sockfd, &out_buf) < 0) {
91110188SJan.Friedel@Sun.COM DPRINT((dfile, "Token sending failed\n"));
91210188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_SYNC);
91310188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &out_buf);
91410188SJan.Friedel@Sun.COM
91510188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
91610188SJan.Friedel@Sun.COM transq_dequeue(node_ptr);
91710188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
91810188SJan.Friedel@Sun.COM
91910188SJan.Friedel@Sun.COM *err_rsn = RSN_OTHER_ERR;
92010188SJan.Friedel@Sun.COM return (SEND_RECORD_NEXT);
92110188SJan.Friedel@Sun.COM }
92210188SJan.Friedel@Sun.COM DPRINT((dfile, "Token sent (transq size = %ld)\n", transq_hdr.count));
92310188SJan.Friedel@Sun.COM
92410188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &out_buf);
92510188SJan.Friedel@Sun.COM
92610188SJan.Friedel@Sun.COM return (SEND_RECORD_SUCCESS);
92710188SJan.Friedel@Sun.COM }
92810188SJan.Friedel@Sun.COM
92910188SJan.Friedel@Sun.COM /*
93010188SJan.Friedel@Sun.COM * init_recv_record() - initialize the receiver thread
93110188SJan.Friedel@Sun.COM */
93210188SJan.Friedel@Sun.COM static void
init_recv_record()93310188SJan.Friedel@Sun.COM init_recv_record()
93410188SJan.Friedel@Sun.COM {
93510188SJan.Friedel@Sun.COM DPRINT((dfile, "Initiating the recv thread\n"));
93610188SJan.Friedel@Sun.COM (void) pthread_create(&recv_tid, NULL, (void *(*)(void *))recv_record,
93710188SJan.Friedel@Sun.COM (void *)NULL);
93810188SJan.Friedel@Sun.COM
93910188SJan.Friedel@Sun.COM }
94010188SJan.Friedel@Sun.COM
94110188SJan.Friedel@Sun.COM
94210188SJan.Friedel@Sun.COM /*
94310188SJan.Friedel@Sun.COM * recv_record() - the receiver thread routine
94410188SJan.Friedel@Sun.COM */
94510188SJan.Friedel@Sun.COM static void
recv_record()94610188SJan.Friedel@Sun.COM recv_record()
94710188SJan.Friedel@Sun.COM {
94810188SJan.Friedel@Sun.COM OM_uint32 maj_stat, min_stat;
94910188SJan.Friedel@Sun.COM gss_qop_t qop_state;
95010188SJan.Friedel@Sun.COM gss_buffer_desc in_buf = GSS_C_EMPTY_BUFFER;
95110188SJan.Friedel@Sun.COM gss_buffer_desc in_buf_mic = GSS_C_EMPTY_BUFFER;
95210188SJan.Friedel@Sun.COM transq_node_t *cur_node;
95310188SJan.Friedel@Sun.COM uint64_t r_seq_num; /* received sequence number */
95410188SJan.Friedel@Sun.COM boolean_t token_verified;
95510188SJan.Friedel@Sun.COM boolean_t break_flag;
95610188SJan.Friedel@Sun.COM struct pollfd fds[2];
95710188SJan.Friedel@Sun.COM int fds_cnt;
95810188SJan.Friedel@Sun.COM struct pollfd *pipe_fd = &fds[0];
95910188SJan.Friedel@Sun.COM struct pollfd *recv_fd = &fds[1];
96010188SJan.Friedel@Sun.COM uint32_t len;
96110188SJan.Friedel@Sun.COM int rc;
96210188SJan.Friedel@Sun.COM pipe_msg_t np_data;
96310188SJan.Friedel@Sun.COM
96410188SJan.Friedel@Sun.COM DPRINT((dfile, "Receiver thread initiated\n"));
96510188SJan.Friedel@Sun.COM
96610188SJan.Friedel@Sun.COM /*
96710188SJan.Friedel@Sun.COM * Fill in the information in the vector of file descriptors passed
96810188SJan.Friedel@Sun.COM * later on to the poll() function. In the initial state, there is only
96910188SJan.Friedel@Sun.COM * one struct pollfd in the vector which contains file descriptor of the
97010188SJan.Friedel@Sun.COM * notification pipe - notify_pipe[1]. There might be up to two file
97110188SJan.Friedel@Sun.COM * descriptors (struct pollfd) in the vector - notify_pipe[1] which
97210188SJan.Friedel@Sun.COM * resides in the vector during the entire life of the receiving thread,
97310188SJan.Friedel@Sun.COM * and the own file descriptor from which we read data sent by the
97410188SJan.Friedel@Sun.COM * remote server application.
97510188SJan.Friedel@Sun.COM */
97610188SJan.Friedel@Sun.COM pipe_fd->fd = notify_pipe[1];
97710188SJan.Friedel@Sun.COM pipe_fd->events = POLLIN;
97810188SJan.Friedel@Sun.COM recv_fd->fd = -1;
97910188SJan.Friedel@Sun.COM recv_fd->events = POLLIN;
98010188SJan.Friedel@Sun.COM fds_cnt = 1;
98110188SJan.Friedel@Sun.COM
98210188SJan.Friedel@Sun.COM /*
98310188SJan.Friedel@Sun.COM * In the endless loop, try to grab some data from the socket or
98410188SJan.Friedel@Sun.COM * notify_pipe[1].
98510188SJan.Friedel@Sun.COM */
98610188SJan.Friedel@Sun.COM for (;;) {
98710188SJan.Friedel@Sun.COM
98810188SJan.Friedel@Sun.COM pipe_fd->revents = 0;
98910188SJan.Friedel@Sun.COM recv_fd->revents = 0;
99010188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_UNDEFINED;
99110188SJan.Friedel@Sun.COM
99210188SJan.Friedel@Sun.COM /* block on poll, thus rc != 0 */
99310188SJan.Friedel@Sun.COM rc = poll(fds, fds_cnt, -1);
99410188SJan.Friedel@Sun.COM if (rc == -1) {
99510188SJan.Friedel@Sun.COM if (errno == EAGAIN || errno == EINTR) {
99610188SJan.Friedel@Sun.COM /* silently continue on EAGAIN || EINTR */
99710188SJan.Friedel@Sun.COM continue;
99810188SJan.Friedel@Sun.COM } else {
99910188SJan.Friedel@Sun.COM /* log the debug message in any other case */
100010188SJan.Friedel@Sun.COM DPRINT((dfile, "poll() failed: %s\n",
100110188SJan.Friedel@Sun.COM strerror(errno)));
100210188SJan.Friedel@Sun.COM report_err(gettext("poll() failed.\n"));
100310188SJan.Friedel@Sun.COM continue;
100410188SJan.Friedel@Sun.COM }
100510188SJan.Friedel@Sun.COM }
100610188SJan.Friedel@Sun.COM
100710188SJan.Friedel@Sun.COM /*
100810188SJan.Friedel@Sun.COM * Receive a message from the notification pipe. Information
100910188SJan.Friedel@Sun.COM * from the notification pipe takes precedence over the received
101010188SJan.Friedel@Sun.COM * data from the remote server application.
101110188SJan.Friedel@Sun.COM *
101210188SJan.Friedel@Sun.COM * Notification pipe message format - message accepted
101310188SJan.Friedel@Sun.COM * from the notify pipe comprises of two parts (int ||
101410188SJan.Friedel@Sun.COM * boolean_t), where if the first part (sizeof (int)) equals
101510188SJan.Friedel@Sun.COM * NP_CLOSE, then the second part (sizeof (boolean_t)) signals
101610188SJan.Friedel@Sun.COM * the necessity of broadcasting (DO_SYNC/DO_NOT_SYNC) the end
101710188SJan.Friedel@Sun.COM * of the reset routine.
101810188SJan.Friedel@Sun.COM */
101910188SJan.Friedel@Sun.COM if (pipe_fd->revents & POLLIN) {
102010188SJan.Friedel@Sun.COM DPRINT((dfile, "An event on notify pipe detected\n"));
102110188SJan.Friedel@Sun.COM if (!read_fd(pipe_fd->fd, (char *)&np_data,
102210188SJan.Friedel@Sun.COM sizeof (np_data))) {
102310188SJan.Friedel@Sun.COM DPRINT((dfile, "Reading notify pipe failed: "
102410188SJan.Friedel@Sun.COM "%s\n", strerror(errno)));
102510188SJan.Friedel@Sun.COM report_err(gettext("Reading notify pipe "
102610188SJan.Friedel@Sun.COM "failed"));
102710188SJan.Friedel@Sun.COM } else {
102810188SJan.Friedel@Sun.COM switch (np_data.sock_num) {
102910188SJan.Friedel@Sun.COM case NP_EXIT: /* exit receiving thread */
103010188SJan.Friedel@Sun.COM do_cleanup(&fds_cnt, recv_fd,
103110188SJan.Friedel@Sun.COM np_data.sync);
103210188SJan.Friedel@Sun.COM pthread_exit((void *)NULL);
103310188SJan.Friedel@Sun.COM break;
103410188SJan.Friedel@Sun.COM case NP_CLOSE: /* close and remove recv_fd */
103510188SJan.Friedel@Sun.COM do_reset(&fds_cnt, recv_fd,
103610188SJan.Friedel@Sun.COM np_data.sync);
103710188SJan.Friedel@Sun.COM continue;
103810188SJan.Friedel@Sun.COM default: /* add rc_pipe to the fds */
103910188SJan.Friedel@Sun.COM recv_fd->fd = np_data.sock_num;
104010188SJan.Friedel@Sun.COM fds_cnt = 2;
104110188SJan.Friedel@Sun.COM continue;
104210188SJan.Friedel@Sun.COM }
104310188SJan.Friedel@Sun.COM }
104410188SJan.Friedel@Sun.COM }
104510188SJan.Friedel@Sun.COM /* Receive a token from the remote server application */
104610188SJan.Friedel@Sun.COM if (recv_fd->revents & POLLIN) {
104710188SJan.Friedel@Sun.COM DPRINT((dfile, "An event on fd detected\n"));
104810188SJan.Friedel@Sun.COM if (!read_fd(recv_fd->fd, (char *)&len, sizeof (len))) {
104910188SJan.Friedel@Sun.COM DPRINT((dfile, "Token length recv failed\n"));
105010188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_TOK_RECV_FAILED;
105110188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_NOT_SYNC);
105210188SJan.Friedel@Sun.COM continue;
105310188SJan.Friedel@Sun.COM }
105410188SJan.Friedel@Sun.COM len = ntohl(len);
105510188SJan.Friedel@Sun.COM
105610188SJan.Friedel@Sun.COM /* simple DOS prevention mechanism */
105710188SJan.Friedel@Sun.COM if (len > MAX_TOK_LEN) {
105810188SJan.Friedel@Sun.COM report_err(gettext("Indicated invalid token "
105910188SJan.Friedel@Sun.COM "length"));
106010188SJan.Friedel@Sun.COM DPRINT((dfile, "Indicated token length > %dB\n",
106110188SJan.Friedel@Sun.COM MAX_TOK_LEN));
106210188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_TOK_TOO_BIG;
106310188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_NOT_SYNC);
106410188SJan.Friedel@Sun.COM continue;
106510188SJan.Friedel@Sun.COM }
106610188SJan.Friedel@Sun.COM
106710188SJan.Friedel@Sun.COM in_buf.value = (char *)malloc(len);
106810188SJan.Friedel@Sun.COM if (in_buf.value == NULL) {
106910188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
107010188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
107110188SJan.Friedel@Sun.COM strerror(errno)));
107210188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_MEMORY_ALLOCATE;
107310188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_NOT_SYNC);
107410188SJan.Friedel@Sun.COM continue;
107510188SJan.Friedel@Sun.COM }
107610188SJan.Friedel@Sun.COM if (!read_fd(recv_fd->fd, (char *)in_buf.value, len)) {
107710188SJan.Friedel@Sun.COM DPRINT((dfile, "Token value recv failed\n"));
107810188SJan.Friedel@Sun.COM free(in_buf.value);
107910188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_TOK_RECV_FAILED;
108010188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_NOT_SYNC);
108110188SJan.Friedel@Sun.COM continue;
108210188SJan.Friedel@Sun.COM }
108310188SJan.Friedel@Sun.COM
108410188SJan.Friedel@Sun.COM in_buf.length = len;
108510188SJan.Friedel@Sun.COM }
108610188SJan.Friedel@Sun.COM
108710188SJan.Friedel@Sun.COM /*
108810188SJan.Friedel@Sun.COM * Extract the sequence number and the MIC from
108910188SJan.Friedel@Sun.COM * the per-message token
109010188SJan.Friedel@Sun.COM */
109110188SJan.Friedel@Sun.COM (void) memcpy(&r_seq_num, in_buf.value, sizeof (r_seq_num));
109210188SJan.Friedel@Sun.COM r_seq_num = ntohll(r_seq_num);
109310188SJan.Friedel@Sun.COM in_buf_mic.length = in_buf.length - sizeof (r_seq_num);
109410188SJan.Friedel@Sun.COM in_buf_mic.value = (char *)in_buf.value + sizeof (r_seq_num);
109510188SJan.Friedel@Sun.COM
109610188SJan.Friedel@Sun.COM /*
109710188SJan.Friedel@Sun.COM * seq_num/r_seq_num - the sequence number does not need to
109810188SJan.Friedel@Sun.COM * be unique in the transmission queue. Any token in the
109910188SJan.Friedel@Sun.COM * transmission queue with the same seq_num as the acknowledge
110010188SJan.Friedel@Sun.COM * token received from the server is tested. This is due to the
110110188SJan.Friedel@Sun.COM * fact that the plugin cannot influence (in the current
110210188SJan.Friedel@Sun.COM * implementation) sequence numbers generated by the kernel (we
110310188SJan.Friedel@Sun.COM * are reusing record sequence numbers as a transmission queue
110410188SJan.Friedel@Sun.COM * sequence numbers). The probability of having two or more
110510188SJan.Friedel@Sun.COM * tokens in the transmission queue is low and at the same time
110610188SJan.Friedel@Sun.COM * the performance gain due to using sequence numbers is quite
110710188SJan.Friedel@Sun.COM * high.
110810188SJan.Friedel@Sun.COM *
110910188SJan.Friedel@Sun.COM * In case a harder condition with regard to duplicate sequence
111010188SJan.Friedel@Sun.COM * numbers in the transmission queue will be desired over time,
111110188SJan.Friedel@Sun.COM * the break_flag behavior used below should be
111210188SJan.Friedel@Sun.COM * removed/changed_accordingly.
111310188SJan.Friedel@Sun.COM */
111410188SJan.Friedel@Sun.COM break_flag = B_FALSE;
111510188SJan.Friedel@Sun.COM token_verified = B_FALSE;
111610188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
111710188SJan.Friedel@Sun.COM cur_node = transq_hdr.head;
111810188SJan.Friedel@Sun.COM while (cur_node != NULL && !break_flag) {
111910188SJan.Friedel@Sun.COM if (cur_node->seq_num != r_seq_num) {
112010188SJan.Friedel@Sun.COM cur_node = cur_node->next;
112110188SJan.Friedel@Sun.COM continue;
112210188SJan.Friedel@Sun.COM }
112310188SJan.Friedel@Sun.COM
112410188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&gss_ctx_lock);
112510188SJan.Friedel@Sun.COM maj_stat = gss_verify_mic(&min_stat, gss_ctx,
112610188SJan.Friedel@Sun.COM &(cur_node->seq_token), &in_buf_mic,
112710188SJan.Friedel@Sun.COM &qop_state);
112810188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
112910188SJan.Friedel@Sun.COM
113010188SJan.Friedel@Sun.COM if (!GSS_ERROR(maj_stat)) { /* the success case */
113110188SJan.Friedel@Sun.COM switch (maj_stat) {
113210188SJan.Friedel@Sun.COM /*
113310188SJan.Friedel@Sun.COM * All the GSS_S_OLD_TOKEN, GSS_S_UNSEQ_TOKEN,
113410188SJan.Friedel@Sun.COM * GSS_S_GAP_TOKEN are perceived as correct
113510188SJan.Friedel@Sun.COM * behavior of the server side. The plugin
113610188SJan.Friedel@Sun.COM * implementation is resistant to any of the
113710188SJan.Friedel@Sun.COM * above mention cases of returned status codes.
113810188SJan.Friedel@Sun.COM */
113910188SJan.Friedel@Sun.COM /*FALLTHRU*/
114010188SJan.Friedel@Sun.COM case GSS_S_OLD_TOKEN:
114110188SJan.Friedel@Sun.COM case GSS_S_UNSEQ_TOKEN:
114210188SJan.Friedel@Sun.COM case GSS_S_GAP_TOKEN:
114310188SJan.Friedel@Sun.COM case GSS_S_COMPLETE:
114410188SJan.Friedel@Sun.COM /*
114510188SJan.Friedel@Sun.COM * remove the verified record/node from
114610188SJan.Friedel@Sun.COM * the transmission queue
114710188SJan.Friedel@Sun.COM */
114810188SJan.Friedel@Sun.COM transq_dequeue(cur_node);
114910188SJan.Friedel@Sun.COM DPRINT((dfile, "Recv thread verified "
115010188SJan.Friedel@Sun.COM "the token (transq len = %ld)\n",
115110188SJan.Friedel@Sun.COM transq_hdr.count));
115210188SJan.Friedel@Sun.COM
115310188SJan.Friedel@Sun.COM token_verified = B_TRUE;
115410188SJan.Friedel@Sun.COM break_flag = B_TRUE;
115510188SJan.Friedel@Sun.COM break;
115610188SJan.Friedel@Sun.COM
115710188SJan.Friedel@Sun.COM /*
115810188SJan.Friedel@Sun.COM * Both the default case as well as
115910188SJan.Friedel@Sun.COM * GSS_S_DUPLICATE_TOKEN case should never
116010188SJan.Friedel@Sun.COM * occur. It's been left here for the sake of
116110188SJan.Friedel@Sun.COM * completeness.
116210188SJan.Friedel@Sun.COM * If any of the two cases occur, it is
116310188SJan.Friedel@Sun.COM * subsequently cought because we don't set
116410188SJan.Friedel@Sun.COM * the token_verified flag.
116510188SJan.Friedel@Sun.COM */
116610188SJan.Friedel@Sun.COM /*FALLTHRU*/
116710188SJan.Friedel@Sun.COM case GSS_S_DUPLICATE_TOKEN:
116810188SJan.Friedel@Sun.COM default:
116910188SJan.Friedel@Sun.COM break_flag = B_TRUE;
117010188SJan.Friedel@Sun.COM break;
117110188SJan.Friedel@Sun.COM } /* switch (maj_stat) */
117210188SJan.Friedel@Sun.COM
117310188SJan.Friedel@Sun.COM } else { /* the failure case */
117410188SJan.Friedel@Sun.COM report_gss_err(
117510188SJan.Friedel@Sun.COM gettext("signature verification of the "
117610188SJan.Friedel@Sun.COM "received token failed"),
117710188SJan.Friedel@Sun.COM maj_stat, min_stat);
117810188SJan.Friedel@Sun.COM
117910188SJan.Friedel@Sun.COM switch (maj_stat) {
118010188SJan.Friedel@Sun.COM case GSS_S_CONTEXT_EXPIRED:
118110188SJan.Friedel@Sun.COM /* retransmission necessary */
118210188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_GSS_CTX_EXP;
118310188SJan.Friedel@Sun.COM break_flag = B_TRUE;
118410188SJan.Friedel@Sun.COM DPRINT((dfile, "Recv thread detected "
118510188SJan.Friedel@Sun.COM "the GSS context expiration\n"));
118610188SJan.Friedel@Sun.COM break;
118710188SJan.Friedel@Sun.COM case GSS_S_BAD_SIG:
118810188SJan.Friedel@Sun.COM DPRINT((dfile, "Bad signature "
118910188SJan.Friedel@Sun.COM "detected (seq_num = %lld)\n",
119010188SJan.Friedel@Sun.COM cur_node->seq_num));
119110188SJan.Friedel@Sun.COM cur_node = cur_node->next;
119210188SJan.Friedel@Sun.COM break;
119310188SJan.Friedel@Sun.COM default:
119410188SJan.Friedel@Sun.COM report_gss_err(
119510188SJan.Friedel@Sun.COM gettext("signature verification"),
119610188SJan.Friedel@Sun.COM maj_stat, min_stat);
119710188SJan.Friedel@Sun.COM break_flag = B_TRUE;
119810188SJan.Friedel@Sun.COM break;
119910188SJan.Friedel@Sun.COM }
120010188SJan.Friedel@Sun.COM }
120110188SJan.Friedel@Sun.COM
120210188SJan.Friedel@Sun.COM } /* while */
120310188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
120410188SJan.Friedel@Sun.COM
120510188SJan.Friedel@Sun.COM if (in_buf.value != NULL) {
120610188SJan.Friedel@Sun.COM free(in_buf.value);
120710188SJan.Friedel@Sun.COM in_buf.value = NULL;
120810188SJan.Friedel@Sun.COM in_buf.length = 0;
120910188SJan.Friedel@Sun.COM }
121010188SJan.Friedel@Sun.COM
121110188SJan.Friedel@Sun.COM if (!token_verified) {
121210188SJan.Friedel@Sun.COM /*
121310188SJan.Friedel@Sun.COM * Received, but unverifiable token is perceived as
121410188SJan.Friedel@Sun.COM * the protocol flow corruption with the penalty of
121510188SJan.Friedel@Sun.COM * reinitializing the client/server connection.
121610188SJan.Friedel@Sun.COM */
121710188SJan.Friedel@Sun.COM DPRINT((dfile, "received unverifiable token\n"));
121810188SJan.Friedel@Sun.COM report_err(gettext("received unverifiable token\n"));
121910188SJan.Friedel@Sun.COM if (recv_closure_rsn == RSN_UNDEFINED) {
122010188SJan.Friedel@Sun.COM recv_closure_rsn = RSN_TOK_UNVERIFIABLE;
122110188SJan.Friedel@Sun.COM }
122210188SJan.Friedel@Sun.COM reset_transport(DO_CLOSE, DO_NOT_SYNC);
122310188SJan.Friedel@Sun.COM }
122410188SJan.Friedel@Sun.COM
122510188SJan.Friedel@Sun.COM } /* for (;;) */
122610188SJan.Friedel@Sun.COM
122710188SJan.Friedel@Sun.COM
122810188SJan.Friedel@Sun.COM }
122910188SJan.Friedel@Sun.COM
123010188SJan.Friedel@Sun.COM
123110188SJan.Friedel@Sun.COM /*
123210188SJan.Friedel@Sun.COM * init_poll() - initiates the polling in the receiving thread via sending the
123310188SJan.Friedel@Sun.COM * appropriate message over the notify pipe. Message format = (int ||
123410188SJan.Friedel@Sun.COM * booleant_t), where the first part (sizeof (int)) contains the
123510188SJan.Friedel@Sun.COM * newly_opened/to_be_polled socket file descriptor. The contents of the second
123610188SJan.Friedel@Sun.COM * part (sizeof (boolean_t)) of the message works only as a padding here and no
123710188SJan.Friedel@Sun.COM * action (no recv/send thread synchronisation) is made in the receiving thread
123810188SJan.Friedel@Sun.COM * based on its value.
123910188SJan.Friedel@Sun.COM */
124010188SJan.Friedel@Sun.COM static boolean_t
init_poll(int fd)124110188SJan.Friedel@Sun.COM init_poll(int fd)
124210188SJan.Friedel@Sun.COM {
124310188SJan.Friedel@Sun.COM pipe_msg_t np_data;
124410188SJan.Friedel@Sun.COM int pipe_in = notify_pipe[0];
124510188SJan.Friedel@Sun.COM
124610188SJan.Friedel@Sun.COM np_data.sock_num = fd;
124710188SJan.Friedel@Sun.COM np_data.sync = B_FALSE; /* padding only */
124810188SJan.Friedel@Sun.COM
124910188SJan.Friedel@Sun.COM if (!write_fd(pipe_in, (char *)&np_data, sizeof (np_data))) {
125010188SJan.Friedel@Sun.COM DPRINT((dfile, "Cannot write to the notify pipe\n"));
125110188SJan.Friedel@Sun.COM report_err(gettext("writing to the notify pipe failed"));
125210188SJan.Friedel@Sun.COM return (B_FALSE);
125310188SJan.Friedel@Sun.COM }
125410188SJan.Friedel@Sun.COM
125510188SJan.Friedel@Sun.COM return (B_TRUE);
125610188SJan.Friedel@Sun.COM }
125710188SJan.Friedel@Sun.COM
125810188SJan.Friedel@Sun.COM
125910188SJan.Friedel@Sun.COM /*
126010188SJan.Friedel@Sun.COM * reset_transport() - locked by the reset_lock initiates the reset of socket,
126110188SJan.Friedel@Sun.COM * GSS security context and (possibly) flags the transq for retransmission; for
126210188SJan.Friedel@Sun.COM * more detailed information see do_reset(). The reset_transport() also allows
126310188SJan.Friedel@Sun.COM * the synchronization - waiting for the reset to be finished.
126410188SJan.Friedel@Sun.COM *
126510188SJan.Friedel@Sun.COM * do_close: DO_SYNC, DO_NOT_SYNC
126610188SJan.Friedel@Sun.COM * sync_on_return: DO_EXIT (DO_NOT_CLOSE), DO_CLOSE (DO_NOT_EXIT)
126710188SJan.Friedel@Sun.COM *
126810188SJan.Friedel@Sun.COM */
126910188SJan.Friedel@Sun.COM void
reset_transport(boolean_t do_close,boolean_t sync_on_return)127010188SJan.Friedel@Sun.COM reset_transport(boolean_t do_close, boolean_t sync_on_return)
127110188SJan.Friedel@Sun.COM {
127210188SJan.Friedel@Sun.COM int pipe_in = notify_pipe[0];
127310188SJan.Friedel@Sun.COM pipe_msg_t np_data;
127410188SJan.Friedel@Sun.COM
127510188SJan.Friedel@Sun.COM /*
127610188SJan.Friedel@Sun.COM * Check if the reset routine is in progress or whether it was already
127710188SJan.Friedel@Sun.COM * executed by some other thread.
127810188SJan.Friedel@Sun.COM */
127910188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&reset_lock);
128010188SJan.Friedel@Sun.COM if (reset_in_progress) {
128110188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
128210188SJan.Friedel@Sun.COM return;
128310188SJan.Friedel@Sun.COM }
128410188SJan.Friedel@Sun.COM reset_in_progress = B_TRUE;
128510188SJan.Friedel@Sun.COM
128610188SJan.Friedel@Sun.COM np_data.sock_num = (do_close ? NP_CLOSE : NP_EXIT);
128710188SJan.Friedel@Sun.COM np_data.sync = sync_on_return;
128810188SJan.Friedel@Sun.COM (void) write_fd(pipe_in, (char *)&np_data, sizeof (np_data));
128910188SJan.Friedel@Sun.COM
129010188SJan.Friedel@Sun.COM if (sync_on_return) {
129110188SJan.Friedel@Sun.COM while (reset_in_progress) {
129210188SJan.Friedel@Sun.COM (void) pthread_cond_wait(&reset_cv, &reset_lock);
129310188SJan.Friedel@Sun.COM DPRINT((dfile, "Wait for sync\n"));
129410188SJan.Friedel@Sun.COM }
129510188SJan.Friedel@Sun.COM DPRINT((dfile, "Synced\n"));
129610188SJan.Friedel@Sun.COM }
129710188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
129810188SJan.Friedel@Sun.COM
129910188SJan.Friedel@Sun.COM }
130010188SJan.Friedel@Sun.COM
130110188SJan.Friedel@Sun.COM
130210188SJan.Friedel@Sun.COM /*
130310188SJan.Friedel@Sun.COM * do_reset() - the own reseting routine called from the recv thread. If the
130410188SJan.Friedel@Sun.COM * synchronization was requested, signal the finish via conditional variable.
130510188SJan.Friedel@Sun.COM */
130610188SJan.Friedel@Sun.COM static void
do_reset(int * fds_cnt,struct pollfd * recv_fd,boolean_t do_signal)130710188SJan.Friedel@Sun.COM do_reset(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal)
130810188SJan.Friedel@Sun.COM {
130910188SJan.Friedel@Sun.COM
131010188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&reset_lock);
131110188SJan.Friedel@Sun.COM
131210188SJan.Friedel@Sun.COM /* socket */
131310188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&sock_lock);
131410188SJan.Friedel@Sun.COM if (sockfd == -1) {
131510188SJan.Friedel@Sun.COM DPRINT((dfile, "socket already closed\n"));
131610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
131710188SJan.Friedel@Sun.COM goto out;
131810188SJan.Friedel@Sun.COM } else {
131910188SJan.Friedel@Sun.COM (void) close(sockfd);
132010188SJan.Friedel@Sun.COM sockfd = -1;
132110188SJan.Friedel@Sun.COM recv_fd->fd = -1;
132210188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
132310188SJan.Friedel@Sun.COM }
132410188SJan.Friedel@Sun.COM *fds_cnt = 1;
132510188SJan.Friedel@Sun.COM
132610188SJan.Friedel@Sun.COM /* context */
132710188SJan.Friedel@Sun.COM if (gss_ctx_initialized) {
132810188SJan.Friedel@Sun.COM delete_context();
132910188SJan.Friedel@Sun.COM }
133010188SJan.Friedel@Sun.COM gss_ctx_initialized = B_FALSE;
133110188SJan.Friedel@Sun.COM gss_ctx = NULL;
133210188SJan.Friedel@Sun.COM
133310188SJan.Friedel@Sun.COM /* mark transq to be flushed */
133410188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
133510188SJan.Friedel@Sun.COM if (transq_hdr.count > 0) {
133610188SJan.Friedel@Sun.COM flush_transq = B_TRUE;
133710188SJan.Friedel@Sun.COM }
133810188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
133910188SJan.Friedel@Sun.COM
134010188SJan.Friedel@Sun.COM out:
134110188SJan.Friedel@Sun.COM reset_in_progress = B_FALSE;
134210188SJan.Friedel@Sun.COM if (do_signal) {
134310188SJan.Friedel@Sun.COM (void) pthread_cond_broadcast(&reset_cv);
134410188SJan.Friedel@Sun.COM }
134510188SJan.Friedel@Sun.COM
134610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
134710188SJan.Friedel@Sun.COM }
134810188SJan.Friedel@Sun.COM
134910188SJan.Friedel@Sun.COM /*
135010188SJan.Friedel@Sun.COM * do_cleanup() - removes all the preallocated space by the plugin; prepares the
135110188SJan.Friedel@Sun.COM * plugin/application to be gracefully finished. Even thought the function
135210188SJan.Friedel@Sun.COM * allows execution without signalling the successful finish, it's recommended
135310188SJan.Friedel@Sun.COM * to use it (we usually want to wait for cleanup before exiting).
135410188SJan.Friedel@Sun.COM */
135510188SJan.Friedel@Sun.COM static void
do_cleanup(int * fds_cnt,struct pollfd * recv_fd,boolean_t do_signal)135610188SJan.Friedel@Sun.COM do_cleanup(int *fds_cnt, struct pollfd *recv_fd, boolean_t do_signal)
135710188SJan.Friedel@Sun.COM {
135810188SJan.Friedel@Sun.COM
135910188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&reset_lock);
136010188SJan.Friedel@Sun.COM
136110188SJan.Friedel@Sun.COM /*
136210188SJan.Friedel@Sun.COM * socket
136310188SJan.Friedel@Sun.COM * note: keeping locking for safety, thought it shouldn't be necessary
136410188SJan.Friedel@Sun.COM * in current implementation - we get here only in case the sending code
136510188SJan.Friedel@Sun.COM * path calls auditd_plugin_close() (thus no socket manipulation) and
136610188SJan.Friedel@Sun.COM * the recv thread is doing the own socket closure.
136710188SJan.Friedel@Sun.COM */
136810188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&sock_lock);
136910188SJan.Friedel@Sun.COM if (sockfd != -1) {
137010188SJan.Friedel@Sun.COM DPRINT((dfile, "Closing socket: %d\n", sockfd));
137110188SJan.Friedel@Sun.COM (void) close(sockfd);
137210188SJan.Friedel@Sun.COM sockfd = -1;
137310188SJan.Friedel@Sun.COM recv_fd->fd = -1;
137410188SJan.Friedel@Sun.COM }
137510188SJan.Friedel@Sun.COM *fds_cnt = 1;
137610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&sock_lock);
137710188SJan.Friedel@Sun.COM
137810188SJan.Friedel@Sun.COM /* context */
137910188SJan.Friedel@Sun.COM if (gss_ctx_initialized) {
138010188SJan.Friedel@Sun.COM DPRINT((dfile, "Deleting context: "));
138110188SJan.Friedel@Sun.COM delete_context();
138210188SJan.Friedel@Sun.COM }
138310188SJan.Friedel@Sun.COM gss_ctx_initialized = B_FALSE;
138410188SJan.Friedel@Sun.COM gss_ctx = NULL;
138510188SJan.Friedel@Sun.COM
138610188SJan.Friedel@Sun.COM /* transmission queue */
138710188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
138810188SJan.Friedel@Sun.COM if (transq_hdr.count > 0) {
138910188SJan.Friedel@Sun.COM DPRINT((dfile, "Deallocating the transmission queue "
139010188SJan.Friedel@Sun.COM "(len = %ld)\n", transq_hdr.count));
139110188SJan.Friedel@Sun.COM while (transq_hdr.count > 0) {
139210188SJan.Friedel@Sun.COM transq_dequeue(transq_hdr.head);
139310188SJan.Friedel@Sun.COM }
139410188SJan.Friedel@Sun.COM }
139510188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
139610188SJan.Friedel@Sun.COM
139710188SJan.Friedel@Sun.COM /* notification pipe */
139810188SJan.Friedel@Sun.COM if (notify_pipe_ready) {
139910188SJan.Friedel@Sun.COM (void) close(notify_pipe[0]);
140010188SJan.Friedel@Sun.COM (void) close(notify_pipe[1]);
140110188SJan.Friedel@Sun.COM notify_pipe_ready = B_FALSE;
140210188SJan.Friedel@Sun.COM }
140310188SJan.Friedel@Sun.COM
140410188SJan.Friedel@Sun.COM reset_in_progress = B_FALSE;
140510188SJan.Friedel@Sun.COM if (do_signal) {
140610188SJan.Friedel@Sun.COM (void) pthread_cond_broadcast(&reset_cv);
140710188SJan.Friedel@Sun.COM }
140810188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&reset_lock);
140910188SJan.Friedel@Sun.COM }
141010188SJan.Friedel@Sun.COM
141110188SJan.Friedel@Sun.COM
141210188SJan.Friedel@Sun.COM /*
141310188SJan.Friedel@Sun.COM * transq_dequeue() - dequeues given node pointed by the node_ptr from the
141410188SJan.Friedel@Sun.COM * transmission queue. Transmission queue should be locked prior to use of this
141510188SJan.Friedel@Sun.COM * function.
141610188SJan.Friedel@Sun.COM */
141710188SJan.Friedel@Sun.COM static void
transq_dequeue(transq_node_t * node_ptr)141810188SJan.Friedel@Sun.COM transq_dequeue(transq_node_t *node_ptr)
141910188SJan.Friedel@Sun.COM {
142010188SJan.Friedel@Sun.COM
142110188SJan.Friedel@Sun.COM if (node_ptr == NULL) {
142210188SJan.Friedel@Sun.COM DPRINT((dfile, "transq_dequeue(): called with NULL pointer\n"));
142310188SJan.Friedel@Sun.COM return;
142410188SJan.Friedel@Sun.COM }
142510188SJan.Friedel@Sun.COM
142610188SJan.Friedel@Sun.COM free(node_ptr->seq_token.value);
142710188SJan.Friedel@Sun.COM
142810188SJan.Friedel@Sun.COM if (node_ptr->prev != NULL) {
142910188SJan.Friedel@Sun.COM node_ptr->prev->next = node_ptr->next;
143010188SJan.Friedel@Sun.COM }
143110188SJan.Friedel@Sun.COM if (node_ptr->next != NULL) {
143210188SJan.Friedel@Sun.COM node_ptr->next->prev = node_ptr->prev;
143310188SJan.Friedel@Sun.COM }
143410188SJan.Friedel@Sun.COM
143510188SJan.Friedel@Sun.COM
143610188SJan.Friedel@Sun.COM /* update the transq_hdr */
143710188SJan.Friedel@Sun.COM if (node_ptr->next == NULL) {
143810188SJan.Friedel@Sun.COM transq_hdr.end = node_ptr->prev;
143910188SJan.Friedel@Sun.COM }
144010188SJan.Friedel@Sun.COM if (node_ptr->prev == NULL) {
144110188SJan.Friedel@Sun.COM transq_hdr.head = node_ptr->next;
144210188SJan.Friedel@Sun.COM }
144310188SJan.Friedel@Sun.COM
144410188SJan.Friedel@Sun.COM transq_hdr.count--;
144510188SJan.Friedel@Sun.COM
144610188SJan.Friedel@Sun.COM free(node_ptr);
144710188SJan.Friedel@Sun.COM }
144810188SJan.Friedel@Sun.COM
144910188SJan.Friedel@Sun.COM
145010188SJan.Friedel@Sun.COM /*
145110188SJan.Friedel@Sun.COM * transq_enqueue() - creates new node in (at the end of) the transmission
145210188SJan.Friedel@Sun.COM * queue. in_ptoken_ptr is a pointer to the plain token in a form of
145310188SJan.Friedel@Sun.COM * gss_buffer_desc. Function returns 0 on success and updates the *node_ptr to
145410188SJan.Friedel@Sun.COM * point to a newly added transmission queue node. In case of any failure
145510188SJan.Friedel@Sun.COM * function returns 1 and sets the *node_ptr to NULL.
145610188SJan.Friedel@Sun.COM * Transmission queue should be locked prior to use of this function.
145710188SJan.Friedel@Sun.COM */
145810188SJan.Friedel@Sun.COM static boolean_t
transq_enqueue(transq_node_t ** node_ptr,gss_buffer_t in_seqtoken_ptr,uint64_t sequence)145910188SJan.Friedel@Sun.COM transq_enqueue(transq_node_t **node_ptr, gss_buffer_t in_seqtoken_ptr,
146010188SJan.Friedel@Sun.COM uint64_t sequence)
146110188SJan.Friedel@Sun.COM {
146210188SJan.Friedel@Sun.COM
146310188SJan.Friedel@Sun.COM *node_ptr = calloc(1, sizeof (transq_node_t));
146410188SJan.Friedel@Sun.COM if (*node_ptr == NULL) {
146510188SJan.Friedel@Sun.COM report_err(gettext("Memory allocation failed"));
146610188SJan.Friedel@Sun.COM DPRINT((dfile, "Memory allocation failed: %s\n",
146710188SJan.Friedel@Sun.COM strerror(errno)));
146810188SJan.Friedel@Sun.COM goto errout;
146910188SJan.Friedel@Sun.COM }
147010188SJan.Friedel@Sun.COM
147110188SJan.Friedel@Sun.COM /* value of the seq_token.value = (sequence number || plain token) */
147210188SJan.Friedel@Sun.COM (*node_ptr)->seq_num = sequence;
147310188SJan.Friedel@Sun.COM (*node_ptr)->seq_token.length = in_seqtoken_ptr->length;
147410188SJan.Friedel@Sun.COM (*node_ptr)->seq_token.value = in_seqtoken_ptr->value;
147510188SJan.Friedel@Sun.COM
147610188SJan.Friedel@Sun.COM /* update the transq_hdr */
147710188SJan.Friedel@Sun.COM if (transq_hdr.head == NULL) {
147810188SJan.Friedel@Sun.COM transq_hdr.head = *node_ptr;
147910188SJan.Friedel@Sun.COM }
148010188SJan.Friedel@Sun.COM if (transq_hdr.end != NULL) {
148110188SJan.Friedel@Sun.COM (transq_hdr.end)->next = *node_ptr;
148210188SJan.Friedel@Sun.COM (*node_ptr)->prev = transq_hdr.end;
148310188SJan.Friedel@Sun.COM }
148410188SJan.Friedel@Sun.COM transq_hdr.end = *node_ptr;
148510188SJan.Friedel@Sun.COM
148610188SJan.Friedel@Sun.COM transq_hdr.count++;
148710188SJan.Friedel@Sun.COM
148810188SJan.Friedel@Sun.COM return (B_TRUE);
148910188SJan.Friedel@Sun.COM
149010188SJan.Friedel@Sun.COM errout:
149110188SJan.Friedel@Sun.COM if (*node_ptr != NULL) {
149210188SJan.Friedel@Sun.COM if ((*node_ptr)->seq_token.value != NULL) {
149310188SJan.Friedel@Sun.COM free((*node_ptr)->seq_token.value);
149410188SJan.Friedel@Sun.COM }
149510188SJan.Friedel@Sun.COM free(*node_ptr);
149610188SJan.Friedel@Sun.COM *node_ptr = NULL;
149710188SJan.Friedel@Sun.COM }
149810188SJan.Friedel@Sun.COM return (B_FALSE);
149910188SJan.Friedel@Sun.COM }
150010188SJan.Friedel@Sun.COM
150110188SJan.Friedel@Sun.COM
150210188SJan.Friedel@Sun.COM /*
150310188SJan.Friedel@Sun.COM * transq_retransmit() - traverse the transmission queue and try to, 1 by 1,
150410188SJan.Friedel@Sun.COM * re-wrap the tokens with the recent context information and retransmit the
150510188SJan.Friedel@Sun.COM * tokens from the transmission queue.
150610188SJan.Friedel@Sun.COM * Function returns 2 on GSS context expiration, 1 on any other error, 0 on
150710188SJan.Friedel@Sun.COM * successfully resent transmission queue.
150810188SJan.Friedel@Sun.COM */
150910188SJan.Friedel@Sun.COM static int
transq_retransmit()151010188SJan.Friedel@Sun.COM transq_retransmit()
151110188SJan.Friedel@Sun.COM {
151210188SJan.Friedel@Sun.COM
151310188SJan.Friedel@Sun.COM OM_uint32 maj_stat, min_stat;
151410188SJan.Friedel@Sun.COM transq_node_t *cur_node = transq_hdr.head;
151510188SJan.Friedel@Sun.COM gss_buffer_desc out_buf;
151610188SJan.Friedel@Sun.COM int conf_state;
151710188SJan.Friedel@Sun.COM
151810188SJan.Friedel@Sun.COM DPRINT((dfile, "Retransmission of the remainder in the transqueue\n"));
151910188SJan.Friedel@Sun.COM
152010188SJan.Friedel@Sun.COM while (cur_node != NULL) {
152110188SJan.Friedel@Sun.COM
152210188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&transq_lock);
152310188SJan.Friedel@Sun.COM (void) pthread_mutex_lock(&gss_ctx_lock);
152410188SJan.Friedel@Sun.COM maj_stat = gss_wrap(&min_stat, gss_ctx, 1, GSS_C_QOP_DEFAULT,
152510188SJan.Friedel@Sun.COM &(cur_node->seq_token), &conf_state, &out_buf);
152610188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&gss_ctx_lock);
152710188SJan.Friedel@Sun.COM
152810188SJan.Friedel@Sun.COM switch (maj_stat) {
152910188SJan.Friedel@Sun.COM case GSS_S_COMPLETE:
153010188SJan.Friedel@Sun.COM break;
153110188SJan.Friedel@Sun.COM case GSS_S_CONTEXT_EXPIRED:
153210188SJan.Friedel@Sun.COM DPRINT((dfile, "Context expired.\n"));
153310188SJan.Friedel@Sun.COM report_gss_err(gettext("gss_wrap message"), maj_stat,
153410188SJan.Friedel@Sun.COM min_stat);
153510188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
153610188SJan.Friedel@Sun.COM return (2);
153710188SJan.Friedel@Sun.COM default:
153810188SJan.Friedel@Sun.COM report_gss_err(gettext("gss_wrap message"), maj_stat,
153910188SJan.Friedel@Sun.COM min_stat);
154010188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
154110188SJan.Friedel@Sun.COM return (1);
154210188SJan.Friedel@Sun.COM }
154310188SJan.Friedel@Sun.COM
154410188SJan.Friedel@Sun.COM DPRINT((dfile, "Sending transmission queue token (seq=%lld, "
154510188SJan.Friedel@Sun.COM "size=%d, transq len=%ld)\n", cur_node->seq_num,
154610188SJan.Friedel@Sun.COM out_buf.length, transq_hdr.count));
154710188SJan.Friedel@Sun.COM if (send_token(&sockfd, &out_buf) < 0) {
154810188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &out_buf);
154910188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
155010188SJan.Friedel@Sun.COM return (1);
155110188SJan.Friedel@Sun.COM }
155210188SJan.Friedel@Sun.COM (void) gss_release_buffer(&min_stat, &out_buf);
155310188SJan.Friedel@Sun.COM
155410188SJan.Friedel@Sun.COM cur_node = cur_node->next;
155510188SJan.Friedel@Sun.COM (void) pthread_mutex_unlock(&transq_lock);
155610188SJan.Friedel@Sun.COM
155710188SJan.Friedel@Sun.COM } /* while */
155810188SJan.Friedel@Sun.COM
155910188SJan.Friedel@Sun.COM return (0);
156010188SJan.Friedel@Sun.COM }
1561