source: openpam/trunk/modules/pam_oath/pam_oath.c @ 697

Last change on this file since 697 was 697, checked in by Dag-Erling Smørgrav, 7 years ago

s/oath_dummy_key/oath_key_dummy/

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.9 KB
Line 
1/*-
2 * Copyright (c) 2012-2013 Universitetet i Oslo
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id: pam_oath.c 697 2013-08-15 16:24:28Z des $
30 */
31
32#ifdef HAVE_CONFIG_H
33# include "config.h"
34#endif
35
36#include <limits.h>
37#include <pwd.h>
38#include <stdint.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#define PAM_SM_AUTH
44#define PAM_SM_ACCOUNT
45
46#include <security/pam_modules.h>
47#include <security/pam_appl.h>
48#include <security/oath.h>
49
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
72PAM_EXTERN int
73pam_sm_authenticate(pam_handle_t *pamh, int flags,
74        int argc, const char *argv[])
75{
76        enum pam_oath_nokey nokey, badkey;
77        struct passwd *pwd;
78        const char *user;
79        char *keyfile;
80        struct oath_key *key;
81        unsigned long response;
82        char *password, *end;
83        int pam_err, ret;
84
85        /* unused */
86        (void)flags;
87        (void)argc;
88        (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);
94
95        /* identify user */
96        if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
97                return (pam_err);
98        if ((pwd = getpwnam(user)) == NULL)
99                return (PAM_USER_UNKNOWN);
100
101        /* load key */
102        /* XXX implement additional schemes */
103        keyfile = calloc(1, strlen(pwd->pw_dir) + sizeof "/.otpauth");
104        if (keyfile == NULL)
105                return (PAM_SYSTEM_ERR);
106        sprintf(keyfile, "%s/.otpauth", pwd->pw_dir);
107        key = oath_key_from_file(keyfile);
108        free(keyfile);
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:
120                        return (PAM_AUTHINFO_UNAVAIL);
121                case nokey_fake:
122                        key = oath_key_dummy(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                }
130        }
131
132        /* get user's response */
133        pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
134            (const char **)&password, PAM_OATH_PROMPT);
135        if (pam_err != PAM_SUCCESS) {
136                oath_key_free(key);
137                return (pam_err);
138        }
139
140        /* convert to number */
141        response = strtoul(password, &end, 10);
142        if (end == password || *end != '\0')
143                response = ULONG_MAX;
144
145        /* verify response */
146        if (key->mode == om_hotp)
147                ret = oath_hotp_match(key, response, 1);
148        else
149                ret = oath_totp_match(key, response, 1);
150        oath_key_free(key);
151        if (ret != 1)
152                return (PAM_AUTH_ERR);
153
154        /* XXX write back */
155        return (PAM_SUCCESS);
156}
157
158PAM_EXTERN int
159pam_sm_setcred(pam_handle_t *pamh, int flags,
160        int argc, const char *argv[])
161{
162
163        /* unused */
164        (void)pamh;
165        (void)flags;
166        (void)argc;
167        (void)argv;
168        return (PAM_SUCCESS);
169}
170
171PAM_EXTERN int
172pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
173        int argc, const char *argv[])
174{
175
176        /* unused */
177        (void)pamh;
178        (void)flags;
179        (void)argc;
180        (void)argv;
181        return (PAM_SUCCESS);
182}
183
184PAM_MODULE_ENTRY("pam_unix");
Note: See TracBrowser for help on using the repository browser.