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