From c8c76fbf4c6b25b3ae60b0df4553bd506cdc1f7b Mon Sep 17 00:00:00 2001 From: Stephen Gelman Date: Mon, 12 Nov 2018 06:49:28 +0000 Subject: [PATCH] Add support for LDAP client certificate authentication This adds support for using a client cert/key to authenticate to an LDAP server. It is separate from binding with a username and password and can either be used alongside it or with an anonymous bind to the server. --- README | 9 +++++++++ pam_yubico.8.txt | 6 ++++++ pam_yubico.c | 21 +++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/README b/README index d32a3e1..35b57da 100644 --- a/README +++ b/README @@ -236,6 +236,15 @@ ldapdn:: specify the dn where the users are stored (eg: ou=users,dc=domain,dc=com). +ldap_clientcertfile:: +The path to a client cert file to use when talking to the LDAP +server. Note this requires 'ldap_clientkeyfile' to be set as well. + +ldap_clientkeyfile:: +The path to a key to be used with the client cert when talking to +the LDAP server. Note this requires 'ldap_clientcertfile' to be +set as well. + ldap_bind_user:: The user to attempt a LDAP bind as. diff --git a/pam_yubico.8.txt b/pam_yubico.8.txt index 415207b..de98d2e 100644 --- a/pam_yubico.8.txt +++ b/pam_yubico.8.txt @@ -80,6 +80,12 @@ The LDAP server host (default LDAP port is used). *Deprecated. Use 'ldap_uri' in *ldapdn*=_dn_:: The distinguished name (DN) where the users are stored (eg: ou=users,dc=domain,dc=com). If 'ldap_filter' is used this is the base from which the subtree search will be performed. +*ldap_clientcertfile*=_clientcertfile_:: +The path to a client cert file to use when talking to the LDAP server. Note this requires 'ldap_clientkeyfile' to be set as well. + +*ldap_clientkeyfile*=_clientkeyfile_:: +The path to a key to be used with the client cert when talking to the LDAP server. Note this requires 'ldap_clientcertfile' to be set as well. + *user_attr*=_attr_:: The LDAP attribute used to store user names (eg:cn). diff --git a/pam_yubico.c b/pam_yubico.c index e911060..2c6c5d9 100644 --- a/pam_yubico.c +++ b/pam_yubico.c @@ -125,6 +125,8 @@ struct cfg const char *ldap_filter; const char *ldap_cacertfile; const char *ldapdn; + const char *ldap_clientcertfile; + const char *ldap_clientkeyfile; const char *user_attr; const char *yubi_attr; const char *yubi_attr_prefix; @@ -292,6 +294,19 @@ authorize_user_token_ldap (struct cfg *cfg, ldap_set_option (0, LDAP_OPT_X_TLS_CACERTFILE, cfg->ldap_cacertfile); } + if (cfg->ldap_clientcertfile && cfg->ldap_clientkeyfile) { + rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_CERTFILE, cfg->ldap_clientcertfile); + if (rc != LDAP_SUCCESS) { + DBG ("tls_certfile: %s", ldap_err2string (rc)); + goto done; + } + rc = ldap_set_option (NULL, LDAP_OPT_X_TLS_KEYFILE, cfg->ldap_clientkeyfile); + if (rc != LDAP_SUCCESS) { + DBG ("tls_keyfile: %s", ldap_err2string (rc)); + goto done; + } + } + if (cfg->ldap_starttls) { rc = ldap_start_tls_s (ld, NULL, NULL); if (rc != LDAP_SUCCESS) { @@ -818,6 +833,10 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg) cfg->ldap_filter = argv[i] + 12; if (strncmp (argv[i], "ldap_cacertfile=", 16) == 0) cfg->ldap_cacertfile = argv[i] + 16; + if (strncmp (argv[i], "ldap_clientcertfile=", 20) == 0) + cfg->ldap_clientcertfile = argv[i] + 20; + if (strncmp (argv[i], "ldap_clientkeyfile=", 19) == 0) + cfg->ldap_clientkeyfile = argv[i] + 19; if (strncmp (argv[i], "ldapdn=", 7) == 0) cfg->ldapdn = argv[i] + 7; if (strncmp (argv[i], "user_attr=", 10) == 0) @@ -894,6 +913,8 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg) DBG ("ldap_filter=%s", cfg->ldap_filter ? cfg->ldap_filter : "(null)"); DBG ("ldap_cacertfile=%s", cfg->ldap_cacertfile ? cfg->ldap_cacertfile : "(null)"); DBG ("ldapdn=%s", cfg->ldapdn ? cfg->ldapdn : "(null)"); + DBG ("ldap_clientcertfile=%s", cfg->ldap_clientcertfile ? cfg->ldap_clientcertfile : "(null)"); + DBG ("ldap_clientkeyfile=%s", cfg->ldap_clientkeyfile ? cfg->ldap_clientkeyfile : "(null)"); DBG ("user_attr=%s", cfg->user_attr ? cfg->user_attr : "(null)"); DBG ("yubi_attr=%s", cfg->yubi_attr ? cfg->yubi_attr : "(null)"); DBG ("yubi_attr_prefix=%s", cfg->yubi_attr_prefix ? cfg->yubi_attr_prefix : "(null)");