~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/lib/krb5/krb/chpw.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
#include <string.h>
5
5
 
6
6
#include "k5-int.h"
7
 
#include "krb5_err.h"
8
7
#include "auth_con.h"
9
8
 
10
9
 
11
10
krb5_error_code 
12
 
krb5int_mk_chpw_req(
13
 
        krb5_context context, 
14
 
        krb5_auth_context auth_context, 
15
 
        krb5_data *ap_req,
16
 
        char *passwd, 
17
 
        krb5_data *packet)
 
11
krb5int_mk_chpw_req(krb5_context context, 
 
12
                    krb5_auth_context auth_context, 
 
13
                    krb5_data *ap_req,
 
14
                    char *passwd, 
 
15
                    krb5_data *packet)
18
16
{
19
17
    krb5_error_code ret = 0;
20
18
    krb5_data clearpw;
26
24
 
27
25
    if ((ret = krb5_auth_con_setflags(context, auth_context,
28
26
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
29
 
          goto cleanup;
 
27
        goto cleanup;
30
28
 
31
29
    clearpw.length = strlen(passwd);
32
30
    clearpw.data = passwd;
33
31
 
34
32
    if ((ret = krb5_mk_priv(context, auth_context,
35
33
                            &clearpw, &cipherpw, &replay)))
36
 
      goto cleanup;
 
34
        goto cleanup;
37
35
 
38
36
    packet->length = 6 + ap_req->length + cipherpw.length;
39
37
    packet->data = (char *) malloc(packet->length);
40
 
    if (packet->data == NULL)
41
 
        {
42
 
            ret = ENOMEM;
43
 
            goto cleanup;
44
 
        }
 
38
    if (packet->data == NULL) {
 
39
        ret = ENOMEM;
 
40
        goto cleanup;
 
41
    }
45
42
    ptr = packet->data;
46
43
 
47
44
    /* length */
48
45
 
49
 
    *ptr++ = (packet->length>> 8) & 0xff;
50
 
    *ptr++ = packet->length & 0xff;
 
46
    store_16_be(packet->length, ptr);
 
47
    ptr += 2;
51
48
 
52
49
    /* version == 0x0001 big-endian */
53
50
 
56
53
 
57
54
    /* ap_req length, big-endian */
58
55
 
59
 
    *ptr++ = (ap_req->length>>8) & 0xff;
60
 
    *ptr++ = ap_req->length & 0xff;
 
56
    store_16_be(ap_req->length, ptr);
 
57
    ptr += 2;
61
58
 
62
59
    /* ap-req data */
63
60
 
69
66
    memcpy(ptr, cipherpw.data, cipherpw.length);
70
67
 
71
68
cleanup:
72
 
    if(cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
73
 
      free(cipherpw.data);
 
69
    if (cipherpw.data != NULL)  /* allocated by krb5_mk_priv */
 
70
        free(cipherpw.data);
74
71
      
75
72
    return(ret);
76
73
}
77
74
 
78
75
krb5_error_code 
79
 
krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
 
76
krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context,
 
77
                    krb5_data *packet, int *result_code, krb5_data *result_data)
80
78
{
81
79
    char *ptr;
82
80
    int plen, vno;
101
99
    plen = (*ptr++ & 0xff);
102
100
    plen = (plen<<8) | (*ptr++ & 0xff);
103
101
 
104
 
    if (plen != packet->length) 
105
 
        {
106
 
                /*
107
 
                 * MS KDCs *may* send back a KRB_ERROR.  Although
108
 
                 * not 100% correct via RFC3244, it's something
109
 
                 * we can workaround here.
110
 
                 */
111
 
                if (krb5_is_krb_error(packet)) {
112
 
 
113
 
                        if ((ret = krb5_rd_error(context, packet, &krberror)))
114
 
                        return(ret);
115
 
 
116
 
                        if (krberror->e_data.data  == NULL) {
117
 
                                ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
118
 
                                krb5_free_error(context, krberror);
119
 
                                return (ret);
120
 
                        }
121
 
                }
122
 
                else
123
 
                {
124
 
                        return(KRB5KRB_AP_ERR_MODIFIED);
125
 
                }
 
102
    if (plen != packet->length) {
 
103
        /*
 
104
         * MS KDCs *may* send back a KRB_ERROR.  Although
 
105
         * not 100% correct via RFC3244, it's something
 
106
         * we can workaround here.
 
107
         */
 
108
        if (krb5_is_krb_error(packet)) {
 
109
 
 
110
            if ((ret = krb5_rd_error(context, packet, &krberror)))
 
111
                return(ret);
 
112
 
 
113
            if (krberror->e_data.data  == NULL) {
 
114
                ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
 
115
                krb5_free_error(context, krberror);
 
116
                return (ret);
 
117
            }
 
118
        } else {
 
119
            return(KRB5KRB_AP_ERR_MODIFIED);
126
120
        }
 
121
    }
127
122
        
128
123
 
129
124
    /* verify version number */
230
225
 
231
226
cleanup:
232
227
    if (ap_rep.length) {
233
 
        krb5_xfree(clearresult.data);
 
228
        free(clearresult.data);
234
229
    } else {
235
230
        krb5_free_error(context, krberror);
236
231
    }
239
234
}
240
235
 
241
236
krb5_error_code KRB5_CALLCONV
242
 
krb5_chpw_result_code_string(krb5_context context, int result_code, char **code_string)
 
237
krb5_chpw_result_code_string(krb5_context context, int result_code,
 
238
                             char **code_string)
243
239
{
244
 
   switch (result_code) {
245
 
   case KRB5_KPASSWD_MALFORMED:
246
 
      *code_string = "Malformed request error";
247
 
      break;
248
 
   case KRB5_KPASSWD_HARDERROR:
249
 
      *code_string = "Server error";
250
 
      break;
251
 
   case KRB5_KPASSWD_AUTHERROR:
252
 
      *code_string = "Authentication error";
253
 
      break;
254
 
   case KRB5_KPASSWD_SOFTERROR:
255
 
      *code_string = "Password change rejected";
256
 
      break;
257
 
   default:
258
 
      *code_string = "Password change failed";
259
 
      break;
260
 
   }
 
240
    switch (result_code) {
 
241
    case KRB5_KPASSWD_MALFORMED:
 
242
        *code_string = "Malformed request error";
 
243
        break;
 
244
    case KRB5_KPASSWD_HARDERROR:
 
245
        *code_string = "Server error";
 
246
        break;
 
247
    case KRB5_KPASSWD_AUTHERROR:
 
248
        *code_string = "Authentication error";
 
249
        break;
 
250
    case KRB5_KPASSWD_SOFTERROR:
 
251
        *code_string = "Password change rejected";
 
252
        break;
 
253
    default:
 
254
        *code_string = "Password change failed";
 
255
        break;
 
256
    }
261
257
 
262
 
   return(0);
 
258
    return(0);
263
259
}
264
260
 
265
261
krb5_error_code 
266
 
krb5int_mk_setpw_req(
267
 
     krb5_context context,
268
 
     krb5_auth_context auth_context,
269
 
     krb5_data *ap_req,
270
 
     krb5_principal targprinc,
271
 
     char *passwd,
272
 
     krb5_data *packet )
 
262
krb5int_mk_setpw_req(krb5_context context,
 
263
                     krb5_auth_context auth_context,
 
264
                     krb5_data *ap_req,
 
265
                     krb5_principal targprinc,
 
266
                     char *passwd,
 
267
                     krb5_data *packet)
273
268
{
274
269
    krb5_error_code ret;
275
270
    krb5_data   cipherpw;
276
271
    krb5_data   *encoded_setpw;
 
272
    struct krb5_setpw_req req;
277
273
 
278
274
    char *ptr;
279
275
 
280
 
     cipherpw.data = NULL;
281
 
     cipherpw.length = 0;
 
276
    cipherpw.data = NULL;
 
277
    cipherpw.length = 0;
282
278
     
283
279
    if ((ret = krb5_auth_con_setflags(context, auth_context,
284
280
                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE)))
285
 
                return(ret);
 
281
        return(ret);
286
282
 
287
 
    ret = encode_krb5_setpw_req(targprinc, passwd, &encoded_setpw);
 
283
    req.target = targprinc;
 
284
    req.password.data = passwd;
 
285
    req.password.length = strlen(passwd);
 
286
    ret = encode_krb5_setpw_req(&req, &encoded_setpw);
288
287
    if (ret) {
289
288
        return ret;
290
289
    }
291
290
 
292
 
    if ( (ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
293
 
        krb5_free_data( context, encoded_setpw);
 
291
    if ((ret = krb5_mk_priv(context, auth_context, encoded_setpw, &cipherpw, NULL)) != 0) {
 
292
        krb5_free_data(context, encoded_setpw);
294
293
        return(ret);
295
294
    }
296
 
    krb5_free_data( context, encoded_setpw);
 
295
    krb5_free_data(context, encoded_setpw);
297
296
    
298
297
 
299
298
    packet->length = 6 + ap_req->length + cipherpw.length;
303
302
        goto cleanup;
304
303
    }
305
304
    ptr = packet->data;
306
 
/*
307
 
** build the packet -
308
 
*/
309
 
/* put in the length */
310
 
    *ptr++ = (packet->length>>8) & 0xff;
311
 
    *ptr++ = packet->length & 0xff;
312
 
/* put in the version */
 
305
    /*
 
306
    ** build the packet -
 
307
    */
 
308
    /* put in the length */
 
309
    store_16_be(packet->length, ptr);
 
310
    ptr += 2;
 
311
    /* put in the version */
313
312
    *ptr++ = (char)0xff;
314
313
    *ptr++ = (char)0x80;
315
 
/* the ap_req length is big endian */
316
 
    *ptr++ = (ap_req->length>>8) & 0xff;
317
 
    *ptr++ = ap_req->length & 0xff;
318
 
/* put in the request data */
 
314
    /* the ap_req length is big endian */
 
315
    store_16_be(ap_req->length, ptr);
 
316
    ptr += 2;
 
317
    /* put in the request data */
319
318
    memcpy(ptr, ap_req->data, ap_req->length);
320
319
    ptr += ap_req->length;
321
 
/*
322
 
** put in the "private" password data -
323
 
*/
 
320
    /*
 
321
    ** put in the "private" password data -
 
322
    */
324
323
    memcpy(ptr, cipherpw.data, cipherpw.length);
325
324
    ret = 0;
326
 
 cleanup:
 
325
cleanup:
327
326
    if (cipherpw.data)
328
327
        krb5_free_data_contents(context, &cipherpw);
329
328
    if ((ret != 0) && packet->data) {
330
 
        free( packet->data);
 
329
        free(packet->data);
331
330
        packet->data = NULL;
332
331
    }
333
332
    return ret;
334
333
}
335
334
 
336
335
krb5_error_code 
337
 
krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
338
 
     int *result_code, krb5_data *result_data )
 
336
krb5int_rd_setpw_rep(krb5_context context, krb5_auth_context auth_context,
 
337
                     krb5_data *packet,
 
338
                     int *result_code, krb5_data *result_data)
339
339
{
340
340
    char *ptr;
341
341
    unsigned int message_length, version_number;
345
345
    krb5_data cipherresult;
346
346
    krb5_data clearresult;
347
347
    krb5_keyblock *tmpkey;
348
 
/*
349
 
** validate the packet length -
350
 
*/
 
348
    /*
 
349
    ** validate the packet length -
 
350
    */
351
351
    if (packet->length < 4)
352
352
        return(KRB5KRB_AP_ERR_MODIFIED);
353
353
 
354
354
    ptr = packet->data;
355
355
 
356
 
/*
357
 
** see if it is an error
358
 
*/
 
356
    /*
 
357
    ** see if it is an error
 
358
    */
359
359
    if (krb5_is_krb_error(packet)) {
360
360
        krb5_error *krberror;
361
361
        if ((ret = krb5_rd_error(context, packet, &krberror)))
369
369
        krberror->e_data.data  = NULL; /*So we can free it later*/
370
370
        krberror->e_data.length = 0;
371
371
        krb5_free_error(context, krberror);
372
 
                
 
372
 
373
373
    } else { /* Not an error*/
374
374
 
375
 
/*
376
 
** validate the message length -
377
 
** length is big endian 
378
 
*/
 
375
        /*
 
376
        ** validate the message length -
 
377
        ** length is big endian 
 
378
        */
379
379
        message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
380
380
        ptr += 2;
381
 
/*
382
 
** make sure the message length and packet length agree -
383
 
*/
 
381
        /*
 
382
        ** make sure the message length and packet length agree -
 
383
        */
384
384
        if (message_length != packet->length)
385
385
            return(KRB5KRB_AP_ERR_MODIFIED);
386
 
/*
387
 
** get the version number -
388
 
*/
 
386
        /*
 
387
        ** get the version number -
 
388
        */
389
389
        version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
390
390
        ptr += 2;
391
 
/*
392
 
** make sure we support the version returned -
393
 
*/
394
 
/*
395
 
** set password version is 0xff80, change password version is 1
396
 
*/
 
391
        /*
 
392
        ** make sure we support the version returned -
 
393
        */
 
394
        /*
 
395
        ** set password version is 0xff80, change password version is 1
 
396
        */
397
397
        if (version_number != 1 && version_number != 0xff80)
398
398
            return(KRB5KDC_ERR_BAD_PVNO);
399
 
/*
400
 
** now fill in ap_rep with the reply -
401
 
*/
402
 
/*
403
 
** get the reply length -
404
 
*/
 
399
        /*
 
400
        ** now fill in ap_rep with the reply -
 
401
        */
 
402
        /*
 
403
        ** get the reply length -
 
404
        */
405
405
        ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
406
406
        ptr += 2;
407
 
/*
408
 
** validate ap_rep length agrees with the packet length -
409
 
*/
 
407
        /*
 
408
        ** validate ap_rep length agrees with the packet length -
 
409
        */
410
410
        if (ptr + ap_rep.length >= packet->data + packet->length)
411
411
            return(KRB5KRB_AP_ERR_MODIFIED);
412
 
/*
413
 
** if data was returned, set the ap_rep ptr -
414
 
*/
415
 
        if( ap_rep.length ) {
 
412
        /*
 
413
        ** if data was returned, set the ap_rep ptr -
 
414
        */
 
415
        if (ap_rep.length) {
416
416
            ap_rep.data = ptr;
417
417
            ptr += ap_rep.length;
418
418
 
430
430
            }
431
431
 
432
432
            krb5_free_ap_rep_enc_part(context, ap_rep_enc);
433
 
/*
434
 
** now decrypt the result -
435
 
*/
 
433
            /*
 
434
            ** now decrypt the result -
 
435
            */
436
436
            cipherresult.data = ptr;
437
437
            cipherresult.length = (packet->data + packet->length) - ptr;
438
438
 
453
453
            return (KRB5KRB_AP_ERR_MODIFIED);
454
454
    } /*Response instead of error*/
455
455
 
456
 
/*
457
 
** validate the cleartext length 
458
 
*/
 
456
    /*
 
457
    ** validate the cleartext length 
 
458
    */
459
459
    if (clearresult.length < 2) {
460
460
        ret = KRB5KRB_AP_ERR_MODIFIED;
461
461
        goto cleanup;
462
462
    }
463
 
/*
464
 
** now decode the result -
465
 
*/
 
463
    /*
 
464
    ** now decode the result -
 
465
    */
466
466
    ptr = clearresult.data;
467
467
 
468
468
    *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
469
469
    ptr += 2;
470
470
 
471
 
/*
472
 
** result code 5 is access denied
473
 
*/
474
 
    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
475
 
    {
 
471
    /*
 
472
    ** result code 5 is access denied
 
473
    */
 
474
    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5)) {
476
475
        ret = KRB5KRB_AP_ERR_MODIFIED;
477
476
        goto cleanup;
478
477
    }
479
 
/*
480
 
** all success replies should be authenticated/encrypted
481
 
*/
482
 
    if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
483
 
    {
 
478
    /*
 
479
    ** all success replies should be authenticated/encrypted
 
480
    */
 
481
    if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
484
482
        ret = KRB5KRB_AP_ERR_MODIFIED;
485
483
        goto cleanup;
486
484
    }
488
486
    if (result_data) {
489
487
        result_data->length = (clearresult.data + clearresult.length) - ptr;
490
488
 
491
 
        if (result_data->length)
492
 
        {
 
489
        if (result_data->length) {
493
490
            result_data->data = (char *) malloc(result_data->length);
494
491
            if (result_data->data)
495
492
                memcpy(result_data->data, ptr, result_data->length);
496
 
        }
497
 
        else
 
493
        } else
498
494
            result_data->data = NULL;
499
495
    }
500
496
    ret = 0;
505
501
}
506
502
 
507
503
krb5_error_code 
508
 
krb5int_setpw_result_code_string( krb5_context context, int result_code, const char **code_string )
 
504
krb5int_setpw_result_code_string(krb5_context context, int result_code,
 
505
                                 const char **code_string)
509
506
{
510
 
   switch (result_code)
511
 
   {
512
 
   case KRB5_KPASSWD_MALFORMED:
513
 
      *code_string = "Malformed request error";
514
 
      break;
515
 
   case KRB5_KPASSWD_HARDERROR:
516
 
      *code_string = "Server error";
517
 
      break;
518
 
   case KRB5_KPASSWD_AUTHERROR:
519
 
      *code_string = "Authentication error";
520
 
      break;
521
 
   case KRB5_KPASSWD_SOFTERROR:
522
 
      *code_string = "Password change rejected";
523
 
      break;
524
 
   case 5: /* access denied */
525
 
      *code_string = "Access denied";
526
 
      break;
527
 
   case 6:      /* bad version */
528
 
      *code_string = "Wrong protocol version";
529
 
      break;
530
 
   case 7: /* initial flag is needed */
531
 
      *code_string = "Initial password required";
532
 
      break;
533
 
   case 0:
534
 
          *code_string = "Success";
535
 
   default:
536
 
      *code_string = "Password change failed";
537
 
      break;
538
 
   }
 
507
    switch (result_code) {
 
508
    case KRB5_KPASSWD_MALFORMED:
 
509
        *code_string = "Malformed request error";
 
510
        break;
 
511
    case KRB5_KPASSWD_HARDERROR:
 
512
        *code_string = "Server error";
 
513
        break;
 
514
    case KRB5_KPASSWD_AUTHERROR:
 
515
        *code_string = "Authentication error";
 
516
        break;
 
517
    case KRB5_KPASSWD_SOFTERROR:
 
518
        *code_string = "Password change rejected";
 
519
        break;
 
520
    case 5: /* access denied */
 
521
        *code_string = "Access denied";
 
522
        break;
 
523
    case 6:     /* bad version */
 
524
        *code_string = "Wrong protocol version";
 
525
        break;
 
526
    case 7: /* initial flag is needed */
 
527
        *code_string = "Initial password required";
 
528
        break;
 
529
    case 0:
 
530
        *code_string = "Success";
 
531
        break;
 
532
    default:
 
533
        *code_string = "Password change failed";
 
534
        break;
 
535
    }
539
536
 
540
 
   return(0);
 
537
    return(0);
541
538
}
542
539