Adding a copy of memcached to the tree.
[awesomized/libmemcached] / memcached / sasl_defs.c
diff --git a/memcached/sasl_defs.c b/memcached/sasl_defs.c
new file mode 100644 (file)
index 0000000..1faefc8
--- /dev/null
@@ -0,0 +1,190 @@
+/* -*- 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>
+#include <sasl/saslplug.h>
+
+char my_sasl_hostname[1025];
+
+#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
+
+#ifndef HAVE_SASL_CALLBACK_FT
+typedef int (*sasl_callback_ft)(void);
+#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_callback_ft)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
+
+    memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname));
+    if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) {
+        if (settings.verbose) {
+            fprintf(stderr, "Error discovering hostname for SASL\n");
+        }
+        my_sasl_hostname[0] = '\0';
+    }
+
+    if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) {
+        fprintf(stderr, "Error initializing sasl.\n");
+        exit(EXIT_FAILURE);
+    } else {
+        if (settings.verbose) {
+            fprintf(stderr, "Initialized SASL.\n");
+        }
+    }
+}