This source file includes following definitions.
- debug_log
- remote_connection_destroy
- init_remote_listener
- check_group_membership
- cib_remote_auth
- remote_auth_timeout_cb
- cib_remote_listen
- cib_remote_connection_destroy
- cib_handle_remote_msg
- cib_remote_msg
- construct_pam_passwd
- authenticate_user
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/crm.h>
12
13 #include <sys/param.h>
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <unistd.h>
18 #include <inttypes.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21
22 #include <netinet/ip.h>
23
24 #include <stdlib.h>
25 #include <errno.h>
26
27 #include <glib.h>
28 #include <libxml/tree.h>
29
30 #include <crm/common/ipc.h>
31 #include <crm/common/ipc_internal.h>
32 #include <crm/common/xml.h>
33 #include <crm/common/remote_internal.h>
34 #include <crm/cib/internal.h>
35
36 #include "pacemaker-based.h"
37
38
39
40
41 #ifdef HAVE_GNUTLS_GNUTLS_H
42 # include <gnutls/gnutls.h>
43 #endif
44
45 #include <pwd.h>
46 #include <grp.h>
47 #if HAVE_SECURITY_PAM_APPL_H
48 # include <security/pam_appl.h>
49 # define HAVE_PAM 1
50 #else
51 # if HAVE_PAM_PAM_APPL_H
52 # include <pam/pam_appl.h>
53 # define HAVE_PAM 1
54 # endif
55 #endif
56
57 extern int remote_tls_fd;
58 extern gboolean cib_shutdown_flag;
59
60 int init_remote_listener(int port, gboolean encrypted);
61 void cib_remote_connection_destroy(gpointer user_data);
62
63 #ifdef HAVE_GNUTLS_GNUTLS_H
64 gnutls_dh_params_t dh_params;
65 gnutls_anon_server_credentials_t anon_cred_s;
66 static void
67 debug_log(int level, const char *str)
68 {
69 fputs(str, stderr);
70 }
71 #endif
72
73
74 #define REMOTE_AUTH_TIMEOUT 10000
75
76 int num_clients;
77 static bool authenticate_user(const char *user, const char *passwd);
78 static int cib_remote_listen(gpointer data);
79 static int cib_remote_msg(gpointer data);
80
81 static void
82 remote_connection_destroy(gpointer user_data)
83 {
84 crm_info("No longer listening for remote connections");
85 return;
86 }
87
88 int
89 init_remote_listener(int port, gboolean encrypted)
90 {
91 int rc;
92 int *ssock = NULL;
93 struct sockaddr_in saddr;
94 int optval;
95
96 static struct mainloop_fd_callbacks remote_listen_fd_callbacks = {
97 .dispatch = cib_remote_listen,
98 .destroy = remote_connection_destroy,
99 };
100
101 if (port <= 0) {
102
103 return 0;
104 }
105
106 if (encrypted) {
107 #ifndef HAVE_GNUTLS_GNUTLS_H
108 crm_warn("TLS support is not available");
109 return 0;
110 #else
111 crm_notice("Starting TLS listener on port %d", port);
112 crm_gnutls_global_init();
113
114 gnutls_global_set_log_function(debug_log);
115 if (pcmk__init_tls_dh(&dh_params) != pcmk_rc_ok) {
116 return -1;
117 }
118 gnutls_anon_allocate_server_credentials(&anon_cred_s);
119 gnutls_anon_set_server_dh_params(anon_cred_s, dh_params);
120 #endif
121 } else {
122 crm_warn("Starting plain-text listener on port %d", port);
123 }
124 #ifndef HAVE_PAM
125 crm_warn("PAM is _not_ enabled!");
126 #endif
127
128
129 ssock = malloc(sizeof(int));
130 if(ssock == NULL) {
131 crm_err("Listener socket allocation failed: %s", pcmk_rc_str(errno));
132 return -1;
133 }
134
135 *ssock = socket(AF_INET, SOCK_STREAM, 0);
136 if (*ssock == -1) {
137 crm_err("Listener socket creation failed: %s", pcmk_rc_str(errno));
138 free(ssock);
139 return -1;
140 }
141
142
143 optval = 1;
144 rc = setsockopt(*ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
145 if (rc < 0) {
146 crm_err("Local address reuse not allowed on listener socket: %s",
147 pcmk_rc_str(errno));
148 }
149
150
151 memset(&saddr, '\0', sizeof(saddr));
152 saddr.sin_family = AF_INET;
153 saddr.sin_addr.s_addr = INADDR_ANY;
154 saddr.sin_port = htons(port);
155 if (bind(*ssock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
156 crm_err("Cannot bind to listener socket: %s", pcmk_rc_str(errno));
157 close(*ssock);
158 free(ssock);
159 return -2;
160 }
161 if (listen(*ssock, 10) == -1) {
162 crm_err("Cannot listen on socket: %s", pcmk_rc_str(errno));
163 close(*ssock);
164 free(ssock);
165 return -3;
166 }
167
168 mainloop_add_fd("cib-remote", G_PRIORITY_DEFAULT, *ssock, ssock, &remote_listen_fd_callbacks);
169 crm_debug("Started listener on port %d", port);
170
171 return *ssock;
172 }
173
174 static int
175 check_group_membership(const char *usr, const char *grp)
176 {
177 int index = 0;
178 struct passwd *pwd = NULL;
179 struct group *group = NULL;
180
181 pwd = getpwnam(usr);
182 if (pwd == NULL) {
183 crm_notice("Rejecting remote client: '%s' is not a valid user", usr);
184 return FALSE;
185 }
186
187 group = getgrgid(pwd->pw_gid);
188 if (group != NULL && pcmk__str_eq(grp, group->gr_name, pcmk__str_none)) {
189 return TRUE;
190 }
191
192 group = getgrnam(grp);
193 if (group == NULL) {
194 crm_err("Rejecting remote client: '%s' is not a valid group", grp);
195 return FALSE;
196 }
197
198 while (TRUE) {
199 char *member = group->gr_mem[index++];
200
201 if (member == NULL) {
202 break;
203
204 } else if (pcmk__str_eq(usr, member, pcmk__str_none)) {
205 return TRUE;
206 }
207 }
208
209 crm_notice("Rejecting remote client: User '%s' is not a member of "
210 "group '%s'", usr, grp);
211 return FALSE;
212 }
213
214 static gboolean
215 cib_remote_auth(xmlNode * login)
216 {
217 const char *user = NULL;
218 const char *pass = NULL;
219 const char *tmp = NULL;
220
221 if (login == NULL) {
222 return FALSE;
223 }
224
225 if (!pcmk__xe_is(login, PCMK__XE_CIB_COMMAND)) {
226 crm_warn("Rejecting remote client: Unrecognizable message "
227 "(element '%s' not '" PCMK__XE_CIB_COMMAND "')", login->name);
228 crm_log_xml_debug(login, "bad");
229 return FALSE;
230 }
231
232 tmp = crm_element_value(login, PCMK_XA_OP);
233 if (!pcmk__str_eq(tmp, "authenticate", pcmk__str_casei)) {
234 crm_warn("Rejecting remote client: Unrecognizable message "
235 "(operation '%s' not 'authenticate')", tmp);
236 crm_log_xml_debug(login, "bad");
237 return FALSE;
238 }
239
240 user = crm_element_value(login, PCMK_XA_USER);
241 pass = crm_element_value(login, PCMK__XA_PASSWORD);
242 if (!user || !pass) {
243 crm_warn("Rejecting remote client: No %s given",
244 ((user == NULL)? "username" : "password"));
245 crm_log_xml_debug(login, "bad");
246 return FALSE;
247 }
248
249 crm_log_xml_debug(login, "auth");
250
251 return check_group_membership(user, CRM_DAEMON_GROUP)
252 && authenticate_user(user, pass);
253 }
254
255 static gboolean
256 remote_auth_timeout_cb(gpointer data)
257 {
258 pcmk__client_t *client = data;
259
260 client->remote->auth_timeout = 0;
261
262 if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
263 return FALSE;
264 }
265
266 mainloop_del_fd(client->remote->source);
267 crm_err("Remote client authentication timed out");
268
269 return FALSE;
270 }
271
272 static int
273 cib_remote_listen(gpointer data)
274 {
275 int csock = 0;
276 unsigned laddr;
277 struct sockaddr_storage addr;
278 char ipstr[INET6_ADDRSTRLEN];
279 int ssock = *(int *)data;
280 int rc;
281
282 pcmk__client_t *new_client = NULL;
283
284 static struct mainloop_fd_callbacks remote_client_fd_callbacks = {
285 .dispatch = cib_remote_msg,
286 .destroy = cib_remote_connection_destroy,
287 };
288
289
290 laddr = sizeof(addr);
291 memset(&addr, 0, sizeof(addr));
292 csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
293 if (csock == -1) {
294 crm_warn("Could not accept remote connection: %s", pcmk_rc_str(errno));
295 return TRUE;
296 }
297
298 pcmk__sockaddr2str(&addr, ipstr);
299
300 rc = pcmk__set_nonblocking(csock);
301 if (rc != pcmk_rc_ok) {
302 crm_warn("Dropping remote connection from %s because "
303 "it could not be set to non-blocking: %s",
304 ipstr, pcmk_rc_str(rc));
305 close(csock);
306 return TRUE;
307 }
308
309 num_clients++;
310
311 new_client = pcmk__new_unauth_client(NULL);
312 new_client->remote = pcmk__assert_alloc(1, sizeof(pcmk__remote_t));
313
314 if (ssock == remote_tls_fd) {
315 #ifdef HAVE_GNUTLS_GNUTLS_H
316 pcmk__set_client_flags(new_client, pcmk__client_tls);
317
318
319 new_client->remote->tls_session = pcmk__new_tls_session(csock,
320 GNUTLS_SERVER,
321 GNUTLS_CRD_ANON,
322 anon_cred_s);
323 if (new_client->remote->tls_session == NULL) {
324 close(csock);
325 return TRUE;
326 }
327 #endif
328 } else {
329 pcmk__set_client_flags(new_client, pcmk__client_tcp);
330 new_client->remote->tcp_socket = csock;
331 }
332
333
334 new_client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
335 remote_auth_timeout_cb,
336 new_client);
337 crm_info("%s connection from %s pending authentication for client %s",
338 ((ssock == remote_tls_fd)? "Encrypted" : "Clear-text"),
339 ipstr, new_client->id);
340
341 new_client->remote->source =
342 mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
343 &remote_client_fd_callbacks);
344
345 return TRUE;
346 }
347
348 void
349 cib_remote_connection_destroy(gpointer user_data)
350 {
351 pcmk__client_t *client = user_data;
352 int csock = 0;
353
354 if (client == NULL) {
355 return;
356 }
357
358 crm_trace("Cleaning up after client %s disconnect",
359 pcmk__client_name(client));
360
361 num_clients--;
362 crm_trace("Num unfree'd clients: %d", num_clients);
363
364 switch (PCMK__CLIENT_TYPE(client)) {
365 case pcmk__client_tcp:
366 csock = client->remote->tcp_socket;
367 break;
368 #ifdef HAVE_GNUTLS_GNUTLS_H
369 case pcmk__client_tls:
370 if (client->remote->tls_session) {
371 void *sock_ptr = gnutls_transport_get_ptr(*client->remote->tls_session);
372
373 csock = GPOINTER_TO_INT(sock_ptr);
374 if (pcmk_is_set(client->flags,
375 pcmk__client_tls_handshake_complete)) {
376 gnutls_bye(*client->remote->tls_session, GNUTLS_SHUT_WR);
377 }
378 gnutls_deinit(*client->remote->tls_session);
379 gnutls_free(client->remote->tls_session);
380 client->remote->tls_session = NULL;
381 }
382 break;
383 #endif
384 default:
385 crm_warn("Unknown transport for client %s "
386 CRM_XS " flags=%#016" PRIx64,
387 pcmk__client_name(client), client->flags);
388 }
389
390 if (csock > 0) {
391 close(csock);
392 }
393
394 pcmk__free_client(client);
395
396 crm_trace("Freed the cib client");
397
398 if (cib_shutdown_flag) {
399 cib_shutdown(0);
400 }
401 return;
402 }
403
404 static void
405 cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command)
406 {
407 if (!pcmk__xe_is(command, PCMK__XE_CIB_COMMAND)) {
408 crm_log_xml_trace(command, "bad");
409 return;
410 }
411
412 if (client->name == NULL) {
413 client->name = pcmk__str_copy(client->id);
414 }
415
416
417 pcmk__xe_remove_attr(command, PCMK__XA_SRC);
418 pcmk__xe_remove_attr(command, PCMK__XA_CIB_HOST);
419 pcmk__xe_remove_attr(command, PCMK__XA_CIB_UPDATE);
420
421 crm_xml_add(command, PCMK__XA_T, PCMK__VALUE_CIB);
422 crm_xml_add(command, PCMK__XA_CIB_CLIENTID, client->id);
423 crm_xml_add(command, PCMK__XA_CIB_CLIENTNAME, client->name);
424 crm_xml_add(command, PCMK__XA_CIB_USER, client->user);
425
426 if (crm_element_value(command, PCMK__XA_CIB_CALLID) == NULL) {
427 char *call_uuid = crm_generate_uuid();
428
429
430 crm_xml_add(command, PCMK__XA_CIB_CALLID, call_uuid);
431 free(call_uuid);
432 }
433
434 if (crm_element_value(command, PCMK__XA_CIB_CALLOPT) == NULL) {
435 crm_xml_add_int(command, PCMK__XA_CIB_CALLOPT, 0);
436 }
437
438 crm_log_xml_trace(command, "Remote command: ");
439 cib_common_callback_worker(0, 0, command, client, TRUE);
440 }
441
442 static int
443 cib_remote_msg(gpointer data)
444 {
445 xmlNode *command = NULL;
446 pcmk__client_t *client = data;
447 int rc;
448 const char *client_name = pcmk__client_name(client);
449
450 crm_trace("Remote %s message received for client %s",
451 pcmk__client_type_str(PCMK__CLIENT_TYPE(client)), client_name);
452
453 #ifdef HAVE_GNUTLS_GNUTLS_H
454 if ((PCMK__CLIENT_TYPE(client) == pcmk__client_tls)
455 && !pcmk_is_set(client->flags, pcmk__client_tls_handshake_complete)) {
456
457 int rc = pcmk__read_handshake_data(client);
458
459 if (rc == EAGAIN) {
460
461
462
463 return 0;
464 } else if (rc != pcmk_rc_ok) {
465 return -1;
466 }
467
468 crm_debug("Completed TLS handshake with remote client %s", client_name);
469 pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
470 if (client->remote->auth_timeout) {
471 g_source_remove(client->remote->auth_timeout);
472 }
473
474
475 client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
476 remote_auth_timeout_cb,
477 client);
478 return 0;
479 }
480 #endif
481
482 rc = pcmk__read_available_remote_data(client->remote);
483 switch (rc) {
484 case pcmk_rc_ok:
485 break;
486
487 case EAGAIN:
488
489 return 0;
490
491 default:
492
493 crm_trace("Error reading from remote client: %s", pcmk_rc_str(rc));
494 return -1;
495 }
496
497
498 if (!pcmk_is_set(client->flags, pcmk__client_authenticated)) {
499 xmlNode *reg;
500 const char *user = NULL;
501
502 command = pcmk__remote_message_xml(client->remote);
503 if (cib_remote_auth(command) == FALSE) {
504 free_xml(command);
505 return -1;
506 }
507
508 pcmk__set_client_flags(client, pcmk__client_authenticated);
509 g_source_remove(client->remote->auth_timeout);
510 client->remote->auth_timeout = 0;
511 client->name = crm_element_value_copy(command, PCMK_XA_NAME);
512
513 user = crm_element_value(command, PCMK_XA_USER);
514 if (user) {
515 client->user = pcmk__str_copy(user);
516 }
517
518 crm_notice("Remote connection accepted for authenticated user %s "
519 CRM_XS " client %s",
520 pcmk__s(user, ""), client_name);
521
522
523 reg = pcmk__xe_create(NULL, PCMK__XE_CIB_RESULT);
524 crm_xml_add(reg, PCMK__XA_CIB_OP, CRM_OP_REGISTER);
525 crm_xml_add(reg, PCMK__XA_CIB_CLIENTID, client->id);
526 pcmk__remote_send_xml(client->remote, reg);
527 free_xml(reg);
528 free_xml(command);
529 }
530
531 command = pcmk__remote_message_xml(client->remote);
532 if (command != NULL) {
533 crm_trace("Remote message received from client %s", client_name);
534 cib_handle_remote_msg(client, command);
535 free_xml(command);
536 }
537
538 return 0;
539 }
540
541 #ifdef HAVE_PAM
542
543
544
545
546
547
548
549
550
551
552
553
554
555 static int
556 construct_pam_passwd(int num_msg, const struct pam_message **msg,
557 struct pam_response **response, void *data)
558 {
559
560
561
562
563 CRM_CHECK((num_msg == 1) && (msg != NULL) && (response != NULL)
564 && (data != NULL), return PAM_CONV_ERR);
565
566 switch (msg[0]->msg_style) {
567 case PAM_PROMPT_ECHO_OFF:
568 case PAM_PROMPT_ECHO_ON:
569
570 break;
571 case PAM_TEXT_INFO:
572 crm_info("PAM: %s", msg[0]->msg);
573 data = NULL;
574 break;
575 case PAM_ERROR_MSG:
576
577
578
579 crm_err("PAM reported an error");
580 data = NULL;
581 break;
582 default:
583 crm_warn("Ignoring PAM message of unrecognized type %d",
584 msg[0]->msg_style);
585 return PAM_CONV_ERR;
586 }
587
588 *response = calloc(1, sizeof(struct pam_response));
589 if (*response == NULL) {
590 return PAM_BUF_ERR;
591 }
592 (*response)->resp_retcode = 0;
593 (*response)->resp = pcmk__str_copy((const char *) data);
594 return PAM_SUCCESS;
595 }
596 #endif
597
598
599
600
601
602
603
604
605
606
607
608
609 static bool
610 authenticate_user(const char *user, const char *passwd)
611 {
612 #ifdef HAVE_PAM
613 int rc = 0;
614 bool pass = false;
615 const void *p_user = NULL;
616 struct pam_conv p_conv;
617 struct pam_handle *pam_h = NULL;
618
619 static const char *pam_name = NULL;
620
621 if (pam_name == NULL) {
622 pam_name = getenv("CIB_pam_service");
623 if (pam_name == NULL) {
624 pam_name = "login";
625 }
626 }
627
628 p_conv.conv = construct_pam_passwd;
629 p_conv.appdata_ptr = (void *) passwd;
630
631 rc = pam_start(pam_name, user, &p_conv, &pam_h);
632 if (rc != PAM_SUCCESS) {
633 crm_warn("Rejecting remote client for user %s "
634 "because PAM initialization failed: %s",
635 user, pam_strerror(pam_h, rc));
636 goto bail;
637 }
638
639
640 rc = pam_authenticate(pam_h, PAM_SILENT);
641 if (rc != PAM_SUCCESS) {
642 crm_notice("Access for remote user %s denied: %s",
643 user, pam_strerror(pam_h, rc));
644 goto bail;
645 }
646
647
648
649
650
651 rc = pam_get_item(pam_h, PAM_USER, &p_user);
652 if (rc != PAM_SUCCESS) {
653 crm_warn("Rejecting remote client for user %s "
654 "because PAM failed to return final user name: %s",
655 user, pam_strerror(pam_h, rc));
656 goto bail;
657 }
658 if (p_user == NULL) {
659 crm_warn("Rejecting remote client for user %s "
660 "because PAM returned no final user name", user);
661 goto bail;
662 }
663
664
665 if (!pcmk__str_eq(p_user, user, pcmk__str_none)) {
666 crm_warn("Rejecting remote client for user %s "
667 "because PAM returned different final user name %s",
668 user, p_user);
669 goto bail;
670 }
671
672
673 rc = pam_acct_mgmt(pam_h, PAM_SILENT);
674 if (rc != PAM_SUCCESS) {
675 crm_notice("Access for remote user %s denied: %s",
676 user, pam_strerror(pam_h, rc));
677 goto bail;
678 }
679 pass = true;
680
681 bail:
682 pam_end(pam_h, rc);
683 return pass;
684 #else
685
686 return true;
687 #endif
688 }