userdb-nss.c revision cca4ba2a504d70a9fe9fee37f8433997359de52c
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch* Copyright (c) 2007-2013 Dovecot authors, see the included COPYING file */
12d535f8c44bbcdc1338f49aa93a0d637bd48fd9Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen/* Currently supports only GLIBC-compatible NSS modules */
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include "auth-common.h"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include "userdb.h"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#ifdef USERDB_NSS
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include "module-dir.h"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include <pwd.h>
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include <unistd.h>
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include <dlfcn.h>
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#include <nss.h>
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#define USER_CACHE_KEY "%u"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstruct nss_userdb_module {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct userdb_module module;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen char *buf;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen size_t bufsize;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct module nss_module;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen enum nss_status (*getpwnam_r)(const char *name, struct passwd *pwd,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen char *buffer, size_t buflen, int *errnop);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen};
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstatic void
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenuserdb_nss_lookup(struct auth_request *auth_request,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen userdb_callback_t *callback)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct userdb_module *_module = auth_request->userdb->userdb;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct nss_userdb_module *module = (struct nss_userdb_module *)_module;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct passwd pw;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen enum nss_status status;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen int err;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_log_debug(auth_request, "nss", "lookup");
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen status = module->getpwnam_r(auth_request->user, &pw,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->buf, module->bufsize, &err);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen switch (status) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen case NSS_STATUS_TRYAGAIN:
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_log_error(auth_request, "nss",
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen "returned tryagain (err=%d)", err);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen break;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen case NSS_STATUS_UNAVAIL:
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_log_error(auth_request, "nss",
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen "unavailable (err=%d)", err);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen break;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen case NSS_STATUS_NOTFOUND:
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_log_info(auth_request, "nss", "unknown user");
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen result = USERDB_RESULT_USER_UNKNOWN;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen break;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen case NSS_STATUS_SUCCESS:
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen result = USERDB_RESULT_OK;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen break;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen default:
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_log_info(auth_request, "nss",
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen "returned %d (err=%d)", status, err);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen break;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (result != USERDB_RESULT_OK) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen callback(result, auth_request);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen return;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen }
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_set_field(auth_request, "user", pw.pw_name, NULL);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen auth_request_init_userdb_reply(auth_request);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen auth_request_set_userdb_field(auth_request, "system_groups_user",
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen pw.pw_name);
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen auth_request_set_userdb_field(auth_request, "uid", dec2str(pw.pw_uid));
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen auth_request_set_userdb_field(auth_request, "gid", dec2str(pw.pw_gid));
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen auth_request_set_userdb_field(auth_request, "home", pw.pw_dir);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen callback(USERDB_RESULT_OK, auth_request);
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenstatic void
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenuserdb_nss_load_module(struct nss_userdb_module *module, pool_t pool)
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen const char *name = module->nss_module.name;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen char *path;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen path = p_strdup_printf(pool, "/usr/lib/libnss_%s.so", name);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->nss_module.handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (module->nss_module.handle == NULL)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_fatal("dlopen(%s) failed: %s", path, dlerror());
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->nss_module.path = path;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->getpwnam_r =
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen module_get_symbol(&module->nss_module,
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen t_strdup_printf("_nss_%s_getpwnam_r", name));
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen if (module->getpwnam_r == NULL)
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen i_fatal("userdb nss: Module %s missing getpwnam_r()", path);
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen}
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainenstatic struct userdb_module *
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainenuserdb_nss_preinit(pool_t pool, const char *args)
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct nss_userdb_module *module;
2c7cde7c78ccb28dcaa864d262ed6e991a7e8eb7Timo Sirainen const char *const *tmp;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module = p_new(pool, struct nss_userdb_module, 1);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->buf = p_malloc(pool, module->bufsize);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->module.blocking = TRUE;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (strcmp(*tmp, "blocking=no") == 0)
abec3f4c5ec486c393e1513950f2d4819dcbc30fTimo Sirainen module->module.blocking = FALSE;
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen else if (strncmp(*tmp, "service=", 8) == 0)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->nss_module.name = p_strdup(pool, *tmp + 8);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen else
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen i_fatal("userdb nss: Unknown setting: %s", *tmp);
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen }
263e4b2733768062cb0b8b8917cad78fa2a04ff9Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (module->nss_module.name == NULL)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen i_fatal("userdb nss: Missing service");
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen userdb_nss_load_module(module, pool);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen module->module.cache_key = USER_CACHE_KEY;
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi return &module->module;
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstatic void userdb_nss_deinit(struct userdb_module *_module)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen{
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen struct nss_userdb_module *module = (struct nss_userdb_module *)_module;
c6ce2e251ac75fa650c7fbfa52150eae69386293Martti Rannanjärvi void (*mod_endpwent)(void);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen const char *symbol;
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen symbol = t_strdup_printf("_nss_%s_endpwent", module->nss_module.name);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen mod_endpwent = module_get_symbol(&module->nss_module, symbol);
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen if (mod_endpwent != NULL)
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen mod_endpwent();
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen}
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstruct userdb_module_interface userdb_nss = {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen "nss",
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
2f564433c979a41ade84b75fa10c7b46fb9781acTimo Sirainen userdb_nss_preinit,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen NULL,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen userdb_nss_deinit,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen userdb_nss_lookup,
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen NULL,
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen NULL,
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen NULL
2f564433c979a41ade84b75fa10c7b46fb9781acTimo Sirainen};
8ccb1a013b07e7ca37b7281732b78c042f128388Timo Sirainen#else
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainenstruct userdb_module_interface userdb_nss = {
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen .name = "nss"
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen};
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen#endif
56c35c844320b0a157d1aaa6b3e62b7f3851b235Timo Sirainen