~yolanda.robla/ubuntu/saucy/freeradius/dep-8-tests

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Josip Rodin
  • Date: 2010-10-14 21:51:51 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20101014215151-po7jgf8lyf0zq5ht
Tags: 2.1.10+dfsg-1
* New upstream version, closes a bunch of reproducible SNAFUs,
  including two tagged as security issues, CVE-2010-3696, CVE-2010-3697,
  closes: #600176.
* Build-depend on newer Libtool because of lt_dladvise_init(), also
  upstream now has a configure check so we no longer need a patch,
  yet we still don't want the old behaviour. Noticed by John Morrissey,
  closes: #584151.
* Added the /etc/default/freeradius file as suggested by
  Rudy Gevaert and Matthew Newton, closes: #564716.
* Stop symlinking /dev/urandom into /etc/freeradius/certs/random,
  it breaks grep -r in /etc. Instead, replace it inside eap.conf,
  both in the new shipped conffile and in postinst.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 * Copyright 2000,2001,2006  The FreeRADIUS server project
21
21
 */
22
22
 
23
 
 
24
 
/*
25
 
 *  mschap.c    MS-CHAP module
26
 
 *
27
 
 *  This implements MS-CHAP, as described in RFC 2548
28
 
 *
29
 
 *  http://www.freeradius.org/rfc/rfc2548.txt
30
 
 *
31
 
 */
32
 
 
33
 
/*
34
 
 *  If you have any questions on NTLM (Samba) passwords
35
 
 *  support, LM authentication and MS-CHAP v2 support
36
 
 *  please contact
37
 
 *
38
 
 *  Vladimir Dubrovin   vlad@sandy.ru
39
 
 *  aka
40
 
 *  ZARAZA              3APA3A@security.nnov.ru
41
 
 */
42
 
 
43
23
/*  MPPE support from Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp> */
44
24
 
45
25
#include        <freeradius-devel/ident.h>
53
33
 
54
34
#include        <ctype.h>
55
35
 
 
36
#include        "mschap.h"
56
37
#include        "smbdes.h"
57
38
 
58
39
#ifdef __APPLE__
147
128
}
148
129
 
149
130
 
150
 
/*
151
 
 *      ntpwdhash converts Unicode password to 16-byte NT hash
152
 
 *      with MD4
153
 
 */
154
 
static void ntpwdhash (uint8_t *szHash, const char *szPassword)
155
 
{
156
 
        char szUnicodePass[513];
157
 
        int nPasswordLen;
158
 
        int i;
159
 
 
160
 
        /*
161
 
         *      NT passwords are unicode.  Convert plain text password
162
 
         *      to unicode by inserting a zero every other byte
163
 
         */
164
 
        nPasswordLen = strlen(szPassword);
165
 
        for (i = 0; i < nPasswordLen; i++) {
166
 
                szUnicodePass[i << 1] = szPassword[i];
167
 
                szUnicodePass[(i << 1) + 1] = 0;
168
 
        }
169
 
 
170
 
        /* Encrypt Unicode password to a 16-byte MD4 hash */
171
 
        fr_md4_calc(szHash, (uint8_t *) szUnicodePass, (nPasswordLen<<1) );
172
 
}
173
 
 
174
 
 
175
 
/*
176
 
 *      challenge_hash() is used by mschap2() and auth_response()
177
 
 *      implements RFC2759 ChallengeHash()
178
 
 *      generates 64 bit challenge
179
 
 */
180
 
static void challenge_hash( const uint8_t *peer_challenge,
181
 
                            const uint8_t *auth_challenge,
182
 
                            const char *user_name, uint8_t *challenge )
183
 
{
184
 
        fr_SHA1_CTX Context;
185
 
        uint8_t hash[20];
186
 
 
187
 
        fr_SHA1Init(&Context);
188
 
        fr_SHA1Update(&Context, peer_challenge, 16);
189
 
        fr_SHA1Update(&Context, auth_challenge, 16);
190
 
        fr_SHA1Update(&Context, (const uint8_t *) user_name,
191
 
                      strlen(user_name));
192
 
        fr_SHA1Final(hash, &Context);
193
 
        memcpy(challenge, hash, 8);
194
 
}
195
 
 
196
 
/*
197
 
 *      auth_response() generates MS-CHAP v2 SUCCESS response
198
 
 *      according to RFC 2759 GenerateAuthenticatorResponse()
199
 
 *      returns 42-octet response string
200
 
 */
201
 
static void auth_response(const char *username,
202
 
                          const uint8_t *nt_hash_hash,
203
 
                          uint8_t *ntresponse,
204
 
                          uint8_t *peer_challenge, uint8_t *auth_challenge,
205
 
                          char *response)
206
 
{
207
 
        fr_SHA1_CTX Context;
208
 
        static const uint8_t magic1[39] =
209
 
        {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
210
 
         0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
211
 
         0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
212
 
         0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
213
 
 
214
 
        static const uint8_t magic2[41] =
215
 
        {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
216
 
         0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
217
 
         0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
218
 
         0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
219
 
         0x6E};
220
 
 
221
 
        static const char hex[16] = "0123456789ABCDEF";
222
 
 
223
 
        size_t i;
224
 
        uint8_t challenge[8];
225
 
        uint8_t digest[20];
226
 
 
227
 
        fr_SHA1Init(&Context);
228
 
        fr_SHA1Update(&Context, nt_hash_hash, 16);
229
 
        fr_SHA1Update(&Context, ntresponse, 24);
230
 
        fr_SHA1Update(&Context, magic1, 39);
231
 
        fr_SHA1Final(digest, &Context);
232
 
        challenge_hash(peer_challenge, auth_challenge, username, challenge);
233
 
        fr_SHA1Init(&Context);
234
 
        fr_SHA1Update(&Context, digest, 20);
235
 
        fr_SHA1Update(&Context, challenge, 8);
236
 
        fr_SHA1Update(&Context, magic2, 41);
237
 
        fr_SHA1Final(digest, &Context);
238
 
 
239
 
        /*
240
 
         *      Encode the value of 'Digest' as "S=" followed by
241
 
         *      40 ASCII hexadecimal digits and return it in
242
 
         *      AuthenticatorResponse.
243
 
         *      For example,
244
 
         *      "S=0123456789ABCDEF0123456789ABCDEF01234567"
245
 
         */
246
 
        response[0] = 'S';
247
 
        response[1] = '=';
248
 
 
249
 
        /*
250
 
         *      The hexadecimal digits [A-F] MUST be uppercase.
251
 
         */
252
 
        for (i = 0; i < sizeof(digest); i++) {
253
 
                response[2 + (i * 2)] = hex[(digest[i] >> 4) & 0x0f];
254
 
                response[3 + (i * 2)] = hex[digest[i] & 0x0f];
255
 
        }
256
 
}
257
 
 
258
 
 
259
131
typedef struct rlm_mschap_t {
260
132
        int use_mppe;
261
133
        int require_encryption;
319
191
                         *      for MS-CHAPv2.
320
192
                         */
321
193
                } else if (chap_challenge->length == 16) {
 
194
                        VALUE_PAIR *name_attr, *response_name;
322
195
                        char *username_string;
323
196
 
324
197
                        RDEBUG2(" mschap2: %02x", chap_challenge->vp_octets[0]);
330
203
                        }
331
204
 
332
205
                        /*
 
206
                         *      FIXME: Much of this is copied from
 
207
                         *      below.  We should put it into a
 
208
                         *      separate function.
 
209
                         */
 
210
 
 
211
                        /*
333
212
                         *      Responses are 50 octets.
334
213
                         */
335
214
                        if (response->length < 50) {
340
219
                        user_name = pairfind(request->packet->vps,
341
220
                                             PW_USER_NAME);
342
221
                        if (!user_name) {
343
 
                                RDEBUG2("User-Name is required to calculateMS-CHAPv1 Challenge.");
 
222
                                RDEBUG2("User-Name is required to calculate MS-CHAPv1 Challenge.");
344
223
                                return 0;
345
224
                        }
346
225
 
 
226
                        /*
 
227
                         *      Check for MS-CHAP-User-Name and if found, use it
 
228
                         *      to construct the MSCHAPv1 challenge.  This is
 
229
                         *      set by rlm_eap_mschap to the MS-CHAP Response
 
230
                         *      packet Name field.
 
231
                         *
 
232
                         *      We prefer this to the User-Name in the
 
233
                         *      packet.
 
234
                         */
 
235
                        response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
 
236
                        if (response_name) {
 
237
                                name_attr = response_name;
 
238
                        } else {
 
239
                                name_attr = user_name;
 
240
                        }
 
241
 
347
242
                        /*
348
243
                         *      with_ntdomain_hack moved here, too.
349
244
                         */
350
 
                        if ((username_string = strchr(user_name->vp_strvalue, '\\')) != NULL) {
 
245
                        if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
351
246
                                if (inst->with_ntdomain_hack) {
352
247
                                        username_string++;
353
248
                                } else {
354
249
                                        RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
355
 
                                        username_string = user_name->vp_strvalue;
 
250
                                        username_string = name_attr->vp_strvalue;
356
251
                                }
357
252
                        } else {
358
 
                                username_string = user_name->vp_strvalue;
 
253
                                username_string = name_attr->vp_strvalue;
 
254
                        }
 
255
 
 
256
                        if (response_name &&
 
257
                            ((user_name->length != response_name->length) ||
 
258
                             (strncasecmp(user_name->vp_strvalue, response_name->vp_strvalue, user_name->length) != 0))) {
 
259
                                RDEBUG("WARNING: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", user_name->vp_strvalue, response_name->vp_strvalue);
359
260
                        }
360
261
 
361
262
                        /*
363
264
                         *      from the MS-CHAPv2 peer challenge,
364
265
                         *      our challenge, and the user name.
365
266
                         */
366
 
                        challenge_hash(response->vp_octets + 2,
 
267
                        RDEBUG2("Creating challenge hash with username: %s",
 
268
                                username_string);
 
269
                        mschap_challenge_hash(response->vp_octets + 2,
367
270
                                       chap_challenge->vp_octets,
368
271
                                       username_string, buffer);
369
272
                        data = buffer;
549
452
                        return 0;
550
453
                }
551
454
 
552
 
                ntpwdhash(buffer,buf2);
 
455
                mschap_ntpwdhash(buffer,buf2);
553
456
 
554
457
                fr_bin2hex(buffer, out, 16);
555
458
                out[32] = '\0';
798
701
                                             buffer, sizeof(buffer),
799
702
                                             NULL, NULL, 1);
800
703
                if (result != 0) {
 
704
                        char *p;
 
705
                        VALUE_PAIR *vp = NULL;
 
706
 
801
707
                        RDEBUG2("External script failed.");
 
708
 
 
709
                        vp = pairmake("Module-Failure-Message", "", T_OP_EQ);
 
710
                        if (!vp) {
 
711
                                radlog_request(L_ERR, 0, request, "No memory to allocate Module-Failure-Message");
 
712
                                return RLM_MODULE_FAIL;
 
713
                        }
 
714
 
 
715
                        p = strchr(buffer, '\n');
 
716
                        if (p) *p = '\0';
 
717
                        snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue),
 
718
                                "%s: External script says %s",
 
719
                                 inst->xlat_name, buffer);
 
720
                        vp->length = strlen(vp->vp_strvalue);
 
721
                        pairadd(&request->packet->vps, vp);
802
722
                        return -1;
803
723
                }
804
724
 
981
901
        }
982
902
 
983
903
        if (pairfind(request->config_items, PW_AUTH_TYPE)) {
984
 
                RDEBUG2("Found existing Auth-Type.  Not changing it.");
 
904
                RDEBUG2("WARNING: Auth-Type already set.  Not setting to MS-CHAP");
985
905
                return RLM_MODULE_NOOP;
986
906
        }
987
907
 
1147
1067
                        radlog_request(L_ERR, 0, request, "No memory");
1148
1068
                        return RLM_MODULE_FAIL;
1149
1069
                } else {
1150
 
                        ntpwdhash(nt_password->vp_octets,
 
1070
                        mschap_ntpwdhash(nt_password->vp_octets,
1151
1071
                                  password->vp_strvalue);
1152
1072
                        nt_password->length = 16;
1153
1073
                }
1155
1075
 
1156
1076
        challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
1157
1077
        if (!challenge) {
1158
 
                RDEBUG2("No MS-CHAP-Challenge in the request");
 
1078
                RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
1159
1079
                return RLM_MODULE_REJECT;
1160
1080
        }
1161
1081
 
1217
1137
 
1218
1138
        } else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
1219
1139
                uint8_t mschapv1_challenge[16];
 
1140
                VALUE_PAIR *name_attr, *response_name;
1220
1141
 
1221
1142
                /*
1222
1143
                 *      MS-CHAPv2 challenges are 16 octets.
1243
1164
                        return RLM_MODULE_INVALID;
1244
1165
                }
1245
1166
 
1246
 
 
1247
 
                /*
1248
 
                 *      with_ntdomain_hack moved here
1249
 
                 */
1250
 
                if ((username_string = strchr(username->vp_strvalue, '\\')) != NULL) {
1251
 
                        if (inst->with_ntdomain_hack) {
1252
 
                                username_string++;
 
1167
                /*
 
1168
                 *      Check for MS-CHAP-User-Name and if found, use it
 
1169
                 *      to construct the MSCHAPv1 challenge.  This is
 
1170
                 *      set by rlm_eap_mschap to the MS-CHAP Response
 
1171
                 *      packet Name field.
 
1172
                 *
 
1173
                 *      We prefer this to the User-Name in the
 
1174
                 *      packet.
 
1175
                 */
 
1176
                response_name = pairfind(request->packet->vps, PW_MS_CHAP_USER_NAME);
 
1177
                if (response_name) {
 
1178
                        name_attr = response_name;
 
1179
                } else {
 
1180
                        name_attr = username;
 
1181
                }
 
1182
                
 
1183
                /*
 
1184
                 *      with_ntdomain_hack moved here, too.
 
1185
                 */
 
1186
                if ((username_string = strchr(name_attr->vp_strvalue, '\\')) != NULL) {
 
1187
                        if (inst->with_ntdomain_hack) {
 
1188
                                username_string++;
1253
1189
                        } else {
1254
 
                                RDEBUG2("  NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
1255
 
                                username_string = username->vp_strvalue;
 
1190
                                RDEBUG2("NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
 
1191
                                username_string = name_attr->vp_strvalue;
1256
1192
                        }
1257
1193
                } else {
1258
 
                        username_string = username->vp_strvalue;
 
1194
                        username_string = name_attr->vp_strvalue;
 
1195
                }
 
1196
                
 
1197
                if (response_name &&
 
1198
                    ((username->length != response_name->length) ||
 
1199
                     (strncasecmp(username->vp_strvalue, response_name->vp_strvalue, username->length) != 0))) {
 
1200
                        RDEBUG("ERROR: User-Name (%s) is not the same as MS-CHAP Name (%s) from EAP-MSCHAPv2", username->vp_strvalue, response_name->vp_strvalue);
 
1201
                        return RLM_MODULE_REJECT;
1259
1202
                }
1260
1203
 
1261
1204
#ifdef __APPLE__
1282
1225
                 *      MS-CHAPv2 takes some additional data to create an
1283
1226
                 *      MS-CHAPv1 challenge, and then does MS-CHAPv1.
1284
1227
                 */
1285
 
                challenge_hash(response->vp_octets + 2, /* peer challenge */
 
1228
                RDEBUG2("Creating challenge hash with username: %s",
 
1229
                        username_string);
 
1230
                mschap_challenge_hash(response->vp_octets + 2, /* peer challenge */
1286
1231
                               challenge->vp_octets, /* our challenge */
1287
1232
                               username_string, /* user name */
1288
1233
                               mschapv1_challenge); /* resulting challenge */
1300
1245
                        return RLM_MODULE_REJECT;
1301
1246
                }
1302
1247
 
1303
 
                /*
1304
 
                 *      Get the NT-hash-hash, if necessary
1305
 
                 */
1306
 
                if (nt_password) {
1307
 
                }
1308
 
 
1309
 
                auth_response(username_string, /* without the domain */
 
1248
                mschap_auth_response(username_string, /* without the domain */
1310
1249
                              nthashhash, /* nt-hash-hash */
1311
1250
                              response->vp_octets + 26, /* peer response */
1312
1251
                              response->vp_octets + 2, /* peer challenge */
1317
1256
                chap = 2;
1318
1257
 
1319
1258
        } else {                /* Neither CHAPv1 or CHAPv2 response: die */
1320
 
                radlog_request(L_AUTH, 0, request, "No MS-CHAP response found");
 
1259
                RDEBUG("ERROR: You set 'Auth-Type = MS-CHAP' for a request that does not contain any MS-CHAP attributes!");
1321
1260
                return RLM_MODULE_INVALID;
1322
1261
        }
1323
1262