In my previous blog entry I announced SASL support in the memcached server provided by Dustin Sallings. Support for SASL in the server might be a good thing to have for someone, but you need support for it in your driver in order to make use of it. Being a contributor to libmemcached, so I decided to add support for SASL there.

So how do the SASL code work? Well you enable it by calling memcached_set_sasl_callbacks with a number of callbacks (I'll get back to them shortly). Whenever libmemcached successfully connects to a server (and SASL is enabled) it will start to authenticate to the server, causing multiple packets to be exchanged between the client and the memcached server (this means that you should use persistent connections, but you know that already... didn't you?)

Let's skip the internals, and look at how you as a user should implement this. The first thing you need to do is to initialize libsasl, create (and initialize) an instance to libmemcached. Before you terminate your application you should also call the cleanup function in libsasl:

...int main(int argc, char **argv){ if (sasl_client_init(NULL) != SASL_OK) { fprintf(stderr, "Failed to initialize sasl library!\n"); return 1; } memcached_st *memc = memcached_create(NULL); memcached_server_st *servers = memcached_servers_parse(servers_list); memcached_server_push(memc, servers); memcached_server_list_free(servers); memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1); [ .... cut ... ] sasl_done();}The next thing you need to do is to create a callback structure where you specify functions that libsasl can call when it wants authentication data from you (like username / password etc):

static sasl_callback_t sasl_callbacks[] = { { SASL_CB_USER, &get_username, NULL }, { SASL_CB_AUTHNAME, &get_username, NULL }, { SASL_CB_PASS, &get_password, NULL }, { SASL_CB_LIST_END, NULL, NULL }};And we associate the callback structure with the memcached instance by calling:

memcached_set_sasl_callbacks(memc, sasl_callbacks);So how does get_username and get_password look like? They may be as simple as:

static char *username = "username";static char *passwd = "secret";static int get_username(void *context, int id, const char **result, unsigned int *len){ if (!result || (id != SASL_CB_USER && id != SASL_CB_AUTHNAME)) { return SASL_BADPARAM; } *result= username; if (len) { *len= (username == NULL) ? 0 : (unsigned int)strlen(username); } return SASL_OK;}static int get_password(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret){ static sasl_secret_t* x; if (!conn || ! psecret || id != SASL_CB_PASS) { return SASL_BADPARAM; } if (passwd == NULL) { *psecret = NULL; return SASL_OK; } size_t len = strlen(passwd); x = realloc(x, sizeof(sasl_secret_t) + len); if (!x) { return SASL_NOMEM; } x->len = len; strcpy((void *)x->data, passwd); *psecret = x; return SASL_OK;}In order to try this out you need either libsasl or libsasl2 on your machine. The functionality is not merged into the development branch of libmemcached, so you will have to grab my development branch and compile from that. If you would like to follow the status for this feature you should monitor RFE 462250. You will find the branch that implements this feature at: https://code.launchpad.net/~trond-no...asl_rfe_462250.

Happy hacking



More...