userdb.c revision be5c76fabc7439fd33bc799bc3ab3f570799977b
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "auth-common.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "array.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "auth-worker-server.h"
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include "userdb.h"
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <stdlib.h>
9511a40d933181045343110c8101b75887062aaeTimo Sirainen#include <pwd.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen#include <grp.h>
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstatic ARRAY_DEFINE(userdb_interfaces, struct userdb_module_interface *);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic ARRAY_DEFINE(userdb_modules, struct userdb_module *);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic struct userdb_module_interface *userdb_interface_find(const char *name)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
9511a40d933181045343110c8101b75887062aaeTimo Sirainen struct userdb_module_interface *const *ifaces;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen struct userdb_module_interface *iface = *ifaces;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (strcmp(iface->name, name) == 0)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen return iface;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen return NULL;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid userdb_register_module(struct userdb_module_interface *iface)
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen{
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen struct userdb_module_interface *old_iface;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen old_iface = userdb_interface_find(iface->name);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (old_iface != NULL && old_iface->lookup == NULL) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* replacing a "support not compiled in" userdb */
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen userdb_unregister_module(old_iface);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen } else if (old_iface != NULL) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_panic("userdb_register_module(%s): Already registered",
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen iface->name);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen array_append(&userdb_interfaces, &iface, 1);
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen}
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid userdb_unregister_module(struct userdb_module_interface *iface)
859cc94211b759825db5e15b0c88754da902ca14Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct userdb_module_interface *const *ifaces;
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen unsigned int idx;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen array_foreach(&userdb_interfaces, ifaces) {
9511a40d933181045343110c8101b75887062aaeTimo Sirainen if (*ifaces == iface) {
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen idx = array_foreach_idx(&userdb_interfaces, ifaces);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen array_delete(&userdb_interfaces, idx, 1);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return;
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen }
42aaebd4b237403aff6bbfafdcdf52cf5f8c1c06Timo Sirainen }
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen i_panic("userdb_unregister_module(%s): Not registered", iface->name);
7a4c6cc0aea1fc7999ac9bbebc3a95197ac2585cTimo Sirainen}
7a4c6cc0aea1fc7999ac9bbebc3a95197ac2585cTimo Sirainen
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainenuid_t userdb_parse_uid(struct auth_request *request, const char *str)
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen{
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen struct passwd *pw;
9b1d6da0f2b42b8b6f612a570a83355c2a5088eeTimo Sirainen uid_t uid;
9b1d6da0f2b42b8b6f612a570a83355c2a5088eeTimo Sirainen char *p;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (str == NULL)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return (uid_t)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (*str >= '0' && *str <= '9') {
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen uid = (uid_t)strtoul(str, &p, 10);
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen if (*p == '\0')
e50c7afe297ab10e07a8acc816c76ce9d45ef409Timo Sirainen return uid;
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen }
e50c7afe297ab10e07a8acc816c76ce9d45ef409Timo Sirainen
e50c7afe297ab10e07a8acc816c76ce9d45ef409Timo Sirainen pw = getpwnam(str);
1117aa7adc2909c750031fd7551a58a486d100d8Timo Sirainen if (pw == NULL) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (request != NULL) {
9b1d6da0f2b42b8b6f612a570a83355c2a5088eeTimo Sirainen auth_request_log_error(request, "userdb",
9b1d6da0f2b42b8b6f612a570a83355c2a5088eeTimo Sirainen "Invalid UID value '%s'", str);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return (uid_t)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return pw->pw_uid;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainengid_t userdb_parse_gid(struct auth_request *request, const char *str)
34ce7c45264902e217bfb5fa7f7a0aace9302074Timo Sirainen{
34ce7c45264902e217bfb5fa7f7a0aace9302074Timo Sirainen struct group *gr;
34ce7c45264902e217bfb5fa7f7a0aace9302074Timo Sirainen gid_t gid;
34ce7c45264902e217bfb5fa7f7a0aace9302074Timo Sirainen char *p;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (str == NULL)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return (gid_t)-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (*str >= '0' && *str <= '9') {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen gid = (gid_t)strtoul(str, &p, 10);
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen if (*p == '\0')
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return gid;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen gr = getgrnam(str);
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen if (gr == NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (request != NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen auth_request_log_error(request, "userdb",
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen "Invalid GID value '%s'", str);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return (gid_t)-1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return gr->gr_gid;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
10c96a244935de4add8213ba0b894178dfb889a5Timo Sirainenstatic struct userdb_module *
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenuserdb_find(const char *driver, const char *args, unsigned int *idx_r)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct userdb_module *const *userdbs;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned int i, count;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen userdbs = array_get(&userdb_modules, &count);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen for (i = 0; i < count; i++) {
597dba3488c648ffb375ee4a552bd52ac4346979Timo Sirainen if (strcmp(userdbs[i]->iface->name, driver) == 0 &&
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen strcmp(userdbs[i]->args, args) == 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen *idx_r = i;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen return userdbs[i];
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen }
1de2b5a16a455e018d8cbf72ee114d4b5d557a48Timo Sirainen return NULL;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenstruct userdb_module *
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenuserdb_preinit(pool_t pool, const char *driver, const char *args)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen{
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen static unsigned int auth_userdb_id = 0;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen struct userdb_module_interface *iface;
9511a40d933181045343110c8101b75887062aaeTimo Sirainen struct userdb_module *userdb;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen unsigned int idx;
iface = userdb_interface_find(driver);
if (iface == NULL)
i_fatal("Unknown userdb driver '%s'", driver);
if (iface->lookup == 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 = iface->preinit(pool, args);
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->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);
}
void userdbs_generate_md5(unsigned char md5[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);
}
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_vpopmail;
extern struct userdb_module_interface userdb_ldap;
extern struct userdb_module_interface userdb_sql;
extern struct userdb_module_interface userdb_nss;
extern struct userdb_module_interface userdb_checkpassword;
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_vpopmail);
userdb_register_module(&userdb_ldap);
userdb_register_module(&userdb_sql);
userdb_register_module(&userdb_nss);
userdb_register_module(&userdb_checkpassword);
}
void userdbs_deinit(void)
{
array_free(&userdb_modules);
array_free(&userdb_interfaces);
}