diff options
Diffstat (limited to 'src/auth/userdb.c')
-rw-r--r-- | src/auth/userdb.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/src/auth/userdb.c b/src/auth/userdb.c new file mode 100644 index 0000000..21751f9 --- /dev/null +++ b/src/auth/userdb.c @@ -0,0 +1,256 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "array.h" +#include "ipwd.h" +#include "auth-worker-server.h" +#include "userdb.h" + +static ARRAY(struct userdb_module_interface *) userdb_interfaces; +static ARRAY(struct userdb_module *) userdb_modules; + +static const struct userdb_module_interface userdb_iface_deinit = { + .name = "deinit" +}; + +static struct userdb_module_interface *userdb_interface_find(const char *name) +{ + struct userdb_module_interface *iface; + + array_foreach_elem(&userdb_interfaces, iface) { + if (strcmp(iface->name, name) == 0) + return iface; + } + return NULL; +} + +void userdb_register_module(struct userdb_module_interface *iface) +{ + struct userdb_module_interface *old_iface; + + old_iface = userdb_interface_find(iface->name); + if (old_iface != NULL && old_iface->lookup == NULL) { + /* replacing a "support not compiled in" userdb */ + userdb_unregister_module(old_iface); + } else if (old_iface != NULL) { + i_panic("userdb_register_module(%s): Already registered", + iface->name); + } + array_push_back(&userdb_interfaces, &iface); +} + +void userdb_unregister_module(struct userdb_module_interface *iface) +{ + struct userdb_module_interface *const *ifaces; + unsigned int idx; + + array_foreach(&userdb_interfaces, ifaces) { + if (*ifaces == iface) { + idx = array_foreach_idx(&userdb_interfaces, ifaces); + array_delete(&userdb_interfaces, idx, 1); + return; + } + } + i_panic("userdb_unregister_module(%s): Not registered", iface->name); +} + +uid_t userdb_parse_uid(struct auth_request *request, const char *str) +{ + struct passwd pw; + uid_t uid; + + if (str == NULL) + return (uid_t)-1; + + if (str_to_uid(str, &uid) == 0) + return uid; + + switch (i_getpwnam(str, &pw)) { + case -1: + e_error(request == NULL ? auth_event : authdb_event(request), + "getpwnam() failed: %m"); + return (uid_t)-1; + case 0: + e_error(request == NULL ? auth_event : authdb_event(request), + "Invalid UID value '%s'", str); + return (uid_t)-1; + default: + return pw.pw_uid; + } +} + +gid_t userdb_parse_gid(struct auth_request *request, const char *str) +{ + struct group gr; + gid_t gid; + + if (str == NULL) + return (gid_t)-1; + + if (str_to_gid(str, &gid) == 0) + return gid; + + switch (i_getgrnam(str, &gr)) { + case -1: + e_error(request == NULL ? auth_event : authdb_event(request), + "getgrnam() failed: %m"); + return (gid_t)-1; + case 0: + e_error(request == NULL ? auth_event : authdb_event(request), + "Invalid GID value '%s'", str); + return (gid_t)-1; + default: + 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 struct auth_userdb_settings *set) +{ + static unsigned int auth_userdb_id = 0; + struct userdb_module_interface *iface; + struct userdb_module *userdb; + unsigned int idx; + + iface = userdb_interface_find(set->driver); + if (iface == NULL || iface->lookup == NULL) { + /* maybe it's a plugin. try to load it. */ + auth_module_load(t_strconcat("authdb_", set->driver, NULL)); + iface = userdb_interface_find(set->driver); + } + if (iface == NULL) + i_fatal("Unknown userdb driver '%s'", set->driver); + if (iface->lookup == NULL) { + i_fatal("Support not compiled in for userdb driver '%s'", + set->driver); + } + if (iface->preinit == NULL && iface->init == NULL && + *set->args != '\0') { + i_fatal("userdb %s: No args are supported: %s", + set->driver, set->args); + } + + userdb = userdb_find(set->driver, set->args, &idx); + if (userdb != NULL) + return userdb; + + if (iface->preinit == NULL) + userdb = p_new(pool, struct userdb_module, 1); + else + userdb = iface->preinit(pool, set->args); + userdb->id = ++auth_userdb_id; + userdb->iface = iface; + userdb->args = p_strdup(pool, set->args); + + array_push_back(&userdb_modules, &userdb); + return userdb; +} + +void userdb_init(struct userdb_module *userdb) +{ + if (userdb->iface->init != NULL && userdb->init_refcount == 0) + userdb->iface->init(userdb); + userdb->init_refcount++; +} + +void userdb_deinit(struct userdb_module *userdb) +{ + 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); + + /* make sure userdb isn't accessed again */ + userdb->iface = &userdb_iface_deinit; +} + +void userdbs_generate_md5(unsigned char md5[STATIC_ARRAY MD5_RESULTLEN]) +{ + struct md5_context ctx; + struct userdb_module *const *userdbs; + unsigned int i, count; + + md5_init(&ctx); + userdbs = array_get(&userdb_modules, &count); + for (i = 0; i < count; i++) { + md5_update(&ctx, &userdbs[i]->id, sizeof(userdbs[i]->id)); + md5_update(&ctx, userdbs[i]->iface->name, + strlen(userdbs[i]->iface->name)); + md5_update(&ctx, userdbs[i]->args, strlen(userdbs[i]->args)); + } + md5_final(&ctx, md5); +} + +const char *userdb_result_to_string(enum userdb_result result) +{ + switch (result) { + case USERDB_RESULT_INTERNAL_FAILURE: + return "internal_failure"; + case USERDB_RESULT_USER_UNKNOWN: + return "user_unknown"; + case USERDB_RESULT_OK: + return "ok"; + } + i_unreached(); +} + +extern struct userdb_module_interface userdb_prefetch; +extern struct userdb_module_interface userdb_static; +extern struct userdb_module_interface userdb_passwd; +extern struct userdb_module_interface userdb_passwd_file; +extern struct userdb_module_interface userdb_ldap; +extern struct userdb_module_interface userdb_sql; +extern struct userdb_module_interface userdb_checkpassword; +extern struct userdb_module_interface userdb_dict; +#ifdef HAVE_LUA +extern struct userdb_module_interface userdb_lua; +#endif + +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); + userdb_register_module(&userdb_static); + userdb_register_module(&userdb_ldap); + userdb_register_module(&userdb_sql); + userdb_register_module(&userdb_checkpassword); + userdb_register_module(&userdb_dict); +#ifdef HAVE_LUA + userdb_register_module(&userdb_lua); +#endif +} + +void userdbs_deinit(void) +{ + array_free(&userdb_modules); + array_free(&userdb_interfaces); +} |