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