|
Packit |
4e8bc4 |
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
Packit |
4e8bc4 |
#include "memcached.h"
|
|
Packit |
4e8bc4 |
#include <stdio.h>
|
|
Packit |
4e8bc4 |
#include <stdlib.h>
|
|
Packit |
4e8bc4 |
#include <string.h>
|
|
Packit |
4e8bc4 |
#include <sasl/saslplug.h>
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
char my_sasl_hostname[1025];
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#if defined(HAVE_SASL_CB_GETCONF) || defined(HAVE_SASL_CB_GETCONFPATH)
|
|
Packit |
4e8bc4 |
/* The locations we may search for a SASL config file if the user didn't
|
|
Packit |
4e8bc4 |
* specify one in the environment variable SASL_CONF_PATH
|
|
Packit |
4e8bc4 |
*/
|
|
Packit |
4e8bc4 |
const char * const locations[] = {
|
|
Packit |
4e8bc4 |
"/etc/sasl/memcached.conf",
|
|
Packit |
4e8bc4 |
"/etc/sasl2/memcached.conf",
|
|
Packit |
4e8bc4 |
NULL
|
|
Packit |
4e8bc4 |
};
|
|
Packit Service |
3cc984 |
|
|
Packit Service |
3cc984 |
/* If the element of locations is file, locations_dir_path stores the
|
|
Packit Service |
3cc984 |
* directory path of these elements */
|
|
Packit Service |
3cc984 |
const char *const locations_dir_path[] = {
|
|
Packit Service |
3cc984 |
"/etc/sasl",
|
|
Packit Service |
3cc984 |
"/etc/sasl2",
|
|
Packit Service |
3cc984 |
NULL
|
|
Packit Service |
3cc984 |
};
|
|
Packit Service |
3cc984 |
|
|
Packit Service |
3cc984 |
/* If the element of locations is directory, locations_file_path stores
|
|
Packit Service |
3cc984 |
* the actual configue file which used by sasl, when GETCONFPATH is
|
|
Packit Service |
3cc984 |
* enabled */
|
|
Packit Service |
3cc984 |
const char *const locations_file_path[] = {
|
|
Packit Service |
3cc984 |
"/etc/sasl/memcached.conf/memcached.conf",
|
|
Packit Service |
3cc984 |
"/etc/sasl2/memcached.conf/memcached.conf",
|
|
Packit Service |
3cc984 |
NULL
|
|
Packit Service |
3cc984 |
};
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#ifndef HAVE_SASL_CALLBACK_FT
|
|
Packit |
4e8bc4 |
typedef int (*sasl_callback_ft)(void);
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#ifdef ENABLE_SASL_PWDB
|
|
Packit |
4e8bc4 |
#define MAX_ENTRY_LEN 256
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static const char *memcached_sasl_pwdb;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static int sasl_server_userdb_checkpass(sasl_conn_t *conn,
|
|
Packit |
4e8bc4 |
void *context,
|
|
Packit |
4e8bc4 |
const char *user,
|
|
Packit |
4e8bc4 |
const char *pass,
|
|
Packit |
4e8bc4 |
unsigned passlen,
|
|
Packit |
4e8bc4 |
struct propctx *propctx)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
size_t unmlen = strlen(user);
|
|
Packit |
4e8bc4 |
if ((passlen + unmlen) > (MAX_ENTRY_LEN - 4)) {
|
|
Packit |
4e8bc4 |
fprintf(stderr,
|
|
Packit |
4e8bc4 |
"WARNING: Failed to authenticate <%s> due to too long password (%d)\n",
|
|
Packit |
4e8bc4 |
user, passlen);
|
|
Packit |
4e8bc4 |
return SASL_NOAUTHZ;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
FILE *pwfile = fopen(memcached_sasl_pwdb, "r");
|
|
Packit |
4e8bc4 |
if (pwfile == NULL) {
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
vperror("WARNING: Failed to open sasl database <%s>",
|
|
Packit |
4e8bc4 |
memcached_sasl_pwdb);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
return SASL_NOAUTHZ;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
char buffer[MAX_ENTRY_LEN];
|
|
Packit |
4e8bc4 |
bool ok = false;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
while ((fgets(buffer, sizeof(buffer), pwfile)) != NULL) {
|
|
Packit |
4e8bc4 |
if (memcmp(user, buffer, unmlen) == 0 && buffer[unmlen] == ':') {
|
|
Packit |
4e8bc4 |
/* This is the correct user */
|
|
Packit |
4e8bc4 |
++unmlen;
|
|
Packit |
4e8bc4 |
if (memcmp(pass, buffer + unmlen, passlen) == 0 &&
|
|
Packit |
4e8bc4 |
(buffer[unmlen + passlen] == ':' || /* Additional tokens */
|
|
Packit |
4e8bc4 |
buffer[unmlen + passlen] == '\n' || /* end of line */
|
|
Packit |
4e8bc4 |
buffer[unmlen + passlen] == '\r'|| /* dos format? */
|
|
Packit |
4e8bc4 |
buffer[unmlen + passlen] == '\0')) { /* line truncated */
|
|
Packit |
4e8bc4 |
ok = true;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
(void)fclose(pwfile);
|
|
Packit |
4e8bc4 |
if (ok) {
|
|
Packit |
4e8bc4 |
return SASL_OK;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "INFO: User <%s> failed to authenticate\n", user);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return SASL_NOAUTHZ;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#if defined(HAVE_SASL_CB_GETCONF) || defined(HAVE_SASL_CB_GETCONFPATH)
|
|
Packit |
4e8bc4 |
static int sasl_getconf(void *context, const char **path)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
*path = getenv("SASL_CONF_PATH");
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (*path == NULL) {
|
|
Packit Service |
3cc984 |
#if defined(HAVE_SASL_CB_GETCONF)
|
|
Packit |
4e8bc4 |
for (int i = 0; locations[i] != NULL; ++i) {
|
|
Packit |
4e8bc4 |
if (access(locations[i], F_OK) == 0) {
|
|
Packit |
4e8bc4 |
*path = locations[i];
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit Service |
3cc984 |
#elif defined(HAVE_SASL_CB_GETCONFPATH)
|
|
Packit Service |
3cc984 |
for (int i = 0; locations[i] != NULL; ++i) {
|
|
Packit Service |
3cc984 |
if (access(locations_file_path[i], F_OK) == 0) {
|
|
Packit Service |
3cc984 |
*path = locations[i];
|
|
Packit Service |
3cc984 |
break;
|
|
Packit Service |
3cc984 |
} else if (access(locations[i], F_OK) == 0) {
|
|
Packit Service |
3cc984 |
*path = locations_dir_path[i];
|
|
Packit Service |
3cc984 |
break;
|
|
Packit Service |
3cc984 |
}
|
|
Packit Service |
3cc984 |
}
|
|
Packit Service |
3cc984 |
#endif
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
if (*path != NULL) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Reading configuration from: <%s>\n", *path);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Failed to locate a config path\n");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return (*path != NULL) ? SASL_OK : SASL_FAIL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static int sasl_log(void *context, int level, const char *message)
|
|
Packit |
4e8bc4 |
{
|
|
Packit |
4e8bc4 |
bool log = true;
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
switch (level) {
|
|
Packit |
4e8bc4 |
case SASL_LOG_NONE:
|
|
Packit |
4e8bc4 |
log = false;
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case SASL_LOG_PASS:
|
|
Packit |
4e8bc4 |
case SASL_LOG_TRACE:
|
|
Packit |
4e8bc4 |
case SASL_LOG_DEBUG:
|
|
Packit |
4e8bc4 |
case SASL_LOG_NOTE:
|
|
Packit |
4e8bc4 |
if (settings.verbose < 2) {
|
|
Packit |
4e8bc4 |
log = false;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
case SASL_LOG_WARN:
|
|
Packit |
4e8bc4 |
case SASL_LOG_FAIL:
|
|
Packit |
4e8bc4 |
if (settings.verbose < 1) {
|
|
Packit |
4e8bc4 |
log = false;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
break;
|
|
Packit |
4e8bc4 |
default:
|
|
Packit |
4e8bc4 |
/* This is an error */
|
|
Packit |
4e8bc4 |
;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (log) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "SASL (severity %d): %s\n", level, message);
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
return SASL_OK;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
static sasl_callback_t sasl_callbacks[] = {
|
|
Packit |
4e8bc4 |
#ifdef ENABLE_SASL_PWDB
|
|
Packit |
4e8bc4 |
{ SASL_CB_SERVER_USERDB_CHECKPASS, (sasl_callback_ft)sasl_server_userdb_checkpass, NULL },
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
{ SASL_CB_LOG, (sasl_callback_ft)sasl_log, NULL },
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
#ifdef HAVE_SASL_CB_GETCONF
|
|
Packit |
4e8bc4 |
{ SASL_CB_GETCONF, sasl_getconf, NULL },
|
|
Packit |
4e8bc4 |
#else
|
|
Packit |
4e8bc4 |
#ifdef HAVE_SASL_CB_GETCONFPATH
|
|
Packit |
4e8bc4 |
{ SASL_CB_GETCONFPATH, (sasl_callback_ft)sasl_getconf, NULL },
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
{ SASL_CB_LIST_END, NULL, NULL }
|
|
Packit |
4e8bc4 |
};
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
void init_sasl(void) {
|
|
Packit |
4e8bc4 |
#ifdef ENABLE_SASL_PWDB
|
|
Packit |
4e8bc4 |
memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB");
|
|
Packit |
4e8bc4 |
if (memcached_sasl_pwdb == NULL) {
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
fprintf(stderr,
|
|
Packit |
4e8bc4 |
"INFO: MEMCACHED_SASL_PWDB not specified. "
|
|
Packit |
4e8bc4 |
"Internal passwd database disabled\n");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
sasl_callbacks[0].id = SASL_CB_LIST_END;
|
|
Packit |
4e8bc4 |
sasl_callbacks[0].proc = NULL;
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
#endif
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname));
|
|
Packit |
4e8bc4 |
if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) {
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Error discovering hostname for SASL\n");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
my_sasl_hostname[0] = '\0';
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
|
|
Packit |
4e8bc4 |
if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Error initializing sasl.\n");
|
|
Packit |
4e8bc4 |
exit(EXIT_FAILURE);
|
|
Packit |
4e8bc4 |
} else {
|
|
Packit |
4e8bc4 |
if (settings.verbose) {
|
|
Packit |
4e8bc4 |
fprintf(stderr, "Initialized SASL.\n");
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|
|
Packit |
4e8bc4 |
}
|