mirror of
https://github.com/Yubico/yubico-pam.git
synced 2025-02-26 21:54:15 +01:00
Merge branch 'feature/ldap_refactor'
Conflicts: pam_yubico.c
This commit is contained in:
commit
8241cd0423
32
README
32
README
@ -20,7 +20,7 @@ later. This has introduced a dependency of libykpers-1 from the
|
|||||||
ykpersonalize package. Pass `--without-cr` to `configure` to avoid
|
ykpersonalize package. Pass `--without-cr` to `configure` to avoid
|
||||||
this dependency.
|
this dependency.
|
||||||
|
|
||||||
The development community is co-ordinated via
|
The development community is co-ordinated via
|
||||||
https://github.com/Yubico/yubico-pam[the GitHub project page].
|
https://github.com/Yubico/yubico-pam[the GitHub project page].
|
||||||
|
|
||||||
The project is licensed under a BSD license. See the file COPYING for
|
The project is licensed under a BSD license. See the file COPYING for
|
||||||
@ -150,7 +150,7 @@ service, go https://upgrade.yubico.com/getapikey[here].
|
|||||||
|
|
||||||
debug:: to enable debug output to stdout.
|
debug:: to enable debug output to stdout.
|
||||||
|
|
||||||
alwaysok::
|
alwaysok::
|
||||||
to enable all authentication attempts to succeed
|
to enable all authentication attempts to succeed
|
||||||
(aka presentation mode).
|
(aka presentation mode).
|
||||||
|
|
||||||
@ -310,10 +310,10 @@ information including the OTP and ID of your token to the shell -- copy the ID
|
|||||||
into your config file and you should be up and going.
|
into your config file and you should be up and going.
|
||||||
|
|
||||||
------
|
------
|
||||||
Yubikey for `youruser':
|
Yubikey for `youruser':
|
||||||
[pam_yubico.c:pam_sm_authenticate(867)] conv returned 44 bytes
|
[pam_yubico.c:pam_sm_authenticate(867)] conv returned 44 bytes
|
||||||
[pam_yubico.c:pam_sm_authenticate(885)] Skipping first 0 bytes. Length is 44, token_id set to 12 and token OTP always 32.
|
[pam_yubico.c:pam_sm_authenticate(885)] Skipping first 0 bytes. Length is 44, token_id set to 12 and token OTP always 32.
|
||||||
[pam_yubico.c:pam_sm_authenticate(892)] OTP: ccccccclabcabkhbdncicglfltnukadfoifadfhhhhfe ID: cccccclabcab
|
[pam_yubico.c:pam_sm_authenticate(892)] OTP: ccccccclabcabkhbdncicglfltnukadfoifadfhhhhfe ID: cccccclabcab
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
||||||
@ -336,5 +336,27 @@ Examples
|
|||||||
If you want to use the YubiKey to authenticate you on Linux console
|
If you want to use the YubiKey to authenticate you on Linux console
|
||||||
logins, add the following to the top of `/etc/pam.d/login`:
|
logins, add the following to the top of `/etc/pam.d/login`:
|
||||||
|
|
||||||
auth sufficient pam_yubico.so id=16 debug
|
auth sufficient pam_yubico.so id=16 debug
|
||||||
|
|
||||||
|
OpenVPN and ActiveDirectory
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
create file '/etc/pam.d/openvpn':
|
||||||
|
|
||||||
|
auth required pam_yubico.so ldap_uri=ldap://ldap-srv debug id=19 yubi_attr=pager
|
||||||
|
ldapdn=dc=ad,dc=next-audience,dc=net
|
||||||
|
ldap_filter=(&(sAMAccountName=%u)(memberOf=CN=mygroup,OU=DefaultUser,DC=adivser,DC=net))
|
||||||
|
ldap_bind_user=bind_user ldap_bind_password=bind_password try_first_pass
|
||||||
|
account required pam_yubico.so
|
||||||
|
|
||||||
|
create file 'openvpn.conf'
|
||||||
|
|
||||||
|
plugin openvpn-plugin-auth-pam.so openvpn
|
||||||
|
|
||||||
|
|
||||||
|
Feedback
|
||||||
|
--------
|
||||||
|
|
||||||
|
If you want to discuss anything related to the Yubico PAM module,
|
||||||
|
please e-mail the mailing list yubico-devel@googlegroups.com.
|
||||||
|
|
||||||
|
@ -57,10 +57,10 @@ This argument is used to show the OTP (One Time Password) when it is entered, i.
|
|||||||
Specify the LDAP server URI (e.g. ldap://localhost).
|
Specify the LDAP server URI (e.g. ldap://localhost).
|
||||||
|
|
||||||
*ldap_server*=_server_::
|
*ldap_server*=_server_::
|
||||||
Specify the LDAP server host (default LDAP port is used). *Deprecated. Use "ldap_uri" instead.*
|
Specify the LDAP server host (default LDAP port is used). *Deprecated. Use 'ldap_uri' instead.*
|
||||||
|
|
||||||
*ldapdn*=_dn_::
|
*ldapdn*=_dn_::
|
||||||
The dn where the users are stored (eg: ou=users,dc=domain,dc=com).
|
The 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.
|
||||||
|
|
||||||
*user_attr*=_attr_::
|
*user_attr*=_attr_::
|
||||||
The LDAP attribute used to store user names (eg:cn).
|
The LDAP attribute used to store user names (eg:cn).
|
||||||
@ -74,12 +74,26 @@ The prefix of the LDAP attribute's value, in case of a generic attribute, used t
|
|||||||
*token_id_length*=_length_::
|
*token_id_length*=_length_::
|
||||||
Length of ID prefixing the OTP (this is 12 if using the YubiCloud).
|
Length of ID prefixing the OTP (this is 12 if using the YubiCloud).
|
||||||
|
|
||||||
|
*ldap_bind_user*=_user_::
|
||||||
|
The user to attempt a LDAP bind as.
|
||||||
|
|
||||||
|
*ldap_bind_password*=_password_::
|
||||||
|
The password to use on LDAP bind.
|
||||||
|
|
||||||
|
*ldap_filter*=_filter_::
|
||||||
|
An ldap filter to use for attempting to find the correct object in LDAP. In this string %u will be replaced with the username.
|
||||||
|
|
||||||
|
*ldap_cacertfile*=_cacertfile_::
|
||||||
|
Ca certfile for the LDAP connection.
|
||||||
|
|
||||||
== EXAMPLES
|
== EXAMPLES
|
||||||
|
|
||||||
auth sufficient pam_yubico.so id=16 debug
|
auth sufficient pam_yubico.so id=16 debug
|
||||||
|
|
||||||
auth required pam_yubico.so mode=challenge-response
|
auth required pam_yubico.so mode=challenge-response
|
||||||
|
|
||||||
|
auth required pam_yubico.so id=16 ldap_uri=ldaps://ldap.example.com ldap_filter=(uid=%u) yubi_attr=yubiKeyId
|
||||||
|
|
||||||
== BUGS
|
== BUGS
|
||||||
Report yubico-pam bugs in the issue tracker: https://github.com/Yubico/yubico-pam/issues
|
Report yubico-pam bugs in the issue tracker: https://github.com/Yubico/yubico-pam/issues
|
||||||
|
|
||||||
|
148
pam_yubico.c
148
pam_yubico.c
@ -113,6 +113,10 @@ struct cfg
|
|||||||
const char *urllist;
|
const char *urllist;
|
||||||
const char *ldapserver;
|
const char *ldapserver;
|
||||||
const char *ldap_uri;
|
const char *ldap_uri;
|
||||||
|
const char *ldap_bind_user;
|
||||||
|
const char *ldap_bind_password;
|
||||||
|
const char *ldap_filter;
|
||||||
|
const char *ldap_cacertfile;
|
||||||
const char *ldapdn;
|
const char *ldapdn;
|
||||||
const char *user_attr;
|
const char *user_attr;
|
||||||
const char *yubi_attr;
|
const char *yubi_attr;
|
||||||
@ -193,8 +197,10 @@ free_out:
|
|||||||
* This function will look in ldap id the token correspond to the
|
* This function will look in ldap id the token correspond to the
|
||||||
* requested user. It will returns 0 for failure and 1 for success.
|
* requested user. It will returns 0 for failure and 1 for success.
|
||||||
*
|
*
|
||||||
* For the moment ldaps is not supported. ldap serve can be on a
|
* ldaps is only supported for ldap_uri based connections.
|
||||||
* remote host.
|
* ldap_cacertfile usually needs to be set for this to work.
|
||||||
|
*
|
||||||
|
* ldap serve can be on a remote host.
|
||||||
*
|
*
|
||||||
* You need the following parameters in you pam config:
|
* You need the following parameters in you pam config:
|
||||||
* ldapserver= OR ldap_uri=
|
* ldapserver= OR ldap_uri=
|
||||||
@ -202,6 +208,9 @@ free_out:
|
|||||||
* user_attr=
|
* user_attr=
|
||||||
* yubi_attr=
|
* yubi_attr=
|
||||||
*
|
*
|
||||||
|
* If using ldap_uri, you can specify multiple failover hosts
|
||||||
|
* eg.
|
||||||
|
* ldap_uri=ldaps://host1.fqdn.example.com,ldaps://host2.fqdn.example.com
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
authorize_user_token_ldap (struct cfg *cfg,
|
authorize_user_token_ldap (struct cfg *cfg,
|
||||||
@ -222,21 +231,18 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
struct berval **vals;
|
struct berval **vals;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
|
|
||||||
|
char *filter = NULL;
|
||||||
char *find = NULL;
|
char *find = NULL;
|
||||||
|
int scope = LDAP_SCOPE_BASE;
|
||||||
#endif
|
#endif
|
||||||
DBG(("called"));
|
DBG(("called"));
|
||||||
#ifdef HAVE_LIBLDAP
|
#ifdef HAVE_LIBLDAP
|
||||||
|
|
||||||
if (cfg->user_attr == NULL) {
|
|
||||||
DBG (("Trying to look up user to YubiKey mapping in LDAP, but user_attr not set!"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (cfg->yubi_attr == NULL) {
|
if (cfg->yubi_attr == NULL) {
|
||||||
DBG (("Trying to look up user to YubiKey mapping in LDAP, but yubi_attr not set!"));
|
DBG (("Trying to look up user to YubiKey mapping in LDAP, but yubi_attr not set!"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (cfg->ldapdn == NULL) {
|
if (cfg->user_attr && cfg->ldapdn == NULL) {
|
||||||
DBG (("Trying to look up user to YubiKey mapping in LDAP, but ldapdn not set!"));
|
DBG (("Trying to look up user to YubiKey mapping in LDAP, user_attr set but ldapdn not set!"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,7 +252,7 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
rc = ldap_initialize (&ld, cfg->ldap_uri);
|
rc = ldap_initialize (&ld, cfg->ldap_uri);
|
||||||
if (rc != LDAP_SUCCESS)
|
if (rc != LDAP_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG (("ldap_init: %s", ldap_err2string (rc)));
|
DBG (("ldap_initialize: %s", ldap_err2string (rc)));
|
||||||
retval = 0;
|
retval = 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -261,10 +267,21 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
|
||||||
ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);
|
ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &protocol);
|
||||||
|
|
||||||
|
if (cfg->ldap_uri && cfg->ldap_cacertfile) {
|
||||||
|
/* Set CA CERTFILE. This makes ldaps work when using ldap_uri */
|
||||||
|
ldap_set_option (0, LDAP_OPT_X_TLS_CACERTFILE, cfg->ldap_cacertfile);
|
||||||
|
}
|
||||||
/* Bind anonymously to the LDAP server. */
|
/* Bind anonymously to the LDAP server. */
|
||||||
rc = ldap_simple_bind_s (ld, NULL, NULL);
|
if (cfg->ldap_bind_user && cfg->ldap_bind_password) {
|
||||||
|
DBG (("try bind with: %s:[%s]", cfg->ldap_bind_user, cfg->ldap_bind_password));
|
||||||
|
rc = ldap_simple_bind_s (ld, cfg->ldap_bind_user, cfg->ldap_bind_password);
|
||||||
|
} else {
|
||||||
|
DBG (("try bind anonymous"));
|
||||||
|
rc = ldap_simple_bind_s (ld, NULL, NULL);
|
||||||
|
}
|
||||||
if (rc != LDAP_SUCCESS)
|
if (rc != LDAP_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG (("ldap_simple_bind_s: %s", ldap_err2string (rc)));
|
DBG (("ldap_simple_bind_s: %s", ldap_err2string (rc)));
|
||||||
@ -273,22 +290,30 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Allocation of memory for search strings depending on input size */
|
/* Allocation of memory for search strings depending on input size */
|
||||||
i = (strlen(cfg->user_attr) + strlen(cfg->ldapdn) + strlen(user) + 3) * sizeof(char);
|
if (cfg->user_attr && cfg->yubi_attr && cfg->ldapdn) {
|
||||||
if ((find = malloc(i)) == NULL) {
|
i = (strlen(cfg->user_attr) + strlen(cfg->ldapdn) + strlen(user) + 3) * sizeof(char);
|
||||||
DBG (("Failed allocating %i bytes", i));
|
if ((find = malloc(i)) == NULL) {
|
||||||
retval = 0;
|
DBG (("Failed allocating %i bytes", i));
|
||||||
goto done;
|
retval = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
sprintf (find, "%s=%s,%s", cfg->user_attr, user, cfg->ldapdn);
|
||||||
|
filter = NULL;
|
||||||
|
} else if (cfg->ldapdn) {
|
||||||
|
find = strdup(cfg->ldapdn); /* allow free later */
|
||||||
|
}
|
||||||
|
if (cfg->ldap_filter) {
|
||||||
|
filter = filter_printf(cfg->ldap_filter, user);
|
||||||
|
scope = LDAP_SCOPE_SUBTREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf (find, "%s=%s,%s", cfg->user_attr, user, cfg->ldapdn);
|
|
||||||
|
|
||||||
attrs[0] = (char *) cfg->yubi_attr;
|
attrs[0] = (char *) cfg->yubi_attr;
|
||||||
|
|
||||||
DBG(("LDAP : look up object '%s', ask for attribute '%s'", find, cfg->yubi_attr));
|
DBG(("LDAP : look up object base='%s' filter='%s', ask for attribute '%s'", find,
|
||||||
|
filter ? filter:"(null)", cfg->yubi_attr));
|
||||||
|
|
||||||
/* Search for the entry. */
|
/* Search for the entry. */
|
||||||
if ((rc = ldap_search_ext_s (ld, find, LDAP_SCOPE_BASE,
|
if ((rc = ldap_search_ext_s (ld, find, scope,
|
||||||
NULL, attrs, 0, NULL, NULL, LDAP_NO_LIMIT,
|
filter, attrs, 0, NULL, NULL, LDAP_NO_LIMIT,
|
||||||
LDAP_NO_LIMIT, &result)) != LDAP_SUCCESS)
|
LDAP_NO_LIMIT, &result)) != LDAP_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG (("ldap_search_ext_s: %s", ldap_err2string (rc)));
|
DBG (("ldap_search_ext_s: %s", ldap_err2string (rc)));
|
||||||
@ -312,16 +337,16 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
{
|
{
|
||||||
if ((vals = ldap_get_values_len (ld, e, a)) != NULL)
|
if ((vals = ldap_get_values_len (ld, e, a)) != NULL)
|
||||||
{
|
{
|
||||||
DBG(("LDAP : Found %i values - checking if any of them match '%s%s'",
|
|
||||||
ldap_count_values_len(vals),
|
|
||||||
cfg->yubi_attr_prefix ? cfg->yubi_attr_prefix : "",
|
|
||||||
token_id));
|
|
||||||
|
|
||||||
yubi_attr_prefix_len = cfg->yubi_attr_prefix ? strlen(cfg->yubi_attr_prefix) : 0;
|
yubi_attr_prefix_len = cfg->yubi_attr_prefix ? strlen(cfg->yubi_attr_prefix) : 0;
|
||||||
|
|
||||||
/* Compare each value for the attribute against the token id. */
|
/* Compare each value for the attribute against the token id. */
|
||||||
for (i = 0; vals[i] != NULL; i++)
|
for (i = 0; vals[i] != NULL; i++)
|
||||||
{
|
{
|
||||||
|
DBG(("LDAP : Found %i values - checking if any of them match '%s:%s:%s'",
|
||||||
|
ldap_count_values_len(vals),
|
||||||
|
vals[i]->bv_val,
|
||||||
|
cfg->yubi_attr_prefix ? cfg->yubi_attr_prefix : "", token_id));
|
||||||
|
|
||||||
/* Only values containing this prefix are considered. */
|
/* Only values containing this prefix are considered. */
|
||||||
if ((!cfg->yubi_attr_prefix || !strncmp (cfg->yubi_attr_prefix, vals[i]->bv_val, yubi_attr_prefix_len)))
|
if ((!cfg->yubi_attr_prefix || !strncmp (cfg->yubi_attr_prefix, vals[i]->bv_val, yubi_attr_prefix_len)))
|
||||||
{
|
{
|
||||||
@ -349,6 +374,8 @@ authorize_user_token_ldap (struct cfg *cfg,
|
|||||||
/* free memory allocated for search strings */
|
/* free memory allocated for search strings */
|
||||||
if (find != NULL)
|
if (find != NULL)
|
||||||
free(find);
|
free(find);
|
||||||
|
if (filter != NULL)
|
||||||
|
free(filter);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
DBG (("Trying to use LDAP, but this function is not compiled in pam_yubico!!"));
|
DBG (("Trying to use LDAP, but this function is not compiled in pam_yubico!!"));
|
||||||
@ -671,6 +698,14 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
|
|||||||
cfg->ldapserver = argv[i] + 11;
|
cfg->ldapserver = argv[i] + 11;
|
||||||
if (strncmp (argv[i], "ldap_uri=", 9) == 0)
|
if (strncmp (argv[i], "ldap_uri=", 9) == 0)
|
||||||
cfg->ldap_uri = argv[i] + 9;
|
cfg->ldap_uri = argv[i] + 9;
|
||||||
|
if (strncmp (argv[i], "ldap_bind_user=", 15) == 0)
|
||||||
|
cfg->ldap_bind_user = argv[i] + 15;
|
||||||
|
if (strncmp (argv[i], "ldap_bind_password=", 19) == 0)
|
||||||
|
cfg->ldap_bind_password = argv[i] + 19;
|
||||||
|
if (strncmp (argv[i], "ldap_filter=", 12) == 0)
|
||||||
|
cfg->ldap_filter = argv[i] + 12;
|
||||||
|
if (strncmp (argv[i], "ldap_cacertfile=", 16) == 0)
|
||||||
|
cfg->ldap_cacertfile = argv[i] + 16;
|
||||||
if (strncmp (argv[i], "ldapdn=", 7) == 0)
|
if (strncmp (argv[i], "ldapdn=", 7) == 0)
|
||||||
cfg->ldapdn = argv[i] + 7;
|
cfg->ldapdn = argv[i] + 7;
|
||||||
if (strncmp (argv[i], "user_attr=", 10) == 0)
|
if (strncmp (argv[i], "user_attr=", 10) == 0)
|
||||||
@ -705,6 +740,10 @@ parse_cfg (int flags, int argc, const char **argv, struct cfg *cfg)
|
|||||||
D (("authfile=%s", cfg->auth_file ? cfg->auth_file : "(null)"));
|
D (("authfile=%s", cfg->auth_file ? cfg->auth_file : "(null)"));
|
||||||
D (("ldapserver=%s", cfg->ldapserver ? cfg->ldapserver : "(null)"));
|
D (("ldapserver=%s", cfg->ldapserver ? cfg->ldapserver : "(null)"));
|
||||||
D (("ldap_uri=%s", cfg->ldap_uri ? cfg->ldap_uri : "(null)"));
|
D (("ldap_uri=%s", cfg->ldap_uri ? cfg->ldap_uri : "(null)"));
|
||||||
|
D (("ldap_bind_user=%s", cfg->ldap_bind_user ? cfg->ldap_bind_user : "(null)"));
|
||||||
|
D (("ldap_bind_password=%s", cfg->ldap_bind_password ? cfg->ldap_bind_password : "(null)"));
|
||||||
|
D (("ldap_filter=%s", cfg->ldap_filter ? cfg->ldap_filter : "(null)"));
|
||||||
|
D (("ldap_cacertfile=%s", cfg->ldap_cacertfile ? cfg->ldap_cacertfile : "(null)"));
|
||||||
D (("ldapdn=%s", cfg->ldapdn ? cfg->ldapdn : "(null)"));
|
D (("ldapdn=%s", cfg->ldapdn ? cfg->ldapdn : "(null)"));
|
||||||
D (("user_attr=%s", cfg->user_attr ? cfg->user_attr : "(null)"));
|
D (("user_attr=%s", cfg->user_attr ? cfg->user_attr : "(null)"));
|
||||||
D (("yubi_attr=%s", cfg->yubi_attr ? cfg->yubi_attr : "(null)"));
|
D (("yubi_attr=%s", cfg->yubi_attr ? cfg->yubi_attr : "(null)"));
|
||||||
@ -741,6 +780,7 @@ pam_sm_authenticate (pam_handle_t * pamh,
|
|||||||
size_t templates = 0;
|
size_t templates = 0;
|
||||||
char *urls[10];
|
char *urls[10];
|
||||||
char *tmpurl = NULL;
|
char *tmpurl = NULL;
|
||||||
|
char *onlypasswd = NULL;
|
||||||
|
|
||||||
parse_cfg (flags, argc, argv, cfg);
|
parse_cfg (flags, argc, argv, cfg);
|
||||||
|
|
||||||
@ -936,7 +976,7 @@ pam_sm_authenticate (pam_handle_t * pamh,
|
|||||||
/* user entered their system password followed by generated OTP? */
|
/* user entered their system password followed by generated OTP? */
|
||||||
if (password_len > TOKEN_OTP_LEN + cfg->token_id_length)
|
if (password_len > TOKEN_OTP_LEN + cfg->token_id_length)
|
||||||
{
|
{
|
||||||
char *onlypasswd = strdup (password);
|
onlypasswd = strdup (password);
|
||||||
|
|
||||||
if (! onlypasswd) {
|
if (! onlypasswd) {
|
||||||
retval = PAM_BUF_ERR;
|
retval = PAM_BUF_ERR;
|
||||||
@ -949,7 +989,6 @@ pam_sm_authenticate (pam_handle_t * pamh,
|
|||||||
"setting item PAM_AUTHTOK"));
|
"setting item PAM_AUTHTOK"));
|
||||||
|
|
||||||
retval = pam_set_item (pamh, PAM_AUTHTOK, onlypasswd);
|
retval = pam_set_item (pamh, PAM_AUTHTOK, onlypasswd);
|
||||||
free (onlypasswd);
|
|
||||||
if (retval != PAM_SUCCESS)
|
if (retval != PAM_SUCCESS)
|
||||||
{
|
{
|
||||||
DBG (("set_item returned error: %s", pam_strerror (pamh, retval)));
|
DBG (("set_item returned error: %s", pam_strerror (pamh, retval)));
|
||||||
@ -1008,6 +1047,8 @@ pam_sm_authenticate (pam_handle_t * pamh,
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (onlypasswd)
|
||||||
|
free(onlypasswd);
|
||||||
if (templates > 0)
|
if (templates > 0)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -1029,7 +1070,7 @@ done:
|
|||||||
retval = PAM_SUCCESS;
|
retval = PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
DBG (("done. [%s]", pam_strerror (pamh, retval)));
|
DBG (("done. [%s]", pam_strerror (pamh, retval)));
|
||||||
pam_set_data (pamh, "yubico_setcred_return", (void*) (intptr_t) retval, NULL);
|
pam_set_data (pamh, "yubico_setcred_return", (void*)(intptr_t)retval, NULL);
|
||||||
|
|
||||||
if (resp)
|
if (resp)
|
||||||
{
|
{
|
||||||
@ -1047,16 +1088,55 @@ pam_sm_setcred (pam_handle_t * pamh, int flags, int argc, const char **argv)
|
|||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
int rc = pam_get_data(pamh, "yubico_setcred_return", (const void**)&retval);
|
||||||
|
if (rc == PAM_SUCCESS && retval == PAM_SUCCESS) {
|
||||||
|
D (("pam_sm_acct_mgmt returing PAM_SUCCESS"));
|
||||||
|
return PAM_SUCCESS;
|
||||||
|
}
|
||||||
|
D (("pam_sm_acct_mgmt returing PAM_AUTH_ERR:%d", rc));
|
||||||
|
return PAM_AUTH_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_open_session(pam_handle_t *pamh, int flags,
|
||||||
|
int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
D(("pam_sm_open_session"));
|
||||||
|
return (PAM_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_close_session(pam_handle_t *pamh, int flags,
|
||||||
|
int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
D(("pam_sm_close_session"));
|
||||||
|
return (PAM_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
PAM_EXTERN int
|
||||||
|
pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||||
|
int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
D(("pam_sm_chauthtok"));
|
||||||
|
return (PAM_SERVICE_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef PAM_STATIC
|
#ifdef PAM_STATIC
|
||||||
|
|
||||||
struct pam_module _pam_yubico_modstruct = {
|
struct pam_module _pam_yubico_modstruct = {
|
||||||
"pam_yubico",
|
"pam_yubico",
|
||||||
pam_sm_authenticate,
|
pam_sm_authenticate,
|
||||||
pam_sm_setcred,
|
pam_sm_setcred,
|
||||||
NULL,
|
pam_sm_acct_mgmt,
|
||||||
NULL,
|
pam_sm_open_session,
|
||||||
NULL,
|
pam_sm_close_session,
|
||||||
NULL
|
pam_sm_chauthtok
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -43,8 +43,9 @@ use constant RESULT_OK => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
my %objects = (
|
my %objects = (
|
||||||
'uid=foo,ou=users,dc=example,dc=com' => ['vvincredible'],
|
'base=uid=foo,ou=users,dc=example,dc=com' => {keys => ['vvincredible']},
|
||||||
'uid=test,ou=users,dc=example,dc=com' =>['cccccccfhcbe', 'ccccccbchvth'],
|
'base=uid=test,ou=users,dc=example,dc=com' => {keys => ['cccccccfhcbe', 'ccccccbchvth']},
|
||||||
|
'sub:base=:(uid=test)' => {keys => ['cccccccfhcbe', 'ccccccbchvth'], dn => 'uid=test,out=users,dc=example,dc=com'},
|
||||||
);
|
);
|
||||||
|
|
||||||
sub bind {
|
sub bind {
|
||||||
@ -56,14 +57,22 @@ sub bind {
|
|||||||
sub search {
|
sub search {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $reqData = shift;
|
my $reqData = shift;
|
||||||
my $base = $reqData->{'baseObject'};
|
my $id;
|
||||||
my $id = $objects{$base};
|
my $base;
|
||||||
|
if($reqData->{'scope'} == 0) {
|
||||||
|
$base = $reqData->{'baseObject'};
|
||||||
|
$id = $objects{'base=' . $base};
|
||||||
|
} elsif($reqData->{'scope'} == 2) {
|
||||||
|
my $match = $reqData->{'filter'}->{'equalityMatch'};
|
||||||
|
$id = $objects{'sub:base=' . $reqData->{'baseObject'} . ':(' . $match->{'attributeDesc'} . '=' . $match->{'assertionValue'} . ')'};
|
||||||
|
$base = $id->{'dn'};
|
||||||
|
}
|
||||||
my @entries;
|
my @entries;
|
||||||
if($id) {
|
if($id) {
|
||||||
my $entry = Net::LDAP::Entry->new;
|
my $entry = Net::LDAP::Entry->new;
|
||||||
$entry->dn($base);
|
$entry->dn($base);
|
||||||
$entry->add(objectClass => [ "person" ]);
|
$entry->add(objectClass => [ "person" ]);
|
||||||
$entry->add(yubiKeyId => $id);
|
$entry->add(yubiKeyId => $id->{'keys'});
|
||||||
push @entries, $entry;
|
push @entries, $entry;
|
||||||
}
|
}
|
||||||
return RESULT_OK, @entries;
|
return RESULT_OK, @entries;
|
||||||
|
@ -63,7 +63,6 @@ static struct data {
|
|||||||
static const char *ldap_cfg[] = {
|
static const char *ldap_cfg[] = {
|
||||||
"id=1",
|
"id=1",
|
||||||
"urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
|
"urllist=http://localhost:"YKVAL_PORT2"/wsapi/2/verify;http://localhost:"YKVAL_PORT1"/wsapi/2/verify",
|
||||||
"authfile="AUTHFILE,
|
|
||||||
"ldap_uri=ldap://localhost:"LDAP_PORT,
|
"ldap_uri=ldap://localhost:"LDAP_PORT,
|
||||||
"ldapdn=ou=users,dc=example,dc=com",
|
"ldapdn=ou=users,dc=example,dc=com",
|
||||||
"user_attr=uid",
|
"user_attr=uid",
|
||||||
@ -71,6 +70,15 @@ static const char *ldap_cfg[] = {
|
|||||||
"debug"
|
"debug"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *ldap_cfg2[] = {
|
||||||
|
"id=1",
|
||||||
|
"urllist=http://localhost:"YKVAL_PORT1"/wsapi/2/verify;http://localhost:"YKVAL_PORT2"/wsapi/2/verify",
|
||||||
|
"ldap_uri=ldap://localhost:"LDAP_PORT,
|
||||||
|
"ldap_filter=(uid=%u)",
|
||||||
|
"yubi_attr=yubiKeyId",
|
||||||
|
"debug"
|
||||||
|
};
|
||||||
|
|
||||||
static const struct data *test_get_data(void *id) {
|
static const struct data *test_get_data(void *id) {
|
||||||
return &_data[(long)id];
|
return &_data[(long)id];
|
||||||
}
|
}
|
||||||
@ -212,6 +220,10 @@ static int test_authenticate_ldap2(void) {
|
|||||||
return pam_sm_authenticate(4, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
|
return pam_sm_authenticate(4, 0, sizeof(ldap_cfg) / sizeof(char*), ldap_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_authenticate_ldap3(void) {
|
||||||
|
return pam_sm_authenticate(4, 0, sizeof(ldap_cfg2) / sizeof(char*), ldap_cfg2);
|
||||||
|
}
|
||||||
|
|
||||||
static pid_t run_mock(const char *port, const char *type) {
|
static pid_t run_mock(const char *port, const char *type) {
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if(pid == 0) {
|
if(pid == 0) {
|
||||||
@ -251,28 +263,32 @@ int main(void) {
|
|||||||
ret = 5;
|
ret = 5;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LIBLDAP
|
if(test_authenticate3() != PAM_SUCCESS) {
|
||||||
if(test_authenticate_ldap1() != PAM_SUCCESS) {
|
|
||||||
ret = 6;
|
ret = 6;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_LIBLDAP
|
||||||
|
if(test_authenticate_ldap1() != PAM_SUCCESS) {
|
||||||
|
ret = 1001;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if(test_authenticate_ldap_fail1() != PAM_USER_UNKNOWN) {
|
if(test_authenticate_ldap_fail1() != PAM_USER_UNKNOWN) {
|
||||||
ret = 7;
|
ret = 1002;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(test_authenticate_ldap_fail2() != PAM_AUTH_ERR) {
|
if(test_authenticate_ldap_fail2() != PAM_AUTH_ERR) {
|
||||||
ret = 8;
|
ret = 1003;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(test_authenticate_ldap2() != PAM_SUCCESS) {
|
if(test_authenticate_ldap2() != PAM_SUCCESS) {
|
||||||
ret = 9;
|
ret = 1004;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if(test_authenticate_ldap3() != PAM_SUCCESS) {
|
||||||
|
ret = 1005;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(test_authenticate3() != PAM_SUCCESS) {
|
|
||||||
ret = 10;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kill(child, 9);
|
kill(child, 9);
|
||||||
|
@ -125,7 +125,27 @@ static void test_load_chalresp_state(void) {
|
|||||||
|
|
||||||
#endif /* HAVE_CR */
|
#endif /* HAVE_CR */
|
||||||
|
|
||||||
|
static void test_filter_printf(void) {
|
||||||
|
assert(filter_result_len("meno %u", "doof", NULL) == 10);
|
||||||
|
assert(filter_result_len("meno %u %u", "doof", NULL) == 15);
|
||||||
|
assert(filter_result_len("%u meno %u", "doof", NULL) == 15);
|
||||||
|
assert(filter_result_len("%u me %u no %u", "doof", NULL) == 21);
|
||||||
|
assert(filter_result_len("meno %w %%u", "doof", NULL) == 14);
|
||||||
|
assert(filter_result_len("meno %w %%u meno", "doof", NULL) == 19);
|
||||||
|
assert(filter_result_len("meno ", "doof", NULL) == 6);
|
||||||
|
|
||||||
|
assert(!strcmp(filter_printf("meno %u", "doof"), "meno doof"));
|
||||||
|
assert(!strcmp(filter_printf("meno %u %u", "doof"), "meno doof doof"));
|
||||||
|
assert(!strcmp(filter_printf("%u meno %u", "doof"), "doof meno doof"));
|
||||||
|
assert(!strcmp(filter_printf("%u me %u no %u", "doof"), "doof me doof no doof"));
|
||||||
|
assert(!strcmp(filter_printf("meno %w %%u", "doof"), "meno %w %doof"));
|
||||||
|
assert(!strcmp(filter_printf("meno %w %%u meno", "doof"), "meno %w %doof meno"));
|
||||||
|
assert(!strcmp(filter_printf("meno ", "doof"), "meno "));
|
||||||
|
printf("test_filter_printf OK\n");
|
||||||
|
}
|
||||||
|
|
||||||
int main (void) {
|
int main (void) {
|
||||||
|
test_filter_printf();
|
||||||
test_get_user_cfgfile_path();
|
test_get_user_cfgfile_path();
|
||||||
test_check_user_token();
|
test_check_user_token();
|
||||||
#if HAVE_CR
|
#if HAVE_CR
|
||||||
|
44
util.c
44
util.c
@ -35,6 +35,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -461,3 +464,44 @@ write_chalresp_state(FILE *f, CR_STATE *state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_CR */
|
#endif /* HAVE_CR */
|
||||||
|
|
||||||
|
size_t filter_result_len(const char *filter, const char *user, char *output) {
|
||||||
|
const char *part = NULL;
|
||||||
|
size_t result = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
part = strstr(filter, "%u");
|
||||||
|
if(part)
|
||||||
|
len = part - filter;
|
||||||
|
else
|
||||||
|
len = strlen(filter);
|
||||||
|
if (output)
|
||||||
|
{
|
||||||
|
strncpy(output, filter, len);
|
||||||
|
output += len;
|
||||||
|
}
|
||||||
|
result += len;
|
||||||
|
filter += len + 2;
|
||||||
|
if(part)
|
||||||
|
{
|
||||||
|
if(output)
|
||||||
|
{
|
||||||
|
strncpy(output, user, strlen(user));
|
||||||
|
output += strlen(user);
|
||||||
|
}
|
||||||
|
result += strlen(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(part);
|
||||||
|
|
||||||
|
if(output)
|
||||||
|
*output = '\0';
|
||||||
|
return(result + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *filter_printf(const char *filter, const char *user) {
|
||||||
|
char *result = malloc(filter_result_len(filter, user, NULL));
|
||||||
|
filter_result_len(filter, user, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
3
util.h
3
util.h
@ -96,4 +96,7 @@ int challenge_response(YK_KEY *yk, int slot,
|
|||||||
|
|
||||||
#endif /* HAVE_CR */
|
#endif /* HAVE_CR */
|
||||||
|
|
||||||
|
size_t filter_result_len(const char *filter, const char *user, char *output);
|
||||||
|
char *filter_printf(const char *filter, const char *user);
|
||||||
|
|
||||||
#endif /* __PAM_YUBICO_UTIL_H_INCLUDED__ */
|
#endif /* __PAM_YUBICO_UTIL_H_INCLUDED__ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user