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