~ubuntu-branches/ubuntu/vivid/dovecot/vivid

« back to all changes in this revision

Viewing changes to src/auth/mech-cram-md5.c

  • Committer: Bazaar Package Importer
  • Author(s): Jaldhar H. Vyas
  • Date: 2005-11-05 23:19:19 UTC
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051105231919-ydujs4y7687fpor2
Tags: upstream-1.0.alpha4
ImportĀ upstreamĀ versionĀ 1.0.alpha4

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
#include "ioloop.h"
8
8
#include "buffer.h"
9
9
#include "hex-binary.h"
10
 
#include "md5.h"
 
10
#include "hmac-md5.h"
11
11
#include "randgen.h"
12
12
#include "mech.h"
13
13
#include "passdb.h"
42
42
                buf[i] = (buf[i] % 10) + '0';
43
43
        buf[sizeof(buf)-1] = '\0';
44
44
 
45
 
        return t_strdup_printf("<%s.%s@%s>", buf, dec2str(ioloop_time),
46
 
                               my_hostname);
 
45
        return t_strdup_printf("<%s.%s@%s>", (const char *)buf,
 
46
                               dec2str(ioloop_time), my_hostname);
47
47
}
48
48
 
49
 
static int verify_credentials(struct cram_auth_request *auth,
 
49
static int verify_credentials(struct cram_auth_request *request,
50
50
                              const char *credentials)
51
51
{
52
52
        
53
 
        unsigned char digest[16], context_digest[32], *cdp;
54
 
        struct md5_context ctxo, ctxi;
 
53
        unsigned char digest[16], context_digest[32];
 
54
        struct hmac_md5_context ctx;
55
55
        buffer_t *context_digest_buf;
56
56
        const char *response_hex;
57
57
 
58
 
        if (credentials == NULL)
59
 
                return FALSE;
60
 
 
61
58
        context_digest_buf =
62
 
                buffer_create_data(data_stack_pool,
 
59
                buffer_create_data(pool_datastack_create(),
63
60
                                   context_digest, sizeof(context_digest));
64
61
 
65
 
        if (hex_to_binary(credentials, context_digest_buf) <= 0)
 
62
        if (hex_to_binary(credentials, context_digest_buf) < 0) {
 
63
                auth_request_log_error(&request->auth_request, "cram-md5",
 
64
                                       "passdb credentials are not in hex");
66
65
                return FALSE;
67
 
 
68
 
#define CDGET(p, c) STMT_START { \
69
 
        (c)  = (*p++);           \
70
 
        (c) += (*p++ << 8);      \
71
 
        (c) += (*p++ << 16);     \
72
 
        (c) += (*p++ << 24);     \
73
 
} STMT_END
74
 
 
75
 
        cdp = context_digest;
76
 
        CDGET(cdp, ctxo.a);
77
 
        CDGET(cdp, ctxo.b);
78
 
        CDGET(cdp, ctxo.c);
79
 
        CDGET(cdp, ctxo.d);
80
 
        CDGET(cdp, ctxi.a);
81
 
        CDGET(cdp, ctxi.b);
82
 
        CDGET(cdp, ctxi.c);
83
 
        CDGET(cdp, ctxi.d);
84
 
 
85
 
        ctxo.lo = ctxi.lo = 64;
86
 
        ctxo.hi = ctxi.hi = 0;
87
 
 
88
 
        md5_update(&ctxi, auth->challenge, strlen(auth->challenge));
89
 
        md5_final(&ctxi, digest);
90
 
        md5_update(&ctxo, digest, 16);
91
 
        md5_final(&ctxo, digest);
 
66
        }
 
67
 
 
68
        hmac_md5_set_cram_context(&ctx, context_digest);
 
69
        hmac_md5_update(&ctx, request->challenge, strlen(request->challenge));
 
70
        hmac_md5_final(&ctx, digest);
 
71
 
92
72
        response_hex = binary_to_hex(digest, 16);
93
73
 
94
 
        if (memcmp(response_hex, auth->response, 32) != 0) {
95
 
                if (verbose) {
96
 
                        i_info("cram-md5(%s): password mismatch",
97
 
                               auth->username);
98
 
                }
 
74
        if (memcmp(response_hex, request->response, 32) != 0) {
 
75
                auth_request_log_info(&request->auth_request, "cram-md5",
 
76
                                      "password mismatch");
99
77
                return FALSE;
100
78
        }
101
79
 
102
80
        return TRUE;
103
81
}
104
82
 
105
 
static int parse_cram_response(struct cram_auth_request *auth,
 
83
static int parse_cram_response(struct cram_auth_request *request,
106
84
                               const unsigned char *data, size_t size,
107
85
                               const char **error_r)
108
86
{
109
 
        size_t i;
 
87
        size_t i, space;
110
88
 
111
89
        *error_r = NULL;
112
90
 
113
 
        for (i = 0; i < size; i++) {
 
91
        /* <username> SPACE <response>. Username may contain spaces, so assume
 
92
           the rightmost space is the response separator. */
 
93
        for (i = space = 0; i < size; i++) {
114
94
                if (data[i] == ' ')
115
 
                        break;
 
95
                        space = i;
116
96
        }
117
97
 
118
 
        if (i == size) {
 
98
        if (space == 0) {
119
99
                *error_r = "missing digest";
120
100
                return FALSE;
121
101
        }
122
102
 
123
 
        auth->username = p_strndup(auth->pool, data, i);
124
 
        i++;
125
 
        auth->response = p_strndup(auth->pool, data + i, size - i);
 
103
        request->username = p_strndup(request->pool, data, space);
 
104
        space++;
 
105
        request->response =
 
106
                p_strndup(request->pool, data + space, size - space);
126
107
        return TRUE;
127
108
}
128
109
 
129
 
static void credentials_callback(const char *result,
130
 
                                 struct auth_request *request)
 
110
static void credentials_callback(enum passdb_result result,
 
111
                                 const char *credentials,
 
112
                                 struct auth_request *auth_request)
131
113
{
132
 
        struct cram_auth_request *auth =
133
 
                (struct cram_auth_request *) request;
 
114
        struct cram_auth_request *request =
 
115
                (struct cram_auth_request *)auth_request;
134
116
 
135
 
        if (verify_credentials(auth, result)) {
136
 
                if (verbose) {
137
 
                        i_info("cram-md5(%s): authenticated",
138
 
                               auth->username == NULL ? "" : auth->username);
139
 
                }
140
 
                mech_auth_finish(request, NULL, 0, TRUE);
141
 
        } else {
142
 
                if (verbose) {
143
 
                        i_info("cram-md5(%s): authentication failed",
144
 
                               auth->username == NULL ? "" : auth->username);
145
 
                }
146
 
                mech_auth_finish(request, NULL, 0, FALSE);
 
117
        switch (result) {
 
118
        case PASSDB_RESULT_OK:
 
119
                if (verify_credentials(request, credentials))
 
120
                        auth_request_success(auth_request, NULL, 0);
 
121
                else
 
122
                        auth_request_fail(auth_request);
 
123
                break;
 
124
        case PASSDB_RESULT_INTERNAL_FAILURE:
 
125
                auth_request_internal_failure(auth_request);
 
126
                break;
 
127
        default:
 
128
                auth_request_fail(auth_request);
 
129
                break;
147
130
        }
148
131
}
149
132
 
150
 
static int
 
133
static void
151
134
mech_cram_md5_auth_continue(struct auth_request *auth_request,
152
 
        struct auth_login_request_continue *request __attr_unused__,
153
 
        const unsigned char *data,
154
 
        mech_callback_t *callback)
 
135
                            const unsigned char *data, size_t data_size)
155
136
{
156
 
        struct cram_auth_request *auth =
 
137
        struct cram_auth_request *request =
157
138
                (struct cram_auth_request *)auth_request;
158
139
        const char *error;
159
140
 
160
 
        if (parse_cram_response(auth, data, request->data_size, &error)) {
161
 
                auth_request->callback = callback;
162
 
 
163
 
                auth_request->user =
164
 
                        p_strdup(auth_request->pool, auth->username);
165
 
 
166
 
                if (mech_is_valid_username(auth_request->user)) {
167
 
                        passdb->lookup_credentials(&auth->auth_request,
168
 
                                                   PASSDB_CREDENTIALS_CRAM_MD5,
169
 
                                                   credentials_callback);
170
 
                        return TRUE;
 
141
        if (parse_cram_response(request, data, data_size, &error)) {
 
142
                if (auth_request_set_username(auth_request, request->username,
 
143
                                              &error)) {
 
144
                        auth_request_lookup_credentials(auth_request,
 
145
                                                PASSDB_CREDENTIALS_CRAM_MD5,
 
146
                                                credentials_callback);
 
147
                        return;
171
148
                }
172
 
 
173
 
                error = "invalid username";
174
149
        }
175
150
 
176
151
        if (error == NULL)
177
152
                error = "authentication failed";
178
153
 
179
 
        if (verbose) {
180
 
                i_info("cram-md5(%s): %s",
181
 
                       auth->username == NULL ? "" : auth->username, error);
182
 
        }
183
 
 
184
 
        /* failed */
185
 
        mech_auth_finish(auth_request, NULL, 0, FALSE);
186
 
        return FALSE;
187
 
}
188
 
 
189
 
static void mech_cram_md5_auth_free(struct auth_request *auth_request)
190
 
{
191
 
        pool_unref(auth_request->pool);
192
 
}
193
 
 
194
 
static struct auth_request *
195
 
mech_cram_md5_auth_new(struct login_connection *conn,
196
 
                       unsigned int id, mech_callback_t *callback)
197
 
{
198
 
        struct auth_login_reply reply;
199
 
        struct cram_auth_request *auth;
 
154
        auth_request_log_info(auth_request, "cram-md5", "%s", error);
 
155
        auth_request_fail(auth_request);
 
156
}
 
157
 
 
158
static void
 
159
mech_cram_md5_auth_initial(struct auth_request *auth_request,
 
160
                           const unsigned char *data __attr_unused__,
 
161
                           size_t data_size __attr_unused__)
 
162
{
 
163
        struct cram_auth_request *request =
 
164
                (struct cram_auth_request *)auth_request;
 
165
 
 
166
        request->challenge = p_strdup(request->pool, get_cram_challenge());
 
167
        auth_request->callback(auth_request, AUTH_CLIENT_RESULT_CONTINUE,
 
168
                               request->challenge, strlen(request->challenge));
 
169
}
 
170
 
 
171
static void mech_cram_md5_auth_free(struct auth_request *request)
 
172
{
 
173
        pool_unref(request->pool);
 
174
}
 
175
 
 
176
static struct auth_request *mech_cram_md5_auth_new(void)
 
177
{
 
178
        struct cram_auth_request *request;
200
179
        pool_t pool;
201
180
 
202
181
        pool = pool_alloconly_create("cram_md5_auth_request", 2048);
203
 
        auth = p_new(pool, struct cram_auth_request, 1);
204
 
        auth->pool = pool;
205
 
 
206
 
        auth->auth_request.pool = pool;
207
 
        auth->auth_request.auth_continue = mech_cram_md5_auth_continue;
208
 
        auth->auth_request.auth_free = mech_cram_md5_auth_free;
209
 
 
210
 
        auth->challenge = p_strdup(auth->pool, get_cram_challenge());
211
 
 
212
 
        /* initialize reply */
213
 
        mech_init_login_reply(&reply);
214
 
        reply.id = id;
215
 
        reply.result = AUTH_LOGIN_RESULT_CONTINUE;
216
 
 
217
 
        /* send the initial challenge */
218
 
        reply.reply_idx = 0;
219
 
        reply.data_size = strlen(auth->challenge);
220
 
        callback(&reply, auth->challenge, conn);
221
 
 
222
 
        return &auth->auth_request;
 
182
        request = p_new(pool, struct cram_auth_request, 1);
 
183
        request->pool = pool;
 
184
 
 
185
        request->auth_request.pool = pool;
 
186
        return &request->auth_request;
223
187
}
224
188
 
225
189
struct mech_module mech_cram_md5 = {
226
 
        AUTH_MECH_CRAM_MD5,
227
 
        mech_cram_md5_auth_new
 
190
        "CRAM-MD5",
 
191
 
 
192
        MEMBER(flags) MECH_SEC_DICTIONARY | MECH_SEC_ACTIVE,
 
193
 
 
194
        MEMBER(passdb_need_plain) FALSE,
 
195
        MEMBER(passdb_need_credentials) TRUE,
 
196
 
 
197
        mech_cram_md5_auth_new,
 
198
        mech_cram_md5_auth_initial,
 
199
        mech_cram_md5_auth_continue,
 
200
        mech_cram_md5_auth_free
228
201
};