userdb.c revision 9d75363d3fbabc2fbc2d80f06672e3ed8965804a
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "auth-common.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "auth-worker-server.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "userdb.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include <pwd.h>
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include <grp.h>
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainenstatic ARRAY_DEFINE(userdb_interfaces, struct userdb_module_interface *);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic ARRAY_DEFINE(userdb_modules, struct userdb_module *);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const struct userdb_module_interface userdb_iface_deinit = {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen .name = "deinit"
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen};
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic struct userdb_module_interface *userdb_interface_find(const char *name)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct userdb_module_interface *const *ifaces;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct userdb_module_interface *iface = *ifaces;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(iface->name, name) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return iface;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return NULL;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid userdb_register_module(struct userdb_module_interface *iface)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen struct userdb_module_interface *old_iface;
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen old_iface = userdb_interface_find(iface->name);
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen if (old_iface != NULL && old_iface->lookup == NULL) {
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen /* replacing a "support not compiled in" userdb */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen userdb_unregister_module(old_iface);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen } else if (old_iface != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_panic("userdb_register_module(%s): Already registered",
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen iface->name);
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen array_append(&userdb_interfaces, &iface, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainenvoid userdb_unregister_module(struct userdb_module_interface *iface)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen struct userdb_module_interface *const *ifaces;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen unsigned int idx;
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (*ifaces == iface) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen idx = array_foreach_idx(&userdb_interfaces, ifaces);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_delete(&userdb_interfaces, idx, 1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen }
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen i_panic("userdb_unregister_module(%s): Not registered", iface->name);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen}
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenuid_t userdb_parse_uid(struct auth_request *request, const char *str)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen{
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen struct passwd *pw;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen uid_t uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str == NULL)
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen return (uid_t)-1;
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str_to_uid(str, &uid) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen pw = getpwnam(str);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (pw == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (request != NULL) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen auth_request_log_error(request, "userdb",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Invalid UID value '%s'", str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return (uid_t)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return pw->pw_uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainengid_t userdb_parse_gid(struct auth_request *request, const char *str)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct group *gr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen gid_t gid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return (gid_t)-1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (str_to_gid(str, &gid) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return gid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen gr = getgrnam(str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (gr == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (request != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_error(request, "userdb",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "Invalid GID value '%s'", str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return (gid_t)-1;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return gr->gr_gid;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenstatic struct userdb_module *
b34fdb68d376d85b4880da4a4bdf67ae726a381bTimo Sirainenuserdb_find(const char *driver, const char *args, unsigned int *idx_r)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct userdb_module *const *userdbs;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdbs = array_get(&userdb_modules, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(userdbs[i]->iface->name, driver) == 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(userdbs[i]->args, args) == 0) {
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen *idx_r = i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return userdbs[i];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct userdb_module *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenuserdb_preinit(pool_t pool, const char *driver, const char *args)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen static unsigned int auth_userdb_id = 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct userdb_module_interface *iface;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct userdb_module *userdb;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int idx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen iface = userdb_interface_find(driver);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (iface == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("Unknown userdb driver '%s'", driver);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (iface->lookup == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("Support not compiled in for userdb driver '%s'",
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen driver);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (iface->preinit == NULL && iface->init == NULL && *args != '\0')
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen i_fatal("userdb %s: No args are supported: %s", driver, args);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen userdb = userdb_find(driver, args, &idx);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (userdb != NULL)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return userdb;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if (iface->preinit == NULL)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen userdb = p_new(pool, struct userdb_module, 1);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen else
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen userdb = iface->preinit(pool, args);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen userdb->id = ++auth_userdb_id;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen userdb->iface = iface;
714d59900e44e6e2dd744bd7b76862e1d11a4f61Timo Sirainen userdb->args = p_strdup(pool, args);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen array_append(&userdb_modules, &userdb, 1);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen return userdb;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen}
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainenvoid userdb_init(struct userdb_module *userdb)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen{
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen if (userdb->iface->init != NULL && userdb->init_refcount == 0)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen userdb->iface->init(userdb);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen userdb->init_refcount++;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen}
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainenvoid userdb_deinit(struct userdb_module *userdb)
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int idx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(userdb->init_refcount > 0);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (--userdb->init_refcount > 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (userdb_find(userdb->iface->name, userdb->args, &idx) == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_unreached();
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen array_delete(&userdb_modules, idx, 1);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (userdb->iface->deinit != NULL)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen userdb->iface->deinit(userdb);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* make sure userdb isn't accessed again */
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen userdb->iface = &userdb_iface_deinit;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid userdbs_generate_md5(unsigned char md5[MD5_RESULTLEN])
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen struct md5_context ctx;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen struct userdb_module *const *userdbs;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen unsigned int i, count;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen md5_init(&ctx);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen userdbs = array_get(&userdb_modules, &count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen for (i = 0; i < count; i++) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen md5_update(&ctx, &userdbs[i]->id, sizeof(userdbs[i]->id));
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen md5_update(&ctx, userdbs[i]->iface->name,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen strlen(userdbs[i]->iface->name));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen md5_update(&ctx, userdbs[i]->args, strlen(userdbs[i]->args));
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen md5_final(&ctx, md5);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenextern struct userdb_module_interface userdb_prefetch;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenextern struct userdb_module_interface userdb_static;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_passwd;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_passwd_file;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_vpopmail;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_ldap;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_sql;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_nss;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenextern struct userdb_module_interface userdb_checkpassword;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid userdbs_init(void)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_array_init(&userdb_interfaces, 16);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_array_init(&userdb_modules, 16);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_passwd);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_passwd_file);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_prefetch);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_static);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_vpopmail);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_ldap);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_sql);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_nss);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen userdb_register_module(&userdb_checkpassword);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid userdbs_deinit(void)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_free(&userdb_modules);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen array_free(&userdb_interfaces);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen