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

« back to all changes in this revision

Viewing changes to src/kim/lib/kim_identity.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:
 
1
/*
 
2
 * $Header$
 
3
 *
 
4
 * Copyright 2006 Massachusetts Institute of Technology.
 
5
 * All Rights Reserved.
 
6
 *
 
7
 * Export of this software from the United States of America may
 
8
 * require a specific license from the United States Government.
 
9
 * It is the responsibility of any person or organization contemplating
 
10
 * export to obtain such a license before exporting.
 
11
 * 
 
12
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 
13
 * distribute this software and its documentation for any purpose and
 
14
 * without fee is hereby granted, provided that the above copyright
 
15
 * notice appear in all copies and that both that copyright notice and
 
16
 * this permission notice appear in supporting documentation, and that
 
17
 * the name of M.I.T. not be used in advertising or publicity pertaining
 
18
 * to distribution of the software without specific, written prior
 
19
 * permission.  Furthermore if you modify this software you must label
 
20
 * your software as modified software and not distribute it in such a
 
21
 * fashion that it might be confused with the original M.I.T. software.
 
22
 * M.I.T. makes no representations about the suitability of
 
23
 * this software for any purpose.  It is provided "as is" without express
 
24
 * or implied warranty.
 
25
 */
 
26
 
 
27
#include "k5-int.h"
 
28
#include <krb5.h>
 
29
#include "kim_private.h"
 
30
 
 
31
/* ------------------------------------------------------------------------ */
 
32
 
 
33
struct kim_identity_opaque {
 
34
    krb5_context          context;
 
35
    krb5_principal        principal;
 
36
};
 
37
 
 
38
struct kim_identity_opaque kim_identity_initializer = { NULL, NULL };
 
39
 
 
40
/* ------------------------------------------------------------------------ */
 
41
 
 
42
static inline kim_error kim_identity_allocate (kim_identity *out_identity)
 
43
{
 
44
    kim_error err = kim_library_init ();
 
45
    kim_identity identity = NULL;
 
46
    
 
47
    if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
48
    
 
49
    if (!err) {
 
50
        identity = malloc (sizeof (*identity));
 
51
        if (!identity) { err = KIM_OUT_OF_MEMORY_ERR; }
 
52
    }
 
53
    
 
54
    if (!err) {
 
55
        *identity = kim_identity_initializer;
 
56
        *out_identity = identity;
 
57
        identity = NULL;
 
58
    }
 
59
    
 
60
    kim_identity_free (&identity);
 
61
    
 
62
    return check_error (err);    
 
63
}
 
64
 
 
65
/* ------------------------------------------------------------------------ */
 
66
 
 
67
kim_error kim_identity_create_from_string (kim_identity *out_identity,
 
68
                                           kim_string    in_string)
 
69
{
 
70
    kim_error err = KIM_NO_ERROR;
 
71
    kim_identity identity = NULL;
 
72
    
 
73
    if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
74
    if (!err && !in_string   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
75
    
 
76
    if (!err) {
 
77
        err = kim_identity_allocate (&identity);
 
78
    }
 
79
    
 
80
    if (!err) {
 
81
        err = krb5_error (NULL, krb5_init_context (&identity->context));
 
82
    }
 
83
    
 
84
    if (!err) {
 
85
        krb5_error_code code = krb5_parse_name (identity->context, in_string, &identity->principal);
 
86
        if (code == KRB5_PARSE_MALFORMED) {
 
87
            err = kim_error_set_message_for_code (KIM_BAD_PRINCIPAL_STRING_ERR, 
 
88
                                                  in_string);
 
89
        } else if (code) {
 
90
            err = krb5_error (identity->context, code);
 
91
        }
 
92
    }
 
93
    
 
94
    if (!err) {
 
95
        *out_identity = identity;
 
96
        identity = NULL;
 
97
    }
 
98
    
 
99
    if (identity) { kim_identity_free (&identity); }
 
100
    
 
101
    return check_error (err);
 
102
}
 
103
 
 
104
/* ------------------------------------------------------------------------ */
 
105
 
 
106
kim_error kim_identity_create_from_components (kim_identity *out_identity,
 
107
                                               kim_string    in_realm, 
 
108
                                               kim_string    in_1st_component,
 
109
                                               ...)
 
110
{
 
111
    kim_error err = KIM_NO_ERROR;
 
112
    kim_identity identity = NULL;
 
113
    
 
114
    if (!err && !out_identity    ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
115
    if (!err && !in_realm        ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
116
    if (!err && !in_1st_component) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
117
    
 
118
    if (!err) {
 
119
        err = kim_identity_allocate (&identity);
 
120
    }
 
121
    
 
122
    if (!err) {
 
123
        err = krb5_error (NULL, krb5_init_context (&identity->context));
 
124
    }
 
125
    
 
126
    if (!err) {
 
127
        va_list args;
 
128
 
 
129
        va_start (args, in_1st_component);
 
130
        err = krb5_error (identity->context,
 
131
                          krb5int_build_principal_alloc_va (identity->context,
 
132
                                                            &identity->principal,
 
133
                                                            strlen(in_realm),
 
134
                                                            in_realm,
 
135
                                                            in_1st_component,
 
136
                                                            args));
 
137
        va_end (args);
 
138
    }   
 
139
 
 
140
    if (!err) {
 
141
        *out_identity = identity;
 
142
        identity = NULL;
 
143
    }
 
144
    
 
145
    kim_identity_free (&identity);
 
146
    
 
147
    return check_error (err);
 
148
}
 
149
 
 
150
/* ------------------------------------------------------------------------ */
 
151
 
 
152
kim_error kim_identity_create_from_krb5_principal (kim_identity  *out_identity,
 
153
                                                   krb5_context   in_krb5_context,
 
154
                                                   krb5_principal in_krb5_principal)
 
155
{
 
156
    kim_error err = KIM_NO_ERROR;
 
157
    kim_identity identity = NULL;
 
158
    
 
159
    if (!err && !out_identity     ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
160
    if (!err && !in_krb5_principal) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
161
    /* KLCreatePrincipalFromKerberos5Principal passes NULL in_krb5_context */
 
162
    
 
163
    if (!err) {
 
164
        err = kim_identity_allocate (&identity);
 
165
    }
 
166
    
 
167
    if (!err) {
 
168
        if (in_krb5_context) {
 
169
            err = krb5_error (in_krb5_context, 
 
170
                              krb5_copy_context (in_krb5_context,
 
171
                                                 &identity->context));
 
172
        } else {
 
173
            err = krb5_error (NULL, 
 
174
                              krb5_init_context (&identity->context));
 
175
        }
 
176
    }
 
177
    
 
178
    if (!err) {
 
179
        err = krb5_error (identity->context,
 
180
                          krb5_copy_principal (identity->context, 
 
181
                                               in_krb5_principal, 
 
182
                                               &identity->principal));
 
183
    }
 
184
    
 
185
    if (!err) {
 
186
        *out_identity = identity;
 
187
        identity = NULL;
 
188
    }
 
189
    
 
190
    kim_identity_free (&identity);
 
191
    
 
192
    return check_error (err);
 
193
}
 
194
 
 
195
/* ------------------------------------------------------------------------ */
 
196
 
 
197
kim_error kim_identity_copy (kim_identity *out_identity,
 
198
                             kim_identity  in_identity)
 
199
{
 
200
    kim_error err = KIM_NO_ERROR;
 
201
    kim_identity identity = KIM_IDENTITY_ANY;
 
202
    
 
203
    if (!err && !out_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
204
    
 
205
    if (!err && in_identity != KIM_IDENTITY_ANY) {
 
206
        err = kim_identity_allocate (&identity);
 
207
        
 
208
        if (!err) {
 
209
            err = krb5_error (in_identity->context, 
 
210
                              krb5_copy_context (in_identity->context,
 
211
                                                 &identity->context));
 
212
        }
 
213
        
 
214
        if (!err) {
 
215
            err = krb5_error (identity->context,
 
216
                              krb5_copy_principal (identity->context, 
 
217
                                                   in_identity->principal, 
 
218
                                                   &identity->principal));
 
219
        }
 
220
    }
 
221
    
 
222
    if (!err) {
 
223
        *out_identity = identity;
 
224
        identity = NULL;
 
225
    }
 
226
    
 
227
    kim_identity_free (&identity);
 
228
    
 
229
    return check_error (err);
 
230
}
 
231
 
 
232
/* ------------------------------------------------------------------------ */
 
233
 
 
234
kim_error kim_identity_compare (kim_identity    in_identity,
 
235
                                kim_identity    in_compare_to_identity,
 
236
                                kim_comparison *out_comparison)
 
237
{
 
238
    kim_error err = KIM_NO_ERROR;
 
239
    
 
240
    if (!err && !in_identity           ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
241
    if (!err && !in_compare_to_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
242
    if (!err && !out_comparison        ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
243
    
 
244
    if (!err) {
 
245
        if (krb5_principal_compare (in_identity->context, 
 
246
                                    in_identity->principal, 
 
247
                                    in_compare_to_identity->principal)) {
 
248
            *out_comparison = 0;
 
249
        } else {
 
250
            kim_string string = NULL;
 
251
            kim_string compare_to_string = NULL;
 
252
            
 
253
            err = kim_identity_get_string (in_identity, &string);
 
254
            
 
255
            if (!err) {
 
256
                err = kim_identity_get_string (in_compare_to_identity, &compare_to_string);
 
257
            }
 
258
            
 
259
            if (!err) {
 
260
                err = kim_string_compare (string, compare_to_string, out_comparison);
 
261
            }
 
262
            
 
263
            kim_string_free (&string);
 
264
            kim_string_free (&compare_to_string);
 
265
        }
 
266
    }
 
267
    
 
268
    return check_error (err);
 
269
}
 
270
 
 
271
/* ------------------------------------------------------------------------ */
 
272
 
 
273
kim_error kim_identity_get_string (kim_identity   in_identity,
 
274
                                   kim_string    *out_string)
 
275
{
 
276
    kim_error err = KIM_NO_ERROR;
 
277
    char *unparsed_name = NULL;
 
278
    
 
279
    if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
280
    if (!err && !out_string ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
281
    
 
282
    if (!err) {
 
283
        err = krb5_error (in_identity->context,
 
284
                          krb5_unparse_name (in_identity->context, 
 
285
                                             in_identity->principal, 
 
286
                                             &unparsed_name));
 
287
    }
 
288
    
 
289
    if (!err) {
 
290
        err = kim_string_copy (out_string, unparsed_name);
 
291
    }
 
292
    
 
293
    if (unparsed_name) { krb5_free_unparsed_name (in_identity->context, unparsed_name); }
 
294
    
 
295
    return check_error (err);
 
296
}
 
297
 
 
298
/* ------------------------------------------------------------------------ */
 
299
 
 
300
kim_error kim_identity_get_display_string (kim_identity   in_identity,
 
301
                                           kim_string    *out_display_string)
 
302
{
 
303
    kim_error err = KIM_NO_ERROR;
 
304
    kim_string string = NULL;
 
305
    
 
306
    if (!err && !in_identity       ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
307
    if (!err && !out_display_string) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
308
    
 
309
    if (!err) {
 
310
        err = kim_identity_get_string (in_identity, &string);
 
311
    }
 
312
    
 
313
    if (!err) {
 
314
        kim_count i, j;
 
315
        kim_count length = strlen (string) + 1; /* Copy the '\0' */
 
316
        char *display_string = (char *) string; /* so we can modify it */
 
317
        
 
318
        /* In place copy, skipping escaped separators.
 
319
         * Note that we do not want to remove other escaped characters
 
320
         * (tab, break, newline, NULL) because they are less readable 
 
321
         * when unescaped (and NULL isn't a valid string character).  */
 
322
        for (i = 0, j = 0; i < length; i++) {
 
323
            if (string[i] == '\\') {
 
324
                switch (string[i + 1]) {
 
325
                    case '/': /* component separator */
 
326
                    case '@': /* realm separator */
 
327
                        continue; /* skip the '\' */
 
328
                }
 
329
            }
 
330
            
 
331
            display_string[j++] = string[i]; /* Copy this char */
 
332
        } 
 
333
        
 
334
        *out_display_string = string;
 
335
        string = NULL;
 
336
    }
 
337
    
 
338
    if (string) { kim_string_free (&string); }
 
339
    
 
340
    return check_error (err);
 
341
}
 
342
 
 
343
/* ------------------------------------------------------------------------ */
 
344
 
 
345
kim_error kim_identity_get_realm (kim_identity  in_identity,
 
346
                                  kim_string   *out_realm_string)
 
347
{
 
348
    kim_error err = KIM_NO_ERROR;
 
349
    
 
350
    if (!err && !in_identity     ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
351
    if (!err && !out_realm_string) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
352
    
 
353
    if (!err) {
 
354
        krb5_data *realm = krb5_princ_realm (in_identity->context, in_identity->principal);
 
355
        
 
356
        err = kim_string_create_from_buffer (out_realm_string, realm->data, realm->length);
 
357
    }
 
358
    
 
359
    return check_error (err);
 
360
}
 
361
 
 
362
/* ------------------------------------------------------------------------ */
 
363
 
 
364
kim_error kim_identity_get_number_of_components (kim_identity  in_identity,
 
365
                                                 kim_count    *out_number_of_components)
 
366
{
 
367
    kim_error err = KIM_NO_ERROR;
 
368
    
 
369
    if (!err && !in_identity             ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
370
    if (!err && !out_number_of_components) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
371
    
 
372
    if (!err) {
 
373
        *out_number_of_components = krb5_princ_size (in_identity->context, in_identity->principal);
 
374
    }
 
375
    
 
376
    return check_error (err);
 
377
}
 
378
 
 
379
/* ------------------------------------------------------------------------ */
 
380
 
 
381
kim_error kim_identity_get_component_at_index (kim_identity  in_identity,
 
382
                                               kim_count     in_index,
 
383
                                               kim_string   *out_component_string)
 
384
{
 
385
    kim_error err = KIM_NO_ERROR;
 
386
    krb5_data *component = NULL;
 
387
    
 
388
    if (!err && !in_identity         ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
389
    if (!err && !out_component_string) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
390
    
 
391
    if (!err) {
 
392
        krb5_int32 i = in_index;
 
393
        component = krb5_princ_component (in_identity->context, in_identity->principal, i);
 
394
        if (!component) { 
 
395
            err = kim_error_set_message_for_code (KIM_BAD_COMPONENT_INDEX_ERR, i); 
 
396
        }
 
397
    }
 
398
    
 
399
    if (!err) {
 
400
        err = kim_string_create_from_buffer (out_component_string, component->data, component->length);
 
401
    }
 
402
    
 
403
    return check_error (err);
 
404
}
 
405
 
 
406
/* ------------------------------------------------------------------------ */
 
407
 
 
408
kim_error kim_identity_get_components_string (kim_identity  in_identity,
 
409
                                              kim_string   *out_components)
 
410
{
 
411
    kim_error err = KIM_NO_ERROR;
 
412
    kim_string components = NULL;
 
413
    kim_count count, i;
 
414
    
 
415
    if (!err && !in_identity   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
416
    if (!err && !out_components) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
417
    
 
418
    if (!err) {
 
419
        err = kim_identity_get_number_of_components (in_identity, &count);
 
420
    }
 
421
    
 
422
    if (!err) {
 
423
        err = kim_identity_get_component_at_index (in_identity, 0, &components);
 
424
    }
 
425
    
 
426
    for (i = 1; !err && i < count; i++) {
 
427
        kim_string new_components = NULL;
 
428
        kim_string component = NULL;
 
429
        
 
430
        err = kim_identity_get_component_at_index (in_identity, i, &component);
 
431
        
 
432
        if (!err) {
 
433
            err = kim_string_create_from_format (&new_components, "%s/%s",
 
434
                                                 components, component);
 
435
        }
 
436
        
 
437
        if (!err) {
 
438
            kim_string_free (&components);
 
439
            components = new_components;
 
440
            new_components = NULL;
 
441
        }
 
442
        
 
443
        if (component     ) { kim_string_free (&component); }
 
444
        if (new_components) { kim_string_free (&new_components); }
 
445
    }
 
446
    
 
447
    if (!err) {
 
448
        *out_components = components;
 
449
        components = NULL;
 
450
    }
 
451
    
 
452
    if (components) { kim_string_free (&components); }
 
453
    
 
454
    return check_error (err);
 
455
}
 
456
 
 
457
/* ------------------------------------------------------------------------ */
 
458
 
 
459
kim_error kim_identity_get_krb5_principal (kim_identity    in_identity,
 
460
                                           krb5_context    in_krb5_context,
 
461
                                           krb5_principal *out_krb5_principal)
 
462
{
 
463
    kim_error err = KIM_NO_ERROR;
 
464
    
 
465
    if (!err && !in_identity       ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
466
    if (!err && !in_krb5_context   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
467
    if (!err && !out_krb5_principal) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
468
    
 
469
    if (!err) {
 
470
        err = krb5_error (in_krb5_context,
 
471
                          krb5_copy_principal (in_krb5_context, 
 
472
                                               in_identity->principal, 
 
473
                                               out_krb5_principal));
 
474
    }    
 
475
    
 
476
    return check_error (err);
 
477
}
 
478
 
 
479
/* ------------------------------------------------------------------------ */
 
480
 
 
481
krb5_principal kim_identity_krb5_principal (kim_identity in_identity)
 
482
{
 
483
    if (in_identity) {
 
484
        return in_identity->principal;
 
485
    }
 
486
    check_error (KIM_NULL_PARAMETER_ERR); /* log error */
 
487
    return NULL;
 
488
}
 
489
 
 
490
/* ------------------------------------------------------------------------ */
 
491
 
 
492
kim_error kim_identity_is_tgt_service (kim_identity  in_identity,
 
493
                                       kim_boolean  *out_is_tgt_service)
 
494
{
 
495
    kim_error err = KIM_NO_ERROR;
 
496
    
 
497
    if (!err && !in_identity       ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
498
    if (!err && !out_is_tgt_service) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
499
    
 
500
    if (!err) {
 
501
        kim_count count = krb5_princ_size (in_identity->context, in_identity->principal);
 
502
        krb5_data *name = krb5_princ_name (in_identity->context, in_identity->principal);
 
503
        
 
504
        /* krbtgt/<REALM1>@<REALM2> (usually REALM1 == REALM2, but not always) */
 
505
        *out_is_tgt_service = ((count == 2) &&
 
506
                               (strlen (KRB5_TGS_NAME) == name->length) &&
 
507
                               (strncmp (name->data, KRB5_TGS_NAME, name->length) == 0));
 
508
    }
 
509
    
 
510
    return check_error (err);
 
511
}
 
512
 
 
513
 
 
514
/* ------------------------------------------------------------------------ */
 
515
 
 
516
kim_error kim_identity_change_password_with_credential (kim_identity    in_identity,
 
517
                                                        kim_credential  in_credential,
 
518
                                                        kim_string      in_new_password,
 
519
                                                        kim_ui_context *in_ui_context,
 
520
                                                        kim_error      *out_rejected_err,
 
521
                                                        kim_string     *out_rejected_message,
 
522
                                                        kim_string     *out_rejected_description)
 
523
{
 
524
    kim_error err = KIM_NO_ERROR;
 
525
    krb5_creds *creds = NULL;
 
526
    int rejected_err = 0;
 
527
    krb5_data message_data;
 
528
    krb5_data description_data;
 
529
    
 
530
    if (!err && !in_identity     ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
531
    if (!err && !in_credential   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
532
    if (!err && !in_new_password ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
533
    if (!err && !in_ui_context   ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
534
    if (!err && !out_rejected_err) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
535
    
 
536
    if (!err) {
 
537
        err = kim_credential_get_krb5_creds (in_credential,
 
538
                                             in_identity->context,
 
539
                                             &creds);
 
540
    }
 
541
 
 
542
    if (!err) {
 
543
        if (krb5_principal_compare (in_identity->context, 
 
544
                                    in_identity->principal,
 
545
                                    creds->client)) {
 
546
            /* Same principal, change the password normally */
 
547
            err = krb5_error (in_identity->context,
 
548
                              krb5_change_password (in_identity->context, 
 
549
                                                    creds, 
 
550
                                                    (char *) in_new_password, 
 
551
                                                    &rejected_err, 
 
552
                                                    &message_data, 
 
553
                                                    &description_data));
 
554
        } else {
 
555
            /* Different principal, use set change password protocol */
 
556
            err = krb5_error (in_identity->context,
 
557
                              krb5_set_password (in_identity->context, 
 
558
                                                 creds, 
 
559
                                                 (char *) in_new_password, 
 
560
                                                 in_identity->principal,
 
561
                                                 &rejected_err, 
 
562
                                                 &message_data, 
 
563
                                                 &description_data));
 
564
        }
 
565
        
 
566
    }
 
567
    
 
568
    if (!err && rejected_err) {
 
569
        kim_string rejected_message = NULL;
 
570
        kim_string rejected_description = NULL;
 
571
        
 
572
        if (message_data.data && message_data.length > 0) {
 
573
            err = kim_string_create_from_buffer (&rejected_message, 
 
574
                                                 message_data.data, 
 
575
                                                 message_data.length);
 
576
        } else {
 
577
            err = kim_os_string_create_localized (&rejected_message,
 
578
                                                  "Kerberos Change Password Failed:");
 
579
        }
 
580
        
 
581
        if (!err) {
 
582
            if (description_data.data && description_data.length > 0) {
 
583
                err = kim_string_create_from_buffer (&rejected_description,
 
584
                                                     description_data.data, 
 
585
                                                     description_data.length);
 
586
            } else {
 
587
                err = kim_os_string_create_localized (&rejected_description,
 
588
                                                      "New password rejected.");
 
589
            }
 
590
        }
 
591
        
 
592
        if (!err && in_ui_context->type != kim_ui_type_cli) {
 
593
            char *c;
 
594
            
 
595
            // replace all \n and \r characters with spaces
 
596
            for (c = (char *) rejected_message; *c != '\0'; c++) {
 
597
                if ((*c == '\n') || (*c == '\r')) { *c = ' '; }
 
598
            }
 
599
            
 
600
            for (c = (char *) rejected_description; *c != '\0'; c++) {
 
601
                if ((*c == '\n') || (*c == '\r')) { *c = ' '; }
 
602
            }
 
603
        }
 
604
        
 
605
        if (!err) {
 
606
            if (out_rejected_message) {
 
607
                *out_rejected_message = rejected_message;
 
608
                rejected_message = NULL;
 
609
            }
 
610
            if (out_rejected_description) {
 
611
                *out_rejected_description = rejected_description;
 
612
                rejected_description = NULL;
 
613
            }
 
614
        }
 
615
        
 
616
        kim_string_free (&rejected_message);
 
617
        kim_string_free (&rejected_description);
 
618
        
 
619
        krb5_free_data_contents (in_identity->context, &message_data);
 
620
        krb5_free_data_contents (in_identity->context, &description_data);
 
621
    }
 
622
    
 
623
    if (!err) {
 
624
        /* do this after reporting errors so we don't double report rejection */
 
625
        *out_rejected_err = rejected_err;
 
626
    }
 
627
    
 
628
    if (creds) { krb5_free_creds (in_identity->context, creds); }
 
629
    
 
630
    return check_error (err);
 
631
}
 
632
 
 
633
/* ------------------------------------------------------------------------ */
 
634
 
 
635
kim_error kim_identity_change_password_common (kim_identity    in_identity,
 
636
                                               kim_boolean     in_old_password_expired,
 
637
                                               kim_ui_context *in_ui_context,
 
638
                                               kim_string     *out_new_password)
 
639
{
 
640
    kim_error err = KIM_NO_ERROR;
 
641
    kim_boolean done = 0;
 
642
    
 
643
    if (!err && !in_identity  ) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
644
    if (!err && !in_ui_context) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
645
    
 
646
    while (!err && !done) {
 
647
        char *old_password = NULL;
 
648
        char *new_password = NULL;
 
649
        char *verify_password = NULL;
 
650
        kim_error rejected_err = KIM_NO_ERROR;
 
651
        kim_string rejected_message = NULL;
 
652
        kim_string rejected_description = NULL;
 
653
        kim_boolean was_prompted = 0;   /* ignore because we always prompt */
 
654
        
 
655
        err = kim_ui_change_password (in_ui_context,
 
656
                                      in_identity,
 
657
                                      in_old_password_expired,
 
658
                                      &old_password,
 
659
                                      &new_password,
 
660
                                      &verify_password);
 
661
        
 
662
        if (!err) {
 
663
            kim_comparison comparison;
 
664
            
 
665
            err = kim_string_compare (new_password, 
 
666
                                      verify_password, 
 
667
                                      &comparison);
 
668
            if (!err && !kim_comparison_is_equal_to (comparison)) {
 
669
                err = check_error (KIM_PASSWORD_MISMATCH_ERR);
 
670
            }
 
671
        }
 
672
        
 
673
        if (!err) {
 
674
            kim_credential credential = NULL;
 
675
            
 
676
            if (in_ui_context->type == kim_ui_type_cli && in_ui_context->tcontext) {
 
677
                /* command line has already gotten the credentials for us */
 
678
                credential = (kim_credential) in_ui_context->tcontext;
 
679
            } else {
 
680
                err = kim_credential_create_for_change_password (&credential,
 
681
                                                                 in_identity,
 
682
                                                                 old_password,
 
683
                                                                 in_ui_context,
 
684
                                                                 &was_prompted);
 
685
            }
 
686
            
 
687
            if (!err) {
 
688
                err = kim_identity_change_password_with_credential (in_identity,
 
689
                                                                    credential, 
 
690
                                                                    new_password,
 
691
                                                                    in_ui_context,
 
692
                                                                    &rejected_err,
 
693
                                                                    &rejected_message,
 
694
                                                                    &rejected_description);
 
695
            }  
 
696
            
 
697
            kim_credential_free (&credential);
 
698
            if (in_ui_context->type == kim_ui_type_cli) { 
 
699
                in_ui_context->tcontext = NULL; /* just freed our creds */
 
700
            }
 
701
        }
 
702
        
 
703
        if (!err && rejected_err) {
 
704
            /* Password rejected, report it to the user */
 
705
            err = kim_ui_handle_error (in_ui_context, in_identity,
 
706
                                       rejected_err,
 
707
                                       rejected_message, 
 
708
                                       rejected_description);
 
709
            
 
710
        } else if (err && err != KIM_USER_CANCELED_ERR && 
 
711
                          err != KIM_DUPLICATE_UI_REQUEST_ERR) {
 
712
            /* New creds failed, report error to user.
 
713
             * Overwrite error so we loop and let the user try again.
 
714
             * The user always gets prompted so we always loop. */
 
715
            err = kim_ui_handle_kim_error (in_ui_context, in_identity, 
 
716
                                           kim_ui_error_type_change_password,
 
717
                                           err);
 
718
            
 
719
        } else {
 
720
            /* password change succeeded or the user gave up */
 
721
            done = 1;
 
722
            
 
723
            if (!err && out_new_password) {
 
724
                err = kim_string_copy (out_new_password, new_password);
 
725
            }
 
726
            
 
727
            if (!err) {
 
728
                kim_error terr = KIM_NO_ERROR;
 
729
                kim_string saved_password = NULL;
 
730
                
 
731
                terr = kim_os_identity_get_saved_password (in_identity, 
 
732
                                                           &saved_password);
 
733
                if (!terr) { 
 
734
                    /* We changed the password and the user had their
 
735
                     * old password saved.  Update it. */
 
736
                    terr = kim_os_identity_set_saved_password (in_identity,
 
737
                                                               new_password);
 
738
                }
 
739
                
 
740
                kim_string_free (&saved_password);
 
741
            }
 
742
 
 
743
            if (err == KIM_DUPLICATE_UI_REQUEST_ERR) { err = KIM_NO_ERROR; }
 
744
        }
 
745
        
 
746
        kim_string_free (&rejected_message);
 
747
        kim_string_free (&rejected_description);
 
748
        
 
749
        kim_ui_free_string (in_ui_context, &old_password);
 
750
        kim_ui_free_string (in_ui_context, &new_password);
 
751
        kim_ui_free_string (in_ui_context, &verify_password);         
 
752
    }
 
753
    
 
754
    return check_error (err);
 
755
}
 
756
 
 
757
/* ------------------------------------------------------------------------ */
 
758
 
 
759
kim_error kim_identity_change_password (kim_identity in_identity)
 
760
{
 
761
    kim_error err = KIM_NO_ERROR;
 
762
    kim_ui_context context;
 
763
    kim_boolean ui_inited = 0;
 
764
 
 
765
    if (!err && !in_identity) { err = check_error (KIM_NULL_PARAMETER_ERR); }
 
766
    
 
767
    if (!err) {
 
768
        err = kim_ui_init (&context);
 
769
        if (!err) { ui_inited = 1; }
 
770
    }
 
771
    
 
772
    if (!err) {
 
773
        err = kim_identity_change_password_common (in_identity, 0, 
 
774
                                                   &context, NULL);
 
775
    }
 
776
    
 
777
    if (ui_inited) {
 
778
        kim_error fini_err = kim_ui_fini (&context);
 
779
        if (!err) { err = check_error (fini_err); }
 
780
    }
 
781
    
 
782
    return check_error (err);
 
783
}
 
784
 
 
785
/* ------------------------------------------------------------------------ */
 
786
 
 
787
void kim_identity_free (kim_identity *io_identity)
 
788
{
 
789
    if (io_identity && *io_identity) { 
 
790
        kim_identity identity = *io_identity;
 
791
        
 
792
        if (identity->context) { 
 
793
            if (identity->principal) { 
 
794
                krb5_free_principal (identity->context, identity->principal); 
 
795
            }
 
796
            krb5_free_context (identity->context);
 
797
        }
 
798
        
 
799
        free (identity);
 
800
        *io_identity = NULL;
 
801
    }
 
802
}