This source file includes following definitions.
- pcmk_new_ipc_api
- free_daemon_specific_data
- pcmk__call_ipc_callback
- ipc_post_disconnect
- pcmk_free_ipc_api
- pcmk_ipc_name
- pcmk_ipc_is_connected
- call_api_dispatch
- dispatch_ipc_data
- dispatch_ipc_source_data
- pcmk_poll_ipc
- pcmk_dispatch_ipc
- connect_with_main_loop
- connect_without_main_loop
- pcmk__connect_ipc
- pcmk_connect_ipc
- pcmk_disconnect_ipc
- pcmk_register_ipc_callback
- pcmk__send_ipc_request
- create_purge_node_request
- pcmk_ipc_purge_node
- crm_ipc_new
- pcmk__connect_generic_ipc
- crm_ipc_connect
- crm_ipc_close
- crm_ipc_destroy
- pcmk__ipc_fd
- crm_ipc_get_fd
- crm_ipc_connected
- crm_ipc_ready
- crm_ipc_decompress
- crm_ipc_read
- crm_ipc_buffer
- crm_ipc_buffer_flags
- crm_ipc_name
- internal_ipc_get_reply
- crm_ipc_send
- is_ipc_provider_expected
- crm_ipc_is_authentic_process
- pcmk__ipc_is_authentic_process_active
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #if defined(HAVE_UCRED) || defined(HAVE_SOCKPEERCRED)
13 # ifdef HAVE_UCRED
14 # ifndef _GNU_SOURCE
15 # define _GNU_SOURCE
16 # endif
17 # endif
18 # include <sys/socket.h>
19 #elif defined(HAVE_GETPEERUCRED)
20 # include <ucred.h>
21 #endif
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <bzlib.h>
27
28 #include <crm/crm.h>
29 #include <crm/common/xml.h>
30 #include <crm/common/ipc.h>
31 #include <crm/common/ipc_internal.h>
32 #include "crmcommon_private.h"
33
34 static int is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
35 uid_t refuid, gid_t refgid, pid_t *gotpid,
36 uid_t *gotuid, gid_t *gotgid);
37
38
39
40
41
42
43
44
45
46
47
48
49
50 int
51 pcmk_new_ipc_api(pcmk_ipc_api_t **api, enum pcmk_ipc_server server)
52 {
53 if (api == NULL) {
54 return EINVAL;
55 }
56
57 *api = calloc(1, sizeof(pcmk_ipc_api_t));
58 if (*api == NULL) {
59 return errno;
60 }
61
62 (*api)->server = server;
63 if (pcmk_ipc_name(*api, false) == NULL) {
64 pcmk_free_ipc_api(*api);
65 *api = NULL;
66 return EOPNOTSUPP;
67 }
68
69 (*api)->ipc_size_max = 0;
70
71
72 switch (server) {
73 case pcmk_ipc_attrd:
74 (*api)->cmds = pcmk__attrd_api_methods();
75 break;
76
77 case pcmk_ipc_based:
78 (*api)->ipc_size_max = 512 * 1024;
79 break;
80
81 case pcmk_ipc_controld:
82 (*api)->cmds = pcmk__controld_api_methods();
83 break;
84
85 case pcmk_ipc_execd:
86 break;
87
88 case pcmk_ipc_fenced:
89 break;
90
91 case pcmk_ipc_pacemakerd:
92 (*api)->cmds = pcmk__pacemakerd_api_methods();
93 break;
94
95 case pcmk_ipc_schedulerd:
96 (*api)->cmds = pcmk__schedulerd_api_methods();
97
98 (*api)->ipc_size_max = 5 * 1024 * 1024;
99 break;
100 }
101 if ((*api)->cmds == NULL) {
102 pcmk_free_ipc_api(*api);
103 *api = NULL;
104 return ENOMEM;
105 }
106
107 (*api)->ipc = crm_ipc_new(pcmk_ipc_name(*api, false),
108 (*api)->ipc_size_max);
109 if ((*api)->ipc == NULL) {
110 pcmk_free_ipc_api(*api);
111 *api = NULL;
112 return ENOMEM;
113 }
114
115
116 if ((*api)->cmds->new_data != NULL) {
117 if ((*api)->cmds->new_data(*api) != pcmk_rc_ok) {
118 pcmk_free_ipc_api(*api);
119 *api = NULL;
120 return ENOMEM;
121 }
122 }
123 crm_trace("Created %s API IPC object", pcmk_ipc_name(*api, true));
124 return pcmk_rc_ok;
125 }
126
127 static void
128 free_daemon_specific_data(pcmk_ipc_api_t *api)
129 {
130 if ((api != NULL) && (api->cmds != NULL)) {
131 if ((api->cmds->free_data != NULL) && (api->api_data != NULL)) {
132 api->cmds->free_data(api->api_data);
133 api->api_data = NULL;
134 }
135 free(api->cmds);
136 api->cmds = NULL;
137 }
138 }
139
140
141
142
143
144
145
146
147
148
149 void
150 pcmk__call_ipc_callback(pcmk_ipc_api_t *api, enum pcmk_ipc_event event_type,
151 crm_exit_t status, void *event_data)
152 {
153 if ((api != NULL) && (api->cb != NULL)) {
154 api->cb(api, event_type, status, event_data, api->user_data);
155 }
156 }
157
158
159
160
161
162
163
164
165
166 static void
167 ipc_post_disconnect(gpointer user_data)
168 {
169 pcmk_ipc_api_t *api = user_data;
170
171 crm_info("Disconnected from %s", pcmk_ipc_name(api, true));
172
173
174 if ((api->cmds != NULL) && (api->cmds->post_disconnect != NULL)) {
175 api->cmds->post_disconnect(api);
176 }
177
178
179 pcmk__call_ipc_callback(api, pcmk_ipc_event_disconnect, CRM_EX_DISCONNECT,
180 NULL);
181
182
183
184
185
186
187 api->ipc = NULL;
188 api->mainloop_io = NULL;
189
190 if (api->free_on_disconnect) {
191
192
193
194 free_daemon_specific_data(api);
195 crm_trace("Freeing IPC API object after disconnect");
196 free(api);
197 }
198 }
199
200
201
202
203
204
205 void
206 pcmk_free_ipc_api(pcmk_ipc_api_t *api)
207 {
208 bool free_on_disconnect = false;
209
210 if (api == NULL) {
211 return;
212 }
213 crm_debug("Releasing %s IPC API", pcmk_ipc_name(api, true));
214
215 if (api->ipc != NULL) {
216 if (api->mainloop_io != NULL) {
217
218
219
220
221
222
223
224
225
226 free_on_disconnect = api->free_on_disconnect = true;
227 }
228 pcmk_disconnect_ipc(api);
229 }
230 if (!free_on_disconnect) {
231 free_daemon_specific_data(api);
232 crm_trace("Freeing IPC API object");
233 free(api);
234 }
235 }
236
237
238
239
240
241
242
243
244
245
246 const char *
247 pcmk_ipc_name(const pcmk_ipc_api_t *api, bool for_log)
248 {
249 if (api == NULL) {
250 return for_log? "Pacemaker" : NULL;
251 }
252 switch (api->server) {
253 case pcmk_ipc_attrd:
254 return for_log? "attribute manager" : PCMK__VALUE_ATTRD;
255
256 case pcmk_ipc_based:
257 return for_log? "CIB manager" : NULL ;
258
259 case pcmk_ipc_controld:
260 return for_log? "controller" : CRM_SYSTEM_CRMD;
261
262 case pcmk_ipc_execd:
263 return for_log? "executor" : NULL ;
264
265 case pcmk_ipc_fenced:
266 return for_log? "fencer" : NULL ;
267
268 case pcmk_ipc_pacemakerd:
269 return for_log? "launcher" : CRM_SYSTEM_MCP;
270
271 case pcmk_ipc_schedulerd:
272 return for_log? "scheduler" : CRM_SYSTEM_PENGINE;
273
274 default:
275 return for_log? "Pacemaker" : NULL;
276 }
277 }
278
279
280
281
282
283
284
285
286 bool
287 pcmk_ipc_is_connected(pcmk_ipc_api_t *api)
288 {
289 return (api != NULL) && crm_ipc_connected(api->ipc);
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303 static bool
304 call_api_dispatch(pcmk_ipc_api_t *api, xmlNode *message)
305 {
306 crm_log_xml_trace(message, "ipc-received");
307 if ((api->cmds != NULL) && (api->cmds->dispatch != NULL)) {
308 return api->cmds->dispatch(api, message);
309 }
310
311 return false;
312 }
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 static int
330 dispatch_ipc_data(const char *buffer, pcmk_ipc_api_t *api)
331 {
332 bool more = false;
333 xmlNode *msg;
334
335 if (buffer == NULL) {
336 crm_warn("Empty message received from %s IPC",
337 pcmk_ipc_name(api, true));
338 return ENOMSG;
339 }
340
341 msg = pcmk__xml_parse(buffer);
342 if (msg == NULL) {
343 crm_warn("Malformed message received from %s IPC",
344 pcmk_ipc_name(api, true));
345 return EPROTO;
346 }
347
348 more = call_api_dispatch(api, msg);
349 free_xml(msg);
350
351 if (more) {
352 return EINPROGRESS;
353 } else {
354 return pcmk_rc_ok;
355 }
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370 static int
371 dispatch_ipc_source_data(const char *buffer, ssize_t length, gpointer user_data)
372 {
373 pcmk_ipc_api_t *api = user_data;
374
375 CRM_CHECK(api != NULL, return 0);
376 dispatch_ipc_data(buffer, api);
377 return 0;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398 int
399 pcmk_poll_ipc(const pcmk_ipc_api_t *api, int timeout_ms)
400 {
401 int rc;
402 struct pollfd pollfd = { 0, };
403
404 if ((api == NULL) || (api->dispatch_type != pcmk_ipc_dispatch_poll)) {
405 return EINVAL;
406 }
407
408 rc = pcmk__ipc_fd(api->ipc, &(pollfd.fd));
409 if (rc != pcmk_rc_ok) {
410 crm_debug("Could not obtain file descriptor for %s IPC: %s",
411 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
412 return rc;
413 }
414
415 pollfd.events = POLLIN;
416 rc = poll(&pollfd, 1, timeout_ms);
417 if (rc < 0) {
418
419
420
421 return (errno == EAGAIN)? ENOMEM : errno;
422 } else if (rc == 0) {
423 return EAGAIN;
424 }
425 return pcmk_rc_ok;
426 }
427
428
429
430
431
432
433
434
435
436
437
438 void
439 pcmk_dispatch_ipc(pcmk_ipc_api_t *api)
440 {
441 if (api == NULL) {
442 return;
443 }
444 while (crm_ipc_ready(api->ipc) > 0) {
445 if (crm_ipc_read(api->ipc) > 0) {
446 dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
447 }
448 }
449 }
450
451
452 static int
453 connect_with_main_loop(pcmk_ipc_api_t *api)
454 {
455 int rc;
456
457 struct ipc_client_callbacks callbacks = {
458 .dispatch = dispatch_ipc_source_data,
459 .destroy = ipc_post_disconnect,
460 };
461
462 rc = pcmk__add_mainloop_ipc(api->ipc, G_PRIORITY_DEFAULT, api,
463 &callbacks, &(api->mainloop_io));
464 if (rc != pcmk_rc_ok) {
465 return rc;
466 }
467 crm_debug("Connected to %s IPC (attached to main loop)",
468 pcmk_ipc_name(api, true));
469
470
471
472 return pcmk_rc_ok;
473 }
474
475
476 static int
477 connect_without_main_loop(pcmk_ipc_api_t *api)
478 {
479 int rc = pcmk__connect_generic_ipc(api->ipc);
480
481 if (rc != pcmk_rc_ok) {
482 crm_ipc_close(api->ipc);
483 } else {
484 crm_debug("Connected to %s IPC (without main loop)",
485 pcmk_ipc_name(api, true));
486 }
487 return rc;
488 }
489
490
491
492
493
494
495
496
497
498
499
500 int
501 pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type,
502 int attempts)
503 {
504 int rc = pcmk_rc_ok;
505
506 if ((api == NULL) || (attempts < 1)) {
507 return EINVAL;
508 }
509
510 if (api->ipc == NULL) {
511 api->ipc = crm_ipc_new(pcmk_ipc_name(api, false), api->ipc_size_max);
512 if (api->ipc == NULL) {
513 return ENOMEM;
514 }
515 }
516
517 if (crm_ipc_connected(api->ipc)) {
518 crm_trace("Already connected to %s", pcmk_ipc_name(api, true));
519 return pcmk_rc_ok;
520 }
521
522 api->dispatch_type = dispatch_type;
523
524 crm_debug("Attempting connection to %s (up to %d time%s)",
525 pcmk_ipc_name(api, true), attempts, pcmk__plural_s(attempts));
526 for (int remaining = attempts - 1; remaining >= 0; --remaining) {
527 switch (dispatch_type) {
528 case pcmk_ipc_dispatch_main:
529 rc = connect_with_main_loop(api);
530 break;
531
532 case pcmk_ipc_dispatch_sync:
533 case pcmk_ipc_dispatch_poll:
534 rc = connect_without_main_loop(api);
535 break;
536 }
537
538 if ((remaining == 0) || ((rc != EAGAIN) && (rc != EALREADY))) {
539 break;
540 }
541
542
543 pcmk__sleep_ms((attempts - remaining) * 500);
544 crm_debug("Re-attempting connection to %s (%d attempt%s remaining)",
545 pcmk_ipc_name(api, true), remaining,
546 pcmk__plural_s(remaining));
547 }
548
549 if (rc != pcmk_rc_ok) {
550 return rc;
551 }
552
553 if ((api->cmds != NULL) && (api->cmds->post_connect != NULL)) {
554 rc = api->cmds->post_connect(api);
555 if (rc != pcmk_rc_ok) {
556 crm_ipc_close(api->ipc);
557 }
558 }
559 return rc;
560 }
561
562
563
564
565
566
567
568
569
570 int
571 pcmk_connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type)
572 {
573 int rc = pcmk__connect_ipc(api, dispatch_type, 2);
574
575 if (rc != pcmk_rc_ok) {
576 crm_err("Connection to %s failed: %s",
577 pcmk_ipc_name(api, true), pcmk_rc_str(rc));
578 }
579 return rc;
580 }
581
582
583
584
585
586
587
588
589
590
591
592
593 void
594 pcmk_disconnect_ipc(pcmk_ipc_api_t *api)
595 {
596 if ((api == NULL) || (api->ipc == NULL)) {
597 return;
598 }
599 switch (api->dispatch_type) {
600 case pcmk_ipc_dispatch_main:
601 {
602 mainloop_io_t *mainloop_io = api->mainloop_io;
603
604
605 api->mainloop_io = NULL;
606 api->ipc = NULL;
607
608 mainloop_del_ipc_client(mainloop_io);
609
610 }
611 break;
612
613 case pcmk_ipc_dispatch_poll:
614 case pcmk_ipc_dispatch_sync:
615 {
616 crm_ipc_t *ipc = api->ipc;
617
618
619 api->ipc = NULL;
620
621
622 api->free_on_disconnect = false;
623
624 crm_ipc_close(ipc);
625 crm_ipc_destroy(ipc);
626 ipc_post_disconnect(api);
627 }
628 break;
629 }
630 }
631
632
633
634
635
636
637
638
639
640
641
642
643
644 void
645 pcmk_register_ipc_callback(pcmk_ipc_api_t *api, pcmk_ipc_callback_t cb,
646 void *user_data)
647 {
648 if (api == NULL) {
649 return;
650 }
651 api->cb = cb;
652 api->user_data = user_data;
653 }
654
655
656
657
658
659
660
661
662
663
664
665
666
667 int
668 pcmk__send_ipc_request(pcmk_ipc_api_t *api, const xmlNode *request)
669 {
670 int rc;
671 xmlNode *reply = NULL;
672 enum crm_ipc_flags flags = crm_ipc_flags_none;
673
674 if ((api == NULL) || (api->ipc == NULL) || (request == NULL)) {
675 return EINVAL;
676 }
677 crm_log_xml_trace(request, "ipc-sent");
678
679
680 if ((api->dispatch_type == pcmk_ipc_dispatch_sync)
681 && (api->cmds != NULL)
682 && (api->cmds->reply_expected != NULL)
683 && (api->cmds->reply_expected(api, request))) {
684 flags = crm_ipc_client_response;
685 }
686
687
688 rc = crm_ipc_send(api->ipc, request, flags, 0, &reply);
689
690 if (rc < 0) {
691 return pcmk_legacy2rc(rc);
692 } else if (rc == 0) {
693 return ENODATA;
694 }
695
696
697 if (reply != NULL) {
698 bool more = call_api_dispatch(api, reply);
699
700 free_xml(reply);
701
702 while (more) {
703 rc = crm_ipc_read(api->ipc);
704
705 if (rc == -EAGAIN) {
706 continue;
707 } else if (rc == -ENOMSG || rc == pcmk_ok) {
708 return pcmk_rc_ok;
709 } else if (rc < 0) {
710 return -rc;
711 }
712
713 rc = dispatch_ipc_data(crm_ipc_buffer(api->ipc), api);
714
715 if (rc == pcmk_rc_ok) {
716 more = false;
717 } else if (rc == EINPROGRESS) {
718 more = true;
719 } else {
720 continue;
721 }
722 }
723 }
724 return pcmk_rc_ok;
725 }
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749 static xmlNode *
750 create_purge_node_request(const pcmk_ipc_api_t *api, const char *node_name,
751 uint32_t nodeid)
752 {
753 xmlNode *request = NULL;
754 const char *client = crm_system_name? crm_system_name : "client";
755
756 switch (api->server) {
757 case pcmk_ipc_attrd:
758 request = pcmk__xe_create(NULL, __func__);
759 crm_xml_add(request, PCMK__XA_T, PCMK__VALUE_ATTRD);
760 crm_xml_add(request, PCMK__XA_SRC, crm_system_name);
761 crm_xml_add(request, PCMK_XA_TASK, PCMK__ATTRD_CMD_PEER_REMOVE);
762 pcmk__xe_set_bool_attr(request, PCMK__XA_REAP, true);
763 pcmk__xe_add_node(request, node_name, nodeid);
764 break;
765
766 case pcmk_ipc_controld:
767 case pcmk_ipc_fenced:
768 case pcmk_ipc_pacemakerd:
769 request = create_request(CRM_OP_RM_NODE_CACHE, NULL, NULL,
770 pcmk_ipc_name(api, false), client, NULL);
771 if (nodeid > 0) {
772 crm_xml_add_ll(request, PCMK_XA_ID, (long long) nodeid);
773 }
774 crm_xml_add(request, PCMK_XA_UNAME, node_name);
775 break;
776
777 case pcmk_ipc_based:
778 case pcmk_ipc_execd:
779 case pcmk_ipc_schedulerd:
780 break;
781 }
782 return request;
783 }
784
785
786
787
788
789
790
791
792
793
794
795
796 int
797 pcmk_ipc_purge_node(pcmk_ipc_api_t *api, const char *node_name, uint32_t nodeid)
798 {
799 int rc = 0;
800 xmlNode *request = NULL;
801
802 if (api == NULL) {
803 return EINVAL;
804 }
805 if ((node_name == NULL) && (nodeid == 0)) {
806 return EINVAL;
807 }
808
809 request = create_purge_node_request(api, node_name, nodeid);
810 if (request == NULL) {
811 return EOPNOTSUPP;
812 }
813 rc = pcmk__send_ipc_request(api, request);
814 free_xml(request);
815
816 crm_debug("%s peer cache purge of node %s[%lu]: rc=%d",
817 pcmk_ipc_name(api, true), node_name, (unsigned long) nodeid, rc);
818 return rc;
819 }
820
821
822
823
824
825 struct crm_ipc_s {
826 struct pollfd pfd;
827 unsigned int max_buf_size;
828 unsigned int buf_size;
829 int msg_size;
830 int need_reply;
831 char *buffer;
832 char *server_name;
833 qb_ipcc_connection_t *ipc;
834 };
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849 crm_ipc_t *
850 crm_ipc_new(const char *name, size_t max_size)
851 {
852 crm_ipc_t *client = NULL;
853
854 client = calloc(1, sizeof(crm_ipc_t));
855 if (client == NULL) {
856 crm_err("Could not create IPC connection: %s", strerror(errno));
857 return NULL;
858 }
859
860 client->server_name = strdup(name);
861 if (client->server_name == NULL) {
862 crm_err("Could not create %s IPC connection: %s",
863 name, strerror(errno));
864 free(client);
865 return NULL;
866 }
867 client->buf_size = pcmk__ipc_buffer_size(max_size);
868 client->buffer = malloc(client->buf_size);
869 if (client->buffer == NULL) {
870 crm_err("Could not create %s IPC connection: %s",
871 name, strerror(errno));
872 free(client->server_name);
873 free(client);
874 return NULL;
875 }
876
877
878 client->max_buf_size = client->buf_size;
879
880 client->pfd.fd = -1;
881 client->pfd.events = POLLIN;
882 client->pfd.revents = 0;
883
884 return client;
885 }
886
887
888
889
890
891
892
893
894
895 int
896 pcmk__connect_generic_ipc(crm_ipc_t *ipc)
897 {
898 uid_t cl_uid = 0;
899 gid_t cl_gid = 0;
900 pid_t found_pid = 0;
901 uid_t found_uid = 0;
902 gid_t found_gid = 0;
903 int rc = pcmk_rc_ok;
904
905 if (ipc == NULL) {
906 return EINVAL;
907 }
908
909 ipc->need_reply = FALSE;
910 ipc->ipc = qb_ipcc_connect(ipc->server_name, ipc->buf_size);
911 if (ipc->ipc == NULL) {
912 return errno;
913 }
914
915 rc = qb_ipcc_fd_get(ipc->ipc, &ipc->pfd.fd);
916 if (rc < 0) {
917 crm_ipc_close(ipc);
918 return -rc;
919 }
920
921 rc = pcmk_daemon_user(&cl_uid, &cl_gid);
922 rc = pcmk_legacy2rc(rc);
923 if (rc != pcmk_rc_ok) {
924 crm_ipc_close(ipc);
925 return rc;
926 }
927
928 rc = is_ipc_provider_expected(ipc->ipc, ipc->pfd.fd, cl_uid, cl_gid,
929 &found_pid, &found_uid, &found_gid);
930 if (rc != pcmk_rc_ok) {
931 if (rc == pcmk_rc_ipc_unauthorized) {
932 crm_info("%s IPC provider authentication failed: process %lld has "
933 "uid %lld (expected %lld) and gid %lld (expected %lld)",
934 ipc->server_name,
935 (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
936 (long long) found_uid, (long long) cl_uid,
937 (long long) found_gid, (long long) cl_gid);
938 }
939 crm_ipc_close(ipc);
940 return rc;
941 }
942
943 ipc->max_buf_size = qb_ipcc_get_buffer_size(ipc->ipc);
944 if (ipc->max_buf_size > ipc->buf_size) {
945 free(ipc->buffer);
946 ipc->buffer = calloc(ipc->max_buf_size, sizeof(char));
947 if (ipc->buffer == NULL) {
948 rc = errno;
949 crm_ipc_close(ipc);
950 return rc;
951 }
952 ipc->buf_size = ipc->max_buf_size;
953 }
954
955 return pcmk_rc_ok;
956 }
957
958
959
960
961
962
963
964
965
966
967 bool
968 crm_ipc_connect(crm_ipc_t *client)
969 {
970 int rc = pcmk__connect_generic_ipc(client);
971
972 if (rc == pcmk_rc_ok) {
973 return true;
974 }
975 if ((client != NULL) && (client->ipc == NULL)) {
976 errno = (rc > 0)? rc : ENOTCONN;
977 crm_debug("Could not establish %s IPC connection: %s (%d)",
978 client->server_name, pcmk_rc_str(errno), errno);
979 } else if (rc == pcmk_rc_ipc_unauthorized) {
980 crm_err("%s IPC provider authentication failed",
981 (client == NULL)? "Pacemaker" : client->server_name);
982 errno = ECONNABORTED;
983 } else {
984 crm_perror(LOG_ERR,
985 "Could not verify authenticity of %s IPC provider",
986 (client == NULL)? "Pacemaker" : client->server_name);
987 errno = ENOTCONN;
988 }
989 return false;
990 }
991
992 void
993 crm_ipc_close(crm_ipc_t * client)
994 {
995 if (client) {
996 if (client->ipc) {
997 qb_ipcc_connection_t *ipc = client->ipc;
998
999 client->ipc = NULL;
1000 qb_ipcc_disconnect(ipc);
1001 }
1002 }
1003 }
1004
1005 void
1006 crm_ipc_destroy(crm_ipc_t * client)
1007 {
1008 if (client) {
1009 if (client->ipc && qb_ipcc_is_connected(client->ipc)) {
1010 crm_notice("Destroying active %s IPC connection",
1011 client->server_name);
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021 } else {
1022 crm_trace("Destroying inactive %s IPC connection",
1023 client->server_name);
1024 }
1025 free(client->buffer);
1026 free(client->server_name);
1027 free(client);
1028 }
1029 }
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040 int
1041 pcmk__ipc_fd(crm_ipc_t *ipc, int *fd)
1042 {
1043 if ((ipc == NULL) || (fd == NULL)) {
1044 return EINVAL;
1045 }
1046 if ((ipc->ipc == NULL) || (ipc->pfd.fd < 0)) {
1047 return ENOTCONN;
1048 }
1049 *fd = ipc->pfd.fd;
1050 return pcmk_rc_ok;
1051 }
1052
1053 int
1054 crm_ipc_get_fd(crm_ipc_t * client)
1055 {
1056 int fd = -1;
1057
1058 if (pcmk__ipc_fd(client, &fd) != pcmk_rc_ok) {
1059 crm_err("Could not obtain file descriptor for %s IPC",
1060 ((client == NULL)? "unspecified" : client->server_name));
1061 errno = EINVAL;
1062 return -EINVAL;
1063 }
1064 return fd;
1065 }
1066
1067 bool
1068 crm_ipc_connected(crm_ipc_t * client)
1069 {
1070 bool rc = FALSE;
1071
1072 if (client == NULL) {
1073 crm_trace("No client");
1074 return FALSE;
1075
1076 } else if (client->ipc == NULL) {
1077 crm_trace("No connection");
1078 return FALSE;
1079
1080 } else if (client->pfd.fd < 0) {
1081 crm_trace("Bad descriptor");
1082 return FALSE;
1083 }
1084
1085 rc = qb_ipcc_is_connected(client->ipc);
1086 if (rc == FALSE) {
1087 client->pfd.fd = -EINVAL;
1088 }
1089 return rc;
1090 }
1091
1092
1093
1094
1095
1096
1097
1098
1099 int
1100 crm_ipc_ready(crm_ipc_t *client)
1101 {
1102 int rc;
1103
1104 pcmk__assert(client != NULL);
1105
1106 if (!crm_ipc_connected(client)) {
1107 return -ENOTCONN;
1108 }
1109
1110 client->pfd.revents = 0;
1111 rc = poll(&(client->pfd), 1, 0);
1112 return (rc < 0)? -errno : rc;
1113 }
1114
1115
1116 static int
1117 crm_ipc_decompress(crm_ipc_t * client)
1118 {
1119 pcmk__ipc_header_t *header = (pcmk__ipc_header_t *)(void*)client->buffer;
1120
1121 if (header->size_compressed) {
1122 int rc = 0;
1123 unsigned int size_u = 1 + header->size_uncompressed;
1124
1125 unsigned int new_buf_size = QB_MAX((sizeof(pcmk__ipc_header_t) + size_u), client->max_buf_size);
1126 char *uncompressed = pcmk__assert_alloc(1, new_buf_size);
1127
1128 crm_trace("Decompressing message data %u bytes into %u bytes",
1129 header->size_compressed, size_u);
1130
1131 rc = BZ2_bzBuffToBuffDecompress(uncompressed + sizeof(pcmk__ipc_header_t), &size_u,
1132 client->buffer + sizeof(pcmk__ipc_header_t), header->size_compressed, 1, 0);
1133 rc = pcmk__bzlib2rc(rc);
1134
1135 if (rc != pcmk_rc_ok) {
1136 crm_err("Decompression failed: %s " CRM_XS " rc=%d",
1137 pcmk_rc_str(rc), rc);
1138 free(uncompressed);
1139 return rc;
1140 }
1141
1142 pcmk__assert(size_u == header->size_uncompressed);
1143
1144 memcpy(uncompressed, client->buffer, sizeof(pcmk__ipc_header_t));
1145 header = (pcmk__ipc_header_t *)(void*)uncompressed;
1146
1147 free(client->buffer);
1148 client->buf_size = new_buf_size;
1149 client->buffer = uncompressed;
1150 }
1151
1152 pcmk__assert(client->buffer[sizeof(pcmk__ipc_header_t)
1153 + header->size_uncompressed - 1] == 0);
1154 return pcmk_rc_ok;
1155 }
1156
1157 long
1158 crm_ipc_read(crm_ipc_t * client)
1159 {
1160 pcmk__ipc_header_t *header = NULL;
1161
1162 pcmk__assert((client != NULL) && (client->ipc != NULL)
1163 && (client->buffer != NULL));
1164
1165 client->buffer[0] = 0;
1166 client->msg_size = qb_ipcc_event_recv(client->ipc, client->buffer,
1167 client->buf_size, 0);
1168 if (client->msg_size >= 0) {
1169 int rc = crm_ipc_decompress(client);
1170
1171 if (rc != pcmk_rc_ok) {
1172 return pcmk_rc2legacy(rc);
1173 }
1174
1175 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1176 if (!pcmk__valid_ipc_header(header)) {
1177 return -EBADMSG;
1178 }
1179
1180 crm_trace("Received %s IPC event %d size=%u rc=%d text='%.100s'",
1181 client->server_name, header->qb.id, header->qb.size,
1182 client->msg_size,
1183 client->buffer + sizeof(pcmk__ipc_header_t));
1184
1185 } else {
1186 crm_trace("No message received from %s IPC: %s",
1187 client->server_name, pcmk_strerror(client->msg_size));
1188
1189 if (client->msg_size == -EAGAIN) {
1190 return -EAGAIN;
1191 }
1192 }
1193
1194 if (!crm_ipc_connected(client) || client->msg_size == -ENOTCONN) {
1195 crm_err("Connection to %s IPC failed", client->server_name);
1196 }
1197
1198 if (header) {
1199
1200 return header->size_uncompressed;
1201 }
1202 return -ENOMSG;
1203 }
1204
1205 const char *
1206 crm_ipc_buffer(crm_ipc_t * client)
1207 {
1208 pcmk__assert(client != NULL);
1209 return client->buffer + sizeof(pcmk__ipc_header_t);
1210 }
1211
1212 uint32_t
1213 crm_ipc_buffer_flags(crm_ipc_t * client)
1214 {
1215 pcmk__ipc_header_t *header = NULL;
1216
1217 pcmk__assert(client != NULL);
1218 if (client->buffer == NULL) {
1219 return 0;
1220 }
1221
1222 header = (pcmk__ipc_header_t *)(void*)client->buffer;
1223 return header->flags;
1224 }
1225
1226 const char *
1227 crm_ipc_name(crm_ipc_t * client)
1228 {
1229 pcmk__assert(client != NULL);
1230 return client->server_name;
1231 }
1232
1233
1234 static int
1235 internal_ipc_get_reply(crm_ipc_t *client, int request_id, int ms_timeout,
1236 ssize_t *bytes)
1237 {
1238 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1239 int rc = pcmk_rc_ok;
1240
1241
1242 crm_trace("Waiting on reply to %s IPC message %d",
1243 client->server_name, request_id);
1244 do {
1245
1246 *bytes = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, 1000);
1247 if (*bytes > 0) {
1248 pcmk__ipc_header_t *hdr = NULL;
1249
1250 rc = crm_ipc_decompress(client);
1251 if (rc != pcmk_rc_ok) {
1252 return rc;
1253 }
1254
1255 hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1256 if (hdr->qb.id == request_id) {
1257
1258 break;
1259 } else if (hdr->qb.id < request_id) {
1260 xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1261
1262 crm_err("Discarding old reply %d (need %d)", hdr->qb.id, request_id);
1263 crm_log_xml_notice(bad, "OldIpcReply");
1264
1265 } else {
1266 xmlNode *bad = pcmk__xml_parse(crm_ipc_buffer(client));
1267
1268 crm_err("Discarding newer reply %d (need %d)", hdr->qb.id, request_id);
1269 crm_log_xml_notice(bad, "ImpossibleReply");
1270 pcmk__assert(hdr->qb.id <= request_id);
1271 }
1272 } else if (!crm_ipc_connected(client)) {
1273 crm_err("%s IPC provider disconnected while waiting for message %d",
1274 client->server_name, request_id);
1275 break;
1276 }
1277
1278 } while (time(NULL) < timeout);
1279
1280 if (*bytes < 0) {
1281 rc = (int) -*bytes;
1282 }
1283 return rc;
1284 }
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299 int
1300 crm_ipc_send(crm_ipc_t *client, const xmlNode *message,
1301 enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply)
1302 {
1303 int rc = 0;
1304 ssize_t qb_rc = 0;
1305 ssize_t bytes = 0;
1306 struct iovec *iov;
1307 static uint32_t id = 0;
1308 static int factor = 8;
1309 pcmk__ipc_header_t *header;
1310
1311 if (client == NULL) {
1312 crm_notice("Can't send IPC request without connection (bug?): %.100s",
1313 message);
1314 return -ENOTCONN;
1315
1316 } else if (!crm_ipc_connected(client)) {
1317
1318 crm_notice("Can't send %s IPC requests: Connection closed",
1319 client->server_name);
1320 return -ENOTCONN;
1321 }
1322
1323 if (ms_timeout == 0) {
1324 ms_timeout = 5000;
1325 }
1326
1327 if (client->need_reply) {
1328 qb_rc = qb_ipcc_recv(client->ipc, client->buffer, client->buf_size, ms_timeout);
1329 if (qb_rc < 0) {
1330 crm_warn("Sending %s IPC disabled until pending reply received",
1331 client->server_name);
1332 return -EALREADY;
1333
1334 } else {
1335 crm_notice("Sending %s IPC re-enabled after pending reply received",
1336 client->server_name);
1337 client->need_reply = FALSE;
1338 }
1339 }
1340
1341 id++;
1342 CRM_LOG_ASSERT(id != 0);
1343 rc = pcmk__ipc_prepare_iov(id, message, client->max_buf_size, &iov, &bytes);
1344 if (rc != pcmk_rc_ok) {
1345 crm_warn("Couldn't prepare %s IPC request: %s " CRM_XS " rc=%d",
1346 client->server_name, pcmk_rc_str(rc), rc);
1347 return pcmk_rc2legacy(rc);
1348 }
1349
1350 header = iov[0].iov_base;
1351 pcmk__set_ipc_flags(header->flags, client->server_name, flags);
1352
1353 if (pcmk_is_set(flags, crm_ipc_proxied)) {
1354
1355 pcmk__clear_ipc_flags(flags, "client", crm_ipc_client_response);
1356 }
1357
1358 if(header->size_compressed) {
1359 if(factor < 10 && (client->max_buf_size / 10) < (bytes / factor)) {
1360 crm_notice("Compressed message exceeds %d0%% of configured IPC "
1361 "limit (%u bytes); consider setting PCMK_ipc_buffer to "
1362 "%u or higher",
1363 factor, client->max_buf_size, 2 * client->max_buf_size);
1364 factor++;
1365 }
1366 }
1367
1368 crm_trace("Sending %s IPC request %d of %u bytes using %dms timeout",
1369 client->server_name, header->qb.id, header->qb.size, ms_timeout);
1370
1371 if ((ms_timeout > 0) || !pcmk_is_set(flags, crm_ipc_client_response)) {
1372
1373 time_t timeout = time(NULL) + 1 + (ms_timeout / 1000);
1374
1375 do {
1376
1377
1378
1379 if (!crm_ipc_connected(client)) {
1380 goto send_cleanup;
1381 }
1382
1383 qb_rc = qb_ipcc_sendv(client->ipc, iov, 2);
1384 } while ((qb_rc == -EAGAIN) && (time(NULL) < timeout));
1385
1386 rc = (int) qb_rc;
1387 if (qb_rc <= 0) {
1388 goto send_cleanup;
1389
1390 } else if (!pcmk_is_set(flags, crm_ipc_client_response)) {
1391 crm_trace("Not waiting for reply to %s IPC request %d",
1392 client->server_name, header->qb.id);
1393 goto send_cleanup;
1394 }
1395
1396 rc = internal_ipc_get_reply(client, header->qb.id, ms_timeout, &bytes);
1397 if (rc != pcmk_rc_ok) {
1398
1399
1400
1401
1402
1403
1404 client->need_reply = TRUE;
1405 }
1406 rc = (int) bytes;
1407
1408 } else {
1409
1410 do {
1411 qb_rc = qb_ipcc_sendv_recv(client->ipc, iov, 2, client->buffer,
1412 client->buf_size, -1);
1413 } while ((qb_rc == -EAGAIN) && crm_ipc_connected(client));
1414 rc = (int) qb_rc;
1415 }
1416
1417 if (rc > 0) {
1418 pcmk__ipc_header_t *hdr = (pcmk__ipc_header_t *)(void*)client->buffer;
1419
1420 crm_trace("Received %d-byte reply %d to %s IPC %d: %.100s",
1421 rc, hdr->qb.id, client->server_name, header->qb.id,
1422 crm_ipc_buffer(client));
1423
1424 if (reply) {
1425 *reply = pcmk__xml_parse(crm_ipc_buffer(client));
1426 }
1427
1428 } else {
1429 crm_trace("No reply to %s IPC %d: rc=%d",
1430 client->server_name, header->qb.id, rc);
1431 }
1432
1433 send_cleanup:
1434 if (!crm_ipc_connected(client)) {
1435 crm_notice("Couldn't send %s IPC request %d: Connection closed "
1436 CRM_XS " rc=%d", client->server_name, header->qb.id, rc);
1437
1438 } else if (rc == -ETIMEDOUT) {
1439 crm_warn("%s IPC request %d failed: %s after %dms " CRM_XS " rc=%d",
1440 client->server_name, header->qb.id, pcmk_strerror(rc),
1441 ms_timeout, rc);
1442 crm_write_blackbox(0, NULL);
1443
1444 } else if (rc <= 0) {
1445 crm_warn("%s IPC request %d failed: %s " CRM_XS " rc=%d",
1446 client->server_name, header->qb.id,
1447 ((rc == 0)? "No bytes sent" : pcmk_strerror(rc)), rc);
1448 }
1449
1450 pcmk_free_ipc_event(iov);
1451 return rc;
1452 }
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471 static int
1472 is_ipc_provider_expected(qb_ipcc_connection_t *qb_ipc, int sock,
1473 uid_t refuid, gid_t refgid,
1474 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1475 {
1476 int rc = EOPNOTSUPP;
1477 pid_t found_pid = 0;
1478 uid_t found_uid = 0;
1479 gid_t found_gid = 0;
1480
1481 #ifdef HAVE_QB_IPCC_AUTH_GET
1482 if (qb_ipc != NULL) {
1483 rc = qb_ipcc_auth_get(qb_ipc, &found_pid, &found_uid, &found_gid);
1484 rc = -rc;
1485 if (rc == pcmk_rc_ok) {
1486 goto found;
1487 }
1488 }
1489 #endif
1490
1491 #ifdef HAVE_UCRED
1492 {
1493 struct ucred ucred;
1494 socklen_t ucred_len = sizeof(ucred);
1495
1496 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &ucred_len) < 0) {
1497 rc = errno;
1498 } else if (ucred_len != sizeof(ucred)) {
1499 rc = EOPNOTSUPP;
1500 } else {
1501 found_pid = ucred.pid;
1502 found_uid = ucred.uid;
1503 found_gid = ucred.gid;
1504 goto found;
1505 }
1506 }
1507 #endif
1508
1509 #ifdef HAVE_SOCKPEERCRED
1510 {
1511 struct sockpeercred sockpeercred;
1512 socklen_t sockpeercred_len = sizeof(sockpeercred);
1513
1514 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED,
1515 &sockpeercred, &sockpeercred_len) < 0) {
1516 rc = errno;
1517 } else if (sockpeercred_len != sizeof(sockpeercred)) {
1518 rc = EOPNOTSUPP;
1519 } else {
1520 found_pid = sockpeercred.pid;
1521 found_uid = sockpeercred.uid;
1522 found_gid = sockpeercred.gid;
1523 goto found;
1524 }
1525 }
1526 #endif
1527
1528 #ifdef HAVE_GETPEEREID
1529 if (getpeereid(sock, &found_uid, &found_gid) < 0) {
1530 rc = errno;
1531 } else {
1532 found_pid = PCMK__SPECIAL_PID;
1533 goto found;
1534 }
1535 #endif
1536
1537 #ifdef HAVE_GETPEERUCRED
1538 {
1539 ucred_t *ucred = NULL;
1540
1541 if (getpeerucred(sock, &ucred) < 0) {
1542 rc = errno;
1543 } else {
1544 found_pid = ucred_getpid(ucred);
1545 found_uid = ucred_geteuid(ucred);
1546 found_gid = ucred_getegid(ucred);
1547 ucred_free(ucred);
1548 goto found;
1549 }
1550 }
1551 #endif
1552
1553 return rc;
1554
1555 found:
1556 if (gotpid != NULL) {
1557 *gotpid = found_pid;
1558 }
1559 if (gotuid != NULL) {
1560 *gotuid = found_uid;
1561 }
1562 if (gotgid != NULL) {
1563 *gotgid = found_gid;
1564 }
1565 if ((found_uid != 0) && (found_uid != refuid) && (found_gid != refgid)) {
1566 return pcmk_rc_ipc_unauthorized;
1567 }
1568 return pcmk_rc_ok;
1569 }
1570
1571 int
1572 crm_ipc_is_authentic_process(int sock, uid_t refuid, gid_t refgid,
1573 pid_t *gotpid, uid_t *gotuid, gid_t *gotgid)
1574 {
1575 int ret = is_ipc_provider_expected(NULL, sock, refuid, refgid,
1576 gotpid, gotuid, gotgid);
1577
1578
1579 if (ret == 0) {
1580 return 1;
1581 } else if (ret == pcmk_rc_ipc_unauthorized) {
1582 return 0;
1583 } else {
1584 return pcmk_rc2legacy(ret);
1585 }
1586 }
1587
1588 int
1589 pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid,
1590 gid_t refgid, pid_t *gotpid)
1591 {
1592 static char last_asked_name[PATH_MAX / 2] = "";
1593 int fd;
1594 int rc = pcmk_rc_ipc_unresponsive;
1595 int auth_rc = 0;
1596 int32_t qb_rc;
1597 pid_t found_pid = 0; uid_t found_uid = 0; gid_t found_gid = 0;
1598 qb_ipcc_connection_t *c;
1599 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1600 struct pollfd pollfd = { 0, };
1601 int poll_rc;
1602
1603 c = qb_ipcc_connect_async(name, 0,
1604 &(pollfd.fd));
1605 #else
1606 c = qb_ipcc_connect(name, 0);
1607 #endif
1608 if (c == NULL) {
1609 crm_info("Could not connect to %s IPC: %s", name, strerror(errno));
1610 rc = pcmk_rc_ipc_unresponsive;
1611 goto bail;
1612 }
1613 #ifdef HAVE_QB_IPCC_CONNECT_ASYNC
1614 pollfd.events = POLLIN;
1615 do {
1616 poll_rc = poll(&pollfd, 1, 2000);
1617 } while ((poll_rc == -1) && (errno == EINTR));
1618
1619
1620
1621
1622
1623
1624 if (qb_ipcc_connect_continue(c) != 0) {
1625 crm_info("Could not connect to %s IPC: %s", name,
1626 (poll_rc == 0)?"timeout":strerror(errno));
1627 rc = pcmk_rc_ipc_unresponsive;
1628 c = NULL;
1629 goto bail;
1630 }
1631 #endif
1632
1633 qb_rc = qb_ipcc_fd_get(c, &fd);
1634 if (qb_rc != 0) {
1635 rc = (int) -qb_rc;
1636 crm_err("Could not get fd from %s IPC: %s " CRM_XS " rc=%d",
1637 name, pcmk_rc_str(rc), rc);
1638 goto bail;
1639 }
1640
1641 auth_rc = is_ipc_provider_expected(c, fd, refuid, refgid,
1642 &found_pid, &found_uid, &found_gid);
1643 if (auth_rc == pcmk_rc_ipc_unauthorized) {
1644 crm_err("Daemon (IPC %s) effectively blocked with unauthorized"
1645 " process %lld (uid: %lld, gid: %lld)",
1646 name, (long long) PCMK__SPECIAL_PID_AS_0(found_pid),
1647 (long long) found_uid, (long long) found_gid);
1648 rc = pcmk_rc_ipc_unauthorized;
1649 goto bail;
1650 }
1651
1652 if (auth_rc != pcmk_rc_ok) {
1653 rc = auth_rc;
1654 crm_err("Could not get peer credentials from %s IPC: %s "
1655 CRM_XS " rc=%d", name, pcmk_rc_str(rc), rc);
1656 goto bail;
1657 }
1658
1659 if (gotpid != NULL) {
1660 *gotpid = found_pid;
1661 }
1662
1663 rc = pcmk_rc_ok;
1664 if ((found_uid != refuid || found_gid != refgid)
1665 && strncmp(last_asked_name, name, sizeof(last_asked_name))) {
1666 if ((found_uid == 0) && (refuid != 0)) {
1667 crm_warn("Daemon (IPC %s) runs as root, whereas the expected"
1668 " credentials are %lld:%lld, hazard of violating"
1669 " the least privilege principle",
1670 name, (long long) refuid, (long long) refgid);
1671 } else {
1672 crm_notice("Daemon (IPC %s) runs as %lld:%lld, whereas the"
1673 " expected credentials are %lld:%lld, which may"
1674 " mean a different set of privileges than expected",
1675 name, (long long) found_uid, (long long) found_gid,
1676 (long long) refuid, (long long) refgid);
1677 }
1678 memccpy(last_asked_name, name, '\0', sizeof(last_asked_name));
1679 }
1680
1681 bail:
1682 if (c != NULL) {
1683 qb_ipcc_disconnect(c);
1684 }
1685 return rc;
1686 }