xref: /onnv-gate/usr/src/lib/fm/libldom/sparc/ldom_xmpp_client.c (revision 12516:22c873a8ec63)
17850SVuong.Nguyen@Sun.COM /*
27850SVuong.Nguyen@Sun.COM  * CDDL HEADER START
37850SVuong.Nguyen@Sun.COM  *
47850SVuong.Nguyen@Sun.COM  * The contents of this file are subject to the terms of the
57850SVuong.Nguyen@Sun.COM  * Common Development and Distribution License (the "License").
67850SVuong.Nguyen@Sun.COM  * You may not use this file except in compliance with the License.
77850SVuong.Nguyen@Sun.COM  *
87850SVuong.Nguyen@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97850SVuong.Nguyen@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107850SVuong.Nguyen@Sun.COM  * See the License for the specific language governing permissions
117850SVuong.Nguyen@Sun.COM  * and limitations under the License.
127850SVuong.Nguyen@Sun.COM  *
137850SVuong.Nguyen@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147850SVuong.Nguyen@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157850SVuong.Nguyen@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167850SVuong.Nguyen@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177850SVuong.Nguyen@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187850SVuong.Nguyen@Sun.COM  *
197850SVuong.Nguyen@Sun.COM  * CDDL HEADER END
207850SVuong.Nguyen@Sun.COM  */
217850SVuong.Nguyen@Sun.COM /*
22*12516SVuong.Nguyen@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237850SVuong.Nguyen@Sun.COM  */
247850SVuong.Nguyen@Sun.COM 
257850SVuong.Nguyen@Sun.COM /*
268357SVuong.Nguyen@Sun.COM  * ldom_xmpp_client.c	Extensible Messaging and Presence Protocol (XMPP)
277850SVuong.Nguyen@Sun.COM  *
287850SVuong.Nguyen@Sun.COM  * Implement an xmpp client to subscribe for domain events from the ldmd.
297850SVuong.Nguyen@Sun.COM  * Notify fmd module clients upon receiving the events.
307850SVuong.Nguyen@Sun.COM  *
317850SVuong.Nguyen@Sun.COM  */
327850SVuong.Nguyen@Sun.COM 
337850SVuong.Nguyen@Sun.COM #include "ldom_xmpp_client.h"
347850SVuong.Nguyen@Sun.COM #include "ldom_alloc.h"
3511831SVuong.Nguyen@Sun.COM #include "ldom_utils.h"
367850SVuong.Nguyen@Sun.COM 
377850SVuong.Nguyen@Sun.COM #include <stdio.h>
387850SVuong.Nguyen@Sun.COM #include <signal.h>
397850SVuong.Nguyen@Sun.COM #include <strings.h>
407850SVuong.Nguyen@Sun.COM #include <unistd.h>
417850SVuong.Nguyen@Sun.COM #include <errno.h>
427850SVuong.Nguyen@Sun.COM 
437850SVuong.Nguyen@Sun.COM #include <netdb.h>
447850SVuong.Nguyen@Sun.COM #include <dlfcn.h>
457850SVuong.Nguyen@Sun.COM #include <fcntl.h>
467850SVuong.Nguyen@Sun.COM #include <sys/socket.h>
477850SVuong.Nguyen@Sun.COM #include <sys/types.h>
487850SVuong.Nguyen@Sun.COM #include <sys/stat.h>
497850SVuong.Nguyen@Sun.COM #include <libxml/parser.h>
507850SVuong.Nguyen@Sun.COM #include <openssl/ssl.h>
517850SVuong.Nguyen@Sun.COM 
527850SVuong.Nguyen@Sun.COM typedef enum conn_state {
537850SVuong.Nguyen@Sun.COM 	CONN_STATE_UNKNOWN,
547850SVuong.Nguyen@Sun.COM 	CONN_STATE_TLS,
557850SVuong.Nguyen@Sun.COM 	CONN_STATE_FEATURE,
567850SVuong.Nguyen@Sun.COM 	CONN_STATE_LDM_INTERFACE,
577850SVuong.Nguyen@Sun.COM 	CONN_STATE_LDM_EVENT,
587850SVuong.Nguyen@Sun.COM 	CONN_STATE_DONE,
597850SVuong.Nguyen@Sun.COM 	CONN_STATE_FAILURE,
607850SVuong.Nguyen@Sun.COM 	CONN_STATE_MAX
617850SVuong.Nguyen@Sun.COM } conn_state_t;
627850SVuong.Nguyen@Sun.COM 
637850SVuong.Nguyen@Sun.COM typedef struct xmpp_conn {
647850SVuong.Nguyen@Sun.COM 	int			fd;
657850SVuong.Nguyen@Sun.COM 	int			state;
667850SVuong.Nguyen@Sun.COM 	boolean_t		tls_started;
677850SVuong.Nguyen@Sun.COM 	SSL			*ssl;
687850SVuong.Nguyen@Sun.COM 	xmlParserCtxtPtr	parser;
697850SVuong.Nguyen@Sun.COM } xmpp_conn_t;
707850SVuong.Nguyen@Sun.COM 
717850SVuong.Nguyen@Sun.COM /* Forward declaration */
727850SVuong.Nguyen@Sun.COM static int iowrite(xmpp_conn_t *conn, char *buf, int size);
737850SVuong.Nguyen@Sun.COM static void start_element(void *state, const xmlChar *name,
747850SVuong.Nguyen@Sun.COM 	const xmlChar **attrs);
757850SVuong.Nguyen@Sun.COM static void end_element(void *state, const xmlChar *name);
767850SVuong.Nguyen@Sun.COM static void error_func(void *state, const char *msg, ...);
777850SVuong.Nguyen@Sun.COM static void xmpp_close(xmpp_conn_t *conn);
787850SVuong.Nguyen@Sun.COM static int start_tls(xmpp_conn_t *conn);
797850SVuong.Nguyen@Sun.COM static void handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size);
807850SVuong.Nguyen@Sun.COM static void handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size);
817850SVuong.Nguyen@Sun.COM 
827850SVuong.Nguyen@Sun.COM static int xmpp_enable = 0;
83*12516SVuong.Nguyen@Sun.COM static int xmpp_notify_pipe[2];
847850SVuong.Nguyen@Sun.COM static pthread_t xmpp_tid = 0;
857850SVuong.Nguyen@Sun.COM static pthread_mutex_t xmpp_tid_lock = PTHREAD_MUTEX_INITIALIZER;
867850SVuong.Nguyen@Sun.COM 
877850SVuong.Nguyen@Sun.COM static client_list_t clt_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
887850SVuong.Nguyen@Sun.COM 
897850SVuong.Nguyen@Sun.COM 
907850SVuong.Nguyen@Sun.COM #define	FUNCTION_ADD(_function, _pointer, _lib, _func_name, _ret)	\
917850SVuong.Nguyen@Sun.COM 	_function = (_pointer)dlsym(_lib, _func_name);			\
927850SVuong.Nguyen@Sun.COM 	if (_function == NULL) {					\
937850SVuong.Nguyen@Sun.COM 		_ret += -1;						\
947850SVuong.Nguyen@Sun.COM 	}
957850SVuong.Nguyen@Sun.COM 
967850SVuong.Nguyen@Sun.COM /*
977850SVuong.Nguyen@Sun.COM  * Prototypes and pointers to functions needed from libssl.
987850SVuong.Nguyen@Sun.COM  */
997850SVuong.Nguyen@Sun.COM typedef void (*SSL_load_error_strings_pt)(void);
1007850SVuong.Nguyen@Sun.COM typedef int (*SSL_library_init_pt)(void);
1017850SVuong.Nguyen@Sun.COM typedef SSL_CTX *(*SSL_CTX_new_pt)(const SSL_METHOD *method);
1027850SVuong.Nguyen@Sun.COM typedef SSL_METHOD *(*SSLv23_client_method_pt)(void);
1037850SVuong.Nguyen@Sun.COM typedef int (*SSL_write_pt)(SSL *ssl, const void *buf, int num);
1047850SVuong.Nguyen@Sun.COM typedef int (*SSL_CTX_use_PrivateKey_file_pt)(SSL_CTX *ctx, const char *file,
1057850SVuong.Nguyen@Sun.COM     int type);
1067850SVuong.Nguyen@Sun.COM typedef void (*RAND_seed_pt)(const void *buf, int num);
1077850SVuong.Nguyen@Sun.COM typedef int (*SSL_get_error_pt)(const SSL *ssl, int ret);
1087850SVuong.Nguyen@Sun.COM typedef long (*ERR_get_error_pt)(void);
1097850SVuong.Nguyen@Sun.COM typedef char *(*ERR_error_string_pt)(unsigned long e, char *buf);
1107850SVuong.Nguyen@Sun.COM typedef int (*SSL_connect_pt)(SSL *ssl);
1117850SVuong.Nguyen@Sun.COM typedef int (*SSL_CTX_use_certificate_chain_file_pt)(SSL_CTX *ctx,
1127850SVuong.Nguyen@Sun.COM     const char *file);
1137850SVuong.Nguyen@Sun.COM typedef int (*SSL_set_fd_pt)(SSL *ssl, int fd);
1147850SVuong.Nguyen@Sun.COM typedef void (*SSL_free_pt)(SSL *ssl);
1157850SVuong.Nguyen@Sun.COM typedef int (*SSL_read_pt)(SSL *ssl, void *buf, int num);
1167850SVuong.Nguyen@Sun.COM typedef SSL *(*SSL_new_pt)(SSL_CTX *ctx);
1177850SVuong.Nguyen@Sun.COM typedef SSL_CTX *(*SSL_get_SSL_CTX_pt)(const SSL *ssl);
1187850SVuong.Nguyen@Sun.COM typedef void (*SSL_CTX_free_pt)(SSL_CTX *ctx);
1197850SVuong.Nguyen@Sun.COM 
1207850SVuong.Nguyen@Sun.COM static SSL_load_error_strings_pt SSL_load_error_strings_f = NULL;
1217850SVuong.Nguyen@Sun.COM static SSL_library_init_pt SSL_library_init_f = NULL;
1227850SVuong.Nguyen@Sun.COM static SSL_CTX_new_pt SSL_CTX_new_f = NULL;
1237850SVuong.Nguyen@Sun.COM static SSLv23_client_method_pt SSLv23_client_method_f = NULL;
1247850SVuong.Nguyen@Sun.COM static SSL_write_pt SSL_write_f = NULL;
1257850SVuong.Nguyen@Sun.COM static SSL_CTX_use_PrivateKey_file_pt SSL_CTX_use_PrivateKey_file_f = NULL;
1267850SVuong.Nguyen@Sun.COM static RAND_seed_pt RAND_seed_f = NULL;
1277850SVuong.Nguyen@Sun.COM static SSL_get_error_pt SSL_get_error_f = NULL;
1287850SVuong.Nguyen@Sun.COM static ERR_get_error_pt ERR_get_error_f = NULL;
1297850SVuong.Nguyen@Sun.COM static ERR_error_string_pt ERR_error_string_f = NULL;
1307850SVuong.Nguyen@Sun.COM static SSL_connect_pt SSL_connect_f = NULL;
1317850SVuong.Nguyen@Sun.COM static SSL_CTX_use_certificate_chain_file_pt
1327850SVuong.Nguyen@Sun.COM SSL_CTX_use_certificate_chain_file_f = NULL;
1337850SVuong.Nguyen@Sun.COM static SSL_set_fd_pt SSL_set_fd_f = NULL;
1347850SVuong.Nguyen@Sun.COM static SSL_free_pt SSL_free_f = NULL;
1357850SVuong.Nguyen@Sun.COM static SSL_read_pt SSL_read_f = NULL;
1367850SVuong.Nguyen@Sun.COM static SSL_new_pt SSL_new_f = NULL;
1377850SVuong.Nguyen@Sun.COM static SSL_get_SSL_CTX_pt SSL_get_SSL_CTX_f = NULL;
1387850SVuong.Nguyen@Sun.COM static SSL_CTX_free_pt SSL_CTX_free_f = NULL;
1397850SVuong.Nguyen@Sun.COM 
1407850SVuong.Nguyen@Sun.COM static void *xmpp_dl = NULL;
1417850SVuong.Nguyen@Sun.COM 
1427850SVuong.Nguyen@Sun.COM static ldom_event_info_t event_table[] = {
1437850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_UNKNOWN, "unknown" },
1447850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_ADD, "add-domain" },
1457850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_REMOVE, "remove-domain" },
1467850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_BIND, "bind-domain" },
1477850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_UNBIND, "unbind-domain" },
1487850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_START, "start-domain" },
1497850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_STOP, "stop-domain" },
1507850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_RESET, "domain-reset" },
1517850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_PANIC, "panic-domain" },
1527850SVuong.Nguyen@Sun.COM 	{ LDOM_EVENT_MAX, NULL }
1537850SVuong.Nguyen@Sun.COM };
1547850SVuong.Nguyen@Sun.COM static int event_table_size = \
1557850SVuong.Nguyen@Sun.COM 		sizeof (event_table) / sizeof (ldom_event_info_t);
1567850SVuong.Nguyen@Sun.COM 
1577850SVuong.Nguyen@Sun.COM static xmlSAXHandler xml_handler = {
1587850SVuong.Nguyen@Sun.COM 	NULL,		/* internalSubsetSAXFunc */
1597850SVuong.Nguyen@Sun.COM 	NULL,		/* isStandaloneSAXFunc */
1607850SVuong.Nguyen@Sun.COM 	NULL,		/* hasInternalSubsetSAXFunc */
1617850SVuong.Nguyen@Sun.COM 	NULL,		/* hasExternalSubsetSAXFunc */
1627850SVuong.Nguyen@Sun.COM 	NULL,		/* resolveEntitySAXFunc */
1637850SVuong.Nguyen@Sun.COM 	NULL,		/* getEntitySAXFunc */
1647850SVuong.Nguyen@Sun.COM 	NULL,		/* entityDeclSAXFunc */
1657850SVuong.Nguyen@Sun.COM 	NULL,		/* notationDeclSAXFunc */
1667850SVuong.Nguyen@Sun.COM 	NULL,		/* attributeDeclSAXFunc */
1677850SVuong.Nguyen@Sun.COM 	NULL,		/* elementDeclSAXFunc */
1687850SVuong.Nguyen@Sun.COM 	NULL,		/* unparsedEntityDeclSAXFunc */
1697850SVuong.Nguyen@Sun.COM 	NULL,		/* setDocumentLocatorSAXFunc */
1707850SVuong.Nguyen@Sun.COM 	NULL,		/* startDocumentSAXFunc */
1717850SVuong.Nguyen@Sun.COM 	NULL,		/* endDocumentSAXFunc */
1727850SVuong.Nguyen@Sun.COM 	start_element,	/* startElementSAXFunc */
1737850SVuong.Nguyen@Sun.COM 	end_element,	/* endElementSAXFunc */
1747850SVuong.Nguyen@Sun.COM 	NULL,		/* referenceSAXFunc */
1757850SVuong.Nguyen@Sun.COM 	NULL,		/* charactersSAXFunc */
1767850SVuong.Nguyen@Sun.COM 	NULL,		/* ignorableWhitespaceSAXFunc */
1777850SVuong.Nguyen@Sun.COM 	NULL,		/* processingInstructionSAXFunc */
1787850SVuong.Nguyen@Sun.COM 	NULL,		/* commentSAXFunc */
1797850SVuong.Nguyen@Sun.COM 	NULL,		/* warningSAXFunc */
1807850SVuong.Nguyen@Sun.COM 	error_func,	/* errorSAXFunc */
1817850SVuong.Nguyen@Sun.COM 	NULL,		/* fatalErrorSAXFunc */
1827850SVuong.Nguyen@Sun.COM 	NULL,		/* getParameterEntitySAXFunc */
1837850SVuong.Nguyen@Sun.COM 	NULL,		/* cdataBlockSAXFunc */
1847850SVuong.Nguyen@Sun.COM 	NULL,		/* externalSubsetSAXFunc */
1857850SVuong.Nguyen@Sun.COM 	0,		/* unsigned int */
1867850SVuong.Nguyen@Sun.COM 	NULL,		/* void * _private */
1877850SVuong.Nguyen@Sun.COM 	NULL,		/* startElementNsSAX2Func */
1887850SVuong.Nguyen@Sun.COM 	NULL,		/* endElementNsSAX2Func */
1897850SVuong.Nguyen@Sun.COM 	NULL		/* xmlStructuredErrorFunc */
1907850SVuong.Nguyen@Sun.COM };
1917850SVuong.Nguyen@Sun.COM 
1927850SVuong.Nguyen@Sun.COM static void
end_element(void * state,const xmlChar * name)1937850SVuong.Nguyen@Sun.COM end_element(void *state, const xmlChar *name)
1947850SVuong.Nguyen@Sun.COM {
1957850SVuong.Nguyen@Sun.COM 	xmpp_conn_t	*conn = (xmpp_conn_t *)state;
1967850SVuong.Nguyen@Sun.COM 
1977850SVuong.Nguyen@Sun.COM 	if (xmlStrcmp(name, STREAM_NODE) == 0) {
1987850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_DONE;
1997850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, STARTTLS_NODE) == 0) {
2007850SVuong.Nguyen@Sun.COM 		(void) iowrite(conn, START_TLS, strlen(START_TLS));
2017850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, PROCEED_NODE) == 0) {
2027850SVuong.Nguyen@Sun.COM 		if (start_tls(conn)) {
2037850SVuong.Nguyen@Sun.COM 			conn->state = CONN_STATE_FAILURE;
2047850SVuong.Nguyen@Sun.COM 		}
2057850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, FEATURE_NODE) == 0) {
2067850SVuong.Nguyen@Sun.COM 		if (conn->state == CONN_STATE_TLS) {
2077850SVuong.Nguyen@Sun.COM 			conn->state = CONN_STATE_FEATURE;
2087850SVuong.Nguyen@Sun.COM 			(void) iowrite(conn, (char *)LDM_REG_DOMAIN_EVENTS,
2097850SVuong.Nguyen@Sun.COM 			    strlen((char *)LDM_REG_DOMAIN_EVENTS));
2107850SVuong.Nguyen@Sun.COM 		}
2117850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, XML_LDM_INTERFACE) == 0) {
2127850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_LDM_INTERFACE;
2137850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, XML_LDM_EVENT) == 0) {
2147850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_LDM_EVENT;
2157850SVuong.Nguyen@Sun.COM 	} else if (xmlStrcmp(name, XML_FAILURE) == 0) {
2167850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_FAILURE;
2177850SVuong.Nguyen@Sun.COM 	}
2187850SVuong.Nguyen@Sun.COM }
2197850SVuong.Nguyen@Sun.COM 
2207850SVuong.Nguyen@Sun.COM /*ARGSUSED*/
2217850SVuong.Nguyen@Sun.COM static void
start_element(void * state,const xmlChar * name,const xmlChar ** attrs)2227850SVuong.Nguyen@Sun.COM start_element(void *state, const xmlChar *name, const xmlChar **attrs)
2237850SVuong.Nguyen@Sun.COM {
2247850SVuong.Nguyen@Sun.COM }
2257850SVuong.Nguyen@Sun.COM 
2267850SVuong.Nguyen@Sun.COM /*ARGSUSED*/
2277850SVuong.Nguyen@Sun.COM static void
error_func(void * state,const char * msg,...)2287850SVuong.Nguyen@Sun.COM error_func(void *state, const char *msg, ...)
2297850SVuong.Nguyen@Sun.COM {
2307850SVuong.Nguyen@Sun.COM }
2317850SVuong.Nguyen@Sun.COM 
2327850SVuong.Nguyen@Sun.COM static int
xmpp_connect(xmpp_conn_t * conn)2337850SVuong.Nguyen@Sun.COM xmpp_connect(xmpp_conn_t *conn)
2347850SVuong.Nguyen@Sun.COM {
2357850SVuong.Nguyen@Sun.COM 	int sock;
2367850SVuong.Nguyen@Sun.COM 	struct sockaddr_in serveraddr;
2377850SVuong.Nguyen@Sun.COM 
2387850SVuong.Nguyen@Sun.COM 	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
2397850SVuong.Nguyen@Sun.COM 		return (-1);
2407850SVuong.Nguyen@Sun.COM 	}
2417850SVuong.Nguyen@Sun.COM 
2427850SVuong.Nguyen@Sun.COM 	serveraddr.sin_family = AF_INET;
2437850SVuong.Nguyen@Sun.COM 	serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2447850SVuong.Nguyen@Sun.COM 	serveraddr.sin_port = htons(XMPP_DEFAULT_PORT);
2457850SVuong.Nguyen@Sun.COM 	if (connect(sock, (struct sockaddr *)(&serveraddr),
2467850SVuong.Nguyen@Sun.COM 	    sizeof (struct sockaddr_in)) < 0) {
2477850SVuong.Nguyen@Sun.COM 		return (-1);
2487850SVuong.Nguyen@Sun.COM 	}
2497850SVuong.Nguyen@Sun.COM 
2507850SVuong.Nguyen@Sun.COM 	(void) bzero(conn, sizeof (xmpp_conn_t));
2517850SVuong.Nguyen@Sun.COM 	conn->fd = sock;
2527850SVuong.Nguyen@Sun.COM 	conn->tls_started = B_FALSE;
2537850SVuong.Nguyen@Sun.COM 
2547850SVuong.Nguyen@Sun.COM 	conn->parser = xmlCreatePushParserCtxt(&xml_handler, (void *) conn,
2557850SVuong.Nguyen@Sun.COM 	    NULL, NULL, NULL);
2567850SVuong.Nguyen@Sun.COM 	if (conn->parser == NULL) {
2577850SVuong.Nguyen@Sun.COM 		return (-1);
2587850SVuong.Nguyen@Sun.COM 	}
2597850SVuong.Nguyen@Sun.COM 
2607850SVuong.Nguyen@Sun.COM 	return (0);
2617850SVuong.Nguyen@Sun.COM }
2627850SVuong.Nguyen@Sun.COM 
2637850SVuong.Nguyen@Sun.COM static void
xmpp_close(xmpp_conn_t * conn)2647850SVuong.Nguyen@Sun.COM xmpp_close(xmpp_conn_t *conn)
2657850SVuong.Nguyen@Sun.COM {
2667850SVuong.Nguyen@Sun.COM 	(void) close(conn->fd);
2677850SVuong.Nguyen@Sun.COM 	conn->fd = -1;
2687850SVuong.Nguyen@Sun.COM 	conn->state = CONN_STATE_UNKNOWN;
2697850SVuong.Nguyen@Sun.COM 	if (conn->parser != NULL) {
2707850SVuong.Nguyen@Sun.COM 		xmlFreeParserCtxt(conn->parser);
2717850SVuong.Nguyen@Sun.COM 		conn->parser = NULL;
2727850SVuong.Nguyen@Sun.COM 	}
2737850SVuong.Nguyen@Sun.COM 	if (conn->tls_started) {
2747850SVuong.Nguyen@Sun.COM 		SSL_free_f(conn->ssl);
2757850SVuong.Nguyen@Sun.COM 		conn->ssl = NULL;
2767850SVuong.Nguyen@Sun.COM 	}
2777850SVuong.Nguyen@Sun.COM 	conn->tls_started = B_FALSE;
2787850SVuong.Nguyen@Sun.COM }
2797850SVuong.Nguyen@Sun.COM 
2807850SVuong.Nguyen@Sun.COM static int
ioread(xmpp_conn_t * conn,char * buf,int size)2817850SVuong.Nguyen@Sun.COM ioread(xmpp_conn_t *conn, char *buf, int size)
2827850SVuong.Nguyen@Sun.COM {
2837850SVuong.Nguyen@Sun.COM 	int count;
2847850SVuong.Nguyen@Sun.COM 	if (conn->tls_started) {
2857850SVuong.Nguyen@Sun.COM 		count = SSL_read_f(conn->ssl, buf, size);
2867850SVuong.Nguyen@Sun.COM 	} else {
2877850SVuong.Nguyen@Sun.COM 		count = read(conn->fd, buf, size);
2887850SVuong.Nguyen@Sun.COM 	}
2897850SVuong.Nguyen@Sun.COM 	if (count <= 0) {
2907850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_FAILURE;
2917850SVuong.Nguyen@Sun.COM 	}
2927850SVuong.Nguyen@Sun.COM 
2937850SVuong.Nguyen@Sun.COM 	return (count);
2947850SVuong.Nguyen@Sun.COM }
2957850SVuong.Nguyen@Sun.COM 
2967850SVuong.Nguyen@Sun.COM static int
iowrite(xmpp_conn_t * conn,char * buf,int size)2977850SVuong.Nguyen@Sun.COM iowrite(xmpp_conn_t *conn, char *buf, int size)
2987850SVuong.Nguyen@Sun.COM {
2997850SVuong.Nguyen@Sun.COM 	int count;
3007850SVuong.Nguyen@Sun.COM 
3017850SVuong.Nguyen@Sun.COM 	if (conn->tls_started) {
3027850SVuong.Nguyen@Sun.COM 		count = SSL_write_f(conn->ssl, buf, size);
3037850SVuong.Nguyen@Sun.COM 	} else {
3047850SVuong.Nguyen@Sun.COM 		count = send(conn->fd, buf, size, 0);
3057850SVuong.Nguyen@Sun.COM 	}
3067850SVuong.Nguyen@Sun.COM 	if (count <= 0) {
3077850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_FAILURE;
3087850SVuong.Nguyen@Sun.COM 	}
3097850SVuong.Nguyen@Sun.COM 
3107850SVuong.Nguyen@Sun.COM 	return (count);
3117850SVuong.Nguyen@Sun.COM }
3127850SVuong.Nguyen@Sun.COM 
3137850SVuong.Nguyen@Sun.COM /*
3147850SVuong.Nguyen@Sun.COM  * notify_event()
3157850SVuong.Nguyen@Sun.COM  * Description:
3167850SVuong.Nguyen@Sun.COM  *     Notify all clients an event by going through the client list and invoke
3177850SVuong.Nguyen@Sun.COM  *     the callback functions.
3187850SVuong.Nguyen@Sun.COM  */
3197850SVuong.Nguyen@Sun.COM static void
notify_event(ldom_event_t event,char * ldom_name)3207850SVuong.Nguyen@Sun.COM notify_event(ldom_event_t event, char *ldom_name)
3217850SVuong.Nguyen@Sun.COM {
3227850SVuong.Nguyen@Sun.COM 	client_info_t *p;
3237850SVuong.Nguyen@Sun.COM 
3247850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_lock(&clt_list.lock);
3257850SVuong.Nguyen@Sun.COM 
3267850SVuong.Nguyen@Sun.COM 	for (p = clt_list.head; p != NULL; p = p->next) {
3277850SVuong.Nguyen@Sun.COM 		p->cb(ldom_name, event, p->data);
3287850SVuong.Nguyen@Sun.COM 	}
3297850SVuong.Nguyen@Sun.COM 
3307850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_unlock(&clt_list.lock);
3317850SVuong.Nguyen@Sun.COM }
3327850SVuong.Nguyen@Sun.COM 
3337850SVuong.Nguyen@Sun.COM /*
3347850SVuong.Nguyen@Sun.COM  * xmpp_client_thr()
3357850SVuong.Nguyen@Sun.COM  * Description:
3367850SVuong.Nguyen@Sun.COM  *     The main entry fo the xmpp client thread.
3377850SVuong.Nguyen@Sun.COM  */
3387850SVuong.Nguyen@Sun.COM /*ARGSUSED*/
3397850SVuong.Nguyen@Sun.COM static void *
xmpp_client_thr(void * data)3407850SVuong.Nguyen@Sun.COM xmpp_client_thr(void *data)
3417850SVuong.Nguyen@Sun.COM {
3427850SVuong.Nguyen@Sun.COM 	int rc = 0;
3437850SVuong.Nguyen@Sun.COM 	int cnt;
3447850SVuong.Nguyen@Sun.COM 	char buf[XMPP_BUF_SIZE];
3457850SVuong.Nguyen@Sun.COM 	xmpp_conn_t conn;
346*12516SVuong.Nguyen@Sun.COM 	pollfd_t pollfd[2];
347*12516SVuong.Nguyen@Sun.COM 	struct pollfd *pipe_fd = &pollfd[0];
348*12516SVuong.Nguyen@Sun.COM 	struct pollfd *recv_fd = &pollfd[1];
3497850SVuong.Nguyen@Sun.COM 
3507850SVuong.Nguyen@Sun.COM 	while (xmpp_enable) {
35111831SVuong.Nguyen@Sun.COM 		/* clear the conn struct */
35211831SVuong.Nguyen@Sun.COM 		bzero(&conn, sizeof (xmpp_conn_t));
3537850SVuong.Nguyen@Sun.COM 
3547850SVuong.Nguyen@Sun.COM 		/* keep making a connection until successfully */
3557850SVuong.Nguyen@Sun.COM 		do {
3567850SVuong.Nguyen@Sun.COM 			if (rc = xmpp_connect(&conn))
3577850SVuong.Nguyen@Sun.COM 				(void) sleep(XMPP_SLEEP);
3587850SVuong.Nguyen@Sun.COM 		} while (rc != 0 && xmpp_enable);
3597850SVuong.Nguyen@Sun.COM 
3607850SVuong.Nguyen@Sun.COM 		/* write the stream node */
3617850SVuong.Nguyen@Sun.COM 		cnt = iowrite(&conn, (char *)STREAM_START,
3627850SVuong.Nguyen@Sun.COM 		    strlen((char *)STREAM_START));
36311831SVuong.Nguyen@Sun.COM 		if (cnt != strlen((char *)STREAM_START)) {
36411831SVuong.Nguyen@Sun.COM 			xmpp_close(&conn);
36511831SVuong.Nguyen@Sun.COM 			(void) sleep(XMPP_SLEEP);
36611831SVuong.Nguyen@Sun.COM 			continue;
36711831SVuong.Nguyen@Sun.COM 		}
3687850SVuong.Nguyen@Sun.COM 
369*12516SVuong.Nguyen@Sun.COM 		pipe_fd->fd = xmpp_notify_pipe[1];	/* notification pipe */
370*12516SVuong.Nguyen@Sun.COM 		pipe_fd->events = POLLIN;
371*12516SVuong.Nguyen@Sun.COM 		recv_fd->fd = conn.fd;			/* XMPP connection */
372*12516SVuong.Nguyen@Sun.COM 		recv_fd->events = POLLIN;
373*12516SVuong.Nguyen@Sun.COM 
3747850SVuong.Nguyen@Sun.COM 		/* process input */
3757850SVuong.Nguyen@Sun.COM 		while ((conn.state != CONN_STATE_FAILURE) &&
3767850SVuong.Nguyen@Sun.COM 		    (conn.state != CONN_STATE_DONE) && xmpp_enable) {
3777850SVuong.Nguyen@Sun.COM 
378*12516SVuong.Nguyen@Sun.COM 			/* Wait for xmpp input or the notification */
379*12516SVuong.Nguyen@Sun.COM 			pipe_fd->revents = 0;
380*12516SVuong.Nguyen@Sun.COM 			recv_fd->revents = 0;
381*12516SVuong.Nguyen@Sun.COM 			if (poll(pollfd, 2, -1) <= 0) {
382*12516SVuong.Nguyen@Sun.COM 				break;
383*12516SVuong.Nguyen@Sun.COM 			} else if (pipe_fd->revents & POLLIN) {
384*12516SVuong.Nguyen@Sun.COM 				/* Receive a notification to exit */
385*12516SVuong.Nguyen@Sun.COM 				xmpp_close(&conn);
386*12516SVuong.Nguyen@Sun.COM 				pthread_exit((void *)NULL);
387*12516SVuong.Nguyen@Sun.COM 			}
388*12516SVuong.Nguyen@Sun.COM 
3897850SVuong.Nguyen@Sun.COM 			/*
3907850SVuong.Nguyen@Sun.COM 			 * Assume the document size of a ldmd response is
3917850SVuong.Nguyen@Sun.COM 			 * less than 1KB. This assumption is valid with the
3927850SVuong.Nguyen@Sun.COM 			 * current ldmd implementation.
3937850SVuong.Nguyen@Sun.COM 			 * Should the document size exceeds 1KB, the buffer
3947850SVuong.Nguyen@Sun.COM 			 * size should be revisited accordingly.
3957850SVuong.Nguyen@Sun.COM 			 */
3967850SVuong.Nguyen@Sun.COM 			(void) memset(buf, 0, XMPP_BUF_SIZE);
3977850SVuong.Nguyen@Sun.COM 			cnt = ioread(&conn, buf, XMPP_BUF_SIZE);
3987850SVuong.Nguyen@Sun.COM 			if (cnt <= 0)
3997850SVuong.Nguyen@Sun.COM 				break;
4007850SVuong.Nguyen@Sun.COM 			if (rc = xmlParseChunk(conn.parser, buf, cnt, 0)) {
4017850SVuong.Nguyen@Sun.COM 				conn.state = CONN_STATE_FAILURE;
4027850SVuong.Nguyen@Sun.COM 			}
4037850SVuong.Nguyen@Sun.COM 
4047850SVuong.Nguyen@Sun.COM 			switch (conn.state) {
4057850SVuong.Nguyen@Sun.COM 			case CONN_STATE_LDM_INTERFACE:
4067850SVuong.Nguyen@Sun.COM 				handle_ldm_resp(&conn, buf, cnt);
4077850SVuong.Nguyen@Sun.COM 				break;
4087850SVuong.Nguyen@Sun.COM 			case CONN_STATE_LDM_EVENT:
4097850SVuong.Nguyen@Sun.COM 				handle_ldm_event(&conn, buf, cnt);
4107850SVuong.Nguyen@Sun.COM 				break;
4117850SVuong.Nguyen@Sun.COM 			default:
4127850SVuong.Nguyen@Sun.COM 				break;
4137850SVuong.Nguyen@Sun.COM 			}
4147850SVuong.Nguyen@Sun.COM 
4157850SVuong.Nguyen@Sun.COM 			/*
4167850SVuong.Nguyen@Sun.COM 			 * For now, the parser is reset after every read.
4177850SVuong.Nguyen@Sun.COM 			 * It should only be reset once after the ssl is opened
4187850SVuong.Nguyen@Sun.COM 			 * in the start_tls().
4197850SVuong.Nguyen@Sun.COM 			 */
4207850SVuong.Nguyen@Sun.COM 			(void) xmlCtxtResetPush(conn.parser, NULL, NULL, NULL,
4217850SVuong.Nguyen@Sun.COM 			    NULL);
4227850SVuong.Nguyen@Sun.COM 		}
4237850SVuong.Nguyen@Sun.COM 		xmpp_close(&conn);
4247850SVuong.Nguyen@Sun.COM 		(void) sleep(XMPP_SLEEP);
4257850SVuong.Nguyen@Sun.COM 	}
4267850SVuong.Nguyen@Sun.COM 	return (NULL);
4277850SVuong.Nguyen@Sun.COM }
4287850SVuong.Nguyen@Sun.COM 
4297850SVuong.Nguyen@Sun.COM /*
4307850SVuong.Nguyen@Sun.COM  * find_client()
4317850SVuong.Nguyen@Sun.COM  * Description:
4327850SVuong.Nguyen@Sun.COM  *     Walk to the list to find a libldom client
4337850SVuong.Nguyen@Sun.COM  */
4347850SVuong.Nguyen@Sun.COM static client_info_t *
find_client(ldom_hdl_t * lhp)4357850SVuong.Nguyen@Sun.COM find_client(ldom_hdl_t *lhp)
4367850SVuong.Nguyen@Sun.COM {
4377850SVuong.Nguyen@Sun.COM 	client_info_t *p;
4387850SVuong.Nguyen@Sun.COM 
4397850SVuong.Nguyen@Sun.COM 	for (p = clt_list.head; p != NULL; p = p->next) {
4407850SVuong.Nguyen@Sun.COM 		if (p->lhp == lhp)
4417850SVuong.Nguyen@Sun.COM 			return (p);
4427850SVuong.Nguyen@Sun.COM 	}
4437850SVuong.Nguyen@Sun.COM 
4447850SVuong.Nguyen@Sun.COM 	return (NULL);
4457850SVuong.Nguyen@Sun.COM }
4467850SVuong.Nguyen@Sun.COM 
4477850SVuong.Nguyen@Sun.COM /*
4487850SVuong.Nguyen@Sun.COM  * xmpp_add_client()
4497850SVuong.Nguyen@Sun.COM  * Description:
4507850SVuong.Nguyen@Sun.COM  *     Add a libldom client from the client list.
4517850SVuong.Nguyen@Sun.COM  */
4527850SVuong.Nguyen@Sun.COM int
xmpp_add_client(ldom_hdl_t * lhp,ldom_reg_cb_t cb,ldom_cb_arg_t data)4537850SVuong.Nguyen@Sun.COM xmpp_add_client(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
4547850SVuong.Nguyen@Sun.COM {
4557850SVuong.Nguyen@Sun.COM 	client_info_t *clt;
4567850SVuong.Nguyen@Sun.COM 
4577850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_lock(&clt_list.lock);
4587850SVuong.Nguyen@Sun.COM 	if (find_client(lhp)) {
4597850SVuong.Nguyen@Sun.COM 		/* already exists */
4607850SVuong.Nguyen@Sun.COM 		(void) pthread_mutex_unlock(&clt_list.lock);
4617850SVuong.Nguyen@Sun.COM 		return (-1);
4627850SVuong.Nguyen@Sun.COM 	}
4637850SVuong.Nguyen@Sun.COM 
4647850SVuong.Nguyen@Sun.COM 	/* new client */
4657850SVuong.Nguyen@Sun.COM 	clt = (client_info_t *)ldom_alloc(sizeof (client_info_t));
4667850SVuong.Nguyen@Sun.COM 	clt->lhp = lhp;
4677850SVuong.Nguyen@Sun.COM 	clt->cb = cb;
4687850SVuong.Nguyen@Sun.COM 	clt->data = data;
4697850SVuong.Nguyen@Sun.COM 	clt->next = NULL;
4707850SVuong.Nguyen@Sun.COM 	clt->prev = NULL;
4717850SVuong.Nguyen@Sun.COM 
4727850SVuong.Nguyen@Sun.COM 	if (clt_list.head == NULL && clt_list.tail == NULL) {
4737850SVuong.Nguyen@Sun.COM 		clt_list.head = clt;
4747850SVuong.Nguyen@Sun.COM 		clt_list.tail = clt;
4757850SVuong.Nguyen@Sun.COM 	} else {
4767850SVuong.Nguyen@Sun.COM 		/* append to the list */
4777850SVuong.Nguyen@Sun.COM 		clt->prev = clt_list.tail;
4787850SVuong.Nguyen@Sun.COM 		clt_list.tail->next  = clt;
4797850SVuong.Nguyen@Sun.COM 		clt_list.tail = clt;
4807850SVuong.Nguyen@Sun.COM 	}
4817850SVuong.Nguyen@Sun.COM 
4827850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_unlock(&clt_list.lock);
4837850SVuong.Nguyen@Sun.COM 	return (0);
4847850SVuong.Nguyen@Sun.COM }
4857850SVuong.Nguyen@Sun.COM 
4867850SVuong.Nguyen@Sun.COM /*
4877850SVuong.Nguyen@Sun.COM  * xmpp_remove_client()
4887850SVuong.Nguyen@Sun.COM  * Description:
4897850SVuong.Nguyen@Sun.COM  *     Remove a libldom client from the client list.
4907850SVuong.Nguyen@Sun.COM  */
4917850SVuong.Nguyen@Sun.COM int
xmpp_remove_client(ldom_hdl_t * lhp)4927850SVuong.Nguyen@Sun.COM xmpp_remove_client(ldom_hdl_t *lhp)
4937850SVuong.Nguyen@Sun.COM {
4947850SVuong.Nguyen@Sun.COM 	client_info_t *p;
4957850SVuong.Nguyen@Sun.COM 
4967850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_lock(&clt_list.lock);
4977850SVuong.Nguyen@Sun.COM 	if ((p = find_client(lhp)) == NULL) {
4987850SVuong.Nguyen@Sun.COM 		/* not present */
4997850SVuong.Nguyen@Sun.COM 		(void) pthread_mutex_unlock(&clt_list.lock);
5007850SVuong.Nguyen@Sun.COM 		return (-1);
5017850SVuong.Nguyen@Sun.COM 	}
5027850SVuong.Nguyen@Sun.COM 
5037850SVuong.Nguyen@Sun.COM 	if (clt_list.head == p && clt_list.tail == p) {
5047850SVuong.Nguyen@Sun.COM 		/* single item list */
5057850SVuong.Nguyen@Sun.COM 		clt_list.head = NULL;
5067850SVuong.Nguyen@Sun.COM 		clt_list.tail = NULL;
5077850SVuong.Nguyen@Sun.COM 	} else if (clt_list.head == p) {
5087850SVuong.Nguyen@Sun.COM 		/* delete the head */
5097850SVuong.Nguyen@Sun.COM 		clt_list.head = p->next;
5107850SVuong.Nguyen@Sun.COM 		clt_list.head->prev = NULL;
5117850SVuong.Nguyen@Sun.COM 	} else if (clt_list.tail == p) {
5127850SVuong.Nguyen@Sun.COM 		/* delete the tail */
5137850SVuong.Nguyen@Sun.COM 		clt_list.tail = p->prev;
5147850SVuong.Nguyen@Sun.COM 		clt_list.tail->next = NULL;
5157850SVuong.Nguyen@Sun.COM 	} else {
5167850SVuong.Nguyen@Sun.COM 		/* delete a middle node */
5177850SVuong.Nguyen@Sun.COM 		p->next->prev = p->prev;
5187850SVuong.Nguyen@Sun.COM 		p->prev->next = p->next;
5197850SVuong.Nguyen@Sun.COM 	}
5207850SVuong.Nguyen@Sun.COM 	ldom_free(p, sizeof (client_info_t));
5217850SVuong.Nguyen@Sun.COM 
5227850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_unlock(&clt_list.lock);
5237850SVuong.Nguyen@Sun.COM 	return (0);
5247850SVuong.Nguyen@Sun.COM }
5257850SVuong.Nguyen@Sun.COM 
5267850SVuong.Nguyen@Sun.COM /*
5277850SVuong.Nguyen@Sun.COM  * xmpp_stop()
5287850SVuong.Nguyen@Sun.COM  * Description:
5297850SVuong.Nguyen@Sun.COM  *     Stop the xmpp client thread
5307850SVuong.Nguyen@Sun.COM  */
5317850SVuong.Nguyen@Sun.COM /*ARGSUSED*/
5327850SVuong.Nguyen@Sun.COM void
xmpp_stop(void)5337850SVuong.Nguyen@Sun.COM xmpp_stop(void)
5347850SVuong.Nguyen@Sun.COM {
5357850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_lock(&xmpp_tid_lock);
5367850SVuong.Nguyen@Sun.COM 	xmpp_enable = 0;
5377850SVuong.Nguyen@Sun.COM 	if (xmpp_tid) {
538*12516SVuong.Nguyen@Sun.COM 		/*
539*12516SVuong.Nguyen@Sun.COM 		 * Write a byte to the pipe to notify the xmpp thread to exit.
540*12516SVuong.Nguyen@Sun.COM 		 * Then wait for it to exit.
541*12516SVuong.Nguyen@Sun.COM 		 */
542*12516SVuong.Nguyen@Sun.COM 		(void) write(xmpp_notify_pipe[0], "1", 1);
5437850SVuong.Nguyen@Sun.COM 		(void) pthread_join(xmpp_tid, NULL);
5447850SVuong.Nguyen@Sun.COM 		xmpp_tid = 0;
5457850SVuong.Nguyen@Sun.COM 	}
5467850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_unlock(&xmpp_tid_lock);
5477850SVuong.Nguyen@Sun.COM }
5487850SVuong.Nguyen@Sun.COM 
5497850SVuong.Nguyen@Sun.COM /*
5507850SVuong.Nguyen@Sun.COM  * xmpp_start()
5517850SVuong.Nguyen@Sun.COM  * Description:
5527850SVuong.Nguyen@Sun.COM  *     Start the xmpp client thread if have not done so.
5537850SVuong.Nguyen@Sun.COM  */
5547850SVuong.Nguyen@Sun.COM void
xmpp_start(void)5557850SVuong.Nguyen@Sun.COM xmpp_start(void)
5567850SVuong.Nguyen@Sun.COM {
5577850SVuong.Nguyen@Sun.COM 	xmpp_conn_t conn;
5587850SVuong.Nguyen@Sun.COM 
5597850SVuong.Nguyen@Sun.COM 	/* Check if the xmmp thread has already started */
5607850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_lock(&xmpp_tid_lock);
5617850SVuong.Nguyen@Sun.COM 	if (xmpp_tid != 0) {
5627850SVuong.Nguyen@Sun.COM 		(void) pthread_mutex_unlock(&xmpp_tid_lock);
5637850SVuong.Nguyen@Sun.COM 		return;
5647850SVuong.Nguyen@Sun.COM 	}
5657850SVuong.Nguyen@Sun.COM 
5667850SVuong.Nguyen@Sun.COM 	/* Check if the ldmd supports xmpp by opening a connection */
5677850SVuong.Nguyen@Sun.COM 	if (xmpp_connect(&conn)) {
5687850SVuong.Nguyen@Sun.COM 		(void) pthread_mutex_unlock(&xmpp_tid_lock);
5697850SVuong.Nguyen@Sun.COM 		return;
5707850SVuong.Nguyen@Sun.COM 	}
5717850SVuong.Nguyen@Sun.COM 	xmpp_close(&conn);
5727850SVuong.Nguyen@Sun.COM 	xmpp_enable = 1;
5737850SVuong.Nguyen@Sun.COM 
5747850SVuong.Nguyen@Sun.COM 	/*
575*12516SVuong.Nguyen@Sun.COM 	 * create xmpp client thread for receiving domain events.
576*12516SVuong.Nguyen@Sun.COM 	 * The notification pipe is for stopping the thread.
5777850SVuong.Nguyen@Sun.COM 	 */
578*12516SVuong.Nguyen@Sun.COM 	(void) notify_setup(xmpp_notify_pipe);
5797850SVuong.Nguyen@Sun.COM 	(void) pthread_create(&xmpp_tid, NULL, xmpp_client_thr, NULL);
5807850SVuong.Nguyen@Sun.COM 
5817850SVuong.Nguyen@Sun.COM 	(void) pthread_mutex_unlock(&xmpp_tid_lock);
5827850SVuong.Nguyen@Sun.COM 
5837850SVuong.Nguyen@Sun.COM 	/*
5847850SVuong.Nguyen@Sun.COM 	 * Register a function to stop the above thread upon a termination
5857850SVuong.Nguyen@Sun.COM 	 */
5867850SVuong.Nguyen@Sun.COM 	(void) atexit(xmpp_stop);
5877850SVuong.Nguyen@Sun.COM }
5887850SVuong.Nguyen@Sun.COM 
5897850SVuong.Nguyen@Sun.COM /*
5907850SVuong.Nguyen@Sun.COM  * This routine will run through the first time we get a remote XMPP
5917850SVuong.Nguyen@Sun.COM  * connection. After that we will not need to do this again. It cannot be run
5927850SVuong.Nguyen@Sun.COM  * from main thread at start as we need to alert remote users if the TLS
5937850SVuong.Nguyen@Sun.COM  * handshake failed.
5947850SVuong.Nguyen@Sun.COM  */
5957850SVuong.Nguyen@Sun.COM static int
load_SSL_lib()5967850SVuong.Nguyen@Sun.COM load_SSL_lib()
5977850SVuong.Nguyen@Sun.COM {
5987850SVuong.Nguyen@Sun.COM 	int ret = 0;
5997850SVuong.Nguyen@Sun.COM 
6007850SVuong.Nguyen@Sun.COM 	/* If we have already opened the library no need to do it again. */
6017850SVuong.Nguyen@Sun.COM 	if (xmpp_dl != NULL)
6027850SVuong.Nguyen@Sun.COM 		return (0);
6037850SVuong.Nguyen@Sun.COM 
6048357SVuong.Nguyen@Sun.COM 	/*
6058357SVuong.Nguyen@Sun.COM 	 * If the libssl.so in not in the default path, attempt to open it
6068357SVuong.Nguyen@Sun.COM 	 * under /usr/sfw/lib.
6078357SVuong.Nguyen@Sun.COM 	 */
6088357SVuong.Nguyen@Sun.COM 	xmpp_dl = dlopen("libssl.so", RTLD_NOW);
6098357SVuong.Nguyen@Sun.COM 	if (xmpp_dl == NULL) {
6108357SVuong.Nguyen@Sun.COM 		xmpp_dl = dlopen("/usr/sfw/lib/libssl.so", RTLD_NOW);
6118357SVuong.Nguyen@Sun.COM 		if (xmpp_dl == NULL)
6128357SVuong.Nguyen@Sun.COM 			return (-1);
6138357SVuong.Nguyen@Sun.COM 	}
6147850SVuong.Nguyen@Sun.COM 
6157850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_load_error_strings_f, SSL_load_error_strings_pt,
6167850SVuong.Nguyen@Sun.COM 	    xmpp_dl, "SSL_load_error_strings", ret);
6177850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_library_init_f, SSL_library_init_pt, xmpp_dl,
6187850SVuong.Nguyen@Sun.COM 	    "SSL_library_init", ret);
6197850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_CTX_new_f, SSL_CTX_new_pt, xmpp_dl,
6207850SVuong.Nguyen@Sun.COM 	    "SSL_CTX_new", ret);
6217850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSLv23_client_method_f, SSLv23_client_method_pt, xmpp_dl,
6227850SVuong.Nguyen@Sun.COM 	    "SSLv23_client_method", ret);
6237850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_write_f, SSL_write_pt, xmpp_dl, "SSL_write", ret);
6247850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_CTX_use_PrivateKey_file_f,
6257850SVuong.Nguyen@Sun.COM 	    SSL_CTX_use_PrivateKey_file_pt, xmpp_dl,
6267850SVuong.Nguyen@Sun.COM 	    "SSL_CTX_use_PrivateKey_file", ret);
6277850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(RAND_seed_f, RAND_seed_pt, xmpp_dl, "RAND_seed", ret);
6287850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_get_error_f, SSL_get_error_pt, xmpp_dl,
6297850SVuong.Nguyen@Sun.COM 	    "SSL_get_error", ret);
6307850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(ERR_get_error_f, ERR_get_error_pt, xmpp_dl,
6317850SVuong.Nguyen@Sun.COM 	    "ERR_get_error", ret);
6327850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(ERR_error_string_f, ERR_error_string_pt, xmpp_dl,
6337850SVuong.Nguyen@Sun.COM 	    "ERR_error_string", ret);
6347850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_connect_f, SSL_connect_pt, xmpp_dl, "SSL_connect",
6357850SVuong.Nguyen@Sun.COM 	    ret);
6367850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_CTX_use_certificate_chain_file_f,
6377850SVuong.Nguyen@Sun.COM 	    SSL_CTX_use_certificate_chain_file_pt, xmpp_dl,
6387850SVuong.Nguyen@Sun.COM 	    "SSL_CTX_use_certificate_chain_file", ret);
6397850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_set_fd_f, SSL_set_fd_pt, xmpp_dl, "SSL_set_fd", ret);
6407850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_free_f, SSL_free_pt, xmpp_dl, "SSL_free", ret);
6417850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_read_f, SSL_read_pt, xmpp_dl, "SSL_read", ret);
6427850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_new_f, SSL_new_pt, xmpp_dl, "SSL_new", ret);
6437850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_get_SSL_CTX_f, SSL_get_SSL_CTX_pt, xmpp_dl,
6447850SVuong.Nguyen@Sun.COM 	    "SSL_get_SSL_CTX", ret);
6457850SVuong.Nguyen@Sun.COM 	FUNCTION_ADD(SSL_CTX_free_f, SSL_CTX_free_pt, xmpp_dl,
6467850SVuong.Nguyen@Sun.COM 	    "SSL_CTX_free", ret);
6477850SVuong.Nguyen@Sun.COM 
6487850SVuong.Nguyen@Sun.COM 	if (ret < 0)
6497850SVuong.Nguyen@Sun.COM 		return (-1);
6507850SVuong.Nguyen@Sun.COM 	else
6517850SVuong.Nguyen@Sun.COM 		return (0);
6527850SVuong.Nguyen@Sun.COM }
6537850SVuong.Nguyen@Sun.COM 
6547850SVuong.Nguyen@Sun.COM /*
6557850SVuong.Nguyen@Sun.COM  * start_tls()
6567850SVuong.Nguyen@Sun.COM  * Description:
6577850SVuong.Nguyen@Sun.COM  *     Load the libssl.so if has not done so and open a ssl connection.
6587850SVuong.Nguyen@Sun.COM  *     It is assumed that there is one xmpp thread to use the ssl connection.
6597850SVuong.Nguyen@Sun.COM  *     If multi-thread xmpp clients use the ssl connection, addtional work is
6607850SVuong.Nguyen@Sun.COM  *     needed to ensure the usage of the ssl be thread-safe.
6617850SVuong.Nguyen@Sun.COM  */
6627850SVuong.Nguyen@Sun.COM static int
start_tls(xmpp_conn_t * conn)6637850SVuong.Nguyen@Sun.COM start_tls(xmpp_conn_t *conn)
6647850SVuong.Nguyen@Sun.COM {
6657850SVuong.Nguyen@Sun.COM 	int		rv, urand_fd;
6667850SVuong.Nguyen@Sun.COM 	SSL_CTX		*ssl_ctx;
6677850SVuong.Nguyen@Sun.COM 	char		rand_buf[RAND_BUF_SIZE];
6687850SVuong.Nguyen@Sun.COM 
6697850SVuong.Nguyen@Sun.COM 	rv = load_SSL_lib();
6707850SVuong.Nguyen@Sun.COM 	if (rv == -1) {
6717850SVuong.Nguyen@Sun.COM 		return (rv);
6727850SVuong.Nguyen@Sun.COM 	}
6737850SVuong.Nguyen@Sun.COM 
6747850SVuong.Nguyen@Sun.COM 	urand_fd = open("/dev/random", O_RDONLY);
6757850SVuong.Nguyen@Sun.COM 	if (urand_fd == -1) {
6767850SVuong.Nguyen@Sun.COM 		return (-1);
6777850SVuong.Nguyen@Sun.COM 	}
6787850SVuong.Nguyen@Sun.COM 	(void) read(urand_fd, rand_buf, RAND_BUF_SIZE);
6797850SVuong.Nguyen@Sun.COM 
6807850SVuong.Nguyen@Sun.COM 	SSL_library_init_f();
6817850SVuong.Nguyen@Sun.COM 	RAND_seed_f(rand_buf, RAND_BUF_SIZE);
6827850SVuong.Nguyen@Sun.COM 
6837850SVuong.Nguyen@Sun.COM 	ssl_ctx = SSL_CTX_new_f(SSLv23_client_method_f());
6847850SVuong.Nguyen@Sun.COM 	if (ssl_ctx == NULL) {
6857850SVuong.Nguyen@Sun.COM 		return (-1);
6867850SVuong.Nguyen@Sun.COM 	}
6877850SVuong.Nguyen@Sun.COM 	conn->ssl = SSL_new_f(ssl_ctx);
6887850SVuong.Nguyen@Sun.COM 	rv = SSL_set_fd_f(conn->ssl, conn->fd);
6897850SVuong.Nguyen@Sun.COM 	if (rv == 0) {
6907850SVuong.Nguyen@Sun.COM 		return (-1);
6917850SVuong.Nguyen@Sun.COM 	}
6927850SVuong.Nguyen@Sun.COM 	rv = SSL_connect_f(conn->ssl);
6937850SVuong.Nguyen@Sun.COM 	if (rv != 1) {
6947850SVuong.Nguyen@Sun.COM 		return (-1);
6957850SVuong.Nguyen@Sun.COM 	}
6967850SVuong.Nguyen@Sun.COM 	conn->tls_started = B_TRUE;
6977850SVuong.Nguyen@Sun.COM 	conn->state = CONN_STATE_TLS;
6987850SVuong.Nguyen@Sun.COM 
6997850SVuong.Nguyen@Sun.COM 	(void) iowrite(conn, STREAM_START, strlen(STREAM_START));
7007850SVuong.Nguyen@Sun.COM 
7017850SVuong.Nguyen@Sun.COM 	return (0);
7027850SVuong.Nguyen@Sun.COM }
7037850SVuong.Nguyen@Sun.COM 
7047850SVuong.Nguyen@Sun.COM /*
7057850SVuong.Nguyen@Sun.COM  * Find and return the first-level subnode (if any) of 'node' which has name
7067850SVuong.Nguyen@Sun.COM  * 'name'.
7077850SVuong.Nguyen@Sun.COM  */
7087850SVuong.Nguyen@Sun.COM xmlNodePtr
xml_find_subnode(xmlNodePtr node,const xmlChar * name)7097850SVuong.Nguyen@Sun.COM xml_find_subnode(xmlNodePtr node, const xmlChar *name)
7107850SVuong.Nguyen@Sun.COM {
7117850SVuong.Nguyen@Sun.COM 	xmlNodePtr subnode;
7127850SVuong.Nguyen@Sun.COM 
7137850SVuong.Nguyen@Sun.COM 	if (node == NULL)
7147850SVuong.Nguyen@Sun.COM 		return (NULL);
7157850SVuong.Nguyen@Sun.COM 
7167850SVuong.Nguyen@Sun.COM 	subnode = node->xmlChildrenNode;
7177850SVuong.Nguyen@Sun.COM 	while (subnode != NULL) {
7187850SVuong.Nguyen@Sun.COM 		if (((char *)subnode->name != NULL) &&
7197850SVuong.Nguyen@Sun.COM 		    (xmlStrcmp(subnode->name, name) == 0))
7207850SVuong.Nguyen@Sun.COM 			break;
7217850SVuong.Nguyen@Sun.COM 		subnode = subnode->next;
7227850SVuong.Nguyen@Sun.COM 	}
7237850SVuong.Nguyen@Sun.COM 
7247850SVuong.Nguyen@Sun.COM 	return (subnode);
7257850SVuong.Nguyen@Sun.COM }
7267850SVuong.Nguyen@Sun.COM 
7277850SVuong.Nguyen@Sun.COM /*
7287850SVuong.Nguyen@Sun.COM  * handle_ldm_resp()
7297850SVuong.Nguyen@Sun.COM  * Description:
7307850SVuong.Nguyen@Sun.COM  *     Parse the ldmd response of the domain event registration for the failure
7317850SVuong.Nguyen@Sun.COM  *     status. If found, set the connection to failure so that it will be
7327850SVuong.Nguyen@Sun.COM  *     closed and a new xmpp connection is established.
7337850SVuong.Nguyen@Sun.COM  */
7347850SVuong.Nguyen@Sun.COM void
handle_ldm_resp(xmpp_conn_t * conn,char * buf,size_t buf_size)7357850SVuong.Nguyen@Sun.COM handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size)
7367850SVuong.Nguyen@Sun.COM {
7377850SVuong.Nguyen@Sun.COM 	xmlDocPtr	xml_output;
7387850SVuong.Nguyen@Sun.COM 	xmlNodePtr	root, resp, status, cmd, action;
7397850SVuong.Nguyen@Sun.COM 	char		*status_str, *action_str;
7407850SVuong.Nguyen@Sun.COM 
7417850SVuong.Nguyen@Sun.COM 	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
7427850SVuong.Nguyen@Sun.COM 		return;
7437850SVuong.Nguyen@Sun.COM 	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
7447850SVuong.Nguyen@Sun.COM 		return;
7457850SVuong.Nguyen@Sun.COM 
7467850SVuong.Nguyen@Sun.COM 	/* get the cmd node */
7477850SVuong.Nguyen@Sun.COM 	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
7487850SVuong.Nguyen@Sun.COM 		return;
7497850SVuong.Nguyen@Sun.COM 	if (strcmp((char *)cmd->name, (char *)XML_CMD) != 0)
7507850SVuong.Nguyen@Sun.COM 		return;
7517850SVuong.Nguyen@Sun.COM 
7527850SVuong.Nguyen@Sun.COM 	/* get the action node and make sure it is the reg-domain-events */
7537850SVuong.Nguyen@Sun.COM 	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
7547850SVuong.Nguyen@Sun.COM 		return;
7557850SVuong.Nguyen@Sun.COM 	}
7567850SVuong.Nguyen@Sun.COM 	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
7577850SVuong.Nguyen@Sun.COM 		return;
7587850SVuong.Nguyen@Sun.COM 	if (strcmp(action_str, XML_REGISTER_ACTION) != 0) {
7597850SVuong.Nguyen@Sun.COM 		xmlFree(action_str);
7607850SVuong.Nguyen@Sun.COM 		return;
7617850SVuong.Nguyen@Sun.COM 	}
7627850SVuong.Nguyen@Sun.COM 	xmlFree(action_str);
7637850SVuong.Nguyen@Sun.COM 
7647850SVuong.Nguyen@Sun.COM 	/* check the status of the response */
7657850SVuong.Nguyen@Sun.COM 	if ((resp = xml_find_subnode(cmd, XML_RESPONSE)) == NULL)
7667850SVuong.Nguyen@Sun.COM 		return;
7677850SVuong.Nguyen@Sun.COM 	if ((status = xml_find_subnode(resp, XML_STATUS)) == NULL)
7687850SVuong.Nguyen@Sun.COM 		return;
7697850SVuong.Nguyen@Sun.COM 	if ((status_str = (char *)xmlNodeGetContent(status)) == NULL)
7707850SVuong.Nguyen@Sun.COM 		return;
7717850SVuong.Nguyen@Sun.COM 	if (strcmp(status_str, (char *)XML_FAILURE) == 0) {
7727850SVuong.Nguyen@Sun.COM 		conn->state = CONN_STATE_FAILURE;
7737850SVuong.Nguyen@Sun.COM 	}
7747850SVuong.Nguyen@Sun.COM 	xmlFree(status_str);
7757850SVuong.Nguyen@Sun.COM }
7767850SVuong.Nguyen@Sun.COM 
7777850SVuong.Nguyen@Sun.COM /*
7787850SVuong.Nguyen@Sun.COM  * handle_ldm_event()
7797850SVuong.Nguyen@Sun.COM  * Description:
7807850SVuong.Nguyen@Sun.COM  *     Parse the LDM_event for the ldom name and domain action. Then invokes
7817850SVuong.Nguyen@Sun.COM  *     the clients's callback to notify them the event.
7827850SVuong.Nguyen@Sun.COM  */
7837850SVuong.Nguyen@Sun.COM /*ARGSUSED*/
7847850SVuong.Nguyen@Sun.COM void
handle_ldm_event(xmpp_conn_t * conn,char * buf,size_t buf_size)7857850SVuong.Nguyen@Sun.COM handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size)
7867850SVuong.Nguyen@Sun.COM {
7877850SVuong.Nguyen@Sun.COM 	int		i;
7887850SVuong.Nguyen@Sun.COM 	xmlDocPtr	xml_output;
7897850SVuong.Nguyen@Sun.COM 	xmlNodePtr	root, cmd, action, data, envelope, content;
7907850SVuong.Nguyen@Sun.COM 	char		*action_str, *ldom_name;
7917850SVuong.Nguyen@Sun.COM 	ldom_event_t	event = LDOM_EVENT_UNKNOWN;
7927850SVuong.Nguyen@Sun.COM 
7937850SVuong.Nguyen@Sun.COM 	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
7947850SVuong.Nguyen@Sun.COM 		return;
7957850SVuong.Nguyen@Sun.COM 	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
7967850SVuong.Nguyen@Sun.COM 		return;
7977850SVuong.Nguyen@Sun.COM 
7987850SVuong.Nguyen@Sun.COM 	/* get the action such as bind-domain, unbind-domain, etc. */
7997850SVuong.Nguyen@Sun.COM 	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
8007850SVuong.Nguyen@Sun.COM 		return;
8017850SVuong.Nguyen@Sun.COM 	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
8027850SVuong.Nguyen@Sun.COM 		return;
8037850SVuong.Nguyen@Sun.COM 	}
8047850SVuong.Nguyen@Sun.COM 	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
8057850SVuong.Nguyen@Sun.COM 		return;
8067850SVuong.Nguyen@Sun.COM 	for (i = 0; i < event_table_size; i++) {
8077850SVuong.Nguyen@Sun.COM 		if (event_table[i].name != NULL &&
8087850SVuong.Nguyen@Sun.COM 		    strcasecmp(event_table[i].name, action_str) == 0) {
8097850SVuong.Nguyen@Sun.COM 			event = event_table[i].id;
8107850SVuong.Nguyen@Sun.COM 			break;
8117850SVuong.Nguyen@Sun.COM 		}
8127850SVuong.Nguyen@Sun.COM 	}
8137850SVuong.Nguyen@Sun.COM 	xmlFree(action_str);
8147850SVuong.Nguyen@Sun.COM 
8157850SVuong.Nguyen@Sun.COM 	/* get the ldom name */
8167850SVuong.Nguyen@Sun.COM 	data = xml_find_subnode(cmd, XML_DATA);
8177850SVuong.Nguyen@Sun.COM 	envelope = xml_find_subnode(data, XML_ENVELOPE);
8187850SVuong.Nguyen@Sun.COM 	content = xml_find_subnode(envelope, XML_CONTENT);
8197850SVuong.Nguyen@Sun.COM 	if ((ldom_name = (char *)xmlGetProp(content, XML_ATTR_ID)) == NULL)
8207850SVuong.Nguyen@Sun.COM 		return;
8217850SVuong.Nguyen@Sun.COM 
8227850SVuong.Nguyen@Sun.COM 	/* Notifies all the clients the event */
8237850SVuong.Nguyen@Sun.COM 	if (VALID_LDOM_EVENT(event)) {
8247850SVuong.Nguyen@Sun.COM 		notify_event(event, ldom_name);
8257850SVuong.Nguyen@Sun.COM 	}
8267850SVuong.Nguyen@Sun.COM 
8277850SVuong.Nguyen@Sun.COM 	xmlFree(ldom_name);
8287850SVuong.Nguyen@Sun.COM }
829