]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added support for password scheme plugins. auth module dir defaults under
authorTimo Sirainen <tss@iki.fi>
Sun, 30 May 2004 03:57:15 +0000 (06:57 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 30 May 2004 03:57:15 +0000 (06:57 +0300)
module_dir now.

--HG--
branch : HEAD

src/auth/Makefile.am
src/auth/main.c
src/auth/password-scheme.c
src/auth/password-scheme.h
src/imap/main.c
src/lib/module-dir.c
src/lib/module-dir.h
src/pop3/main.c

index fbc91d162a6bff07390a91070cc47f0547d3b852..1126d0c9322819fc4535202da733ef6c2fc58a1a 100644 (file)
@@ -5,7 +5,7 @@ pkglibexec_PROGRAMS = dovecot-auth
 INCLUDES = \
        -I$(top_srcdir)/src/lib \
        -I$(top_srcdir)/src/lib-settings \
-       -DAUTH_MODULE_DIR=\""$(libdir)/dovecot/auth"\" \
+       -DAUTH_MODULE_DIR=\""$(moduledir)/auth"\" \
        $(AUTH_CFLAGS)
 
 dovecot_auth_LDADD = \
index f03432f55a1e3dd0ebbd14f8c0430f717a0a6ac5..cf24101fe385e16ddb6cada184831c794dd1d938 100644 (file)
@@ -11,6 +11,7 @@
 #include "mech.h"
 #include "userdb.h"
 #include "passdb.h"
+#include "password-scheme.h"
 #include "auth-master-connection.h"
 #include "auth-client-connection.h"
 
@@ -93,6 +94,7 @@ static void main_init(void)
        mech_init();
        userdb_init();
        passdb_init();
+        password_schemes_init();
 
        masters_buf = buffer_create_dynamic(default_pool, 64, (size_t)-1);
 
@@ -161,6 +163,7 @@ static void main_deinit(void)
                auth_master_connection_free(master[i]);
        }
 
+        password_schemes_deinit();
        passdb_deinit();
        userdb_deinit();
        mech_deinit();
index f9551255996be03029fa5d1bc253b46dba433e60..c7e08da13f791e0c365cbd6df09aabb17e67b7fd 100644 (file)
@@ -1,9 +1,11 @@
 /* Copyright (C) 2003 Timo Sirainen */
 
 #include "lib.h"
+#include "buffer.h"
 #include "base64.h"
 #include "hex-binary.h"
 #include "md5.h"
+#include "module-dir.h"
 #include "mycrypt.h"
 #include "randgen.h"
 #include "str.h"
 static const char *salt_chars =
        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
+static buffer_t *schemes_buf;
+static const struct password_scheme *schemes;
+#ifdef HAVE_MODULES
+static struct module *scheme_modules;
+#endif
+
 int password_verify(const char *plaintext, const char *password,
                    const char *scheme, const char *user)
 {
-       unsigned char md5_digest[16];
-       const char *realm, *str;
+       const struct password_scheme *s;
 
        if (password == NULL)
                return 0;
 
-       if (strcasecmp(scheme, "CRYPT") == 0)
-               return strcmp(mycrypt(plaintext, password), password) == 0;
-
-       if (strcasecmp(scheme, "MD5") == 0) {
-                str = password_generate_md5_crypt(plaintext, password);
-               return strcmp(str, password) == 0;
-       }
-#ifdef HAVE_OPENSSL_SHA1
-       if (strcasecmp(scheme, "SHA") == 0 ||
-           strcasecmp(scheme, "SHA1") == 0) {
-               unsigned char sha1_digest[SHA_DIGEST_LENGTH];
-               string_t *str;
-
-               SHA1(plaintext, strlen(plaintext), sha1_digest);
-
-               str = t_str_new(64);
-               base64_encode(sha1_digest, sizeof(sha1_digest), str);
-               return strcasecmp(str_c(str), password) == 0;
-       }
-#endif
-
-       if (strcasecmp(scheme, "PLAIN") == 0)
-               return strcmp(password, plaintext) == 0;
-
-       if (strcasecmp(scheme, "HMAC-MD5") == 0) {
-               str = password_generate_cram_md5(plaintext);
-               return strcmp(str, password) == 0;
-       }
-
-       if (strcasecmp(scheme, "DIGEST-MD5") == 0) {
-               /* user:realm:passwd */
-               realm = strchr(user, '@');
-               if (realm != NULL) realm++; else realm = "";
-
-               str = t_strconcat(t_strcut(user, '@'), ":", realm,  ":",
-                                 plaintext, NULL);
-               md5_get_digest(str, strlen(str), md5_digest);
-               str = binary_to_hex(md5_digest, sizeof(md5_digest));
-
-               return strcasecmp(str, password) == 0;
-       }
-
-       if (strcasecmp(scheme, "PLAIN-MD5") == 0) {
-               md5_get_digest(plaintext, strlen(plaintext), md5_digest);
-               str = binary_to_hex(md5_digest, sizeof(md5_digest));
-               return strcasecmp(str, password) == 0;
+       for (s = schemes; s->name != NULL; s++) {
+               if (strcasecmp(s->name, scheme) == 0)
+                       return s->password_verify(plaintext, password, user);
        }
 
        return -1;
@@ -110,48 +74,197 @@ const char *password_get_scheme(const char **password)
 const char *password_generate(const char *plaintext, const char *user,
                              const char *scheme)
 {
-       const char *realm, *str;
-       unsigned char digest[16];
+       const struct password_scheme *s;
+
+       for (s = schemes; s->name != NULL; s++) {
+               if (strcasecmp(s->name, scheme) == 0)
+                       return s->password_generate(plaintext, user);
+       }
+
+       return NULL;
+}
+
+static int crypt_verify(const char *plaintext, const char *password,
+                       const char *user __attr_unused__)
+{
+       return strcmp(mycrypt(plaintext, password), password) == 0;
+}
+
+static const char *crypt_generate(const char *plaintext,
+                                 const char *user __attr_unused__)
+{
+       char salt[9];
+
+       random_fill(salt, 2);
+       salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)];
+       salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)];
+       salt[2] = '\0';
+       return t_strdup(mycrypt(plaintext, salt));
+}
+
+static int md5_verify(const char *plaintext, const char *password,
+                     const char *user __attr_unused__)
+{
+       const char *str;
+
+       str = password_generate_md5_crypt(plaintext, password);
+       return strcmp(str, password) == 0;
+}
+
+static const char *md5_generate(const char *plaintext,
+                               const char *user __attr_unused__)
+{
        char salt[9];
        int i;
 
-       if (strcasecmp(scheme, "CRYPT") == 0) {
-               random_fill(salt, 2);
-               salt[0] = salt_chars[salt[0] % (sizeof(salt_chars)-1)];
-               salt[1] = salt_chars[salt[1] % (sizeof(salt_chars)-1)];
-               salt[2] = '\0';
-               return t_strdup(mycrypt(plaintext, salt));
-       }
+       random_fill(salt, 8);
+       for (i = 0; i < 8; i++)
+               salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
+       salt[8] = '\0';
+       return password_generate_md5_crypt(plaintext, salt);
+}
 
-       if (strcasecmp(scheme, "MD5") == 0) {
-               random_fill(salt, 8);
-               for (i = 0; i < 8; i++)
-                       salt[i] = salt_chars[salt[i] % (sizeof(salt_chars)-1)];
-               salt[8] = '\0';
-               return password_generate_md5_crypt(plaintext, salt);
-       }
+#ifdef HAVE_OPENSSL_SHA1
+static int sha_verify(const char *plaintext, const char *password,
+                     const char *user __attr_unused__)
+{
+       unsigned char digest[SHA_DIGEST_LENGTH];
+       string_t *str;
+
+       SHA1(plaintext, strlen(plaintext), digest);
+
+       str = t_str_new(64);
+       base64_encode(digest, sizeof(digest), str);
+       return strcasecmp(str_c(str), password) == 0;
+}
+#endif
 
-       if (strcasecmp(scheme, "PLAIN") == 0)
-               return plaintext;
+static int plain_verify(const char *plaintext, const char *password,
+                       const char *user __attr_unused__)
+{
+       return strcmp(password, plaintext) == 0;
+}
+
+static const char *plain_generate(const char *plaintext,
+                                 const char *user __attr_unused__)
+{
+       return plaintext;
+}
 
-       if (strcasecmp(scheme, "HMAC-MD5") == 0)
-               return password_generate_cram_md5(plaintext);
+static int hmac_md5_verify(const char *plaintext, const char *password,
+                          const char *user __attr_unused__)
+{
+       return strcmp(password_generate_cram_md5(plaintext), password) == 0;
+}
 
-       if (strcasecmp(scheme, "DIGEST-MD5") == 0) {
-               /* user:realm:passwd */
-               realm = strchr(user, '@');
-               if (realm != NULL) realm++; else realm = "";
+static const char *hmac_md5_generate(const char *plaintext,
+                                    const char *user __attr_unused__)
+{
+       return password_generate_cram_md5(plaintext);
+}
 
-               str = t_strconcat(t_strcut(user, '@'), ":", realm,  ":",
-                                 plaintext, NULL);
-               md5_get_digest(str, strlen(str), digest);
-               return binary_to_hex(digest, sizeof(digest));
-       }
+static int digest_md5_verify(const char *plaintext, const char *password,
+                            const char *user)
+{
+       unsigned char digest[16];
+       const char *realm, *str;
+
+       /* user:realm:passwd */
+       realm = strchr(user, '@');
+       if (realm != NULL) realm++; else realm = "";
+
+       str = t_strconcat(t_strcut(user, '@'), ":", realm,  ":",
+                         plaintext, NULL);
+       md5_get_digest(str, strlen(str), digest);
+       str = binary_to_hex(digest, sizeof(digest));
+
+       return strcasecmp(str, password) == 0;
+}
+
+static const char *digest_md5_generate(const char *plaintext, const char *user)
+{
+       const char *realm, *str;
+       unsigned char digest[16];
+
+       /* user:realm:passwd */
+       realm = strchr(user, '@');
+       if (realm != NULL) realm++; else realm = "";
+
+       str = t_strconcat(t_strcut(user, '@'), ":", realm,  ":",
+                         plaintext, NULL);
+       md5_get_digest(str, strlen(str), digest);
+       return binary_to_hex(digest, sizeof(digest));
+}
 
-       if (strcasecmp(scheme, "PLAIN-MD5") == 0) {
-               md5_get_digest(plaintext, strlen(plaintext), digest);
-               return binary_to_hex(digest, sizeof(digest));
+static int plain_md5_verify(const char *plaintext, const char *password,
+                           const char *user __attr_unused__)
+{
+       unsigned char digest[16];
+       const char *str;
+
+       md5_get_digest(plaintext, strlen(plaintext), digest);
+       str = binary_to_hex(digest, sizeof(digest));
+       return strcasecmp(str, password) == 0;
+}
+
+static const char *plain_md5_generate(const char *plaintext,
+                                     const char *user __attr_unused__)
+{
+       unsigned char digest[16];
+
+       md5_get_digest(plaintext, strlen(plaintext), digest);
+       return binary_to_hex(digest, sizeof(digest));
+}
+
+static const struct password_scheme default_schemes[] = {
+       { "CRYPT", crypt_verify, crypt_generate },
+       { "MD5", md5_verify, md5_generate },
+#ifdef HAVE_OPENSSL_SHA1
+       { "SHA", sha_verify, NULL },
+       { "SHA1", sha_verify, NULL },
+#endif
+       { "PLAIN", plain_verify, plain_generate },
+       { "HMAC-MD5", hmac_md5_verify, hmac_md5_generate },
+       { "DIGEST-MD5", digest_md5_verify, digest_md5_generate },
+       { "PLAIN-MD5", plain_md5_verify, plain_md5_generate },
+       { NULL, NULL, NULL }
+};
+
+void password_schemes_init(void)
+{
+       static const struct password_scheme null_scheme = { NULL, NULL, NULL };
+       const struct password_scheme *s;
+#ifdef HAVE_MODULES
+       struct module *mod;
+       const char *symbol;
+#endif
+
+       schemes_buf = buffer_create_dynamic(default_pool, 128, (size_t)-1);
+       for (s = default_schemes; s->name != NULL; s++)
+               buffer_append(schemes_buf, s, sizeof(*s));
+
+#ifdef HAVE_MODULES
+       scheme_modules = module_dir_load(AUTH_MODULE_DIR"/password", FALSE);
+       for (mod = scheme_modules; mod != NULL; mod = mod->next) {
+               t_push();
+               symbol = t_strconcat(mod->name, "_scheme", NULL);
+               s = module_get_symbol(mod, symbol);
+               if (s != NULL)
+                       buffer_append(schemes_buf, s, sizeof(*s));
+               t_pop();
        }
+#endif
 
-       return NULL;
+       buffer_append(schemes_buf, &null_scheme, sizeof(null_scheme));
+       schemes = buffer_get_data(schemes_buf, NULL);
+}
+
+void password_schemes_deinit(void)
+{
+#ifdef HAVE_MODULES
+       module_dir_unload(scheme_modules);
+#endif
+
+       buffer_free(schemes_buf);
+       schemes = NULL;
 }
index 0cd7750bb21ac1430ceeb0e3890e42c86d4b387c..e24c4fcbf42acb4554d77a6ccdb26b6aecc832e4 100644 (file)
@@ -1,6 +1,15 @@
 #ifndef __PASSWORD_SCHEME_H
 #define __PASSWORD_SCHEME_H
 
+struct password_scheme {
+       const char *name;
+
+       int (*password_verify)(const char *plaintext, const char *password,
+                              const char *user);
+       const char *(*password_generate)(const char *plaintext,
+                                        const char *user);
+};
+
 /* Returns 1 = matched, 0 = didn't match, -1 = unknown scheme */
 int password_verify(const char *plaintext, const char *password,
                    const char *scheme, const char *user);
@@ -12,6 +21,9 @@ const char *password_get_scheme(const char **password);
 const char *password_generate(const char *plaintext, const char *user,
                              const char *scheme);
 
+void password_schemes_init(void);
+void password_schemes_deinit(void);
+
 /* INTERNAL: */
 const char *password_generate_md5_crypt(const char *pw, const char *salt);
 const char *password_generate_cram_md5(const char *pw);
index edf4a62e7beb10bb6a8f8ed327da3c1a00e8c0fb..ede12e2578fa616220407d2d53c3e9e666304ccd 100644 (file)
@@ -111,7 +111,7 @@ static void main_init(void)
        commands_init();
 
        modules = getenv("MODULE_DIR") == NULL ? NULL :
-               module_dir_load(getenv("MODULE_DIR"));
+               module_dir_load(getenv("MODULE_DIR"), TRUE);
 
        str = getenv("IMAP_MAX_LINE_LENGTH");
        imap_max_line_length = str != NULL ?
index 1f98a99115e4e087f4afc23069e63e87f6003a10..e159c9058e11f34c2cd044a9201e2fd052756e5f 100644 (file)
 #  define RTLD_NOW 0
 #endif
 
-static void *get_symbol(const char *path, void *handle, const char *symbol)
+void *module_get_symbol(struct module *module, const char *symbol)
 {
        const char *error;
        void *ret;
 
        /* get our init func */
-       ret = dlsym(handle, symbol);
+       ret = dlsym(module->handle, symbol);
 
        error = dlerror();
        if (error != NULL) {
-               i_error("module %s: dlsym(%s) failed: %s", path, symbol, error);
+               i_error("module %s: dlsym(%s) failed: %s",
+                       module->path, symbol, error);
                ret = NULL;
        }
 
        return ret;
 }
 
-static struct module *module_load(const char *path, const char *name)
+static void module_free(struct module *module)
+{
+       if (module->deinit != NULL)
+               module->deinit();
+       if (dlclose(module->handle) != 0)
+               i_error("dlclose(%s) failed: %m", module->path);
+       i_free(module->path);
+       i_free(module->name);
+       i_free(module);
+}
+
+static struct module *
+module_load(const char *path, const char *name, int require_init_funcs)
 {
        void *handle;
        void (*init)(void);
-       void (*deinit)(void);
        struct module *module;
 
        handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
@@ -47,27 +59,29 @@ static struct module *module_load(const char *path, const char *name)
                return NULL;
        }
 
+       module = i_new(struct module, 1);
+       module->path = i_strdup(path);
+       module->name = i_strdup(name);
+       module->handle = handle;
+
        /* get our init func */
-       init = (void (*)()) get_symbol(path, handle,
-                                      t_strconcat(name, "_init", NULL));
-       deinit = init == NULL ? NULL :
-               (void (*)()) get_symbol(path, handle,
-                                       t_strconcat(name, "_deinit", NULL));
-
-       if (init == NULL || deinit == NULL) {
-               (void)dlclose(handle);
+       init = (void (*)())
+               module_get_symbol(module, t_strconcat(name, "_init", NULL));
+       module->deinit = init == NULL ? NULL : (void (*)())
+               module_get_symbol(module, t_strconcat(name, "_deinit", NULL));
+
+       if ((init == NULL || module->deinit == NULL) && require_init_funcs) {
+               module->deinit = NULL;
+               module_free(module);
                return NULL;
        }
 
-       init();
-
-       module = i_new(struct module, 1);
-       module->handle = handle;
-       module->deinit = deinit;
+       if (init != NULL)
+               init();
        return module;
 }
 
-struct module *module_dir_load(const char *dir)
+struct module *module_dir_load(const char *dir, int require_init_funcs)
 {
        DIR *dirp;
        struct dirent *d;
@@ -97,7 +111,7 @@ struct module *module_dir_load(const char *dir)
                t_push();
                name = t_strdup_until(d->d_name, p);
                path = t_strconcat(dir, "/", d->d_name, NULL);
-               module = module_load(path, name);
+               module = module_load(path, name, require_init_funcs);
                t_pop();
 
                if (module != NULL) {
@@ -118,10 +132,7 @@ void module_dir_unload(struct module *modules)
 
        while (modules != NULL) {
                next = modules->next;
-               modules->deinit();
-               if (dlclose(modules->handle) != 0)
-                       i_error("dlclose() failed: %m");
-               i_free(modules);
+               module_free(modules);
                modules = next;
        }
 }
index 53b293c61bb1374355a76fce01b5f37ea7181a66..615fd4169b4cb878911d96c7e0aed2e985abcb5d 100644 (file)
@@ -2,6 +2,8 @@
 #define __MODULE_DIR_H
 
 struct module {
+       char *path, *name;
+
        void *handle;
        void (*deinit)(void);
 
@@ -9,8 +11,10 @@ struct module {
 };
 
 /* Load all modules in given directory. */
-struct module *module_dir_load(const char *dir);
+struct module *module_dir_load(const char *dir, int require_init_funcs);
 /* Unload all modules */
 void module_dir_unload(struct module *modules);
 
+void *module_get_symbol(struct module *module, const char *symbol);
+
 #endif
index b254f478805c0b6cf603ece23477afb9f533c887..e66724944fb2ef3846264bda554c5daa74dec802 100644 (file)
@@ -86,7 +86,7 @@ static int main_init(void)
        clients_init();
 
        modules = getenv("MODULE_DIR") == NULL ? NULL :
-               module_dir_load(getenv("MODULE_DIR"));
+               module_dir_load(getenv("MODULE_DIR"), TRUE);
 
        mail = getenv("MAIL");
        if (mail == NULL) {