http://bugs.gentoo.org/336449 Patch contributed by Jan Sembera In my environment, I'd like to use pam_skey as optional authentication measure that wouldn't replace the password, but would complement it. Ie. when the user sets the S/Key, he should be afterwards asked to provide the S/Key _and_ his password, without the possibility to just enter his password and circumvent S/Keys. On the other hand, when the user doesn't have S/Key set, he should be able to login with his password only. Why PAM would generally allow this, with the current internals of pam_skey, this setup isn't possible. You simply cannot distinguish between "user has no S/Key set" case (it returns IGNORE) and "user doesn't want to provide S/Key" (it returns IGNORE as well). I'm attaching a patch that will add option require_skey to pam_skey. When this option is set, module will require the user to successfully authenticate using S/key, and will return IGNORE only in case the user didn't set up his key. If this option isn't provided, the behaviour of the module doesn't change. --- pam_skey-orig/README +++ pam_skey/README @@ -21,7 +21,7 @@ - The options accepted by the pam_skey.so module are different, as described below. -Four options are accepted by the pam_skey.so module: +Five options are accepted by the pam_skey.so module: debug - This option turns on debug logging. try_first_pass - This option tells the module to first try using the authentication token passed from the @@ -44,6 +44,12 @@ cause the module to pass the given password to the next module in the authentication stack (usually pam_unix.so with the try_first_pass option). + require_skey - This option tells the module to require S/Key + authentication if the user has S/Key set. When + this option is set, it is possible to require both + S/Key and another authentication method (like + password) for successful login. This is mutually + exclusive with no_default_skey. The exact behavior of pam_skey.so is detailed below: @@ -54,21 +60,22 @@ if it is a valid response to the current S/Key challenge. If so, return PAM_SUCCESS. 3a. If the token is invalid and use_first_pass is enabled, return - PAM_IGNORE. + PAM_IGNORE (or PAM_AUTHERR if require_skey is set). 4. If no_default_skey is enabled, issue a "Password: " prompt. 4a. If the response is anything besides "s/key" (case insensitive), store it as the authentication token and return PAM_IGNORE. 5. Display the current S/Key challenge and request a response, with - input not echoed. If no_default_skey is enabled, this will only be - an S/Key response request; otherwise, it will request either an - S/Key response or a system passsword. + input not echoed. If no_default_skey or require_skey is enabled, + this will only be an S/Key response request; otherwise, it will + request either an S/Key response or a system passsword. 5a. If an empty response is given, request the S/Key response again, this time with input echoed. 5b. If the response is a valid S/Key response, return PAM_SUCCESS. Otherwise, return PAM_AUTHERR. 6. If the response is a valid S/Key response, return PAM_SUCCESS. -7. Otherwise, if no_default_skey is enabled (the user specifically - requested "s/key" authentication), return PAM_AUTHERR. +7. Otherwise, if no_default_skey is enabled (and the user specifically + requested "s/key" authentication), or if require_skey is enabled, + return PAM_AUTHERR. 8. Otherwise, store the response as the authentication token and return PAM_IGNORE. --- pam_skey-orig/pam_skey.c +++ pam_skey/pam_skey.c @@ -110,7 +110,7 @@ if (skey_passcheck(username, response) != -1) { return PAM_SUCCESS; } else if (mod_opt & _MOD_USE_FIRST_PASS) { - return PAM_IGNORE; + return (mod_opt & _MOD_REQUIRE_SKEY) ? PAM_AUTH_ERR : PAM_IGNORE; } } else if (mod_opt & _MOD_USE_FIRST_PASS) { return PAM_AUTHTOK_RECOVER_ERR; @@ -138,7 +138,7 @@ return PAM_AUTHINFO_UNAVAIL; } - if (mod_opt & _MOD_NO_DEFAULT_SKEY) + if ((mod_opt & _MOD_NO_DEFAULT_SKEY) || (mod_opt & _MOD_REQUIRE_SKEY)) status = mod_talk_touser(pamh, mod_opt, challenge, QUERY_RESPONSE, 0, &response); else status = mod_talk_touser(pamh, mod_opt, challenge, QUERY_RESPONSE_OR_PASSWORD, 0, &response); @@ -166,7 +166,7 @@ return PAM_SUCCESS; } - if (mod_opt & _MOD_NO_DEFAULT_SKEY) { + if ((mod_opt & _MOD_NO_DEFAULT_SKEY) || (mod_opt & _MOD_REQUIRE_SKEY)) { _pam_delete(response); return PAM_AUTH_ERR; } --- pam_skey-orig/pam_skey.h +++ pam_skey/pam_skey.h @@ -78,13 +78,14 @@ #define _MOD_TRY_FIRST_PASS 0x0002 /* Attempt using PAM_AUTHTOK */ #define _MOD_USE_FIRST_PASS 0x0004 /* Only use PAM_AUTHTOK */ #define _MOD_NO_DEFAULT_SKEY 0x0008 /* Don't use S/Key by default */ +#define _MOD_REQUIRE_SKEY 0x0010 /* Require S/Key if set */ /* Setup defaults - use echo off only */ #define _MOD_DEFAULT_FLAG _MOD_NONE_ON #define _MOD_DEFAULT_MASK _MOD_ALL_ON /* Number of parameters currently known */ -#define _MOD_ARGS 4 +#define _MOD_ARGS 5 /* Structure for flexible argument parsing */ typedef struct @@ -101,5 +102,6 @@ {"debug", _MOD_ALL_ON, _MOD_DEBUG}, {"try_first_pass", _MOD_ALL_ON, _MOD_TRY_FIRST_PASS}, {"use_first_pass", _MOD_ALL_ON, _MOD_USE_FIRST_PASS}, - {"no_default_skey", _MOD_ALL_ON, _MOD_NO_DEFAULT_SKEY} + {"no_default_skey", _MOD_ALL_ON & ~_MOD_REQUIRE_SKEY, _MOD_NO_DEFAULT_SKEY}, + {"require_skey", _MOD_ALL_ON & ~_MOD_NO_DEFAULT_SKEY, _MOD_REQUIRE_SKEY} };