From 45c2c496dcf89f568b90fcf403af9d63b2361fbd Mon Sep 17 00:00:00 2001 From: Iker Pedrosa Date: Mon, 10 Jul 2023 12:45:12 +0200 Subject: [PATCH] pam_userdb: enable GDBM support * configure.ac: add `gdbm` option to `enable-db` * modules/pam_userdb/pam_userdb.c: conditionally provide database access depending on the database technology Signed-off-by: Iker Pedrosa --- configure.ac | 10 +++- modules/pam_userdb/pam_userdb.c | 90 ++++++++++++++++++++++++++++----- 2 files changed, 86 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 6666b1b2..7565a830 100644 --- a/configure.ac +++ b/configure.ac @@ -436,10 +436,10 @@ if test -n "$opt_randomdev"; then AC_DEFINE_UNQUOTED(PAM_PATH_RANDOMDEV, "$opt_randomdev", [Random device path.]) fi -dnl check for libdb or libndbm as fallback. Some libndbm compat +dnl check for libdb or gdbm or libndbm as fallback. Some libndbm compat dnl libraries are unusable, so try libdb first. AC_ARG_ENABLE([db], - AS_HELP_STRING([--enable-db=(db|ndbm|yes|no)],[Default behavior 'yes', which is to check for libdb first, followed by ndbm. Use 'no' to disable db support.]), + AS_HELP_STRING([--enable-db=(db|gdbm|ndbm|yes|no)],[Default behavior 'yes', which is to check for libdb first, followed by gdbm and ndbm. Use 'no' to disable db support.]), WITH_DB=$enableval, WITH_DB=yes) AC_ARG_WITH([db-uniquename], AS_HELP_STRING([--with-db-uniquename=extension],[Unique name for db libraries and functions.])) @@ -451,6 +451,12 @@ if test x"$WITH_DB" != xno ; then [LIBDB="-ldb$with_db_uniquename"; break]) LIBS=$old_libs fi + if test x"$WITH_DB" = xgdbm ; then + AC_CHECK_LIB([gdbm],[gdbm_store], LIBDB="-lgdbm", LIBDB="") + if test -n "$LIBDB" ; then + AC_CHECK_HEADERS(gdbm.h) + fi + fi if test -z "$LIBDB" ; then AC_CHECK_LIB([ndbm],[dbm_store], LIBDB="-lndbm", LIBDB="") if test -n "$LIBDB" ; then diff --git a/modules/pam_userdb/pam_userdb.c b/modules/pam_userdb/pam_userdb.c index 297403b0..0b5e5965 100644 --- a/modules/pam_userdb/pam_userdb.c +++ b/modules/pam_userdb/pam_userdb.c @@ -25,6 +25,8 @@ #ifdef HAVE_NDBM_H # include +#elif defined(HAVE_GDBM_H) +# include #else # ifdef HAVE_DB_H # define DB_DBM_HSEARCH 1 /* use the dbm interface */ @@ -40,6 +42,12 @@ #include #include "pam_inline.h" +#ifndef HAVE_GDBM_H +# define COND_UNUSED UNUSED +#else +# define COND_UNUSED +#endif /* HAVE_GDBM_H */ + /* * Conversation function to obtain the user's password */ @@ -129,6 +137,60 @@ _pam_parse (pam_handle_t *pamh, int argc, const char **argv, return ctrl; } +/* + * Database abstraction functions + */ +static void * +db_open(const char *database, mode_t file_mode) +{ +#ifdef HAVE_GDBM_H + return gdbm_open(database, 4096, GDBM_READER, file_mode, NULL); +#else + return dbm_open(database, O_RDONLY, file_mode); +#endif /* HAVE_GDBM_H */ +} + +static datum +db_firstkey(void *dbm) +{ +#ifdef HAVE_GDBM_H + return gdbm_firstkey(dbm); +#else + return dbm_firstkey(dbm); +#endif /* HAVE_GDBM_H */ +} + +static datum +db_nextkey(void *dbm, datum key COND_UNUSED) +{ +#ifdef HAVE_GDBM_H + return gdbm_nextkey(dbm, key); +#else + return dbm_nextkey(dbm); +#endif /* HAVE_GDBM_H */ +} + +static datum +db_fetch(void *dbm, datum key) +{ +#ifdef HAVE_GDBM_H + return gdbm_fetch(dbm, key); +#else + return dbm_fetch(dbm, key); +#endif /* HAVE_GDBM_H */ +} + +static int +db_close(void *dbm) +{ +#ifdef HAVE_GDBM_H + return gdbm_close(dbm); +#else + dbm_close(dbm); + return 0; +#endif /* HAVE_GDBM_H */ +} + /* * Looks up a user name in a database and checks the password @@ -143,11 +205,15 @@ static int user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, const char *user, const char *pass, int ctrl) { +#ifdef HAVE_GDBM_H + GDBM_FILE *dbm; +#else DBM *dbm; +#endif datum key, data; /* Open the DB file. */ - dbm = dbm_open(database, O_RDONLY, 0644); + dbm = db_open(database, 0644); if (dbm == NULL) { pam_syslog(pamh, LOG_ERR, "user_lookup: could not open database `%s': %m", database); @@ -157,9 +223,9 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, /* dump out the database contents for debugging */ if (ctrl & PAM_DUMP_ARG) { pam_syslog(pamh, LOG_INFO, "Database dump:"); - for (key = dbm_firstkey(dbm); key.dptr != NULL; - key = dbm_nextkey(dbm)) { - data = dbm_fetch(dbm, key); + for (key = db_firstkey(dbm); key.dptr != NULL; + key = db_nextkey(dbm, key)) { + data = db_fetch(dbm, key); pam_syslog(pamh, LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'", key.dsize, key.dptr, data.dsize, data.dptr); @@ -180,7 +246,7 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, } if (key.dptr) { - data = dbm_fetch(dbm, key); + data = db_fetch(dbm, key); pam_overwrite_n(key.dptr, key.dsize); free(key.dptr); } @@ -196,7 +262,7 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, if (ctrl & PAM_KEY_ONLY_ARG) { - dbm_close (dbm); + db_close (dbm); return 0; /* found it, data contents don't matter */ } @@ -275,7 +341,7 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, } - dbm_close(dbm); + db_close(dbm); if (compare == 0) return 0; /* match */ else @@ -290,14 +356,14 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, /* probably we should check dbm_error() here */ if ((ctrl & PAM_KEY_ONLY_ARG) == 0) { - dbm_close(dbm); + db_close(dbm); return 1; /* not key_only, so no entry => no entry for the user */ } /* now handle the key_only case */ - for (key = dbm_firstkey(dbm); + for (key = db_firstkey(dbm); key.dptr != NULL; - key = dbm_nextkey(dbm)) { + key = db_nextkey(dbm, key)) { int compare; /* first compare the user portion (case sensitive) */ compare = strncmp(key.dptr, user, strlen(user)); @@ -322,12 +388,12 @@ user_lookup (pam_handle_t *pamh, const char *database, const char *cryptmode, } } if (compare == 0) { - dbm_close(dbm); + db_close(dbm); return 0; /* match */ } } } - dbm_close(dbm); + db_close(dbm); if (saw_user) return -1; /* saw the user, but password mismatch */ else -- 2.41.0