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