Mercurial > dovecot > core-2.2
diff src/auth/userdb-nss.c @ 5870:c9b49ed99d28 HEAD
Added userdb nss which currently supports glibc-compatible NSS modules.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 03 Jul 2007 01:50:13 +0300 |
parents | |
children | 93bd157917ca |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/userdb-nss.c Tue Jul 03 01:50:13 2007 +0300 @@ -0,0 +1,154 @@ +/* Copyright (C) 2007 Timo Sirainen */ + +/* Currently supports only GLIBC-compatible NSS modules */ + +#include "common.h" + +#ifdef USERDB_NSS + +#include "module-dir.h" +#include "userdb.h" + +#include <pwd.h> +#include <unistd.h> +#include <dlfcn.h> +#include <nss.h> + +#define USER_CACHE_KEY "%u" + +struct nss_userdb_module { + struct userdb_module module; + + char *buf; + size_t bufsize; + + struct module nss_module; + enum nss_status (*getpwnam_r)(const char *name, struct passwd *pwd, + char *buffer, size_t buflen, int *errnop); +}; + +static void +userdb_nss_lookup(struct auth_request *auth_request, + userdb_callback_t *callback) +{ + struct userdb_module *_module = auth_request->userdb->userdb; + struct nss_userdb_module *module = (struct nss_userdb_module *)_module; + struct auth_stream_reply *reply; + struct passwd pw; + enum nss_status status; + enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE; + int err; + + auth_request_log_debug(auth_request, "nss", "lookup"); + + status = module->getpwnam_r(auth_request->user, &pw, + module->buf, module->bufsize, &err); + switch (status) { + case NSS_STATUS_TRYAGAIN: + auth_request_log_error(auth_request, "nss", + "returned tryagain (err=%d)", err); + break; + case NSS_STATUS_UNAVAIL: + auth_request_log_error(auth_request, "nss", + "unavailable (err=%d)", err); + break; + case NSS_STATUS_NOTFOUND: + auth_request_log_info(auth_request, "nss", "unknown user"); + result = USERDB_RESULT_USER_UNKNOWN; + break; + case NSS_STATUS_SUCCESS: + result = USERDB_RESULT_OK; + break; + default: + auth_request_log_info(auth_request, "nss", + "returned %d (err=%d)", status, err); + break; + } + + if (result != USERDB_RESULT_OK) { + callback(result, NULL, auth_request); + return; + } + + reply = auth_stream_reply_init(auth_request); + auth_stream_reply_add(reply, NULL, pw.pw_name); + auth_stream_reply_add(reply, "system_user", pw.pw_name); + auth_stream_reply_add(reply, "uid", dec2str(pw.pw_uid)); + auth_stream_reply_add(reply, "gid", dec2str(pw.pw_gid)); + auth_stream_reply_add(reply, "home", pw.pw_dir); + + callback(USERDB_RESULT_OK, reply, auth_request); +} + +static void +userdb_nss_load_module(struct nss_userdb_module *module, pool_t pool) +{ + const char *name = module->nss_module.name; + char *path; + + path = p_strdup_printf(pool, "/usr/lib/libnss_%s.so", name); + module->nss_module.handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW); + if (module->nss_module.handle == NULL) + i_fatal("dlopen(%s) failed: %s", path, dlerror()); + module->nss_module.path = path; + + module->getpwnam_r = + module_get_symbol(&module->nss_module, + t_strdup_printf("_nss_%s_getpwnam_r", name)); + if (module->getpwnam_r == NULL) + i_fatal("userdb nss: Module %s missing getpwnam_r()", path); +} + +static struct userdb_module * +userdb_nss_preinit(struct auth_userdb *auth_userdb, const char *args) +{ + struct nss_userdb_module *module; + const char *const *tmp; + pool_t pool = auth_userdb->auth->pool; + + module = p_new(pool, struct nss_userdb_module, 1); + module->bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + module->buf = p_malloc(pool, module->bufsize); + + t_push(); + for (tmp = t_strsplit(args, " "); *tmp != NULL; tmp++) { + if (strcmp(*tmp, "blocking=yes") == 0) + module->module.blocking = TRUE; + else if (strncmp(*tmp, "service=", 8) == 0) + module->nss_module.name = p_strdup(pool, *tmp + 8); + else + i_fatal("userdb nss: Unknown parameter: %s", *tmp); + } + t_pop(); + + if (module->nss_module.name == NULL) + i_fatal("userdb nss: Missing service"); + userdb_nss_load_module(module, pool); + + module->module.cache_key = USER_CACHE_KEY; + return &module->module; +} + +static void userdb_nss_deinit(struct userdb_module *_module) +{ + struct nss_userdb_module *module = (struct nss_userdb_module *)_module; + void (*endpwent)(void); + + endpwent = module_get_symbol(&module->nss_module, + t_strdup_printf("_nss_%s_endpwent", + module->nss_module.name)); + if (endpwent != NULL) + endpwent(); +} + +struct userdb_module_interface userdb_nss = { + "nss", + + userdb_nss_preinit, + NULL, + userdb_nss_deinit, + + userdb_nss_lookup +}; + +#endif