# HG changeset patch # User Timo Sirainen # Date 1183416613 -10800 # Node ID c9b49ed99d28fc606b27ecac1502687745d59a8f # Parent 38ff50597e543657e2d6e6d92f79e92b408761be Added userdb nss which currently supports glibc-compatible NSS modules. diff -r 38ff50597e54 -r c9b49ed99d28 configure.in --- a/configure.in Tue Jul 03 00:30:48 2007 +0300 +++ b/configure.in Tue Jul 03 01:50:13 2007 +0300 @@ -82,6 +82,15 @@ fi, want_passwd=yes) +AC_ARG_WITH(passwd, +[ --with-nss Build with NSS module support (default)], + if test x$withval = xno; then + want_nss=no + else + want_nss=yes + fi, + want_nss=yes) + AC_ARG_WITH(passwd-file, [ --with-passwd-file Build with passwd-like file support (default)], if test x$withval = xno; then @@ -1804,6 +1813,17 @@ AC_SUBST(MODULE_LIBS) fi +if test $want_nss = yes && test $have_modules = yes; then + AC_TRY_COMPILE([ + #include + ], [ + enum nss_status status = NSS_STATUS_TRYAGAIN; + ], [ + AC_DEFINE(USERDB_NSS,, Build with NSS module support) + userdb="$userdb nss" + ]) +fi + AC_SUBST(AUTH_CFLAGS) AC_SUBST(AUTH_LIBS) AC_SUBST(SQL_CFLAGS) diff -r 38ff50597e54 -r c9b49ed99d28 src/auth/Makefile.am --- a/src/auth/Makefile.am Tue Jul 03 00:30:48 2007 +0300 +++ b/src/auth/Makefile.am Tue Jul 03 01:50:13 2007 +0300 @@ -68,11 +68,11 @@ passdb-blocking.c \ passdb-bsdauth.c \ passdb-cache.c \ + passdb-checkpassword.c \ passdb-ldap.c \ passdb-passwd.c \ passdb-passwd-file.c \ passdb-pam.c \ - passdb-checkpassword.c \ passdb-shadow.c \ passdb-sia.c \ passdb-vpopmail.c \ @@ -80,6 +80,7 @@ userdb.c \ userdb-blocking.c \ userdb-ldap.c \ + userdb-nss.c \ userdb-passwd.c \ userdb-passwd-file.c \ userdb-prefetch.c \ diff -r 38ff50597e54 -r c9b49ed99d28 src/auth/userdb-nss.c --- /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 +#include +#include +#include + +#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 diff -r 38ff50597e54 -r c9b49ed99d28 src/auth/userdb.c --- a/src/auth/userdb.c Tue Jul 03 00:30:48 2007 +0300 +++ b/src/auth/userdb.c Tue Jul 03 01:50:13 2007 +0300 @@ -16,6 +16,7 @@ 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; struct userdb_module_interface *userdb_interfaces[] = { #ifdef USERDB_PASSWD @@ -39,6 +40,9 @@ #ifdef USERDB_SQL &userdb_sql, #endif +#ifdef USERDB_NSS + &userdb_nss, +#endif NULL };