userdb.c revision 9261dbf0675204898c6557591c7aa376e23a52b2
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-worker-server.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "userdb.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen#include <stdlib.h>
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#include <pwd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <grp.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainenstatic ARRAY_DEFINE(userdb_interfaces, struct userdb_module_interface *);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic ARRAY_DEFINE(userdb_modules, struct userdb_module *);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct userdb_module_interface *userdb_interface_find(const char *name)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct userdb_module_interface *const *ifaces;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen struct userdb_module_interface *iface = *ifaces;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (strcmp(iface->name, name) == 0)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return iface;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid userdb_register_module(struct userdb_module_interface *iface)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct userdb_module_interface *old_iface;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_iface = userdb_interface_find(iface->name);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (old_iface != NULL && old_iface->lookup == NULL) {
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen /* replacing a "support not compiled in" userdb */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen userdb_unregister_module(old_iface);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen } else if (old_iface != NULL) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_panic("userdb_register_module(%s): Already registered",
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen iface->name);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&userdb_interfaces, &iface, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenvoid userdb_unregister_module(struct userdb_module_interface *iface)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct userdb_module_interface *const *ifaces;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen unsigned int idx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (*ifaces == iface) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen idx = array_foreach_idx(&userdb_interfaces, ifaces);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_delete(&userdb_interfaces, idx, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("userdb_unregister_module(%s): Not registered", iface->name);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenuid_t userdb_parse_uid(struct auth_request *request, const char *str)
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct passwd *pw;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uid_t uid;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen if (str == NULL)
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen return (uid_t)-1;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (str_to_uid(str, &uid) == 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pw = getpwnam(str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (pw == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (request != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_error(request, "userdb",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Invalid UID value '%s'", str);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return (uid_t)-1;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return pw->pw_uid;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen}
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainengid_t userdb_parse_gid(struct auth_request *request, const char *str)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen struct group *gr;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen gid_t gid;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (str == NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return (gid_t)-1;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (str_to_gid(str, &gid) == 0)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return gid;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen gr = getgrnam(str);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (gr == NULL) {
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (request != NULL) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen auth_request_log_error(request, "userdb",
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen "Invalid GID value '%s'", str);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen }
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return (gid_t)-1;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return gr->gr_gid;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic struct userdb_module *
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenuserdb_find(const char *driver, const char *args, unsigned int *idx_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen struct userdb_module *const *userdbs;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen unsigned int i, count;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen userdbs = array_get(&userdb_modules, &count);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen for (i = 0; i < count; i++) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (strcmp(userdbs[i]->iface->name, driver) == 0 &&
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen strcmp(userdbs[i]->args, args) == 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen *idx_r = i;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return userdbs[i];
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen }
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen return NULL;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstruct userdb_module *
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenuserdb_preinit(pool_t pool, const char *driver, const char *args)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen static unsigned int auth_userdb_id = 0;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct userdb_module_interface *iface;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen struct userdb_module *userdb;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen unsigned int idx;
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen iface = userdb_interface_find(driver);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (iface == NULL)
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen i_fatal("Unknown userdb driver '%s'", driver);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (iface->lookup == NULL) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_fatal("Support not compiled in for userdb driver '%s'",
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen driver);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen }
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen if (iface->preinit == NULL && iface->init == NULL && *args != '\0')
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen i_fatal("userdb %s: No args are supported: %s", driver, args);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen userdb = userdb_find(driver, args, &idx);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (userdb != NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return userdb;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (iface->preinit == NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen userdb = p_new(pool, struct userdb_module, 1);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen else
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen userdb = iface->preinit(pool, args);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->id = ++auth_userdb_id;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->iface = iface;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->args = p_strdup(pool, args);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen array_append(&userdb_modules, &userdb, 1);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return userdb;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenvoid userdb_init(struct userdb_module *userdb)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (userdb->iface->init != NULL && userdb->init_refcount == 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->iface->init(userdb);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->init_refcount++;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen}
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainenvoid userdb_deinit(struct userdb_module *userdb)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen unsigned int idx;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_assert(userdb->init_refcount > 0);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (--userdb->init_refcount > 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen return;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (userdb_find(userdb->iface->name, userdb->args, &idx) == NULL)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_unreached();
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen array_delete(&userdb_modules, idx, 1);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (userdb->iface->deinit != NULL)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen userdb->iface->deinit(userdb);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenvoid userdbs_generate_md5(unsigned char md5[MD5_RESULTLEN])
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen struct md5_context ctx;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen struct userdb_module *const *userdbs;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen unsigned int i, count;
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen md5_init(&ctx);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen userdbs = array_get(&userdb_modules, &count);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen for (i = 0; i < count; i++) {
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen md5_update(&ctx, &userdbs[i]->id, sizeof(userdbs[i]->id));
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen md5_update(&ctx, userdbs[i]->iface->name,
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen strlen(userdbs[i]->iface->name));
367c05967091a2cbfce59b7f274f55b1a0f9e8c9Timo Sirainen md5_update(&ctx, userdbs[i]->args, strlen(userdbs[i]->args));
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen md5_final(&ctx, md5);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenextern struct userdb_module_interface userdb_prefetch;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenextern struct userdb_module_interface userdb_static;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenextern struct userdb_module_interface userdb_passwd;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenextern struct userdb_module_interface userdb_passwd_file;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenextern struct userdb_module_interface userdb_vpopmail;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenextern struct userdb_module_interface userdb_ldap;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainenextern struct userdb_module_interface userdb_sql;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenextern struct userdb_module_interface userdb_nss;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenextern struct userdb_module_interface userdb_checkpassword;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenvoid userdbs_init(void)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_array_init(&userdb_interfaces, 16);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen i_array_init(&userdb_modules, 16);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen userdb_register_module(&userdb_passwd);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_passwd_file);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_prefetch);
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen userdb_register_module(&userdb_static);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_vpopmail);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_ldap);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_sql);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_nss);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen userdb_register_module(&userdb_checkpassword);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenvoid userdbs_deinit(void)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen array_free(&userdb_modules);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen array_free(&userdb_interfaces);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen