~ubuntu-branches/ubuntu/saucy/sssd/saucy

« back to all changes in this revision

Viewing changes to server/responder/pam/pamsrv_cache.c

  • Committer: Stéphane Graber
  • Date: 2011-06-15 16:23:14 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: stgraber@ubuntu.com-20110615162314-rbhoppnpaxfqo5q7
Merge 1.5.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
   SSSD
3
 
 
4
 
   PAM cache credentials
5
 
 
6
 
   Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
7
 
   Copyright (C) Sumit Bose <sbose@redhat.com>  2009
8
 
 
9
 
   This program is free software; you can redistribute it and/or modify
10
 
   it under the terms of the GNU General Public License as published by
11
 
   the Free Software Foundation; either version 3 of the License, or
12
 
   (at your option) any later version.
13
 
 
14
 
   This program is distributed in the hope that it will be useful,
15
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
   GNU General Public License for more details.
18
 
 
19
 
   You should have received a copy of the GNU General Public License
20
 
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
*/
22
 
 
23
 
#include <security/pam_modules.h>
24
 
#include <time.h>
25
 
#include "util/util.h"
26
 
#include "db/sysdb.h"
27
 
#include "util/nss_sha512crypt.h"
28
 
#include "providers/data_provider.h"
29
 
#include "responder/pam/pamsrv.h"
30
 
 
31
 
static int authtok2str(const void *mem_ctx,
32
 
                       uint8_t *src, const int src_size,
33
 
                       char **_dest)
34
 
{
35
 
    char *dest;
36
 
 
37
 
    if ((src == NULL && src_size != 0) ||
38
 
        (src != NULL && *src != '\0' && src_size == 0)) {
39
 
        return EINVAL;
40
 
    }
41
 
 
42
 
    dest = talloc_size(mem_ctx, src_size + 1);
43
 
    if (dest == NULL) {
44
 
        return ENOMEM;
45
 
    }
46
 
 
47
 
    memcpy(dest, src, src_size);
48
 
    dest[src_size]='\0';
49
 
 
50
 
    *_dest = dest;
51
 
    return EOK;
52
 
}
53
 
 
54
 
static void pam_cache_auth_return(struct pam_auth_req *preq, int error)
55
 
{
56
 
    preq->pd->pam_status = error;
57
 
    preq->callback(preq);
58
 
}
59
 
 
60
 
static void pam_cache_auth_callback(void *pvt, int ldb_status,
61
 
                                    struct ldb_result *res)
62
 
{
63
 
    struct pam_auth_req *preq;
64
 
    struct pam_ctx *pctx;
65
 
    struct pam_data *pd;
66
 
    const char *userhash;
67
 
    char *comphash;
68
 
    char *password = NULL;
69
 
    int i, ret;
70
 
    uint64_t lastLogin = 0;
71
 
 
72
 
    preq = talloc_get_type(pvt, struct pam_auth_req);
73
 
    pd = preq->pd;
74
 
 
75
 
    pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
76
 
 
77
 
    if (ldb_status != LDB_SUCCESS) {
78
 
        DEBUG(4, ("User info retrieval failed! (%d [%s])\n",
79
 
                  ldb_status, sysdb_error_to_errno(ldb_status)));
80
 
 
81
 
        ret = PAM_SYSTEM_ERR;
82
 
        goto done;
83
 
    }
84
 
 
85
 
    if (res->count == 0) {
86
 
        DEBUG(4, ("User [%s@%s] not found.\n",
87
 
                  pd->user, preq->domain->name));
88
 
        ret = PAM_USER_UNKNOWN;
89
 
        goto done;
90
 
    }
91
 
 
92
 
    if (res->count != 1) {
93
 
        DEBUG(4, ("Too many results for user [%s@%s].\n",
94
 
                  pd->user, preq->domain->name));
95
 
        ret = PAM_SYSTEM_ERR;
96
 
        goto done;
97
 
    }
98
 
 
99
 
    /* Check offline_auth_cache_timeout */
100
 
    lastLogin = ldb_msg_find_attr_as_uint64(res->msgs[0],
101
 
                                            SYSDB_LAST_ONLINE_AUTH,
102
 
                                            0);
103
 
    if (pctx->cred_expiration &&
104
 
        lastLogin + (pctx->cred_expiration * 86400) < time(NULL)) {
105
 
        DEBUG(4, ("Cached user entry is too old."));
106
 
        ret = PAM_AUTHINFO_UNAVAIL;
107
 
        goto done;
108
 
    }
109
 
 
110
 
    /* TODO: verify user account (failed logins, disabled, expired ...) */
111
 
 
112
 
    ret = authtok2str(preq, pd->authtok, pd->authtok_size, &password);
113
 
    if (ret) {
114
 
        DEBUG(4, ("Invalid auth token.\n"));
115
 
        ret = PAM_AUTH_ERR;
116
 
        goto done;
117
 
    }
118
 
 
119
 
    userhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_CACHEDPWD, NULL);
120
 
    if (userhash == NULL || *userhash == '\0') {
121
 
        DEBUG(4, ("Cached credentials not available.\n"));
122
 
        ret = PAM_AUTHINFO_UNAVAIL;
123
 
        goto done;
124
 
    }
125
 
 
126
 
    ret = s3crypt_sha512(preq, password, userhash, &comphash);
127
 
    if (ret) {
128
 
        DEBUG(4, ("Failed to create password hash.\n"));
129
 
        ret = PAM_SYSTEM_ERR;
130
 
        goto done;
131
 
    }
132
 
 
133
 
    if (strcmp(userhash, comphash) == 0) {
134
 
        /* TODO: probable good point for audit logging */
135
 
        DEBUG(4, ("Hashes do match!\n"));
136
 
        ret = PAM_SUCCESS;
137
 
        goto done;
138
 
    }
139
 
 
140
 
    DEBUG(4, ("Authentication failed.\n"));
141
 
    ret = PAM_AUTH_ERR;
142
 
 
143
 
done:
144
 
    if (password) for (i = 0; password[i]; i++) password[i] = 0;
145
 
    pam_cache_auth_return(preq, ret);
146
 
}
147
 
 
148
 
int pam_cache_auth(struct pam_auth_req *preq)
149
 
{
150
 
    struct sysdb_ctx *sysdb;
151
 
    int ret;
152
 
 
153
 
    static const char *attrs[] = {SYSDB_NAME,
154
 
                                  SYSDB_CACHEDPWD,
155
 
                                  SYSDB_DISABLED,
156
 
                                  SYSDB_LAST_LOGIN,
157
 
                                  SYSDB_LAST_ONLINE_AUTH,
158
 
                                  "lastCachedPasswordChange",
159
 
                                  "accountExpires",
160
 
                                  "failedLoginAttempts",
161
 
                                  "lastFailedLogin",
162
 
                                  NULL};
163
 
 
164
 
    ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
165
 
                                  preq->domain, &sysdb);
166
 
    if (ret != EOK) {
167
 
        DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
168
 
        return ret;
169
 
    }
170
 
    ret = sysdb_get_user_attr(preq, sysdb,
171
 
                              preq->domain, preq->pd->user, attrs,
172
 
                              pam_cache_auth_callback, preq);
173
 
 
174
 
    if (ret != EOK) {
175
 
        DEBUG(2, ("sysdb_get_user_attr failed.\n"));
176
 
    }
177
 
 
178
 
    return ret;
179
 
}
180