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