xref: /titanic_44/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c (revision f044df33d9fe9e8e3ed7344a8b548b17f20709f2)
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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * ldom_xmpp_client.c	Extensible Messaging and Presence Protocol (XMPP)
27  *
28  * Implement an xmpp client to subscribe for domain events from the ldmd.
29  * Notify fmd module clients upon receiving the events.
30  *
31  */
32 
33 #include "ldom_xmpp_client.h"
34 #include "ldom_alloc.h"
35 #include "ldom_utils.h"
36 
37 #include <stdio.h>
38 #include <signal.h>
39 #include <strings.h>
40 #include <unistd.h>
41 #include <errno.h>
42 
43 #include <netdb.h>
44 #include <dlfcn.h>
45 #include <fcntl.h>
46 #include <sys/socket.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <libxml/parser.h>
50 #include <openssl/ssl.h>
51 
52 typedef enum conn_state {
53 	CONN_STATE_UNKNOWN,
54 	CONN_STATE_TLS,
55 	CONN_STATE_FEATURE,
56 	CONN_STATE_LDM_INTERFACE,
57 	CONN_STATE_LDM_EVENT,
58 	CONN_STATE_DONE,
59 	CONN_STATE_FAILURE,
60 	CONN_STATE_MAX
61 } conn_state_t;
62 
63 typedef struct xmpp_conn {
64 	int			fd;
65 	int			state;
66 	boolean_t		tls_started;
67 	SSL			*ssl;
68 	xmlParserCtxtPtr	parser;
69 } xmpp_conn_t;
70 
71 /* Forward declaration */
72 static int iowrite(xmpp_conn_t *conn, char *buf, int size);
73 static void start_element(void *state, const xmlChar *name,
74 	const xmlChar **attrs);
75 static void end_element(void *state, const xmlChar *name);
76 static void error_func(void *state, const char *msg, ...);
77 static void xmpp_close(xmpp_conn_t *conn);
78 static int start_tls(xmpp_conn_t *conn);
79 static void handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size);
80 static void handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size);
81 
82 static int xmpp_enable = 0;
83 static int xmpp_notify_pipe[2];
84 static pthread_t xmpp_tid = 0;
85 static pthread_mutex_t xmpp_tid_lock = PTHREAD_MUTEX_INITIALIZER;
86 
87 static client_list_t clt_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
88 
89 
90 #define	FUNCTION_ADD(_function, _pointer, _lib, _func_name, _ret)	\
91 	_function = (_pointer)dlsym(_lib, _func_name);			\
92 	if (_function == NULL) {					\
93 		_ret += -1;						\
94 	}
95 
96 /*
97  * Prototypes and pointers to functions needed from libssl.
98  */
99 typedef void (*SSL_load_error_strings_pt)(void);
100 typedef int (*SSL_library_init_pt)(void);
101 typedef SSL_CTX *(*SSL_CTX_new_pt)(const SSL_METHOD *method);
102 typedef SSL_METHOD *(*SSLv23_client_method_pt)(void);
103 typedef int (*SSL_write_pt)(SSL *ssl, const void *buf, int num);
104 typedef int (*SSL_CTX_use_PrivateKey_file_pt)(SSL_CTX *ctx, const char *file,
105     int type);
106 typedef void (*RAND_seed_pt)(const void *buf, int num);
107 typedef int (*SSL_get_error_pt)(const SSL *ssl, int ret);
108 typedef long (*ERR_get_error_pt)(void);
109 typedef char *(*ERR_error_string_pt)(unsigned long e, char *buf);
110 typedef int (*SSL_connect_pt)(SSL *ssl);
111 typedef int (*SSL_CTX_use_certificate_chain_file_pt)(SSL_CTX *ctx,
112     const char *file);
113 typedef int (*SSL_set_fd_pt)(SSL *ssl, int fd);
114 typedef void (*SSL_free_pt)(SSL *ssl);
115 typedef int (*SSL_read_pt)(SSL *ssl, void *buf, int num);
116 typedef SSL *(*SSL_new_pt)(SSL_CTX *ctx);
117 typedef SSL_CTX *(*SSL_get_SSL_CTX_pt)(const SSL *ssl);
118 typedef void (*SSL_CTX_free_pt)(SSL_CTX *ctx);
119 
120 static SSL_load_error_strings_pt SSL_load_error_strings_f = NULL;
121 static SSL_library_init_pt SSL_library_init_f = NULL;
122 static SSL_CTX_new_pt SSL_CTX_new_f = NULL;
123 static SSLv23_client_method_pt SSLv23_client_method_f = NULL;
124 static SSL_write_pt SSL_write_f = NULL;
125 static SSL_CTX_use_PrivateKey_file_pt SSL_CTX_use_PrivateKey_file_f = NULL;
126 static RAND_seed_pt RAND_seed_f = NULL;
127 static SSL_get_error_pt SSL_get_error_f = NULL;
128 static ERR_get_error_pt ERR_get_error_f = NULL;
129 static ERR_error_string_pt ERR_error_string_f = NULL;
130 static SSL_connect_pt SSL_connect_f = NULL;
131 static SSL_CTX_use_certificate_chain_file_pt
132 SSL_CTX_use_certificate_chain_file_f = NULL;
133 static SSL_set_fd_pt SSL_set_fd_f = NULL;
134 static SSL_free_pt SSL_free_f = NULL;
135 static SSL_read_pt SSL_read_f = NULL;
136 static SSL_new_pt SSL_new_f = NULL;
137 static SSL_get_SSL_CTX_pt SSL_get_SSL_CTX_f = NULL;
138 static SSL_CTX_free_pt SSL_CTX_free_f = NULL;
139 
140 static void *xmpp_dl = NULL;
141 
142 static ldom_event_info_t event_table[] = {
143 	{ LDOM_EVENT_UNKNOWN, "unknown" },
144 	{ LDOM_EVENT_ADD, "add-domain" },
145 	{ LDOM_EVENT_REMOVE, "remove-domain" },
146 	{ LDOM_EVENT_BIND, "bind-domain" },
147 	{ LDOM_EVENT_UNBIND, "unbind-domain" },
148 	{ LDOM_EVENT_START, "start-domain" },
149 	{ LDOM_EVENT_STOP, "stop-domain" },
150 	{ LDOM_EVENT_RESET, "domain-reset" },
151 	{ LDOM_EVENT_PANIC, "panic-domain" },
152 	{ LDOM_EVENT_MAX, NULL }
153 };
154 static int event_table_size = \
155 		sizeof (event_table) / sizeof (ldom_event_info_t);
156 
157 static xmlSAXHandler xml_handler = {
158 	NULL,		/* internalSubsetSAXFunc */
159 	NULL,		/* isStandaloneSAXFunc */
160 	NULL,		/* hasInternalSubsetSAXFunc */
161 	NULL,		/* hasExternalSubsetSAXFunc */
162 	NULL,		/* resolveEntitySAXFunc */
163 	NULL,		/* getEntitySAXFunc */
164 	NULL,		/* entityDeclSAXFunc */
165 	NULL,		/* notationDeclSAXFunc */
166 	NULL,		/* attributeDeclSAXFunc */
167 	NULL,		/* elementDeclSAXFunc */
168 	NULL,		/* unparsedEntityDeclSAXFunc */
169 	NULL,		/* setDocumentLocatorSAXFunc */
170 	NULL,		/* startDocumentSAXFunc */
171 	NULL,		/* endDocumentSAXFunc */
172 	start_element,	/* startElementSAXFunc */
173 	end_element,	/* endElementSAXFunc */
174 	NULL,		/* referenceSAXFunc */
175 	NULL,		/* charactersSAXFunc */
176 	NULL,		/* ignorableWhitespaceSAXFunc */
177 	NULL,		/* processingInstructionSAXFunc */
178 	NULL,		/* commentSAXFunc */
179 	NULL,		/* warningSAXFunc */
180 	error_func,	/* errorSAXFunc */
181 	NULL,		/* fatalErrorSAXFunc */
182 	NULL,		/* getParameterEntitySAXFunc */
183 	NULL,		/* cdataBlockSAXFunc */
184 	NULL,		/* externalSubsetSAXFunc */
185 	0,		/* unsigned int */
186 	NULL,		/* void * _private */
187 	NULL,		/* startElementNsSAX2Func */
188 	NULL,		/* endElementNsSAX2Func */
189 	NULL		/* xmlStructuredErrorFunc */
190 };
191 
192 static void
end_element(void * state,const xmlChar * name)193 end_element(void *state, const xmlChar *name)
194 {
195 	xmpp_conn_t	*conn = (xmpp_conn_t *)state;
196 
197 	if (xmlStrcmp(name, STREAM_NODE) == 0) {
198 		conn->state = CONN_STATE_DONE;
199 	} else if (xmlStrcmp(name, STARTTLS_NODE) == 0) {
200 		(void) iowrite(conn, START_TLS, strlen(START_TLS));
201 	} else if (xmlStrcmp(name, PROCEED_NODE) == 0) {
202 		if (start_tls(conn)) {
203 			conn->state = CONN_STATE_FAILURE;
204 		}
205 	} else if (xmlStrcmp(name, FEATURE_NODE) == 0) {
206 		if (conn->state == CONN_STATE_TLS) {
207 			conn->state = CONN_STATE_FEATURE;
208 			(void) iowrite(conn, (char *)LDM_REG_DOMAIN_EVENTS,
209 			    strlen((char *)LDM_REG_DOMAIN_EVENTS));
210 		}
211 	} else if (xmlStrcmp(name, XML_LDM_INTERFACE) == 0) {
212 		conn->state = CONN_STATE_LDM_INTERFACE;
213 	} else if (xmlStrcmp(name, XML_LDM_EVENT) == 0) {
214 		conn->state = CONN_STATE_LDM_EVENT;
215 	} else if (xmlStrcmp(name, XML_FAILURE) == 0) {
216 		conn->state = CONN_STATE_FAILURE;
217 	}
218 }
219 
220 /*ARGSUSED*/
221 static void
start_element(void * state,const xmlChar * name,const xmlChar ** attrs)222 start_element(void *state, const xmlChar *name, const xmlChar **attrs)
223 {
224 }
225 
226 /*ARGSUSED*/
227 static void
error_func(void * state,const char * msg,...)228 error_func(void *state, const char *msg, ...)
229 {
230 }
231 
232 static int
xmpp_connect(xmpp_conn_t * conn)233 xmpp_connect(xmpp_conn_t *conn)
234 {
235 	int sock;
236 	struct sockaddr_in serveraddr;
237 
238 	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
239 		return (-1);
240 	}
241 
242 	serveraddr.sin_family = AF_INET;
243 	serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
244 	serveraddr.sin_port = htons(XMPP_DEFAULT_PORT);
245 	if (connect(sock, (struct sockaddr *)(&serveraddr),
246 	    sizeof (struct sockaddr_in)) < 0) {
247 		return (-1);
248 	}
249 
250 	(void) bzero(conn, sizeof (xmpp_conn_t));
251 	conn->fd = sock;
252 	conn->tls_started = B_FALSE;
253 
254 	conn->parser = xmlCreatePushParserCtxt(&xml_handler, (void *) conn,
255 	    NULL, NULL, NULL);
256 	if (conn->parser == NULL) {
257 		return (-1);
258 	}
259 
260 	return (0);
261 }
262 
263 static void
xmpp_close(xmpp_conn_t * conn)264 xmpp_close(xmpp_conn_t *conn)
265 {
266 	(void) close(conn->fd);
267 	conn->fd = -1;
268 	conn->state = CONN_STATE_UNKNOWN;
269 	if (conn->parser != NULL) {
270 		xmlFreeParserCtxt(conn->parser);
271 		conn->parser = NULL;
272 	}
273 	if (conn->tls_started) {
274 		SSL_free_f(conn->ssl);
275 		conn->ssl = NULL;
276 	}
277 	conn->tls_started = B_FALSE;
278 }
279 
280 static int
ioread(xmpp_conn_t * conn,char * buf,int size)281 ioread(xmpp_conn_t *conn, char *buf, int size)
282 {
283 	int count;
284 	if (conn->tls_started) {
285 		count = SSL_read_f(conn->ssl, buf, size);
286 	} else {
287 		count = read(conn->fd, buf, size);
288 	}
289 	if (count <= 0) {
290 		conn->state = CONN_STATE_FAILURE;
291 	}
292 
293 	return (count);
294 }
295 
296 static int
iowrite(xmpp_conn_t * conn,char * buf,int size)297 iowrite(xmpp_conn_t *conn, char *buf, int size)
298 {
299 	int count;
300 
301 	if (conn->tls_started) {
302 		count = SSL_write_f(conn->ssl, buf, size);
303 	} else {
304 		count = send(conn->fd, buf, size, 0);
305 	}
306 	if (count <= 0) {
307 		conn->state = CONN_STATE_FAILURE;
308 	}
309 
310 	return (count);
311 }
312 
313 /*
314  * notify_event()
315  * Description:
316  *     Notify all clients an event by going through the client list and invoke
317  *     the callback functions.
318  */
319 static void
notify_event(ldom_event_t event,char * ldom_name)320 notify_event(ldom_event_t event, char *ldom_name)
321 {
322 	client_info_t *p;
323 
324 	(void) pthread_mutex_lock(&clt_list.lock);
325 
326 	for (p = clt_list.head; p != NULL; p = p->next) {
327 		p->cb(ldom_name, event, p->data);
328 	}
329 
330 	(void) pthread_mutex_unlock(&clt_list.lock);
331 }
332 
333 /*
334  * xmpp_client_thr()
335  * Description:
336  *     The main entry fo the xmpp client thread.
337  */
338 /*ARGSUSED*/
339 static void *
xmpp_client_thr(void * data)340 xmpp_client_thr(void *data)
341 {
342 	int rc = 0;
343 	int cnt;
344 	char buf[XMPP_BUF_SIZE];
345 	xmpp_conn_t conn;
346 	pollfd_t pollfd[2];
347 	struct pollfd *pipe_fd = &pollfd[0];
348 	struct pollfd *recv_fd = &pollfd[1];
349 
350 	while (xmpp_enable) {
351 		/* clear the conn struct */
352 		bzero(&conn, sizeof (xmpp_conn_t));
353 
354 		/* keep making a connection until successfully */
355 		do {
356 			if (rc = xmpp_connect(&conn))
357 				(void) sleep(XMPP_SLEEP);
358 		} while (rc != 0 && xmpp_enable);
359 
360 		/* write the stream node */
361 		cnt = iowrite(&conn, (char *)STREAM_START,
362 		    strlen((char *)STREAM_START));
363 		if (cnt != strlen((char *)STREAM_START)) {
364 			xmpp_close(&conn);
365 			(void) sleep(XMPP_SLEEP);
366 			continue;
367 		}
368 
369 		pipe_fd->fd = xmpp_notify_pipe[1];	/* notification pipe */
370 		pipe_fd->events = POLLIN;
371 		recv_fd->fd = conn.fd;			/* XMPP connection */
372 		recv_fd->events = POLLIN;
373 
374 		/* process input */
375 		while ((conn.state != CONN_STATE_FAILURE) &&
376 		    (conn.state != CONN_STATE_DONE) && xmpp_enable) {
377 
378 			/* Wait for xmpp input or the notification */
379 			pipe_fd->revents = 0;
380 			recv_fd->revents = 0;
381 			if (poll(pollfd, 2, -1) <= 0) {
382 				break;
383 			} else if (pipe_fd->revents & POLLIN) {
384 				/* Receive a notification to exit */
385 				xmpp_close(&conn);
386 				pthread_exit((void *)NULL);
387 			}
388 
389 			/*
390 			 * Assume the document size of a ldmd response is
391 			 * less than 1KB. This assumption is valid with the
392 			 * current ldmd implementation.
393 			 * Should the document size exceeds 1KB, the buffer
394 			 * size should be revisited accordingly.
395 			 */
396 			(void) memset(buf, 0, XMPP_BUF_SIZE);
397 			cnt = ioread(&conn, buf, XMPP_BUF_SIZE);
398 			if (cnt <= 0)
399 				break;
400 			if (rc = xmlParseChunk(conn.parser, buf, cnt, 0)) {
401 				conn.state = CONN_STATE_FAILURE;
402 			}
403 
404 			switch (conn.state) {
405 			case CONN_STATE_LDM_INTERFACE:
406 				handle_ldm_resp(&conn, buf, cnt);
407 				break;
408 			case CONN_STATE_LDM_EVENT:
409 				handle_ldm_event(&conn, buf, cnt);
410 				break;
411 			default:
412 				break;
413 			}
414 
415 			/*
416 			 * For now, the parser is reset after every read.
417 			 * It should only be reset once after the ssl is opened
418 			 * in the start_tls().
419 			 */
420 			(void) xmlCtxtResetPush(conn.parser, NULL, NULL, NULL,
421 			    NULL);
422 		}
423 		xmpp_close(&conn);
424 		(void) sleep(XMPP_SLEEP);
425 	}
426 	return (NULL);
427 }
428 
429 /*
430  * find_client()
431  * Description:
432  *     Walk to the list to find a libldom client
433  */
434 static client_info_t *
find_client(ldom_hdl_t * lhp)435 find_client(ldom_hdl_t *lhp)
436 {
437 	client_info_t *p;
438 
439 	for (p = clt_list.head; p != NULL; p = p->next) {
440 		if (p->lhp == lhp)
441 			return (p);
442 	}
443 
444 	return (NULL);
445 }
446 
447 /*
448  * xmpp_add_client()
449  * Description:
450  *     Add a libldom client from the client list.
451  */
452 int
xmpp_add_client(ldom_hdl_t * lhp,ldom_reg_cb_t cb,ldom_cb_arg_t data)453 xmpp_add_client(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
454 {
455 	client_info_t *clt;
456 
457 	(void) pthread_mutex_lock(&clt_list.lock);
458 	if (find_client(lhp)) {
459 		/* already exists */
460 		(void) pthread_mutex_unlock(&clt_list.lock);
461 		return (-1);
462 	}
463 
464 	/* new client */
465 	clt = (client_info_t *)ldom_alloc(sizeof (client_info_t));
466 	clt->lhp = lhp;
467 	clt->cb = cb;
468 	clt->data = data;
469 	clt->next = NULL;
470 	clt->prev = NULL;
471 
472 	if (clt_list.head == NULL && clt_list.tail == NULL) {
473 		clt_list.head = clt;
474 		clt_list.tail = clt;
475 	} else {
476 		/* append to the list */
477 		clt->prev = clt_list.tail;
478 		clt_list.tail->next  = clt;
479 		clt_list.tail = clt;
480 	}
481 
482 	(void) pthread_mutex_unlock(&clt_list.lock);
483 	return (0);
484 }
485 
486 /*
487  * xmpp_remove_client()
488  * Description:
489  *     Remove a libldom client from the client list.
490  */
491 int
xmpp_remove_client(ldom_hdl_t * lhp)492 xmpp_remove_client(ldom_hdl_t *lhp)
493 {
494 	client_info_t *p;
495 
496 	(void) pthread_mutex_lock(&clt_list.lock);
497 	if ((p = find_client(lhp)) == NULL) {
498 		/* not present */
499 		(void) pthread_mutex_unlock(&clt_list.lock);
500 		return (-1);
501 	}
502 
503 	if (clt_list.head == p && clt_list.tail == p) {
504 		/* single item list */
505 		clt_list.head = NULL;
506 		clt_list.tail = NULL;
507 	} else if (clt_list.head == p) {
508 		/* delete the head */
509 		clt_list.head = p->next;
510 		clt_list.head->prev = NULL;
511 	} else if (clt_list.tail == p) {
512 		/* delete the tail */
513 		clt_list.tail = p->prev;
514 		clt_list.tail->next = NULL;
515 	} else {
516 		/* delete a middle node */
517 		p->next->prev = p->prev;
518 		p->prev->next = p->next;
519 	}
520 	ldom_free(p, sizeof (client_info_t));
521 
522 	(void) pthread_mutex_unlock(&clt_list.lock);
523 	return (0);
524 }
525 
526 /*
527  * xmpp_stop()
528  * Description:
529  *     Stop the xmpp client thread
530  */
531 /*ARGSUSED*/
532 void
xmpp_stop(void)533 xmpp_stop(void)
534 {
535 	(void) pthread_mutex_lock(&xmpp_tid_lock);
536 	xmpp_enable = 0;
537 	if (xmpp_tid) {
538 		/*
539 		 * Write a byte to the pipe to notify the xmpp thread to exit.
540 		 * Then wait for it to exit.
541 		 */
542 		(void) write(xmpp_notify_pipe[0], "1", 1);
543 		(void) pthread_join(xmpp_tid, NULL);
544 		xmpp_tid = 0;
545 	}
546 	(void) pthread_mutex_unlock(&xmpp_tid_lock);
547 }
548 
549 /*
550  * xmpp_start()
551  * Description:
552  *     Start the xmpp client thread if have not done so.
553  */
554 void
xmpp_start(void)555 xmpp_start(void)
556 {
557 	xmpp_conn_t conn;
558 
559 	/* Check if the xmmp thread has already started */
560 	(void) pthread_mutex_lock(&xmpp_tid_lock);
561 	if (xmpp_tid != 0) {
562 		(void) pthread_mutex_unlock(&xmpp_tid_lock);
563 		return;
564 	}
565 
566 	/* Check if the ldmd supports xmpp by opening a connection */
567 	if (xmpp_connect(&conn)) {
568 		(void) pthread_mutex_unlock(&xmpp_tid_lock);
569 		return;
570 	}
571 	xmpp_close(&conn);
572 	xmpp_enable = 1;
573 
574 	/*
575 	 * create xmpp client thread for receiving domain events.
576 	 * The notification pipe is for stopping the thread.
577 	 */
578 	(void) notify_setup(xmpp_notify_pipe);
579 	(void) pthread_create(&xmpp_tid, NULL, xmpp_client_thr, NULL);
580 
581 	(void) pthread_mutex_unlock(&xmpp_tid_lock);
582 
583 	/*
584 	 * Register a function to stop the above thread upon a termination
585 	 */
586 	(void) atexit(xmpp_stop);
587 }
588 
589 /*
590  * This routine will run through the first time we get a remote XMPP
591  * connection. After that we will not need to do this again. It cannot be run
592  * from main thread at start as we need to alert remote users if the TLS
593  * handshake failed.
594  */
595 static int
load_SSL_lib()596 load_SSL_lib()
597 {
598 	int ret = 0;
599 
600 	/* If we have already opened the library no need to do it again. */
601 	if (xmpp_dl != NULL)
602 		return (0);
603 
604 	/*
605 	 * If the libssl.so in not in the default path, attempt to open it
606 	 * under /usr/sfw/lib.
607 	 */
608 	xmpp_dl = dlopen("libssl.so", RTLD_NOW);
609 	if (xmpp_dl == NULL) {
610 		xmpp_dl = dlopen("/usr/sfw/lib/libssl.so", RTLD_NOW);
611 		if (xmpp_dl == NULL)
612 			return (-1);
613 	}
614 
615 	FUNCTION_ADD(SSL_load_error_strings_f, SSL_load_error_strings_pt,
616 	    xmpp_dl, "SSL_load_error_strings", ret);
617 	FUNCTION_ADD(SSL_library_init_f, SSL_library_init_pt, xmpp_dl,
618 	    "SSL_library_init", ret);
619 	FUNCTION_ADD(SSL_CTX_new_f, SSL_CTX_new_pt, xmpp_dl,
620 	    "SSL_CTX_new", ret);
621 	FUNCTION_ADD(SSLv23_client_method_f, SSLv23_client_method_pt, xmpp_dl,
622 	    "SSLv23_client_method", ret);
623 	FUNCTION_ADD(SSL_write_f, SSL_write_pt, xmpp_dl, "SSL_write", ret);
624 	FUNCTION_ADD(SSL_CTX_use_PrivateKey_file_f,
625 	    SSL_CTX_use_PrivateKey_file_pt, xmpp_dl,
626 	    "SSL_CTX_use_PrivateKey_file", ret);
627 	FUNCTION_ADD(RAND_seed_f, RAND_seed_pt, xmpp_dl, "RAND_seed", ret);
628 	FUNCTION_ADD(SSL_get_error_f, SSL_get_error_pt, xmpp_dl,
629 	    "SSL_get_error", ret);
630 	FUNCTION_ADD(ERR_get_error_f, ERR_get_error_pt, xmpp_dl,
631 	    "ERR_get_error", ret);
632 	FUNCTION_ADD(ERR_error_string_f, ERR_error_string_pt, xmpp_dl,
633 	    "ERR_error_string", ret);
634 	FUNCTION_ADD(SSL_connect_f, SSL_connect_pt, xmpp_dl, "SSL_connect",
635 	    ret);
636 	FUNCTION_ADD(SSL_CTX_use_certificate_chain_file_f,
637 	    SSL_CTX_use_certificate_chain_file_pt, xmpp_dl,
638 	    "SSL_CTX_use_certificate_chain_file", ret);
639 	FUNCTION_ADD(SSL_set_fd_f, SSL_set_fd_pt, xmpp_dl, "SSL_set_fd", ret);
640 	FUNCTION_ADD(SSL_free_f, SSL_free_pt, xmpp_dl, "SSL_free", ret);
641 	FUNCTION_ADD(SSL_read_f, SSL_read_pt, xmpp_dl, "SSL_read", ret);
642 	FUNCTION_ADD(SSL_new_f, SSL_new_pt, xmpp_dl, "SSL_new", ret);
643 	FUNCTION_ADD(SSL_get_SSL_CTX_f, SSL_get_SSL_CTX_pt, xmpp_dl,
644 	    "SSL_get_SSL_CTX", ret);
645 	FUNCTION_ADD(SSL_CTX_free_f, SSL_CTX_free_pt, xmpp_dl,
646 	    "SSL_CTX_free", ret);
647 
648 	if (ret < 0)
649 		return (-1);
650 	else
651 		return (0);
652 }
653 
654 /*
655  * start_tls()
656  * Description:
657  *     Load the libssl.so if has not done so and open a ssl connection.
658  *     It is assumed that there is one xmpp thread to use the ssl connection.
659  *     If multi-thread xmpp clients use the ssl connection, addtional work is
660  *     needed to ensure the usage of the ssl be thread-safe.
661  */
662 static int
start_tls(xmpp_conn_t * conn)663 start_tls(xmpp_conn_t *conn)
664 {
665 	int		rv, urand_fd;
666 	SSL_CTX		*ssl_ctx;
667 	char		rand_buf[RAND_BUF_SIZE];
668 
669 	rv = load_SSL_lib();
670 	if (rv == -1) {
671 		return (rv);
672 	}
673 
674 	urand_fd = open("/dev/random", O_RDONLY);
675 	if (urand_fd == -1) {
676 		return (-1);
677 	}
678 	(void) read(urand_fd, rand_buf, RAND_BUF_SIZE);
679 
680 	SSL_library_init_f();
681 	RAND_seed_f(rand_buf, RAND_BUF_SIZE);
682 
683 	ssl_ctx = SSL_CTX_new_f(SSLv23_client_method_f());
684 	if (ssl_ctx == NULL) {
685 		return (-1);
686 	}
687 	conn->ssl = SSL_new_f(ssl_ctx);
688 	rv = SSL_set_fd_f(conn->ssl, conn->fd);
689 	if (rv == 0) {
690 		return (-1);
691 	}
692 	rv = SSL_connect_f(conn->ssl);
693 	if (rv != 1) {
694 		return (-1);
695 	}
696 	conn->tls_started = B_TRUE;
697 	conn->state = CONN_STATE_TLS;
698 
699 	(void) iowrite(conn, STREAM_START, strlen(STREAM_START));
700 
701 	return (0);
702 }
703 
704 /*
705  * Find and return the first-level subnode (if any) of 'node' which has name
706  * 'name'.
707  */
708 xmlNodePtr
xml_find_subnode(xmlNodePtr node,const xmlChar * name)709 xml_find_subnode(xmlNodePtr node, const xmlChar *name)
710 {
711 	xmlNodePtr subnode;
712 
713 	if (node == NULL)
714 		return (NULL);
715 
716 	subnode = node->xmlChildrenNode;
717 	while (subnode != NULL) {
718 		if (((char *)subnode->name != NULL) &&
719 		    (xmlStrcmp(subnode->name, name) == 0))
720 			break;
721 		subnode = subnode->next;
722 	}
723 
724 	return (subnode);
725 }
726 
727 /*
728  * handle_ldm_resp()
729  * Description:
730  *     Parse the ldmd response of the domain event registration for the failure
731  *     status. If found, set the connection to failure so that it will be
732  *     closed and a new xmpp connection is established.
733  */
734 void
handle_ldm_resp(xmpp_conn_t * conn,char * buf,size_t buf_size)735 handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size)
736 {
737 	xmlDocPtr	xml_output;
738 	xmlNodePtr	root, resp, status, cmd, action;
739 	char		*status_str, *action_str;
740 
741 	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
742 		return;
743 	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
744 		return;
745 
746 	/* get the cmd node */
747 	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
748 		return;
749 	if (strcmp((char *)cmd->name, (char *)XML_CMD) != 0)
750 		return;
751 
752 	/* get the action node and make sure it is the reg-domain-events */
753 	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
754 		return;
755 	}
756 	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
757 		return;
758 	if (strcmp(action_str, XML_REGISTER_ACTION) != 0) {
759 		xmlFree(action_str);
760 		return;
761 	}
762 	xmlFree(action_str);
763 
764 	/* check the status of the response */
765 	if ((resp = xml_find_subnode(cmd, XML_RESPONSE)) == NULL)
766 		return;
767 	if ((status = xml_find_subnode(resp, XML_STATUS)) == NULL)
768 		return;
769 	if ((status_str = (char *)xmlNodeGetContent(status)) == NULL)
770 		return;
771 	if (strcmp(status_str, (char *)XML_FAILURE) == 0) {
772 		conn->state = CONN_STATE_FAILURE;
773 	}
774 	xmlFree(status_str);
775 }
776 
777 /*
778  * handle_ldm_event()
779  * Description:
780  *     Parse the LDM_event for the ldom name and domain action. Then invokes
781  *     the clients's callback to notify them the event.
782  */
783 /*ARGSUSED*/
784 void
handle_ldm_event(xmpp_conn_t * conn,char * buf,size_t buf_size)785 handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size)
786 {
787 	int		i;
788 	xmlDocPtr	xml_output;
789 	xmlNodePtr	root, cmd, action, data, envelope, content;
790 	char		*action_str, *ldom_name;
791 	ldom_event_t	event = LDOM_EVENT_UNKNOWN;
792 
793 	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
794 		return;
795 	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
796 		return;
797 
798 	/* get the action such as bind-domain, unbind-domain, etc. */
799 	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
800 		return;
801 	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
802 		return;
803 	}
804 	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
805 		return;
806 	for (i = 0; i < event_table_size; i++) {
807 		if (event_table[i].name != NULL &&
808 		    strcasecmp(event_table[i].name, action_str) == 0) {
809 			event = event_table[i].id;
810 			break;
811 		}
812 	}
813 	xmlFree(action_str);
814 
815 	/* get the ldom name */
816 	data = xml_find_subnode(cmd, XML_DATA);
817 	envelope = xml_find_subnode(data, XML_ENVELOPE);
818 	content = xml_find_subnode(envelope, XML_CONTENT);
819 	if ((ldom_name = (char *)xmlGetProp(content, XML_ATTR_ID)) == NULL)
820 		return;
821 
822 	/* Notifies all the clients the event */
823 	if (VALID_LDOM_EVENT(event)) {
824 		notify_event(event, ldom_name);
825 	}
826 
827 	xmlFree(ldom_name);
828 }
829