diff options
author | Trond Norbye <Trond.Norbye@gmail.com> | 2010-02-24 16:16:23 +0100 |
---|---|---|
committer | Dustin Sallings <dustin@spy.net> | 2010-03-06 01:10:54 -0800 |
commit | 7a221d95a870bd01ba1c93650c63abd583b00d39 (patch) | |
tree | d25a3ae5a9cc8e35f04a2fe8fe1706d7ec50b8b3 /sasl_defs.c | |
parent | d3094edf7c95ee499b4fa5a41afcec5381a8a633 (diff) | |
download | memcached-7a221d95a870bd01ba1c93650c63abd583b00d39.tar.gz |
Add support for --enable-sasl-pwdb
--enable-sasl-pwdb allows memcached to use it's own password file and
verify a plaintext password.
The file is specified with the environment variable
MEMCACHED_SASL_PWDB, and is a plain text file with the following
syntax:
username:password
Please note that you have to specify "mech_list: plain" in your sasl
config file for this to work.
Ex:
echo "mech_list: plain" > memcached.conf
echo "myname:mypass" > /tmp/memcached-sasl-db
export MEMCACHED_SASL_PWDB=/tmp/memcached-sasl-db
export SASL_CONF_PATH=`pwd`/memcached.conf
./memcached -S -v
and you should be able to use your favorite memcached client with sasl
support to connect to the server.
(Please note that not all SASL implementations support
SASL_CB_GETCONF, so you may have to install the sasl config
(memcached.conf) to the systemwide location)
Diffstat (limited to 'sasl_defs.c')
-rw-r--r-- | sasl_defs.c | 161 |
1 files changed, 158 insertions, 3 deletions
diff --git a/sasl_defs.c b/sasl_defs.c index 7e803d4..2e2c577 100644 --- a/sasl_defs.c +++ b/sasl_defs.c @@ -1,14 +1,169 @@ +/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "memcached.h" #include <stdio.h> #include <stdlib.h> +#include <string.h> -static sasl_callback_t sasl_callbacks[] = { - { - SASL_CB_LIST_END, NULL, NULL +#ifdef HAVE_SASL_CB_GETCONF +/* The locations we may search for a SASL config file if the user didn't + * specify one in the environment variable SASL_CONF_PATH + */ +const char * const locations[] = { + "/etc/sasl/memcached.conf", + "/etc/sasl2/memcached.conf", + NULL +}; +#endif + +#ifdef ENABLE_SASL_PWDB +#define MAX_ENTRY_LEN 256 + +static const char *memcached_sasl_pwdb; + +static int sasl_server_userdb_checkpass(sasl_conn_t *conn, + void *context, + const char *user, + const char *pass, + unsigned passlen, + struct propctx *propctx) +{ + size_t unmlen = strlen(user); + if ((passlen + unmlen) > (MAX_ENTRY_LEN - 4)) { + fprintf(stderr, + "WARNING: Failed to authenticate <%s> due to too long password (%d)\n", + user, passlen); + return SASL_NOAUTHZ; + } + + FILE *pwfile = fopen(memcached_sasl_pwdb, "r"); + if (pwfile == NULL) { + if (settings.verbose) { + vperror("WARNING: Failed to open sasl database <%s>", + memcached_sasl_pwdb); + } + return SASL_NOAUTHZ; + } + + char buffer[MAX_ENTRY_LEN]; + bool ok = false; + + while ((fgets(buffer, sizeof(buffer), pwfile)) != NULL) { + if (memcmp(user, buffer, unmlen) == 0 && buffer[unmlen] == ':') { + /* This is the correct user */ + ++unmlen; + if (memcmp(pass, buffer + unmlen, passlen) == 0 && + (buffer[unmlen + passlen] == ':' || /* Additional tokens */ + buffer[unmlen + passlen] == '\n' || /* end of line */ + buffer[unmlen + passlen] == '\r'|| /* dos format? */ + buffer[unmlen + passlen] == '\0')) { /* line truncated */ + ok = true; + } + + break; + } + } + (void)fclose(pwfile); + if (ok) { + return SASL_OK; + } + + if (settings.verbose) { + fprintf(stderr, "INFO: User <%s> failed to authenticate\n", user); + } + + return SASL_NOAUTHZ; +} +#endif + +#ifdef HAVE_SASL_CB_GETCONF +static int sasl_getconf(void *context, const char **path) +{ + *path = getenv("SASL_CONF_PATH"); + + if (*path == NULL) { + for (int i = 0; locations[i] != NULL; ++i) { + if (access(locations[i], F_OK) == 0) { + *path = locations[i]; + break; + } + } } + + if (settings.verbose) { + if (*path != NULL) { + fprintf(stderr, "Reading configuration from: <%s>\n", *path); + } else { + fprintf(stderr, "Failed to locate a config path\n"); + } + + } + + return (*path != NULL) ? SASL_OK : SASL_FAIL; +} +#endif + +static int sasl_log(void *context, int level, const char *message) +{ + bool log = true; + + switch (level) { + case SASL_LOG_NONE: + log = false; + break; + case SASL_LOG_PASS: + case SASL_LOG_TRACE: + case SASL_LOG_DEBUG: + case SASL_LOG_NOTE: + if (settings.verbose < 2) { + log = false; + } + break; + case SASL_LOG_WARN: + case SASL_LOG_FAIL: + if (settings.verbose < 1) { + log = false; + } + break; + default: + /* This is an error */ + ; + } + + if (log) { + fprintf(stderr, "SASL (severity %d): %s\n", level, message); + } + + return SASL_OK; +} + +static sasl_callback_t sasl_callbacks[] = { +#ifdef ENABLE_SASL_PWDB + { SASL_CB_SERVER_USERDB_CHECKPASS, sasl_server_userdb_checkpass, NULL }, +#endif + + { SASL_CB_LOG, sasl_log, NULL }, + +#ifdef HAVE_SASL_CB_GETCONF + { SASL_CB_GETCONF, sasl_getconf, NULL }, +#endif + + { SASL_CB_LIST_END, NULL, NULL } }; void init_sasl(void) { +#ifdef ENABLE_SASL_PWDB + memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB"); + if (memcached_sasl_pwdb == NULL) { + if (settings.verbose) { + fprintf(stderr, + "INFO: MEMCACHED_SASL_PWDB not specified. " + "Internal passwd database disabled\n"); + } + sasl_callbacks[0].id = SASL_CB_LIST_END; + sasl_callbacks[0].proc = NULL; + } +#endif + if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) { fprintf(stderr, "Error initializing sasl.\n"); exit(EXIT_FAILURE); |