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 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 222 start_element(void *state, const xmlChar *name, const xmlChar **attrs) 223 { 224 } 225 226 /*ARGSUSED*/ 227 static void 228 error_func(void *state, const char *msg, ...) 229 { 230 } 231 232 static int 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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