#if defined(LIBMEMCACHED_WITH_SASL_SUPPORT) && LIBMEMCACHED_WITH_SASL_SUPPORT
+#if defined(HAVE_LIBSASL) && HAVE_LIBSASL
#include <sasl/sasl.h>
+#endif
+
+#include <pthread.h>
void memcached_set_sasl_callbacks(memcached_st *ptr,
const sasl_callback_t *callbacks)
* @param raddr remote address (out)
* @return true on success false otherwise (errno contains more info)
*/
-static memcached_return_t resolve_names(memcached_server_st& server, char *laddr, size_t laddr_length, char *raddr, size_t raddr_length)
+static memcached_return_t resolve_names(memcached_instance_st& server, char *laddr, size_t laddr_length, char *raddr, size_t raddr_length)
{
char host[NI_MAXHOST];
char port[NI_MAXSERV];
if (getsockname(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
{
- return memcached_set_errno(server, MEMCACHED_ERRNO, MEMCACHED_AT);
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
}
if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV) < 0)
{
- return MEMCACHED_HOST_LOOKUP_FAILURE;
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
}
(void)snprintf(laddr, laddr_length, "%s;%s", host, port);
if (getpeername(server.fd, (struct sockaddr *)&saddr, &salen) < 0)
{
- return memcached_set_errno(server, MEMCACHED_ERRNO, MEMCACHED_AT);
+ return memcached_set_error(server, MEMCACHED_HOST_LOOKUP_FAILURE, MEMCACHED_AT);
}
if (getnameinfo((struct sockaddr *)&saddr, salen, host, sizeof(host),
return MEMCACHED_SUCCESS;
}
-memcached_return_t memcached_sasl_authenticate_connection(memcached_server_st *server)
+extern "C" {
+
+static void sasl_shutdown_function()
+{
+ sasl_done();
+}
+
+static volatile int sasl_startup_state= SASL_OK;
+pthread_mutex_t sasl_startup_state_LOCK= PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t sasl_startup_once= PTHREAD_ONCE_INIT;
+static void sasl_startup_function(void)
+{
+ sasl_startup_state= sasl_client_init(NULL);
+
+ if (sasl_startup_state == SASL_OK)
+ {
+ (void)atexit(sasl_shutdown_function);
+ }
+}
+
+} // extern "C"
+
+memcached_return_t memcached_sasl_authenticate_connection(org::libmemcached::Instance* server)
{
if (LIBMEMCACHED_WITH_SASL_SUPPORT == 0)
{
}
/* SANITY CHECK: SASL can only be used with the binary protocol */
- if (server->root->flags.binary_protocol == false)
+ if (memcached_is_binary(server->root) == false)
{
- return MEMCACHED_PROTOCOL_ERROR;
+ return memcached_set_error(*server, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
+ memcached_literal_param("memcached_sasl_authenticate_connection() is not supported via the ASCII protocol"));
}
/* Try to get the supported mech from the server. Servers without SASL
* as authenticated
*/
protocol_binary_request_no_extras request= { };
- request.message.header.request.magic= PROTOCOL_BINARY_REQ;
+
+ initialize_binary_request(ptr, request.message.header);
+
request.message.header.request.opcode= PROTOCOL_BINARY_CMD_SASL_LIST_MECHS;
if (memcached_io_write(server, request.bytes,
return rc;
}
- int ret;
- if ((ret= sasl_client_init(NULL)) != SASL_OK)
+ int pthread_error;
+ if ((pthread_error= pthread_once(&sasl_startup_once, sasl_startup_function)) != 0)
{
- const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
+ return memcached_set_errno(*server, pthread_error, MEMCACHED_AT);
+ }
+
+ (void)pthread_mutex_lock(&sasl_startup_state_LOCK);
+ if (sasl_startup_state != SASL_OK)
+ {
+ const char *sasl_error_msg= sasl_errstring(sasl_startup_state, NULL, NULL);
return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
memcached_string_make_from_cstr(sasl_error_msg));
}
+ (void)pthread_mutex_unlock(&sasl_startup_state_LOCK);
sasl_conn_t *conn;
+ int ret;
if ((ret= sasl_client_new("memcached", server->hostname, laddr, raddr, server->root->sasl.callbacks, 0, &conn) ) != SASL_OK)
{
const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
+
+ sasl_dispose(&conn);
+
return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
memcached_string_make_from_cstr(sasl_error_msg));
}
if (ret != SASL_OK and ret != SASL_CONTINUE)
{
const char *sasl_error_msg= sasl_errstring(ret, NULL, NULL);
+
+ sasl_dispose(&conn);
+
return memcached_set_error(*server, MEMCACHED_AUTH_PROBLEM, MEMCACHED_AT,
memcached_string_make_from_cstr(sasl_error_msg));
}
do {
/* send the packet */
- struct libmemcached_io_vector_st vector[]=
+ libmemcached_io_vector_st vector[]=
{
- { sizeof(request.bytes), request.bytes },
- { keylen, chosenmech },
- { len, data }
+ { request.bytes, sizeof(request.bytes) },
+ { chosenmech, keylen },
+ { data, len }
};
- if (memcached_io_writev(server, vector, 3, true) == -1)
+ if (memcached_io_writev(server, vector, 3, true) == false)
{
rc= MEMCACHED_WRITE_FAILURE;
break;
return MEMCACHED_INVALID_ARGUMENTS;
}
+ memcached_return_t ret;
+ if (memcached_failed(ret= memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1)))
+ {
+ return memcached_set_error(*ptr, ret, MEMCACHED_AT, memcached_literal_param("Unable change to binary protocol which is required for SASL."));
+ }
+
memcached_destroy_sasl_auth_data(ptr);
- sasl_callback_t *callbacks= (sasl_callback_t*)libmemcached_calloc(ptr, 4, sizeof(sasl_callback_t));
+ sasl_callback_t *callbacks= libmemcached_xcalloc(ptr, 4, sasl_callback_t);
size_t password_length= strlen(password);
size_t username_length= strlen(username);
char *name= (char *)libmemcached_malloc(ptr, username_length +1);
* into the list, but if we don't know the ID we don't know how to handle
* the context...
*/
- size_t total= 0;
+ ptrdiff_t total= 0;
while (source->sasl.callbacks[total].id != SASL_CB_LIST_END)
{
++total;
}
- sasl_callback_t *callbacks= (sasl_callback_t*)libmemcached_calloc(clone, total +1, sizeof(sasl_callback_t));
+ sasl_callback_t *callbacks= libmemcached_xcalloc(clone, total +1, sasl_callback_t);
if (callbacks == NULL)
{
return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
memcpy(callbacks, source->sasl.callbacks, (total + 1) * sizeof(sasl_callback_t));
/* Now update the context... */
- for (size_t x= 0; x < total; ++x)
+ for (ptrdiff_t x= 0; x < total; ++x)
{
if (callbacks[x].id == SASL_CB_USER || callbacks[x].id == SASL_CB_AUTHNAME)
{
if (callbacks[x].context == NULL)
{
/* Failed to allocate memory, clean up previously allocated memory */
- for (size_t y= 0; y < x; ++y)
+ for (ptrdiff_t y= 0; y < x; ++y)
{
libmemcached_free(clone, clone->sasl.callbacks[y].context);
}
if (n == NULL)
{
/* Failed to allocate memory, clean up previously allocated memory */
- for (size_t y= 0; y < x; ++y)
+ for (ptrdiff_t y= 0; y < x; ++y)
{
libmemcached_free(clone, clone->sasl.callbacks[y].context);
}