This source file includes following definitions.
- cib_remote_inputfd
- cib_remote_set_connection_dnotify
- cib_remote_register_notification
- cib_remote_new
- cib_tls_close
- cib__tls_client_handshake
- cib_tls_signon
- cib_remote_connection_destroy
- cib_remote_command_dispatch
- cib_remote_callback_dispatch
- cib_remote_signon
- cib_remote_signoff
- cib_remote_free
- cib_remote_perform_op
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <string.h>
17 #include <netdb.h>
18 #include <termios.h>
19 #include <sys/socket.h>
20
21 #include <glib.h>
22
23 #include <crm/crm.h>
24 #include <crm/cib/internal.h>
25 #include <crm/msg_xml.h>
26 #include <crm/common/ipc_internal.h>
27 #include <crm/common/mainloop.h>
28 #include <crm/common/remote_internal.h>
29
30 #ifdef HAVE_GNUTLS_GNUTLS_H
31 # undef KEYFILE
32 # include <gnutls/gnutls.h>
33 gnutls_anon_client_credentials_t anon_cred_c;
34
35 # define DEFAULT_CLIENT_HANDSHAKE_TIMEOUT 5000
36
37 const int kx_prio[] = {
38 GNUTLS_KX_ANON_DH,
39 0
40 };
41
42 static gboolean remote_gnutls_credentials_init = FALSE;
43 #else
44 typedef void gnutls_session_t;
45 #endif
46
47 #include <arpa/inet.h>
48 #ifndef ON_BSD
49 # include <sgtty.h>
50 #endif
51
52 #define DH_BITS 1024
53
54 typedef struct cib_remote_opaque_s {
55 int flags;
56 int socket;
57 int port;
58 char *server;
59 char *user;
60 char *passwd;
61 gboolean encrypted;
62 pcmk__remote_t command;
63 pcmk__remote_t callback;
64
65 } cib_remote_opaque_t;
66
67 void cib_remote_connection_destroy(gpointer user_data);
68 int cib_remote_callback_dispatch(gpointer user_data);
69 int cib_remote_command_dispatch(gpointer user_data);
70 int cib_remote_signon(cib_t * cib, const char *name, enum cib_conn_type type);
71 int cib_remote_signoff(cib_t * cib);
72 int cib_remote_free(cib_t * cib);
73
74 int cib_remote_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
75 xmlNode * data, xmlNode ** output_data, int call_options,
76 const char *name);
77
78 static int
79 cib_remote_inputfd(cib_t * cib)
80 {
81 cib_remote_opaque_t *private = cib->variant_opaque;
82
83 return private->callback.tcp_socket;
84 }
85
86 static int
87 cib_remote_set_connection_dnotify(cib_t * cib, void (*dnotify) (gpointer user_data))
88 {
89 return -EPROTONOSUPPORT;
90 }
91
92 static int
93 cib_remote_register_notification(cib_t * cib, const char *callback, int enabled)
94 {
95 xmlNode *notify_msg = create_xml_node(NULL, "cib_command");
96 cib_remote_opaque_t *private = cib->variant_opaque;
97
98 crm_xml_add(notify_msg, F_CIB_OPERATION, T_CIB_NOTIFY);
99 crm_xml_add(notify_msg, F_CIB_NOTIFY_TYPE, callback);
100 crm_xml_add_int(notify_msg, F_CIB_NOTIFY_ACTIVATE, enabled);
101 pcmk__remote_send_xml(&private->callback, notify_msg);
102 free_xml(notify_msg);
103 return pcmk_ok;
104 }
105
106 cib_t *
107 cib_remote_new(const char *server, const char *user, const char *passwd, int port,
108 gboolean encrypted)
109 {
110 cib_remote_opaque_t *private = NULL;
111 cib_t *cib = cib_new_variant();
112
113 private = calloc(1, sizeof(cib_remote_opaque_t));
114
115 cib->variant = cib_remote;
116 cib->variant_opaque = private;
117
118 if (server) {
119 private->server = strdup(server);
120 }
121
122 if (user) {
123 private->user = strdup(user);
124 }
125
126 if (passwd) {
127 private->passwd = strdup(passwd);
128 }
129
130 private->port = port;
131 private->encrypted = encrypted;
132
133
134 cib->delegate_fn = cib_remote_perform_op;
135 cib->cmds->signon = cib_remote_signon;
136 cib->cmds->signoff = cib_remote_signoff;
137 cib->cmds->free = cib_remote_free;
138 cib->cmds->inputfd = cib_remote_inputfd;
139
140 cib->cmds->register_notification = cib_remote_register_notification;
141 cib->cmds->set_connection_dnotify = cib_remote_set_connection_dnotify;
142
143 return cib;
144 }
145
146 static int
147 cib_tls_close(cib_t * cib)
148 {
149 cib_remote_opaque_t *private = cib->variant_opaque;
150
151 #ifdef HAVE_GNUTLS_GNUTLS_H
152 if (private->encrypted) {
153 if (private->command.tls_session) {
154 gnutls_bye(*(private->command.tls_session), GNUTLS_SHUT_RDWR);
155 gnutls_deinit(*(private->command.tls_session));
156 gnutls_free(private->command.tls_session);
157 }
158
159 if (private->callback.tls_session) {
160 gnutls_bye(*(private->callback.tls_session), GNUTLS_SHUT_RDWR);
161 gnutls_deinit(*(private->callback.tls_session));
162 gnutls_free(private->callback.tls_session);
163 }
164 private->command.tls_session = NULL;
165 private->callback.tls_session = NULL;
166 if (remote_gnutls_credentials_init) {
167 gnutls_anon_free_client_credentials(anon_cred_c);
168 gnutls_global_deinit();
169 remote_gnutls_credentials_init = FALSE;
170 }
171 }
172 #endif
173
174 if (private->command.tcp_socket) {
175 shutdown(private->command.tcp_socket, SHUT_RDWR);
176 close(private->command.tcp_socket);
177 }
178 if (private->callback.tcp_socket) {
179 shutdown(private->callback.tcp_socket, SHUT_RDWR);
180 close(private->callback.tcp_socket);
181 }
182 private->command.tcp_socket = 0;
183 private->callback.tcp_socket = 0;
184
185 free(private->command.buffer);
186 free(private->callback.buffer);
187 private->command.buffer = NULL;
188 private->callback.buffer = NULL;
189
190 return 0;
191 }
192
193 static inline int
194 cib__tls_client_handshake(pcmk__remote_t *remote)
195 {
196 #ifdef HAVE_GNUTLS_GNUTLS_H
197 return pcmk__tls_client_handshake(remote, DEFAULT_CLIENT_HANDSHAKE_TIMEOUT);
198 #else
199 return 0;
200 #endif
201 }
202
203 static int
204 cib_tls_signon(cib_t *cib, pcmk__remote_t *connection, gboolean event_channel)
205 {
206 cib_remote_opaque_t *private = cib->variant_opaque;
207 int rc;
208
209 xmlNode *answer = NULL;
210 xmlNode *login = NULL;
211
212 static struct mainloop_fd_callbacks cib_fd_callbacks = { 0, };
213
214 cib_fd_callbacks.dispatch =
215 event_channel ? cib_remote_callback_dispatch : cib_remote_command_dispatch;
216 cib_fd_callbacks.destroy = cib_remote_connection_destroy;
217
218 connection->tcp_socket = -1;
219 #ifdef HAVE_GNUTLS_GNUTLS_H
220 connection->tls_session = NULL;
221 #endif
222 rc = pcmk__connect_remote(private->server, private->port, 0, NULL,
223 &(connection->tcp_socket), NULL, NULL);
224 if (rc != pcmk_rc_ok) {
225 crm_info("Remote connection to %s:%d failed: %s " CRM_XS " rc=%d",
226 private->server, private->port, pcmk_rc_str(rc), rc);
227 return -ENOTCONN;
228 }
229
230 if (private->encrypted) {
231
232 #ifdef HAVE_GNUTLS_GNUTLS_H
233 if (remote_gnutls_credentials_init == FALSE) {
234 crm_gnutls_global_init();
235 gnutls_anon_allocate_client_credentials(&anon_cred_c);
236 remote_gnutls_credentials_init = TRUE;
237 }
238
239
240 connection->tls_session = pcmk__new_tls_session(connection->tcp_socket,
241 GNUTLS_CLIENT,
242 GNUTLS_CRD_ANON,
243 anon_cred_c);
244 if (connection->tls_session == NULL) {
245 cib_tls_close(cib);
246 return -1;
247 }
248
249 if (cib__tls_client_handshake(connection) != pcmk_rc_ok) {
250 crm_err("Session creation for %s:%d failed", private->server, private->port);
251
252 gnutls_deinit(*connection->tls_session);
253 gnutls_free(connection->tls_session);
254 connection->tls_session = NULL;
255 cib_tls_close(cib);
256 return -1;
257 }
258 #else
259 return -EPROTONOSUPPORT;
260 #endif
261 }
262
263
264 login = create_xml_node(NULL, "cib_command");
265 crm_xml_add(login, "op", "authenticate");
266 crm_xml_add(login, "user", private->user);
267 crm_xml_add(login, "password", private->passwd);
268 crm_xml_add(login, "hidden", "password");
269
270 pcmk__remote_send_xml(connection, login);
271 free_xml(login);
272
273 rc = pcmk_ok;
274 if (pcmk__read_remote_message(connection, -1) == ENOTCONN) {
275 rc = -ENOTCONN;
276 }
277
278 answer = pcmk__remote_message_xml(connection);
279
280 crm_log_xml_trace(answer, "Reply");
281 if (answer == NULL) {
282 rc = -EPROTO;
283
284 } else {
285
286 const char *msg_type = crm_element_value(answer, F_CIB_OPERATION);
287 const char *tmp_ticket = crm_element_value(answer, F_CIB_CLIENTID);
288
289 if (!pcmk__str_eq(msg_type, CRM_OP_REGISTER, pcmk__str_casei)) {
290 crm_err("Invalid registration message: %s", msg_type);
291 rc = -EPROTO;
292
293 } else if (tmp_ticket == NULL) {
294 rc = -EPROTO;
295
296 } else {
297 connection->token = strdup(tmp_ticket);
298 }
299 }
300 free_xml(answer);
301 answer = NULL;
302
303 if (rc != 0) {
304 cib_tls_close(cib);
305 return rc;
306 }
307
308 crm_trace("remote client connection established");
309 connection->source = mainloop_add_fd("cib-remote", G_PRIORITY_HIGH,
310 connection->tcp_socket, cib,
311 &cib_fd_callbacks);
312 return rc;
313 }
314
315 void
316 cib_remote_connection_destroy(gpointer user_data)
317 {
318 crm_err("Connection destroyed");
319 #ifdef HAVE_GNUTLS_GNUTLS_H
320 cib_tls_close(user_data);
321 #endif
322 return;
323 }
324
325 int
326 cib_remote_command_dispatch(gpointer user_data)
327 {
328 int rc;
329 cib_t *cib = user_data;
330 cib_remote_opaque_t *private = cib->variant_opaque;
331
332 rc = pcmk__read_remote_message(&private->command, -1);
333
334 free(private->command.buffer);
335 private->command.buffer = NULL;
336 crm_err("received late reply for remote cib connection, discarding");
337
338 if (rc == ENOTCONN) {
339 return -1;
340 }
341 return 0;
342 }
343
344 int
345 cib_remote_callback_dispatch(gpointer user_data)
346 {
347 int rc;
348 cib_t *cib = user_data;
349 cib_remote_opaque_t *private = cib->variant_opaque;
350
351 xmlNode *msg = NULL;
352
353 crm_info("Message on callback channel");
354
355 rc = pcmk__read_remote_message(&private->callback, -1);
356
357 msg = pcmk__remote_message_xml(&private->callback);
358 while (msg) {
359 const char *type = crm_element_value(msg, F_TYPE);
360
361 crm_trace("Activating %s callbacks...", type);
362
363 if (pcmk__str_eq(type, T_CIB, pcmk__str_casei)) {
364 cib_native_callback(cib, msg, 0, 0);
365
366 } else if (pcmk__str_eq(type, T_CIB_NOTIFY, pcmk__str_casei)) {
367 g_list_foreach(cib->notify_list, cib_native_notify, msg);
368
369 } else {
370 crm_err("Unknown message type: %s", type);
371 }
372
373 free_xml(msg);
374 msg = pcmk__remote_message_xml(&private->callback);
375 }
376
377 if (rc == ENOTCONN) {
378 return -1;
379 }
380
381 return 0;
382 }
383
384 int
385 cib_remote_signon(cib_t * cib, const char *name, enum cib_conn_type type)
386 {
387 int rc = pcmk_ok;
388 cib_remote_opaque_t *private = cib->variant_opaque;
389
390 if (private->passwd == NULL) {
391 struct termios settings;
392
393 rc = tcgetattr(0, &settings);
394 if(rc == 0) {
395 settings.c_lflag &= ~ECHO;
396 rc = tcsetattr(0, TCSANOW, &settings);
397 }
398
399 if(rc == 0) {
400 fprintf(stderr, "Password: ");
401 private->passwd = calloc(1, 1024);
402 rc = scanf("%1023s", private->passwd);
403 fprintf(stderr, "\n");
404 }
405
406 if (rc < 1) {
407 private->passwd = NULL;
408 }
409
410 settings.c_lflag |= ECHO;
411 rc = tcsetattr(0, TCSANOW, &settings);
412 }
413
414 if (private->server == NULL || private->user == NULL) {
415 rc = -EINVAL;
416 }
417
418 if (rc == pcmk_ok) {
419 rc = cib_tls_signon(cib, &(private->command), FALSE);
420 }
421
422 if (rc == pcmk_ok) {
423 rc = cib_tls_signon(cib, &(private->callback), TRUE);
424 }
425
426 if (rc == pcmk_ok) {
427 xmlNode *hello =
428 cib_create_op(0, private->callback.token, CRM_OP_REGISTER, NULL, NULL, NULL, 0, NULL);
429 crm_xml_add(hello, F_CIB_CLIENTNAME, name);
430 pcmk__remote_send_xml(&private->command, hello);
431 free_xml(hello);
432 }
433
434 if (rc == pcmk_ok) {
435 crm_info("Opened connection to %s:%d for %s",
436 private->server, private->port, name);
437 cib->state = cib_connected_command;
438 cib->type = cib_command;
439
440 } else {
441 crm_info("Connection to %s:%d for %s failed: %s\n",
442 private->server, private->port, name, pcmk_strerror(rc));
443 }
444
445 return rc;
446 }
447
448 int
449 cib_remote_signoff(cib_t * cib)
450 {
451 int rc = pcmk_ok;
452
453
454
455 crm_debug("Disconnecting from the CIB manager");
456 #ifdef HAVE_GNUTLS_GNUTLS_H
457 cib_tls_close(cib);
458 #endif
459
460 cib->state = cib_disconnected;
461 cib->type = cib_no_connection;
462
463 return rc;
464 }
465
466 int
467 cib_remote_free(cib_t * cib)
468 {
469 int rc = pcmk_ok;
470
471 crm_warn("Freeing CIB");
472 if (cib->state != cib_disconnected) {
473 rc = cib_remote_signoff(cib);
474 if (rc == pcmk_ok) {
475 cib_remote_opaque_t *private = cib->variant_opaque;
476
477 free(private->server);
478 free(private->user);
479 free(private->passwd);
480 free(cib->cmds);
481 free(private);
482 free(cib);
483 }
484 }
485
486 return rc;
487 }
488
489 int
490 cib_remote_perform_op(cib_t * cib, const char *op, const char *host, const char *section,
491 xmlNode * data, xmlNode ** output_data, int call_options, const char *name)
492 {
493 int rc;
494 int remaining_time = 0;
495 time_t start_time;
496
497 xmlNode *op_msg = NULL;
498 xmlNode *op_reply = NULL;
499
500 cib_remote_opaque_t *private = cib->variant_opaque;
501
502 if (cib->state == cib_disconnected) {
503 return -ENOTCONN;
504 }
505
506 if (output_data != NULL) {
507 *output_data = NULL;
508 }
509
510 if (op == NULL) {
511 crm_err("No operation specified");
512 return -EINVAL;
513 }
514
515 cib->call_id++;
516 if (cib->call_id < 1) {
517 cib->call_id = 1;
518 }
519
520 op_msg =
521 cib_create_op(cib->call_id, private->callback.token, op, host, section, data, call_options,
522 NULL);
523 if (op_msg == NULL) {
524 return -EPROTO;
525 }
526
527 crm_trace("Sending %s message to the CIB manager", op);
528 if (!(call_options & cib_sync_call)) {
529 pcmk__remote_send_xml(&private->callback, op_msg);
530 } else {
531 pcmk__remote_send_xml(&private->command, op_msg);
532 }
533 free_xml(op_msg);
534
535 if ((call_options & cib_discard_reply)) {
536 crm_trace("Discarding reply");
537 return pcmk_ok;
538
539 } else if (!(call_options & cib_sync_call)) {
540 return cib->call_id;
541 }
542
543 crm_trace("Waiting for a synchronous reply");
544
545 start_time = time(NULL);
546 remaining_time = cib->call_timeout ? cib->call_timeout : 60;
547
548 rc = pcmk_rc_ok;
549 while (remaining_time > 0 && (rc != ENOTCONN)) {
550 int reply_id = -1;
551 int msg_id = cib->call_id;
552
553 rc = pcmk__read_remote_message(&private->command,
554 remaining_time * 1000);
555 op_reply = pcmk__remote_message_xml(&private->command);
556
557 if (!op_reply) {
558 break;
559 }
560
561 crm_element_value_int(op_reply, F_CIB_CALLID, &reply_id);
562
563 if (reply_id == msg_id) {
564 break;
565
566 } else if (reply_id < msg_id) {
567 crm_debug("Received old reply: %d (wanted %d)", reply_id, msg_id);
568 crm_log_xml_trace(op_reply, "Old reply");
569
570 } else if ((reply_id - 10000) > msg_id) {
571
572 crm_debug("Received old reply: %d (wanted %d)", reply_id, msg_id);
573 crm_log_xml_trace(op_reply, "Old reply");
574 } else {
575 crm_err("Received a __future__ reply:" " %d (wanted %d)", reply_id, msg_id);
576 }
577
578 free_xml(op_reply);
579 op_reply = NULL;
580
581
582 remaining_time = time(NULL) - start_time;
583 }
584
585
586
587
588
589
590
591 if (rc == ENOTCONN) {
592 crm_err("Disconnected while waiting for reply.");
593 return -ENOTCONN;
594 } else if (op_reply == NULL) {
595 crm_err("No reply message - empty");
596 return -ENOMSG;
597 }
598
599 crm_trace("Synchronous reply received");
600
601
602 if (crm_element_value_int(op_reply, F_CIB_RC, &rc) != 0) {
603 rc = -EPROTO;
604 }
605
606 if (rc == -pcmk_err_diff_resync) {
607
608 rc = pcmk_ok;
609 }
610
611 if (rc == pcmk_ok || rc == -EPERM) {
612 crm_log_xml_debug(op_reply, "passed");
613
614 } else {
615
616 crm_err("Call failed: %s", pcmk_strerror(rc));
617 crm_log_xml_warn(op_reply, "failed");
618 }
619
620 if (output_data == NULL) {
621
622
623 } else if (!(call_options & cib_discard_reply)) {
624 xmlNode *tmp = get_message_xml(op_reply, F_CIB_CALLDATA);
625
626 if (tmp == NULL) {
627 crm_trace("No output in reply to \"%s\" command %d", op, cib->call_id - 1);
628 } else {
629 *output_data = copy_xml(tmp);
630 }
631 }
632
633 free_xml(op_reply);
634
635 return rc;
636 }