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/msg_xml.h>
31 #include <crm/common/ipc.h>
32 #include <crm/common/ipc_internal.h>
33 #include <crm/common/xml.h>
34 #include <crm/common/remote_internal.h>
35 #include <crm/cib/internal.h>
36
37 #include "pacemaker-based.h"
38
39
40
41
42 #ifdef HAVE_GNUTLS_GNUTLS_H
43 # include <gnutls/gnutls.h>
44 #endif
45
46 #include <pwd.h>
47 #include <grp.h>
48 #if HAVE_SECURITY_PAM_APPL_H
49 # include <security/pam_appl.h>
50 # define HAVE_PAM 1
51 #else
52 # if HAVE_PAM_PAM_APPL_H
53 # include <pam/pam_appl.h>
54 # define HAVE_PAM 1
55 # endif
56 #endif
57
58 extern int remote_tls_fd;
59 extern gboolean cib_shutdown_flag;
60
61 int init_remote_listener(int port, gboolean encrypted);
62 void cib_remote_connection_destroy(gpointer user_data);
63
64 #ifdef HAVE_GNUTLS_GNUTLS_H
65 gnutls_dh_params_t dh_params;
66 gnutls_anon_server_credentials_t anon_cred_s;
67 static void
68 debug_log(int level, const char *str)
69 {
70 fputs(str, stderr);
71 }
72 #endif
73
74 #define REMOTE_AUTH_TIMEOUT 10000
75
76 int num_clients;
77 int 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 CRM_CHECK(usr != NULL, return FALSE);
182 CRM_CHECK(grp != NULL, return FALSE);
183
184 pwd = getpwnam(usr);
185 if (pwd == NULL) {
186 crm_err("No user named '%s' exists!", usr);
187 return FALSE;
188 }
189
190 group = getgrgid(pwd->pw_gid);
191 if (group != NULL && pcmk__str_eq(grp, group->gr_name, pcmk__str_none)) {
192 return TRUE;
193 }
194
195 group = getgrnam(grp);
196 if (group == NULL) {
197 crm_err("No group named '%s' exists!", grp);
198 return FALSE;
199 }
200
201 while (TRUE) {
202 char *member = group->gr_mem[index++];
203
204 if (member == NULL) {
205 break;
206
207 } else if (pcmk__str_eq(usr, member, pcmk__str_none)) {
208 return TRUE;
209 }
210 };
211
212 return FALSE;
213 }
214
215 static gboolean
216 cib_remote_auth(xmlNode * login)
217 {
218 const char *user = NULL;
219 const char *pass = NULL;
220 const char *tmp = NULL;
221
222 crm_log_xml_info(login, "Login: ");
223 if (login == NULL) {
224 return FALSE;
225 }
226
227 if (!pcmk__xe_is(login, T_CIB_COMMAND)) {
228 crm_err("Unrecognizable message from remote client");
229 crm_log_xml_info(login, "bad");
230 return FALSE;
231 }
232
233 tmp = crm_element_value(login, "op");
234 if (!pcmk__str_eq(tmp, "authenticate", pcmk__str_casei)) {
235 crm_err("Wrong operation: %s", tmp);
236 return FALSE;
237 }
238
239 user = crm_element_value(login, "user");
240 pass = crm_element_value(login, "password");
241
242 if (!user || !pass) {
243 crm_err("missing auth credentials");
244 return FALSE;
245 }
246
247
248
249
250 if (check_group_membership(user, CRM_DAEMON_GROUP) == FALSE) {
251 crm_err("User is not a member of the required group");
252 return FALSE;
253
254 } else if (authenticate_user(user, pass) == FALSE) {
255 crm_err("PAM auth failed");
256 return FALSE;
257 }
258
259 return TRUE;
260 }
261
262 static gboolean
263 remote_auth_timeout_cb(gpointer data)
264 {
265 pcmk__client_t *client = data;
266
267 client->remote->auth_timeout = 0;
268
269 if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
270 return FALSE;
271 }
272
273 mainloop_del_fd(client->remote->source);
274 crm_err("Remote client authentication timed out");
275
276 return FALSE;
277 }
278
279 static int
280 cib_remote_listen(gpointer data)
281 {
282 int csock = 0;
283 unsigned laddr;
284 struct sockaddr_storage addr;
285 char ipstr[INET6_ADDRSTRLEN];
286 int ssock = *(int *)data;
287 int rc;
288
289 pcmk__client_t *new_client = NULL;
290
291 static struct mainloop_fd_callbacks remote_client_fd_callbacks = {
292 .dispatch = cib_remote_msg,
293 .destroy = cib_remote_connection_destroy,
294 };
295
296
297 laddr = sizeof(addr);
298 memset(&addr, 0, sizeof(addr));
299 csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
300 if (csock == -1) {
301 crm_err("Could not accept socket connection: %s", pcmk_rc_str(errno));
302 return TRUE;
303 }
304
305 pcmk__sockaddr2str(&addr, ipstr);
306 crm_debug("New %s connection from %s",
307 ((ssock == remote_tls_fd)? "secure" : "clear-text"), ipstr);
308
309 rc = pcmk__set_nonblocking(csock);
310 if (rc != pcmk_rc_ok) {
311 crm_err("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
312 pcmk_rc_str(rc), rc);
313 close(csock);
314 return TRUE;
315 }
316
317 num_clients++;
318
319 new_client = pcmk__new_unauth_client(NULL);
320 new_client->remote = calloc(1, sizeof(pcmk__remote_t));
321
322 if (ssock == remote_tls_fd) {
323 #ifdef HAVE_GNUTLS_GNUTLS_H
324 pcmk__set_client_flags(new_client, pcmk__client_tls);
325
326
327 new_client->remote->tls_session = pcmk__new_tls_session(csock,
328 GNUTLS_SERVER,
329 GNUTLS_CRD_ANON,
330 anon_cred_s);
331 if (new_client->remote->tls_session == NULL) {
332 close(csock);
333 return TRUE;
334 }
335 #endif
336 } else {
337 pcmk__set_client_flags(new_client, pcmk__client_tcp);
338 new_client->remote->tcp_socket = csock;
339 }
340
341
342 new_client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
343 remote_auth_timeout_cb,
344 new_client);
345 crm_info("Remote CIB client pending authentication "
346 CRM_XS " %p id: %s", new_client, new_client->id);
347
348 new_client->remote->source =
349 mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
350 &remote_client_fd_callbacks);
351
352 return TRUE;
353 }
354
355 void
356 cib_remote_connection_destroy(gpointer user_data)
357 {
358 pcmk__client_t *client = user_data;
359 int csock = 0;
360
361 if (client == NULL) {
362 return;
363 }
364
365 crm_trace("Cleaning up after client %s disconnect",
366 pcmk__client_name(client));
367
368 num_clients--;
369 crm_trace("Num unfree'd clients: %d", num_clients);
370
371 switch (PCMK__CLIENT_TYPE(client)) {
372 case pcmk__client_tcp:
373 csock = client->remote->tcp_socket;
374 break;
375 #ifdef HAVE_GNUTLS_GNUTLS_H
376 case pcmk__client_tls:
377 if (client->remote->tls_session) {
378 void *sock_ptr = gnutls_transport_get_ptr(*client->remote->tls_session);
379
380 csock = GPOINTER_TO_INT(sock_ptr);
381 if (pcmk_is_set(client->flags,
382 pcmk__client_tls_handshake_complete)) {
383 gnutls_bye(*client->remote->tls_session, GNUTLS_SHUT_WR);
384 }
385 gnutls_deinit(*client->remote->tls_session);
386 gnutls_free(client->remote->tls_session);
387 client->remote->tls_session = NULL;
388 }
389 break;
390 #endif
391 default:
392 crm_warn("Unknown transport for client %s "
393 CRM_XS " flags=%#016" PRIx64,
394 pcmk__client_name(client), client->flags);
395 }
396
397 if (csock > 0) {
398 close(csock);
399 }
400
401 pcmk__free_client(client);
402
403 crm_trace("Freed the cib client");
404
405 if (cib_shutdown_flag) {
406 cib_shutdown(0);
407 }
408 return;
409 }
410
411 static void
412 cib_handle_remote_msg(pcmk__client_t *client, xmlNode *command)
413 {
414 const char *value = NULL;
415
416 if (!pcmk__xe_is(command, T_CIB_COMMAND)) {
417 crm_log_xml_trace(command, "bad");
418 return;
419 }
420
421 if (client->name == NULL) {
422 value = crm_element_value(command, F_CLIENTNAME);
423 if (value == NULL) {
424 client->name = strdup(client->id);
425 } else {
426 client->name = strdup(value);
427 }
428 }
429
430
431 xml_remove_prop(command, F_ORIG);
432 xml_remove_prop(command, F_CIB_HOST);
433 xml_remove_prop(command, F_CIB_GLOBAL_UPDATE);
434
435 crm_xml_add(command, F_TYPE, T_CIB);
436 crm_xml_add(command, F_CIB_CLIENTID, client->id);
437 crm_xml_add(command, F_CIB_CLIENTNAME, client->name);
438 crm_xml_add(command, F_CIB_USER, client->user);
439
440 if (crm_element_value(command, F_CIB_CALLID) == NULL) {
441 char *call_uuid = crm_generate_uuid();
442
443
444 crm_xml_add(command, F_CIB_CALLID, call_uuid);
445 free(call_uuid);
446 }
447
448 if (crm_element_value(command, F_CIB_CALLOPTS) == NULL) {
449 crm_xml_add_int(command, F_CIB_CALLOPTS, 0);
450 }
451
452 crm_log_xml_trace(command, "Remote command: ");
453 cib_common_callback_worker(0, 0, command, client, TRUE);
454 }
455
456 static int
457 cib_remote_msg(gpointer data)
458 {
459 xmlNode *command = NULL;
460 pcmk__client_t *client = data;
461 int rc;
462 int timeout = 1000;
463
464 if (pcmk_is_set(client->flags, pcmk__client_authenticated)) {
465 timeout = -1;
466 }
467
468 crm_trace("Remote %s message received for client %s",
469 pcmk__client_type_str(PCMK__CLIENT_TYPE(client)),
470 pcmk__client_name(client));
471
472 #ifdef HAVE_GNUTLS_GNUTLS_H
473 if ((PCMK__CLIENT_TYPE(client) == pcmk__client_tls)
474 && !pcmk_is_set(client->flags, pcmk__client_tls_handshake_complete)) {
475
476 int rc = pcmk__read_handshake_data(client);
477
478 if (rc == EAGAIN) {
479
480
481
482 return 0;
483 } else if (rc != pcmk_rc_ok) {
484 return -1;
485 }
486
487 crm_debug("TLS handshake with remote CIB client completed");
488 pcmk__set_client_flags(client, pcmk__client_tls_handshake_complete);
489 if (client->remote->auth_timeout) {
490 g_source_remove(client->remote->auth_timeout);
491 }
492
493
494 client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
495 remote_auth_timeout_cb,
496 client);
497 return 0;
498 }
499 #endif
500
501 rc = pcmk__read_remote_message(client->remote, timeout);
502
503
504 if (!pcmk_is_set(client->flags, pcmk__client_authenticated)) {
505 xmlNode *reg;
506 const char *user = NULL;
507
508 command = pcmk__remote_message_xml(client->remote);
509 if (cib_remote_auth(command) == FALSE) {
510 free_xml(command);
511 return -1;
512 }
513
514 crm_notice("Remote CIB client connection accepted");
515 pcmk__set_client_flags(client, pcmk__client_authenticated);
516 g_source_remove(client->remote->auth_timeout);
517 client->remote->auth_timeout = 0;
518 client->name = crm_element_value_copy(command, "name");
519
520 user = crm_element_value(command, "user");
521 if (user) {
522 client->user = strdup(user);
523 }
524
525
526 reg = create_xml_node(NULL, "cib_result");
527 crm_xml_add(reg, F_CIB_OPERATION, CRM_OP_REGISTER);
528 crm_xml_add(reg, F_CIB_CLIENTID, client->id);
529 pcmk__remote_send_xml(client->remote, reg);
530 free_xml(reg);
531 free_xml(command);
532 }
533
534 command = pcmk__remote_message_xml(client->remote);
535 while (command) {
536 crm_trace("Remote client message received");
537 cib_handle_remote_msg(client, command);
538 free_xml(command);
539 command = pcmk__remote_message_xml(client->remote);
540 }
541
542 if (rc == ENOTCONN) {
543 crm_trace("Remote CIB client disconnected while reading from it");
544 return -1;
545 }
546
547 return 0;
548 }
549
550 #ifdef HAVE_PAM
551 static int
552 construct_pam_passwd(int num_msg, const struct pam_message **msg,
553 struct pam_response **response, void *data)
554 {
555 int count = 0;
556 struct pam_response *reply;
557 char *string = (char *)data;
558
559 CRM_CHECK(data, return PAM_CONV_ERR);
560 CRM_CHECK(num_msg == 1, return PAM_CONV_ERR);
561
562 reply = calloc(1, sizeof(struct pam_response));
563 CRM_ASSERT(reply != NULL);
564
565 for (count = 0; count < num_msg; ++count) {
566 switch (msg[count]->msg_style) {
567 case PAM_TEXT_INFO:
568 crm_info("PAM: %s", msg[count]->msg);
569 break;
570 case PAM_PROMPT_ECHO_OFF:
571 case PAM_PROMPT_ECHO_ON:
572 reply[count].resp_retcode = 0;
573 reply[count].resp = string;
574 break;
575 case PAM_ERROR_MSG:
576
577
578
579
580 break;
581 default:
582 crm_err("Unhandled conversation type: %d", msg[count]->msg_style);
583 goto bail;
584 }
585 }
586
587 *response = reply;
588 reply = NULL;
589
590 return PAM_SUCCESS;
591
592 bail:
593 for (count = 0; count < num_msg; ++count) {
594 if (reply[count].resp != NULL) {
595 switch (msg[count]->msg_style) {
596 case PAM_PROMPT_ECHO_ON:
597 case PAM_PROMPT_ECHO_OFF:
598
599 while (*(reply[count].resp)) {
600 *(reply[count].resp)++ = '\0';
601 }
602 free(reply[count].resp);
603 break;
604 }
605 reply[count].resp = NULL;
606 }
607 }
608 free(reply);
609 reply = NULL;
610
611 return PAM_CONV_ERR;
612 }
613 #endif
614
615 int
616 authenticate_user(const char *user, const char *passwd)
617 {
618 #ifndef HAVE_PAM
619 gboolean pass = TRUE;
620 #else
621 int rc = 0;
622 gboolean pass = FALSE;
623 const void *p_user = NULL;
624
625 struct pam_conv p_conv;
626 struct pam_handle *pam_h = NULL;
627 static const char *pam_name = NULL;
628
629 if (pam_name == NULL) {
630 pam_name = getenv("CIB_pam_service");
631 }
632 if (pam_name == NULL) {
633 pam_name = "login";
634 }
635
636 p_conv.conv = construct_pam_passwd;
637 p_conv.appdata_ptr = strdup(passwd);
638
639 rc = pam_start(pam_name, user, &p_conv, &pam_h);
640 if (rc != PAM_SUCCESS) {
641 crm_err("Could not initialize PAM: %s (%d)", pam_strerror(pam_h, rc), rc);
642 goto bail;
643 }
644
645 rc = pam_authenticate(pam_h, 0);
646 if (rc != PAM_SUCCESS) {
647 crm_err("Authentication failed for %s: %s (%d)", user, pam_strerror(pam_h, rc), rc);
648 goto bail;
649 }
650
651
652
653
654
655
656 rc = pam_get_item(pam_h, PAM_USER, &p_user);
657 if (rc != PAM_SUCCESS) {
658 crm_err("Internal PAM error: %s (%d)", pam_strerror(pam_h, rc), rc);
659 goto bail;
660
661 } else if (p_user == NULL) {
662 crm_err("Unknown user authenticated.");
663 goto bail;
664
665 } else if (!pcmk__str_eq(p_user, user, pcmk__str_casei)) {
666 crm_err("User mismatch: %s vs. %s.", (const char *)p_user, (const char *)user);
667 goto bail;
668 }
669
670 rc = pam_acct_mgmt(pam_h, 0);
671 if (rc != PAM_SUCCESS) {
672 crm_err("Access denied: %s (%d)", pam_strerror(pam_h, rc), rc);
673 goto bail;
674 }
675 pass = TRUE;
676
677 bail:
678 pam_end(pam_h, rc);
679 #endif
680 return pass;
681 }