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