Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

More fixes/improvements and make distcheck fixed #24

Closed
wants to merge 8 commits into from

2 participants

@Flameeyes

I cherry-picked again the patches you skipped over for pam_duo (which is honestly what I care most about, without those for me is totally useless — portability in that regard doesn't seem to be an issue to me at all).

You also did pick the patch that caused make distcheck to fail so I've reverted that one and implemented the same idea differently (I'll submit a bug/fix to automake about that later today).

I also made sure that parallel install works, as it was unsafe before when using DESTDIR.

Flameeyes added some commits
@Flameeyes Flameeyes Revert "from flameeyes: build: replace libcompat with libcommon and m…
…ove common functions there."

Seems like there is a bug with using `SUBDIRS = . lib`, sources in lib/ and `subdir-objects`.

This reverts commit d1caf3f.
455a675
@Flameeyes Flameeyes build: do not add -lpam to LIBS when building with PAM.
This was introduced by the use of AC_SEARCH_LIBS to identify the presence
of pam_vprompt, as it changes the value of LIBS. With the new code,
AC_SEARCH_LIBS can also be replaced with the simpler AC_CHECK_FUNCS macro.
6ffda52
@Flameeyes Flameeyes pam_duo: allow using try_first_pass/use_first_pass options.
These options are commonly used with pam_unix and pam_pgsql and allow
to re-use a previously presented password; at the same time, this
allows for the password to be read from binary prompts such as when
used with ftpd servers.

The pam_get_pass function is derived out of pam_pgsql which in turn
derives it from FreeBSD and is licensed by Juniper Networks under
2-clause BSD license (ISC-like).
56a0394
@Flameeyes Flameeyes pam_duo: replace match on 'su' service with a use_uid parameter.
This make it behave a lot like Linux-PAM's pam_wheel, and allows using
the same behaviour with any other similar service, rather than just
with su.
bf180a9
@Flameeyes Flameeyes pam_duo: add a push option to force using push as factor.
This only changes the prompt to force the use of a given factor for
pam_duo, allowing to use this in conjunction with pam_unix for actual
dual-factor authentication of users on services such as ftpd.
c9800d5
@Flameeyes Flameeyes build: make libcompat.la handle the common code as well 2d46f6e
@Flameeyes Flameeyes build: link login_duo to the libcompat library. 64e8cd5
@Flameeyes Flameeyes build: use the proper targets for install hooks
Also always create directories before using them (for parallel install
compatibility), and fix one bad name.
bc5e1ef
@jonoberheide

Thanks for the build fixes, Diego! It's unlikely we'll merge the feature enhancements for this release though.

@Flameeyes
@Flameeyes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 21, 2012
  1. @Flameeyes

    Revert "from flameeyes: build: replace libcompat with libcommon and m…

    Flameeyes authored
    …ove common functions there."
    
    Seems like there is a bug with using `SUBDIRS = . lib`, sources in lib/ and `subdir-objects`.
    
    This reverts commit d1caf3f.
  2. @Flameeyes

    build: do not add -lpam to LIBS when building with PAM.

    Flameeyes authored
    This was introduced by the use of AC_SEARCH_LIBS to identify the presence
    of pam_vprompt, as it changes the value of LIBS. With the new code,
    AC_SEARCH_LIBS can also be replaced with the simpler AC_CHECK_FUNCS macro.
  3. @Flameeyes

    pam_duo: allow using try_first_pass/use_first_pass options.

    Flameeyes authored
    These options are commonly used with pam_unix and pam_pgsql and allow
    to re-use a previously presented password; at the same time, this
    allows for the password to be read from binary prompts such as when
    used with ftpd servers.
    
    The pam_get_pass function is derived out of pam_pgsql which in turn
    derives it from FreeBSD and is licensed by Juniper Networks under
    2-clause BSD license (ISC-like).
  4. @Flameeyes

    pam_duo: replace match on 'su' service with a use_uid parameter.

    Flameeyes authored
    This make it behave a lot like Linux-PAM's pam_wheel, and allows using
    the same behaviour with any other similar service, rather than just
    with su.
  5. @Flameeyes

    pam_duo: add a push option to force using push as factor.

    Flameeyes authored
    This only changes the prompt to force the use of a given factor for
    pam_duo, allowing to use this in conjunction with pam_unix for actual
    dual-factor authentication of users on services such as ftpd.
  6. @Flameeyes
  7. @Flameeyes
  8. @Flameeyes

    build: use the proper targets for install hooks

    Flameeyes authored
    Also always create directories before using them (for parallel install
    compatibility), and fix one bad name.
This page is out of date. Refresh to see the latest.
View
9 Makefile.am
@@ -1,14 +1,7 @@
ACLOCAL_AMFLAGS = -I autotools
-noinst_LTLIBRARIES = libcommon.la
-
-libcommon_la_SOURCES = \
- lib/groupaccess.c lib/groupaccess.h \
- lib/match.c lib/match.h
-libcommon_la_LIBADD = @LTLIBOBJS@
-
-SUBDIRS = . lib login_duo
+SUBDIRS = compat lib login_duo
if PAM
SUBDIRS += pam_duo
View
5 compat/Makefile.am
@@ -0,0 +1,5 @@
+
+noinst_LTLIBRARIES = libcompat.la
+libcompat_la_SOURCES = groupaccess.c groupaccess.h match.c match.h
+libcompat_la_LIBADD = @LTLIBOBJS@
+
View
0  compat/dummy.c
No changes.
View
0  lib/groupaccess.c → compat/groupaccess.c
File renamed without changes
View
0  lib/groupaccess.h → compat/groupaccess.h
File renamed without changes
View
0  lib/match.c → compat/match.c
File renamed without changes
View
0  lib/match.h → compat/match.h
File renamed without changes
View
16 configure.ac
@@ -36,6 +36,7 @@ AC_PROG_CC
AM_PROG_CC_C_O
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_INSTALL
+AC_PROG_MKDIR_P
LT_INIT
# Compiler options
@@ -99,12 +100,16 @@ AC_ARG_WITH(pam,
)
AM_CONDITIONAL([PAM], [ test "x$with_pam" != "xno" ])
-if test "x$with_pam" != "xno" ; then
+AS_IF([test "x$with_pam" != "xno"], [
+ save_LIBS=$LIBS
AC_CHECK_HEADERS([security/pam_appl.h], [],
[AC_MSG_ERROR([[PAM header files not found, install libpam-dev/pam-devel/etc.]])])
AC_CHECK_HEADERS([security/pam_modules.h security/pam_ext.h], [], [],
[#include <security/pam_appl.h>])
- AC_CHECK_LIB([pam], [main], [AC_SUBST([LIBPAM], ["-lpam"])], AC_MSG_FAILURE([libpam not found]))
+
+ AC_CHECK_LIB([pam], [main], [], AC_MSG_FAILURE([libpam not found]))
+ AC_SUBST([LIBPAM], ["-lpam"])
+
AS_IF([ test "x$with_pam" != "xno" ], [
case "${withval}" in
/*|\$*) PAMDIR="${withval}";;
@@ -113,8 +118,9 @@ if test "x$with_pam" != "xno" ; then
esac
AC_MSG_NOTICE([PAM installation path $PAMDIR])
])
- AC_SEARCH_LIBS(pam_vprompt, pam, [AC_DEFINE([HAVE_PAM_VPROMPT], [1], [Define if pam_vprompt exists])])
-fi
+ AC_CHECK_FUNCS([pam_vprompt])
+ LIBS=$save_LIBS
+])
AC_SUBST(PAMDIR, "$PAMDIR")
# Check for Duo privsep user
@@ -168,6 +174,6 @@ AC_REPLACE_FUNCS([asprintf getgrouplist strlcpy vsyslog])
AC_SEARCH_LIBS(inet_ntoa, nsl)
AC_SEARCH_LIBS(gethostbyname, resolv nsl)
-AC_CONFIG_FILES(Makefile lib/Makefile lib/libduo.pc login_duo/Makefile pam_duo/Makefile duo_unix.spec tests/Makefile)
+AC_CONFIG_FILES(Makefile compat/Makefile lib/Makefile lib/libduo.pc login_duo/Makefile pam_duo/Makefile duo_unix.spec tests/Makefile)
AC_OUTPUT
View
8 lib/Makefile.am
@@ -6,7 +6,7 @@ lib_LTLIBRARIES = libduo.la
libduo_la_SOURCES = bson.h bson.c cacert.h duo.c \
http_parser.h http_parser.c https.h https.c ini.h ini.c \
urlenc.h urlenc.c
-libduo_la_LIBADD = ../libcommon.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@
+libduo_la_LIBADD = $(top_builddir)/compat/libcompat.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@
# http://sourceware.org/autobook/autobook/autobook_91.html
libduo_la_LDFLAGS = -no-undefined -version-info 3:0:0 -export-symbols-regex '^duo_'
@@ -22,12 +22,12 @@ noinst_PROGRAMS = testduo
testduo_LDADD = libduo.la
-install-exec-hook:
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)
-@if [ ! -f $(DESTDIR)$(sysconfdir)/duo.crt ]; then \
- mkdir -p -m 755 $(DESTDIR)$(sysconfdir); \
cp duo.crt $(DESTDIR)$(sysconfdir)/duo.crt; \
echo "Created ${DESTDIR}$(sysconfdir)/duo.crt"; \
else \
- echo "Found existing ${DESTDIR}$(sysconfdir)/login_duo.conf - skipping"; \
+ echo "Found existing ${DESTDIR}$(sysconfdir)/duo.crt - skipping"; \
fi
View
6 login_duo/Makefile.am
@@ -4,15 +4,17 @@ AM_CPPFLAGS = -I$(top_srcdir)/compat -I$(top_srcdir)/lib @OPENSSL_INCLUDES@
sbin_PROGRAMS = login_duo
login_duo_SOURCES = login_duo.c
-login_duo_LDADD = $(top_builddir)/lib/libduo.la $(top_builddir)/libcommon.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@
+login_duo_LDADD = $(top_builddir)/lib/libduo.la $(top_builddir)/compat/libcompat.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@
notrans_dist_man8_MANS = login_duo.8
install-exec-hook:
-chown root $(DESTDIR)$(sbindir)/login_duo && \
chmod 4755 $(DESTDIR)$(sbindir)/login_duo
+
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)
-@if [ ! -f $(DESTDIR)$(sysconfdir)/login_duo.conf ]; then \
- mkdir -p -m 755 $(DESTDIR)$(sysconfdir); \
cp login_duo.conf $(DESTDIR)$(sysconfdir)/login_duo.conf; \
echo "Created ${DESTDIR}$(sysconfdir)/login_duo.conf"; \
echo "Please edit it to add your Duo integration and secret keys"; \
View
7 pam_duo/Makefile.am
@@ -5,13 +5,14 @@ pam_libdir = @PAMDIR@
pam_lib_LTLIBRARIES = pam_duo.la
pam_duo_la_DEFS = -DDEBUG_PAM -DPAM_DEBUG @DEFS@
-pam_duo_la_SOURCES = pam_duo.c pam_extra.h pam_extra.c
-pam_duo_la_LIBADD = $(top_builddir)/lib/libduo.la $(top_builddir)/libcommon.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@ -lpam
+pam_duo_la_SOURCES = pam_duo.c pam_extra.h pam_extra.c pam_get_pass.c
+pam_duo_la_LIBADD = $(top_builddir)/lib/libduo.la @OPENSSL_LDFLAGS@ @OPENSSL_LIBS@ -lpam
pam_duo_la_LDFLAGS = -module -no-undefined -avoid-version -shared -export-symbols-regex '^pam_sm_'
notrans_dist_man8_MANS = pam_duo.8
-install-exec-hook:
+install-data-local:
+ $(MKDIR_P) $(DESTDIR)$(sysconfdir)
-@if [ ! -f $(DESTDIR)$(sysconfdir)/pam_duo.conf ]; then \
cp pam_duo.conf $(DESTDIR)$(sysconfdir)/pam_duo.conf; \
echo "Created ${DESTDIR}$(sysconfdir)/pam_duo.conf"; \
View
46 pam_duo/pam_duo.c
@@ -58,6 +58,7 @@
#include "duo.h"
#include "groupaccess.h"
#include "pam_extra.h"
+#include "pam_duo_options.h"
#ifndef PAM_EXTERN
#define PAM_EXTERN
@@ -75,7 +76,7 @@ enum {
DUO_FAIL_SECURE,
};
-static int debug = 0;
+static int options = 0;
struct duo_config {
char *ikey;
@@ -96,7 +97,7 @@ _syslog(int priority, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- if (debug) {
+ if (options & PAM_OPT_DEBUG) {
fprintf(stderr, "[%d] ", priority);
vfprintf(stderr, fmt, ap);
fputs("\n", stderr);
@@ -172,14 +173,17 @@ __duo_status(void *arg, const char *msg)
static char *
__duo_prompt(void *arg, const char *prompt, char *buf, size_t bufsz)
{
- char *p;
-
- if (pam_prompt((pam_handle_t *)arg, PAM_PROMPT_ECHO_ON, &p,
- "%s", prompt) != PAM_SUCCESS) {
+ pam_handle_t *pamh = (pam_handle_t *)arg;
+ const char *p;
+ int rc;
+
+ if (options & PAM_OPT_PUSH)
+ strlcpy(buf, "push", bufsz);
+ else if ((rc = pam_get_pass(pamh, PAM_AUTHTOK, &p, prompt, options)) == PAM_SUCCESS)
+ strlcpy(buf, p, bufsz);
+ else
return (NULL);
- }
- strlcpy(buf, p, bufsz);
- free(p);
+
return (buf);
}
@@ -227,7 +231,15 @@ pam_sm_authenticate(pam_handle_t *pamh, int pam_flags,
if (strncmp("conf=", argv[i], 5) == 0) {
config = argv[i] + 5;
} else if (strcmp("debug", argv[i]) == 0) {
- debug = 1;
+ options |= PAM_OPT_DEBUG;
+ } else if (strcmp("try_first_pass", argv[i]) == 0) {
+ options |= PAM_OPT_TRY_FIRST_PASS;
+ } else if (strcmp("use_first_pass", argv[i]) == 0) {
+ options |= PAM_OPT_USE_FIRST_PASS|PAM_OPT_TRY_FIRST_PASS;
+ } else if (strcmp("use_uid", argv[i]) == 0) {
+ options |= PAM_OPT_USE_UID;
+ } else if (strcmp("push", argv[i]) == 0) {
+ options |= PAM_OPT_PUSH;
} else {
_syslog(LOG_ERR, "Invalid pam_duo option: '%s'",
argv[i]);
@@ -264,6 +276,14 @@ pam_sm_authenticate(pam_handle_t *pamh, int pam_flags,
(duopam_const void *)&service) != PAM_SUCCESS) {
return (PAM_SERVICE_ERR);
}
+ if (options & PAM_OPT_USE_UID) {
+ /* Check calling user for Duo auth, just like sudo */
+ if ((pw = getpwuid(getuid())) == NULL) {
+ return (PAM_USER_UNKNOWN);
+ }
+ user = pw->pw_name;
+ }
+
if (strcmp(service, "sshd") == 0) {
/*
* Disable incremental status reporting for sshd :-(
@@ -273,12 +293,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int pam_flags,
flags |= DUO_FLAG_SYNC;
} else if (strcmp(service, "sudo") == 0) {
cmd = getenv("SUDO_COMMAND");
- } else if (strcmp(service, "su") == 0) {
- /* Check calling user for Duo auth, just like sudo */
- if ((pw = getpwuid(getuid())) == NULL) {
- return (PAM_USER_UNKNOWN);
- }
- user = pw->pw_name;
}
/* Check group membership */
if (cfg.groups_cnt > 0) {
View
20 pam_duo/pam_duo_options.h
@@ -0,0 +1,20 @@
+/*
+ * pam_duo_options.h
+ *
+ * Copyright (c) 2012 Diego Elio Pettenò
+ * All rights reserved, all wrongs reversed.
+ */
+
+#ifndef PAM_DUO_OPTIONS_H__
+#define PAM_DUO_OPTIONS_H__
+
+#define PAM_OPT_DEBUG 0x01
+#define PAM_OPT_TRY_FIRST_PASS 0x02
+#define PAM_OPT_USE_FIRST_PASS 0x04
+#define PAM_OPT_ECHO_PASS 0x08
+#define PAM_OPT_USE_UID 0x10
+#define PAM_OPT_PUSH 0x20
+
+int pam_get_pass(pam_handle_t *, int, const char **, const char *, int);
+
+#endif
View
164 pam_duo/pam_get_pass.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2000. Leon Breedt, Copyright (c) 2002 David D.W. Downey
+ * Adapted FreeBSD version
+ */
+/*-
+ * Copyright 1998 Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libpam/libpam/pam_get_pass.c,v 1.1.1.1 1998/11/18 01:44:37 jdp Exp $
+ */
+
+/* $Id: pam_get_pass.c,v 1.2 2000/06/25 09:39:28 ljb Exp $ */
+#include <stdlib.h>
+#include <string.h>
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+#include "pam_duo_options.h"
+
+#ifdef __FreeBSD__
+#include <sys/param.h>
+#endif
+
+static int
+pam_conv_pass(pam_handle_t *pamh, int pam_item, const char *prompt, int options)
+{
+ int retval;
+ const void *item;
+ const struct pam_conv *conv;
+ struct pam_message msg;
+ const struct pam_message *msgs[1];
+ struct pam_response *resp;
+
+ if ((retval = pam_get_item(pamh, PAM_CONV, &item)) !=
+ PAM_SUCCESS)
+ return retval;
+ conv = (const struct pam_conv *)item;
+ msg.msg_style = options & PAM_OPT_ECHO_PASS ?
+ PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
+ msg.msg = prompt;
+ msgs[0] = &msg;
+ if ((retval = conv->conv(1, msgs, &resp, conv->appdata_ptr)) !=
+ PAM_SUCCESS)
+ return retval;
+ if ((retval = pam_set_item(pamh, pam_item, resp[0].resp)) !=
+ PAM_SUCCESS)
+ return retval;
+ memset(resp[0].resp, 0, strlen(resp[0].resp));
+ free(resp[0].resp);
+ free(resp);
+ return PAM_SUCCESS;
+}
+
+int
+pam_get_pass(pam_handle_t *pamh, int pam_item, const char **passp, const char *prompt,
+ int options)
+{
+ int retval;
+ const void *item = NULL;
+
+ /*
+ * Grab the already-entered password if we might want to use it.
+ */
+ if ((pam_item == PAM_AUTHTOK) && (options & (PAM_OPT_TRY_FIRST_PASS | PAM_OPT_USE_FIRST_PASS))) {
+ if ((retval = pam_get_item(pamh, pam_item, &item)) !=
+ PAM_SUCCESS)
+ return retval;
+ }
+
+ if (item == NULL) {
+ /* The user hasn't entered a password yet. */
+ if ((pam_item == PAM_AUTHTOK) && (options & PAM_OPT_USE_FIRST_PASS))
+ return PAM_AUTH_ERR;
+ /* Use the conversation function to get a password. */
+ if ((retval = pam_conv_pass(pamh, pam_item, prompt, options)) !=
+ PAM_SUCCESS ||
+ (retval = pam_get_item(pamh, pam_item, &item)) !=
+ PAM_SUCCESS)
+ return retval;
+ }
+ *passp = (const char *)item;
+ return PAM_SUCCESS;
+}
+
+int
+pam_get_confirm_pass(pam_handle_t *pamh, const char **passp, const char *prompt1, const char *prompt2, int options)
+{
+ int retval = PAM_AUTH_ERR;
+ int i;
+ const void *item = NULL;
+ const struct pam_conv *conv;
+ struct pam_message msgs[2];
+ const struct pam_message *pmsgs[2];
+ struct pam_response *resp;
+
+ /* Grab the already-entered password if we might want to use it.*/
+ if (options & (PAM_OPT_TRY_FIRST_PASS | PAM_OPT_USE_FIRST_PASS)) {
+
+ if ((retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item)) != PAM_SUCCESS)
+ return retval;
+ }
+
+ if (item == NULL) {
+
+ if (options & PAM_OPT_USE_FIRST_PASS)
+ return PAM_AUTH_ERR;
+
+ if ((retval = pam_get_item(pamh, PAM_CONV, (const void **)&item)) != PAM_SUCCESS)
+ return retval;
+
+ conv = (const struct pam_conv *)item;
+ for(i = 0; i < 2; i++)
+ msgs[i].msg_style = (options & PAM_OPT_ECHO_PASS) ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
+
+ msgs[0].msg = prompt1;
+ msgs[1].msg = prompt2;
+ pmsgs[0] = &msgs[0];
+ pmsgs[1] = &msgs[1];
+
+ if((retval = conv->conv(2, pmsgs, &resp, conv->appdata_ptr)) != PAM_SUCCESS)
+ return retval;
+
+ if(!resp)
+ return PAM_AUTHTOK_RECOVERY_ERR;
+
+ if(strcmp(resp[0].resp, resp[1].resp) != 0)
+ return PAM_AUTHTOK_RECOVERY_ERR;
+
+ retval = pam_set_item(pamh, PAM_AUTHTOK, resp[0].resp);
+ memset(resp[0].resp, 0, strlen(resp[0].resp));
+ memset(resp[1].resp, 0, strlen(resp[1].resp));
+ free(resp[0].resp);
+ free(resp[1].resp);
+ free(resp);
+
+ if(retval == PAM_SUCCESS) {
+ item = NULL;
+ retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&item);
+ }
+ }
+ *passp = item;
+
+ return retval;
+}
Something went wrong with that request. Please try again.