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