diff --git a/crm/cib/remote.c b/crm/cib/remote.c index 2b529b8245..ba9b2476eb 100644 --- a/crm/cib/remote.c +++ b/crm/cib/remote.c @@ -1,462 +1,574 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "callbacks.h" +/* #undef HAVE_PAM_PAM_APPL_H */ +/* #undef HAVE_GNUTLS_GNUTLS_H */ -#undef KEYFILE -#include +#ifdef HAVE_GNUTLS_GNUTLS_H +# undef KEYFILE +# include +#endif #include #include -# include #if HAVE_SECURITY_PAM_APPL_H # include +# define HAVE_PAM 1 #else # if HAVE_PAM_PAM_APPL_H # include +# define HAVE_PAM 1 # endif #endif -extern int num_clients; +int init_remote_listener(int port); +char *cib_recv_remote_msg(void *session); +void cib_send_remote_msg(void *session, HA_Message *msg); + -#define DH_BITS 1024 +#ifdef HAVE_GNUTLS_GNUTLS_H +# define DH_BITS 1024 +const int tls_kx_order[] = { + GNUTLS_KX_ANON_DH, + GNUTLS_KX_DHE_RSA, + GNUTLS_KX_DHE_DSS, + GNUTLS_KX_RSA, + 0 +}; gnutls_dh_params dh_params; gnutls_anon_server_credentials anon_cred; +char *cib_send_tls(gnutls_session_t *session, HA_Message *msg); +char *cib_recv_tls(gnutls_session_t *session); +#endif -int init_remote_listener(int port); -char *cib_recv_tls_string(gnutls_session_t *session); +extern int num_clients; int authenticate_user(const char* user, const char* passwd); gboolean cib_remote_listen(int ssock, gpointer data); gboolean cib_remote_msg(int csock, gpointer data); -char *cib_send_tls_msg(gnutls_session_t *session, HA_Message *msg); -extern struct IPC_CHANNEL* socket_server_channel_new(int sockfd); +char *cib_send_plaintext(int sock, HA_Message *msg); +char *cib_recv_plaintext(int sock); + extern void cib_process_request( HA_Message *request, gboolean privileged, gboolean force_synchronous, gboolean from_peer, cib_client_t *cib_client); +#ifdef HAVE_GNUTLS_GNUTLS_H static void debug_log(int level, const char *str) { fputs (str, stderr); } +static gnutls_session * +create_tls_session(int csock) +{ + int rc = 0; + gnutls_session *session; + session = (gnutls_session*)gnutls_malloc(sizeof(gnutls_session)); + + gnutls_init(session, GNUTLS_SERVER); + gnutls_set_default_priority(*session); + gnutls_kx_set_priority (*session, tls_kx_order); + gnutls_credentials_set(*session, GNUTLS_CRD_ANON, anon_cred); + gnutls_transport_set_ptr(*session, + (gnutls_transport_ptr) GINT_TO_POINTER(csock)); + do { + rc = gnutls_handshake (*session); + } while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); + + if (rc < 0) { + crm_err("Handshake failed: %s", gnutls_strerror(rc)); + gnutls_deinit(*session); + gnutls_free(session); + return NULL; + } + return session; +} + +char* +cib_send_tls(gnutls_session_t *session, HA_Message *msg) +{ + char *xml_text = NULL; + ha_msg_mod(msg, F_XML_TAGNAME, "cib_result"); + crm_log_xml(LOG_DEBUG_2, "Result: ", msg); + xml_text = dump_xml_unformatted(msg); + if(xml_text != NULL) { + int len = strlen(xml_text); + len++; /* null char */ + crm_debug_3("Message size: %d", len); + gnutls_record_send (*session, xml_text, len); + } + crm_free(xml_text); + return NULL; + +} + +char* +cib_recv_tls(gnutls_session_t *session) +{ + int len = 0; + char* buf = NULL; + int chunk_size = 512; + + if (session == NULL) { + return NULL; + } + + crm_malloc0(buf, chunk_size); + + while(1) { + int rc = gnutls_record_recv(*session, buf+len, chunk_size); + if (rc == 0) { + if(len == 0) { + goto bail; + } + return buf; + + } else if(rc > 0 && rc < chunk_size) { + return buf; + + } else if(rc == chunk_size) { + len += chunk_size; + crm_realloc(buf, len); + CRM_ASSERT(buf != NULL); + } + + if(rc < 0 + && rc != GNUTLS_E_INTERRUPTED + && rc != GNUTLS_E_AGAIN) { + cl_perror("Error receiving message: %d", rc); + goto bail; + } + } + bail: + crm_free(buf); + return NULL; + +} +#endif + int init_remote_listener(int port) { int ssock; struct sockaddr_in saddr; int optval; if(port < 0) { /* dont start it */ return 0; } +#ifdef HAVE_GNUTLS_GNUTLS_H /* init pam & gnutls lib */ gnutls_global_init(); /* gnutls_global_set_log_level (10); */ gnutls_global_set_log_function (debug_log); gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, DH_BITS); gnutls_anon_allocate_server_credentials (&anon_cred); gnutls_anon_set_server_dh_params (anon_cred, dh_params); +#endif /* create server socket */ ssock = socket(AF_INET, SOCK_STREAM, 0); if (ssock == -1) { crm_err("Can not create server socket. Shutting down."); return -1; } /* reuse address */ optval = 1; setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); /* bind server socket*/ memset(&saddr, '\0', sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_port = htons(port); if (bind(ssock, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) { crm_err("Can not bind server socket. Shutting down."); return -2; } if (listen(ssock, 10) == -1) { crm_err("Can not start listen. Shutting down."); return -3; } G_main_add_fd(G_PRIORITY_HIGH, ssock, FALSE, cib_remote_listen, NULL, default_ipc_connection_destroy); return 0; } -const int tls_kx_order[] = { - GNUTLS_KX_ANON_DH, - GNUTLS_KX_DHE_RSA, - GNUTLS_KX_DHE_DSS, - GNUTLS_KX_RSA, - 0 -}; - -static gnutls_session * -create_tls_session(int csock) -{ - int rc = 0; - gnutls_session *session; - session = (gnutls_session*)gnutls_malloc(sizeof(gnutls_session)); - - gnutls_init(session, GNUTLS_SERVER); - gnutls_set_default_priority(*session); - gnutls_kx_set_priority (*session, tls_kx_order); - gnutls_credentials_set(*session, GNUTLS_CRD_ANON, anon_cred); - gnutls_transport_set_ptr(*session, - (gnutls_transport_ptr) GINT_TO_POINTER(csock)); - do { - rc = gnutls_handshake (*session); - } while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); - - if (rc < 0) { - crm_err("Handshake failed: %s", gnutls_strerror(rc)); - gnutls_deinit(*session); - gnutls_free(session); - return NULL; - } - return session; -} - -#define WELCOME "hello there from gnutls\r\n" static int check_group_membership(const char* usr, const char* grp) { int index = 0; struct group *group = NULL; CRM_CHECK(usr != NULL, return FALSE); CRM_CHECK(grp != NULL, return FALSE); group = getgrnam(grp); if (group == NULL) { crm_err("No group named '%s' exists!", grp); return FALSE; } while (TRUE) { char* member = group->gr_mem[index++]; if(member == NULL) { break; } else if (crm_str_eq(usr, member, TRUE)) { return TRUE; } }; return FALSE; } +#define WELCOME "" + gboolean cib_remote_listen(int ssock, gpointer data) { - char *msg = NULL; int lpc = 0; int csock; unsigned laddr; + char *msg = NULL; struct sockaddr_in addr; +#ifdef HAVE_GNUTLS_GNUTLS_H gnutls_session *session = NULL; +#endif cib_client_t *new_client = NULL; crm_data_t *login = NULL; const char *user = NULL; const char *pass = NULL; const char *tmp = NULL; cl_uuid_t client_id; char uuid_str[UU_UNPARSE_SIZEOF]; crm_debug("New connection"); /* accept the connection */ laddr = sizeof(addr); csock = accept(ssock, (struct sockaddr*)&addr, &laddr); if (csock == -1) { crm_err("accept socket failed"); return TRUE; } +#ifdef HAVE_GNUTLS_GNUTLS_H /* create gnutls session for the server socket */ session = create_tls_session(csock); if (session == NULL) { crm_err("TLS session creation failed"); close(csock); return TRUE; } - - crm_err("Sending '%s' size=%d", WELCOME, (int)sizeof (WELCOME)); - gnutls_record_send (*session, WELCOME, sizeof (WELCOME)); - crm_free(msg); - msg = NULL; +#endif do { - crm_err("Iter: %d", lpc++); - msg = cib_recv_tls_string(session); + crm_debug_2("Iter: %d", lpc++); +#ifdef HAVE_GNUTLS_GNUTLS_H + msg = cib_recv_remote_msg(session); +#else + msg = cib_recv_remote_msg(GINT_TO_POINTER(csock)); +#endif sleep(1); } while(msg == NULL && lpc < 10); /* convert to xml */ login = string2xml(msg); - crm_log_xml_err(login, "Login: "); + crm_log_xml_err(login, "Login: "); + if(login == NULL) { + goto bail; + } + tmp = crm_element_name(login); if(safe_str_neq(tmp, "cib_command")) { goto bail; } tmp = crm_element_value(login, "op"); if(safe_str_neq(tmp, "authenticate")) { goto bail; } user = crm_element_value(login, "user"); pass = crm_element_value(login, "password"); if(check_group_membership(user, "admin") == FALSE) { crm_err("User is not a member of the required group"); goto bail; } else if (authenticate_user(user, pass) == FALSE) { crm_err("PAM auth failed"); goto bail; } /* send ACK */ + crm_err("Sending '%s' size=%d", WELCOME, (int)sizeof (WELCOME)); crm_malloc0(new_client, sizeof(cib_client_t)); num_clients++; new_client->channel_name = "remote"; cl_uuid_generate(&client_id); cl_uuid_unparse(&client_id, uuid_str); CRM_CHECK(new_client->id == NULL, crm_free(new_client->id)); new_client->id = crm_strdup(uuid_str); new_client->callback_id = NULL; +#ifdef HAVE_GNUTLS_GNUTLS_H new_client->channel = (void*)session; - + gnutls_record_send (*session, WELCOME, sizeof (WELCOME)); +#else + new_client->channel = GINT_TO_POINTER(csock); + write(csock, WELCOME, sizeof (WELCOME)); +#endif new_client->source = (void*)G_main_add_fd( G_PRIORITY_HIGH, csock, FALSE, cib_remote_msg, new_client, default_ipc_connection_destroy); g_hash_table_insert(client_list, new_client->id, new_client); return TRUE; bail: +#ifdef HAVE_GNUTLS_GNUTLS_H gnutls_bye(*session, GNUTLS_SHUT_RDWR); gnutls_deinit(*session); gnutls_free(session); +#endif close(csock); return TRUE; } gboolean cib_remote_msg(int csock, gpointer data) { cl_uuid_t call_id; char call_uuid[UU_UNPARSE_SIZEOF]; const char *value = NULL; crm_data_t *command = NULL; cib_client_t *client = data; - char* msg = cib_recv_tls_string((void*)client->channel); + char* msg = cib_recv_remote_msg(client->channel); if(msg == NULL) { return FALSE; } command = string2xml(msg); if(command == NULL) { crm_err("Could not parse: %s", msg); goto bail; } crm_log_xml(LOG_MSG+1, "Command: ", command); value = crm_element_name(command); if(safe_str_neq(value, "cib_command")) { goto bail; } cl_uuid_generate(&call_id); cl_uuid_unparse(&call_id, call_uuid); crm_xml_add(command, F_TYPE, T_CIB); crm_xml_add(command, F_CIB_CLIENTID, client->id); crm_xml_add(command, F_CIB_CLIENTNAME, client->name); crm_xml_add(command, F_CIB_CALLID, call_uuid); if(crm_element_value(command, F_CIB_CALLOPTS) == NULL) { crm_xml_add_int(command, F_CIB_CALLOPTS, 0); } crm_log_xml(LOG_MSG, "Fixed Command: ", command); /* unset dangerous options */ xml_remove_prop(command, F_ORIG); xml_remove_prop(command, F_CIB_HOST); xml_remove_prop(command, F_CIB_GLOBAL_UPDATE); cib_process_request(command, TRUE, TRUE, FALSE, client); bail: free_xml(command); crm_free(msg); return TRUE; } +#ifdef HAVE_PAM /* * Useful Examples: * http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html * http://developer.apple.com/samplecode/CryptNoMore/index.html */ static int construct_pam_passwd(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { struct pam_response *reply; int i; char* passwd = (char*)data; crm_malloc0(reply, n * sizeof(*reply)); CRM_ASSERT(reply != NULL); /* Construct a PAM password message */ for (i = 0; i < n; ++i) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: reply[i].resp = passwd; break; default: /* case PAM_ERROR_MSG: */ /* case PAM_TEXT_INFO: */ crm_err("Unhandled message type: %d", msg[i]->msg_style); goto bail; break; } } *resp = reply; return PAM_SUCCESS; bail: crm_free(reply); return PAM_CONV_ERR; } +#endif int authenticate_user(const char* user, const char* passwd) { +#ifndef HAVE_PAM + gboolean pass = TRUE; +#else gboolean pass = FALSE; int rc = 0; struct pam_handle *handle = NULL; struct pam_conv passwd_data; passwd_data.conv = construct_pam_passwd; passwd_data.appdata_ptr = strdup(passwd); rc = pam_start ("cib", user, &passwd_data, &handle); if (rc != PAM_SUCCESS) { goto bail; } rc = pam_authenticate (handle, 0); if(rc != PAM_SUCCESS) { crm_err("pam_authenticate: %s (%d)", pam_strerror(handle, rc), rc); goto bail; } rc = pam_acct_mgmt(handle, 0); /* permitted access? */ if(rc != PAM_SUCCESS) { crm_err("pam_acct: %s (%d)", pam_strerror(handle, rc), rc); goto bail; } pass = TRUE; bail: rc = pam_end (handle, rc); +#endif return pass; } - char* -cib_send_tls_msg(gnutls_session_t *session, HA_Message *msg) +cib_send_plaintext(int sock, HA_Message *msg) { char *xml_text = NULL; ha_msg_mod(msg, F_XML_TAGNAME, "cib_result"); crm_log_xml(LOG_DEBUG_2, "Result: ", msg); xml_text = dump_xml_unformatted(msg); if(xml_text != NULL) { int len = strlen(xml_text); len++; /* null char */ crm_debug_3("Message size: %d", len); - gnutls_record_send (*session, xml_text, len); + write (sock, xml_text, len); } crm_free(xml_text); return NULL; } char* -cib_recv_tls_string(gnutls_session_t *session) +cib_recv_plaintext(int sock) { int len = 0; char* buf = NULL; int chunk_size = 512; - if (session == NULL) { - return NULL; - } - crm_malloc0(buf, chunk_size); while(1) { - int rc = gnutls_record_recv(*session, buf+len, chunk_size); + int rc = recv(sock, buf+len, chunk_size, 0); if (rc == 0) { if(len == 0) { goto bail; } return buf; } else if(rc > 0 && rc < chunk_size) { return buf; } else if(rc == chunk_size) { len += chunk_size; crm_realloc(buf, len); CRM_ASSERT(buf != NULL); } - if(rc < 0 - && rc != GNUTLS_E_INTERRUPTED - && rc != GNUTLS_E_AGAIN) { + if(rc < 0 && errno != EINTR) { cl_perror("Error receiving message: %d", rc); goto bail; } } bail: crm_free(buf); return NULL; } + +void +cib_send_remote_msg(void *session, HA_Message *msg) +{ +#ifdef HAVE_GNUTLS_GNUTLS_H + cib_send_tls(session, msg); +#else + cib_send_plaintext(GPOINTER_TO_INT(session), msg); +#endif +} + +char * +cib_recv_remote_msg(void *session) +{ +#ifdef HAVE_GNUTLS_GNUTLS_H + return cib_recv_tls(session); +#else + return cib_recv_plaintext(GPOINTER_TO_INT(session)); +#endif +} +