~ubuntu-branches/ubuntu/feisty/freeradius/feisty-security

« back to all changes in this revision

Viewing changes to src/modules/rlm_digest/rlm_digest.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2006-12-16 20:45:11 UTC
  • mfrom: (3.1.10 feisty)
  • Revision ID: james.westby@ubuntu.com-20061216204511-3pbbsu4s8jtehsor
Tags: 1.1.3-3
Fix POSIX compliance problem in init script.  Closes: #403384. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * rlm_chap.c
3
3
 *
4
 
 * Version:  $Id: rlm_digest.c,v 1.5 2004/05/15 14:57:41 mgriego Exp $
 
4
 * Version:  $Id: rlm_digest.c,v 1.5.4.5 2006/04/28 23:44:31 aland Exp $
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
7
7
 *   it under the terms of the GNU General Public License as published by
22
22
 */
23
23
 
24
24
#include "autoconf.h"
25
 
#include "libradius.h"
26
25
 
27
26
#include <stdio.h>
28
27
#include <stdlib.h>
31
30
#include "radiusd.h"
32
31
#include "modules.h"
33
32
#include "conffile.h"
34
 
#include "rad_assert.h"
35
33
 
36
 
static const char rcsid[] = "$Id: rlm_digest.c,v 1.5 2004/05/15 14:57:41 mgriego Exp $";
 
34
static const char rcsid[] = "$Id: rlm_digest.c,v 1.5.4.5 2006/04/28 23:44:31 aland Exp $";
37
35
 
38
36
static int digest_authorize(void *instance, REQUEST *request)
39
37
{
68
66
        }
69
67
 
70
68
        /*
 
69
         *      Everything's OK, add a digest authentication type.
 
70
         */
 
71
        if (pairfind(request->config_items, PW_AUTHTYPE) == NULL) {
 
72
                DEBUG("rlm_digest: Adding Auth-Type = DIGEST");
 
73
                pairadd(&request->config_items,
 
74
                        pairmake("Auth-Type", "DIGEST", T_OP_EQ));
 
75
        }
 
76
 
 
77
        return RLM_MODULE_OK;
 
78
}
 
79
 
 
80
/*
 
81
 *      Perform all of the wondrous variants of digest authentication.
 
82
 */
 
83
static int digest_authenticate(void *instance, REQUEST *request)
 
84
{
 
85
        int i;
 
86
        size_t a1_len, a2_len, kd_len;
 
87
        uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
 
88
        uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
 
89
        uint8_t kd[(MAX_STRING_LEN + 1) * 5];
 
90
        uint8_t hash[16];       /* MD5 output */
 
91
        VALUE_PAIR *vp, *passwd, *algo;
 
92
        VALUE_PAIR *qop, *nonce;
 
93
 
 
94
        instance = instance;    /* -Wunused */
 
95
 
 
96
        /*
 
97
         *      We require access to the plain-text password.
 
98
         */
 
99
        passwd = pairfind(request->config_items, PW_DIGEST_HA1);
 
100
        if (passwd) {
 
101
                if (passwd->length != 32) {
 
102
                        radlog(L_AUTH, "rlm_digest: Digest-HA1 has invalid length, authentication failed.");
 
103
                        return RLM_MODULE_INVALID;
 
104
                }
 
105
        } else {
 
106
                passwd = pairfind(request->config_items, PW_PASSWORD);
 
107
        }
 
108
        if (!passwd) {
 
109
                radlog(L_AUTH, "rlm_digest: Configuration item \"User-Password\" or Digest-HA1 is required for authentication.");
 
110
                return RLM_MODULE_INVALID;
 
111
        }
 
112
 
 
113
        /*
 
114
         *      We need these, too.
 
115
         */
 
116
        vp = pairfind(request->packet->vps, PW_DIGEST_ATTRIBUTES);
 
117
        if (vp == NULL) {
 
118
                DEBUG("ERROR: You set 'Auth-Type = Digest' for a request that did not contain any digest attributes!");
 
119
                return RLM_MODULE_INVALID;
 
120
        }
 
121
 
 
122
        /*
71
123
         *      Loop through the Digest-Attributes, sanity checking them.
72
124
         */
73
125
        DEBUG("    rlm_digest: Converting Digest-Attributes to something sane...");
149
201
        }
150
202
 
151
203
        /*
152
 
         *      Everything's OK, add a digest authentication type.
153
 
         */
154
 
        if (pairfind(request->config_items, PW_AUTHTYPE) == NULL) {
155
 
                DEBUG("rlm_digest: Adding Auth-Type = DIGEST");
156
 
                pairadd(&request->config_items,
157
 
                        pairmake("Auth-Type", "DIGEST", T_OP_EQ));
158
 
        }
159
 
 
160
 
        return RLM_MODULE_OK;
161
 
}
162
 
 
163
 
/*
164
 
 *      Convert a string in hex to one in binary
165
 
 */
166
 
static void hex2bin(uint8_t *out, const uint8_t *in)
167
 
{
168
 
        unsigned int tmp;
169
 
 
170
 
        while (*in) {
171
 
                sscanf(in, "%02x", &tmp);
172
 
                *out = tmp;
173
 
                out++;
174
 
                in += 2;
175
 
        }
176
 
}
177
 
 
178
 
/*
179
 
 *      Perform all of the wondrous variants of digest authentication.
180
 
 */
181
 
static int digest_authenticate(void *instance, REQUEST *request)
182
 
{
183
 
        int i;
184
 
        int a1_len, a2_len, kd_len;
185
 
        uint8_t a1[(MAX_STRING_LEN + 1) * 5]; /* can be 5 attributes */
186
 
        uint8_t a2[(MAX_STRING_LEN + 1) * 3]; /* can be 3 attributes */
187
 
        uint8_t kd[(MAX_STRING_LEN + 1) * 5];
188
 
        uint8_t hash[16];       /* MD5 output */
189
 
        VALUE_PAIR *vp;
190
 
        VALUE_PAIR *qop, *nonce;
191
 
 
192
 
        /*
193
 
         *      We require access to the plain-text password.
194
 
         */
195
 
        vp = pairfind(request->config_items, PW_PASSWORD);
196
 
        if (!vp) {
197
 
                radlog(L_AUTH, "rlm_digest: Configuration item \"User-Password\" is required for authentication.");
198
 
                return RLM_MODULE_INVALID;
199
 
        }
200
 
 
201
 
        /*
202
204
         *      We require access to the Digest-Nonce-Value
203
205
         */
204
206
        nonce = pairfind(request->packet->vps, PW_DIGEST_NONCE);
232
234
        a1[a1_len] = ':';
233
235
        a1_len++;
234
236
 
235
 
        vp = pairfind(request->config_items, PW_PASSWORD);
236
 
        if (!vp) {
237
 
                DEBUG("ERROR: No User-Password: Cannot perform Digest authentication");
238
 
                return RLM_MODULE_INVALID;
 
237
        if (passwd->attribute == PW_USER_PASSWORD) {
 
238
                memcpy(&a1[a1_len], &passwd->strvalue[0], passwd->length);
 
239
                a1_len += passwd->length;
 
240
                a1[a1_len] = '\0';
 
241
                DEBUG2("A1 = %s", a1);
 
242
        } else {
 
243
                a1[a1_len] = '\0';
 
244
                DEBUG2("A1 = %s (using Digest-HA1)", a1);
 
245
                a1_len = 16;
239
246
        }
240
 
        memcpy(&a1[a1_len], &vp->strvalue[0], vp->length);
241
 
        a1_len += vp->length;
242
 
 
243
 
        a1[a1_len] = '\0';
244
 
        DEBUG2("A1 = %s", a1);
245
247
 
246
248
        /*
247
249
         *      See which variant we calculate.
 
250
         *      Assume MD5 if no Digest-Algorithm attribute received
248
251
         */
249
 
        vp = pairfind(request->packet->vps, PW_DIGEST_ALGORITHM);
250
 
        if ((vp != NULL) &&
251
 
            (strcasecmp(vp->strvalue, "MD5-sess") == 0)) {
252
 
                librad_md5_calc(hash, &a1[0], a1_len);
253
 
                memcpy(&a1[0], hash, 16);
254
 
                a1_len = 16;
 
252
        algo = pairfind(request->packet->vps, PW_DIGEST_ALGORITHM);
 
253
        if ((algo == NULL) || 
 
254
            (strcasecmp(algo->strvalue, "MD5") == 0)) {
 
255
                /*
 
256
                 *      Set A1 to Digest-HA1 if no User-Password found
 
257
                 */
 
258
                if (passwd->attribute == PW_DIGEST_HA1) {
 
259
                        lrad_hex2bin(passwd->strvalue, &a1[0], 16);
 
260
                }
 
261
 
 
262
        } else if (strcasecmp(algo->strvalue, "MD5-sess") == 0) {
 
263
                /*
 
264
                 *      K1 = H(A1) : Digest-Nonce ... : H(A2)
 
265
                 *
 
266
                 *      If we find Digest-HA1, we assume it contains
 
267
                 *      H(A1).
 
268
                 */
 
269
                if (passwd->attribute == PW_USER_PASSWORD) {
 
270
                        librad_md5_calc(hash, &a1[0], a1_len);
 
271
                        lrad_bin2hex(hash, &a1[0], 16);
 
272
                } else {        /* MUST be Digest-HA1 */
 
273
                        memcpy(&a1[0], passwd->strvalue, 32);
 
274
                }
 
275
                a1_len = 32;
255
276
 
256
277
                a1[a1_len] = ':';
257
278
                a1_len++;
258
279
 
259
280
                /*
260
 
                 *      Tack on the Digest-Nonce
 
281
                 *      Tack on the Digest-Nonce. Length must be even
261
282
                 */
262
 
                hex2bin(&a1[a1_len], &nonce->strvalue[0]);
263
 
                a1_len += (nonce->length >> 1); /* FIXME: CHECK LENGTH */
 
283
                if ((nonce->length & 1) != 0) {
 
284
                        DEBUG("ERROR: Received Digest-Nonce hex string with invalid length: Cannot perform Digest authentication");
 
285
                        return RLM_MODULE_INVALID;
 
286
                }
 
287
                memcpy(&a1[a1_len], &nonce->strvalue[0], nonce->length);
 
288
                a1_len += nonce->length;
264
289
 
265
290
                a1[a1_len] = ':';
266
291
                a1_len++;
267
292
 
268
293
                vp = pairfind(request->packet->vps, PW_DIGEST_CNONCE);
269
294
                if (!vp) {
270
 
                  DEBUG("ERROR: No Digest-CNonce: Cannot perform Digest authentication");
271
 
                  return RLM_MODULE_INVALID;
272
 
                }
273
 
 
274
 
                hex2bin(&a1[a1_len], &vp->strvalue[0]);
275
 
                a1_len += (vp->length >> 1); /* FIXME: CHECK LENGTH */
276
 
 
277
 
        } else if ((vp != NULL) &&
278
 
                   (strcasecmp(vp->strvalue, "MD5") != 0)) {
 
295
                        DEBUG("ERROR: No Digest-CNonce: Cannot perform Digest authentication");
 
296
                        return RLM_MODULE_INVALID;
 
297
                }
 
298
 
 
299
                /*
 
300
                 *      Digest-CNonce length must be even
 
301
                 */
 
302
                if ((vp->length & 1) != 0) {
 
303
                        DEBUG("ERROR: Received Digest-CNonce hex string with invalid length: Cannot perform Digest authentication");
 
304
                        return RLM_MODULE_INVALID;
 
305
                }
 
306
                memcpy(&a1[a1_len], &vp->strvalue[0], vp->length);
 
307
                a1_len += vp->length;
 
308
 
 
309
        } else if ((algo != NULL) &&
 
310
                   (strcasecmp(algo->strvalue, "MD5") != 0)) {
279
311
                /*
280
312
                 *      We check for "MD5-sess" and "MD5".
281
313
                 *      Anything else is an error.
329
361
                        return RLM_MODULE_INVALID;
330
362
                }
331
363
 
332
 
                rad_assert(body->length == 32); /* FIXME: check in 'auth' */
333
 
                hex2bin(&a2[a2_len], &body->strvalue[0]);
334
 
                a2_len += (body->length >> 1);
 
364
                if ((a2_len + body->length) > sizeof(a2)) {
 
365
                        DEBUG("ERROR: Digest-Body-Digest is too long");
 
366
                        return RLM_MODULE_INVALID;
 
367
                }
 
368
 
 
369
                memcpy(a2 + a2_len, body->strvalue, body->length);
 
370
                a2_len += body->length;
335
371
 
336
372
        } else if ((qop != NULL) &&
337
373
                   (strcasecmp(qop->strvalue, "auth") != 0)) {
343
379
        DEBUG2("A2 = %s", a2);
344
380
 
345
381
        /*
346
 
         *     KD = H(A1) : Digest-Nonce ... : H(A2)
 
382
         *     KD = H(A1) : Digest-Nonce ... : H(A2).
 
383
         *     Compute MD5 if Digest-Algorithm == "MD5-Sess",
 
384
         *     or if we found a User-Password.
347
385
         */
348
 
        librad_md5_calc(&hash[0], &a1[0], a1_len);
349
 
 
350
 
        for (i = 0; i < 16; i++) {
351
 
                sprintf(&kd[i * 2], "%02x", hash[i]);
 
386
        if (((algo != NULL) && 
 
387
             (strcasecmp(algo->strvalue, "MD5-Sess") == 0)) ||
 
388
            (passwd->attribute == PW_USER_PASSWORD)) {
 
389
          a1[a1_len] = '\0';
 
390
                librad_md5_calc(&hash[0], &a1[0], a1_len);
 
391
        } else {
 
392
                memcpy(&hash[0], &a1[0], a1_len);
352
393
        }
 
394
        lrad_bin2hex(hash, kd, sizeof(hash));
353
395
 
354
396
#ifndef NDEBUG
355
397
        if (debug_flag) {
418
460
 
419
461
        librad_md5_calc(&hash[0], &a2[0], a2_len);
420
462
 
421
 
        for (i = 0; i < 16; i++) {
422
 
                sprintf(&kd[kd_len + (i * 2)], "%02x", hash[i]);
423
 
        }
 
463
        lrad_bin2hex(hash, kd + kd_len, sizeof(hash));
424
464
 
425
465
#ifndef NDEBUG
426
466
        if (debug_flag) {
447
487
         *      Get the binary value of Digest-Response
448
488
         */
449
489
        vp = pairfind(request->packet->vps, PW_DIGEST_RESPONSE);
450
 
        rad_assert(vp != NULL);
 
490
        if (!vp) {
 
491
                DEBUG("ERROR: No Digest-Response attribute in the request.  Cannot perform digest authentication");
 
492
                return RLM_MODULE_INVALID;
 
493
        }
451
494
 
452
 
        hex2bin(&hash[0], &vp->strvalue[0]);
 
495
        lrad_hex2bin(&vp->strvalue[0], &hash[0], vp->length >> 1);
453
496
 
454
497
#ifndef NDEBUG
455
498
        if (debug_flag) {