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