Changeset 676 in openpam


Ignore:
Timestamp:
Mar 18, 2013, 7:20:54 PM (8 years ago)
Author:
Dag-Erling Smørgrav
Message:
  • Add module options for specifying what to do if the user has no key or if the key was unreadable or invalid.
  • Fix inverted success / failure logic.

The module is now in a (barely) usable state.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/modules/pam_oath/pam_oath.c

    r646 r676  
    4848#include <security/oath.h>
    4949
     50#define PAM_OATH_PROMPT "Verification code: "
     51
     52enum pam_oath_nokey { nokey_error = -1, nokey_fail, nokey_fake, nokey_ignore };
     53
     54static enum pam_oath_nokey
     55get_nokey_option(pam_handle_t *pamh, const char *option)
     56{
     57        const char *value;
     58
     59        if ((value = openpam_get_option(pamh, option)) == NULL)
     60                return (nokey_fail);
     61        else if (strcmp(value, "fail") == 0)
     62                return (nokey_fail);
     63        else if (strcmp(value, "fake") == 0)
     64                return (nokey_fake);
     65        else if (strcmp(value, "ignore") == 0)
     66                return (nokey_ignore);
     67        openpam_log(PAM_LOG_ERROR, "the value of the %s option "
     68            "must be either 'fail', 'fake' or 'ignore'", option);
     69        return (nokey_error);
     70}
     71
    5072PAM_EXTERN int
    5173pam_sm_authenticate(pam_handle_t *pamh, int flags,
    5274        int argc, const char *argv[])
    5375{
     76        enum pam_oath_nokey nokey, badkey;
    5477        struct passwd *pwd;
    5578        const char *user;
    5679        char *keyfile;
    5780        struct oath_key *key;
    58         unsigned long code;
     81        unsigned long response;
    5982        char *password, *end;
    6083        int pam_err, ret;
    6184
     85        /* unused */
    6286        (void)flags;
    6387        (void)argc;
    6488        (void)argv;
     89
     90        /* check how to behave if the user does not have a valid key */
     91        if ((nokey = get_nokey_option(pamh, "nokey")) == nokey_error ||
     92            (badkey = get_nokey_option(pamh, "badkey")) == nokey_error)
     93                return (PAM_SERVICE_ERR);
    6594
    6695        /* identify user */
     
    71100
    72101        /* load key */
     102        /* XXX implement additional schemes */
    73103        keyfile = calloc(1, strlen(pwd->pw_dir) + sizeof "/.otpauth");
    74104        if (keyfile == NULL)
    75105                return (PAM_SYSTEM_ERR);
    76106        sprintf(keyfile, "%s/.otpauth", pwd->pw_dir);
     107        key = oath_key_from_file(keyfile);
    77108        free(keyfile);
    78         if ((key = oath_key_from_file(keyfile)) == NULL) {
    79                 /* no key, fake it? */
    80                 if (openpam_get_option(pamh, "fakeauth") == NULL)
     109
     110        /*
     111         * The user doesn't have a key, should we fake it?
     112         *
     113         * XXX implement badkey - currently, oath_key_from_file() doesn't
     114         * provide enough information for us to tell the difference
     115         * between a bad key and no key at all.
     116         */
     117        if (key == NULL) {
     118                switch (nokey) {
     119                case nokey_fail:
    81120                        return (PAM_AUTHINFO_UNAVAIL);
    82                 key = oath_dummy_key(om_hotp, oh_sha1, 6);
     121                case nokey_fake:
     122                        key = oath_dummy_key(om_hotp, oh_sha1, 6);
     123                        break;
     124                case nokey_ignore:
     125                        return (PAM_IGNORE);
     126                default:
     127                        /* can't happen */
     128                        return (PAM_SERVICE_ERR);
     129                }
    83130        }
    84131
    85         /* get code */
     132        /* get user's response */
    86133        pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
    87             (const char **)&password, NULL);
    88         if (pam_err == PAM_CONV_ERR)
     134            (const char **)&password, PAM_OATH_PROMPT);
     135        if (pam_err != PAM_SUCCESS) {
     136                oath_key_free(key);
    89137                return (pam_err);
    90         if (pam_err != PAM_SUCCESS)
    91                 return (PAM_AUTH_ERR);
     138        }
    92139
    93140        /* convert to number */
    94         code = strtoul(password, &end, 10);
     141        response = strtoul(password, &end, 10);
    95142        if (end == password || *end != '\0')
    96                 code = ULONG_MAX;
     143                response = ULONG_MAX;
    97144
    98145        /* verify response */
    99146        if (key->mode == om_hotp)
    100                 ret = oath_hotp_match(key, code, 1);
     147                ret = oath_hotp_match(key, response, 1);
    101148        else
    102                 ret = oath_totp_match(key, code, 1);
     149                ret = oath_totp_match(key, response, 1);
    103150        oath_key_free(key);
    104         if (ret != 0)
     151        if (ret != 1)
    105152                return (PAM_AUTH_ERR);
    106153
     
    114161{
    115162
     163        /* unused */
    116164        (void)pamh;
    117165        (void)flags;
     
    126174{
    127175
     176        /* unused */
    128177        (void)pamh;
    129178        (void)flags;
Note: See TracChangeset for help on using the changeset viewer.