conn->auth->set->debug_passwords ? line :
auth_line_hide_pass(line));
}
- return auth_request_handler_auth_begin(conn->auth,
- conn->request_handler,
+ return auth_request_handler_auth_begin(conn->request_handler,
line + 5);
}
if (strncmp(line, "CONT\t", 5) == 0) {
return -1;
}
- auth_request = auth_request_new_dummy(conn->auth);
+ auth_request = auth_request_new_dummy();
auth_request->id = (unsigned int)strtoul(list[0], NULL, 10);
auth_request->context = conn;
auth_master_connection_ref(conn);
auth_request_unref(&auth_request);
return -1;
}
+
+ auth_request_init(auth_request);
*request_r = auth_request;
return 1;
}
}
}
-bool auth_request_handler_auth_begin(struct auth *auth,
- struct auth_request_handler *handler,
+bool auth_request_handler_auth_begin(struct auth_request_handler *handler,
const char *args)
{
const struct mech_module *mech;
return FALSE;
}
- request = auth_request_new(auth, mech, auth_callback, handler);
+ request = auth_request_new(mech, auth_callback, handler);
request->handler = handler;
request->connect_uid = handler->connect_uid;
request->client_pid = handler->client_pid;
auth_request_unref(&request);
return FALSE;
}
+ auth_request_init(request);
request->to_abort = timeout_add(AUTH_REQUEST_TIMEOUT * 1000,
auth_request_timeout, request);
hash_table_insert(handler->requests, POINTER_CAST(id), request);
- if (request->auth->set->ssl_require_client_cert &&
+ if (request->set->ssl_require_client_cert &&
!request->valid_client_cert) {
/* we fail without valid certificate */
auth_request_handler_auth_fail(handler, request,
/* FIXME: assumess that failure_delay is always the same. */
diff = ioloop_time - auth_request->last_access;
- if (diff < (time_t)auth_request->auth->set->failure_delay &&
+ if (diff < (time_t)auth_request->set->failure_delay &&
!flush_all)
break;
unsigned int connect_uid,
unsigned int client_pid);
-bool auth_request_handler_auth_begin(struct auth *auth,
- struct auth_request_handler *handler,
+bool auth_request_handler_auth_begin(struct auth_request_handler *handler,
const char *args);
bool auth_request_handler_auth_continue(struct auth_request_handler *handler,
const char *args);
const char *subsystem);
struct auth_request *
-auth_request_new(struct auth *auth, const struct mech_module *mech,
+auth_request_new(const struct mech_module *mech,
mech_callback_t *callback, void *context)
{
struct auth_request *request;
request = mech->auth_new();
request->state = AUTH_REQUEST_STATE_NEW;
- request->passdb = auth->passdbs;
- request->userdb = auth->userdbs;
request->refcount = 1;
request->last_access = ioloop_time;
- request->auth = auth;
+ request->set = global_auth_settings;
request->mech = mech;
request->mech_name = mech == NULL ? NULL : mech->mech_name;
request->callback = callback;
return request;
}
-struct auth_request *auth_request_new_dummy(struct auth *auth)
+struct auth_request *auth_request_new_dummy(void)
{
struct auth_request *auth_request;
pool_t pool;
auth_request->refcount = 1;
auth_request->last_access = ioloop_time;
-
- if (auth == NULL) {
- auth = p_new(pool, struct auth, 1);
- auth->set = global_auth_settings;
- }
- auth_request->auth = auth;
- auth_request->passdb = auth->passdbs;
- auth_request->userdb = auth->userdbs;
+ auth_request->set = global_auth_settings;
return auth_request;
}
+void auth_request_init(struct auth_request *request)
+{
+ struct auth *auth;
+
+ auth = auth_request_get_auth(request);
+ request->set = auth->set;
+ request->passdb = auth->passdbs;
+ request->userdb = auth->userdbs;
+}
+
+struct auth *auth_request_get_auth(struct auth_request *request)
+{
+ return auth_find_service(request->service);
+}
+
void auth_request_success(struct auth_request *request,
const void *data, size_t data_size)
{
else if (strcmp(key, "original_username") == 0)
request->original_username = p_strdup(request->pool, value);
else if (strcmp(key, "cert_username") == 0) {
- if (request->auth->set->ssl_username_from_cert) {
+ if (request->set->ssl_username_from_cert) {
/* get username from SSL certificate. it overrides
the username given by the auth mechanism. */
request->user = p_strdup(request->pool, value);
/* the authentication continues with passdb lookup for the
requested_login_user. */
- request->passdb = request->auth->passdbs;
+ request->passdb = auth_request_get_auth(request)->passdbs;
return FALSE;
}
request->credentials_scheme,
request->private_callback.lookup_credentials);
} else {
- if (request->auth->set->debug_passwords &&
+ if (request->set->debug_passwords &&
result == PASSDB_RESULT_OK) {
auth_request_log_debug(request, "password",
"Credentials: %s",
request->client_pid != 0) {
/* this was an actual login attempt, the user should
have been found. */
- if (request->auth->userdbs->next == NULL) {
+ if (auth_request_get_auth(request)->userdbs->next == NULL) {
auth_request_log_error(request, "userdb",
"user not found from userdb %s",
- request->auth->userdbs->userdb->iface->name);
+ request->userdb->userdb->iface->name);
} else {
auth_request_log_error(request, "userdb",
"user not found from any userdbs");
auth_request_fix_username(struct auth_request *request, const char *username,
const char **error_r)
{
- const struct auth_settings *set = request->auth->set;
+ const struct auth_settings *set = request->set;
unsigned char *p;
char *user;
bool auth_request_set_username(struct auth_request *request,
const char *username, const char **error_r)
{
- const struct auth_settings *set = request->auth->set;
+ const struct auth_settings *set = request->set;
const char *p, *login_username = NULL;
if (*set->master_user_separator != '\0' && !request->userdb_lookup) {
}
/* lookup request->user from masterdb first */
- request->passdb = request->auth->masterdbs;
+ request->passdb = auth_request_get_auth(request)->masterdbs;
request->requested_login_user =
auth_request_fix_username(request, username, error_r);
const char *subsystem)
{
string_t *str;
- const char *log_type = request->auth->set->verbose_passwords;
+ const char *log_type = request->set->verbose_passwords;
if (strcmp(log_type, "no") == 0) {
auth_request_log_info(request, subsystem, "Password mismatch");
i_assert(ret >= 0);
if (ret == 0) {
auth_request_log_password_mismatch(request, subsystem);
- if (request->auth->set->debug_passwords) T_BEGIN {
+ if (request->set->debug_passwords) T_BEGIN {
log_password_failure(request, plain_password,
crypted_password, scheme,
request->original_username,
{
va_list va;
- if (!auth_request->auth->set->debug)
+ if (!auth_request->set->debug)
return;
va_start(va, format);
{
va_list va;
- if (!auth_request->auth->set->verbose)
+ if (!auth_request->set->verbose)
return;
va_start(va, format);
const struct mech_module *mech;
struct auth_request_handler *handler;
- struct auth *auth;
+ const struct auth_settings *set;
struct auth_passdb *passdb;
struct auth_userdb *userdb;
};
struct auth_request *
-auth_request_new(struct auth *auth, const struct mech_module *mech,
+auth_request_new(const struct mech_module *mech,
mech_callback_t *callback, void *context);
-struct auth_request *auth_request_new_dummy(struct auth *auth);
+struct auth_request *auth_request_new_dummy(void);
+void auth_request_init(struct auth_request *request);
+struct auth *auth_request_get_auth(struct auth_request *request);
+
void auth_request_ref(struct auth_request *request);
void auth_request_unref(struct auth_request **request);
#include "lib.h"
#include "array.h"
#include "settings-parser.h"
+#include "master-service.h"
#include "master-service-settings.h"
#include "service-settings.h"
#include "auth-settings.h"
struct auth_settings *global_auth_settings;
-struct auth_settings *
-auth_settings_read(struct master_service *service)
+struct auth_settings *auth_settings_read(const char *service)
{
static const struct setting_parser_info *set_roots[] = {
&auth_setting_parser_info,
NULL
};
+ struct master_service_settings_input input;
+ struct master_service_settings_output output;
const char *error;
void **sets;
- if (master_service_settings_read_simple(service, set_roots, &error) < 0)
+ memset(&input, 0, sizeof(input));
+ input.roots = set_roots;
+ input.module = "auth";
+ input.service = service;
+ if (master_service_settings_read(master_service, &input,
+ &output, &error) < 0)
i_fatal("Error reading configuration: %s", error);
- sets = master_service_settings_get_others(service);
+ sets = master_service_settings_get_others(master_service);
return sets[0];
}
extern struct auth_settings *global_auth_settings;
-struct auth_settings *auth_settings_read(struct master_service *service);
+struct auth_settings *auth_settings_read(const char *service);
#endif
struct auth_request *auth_request;
const char *key, *value, *const *tmp;
- auth_request = auth_request_new_dummy(client->auth);
+ auth_request = auth_request_new_dummy();
client->refcount++;
auth_request->context = client;
}
}
+ auth_request_init(auth_request);
return auth_request;
}
if (passdb == NULL) {
/* could be a masterdb */
- passdb = auth_request->auth->masterdbs;
+ passdb = auth_request_get_auth(auth_request)->masterdbs;
while (passdb != NULL && passdb->passdb->id != passdb_id)
passdb = passdb->next;
.args = ""
};
+static ARRAY_DEFINE(auths, struct auth *);
+
static void
auth_passdb_preinit(struct auth *auth, const struct auth_passdb_settings *set)
{
}
struct auth *
-auth_preinit(struct auth_settings *set, const struct mechanisms_register *reg)
+auth_preinit(const struct auth_settings *set, const char *service,
+ const struct mechanisms_register *reg)
{
struct auth_passdb_settings *const *passdbs;
struct auth_userdb_settings *const *userdbs;
pool = pool_alloconly_create("auth", 2048);
auth = p_new(pool, struct auth, 1);
auth->pool = pool;
+ auth->service = p_strdup(pool, service);
auth->set = set;
auth->reg = reg;
pool_unref(&auth->pool);
}
+
+struct auth *auth_find_service(const char *name)
+{
+ struct auth *const *a;
+ unsigned int i, count;
+
+ a = array_get(&auths, &count);
+ if (name != NULL) {
+ for (i = 1; i < count; i++) {
+ if (strcmp(a[i]->service, name) == 0)
+ return a[i];
+ }
+ }
+ return a[0];
+}
+
+void auths_preinit(const struct auth_settings *set,
+ const struct mechanisms_register *reg)
+{
+ static const char *services[] = {
+ "imap", "pop3", "lda", "lmtp", "managesieve"
+ };
+ const struct auth_settings *service_set;
+ struct auth *auth;
+ unsigned int i;
+
+ i_array_init(&auths, 8);
+
+ auth = auth_preinit(set, NULL, reg);
+ array_append(&auths, &auth, 1);
+
+ /* FIXME: this is ugly.. the service names should be coming from
+ the first config lookup */
+ for (i = 0; i < N_ELEMENTS(services); i++) {
+ service_set = auth_settings_read(services[i]);
+ auth = auth_preinit(service_set, services[i], reg);
+ array_append(&auths, &auth, 1);
+ }
+}
+
+void auths_init(void)
+{
+ struct auth *const *auth;
+
+ array_foreach(&auths, auth)
+ auth_init(*auth);
+}
+
+void auths_deinit(void)
+{
+ struct auth **auth;
+ unsigned int i, count;
+
+ /* deinit in reverse order, because modules have been allocated by
+ the first auth pool that used them */
+ auth = array_get_modifiable(&auths, &count);
+ for (i = count; i > 0; i--)
+ auth_deinit(&auth[i-1]);
+ array_free(&auths);
+}
struct auth {
pool_t pool;
+ const char *service;
const struct auth_settings *set;
const struct mechanisms_register *reg;
struct auth_userdb *userdbs;
};
+extern struct auth_penalty *auth_penalty;
+
struct auth *
-auth_preinit(struct auth_settings *set, const struct mechanisms_register *reg);
+auth_preinit(const struct auth_settings *set, const char *service,
+ const struct mechanisms_register *mech_reg);
void auth_init(struct auth *auth);
void auth_deinit(struct auth **auth);
+struct auth *auth_find_service(const char *name);
+
+void auths_preinit(const struct auth_settings *set,
+ const struct mechanisms_register *reg);
+void auths_init(void);
+void auths_deinit(void);
+
#endif
ctx->static_attrs = t_strsplit(str_c(str), ",");
}
- if (auth_request->auth->set->debug)
+ if (auth_request->set->debug)
ctx->debug = t_str_new(256);
ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
if (ctx->debug != NULL) {
if (!first)
str_append_c(ctx->debug, '/');
- if (ctx->auth_request->auth->set->debug_passwords ||
+ if (ctx->auth_request->set->debug_passwords ||
strcmp(ctx->name, "password") != 0)
str_append(ctx->debug, ctx->value);
else
struct auth_penalty *auth_penalty;
static struct module *modules = NULL;
-static struct auth *auth;
static struct mechanisms_register *mech_reg;
static ARRAY_DEFINE(listen_fd_types, enum auth_socket_type);
modules = module_dir_load(AUTH_MODULE_DIR, NULL, &mod_set);
module_dir_init(modules);
+ auth_penalty = auth_penalty_init(AUTH_PENALTY_ANVIL_PATH);
mech_init(global_auth_settings);
mech_reg = mech_register_init(global_auth_settings);
- auth = auth_preinit(global_auth_settings, mech_reg);
- auth_penalty = auth_penalty_init(AUTH_PENALTY_ANVIL_PATH);
+ auths_preinit(global_auth_settings, mech_reg);
/* Password lookups etc. may require roots, allow it. */
restrict_access_by_env(NULL, FALSE);
child_wait_init();
password_schemes_init();
auth_worker_server_init();
- auth_init(auth);
+ auths_init();
auth_request_handler_init();
auth_master_connections_init();
auth_client_connections_init();
auth_master_connections_deinit();
auth_worker_server_deinit();
- mech_deinit(auth->set);
- auth_deinit(&auth);
+ mech_deinit(global_auth_settings);
+ auths_deinit();
mech_register_deinit(&mech_reg);
auth_penalty_deinit(&auth_penalty);
(void)close(conn->fd);
return;
}
- (void)auth_worker_client_create(auth, conn->fd);
+
+ (void)auth_worker_client_create(auth_find_service(NULL), conn->fd);
}
static void client_connected(const struct master_service_connection *conn)
{
enum auth_socket_type *type;
const char *name, *suffix;
+ struct auth *auth;
type = array_idx_modifiable(&listen_fd_types, conn->listen_fd);
if (*type == AUTH_SOCKET_UNKNOWN) {
}
}
+ auth = auth_find_service(NULL);
switch (*type) {
case AUTH_SOCKET_MASTER:
(void)auth_master_connection_create(auth, conn->fd, FALSE);
}
}
- global_auth_settings = auth_settings_read(master_service);
+ global_auth_settings = auth_settings_read(NULL);
main_preinit();
master_service_init_finish(master_service);
mech_anonymous_auth_continue(struct auth_request *request,
const unsigned char *data, size_t data_size)
{
- i_assert(*request->auth->set->anonymous_username != '\0');
+ i_assert(*request->set->anonymous_username != '\0');
- if (request->auth->set->verbose) {
+ if (request->set->verbose) {
/* temporarily set the user to the one that was given,
so that the log message goes right */
request->user =
}
request->user = p_strdup(request->pool,
- request->auth->set->anonymous_username);
+ request->set->anonymous_username);
auth_request_success(request, NULL, 0);
}
static string_t *get_digest_challenge(struct digest_auth_request *request)
{
- struct auth *auth = request->auth_request.auth;
+ const struct auth_settings *set = request->auth_request.set;
buffer_t buf;
string_t *str;
const char *const *tmp;
request->nonce = p_strdup(request->pool, buf.data);
str = t_str_new(256);
- if (*auth->set->realms_arr == NULL) {
+ if (*set->realms_arr == NULL) {
/* If no realms are given, at least Cyrus SASL client defaults
to destination host name */
str_append(str, "realm=\"\",");
} else {
- for (tmp = auth->set->realms_arr; *tmp != NULL; tmp++)
+ for (tmp = set->realms_arr; *tmp != NULL; tmp++)
str_printfa(str, "realm=\"%s\",", *tmp);
}
mech_gssapi_initialize(request->auth);
}
- if (strcmp(request->auth->set->gssapi_hostname, "$ALL") == 0) {
+ if (strcmp(request->set->gssapi_hostname, "$ALL") == 0) {
auth_request_log_debug(request, "gssapi",
"Using all keytab entries");
*ret_r = GSS_C_NO_CREDENTIAL;
principal_name = t_str_new(128);
str_append(principal_name, service_name);
str_append_c(principal_name, '@');
- str_append(principal_name, request->auth->set->gssapi_hostname);
+ str_append(principal_name, request->set->gssapi_hostname);
auth_request_log_debug(request, "gssapi",
"Obtaining credentials for %s", str_c(principal_name));
static const unsigned char *
mech_rpa_build_token2(struct rpa_auth_request *request, size_t *size)
{
- struct auth *auth = request->auth_request.auth;
+ const struct auth_settings *set = request->auth_request.set;
unsigned int realms_len, length;
string_t *realms;
buffer_t *buf;
const char *const *tmp;
realms = t_str_new(64);
- for (tmp = auth->set->realms_arr; *tmp != NULL; tmp++) {
+ for (tmp = set->realms_arr; *tmp != NULL; tmp++) {
rpa_add_realm(realms, *tmp, request->auth_request.service);
}
if (str_len(realms) == 0) {
- rpa_add_realm(realms, *auth->set->default_realm != '\0' ?
- auth->set->default_realm : my_hostname,
+ rpa_add_realm(realms, *set->default_realm != '\0' ?
+ set->default_realm : my_hostname,
request->auth_request.service);
}
}
static void
-winbind_helper_connect(struct auth *auth, struct winbind_helper *winbind)
+winbind_helper_connect(const struct auth_settings *set,
+ struct winbind_helper *winbind)
{
int infd[2], outfd[2];
pid_t pid;
dup2(infd[1], STDOUT_FILENO) < 0)
i_fatal("dup2() failed: %m");
- args[0] = auth->set->winbind_helper_path;
+ args[0] = set->winbind_helper_path;
args[1] = winbind->param;
args[2] = NULL;
execv(args[0], (void *)args);
struct winbind_auth_request *request =
(struct winbind_auth_request *)auth_request;
- winbind_helper_connect(auth_request->auth, request->winbind);
+ winbind_helper_connect(auth_request->set, request->winbind);
mech_generic_auth_initial(auth_request, data, data_size);
}
{
const char *p;
- if (!request->auth->set->debug_passwords &&
+ if (!request->set->debug_passwords &&
*value != '\0' && *value != '\t') {
/* hide the password */
p = strchr(value, '\t');
passdb_result = PASSDB_RESULT_OK;
else if (ret == LDAP_INVALID_CREDENTIALS) {
str = "invalid credentials";
- if (auth_request->auth->set->debug_passwords) {
+ if (auth_request->set->debug_passwords) {
str = t_strconcat(str, " (given password: ",
auth_request->mech_password,
")", NULL);
auth_request_log_error(request, "pam", "%s", str);
} else if (status == PAM_AUTH_ERR) {
str = t_strconcat(str, " (password mismatch?)", NULL);
- if (request->auth->set->debug_passwords) {
+ if (request->set->debug_passwords) {
str = t_strconcat(str, " (given password: ",
request->mech_password,
")", NULL);
#include <stdlib.h>
static ARRAY_DEFINE(passdb_interfaces, struct passdb_module_interface *);
+static ARRAY_DEFINE(passdb_modules, struct passdb_module *);
static struct passdb_module_interface *passdb_interface_find(const char *name)
{
const char *error = t_strdup_printf(
"Requested %s scheme, but we have only %s",
wanted_scheme, input_scheme);
- if (auth_request->auth->set->debug_passwords) {
+ if (auth_request->set->debug_passwords) {
error = t_strdup_printf("%s (input: %s)",
error, input);
}
username = t_strconcat(username, "@",
auth_request->realm, NULL);
}
- if (auth_request->auth->set->debug_passwords) {
+ if (auth_request->set->debug_passwords) {
auth_request_log_debug(auth_request, "password",
"Generating %s from user '%s', password '%s'",
wanted_scheme, username, plaintext);
callback(result, credentials, size, auth_request);
}
+static struct passdb_module *
+passdb_find(const char *driver, const char *args, unsigned int *idx_r)
+{
+ struct passdb_module *const *passdbs;
+ unsigned int i, count;
+
+ passdbs = array_get(&passdb_modules, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(passdbs[i]->iface.name, driver) == 0 &&
+ strcmp(passdbs[i]->args, args) == 0) {
+ *idx_r = i;
+ return passdbs[i];
+ }
+ }
+ return NULL;
+}
+
struct passdb_module *
passdb_preinit(pool_t pool, const char *driver, const char *args)
{
static unsigned int auth_passdb_id = 0;
struct passdb_module_interface *iface;
struct passdb_module *passdb;
+ unsigned int idx;
iface = passdb_interface_find(driver);
if (iface == NULL)
i_fatal("Support not compiled in for passdb driver '%s'",
driver);
}
-
if (iface->preinit == NULL && iface->init == NULL && *args != '\0')
i_fatal("passdb %s: No args are supported: %s", driver, args);
+ passdb = passdb_find(driver, args, &idx);
+ if (passdb != NULL)
+ return passdb;
+
if (iface->preinit == NULL)
passdb = p_new(pool, struct passdb_module, 1);
else
passdb->id = ++auth_passdb_id;
passdb->iface = *iface;
passdb->args = p_strdup(pool, args);
+ array_append(&passdb_modules, &passdb, 1);
return passdb;
}
void passdb_init(struct passdb_module *passdb)
{
- if (passdb->iface.init != NULL && !passdb->initialized) {
- passdb->initialized = TRUE;
+ 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)
{
- i_assert(passdb->initialized);
+ 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);
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);
void passdbs_deinit(void)
{
+ array_free(&passdb_modules);
array_free(&passdb_interfaces);
}
/* id is used by blocking passdb to identify the passdb */
unsigned int id;
- struct passdb_module_interface iface;
+ /* number of time init() has been called */
+ int init_refcount;
- /* init() has been called */
- unsigned int initialized:1;
+ struct passdb_module_interface iface;
};
/* Try to get credentials in wanted scheme (request->credentials_scheme) from
request = &ctx->request;
request->ctx = ctx;
- request->request.request.auth_request = auth_request_new_dummy(NULL);
+ request->request.request.auth_request = auth_request_new_dummy();
request->request.base = conn->set.base;
request->request.filter = conn->set.iterate_filter;
request->request.attributes = conn->iterate_attr_names;
/* auth_request_set_field() should have already placed the userdb_*
values to userdb_reply. */
if (auth_request->userdb_reply == NULL) {
- if (auth_request->auth->userdbs->next == NULL) {
+ if (auth_request_get_auth(auth_request)->userdbs->next == NULL) {
/* no other userdbs */
if (auth_request->userdb_lookup) {
auth_request_log_error(auth_request, "prefetch",
"passdb didn't return userdb entries");
}
} else if (!auth_request->userdb_lookup ||
- auth_request->auth->set->debug) {
+ auth_request->set->debug) {
/* more userdbs, they may know the user */
auth_request_log_debug(auth_request, "prefetch",
"passdb didn't return userdb entries, "
#include <grp.h>
static ARRAY_DEFINE(userdb_interfaces, struct userdb_module_interface *);
+static ARRAY_DEFINE(userdb_modules, struct userdb_module *);
static struct userdb_module_interface *userdb_interface_find(const char *name)
{
return gr->gr_gid;
}
+static struct userdb_module *
+userdb_find(const char *driver, const char *args, unsigned int *idx_r)
+{
+ struct userdb_module *const *userdbs;
+ unsigned int i, count;
+
+ userdbs = array_get(&userdb_modules, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(userdbs[i]->iface->name, driver) == 0 &&
+ strcmp(userdbs[i]->args, args) == 0) {
+ *idx_r = i;
+ return userdbs[i];
+ }
+ }
+ return NULL;
+}
+
struct userdb_module *
userdb_preinit(pool_t pool, const char *driver, const char *args)
{
static unsigned int auth_userdb_id = 0;
struct userdb_module_interface *iface;
struct userdb_module *userdb;
+ unsigned int idx;
iface = userdb_interface_find(driver);
if (iface == NULL)
i_fatal("Support not compiled in for userdb driver '%s'",
driver);
}
-
if (iface->preinit == NULL && iface->init == NULL && *args != '\0')
i_fatal("userdb %s: No args are supported: %s", driver, args);
+ userdb = userdb_find(driver, args, &idx);
+ if (userdb != NULL)
+ return userdb;
+
if (iface->preinit == NULL)
userdb = p_new(pool, struct userdb_module, 1);
else
userdb->id = ++auth_userdb_id;
userdb->iface = iface;
userdb->args = p_strdup(pool, args);
+ array_append(&userdb_modules, &userdb, 1);
return userdb;
}
void userdb_init(struct userdb_module *userdb)
{
- if (userdb->iface->init != NULL && !userdb->initialized) {
- userdb->initialized = TRUE;
+ if (userdb->iface->init != NULL && userdb->init_refcount == 0)
userdb->iface->init(userdb);
- }
+ userdb->init_refcount++;
}
void userdb_deinit(struct userdb_module *userdb)
{
- i_assert(userdb->initialized);
+ unsigned int idx;
+
+ i_assert(userdb->init_refcount > 0);
+
+ if (--userdb->init_refcount > 0)
+ return;
+
+ if (userdb_find(userdb->iface->name, userdb->args, &idx) == NULL)
+ i_unreached();
+ array_delete(&userdb_modules, idx, 1);
+
if (userdb->iface->deinit != NULL)
userdb->iface->deinit(userdb);
}
void userdbs_init(void)
{
i_array_init(&userdb_interfaces, 16);
+ i_array_init(&userdb_modules, 16);
userdb_register_module(&userdb_passwd);
userdb_register_module(&userdb_passwd_file);
userdb_register_module(&userdb_prefetch);
void userdbs_deinit(void)
{
+ array_free(&userdb_modules);
array_free(&userdb_interfaces);
}
/* id is used by blocking userdb to identify the userdb */
unsigned int id;
- const struct userdb_module_interface *iface;
+ /* number of time init() has been called */
+ int init_refcount;
- /* init() has been called */
- unsigned int initialized:1;
+ const struct userdb_module_interface *iface;
};
struct userdb_iterate_context {