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