passdb.c revision 9ed2951bd0bb1878a27437d7c00611b2baadd614
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "auth-common.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "array.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "password-scheme.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "auth-worker-server.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include "passdb.h"
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher#include <stdlib.h>
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic ARRAY_DEFINE(passdb_interfaces, struct passdb_module_interface *);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic ARRAY_DEFINE(passdb_modules, struct passdb_module *);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct passdb_module_interface *passdb_interface_find(const char *name)
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher{
33396dc46ea52c18f47db1b5d590880806521005Sumit Bose struct passdb_module_interface *const *ifaces;
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher
33396dc46ea52c18f47db1b5d590880806521005Sumit Bose array_foreach(&passdb_interfaces, ifaces) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct passdb_module_interface *iface = *ifaces;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(iface->name, name) == 0)
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher return iface;
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher }
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher return NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid passdb_register_module(struct passdb_module_interface *iface)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct passdb_module_interface *old_iface;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher old_iface = passdb_interface_find(iface->name);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (old_iface != NULL && old_iface->verify_plain == NULL) {
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher /* replacing a "support not compiled in" passdb */
cc98edd9479d4622634a1275c98058916c14059aStephen Gallagher passdb_unregister_module(old_iface);
ee359fe1384507fed6c2274e7bfe81d288de4542Stephen Gallagher } else if (old_iface != NULL) {
cc98edd9479d4622634a1275c98058916c14059aStephen Gallagher i_panic("passdb_register_module(%s): Already registered",
1183d29d87c5c7439cf2364b7d7324d4a13b6e35Stephen Gallagher iface->name);
1183d29d87c5c7439cf2364b7d7324d4a13b6e35Stephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_append(&passdb_interfaces, &iface, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid passdb_unregister_module(struct passdb_module_interface *iface)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct passdb_module_interface *const *ifaces;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int idx;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_foreach(&passdb_interfaces, ifaces) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*ifaces == iface) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher idx = array_foreach_idx(&passdb_interfaces, ifaces);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_delete(&passdb_interfaces, idx, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return;
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce }
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce }
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce i_panic("passdb_unregister_module(%s): Not registered", iface->name);
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce}
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorce
c89589fa349f38214c9cb8d9389c0fd557e5dca2Simo Sorcebool passdb_get_credentials(struct auth_request *auth_request,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *input, const char *input_scheme,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const unsigned char **credentials_r, size_t *size_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *wanted_scheme = auth_request->credentials_scheme;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *plaintext, *username;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher int ret;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (auth_request->prefer_plain_credentials &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher password_scheme_is_alias(input_scheme, "PLAIN")) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we've a plaintext scheme and we prefer to get it instead
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher of converting it to the fallback scheme */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher wanted_scheme = "";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
d921c1eba437662437847279f251a0a5d8f70127Maxim
d921c1eba437662437847279f251a0a5d8f70127Maxim ret = password_decode(input, input_scheme, credentials_r, size_r);
d921c1eba437662437847279f251a0a5d8f70127Maxim if (ret <= 0) {
d921c1eba437662437847279f251a0a5d8f70127Maxim if (ret < 0) {
d921c1eba437662437847279f251a0a5d8f70127Maxim auth_request_log_error(auth_request, "password",
d921c1eba437662437847279f251a0a5d8f70127Maxim "Password in passdb is not in expected scheme %s",
d921c1eba437662437847279f251a0a5d8f70127Maxim input_scheme);
327127bb7fcc07f882209f029e14026de1b23c94Maxim } else {
327127bb7fcc07f882209f029e14026de1b23c94Maxim auth_request_log_error(auth_request, "password",
327127bb7fcc07f882209f029e14026de1b23c94Maxim "Unknown scheme %s", input_scheme);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (*wanted_scheme == '\0') {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* anything goes. change the credentials_scheme to what we
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher actually got, so blocking passdbs work. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request->credentials_scheme =
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher p_strdup(auth_request->pool, input_scheme);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return TRUE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!password_scheme_is_alias(input_scheme, wanted_scheme)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!password_scheme_is_alias(input_scheme, "PLAIN")) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *error = t_strdup_printf(
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Requested %s scheme, but we have only %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher wanted_scheme, input_scheme);
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek if (auth_request->set->debug_passwords) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher error = t_strdup_printf("%s (input: %s)",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher error, input);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_info(auth_request, "password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "%s", error);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we can generate anything out of plaintext passwords */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher plaintext = t_strndup(*credentials_r, *size_r);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher username = auth_request->original_username;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!auth_request->domain_is_realm &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher strchr(username, '@') != NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* domain must not be used as realm. add the @realm. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher username = t_strconcat(username, "@",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request->realm, NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (auth_request->set->debug_passwords) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_debug(auth_request, "password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Generating %s from user '%s', password '%s'",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher wanted_scheme, username, plaintext);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!password_generate(plaintext, username,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher wanted_scheme, credentials_r, size_r)) {
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek auth_request_log_error(auth_request, "password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Requested unknown scheme %s", wanted_scheme);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return FALSE;
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek }
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek }
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek
e6e26182d58c05d896f72f2925426658a6dc70b5Jakub Hrozek return TRUE;
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallaghervoid passdb_handle_credentials(enum passdb_result result,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const char *password, const char *scheme,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher lookup_credentials_callback_t *callback,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct auth_request *auth_request)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const unsigned char *credentials;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher size_t size = 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (result != PASSDB_RESULT_OK) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher callback(result, NULL, 0, auth_request);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (password == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request_log_info(auth_request, "password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "Requested %s scheme, but we have a NULL password",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher auth_request->credentials_scheme);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (!passdb_get_credentials(auth_request, password, scheme,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher &credentials, &size)) {
6f51c802311fd81a409a26763ed45b28a3234d0dJakub Hrozek result = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
6f51c802311fd81a409a26763ed45b28a3234d0dJakub Hrozek }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher callback(result, credentials, size, auth_request);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic struct passdb_module *
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherpassdb_find(const char *driver, const char *args, unsigned int *idx_r)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct passdb_module *const *passdbs;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher unsigned int i, count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdbs = array_get(&passdb_modules, &count);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (i = 0; i < count; i++) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (strcmp(passdbs[i]->iface.name, driver) == 0 &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher strcmp(passdbs[i]->args, args) == 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *idx_r = i;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return passdbs[i];
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
5352c9b3609bca63814f9f6f03dbbbadf6c6333aStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return NULL;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher}
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozekstruct passdb_module *
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozekpassdb_preinit(pool_t pool, const char *driver, const char *args)
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek{
2a5790216f57e9bdfb2930d52860bb5300366536Jakub Hrozek static unsigned int auth_passdb_id = 0;
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek struct passdb_module_interface *iface;
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek struct passdb_module *passdb;
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek unsigned int idx;
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek iface = passdb_interface_find(driver);
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek if (iface == NULL)
172c07013d1ea99447a780fd36f49d5c3a76981bJakub Hrozek i_fatal("Unknown passdb driver '%s'", driver);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (iface->verify_plain == NULL) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("Support not compiled in for passdb driver '%s'",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher driver);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher }
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (iface->preinit == NULL && iface->init == NULL && *args != '\0')
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_fatal("passdb %s: No args are supported: %s", driver, args);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb = passdb_find(driver, args, &idx);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (passdb != NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return passdb;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (iface->preinit == NULL)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb = p_new(pool, struct passdb_module, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher else
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb = iface->preinit(pool, args);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb->id = ++auth_passdb_id;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb->iface = *iface;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher passdb->args = p_strdup(pool, args);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_append(&passdb_modules, &passdb, 1);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return passdb;
96c73559adfbdac96720008fc022cb1d540b53c3Jakub Hrozek}
6f51c802311fd81a409a26763ed45b28a3234d0dJakub Hrozek
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallaghervoid passdb_init(struct passdb_module *passdb)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher{
if (passdb->iface.init != NULL && passdb->init_refcount == 0)
passdb->iface.init(passdb);
passdb->init_refcount++;
i_assert(passdb->default_pass_scheme != NULL ||
passdb->cache_key == NULL);
}
void passdb_deinit(struct passdb_module *passdb)
{
unsigned int idx;
i_assert(passdb->init_refcount > 0);
if (--passdb->init_refcount > 0)
return;
if (passdb_find(passdb->iface.name, passdb->args, &idx) == NULL)
i_unreached();
array_delete(&passdb_modules, idx, 1);
if (passdb->iface.deinit != NULL)
passdb->iface.deinit(passdb);
}
extern struct passdb_module_interface passdb_passwd;
extern struct passdb_module_interface passdb_bsdauth;
extern struct passdb_module_interface passdb_shadow;
extern struct passdb_module_interface passdb_passwd_file;
extern struct passdb_module_interface passdb_pam;
extern struct passdb_module_interface passdb_checkpassword;
extern struct passdb_module_interface passdb_vpopmail;
extern struct passdb_module_interface passdb_ldap;
extern struct passdb_module_interface passdb_sql;
extern struct passdb_module_interface passdb_sia;
void passdbs_init(void)
{
i_array_init(&passdb_interfaces, 16);
i_array_init(&passdb_modules, 16);
passdb_register_module(&passdb_passwd);
passdb_register_module(&passdb_bsdauth);
passdb_register_module(&passdb_passwd_file);
passdb_register_module(&passdb_pam);
passdb_register_module(&passdb_checkpassword);
passdb_register_module(&passdb_shadow);
passdb_register_module(&passdb_vpopmail);
passdb_register_module(&passdb_ldap);
passdb_register_module(&passdb_sql);
passdb_register_module(&passdb_sia);
}
void passdbs_deinit(void)
{
array_free(&passdb_modules);
array_free(&passdb_interfaces);
}