~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/libads/kerberos.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   kerberos utility library
 
4
   Copyright (C) Andrew Tridgell 2001
 
5
   Copyright (C) Remus Koos 2001
 
6
   Copyright (C) Nalin Dahyabhai <nalin@redhat.com> 2004.
 
7
   Copyright (C) Jeremy Allison 2004.
 
8
   Copyright (C) Gerald Carter 2006.
 
9
 
 
10
   This program is free software; you can redistribute it and/or modify
 
11
   it under the terms of the GNU General Public License as published by
 
12
   the Free Software Foundation; either version 3 of the License, or
 
13
   (at your option) any later version.
 
14
   
 
15
   This program is distributed in the hope that it will be useful,
 
16
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
   GNU General Public License for more details.
 
19
   
 
20
   You should have received a copy of the GNU General Public License
 
21
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
22
*/
 
23
 
 
24
#include "includes.h"
 
25
#include "smb_krb5.h"
 
26
 
 
27
#ifdef HAVE_KRB5
 
28
 
 
29
#define DEFAULT_KRB5_PORT 88
 
30
 
 
31
#define LIBADS_CCACHE_NAME "MEMORY:libads"
 
32
 
 
33
/*
 
34
  we use a prompter to avoid a crash bug in the kerberos libs when 
 
35
  dealing with empty passwords
 
36
  this prompter is just a string copy ...
 
37
*/
 
38
static krb5_error_code 
 
39
kerb_prompter(krb5_context ctx, void *data,
 
40
               const char *name,
 
41
               const char *banner,
 
42
               int num_prompts,
 
43
               krb5_prompt prompts[])
 
44
{
 
45
        if (num_prompts == 0) return 0;
 
46
 
 
47
        memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
 
48
        if (prompts[0].reply->length > 0) {
 
49
                if (data) {
 
50
                        strncpy(prompts[0].reply->data, (const char *)data,
 
51
                                prompts[0].reply->length-1);
 
52
                        prompts[0].reply->length = strlen(prompts[0].reply->data);
 
53
                } else {
 
54
                        prompts[0].reply->length = 0;
 
55
                }
 
56
        }
 
57
        return 0;
 
58
}
 
59
 
 
60
 static bool smb_krb5_get_ntstatus_from_krb5_error(krb5_error *error,
 
61
                                                   NTSTATUS *nt_status)
 
62
{
 
63
        DATA_BLOB edata;
 
64
        DATA_BLOB unwrapped_edata;
 
65
        TALLOC_CTX *mem_ctx;
 
66
        struct KRB5_EDATA_NTSTATUS parsed_edata;
 
67
        enum ndr_err_code ndr_err;
 
68
 
 
69
#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
 
70
        edata = data_blob(error->e_data->data, error->e_data->length);
 
71
#else
 
72
        edata = data_blob(error->e_data.data, error->e_data.length);
 
73
#endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
 
74
 
 
75
#ifdef DEVELOPER
 
76
        dump_data(10, edata.data, edata.length);
 
77
#endif /* DEVELOPER */
 
78
 
 
79
        mem_ctx = talloc_init("smb_krb5_get_ntstatus_from_krb5_error");
 
80
        if (mem_ctx == NULL) {
 
81
                data_blob_free(&edata);
 
82
                return False;
 
83
        }
 
84
 
 
85
        if (!unwrap_edata_ntstatus(mem_ctx, &edata, &unwrapped_edata)) {
 
86
                data_blob_free(&edata);
 
87
                TALLOC_FREE(mem_ctx);
 
88
                return False;
 
89
        }
 
90
 
 
91
        data_blob_free(&edata);
 
92
 
 
93
        ndr_err = ndr_pull_struct_blob_all(&unwrapped_edata, mem_ctx, NULL,
 
94
                        &parsed_edata,
 
95
                        (ndr_pull_flags_fn_t)ndr_pull_KRB5_EDATA_NTSTATUS);
 
96
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
97
                data_blob_free(&unwrapped_edata);
 
98
                TALLOC_FREE(mem_ctx);
 
99
                return False;
 
100
        }
 
101
 
 
102
        data_blob_free(&unwrapped_edata);
 
103
 
 
104
        if (nt_status) {
 
105
                *nt_status = parsed_edata.ntstatus;
 
106
        }
 
107
 
 
108
        TALLOC_FREE(mem_ctx);
 
109
 
 
110
        return True;
 
111
}
 
112
 
 
113
 static bool smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(krb5_context ctx, 
 
114
                                                                  krb5_get_init_creds_opt *opt, 
 
115
                                                                  NTSTATUS *nt_status)
 
116
{
 
117
        bool ret = False;
 
118
        krb5_error *error = NULL;
 
119
 
 
120
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR
 
121
        ret = krb5_get_init_creds_opt_get_error(ctx, opt, &error);
 
122
        if (ret) {
 
123
                DEBUG(1,("krb5_get_init_creds_opt_get_error gave: %s\n", 
 
124
                        error_message(ret)));
 
125
                return False;
 
126
        }
 
127
#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_GET_ERROR */
 
128
 
 
129
        if (!error) {
 
130
                DEBUG(1,("no krb5_error\n"));
 
131
                return False;
 
132
        }
 
133
 
 
134
#ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR
 
135
        if (!error->e_data) {
 
136
#else
 
137
        if (error->e_data.data == NULL) {
 
138
#endif /* HAVE_E_DATA_POINTER_IN_KRB5_ERROR */
 
139
                DEBUG(1,("no edata in krb5_error\n")); 
 
140
                krb5_free_error(ctx, error);
 
141
                return False;
 
142
        }
 
143
 
 
144
        ret = smb_krb5_get_ntstatus_from_krb5_error(error, nt_status);
 
145
 
 
146
        krb5_free_error(ctx, error);
 
147
 
 
148
        return ret;
 
149
}
 
150
 
 
151
/*
 
152
  simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
 
153
  place in default cache location.
 
154
  remus@snapserver.com
 
155
*/
 
156
int kerberos_kinit_password_ext(const char *principal,
 
157
                                const char *password,
 
158
                                int time_offset,
 
159
                                time_t *expire_time,
 
160
                                time_t *renew_till_time,
 
161
                                const char *cache_name,
 
162
                                bool request_pac,
 
163
                                bool add_netbios_addr,
 
164
                                time_t renewable_time,
 
165
                                NTSTATUS *ntstatus)
 
166
{
 
167
        krb5_context ctx = NULL;
 
168
        krb5_error_code code = 0;
 
169
        krb5_ccache cc = NULL;
 
170
        krb5_principal me = NULL;
 
171
        krb5_creds my_creds;
 
172
        krb5_get_init_creds_opt *opt = NULL;
 
173
        smb_krb5_addresses *addr = NULL;
 
174
 
 
175
        ZERO_STRUCT(my_creds);
 
176
 
 
177
        initialize_krb5_error_table();
 
178
        if ((code = krb5_init_context(&ctx)))
 
179
                goto out;
 
180
 
 
181
        if (time_offset != 0) {
 
182
                krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
 
183
        }
 
184
 
 
185
        DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n",
 
186
                        principal,
 
187
                        cache_name ? cache_name: krb5_cc_default_name(ctx),
 
188
                        getenv("KRB5_CONFIG")));
 
189
 
 
190
        if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) {
 
191
                goto out;
 
192
        }
 
193
        
 
194
        if ((code = smb_krb5_parse_name(ctx, principal, &me))) {
 
195
                goto out;
 
196
        }
 
197
 
 
198
        if ((code = smb_krb5_get_init_creds_opt_alloc(ctx, &opt))) {
 
199
                goto out;
 
200
        }
 
201
 
 
202
        krb5_get_init_creds_opt_set_renew_life(opt, renewable_time);
 
203
        krb5_get_init_creds_opt_set_forwardable(opt, True);
 
204
#if 0
 
205
        /* insane testing */
 
206
        krb5_get_init_creds_opt_set_tkt_life(opt, 60);
 
207
#endif
 
208
 
 
209
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PAC_REQUEST
 
210
        if (request_pac) {
 
211
                if ((code = krb5_get_init_creds_opt_set_pac_request(ctx, opt, (krb5_boolean)request_pac))) {
 
212
                        goto out;
 
213
                }
 
214
        }
 
215
#endif
 
216
        if (add_netbios_addr) {
 
217
                if ((code = smb_krb5_gen_netbios_krb5_address(&addr))) {
 
218
                        goto out;
 
219
                }
 
220
                krb5_get_init_creds_opt_set_address_list(opt, addr->addrs);
 
221
        }
 
222
 
 
223
        if ((code = krb5_get_init_creds_password(ctx, &my_creds, me, CONST_DISCARD(char *,password), 
 
224
                                                 kerb_prompter, CONST_DISCARD(char *,password),
 
225
                                                 0, NULL, opt))) {
 
226
                goto out;
 
227
        }
 
228
 
 
229
        if ((code = krb5_cc_initialize(ctx, cc, me))) {
 
230
                goto out;
 
231
        }
 
232
        
 
233
        if ((code = krb5_cc_store_cred(ctx, cc, &my_creds))) {
 
234
                goto out;
 
235
        }
 
236
 
 
237
        if (expire_time) {
 
238
                *expire_time = (time_t) my_creds.times.endtime;
 
239
        }
 
240
 
 
241
        if (renew_till_time) {
 
242
                *renew_till_time = (time_t) my_creds.times.renew_till;
 
243
        }
 
244
 out:
 
245
        if (ntstatus) {
 
246
 
 
247
                NTSTATUS status;
 
248
 
 
249
                /* fast path */
 
250
                if (code == 0) {
 
251
                        *ntstatus = NT_STATUS_OK;
 
252
                        goto cleanup;
 
253
                }
 
254
 
 
255
                /* try to get ntstatus code out of krb5_error when we have it
 
256
                 * inside the krb5_get_init_creds_opt - gd */
 
257
 
 
258
                if (opt && smb_krb5_get_ntstatus_from_krb5_error_init_creds_opt(ctx, opt, &status)) {
 
259
                        *ntstatus = status;
 
260
                        goto cleanup;
 
261
                }
 
262
 
 
263
                /* fall back to self-made-mapping */
 
264
                *ntstatus = krb5_to_nt_status(code);
 
265
        }
 
266
 
 
267
 cleanup:
 
268
        krb5_free_cred_contents(ctx, &my_creds);
 
269
        if (me) {
 
270
                krb5_free_principal(ctx, me);
 
271
        }
 
272
        if (addr) {
 
273
                smb_krb5_free_addresses(ctx, addr);
 
274
        }
 
275
        if (opt) {
 
276
                smb_krb5_get_init_creds_opt_free(ctx, opt);
 
277
        }
 
278
        if (cc) {
 
279
                krb5_cc_close(ctx, cc);
 
280
        }
 
281
        if (ctx) {
 
282
                krb5_free_context(ctx);
 
283
        }
 
284
        return code;
 
285
}
 
286
 
 
287
 
 
288
 
 
289
/* run kinit to setup our ccache */
 
290
int ads_kinit_password(ADS_STRUCT *ads)
 
291
{
 
292
        char *s;
 
293
        int ret;
 
294
        const char *account_name;
 
295
        fstring acct_name;
 
296
 
 
297
        if (ads->auth.flags & ADS_AUTH_USER_CREDS) {
 
298
                account_name = ads->auth.user_name;
 
299
                goto got_accountname;
 
300
        }
 
301
 
 
302
        if ( IS_DC ) {
 
303
                /* this will end up getting a ticket for DOMAIN@RUSTED.REA.LM */
 
304
                account_name = lp_workgroup();
 
305
        } else {
 
306
                /* always use the sAMAccountName for security = domain */
 
307
                /* global_myname()$@REA.LM */
 
308
                if ( lp_security() == SEC_DOMAIN ) {
 
309
                        fstr_sprintf( acct_name, "%s$", global_myname() );
 
310
                        account_name = acct_name;
 
311
                }
 
312
                else 
 
313
                        /* This looks like host/global_myname()@REA.LM */
 
314
                        account_name = ads->auth.user_name;
 
315
        }
 
316
 
 
317
 got_accountname:
 
318
        if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
 
319
                return KRB5_CC_NOMEM;
 
320
        }
 
321
 
 
322
        if (!ads->auth.password) {
 
323
                SAFE_FREE(s);
 
324
                return KRB5_LIBOS_CANTREADPWD;
 
325
        }
 
326
        
 
327
        ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
 
328
                        &ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable, 
 
329
                        NULL);
 
330
 
 
331
        if (ret) {
 
332
                DEBUG(0,("kerberos_kinit_password %s failed: %s\n", 
 
333
                         s, error_message(ret)));
 
334
        }
 
335
        SAFE_FREE(s);
 
336
        return ret;
 
337
}
 
338
 
 
339
int ads_kdestroy(const char *cc_name)
 
340
{
 
341
        krb5_error_code code;
 
342
        krb5_context ctx = NULL;
 
343
        krb5_ccache cc = NULL;
 
344
 
 
345
        initialize_krb5_error_table();
 
346
        if ((code = krb5_init_context (&ctx))) {
 
347
                DEBUG(3, ("ads_kdestroy: kdb5_init_context failed: %s\n", 
 
348
                        error_message(code)));
 
349
                return code;
 
350
        }
 
351
  
 
352
        if (!cc_name) {
 
353
                if ((code = krb5_cc_default(ctx, &cc))) {
 
354
                        krb5_free_context(ctx);
 
355
                        return code;
 
356
                }
 
357
        } else {
 
358
                if ((code = krb5_cc_resolve(ctx, cc_name, &cc))) {
 
359
                        DEBUG(3, ("ads_kdestroy: krb5_cc_resolve failed: %s\n",
 
360
                                  error_message(code)));
 
361
                        krb5_free_context(ctx);
 
362
                        return code;
 
363
                }
 
364
        }
 
365
 
 
366
        if ((code = krb5_cc_destroy (ctx, cc))) {
 
367
                DEBUG(3, ("ads_kdestroy: krb5_cc_destroy failed: %s\n", 
 
368
                        error_message(code)));
 
369
        }
 
370
 
 
371
        krb5_free_context (ctx);
 
372
        return code;
 
373
}
 
374
 
 
375
/************************************************************************
 
376
 Routine to fetch the salting principal for a service.  Active
 
377
 Directory may use a non-obvious principal name to generate the salt
 
378
 when it determines the key to use for encrypting tickets for a service,
 
379
 and hopefully we detected that when we joined the domain.
 
380
 ************************************************************************/
 
381
 
 
382
static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
 
383
{
 
384
        char *key = NULL;
 
385
        char *ret = NULL;
 
386
 
 
387
        if (asprintf(&key, "%s/%s/enctype=%d",
 
388
                     SECRETS_SALTING_PRINCIPAL, service, enctype) == -1) {
 
389
                return NULL;
 
390
        }
 
391
        ret = (char *)secrets_fetch(key, NULL);
 
392
        SAFE_FREE(key);
 
393
        return ret;
 
394
}
 
395
 
 
396
/************************************************************************
 
397
 Return the standard DES salt key
 
398
************************************************************************/
 
399
 
 
400
char* kerberos_standard_des_salt( void )
 
401
{
 
402
        fstring salt;
 
403
 
 
404
        fstr_sprintf( salt, "host/%s.%s@", global_myname(), lp_realm() );
 
405
        strlower_m( salt );
 
406
        fstrcat( salt, lp_realm() );
 
407
 
 
408
        return SMB_STRDUP( salt );
 
409
}
 
410
 
 
411
/************************************************************************
 
412
************************************************************************/
 
413
 
 
414
static char* des_salt_key( void )
 
415
{
 
416
        char *key;
 
417
 
 
418
        if (asprintf(&key, "%s/DES/%s", SECRETS_SALTING_PRINCIPAL,
 
419
                     lp_realm()) == -1) {
 
420
                return NULL;
 
421
        }
 
422
 
 
423
        return key;
 
424
}
 
425
 
 
426
/************************************************************************
 
427
************************************************************************/
 
428
 
 
429
bool kerberos_secrets_store_des_salt( const char* salt )
 
430
{
 
431
        char* key;
 
432
        bool ret;
 
433
 
 
434
        if ( (key = des_salt_key()) == NULL ) {
 
435
                DEBUG(0,("kerberos_secrets_store_des_salt: failed to generate key!\n"));
 
436
                return False;
 
437
        }
 
438
 
 
439
        if ( !salt ) {
 
440
                DEBUG(8,("kerberos_secrets_store_des_salt: deleting salt\n"));
 
441
                secrets_delete( key );
 
442
                return True;
 
443
        }
 
444
 
 
445
        DEBUG(3,("kerberos_secrets_store_des_salt: Storing salt \"%s\"\n", salt));
 
446
 
 
447
        ret = secrets_store( key, salt, strlen(salt)+1 );
 
448
 
 
449
        SAFE_FREE( key );
 
450
 
 
451
        return ret;
 
452
}
 
453
 
 
454
/************************************************************************
 
455
************************************************************************/
 
456
 
 
457
char* kerberos_secrets_fetch_des_salt( void )
 
458
{
 
459
        char *salt, *key;
 
460
 
 
461
        if ( (key = des_salt_key()) == NULL ) {
 
462
                DEBUG(0,("kerberos_secrets_fetch_des_salt: failed to generate key!\n"));
 
463
                return False;
 
464
        }
 
465
 
 
466
        salt = (char*)secrets_fetch( key, NULL );
 
467
 
 
468
        SAFE_FREE( key );
 
469
 
 
470
        return salt;
 
471
}
 
472
 
 
473
/************************************************************************
 
474
 Routine to get the default realm from the kerberos credentials cache.
 
475
 Caller must free if the return value is not NULL.
 
476
************************************************************************/
 
477
 
 
478
char *kerberos_get_default_realm_from_ccache( void )
 
479
{
 
480
        char *realm = NULL;
 
481
        krb5_context ctx = NULL;
 
482
        krb5_ccache cc = NULL;
 
483
        krb5_principal princ = NULL;
 
484
 
 
485
        initialize_krb5_error_table();
 
486
        if (krb5_init_context(&ctx)) {
 
487
                return NULL;
 
488
        }
 
489
 
 
490
        DEBUG(5,("kerberos_get_default_realm_from_ccache: "
 
491
                "Trying to read krb5 cache: %s\n",
 
492
                krb5_cc_default_name(ctx)));
 
493
        if (krb5_cc_default(ctx, &cc)) {
 
494
                DEBUG(0,("kerberos_get_default_realm_from_ccache: "
 
495
                        "failed to read default cache\n"));
 
496
                goto out;
 
497
        }
 
498
        if (krb5_cc_get_principal(ctx, cc, &princ)) {
 
499
                DEBUG(0,("kerberos_get_default_realm_from_ccache: "
 
500
                        "failed to get default principal\n"));
 
501
                goto out;
 
502
        }
 
503
 
 
504
#if defined(HAVE_KRB5_PRINCIPAL_GET_REALM)
 
505
        realm = SMB_STRDUP(krb5_principal_get_realm(ctx, princ));
 
506
#elif defined(HAVE_KRB5_PRINC_REALM)
 
507
        {
 
508
                krb5_data *realm_data = krb5_princ_realm(ctx, princ);
 
509
                realm = SMB_STRNDUP(realm_data->data, realm_data->length);
 
510
        }
 
511
#endif
 
512
 
 
513
  out:
 
514
 
 
515
        if (ctx) {
 
516
                if (princ) {
 
517
                        krb5_free_principal(ctx, princ);
 
518
                }
 
519
                if (cc) {
 
520
                        krb5_cc_close(ctx, cc);
 
521
                }
 
522
                krb5_free_context(ctx);
 
523
        }
 
524
 
 
525
        return realm;
 
526
}
 
527
 
 
528
 
 
529
/************************************************************************
 
530
 Routine to get the salting principal for this service.  This is 
 
531
 maintained for backwards compatibilty with releases prior to 3.0.24.
 
532
 Since we store the salting principal string only at join, we may have 
 
533
 to look for the older tdb keys.  Caller must free if return is not null.
 
534
 ************************************************************************/
 
535
 
 
536
krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
 
537
                                                        krb5_principal host_princ,
 
538
                                                        int enctype)
 
539
{
 
540
        char *unparsed_name = NULL, *salt_princ_s = NULL;
 
541
        krb5_principal ret_princ = NULL;
 
542
        
 
543
        /* lookup new key first */
 
544
 
 
545
        if ( (salt_princ_s = kerberos_secrets_fetch_des_salt()) == NULL ) {
 
546
        
 
547
                /* look under the old key.  If this fails, just use the standard key */
 
548
 
 
549
                if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) {
 
550
                        return (krb5_principal)NULL;
 
551
                }
 
552
                if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
 
553
                        /* fall back to host/machine.realm@REALM */
 
554
                        salt_princ_s = kerberos_standard_des_salt();
 
555
                }
 
556
        }
 
557
 
 
558
        if (smb_krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
 
559
                ret_princ = NULL;
 
560
        }
 
561
        
 
562
        TALLOC_FREE(unparsed_name);
 
563
        SAFE_FREE(salt_princ_s);
 
564
        
 
565
        return ret_princ;
 
566
}
 
567
 
 
568
/************************************************************************
 
569
 Routine to set the salting principal for this service.  Active
 
570
 Directory may use a non-obvious principal name to generate the salt
 
571
 when it determines the key to use for encrypting tickets for a service,
 
572
 and hopefully we detected that when we joined the domain.
 
573
 Setting principal to NULL deletes this entry.
 
574
 ************************************************************************/
 
575
 
 
576
bool kerberos_secrets_store_salting_principal(const char *service,
 
577
                                              int enctype,
 
578
                                              const char *principal)
 
579
{
 
580
        char *key = NULL;
 
581
        bool ret = False;
 
582
        krb5_context context = NULL;
 
583
        krb5_principal princ = NULL;
 
584
        char *princ_s = NULL;
 
585
        char *unparsed_name = NULL;
 
586
        krb5_error_code code;
 
587
 
 
588
        if (((code = krb5_init_context(&context)) != 0) || (context == NULL)) {
 
589
                DEBUG(5, ("kerberos_secrets_store_salting_pricipal: kdb5_init_context failed: %s\n",
 
590
                          error_message(code)));
 
591
                return False;
 
592
        }
 
593
        if (strchr_m(service, '@')) {
 
594
                if (asprintf(&princ_s, "%s", service) == -1) {
 
595
                        goto out;
 
596
                }
 
597
        } else {
 
598
                if (asprintf(&princ_s, "%s@%s", service, lp_realm()) == -1) {
 
599
                        goto out;
 
600
                }
 
601
        }
 
602
 
 
603
        if (smb_krb5_parse_name(context, princ_s, &princ) != 0) {
 
604
                goto out;
 
605
                
 
606
        }
 
607
        if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) {
 
608
                goto out;
 
609
        }
 
610
 
 
611
        if (asprintf(&key, "%s/%s/enctype=%d",
 
612
                     SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype)
 
613
            == -1) {
 
614
                goto out;
 
615
        }
 
616
 
 
617
        if ((principal != NULL) && (strlen(principal) > 0)) {
 
618
                ret = secrets_store(key, principal, strlen(principal) + 1);
 
619
        } else {
 
620
                ret = secrets_delete(key);
 
621
        }
 
622
 
 
623
 out:
 
624
 
 
625
        SAFE_FREE(key);
 
626
        SAFE_FREE(princ_s);
 
627
        TALLOC_FREE(unparsed_name);
 
628
 
 
629
        if (princ) {
 
630
                krb5_free_principal(context, princ);
 
631
        }
 
632
 
 
633
        if (context) {
 
634
                krb5_free_context(context);
 
635
        }
 
636
 
 
637
        return ret;
 
638
}
 
639
 
 
640
 
 
641
/************************************************************************
 
642
************************************************************************/
 
643
 
 
644
int kerberos_kinit_password(const char *principal,
 
645
                            const char *password,
 
646
                            int time_offset,
 
647
                            const char *cache_name)
 
648
{
 
649
        return kerberos_kinit_password_ext(principal, 
 
650
                                           password, 
 
651
                                           time_offset, 
 
652
                                           0, 
 
653
                                           0,
 
654
                                           cache_name,
 
655
                                           False,
 
656
                                           False,
 
657
                                           0,
 
658
                                           NULL);
 
659
}
 
660
 
 
661
/************************************************************************
 
662
************************************************************************/
 
663
 
 
664
static char *print_kdc_line(char *mem_ctx,
 
665
                        const char *prev_line,
 
666
                        const struct sockaddr_storage *pss)
 
667
{
 
668
        char *kdc_str = NULL;
 
669
 
 
670
        if (pss->ss_family == AF_INET) {
 
671
                kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
 
672
                                        prev_line,
 
673
                                        print_canonical_sockaddr(mem_ctx, pss));
 
674
        } else {
 
675
                char addr[INET6_ADDRSTRLEN];
 
676
                uint16_t port = get_sockaddr_port(pss);
 
677
 
 
678
                if (port != 0 && port != DEFAULT_KRB5_PORT) {
 
679
                        /* Currently for IPv6 we can't specify a non-default
 
680
                           krb5 port with an address, as this requires a ':'.
 
681
                           Resolve to a name. */
 
682
                        char hostname[MAX_DNS_NAME_LENGTH];
 
683
                        int ret = sys_getnameinfo((const struct sockaddr *)pss,
 
684
                                        sizeof(*pss),
 
685
                                        hostname, sizeof(hostname),
 
686
                                        NULL, 0,
 
687
                                        NI_NAMEREQD);
 
688
                        if (ret) {
 
689
                                DEBUG(0,("print_kdc_line: can't resolve name "
 
690
                                        "for kdc with non-default port %s. "
 
691
                                        "Error %s\n.",
 
692
                                        print_canonical_sockaddr(mem_ctx, pss),
 
693
                                        gai_strerror(ret)));
 
694
                        }
 
695
                        /* Success, use host:port */
 
696
                        kdc_str = talloc_asprintf(mem_ctx,
 
697
                                        "%s\tkdc = %s:%u\n",
 
698
                                        prev_line,
 
699
                                        hostname,
 
700
                                        (unsigned int)port);
 
701
                } else {
 
702
                        kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
 
703
                                        prev_line,
 
704
                                        print_sockaddr(addr,
 
705
                                                sizeof(addr),
 
706
                                                pss));
 
707
                }
 
708
        }
 
709
        return kdc_str;
 
710
}
 
711
 
 
712
/************************************************************************
 
713
 Create a string list of available kdc's, possibly searching by sitename.
 
714
 Does DNS queries.
 
715
 
 
716
 If "sitename" is given, the DC's in that site are listed first.
 
717
 
 
718
************************************************************************/
 
719
 
 
720
static char *get_kdc_ip_string(char *mem_ctx,
 
721
                const char *realm,
 
722
                const char *sitename,
 
723
                struct sockaddr_storage *pss)
 
724
{
 
725
        int i;
 
726
        struct ip_service *ip_srv_site = NULL;
 
727
        struct ip_service *ip_srv_nonsite = NULL;
 
728
        int count_site = 0;
 
729
        int count_nonsite;
 
730
        char *kdc_str = print_kdc_line(mem_ctx, "", pss);
 
731
 
 
732
        if (kdc_str == NULL) {
 
733
                return NULL;
 
734
        }
 
735
 
 
736
        /*
 
737
         * First get the KDC's only in this site, the rest will be
 
738
         * appended later
 
739
         */
 
740
 
 
741
        if (sitename) {
 
742
 
 
743
                get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
 
744
 
 
745
                for (i = 0; i < count_site; i++) {
 
746
                        if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
 
747
                                                   (struct sockaddr *)pss)) {
 
748
                                continue;
 
749
                        }
 
750
                        /* Append to the string - inefficient
 
751
                         * but not done often. */
 
752
                        kdc_str = print_kdc_line(mem_ctx,
 
753
                                                kdc_str,
 
754
                                                &ip_srv_site[i].ss);
 
755
                        if (!kdc_str) {
 
756
                                SAFE_FREE(ip_srv_site);
 
757
                                return NULL;
 
758
                        }
 
759
                }
 
760
        }
 
761
 
 
762
        /* Get all KDC's. */
 
763
 
 
764
        get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
 
765
 
 
766
        for (i = 0; i < count_nonsite; i++) {
 
767
                int j;
 
768
 
 
769
                if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
 
770
                        continue;
 
771
                }
 
772
 
 
773
                /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
 
774
                for (j = 0; j < count_site; j++) {
 
775
                        if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
 
776
                                                (struct sockaddr *)&ip_srv_site[j].ss)) {
 
777
                                break;
 
778
                        }
 
779
                        /* As the lists are sorted we can break early if nonsite > site. */
 
780
                        if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
 
781
                                break;
 
782
                        }
 
783
                }
 
784
                if (j != i) {
 
785
                        continue;
 
786
                }
 
787
 
 
788
                /* Append to the string - inefficient but not done often. */
 
789
                kdc_str = print_kdc_line(mem_ctx,
 
790
                                kdc_str,
 
791
                                &ip_srv_nonsite[i].ss);
 
792
                if (!kdc_str) {
 
793
                        SAFE_FREE(ip_srv_site);
 
794
                        SAFE_FREE(ip_srv_nonsite);
 
795
                        return NULL;
 
796
                }
 
797
        }
 
798
 
 
799
 
 
800
        SAFE_FREE(ip_srv_site);
 
801
        SAFE_FREE(ip_srv_nonsite);
 
802
 
 
803
        DEBUG(10,("get_kdc_ip_string: Returning %s\n",
 
804
                kdc_str ));
 
805
 
 
806
        return kdc_str;
 
807
}
 
808
 
 
809
/************************************************************************
 
810
 Create  a specific krb5.conf file in the private directory pointing
 
811
 at a specific kdc for a realm. Keyed off domain name. Sets
 
812
 KRB5_CONFIG environment variable to point to this file. Must be
 
813
 run as root or will fail (which is a good thing :-).
 
814
************************************************************************/
 
815
 
 
816
bool create_local_private_krb5_conf_for_domain(const char *realm,
 
817
                                                const char *domain,
 
818
                                                const char *sitename,
 
819
                                                struct sockaddr_storage *pss)
 
820
{
 
821
        char *dname = lock_path("smb_krb5");
 
822
        char *tmpname = NULL;
 
823
        char *fname = NULL;
 
824
        char *file_contents = NULL;
 
825
        char *kdc_ip_string = NULL;
 
826
        size_t flen = 0;
 
827
        ssize_t ret;
 
828
        int fd;
 
829
        char *realm_upper = NULL;
 
830
        bool result = false;
 
831
 
 
832
        if (!dname) {
 
833
                return false;
 
834
        }
 
835
        if ((mkdir(dname, 0755)==-1) && (errno != EEXIST)) {
 
836
                DEBUG(0,("create_local_private_krb5_conf_for_domain: "
 
837
                        "failed to create directory %s. Error was %s\n",
 
838
                        dname, strerror(errno) ));
 
839
                goto done;
 
840
        }
 
841
 
 
842
        tmpname = lock_path("smb_tmp_krb5.XXXXXX");
 
843
        if (!tmpname) {
 
844
                goto done;
 
845
        }
 
846
 
 
847
        fname = talloc_asprintf(dname, "%s/krb5.conf.%s", dname, domain);
 
848
        if (!fname) {
 
849
                goto done;
 
850
        }
 
851
 
 
852
        DEBUG(10,("create_local_private_krb5_conf_for_domain: fname = %s, realm = %s, domain = %s\n",
 
853
                fname, realm, domain ));
 
854
 
 
855
        realm_upper = talloc_strdup(fname, realm);
 
856
        strupper_m(realm_upper);
 
857
 
 
858
        kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, pss);
 
859
        if (!kdc_ip_string) {
 
860
                goto done;
 
861
        }
 
862
 
 
863
        file_contents = talloc_asprintf(fname,
 
864
                                        "[libdefaults]\n\tdefault_realm = %s\n"
 
865
                                        "\tdefault_tgs_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
 
866
                                        "\tdefault_tkt_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n"
 
867
                                        "\tpreferred_enctypes = RC4-HMAC DES-CBC-CRC DES-CBC-MD5\n\n"
 
868
                                        "[realms]\n\t%s = {\n"
 
869
                                        "\t%s\t}\n",
 
870
                                        realm_upper, realm_upper, kdc_ip_string);
 
871
 
 
872
        if (!file_contents) {
 
873
                goto done;
 
874
        }
 
875
 
 
876
        flen = strlen(file_contents);
 
877
 
 
878
        fd = smb_mkstemp(tmpname);
 
879
        if (fd == -1) {
 
880
                DEBUG(0,("create_local_private_krb5_conf_for_domain: smb_mkstemp failed,"
 
881
                        " for file %s. Errno %s\n",
 
882
                        tmpname, strerror(errno) ));
 
883
                goto done;
 
884
        }
 
885
 
 
886
        if (fchmod(fd, 0644)==-1) {
 
887
                DEBUG(0,("create_local_private_krb5_conf_for_domain: fchmod failed for %s."
 
888
                        " Errno %s\n",
 
889
                        tmpname, strerror(errno) ));
 
890
                unlink(tmpname);
 
891
                close(fd);
 
892
                goto done;
 
893
        }
 
894
 
 
895
        ret = write(fd, file_contents, flen);
 
896
        if (flen != ret) {
 
897
                DEBUG(0,("create_local_private_krb5_conf_for_domain: write failed,"
 
898
                        " returned %d (should be %u). Errno %s\n",
 
899
                        (int)ret, (unsigned int)flen, strerror(errno) ));
 
900
                unlink(tmpname);
 
901
                close(fd);
 
902
                goto done;
 
903
        }
 
904
        if (close(fd)==-1) {
 
905
                DEBUG(0,("create_local_private_krb5_conf_for_domain: close failed."
 
906
                        " Errno %s\n", strerror(errno) ));
 
907
                unlink(tmpname);
 
908
                goto done;
 
909
        }
 
910
 
 
911
        if (rename(tmpname, fname) == -1) {
 
912
                DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
 
913
                        "of %s to %s failed. Errno %s\n",
 
914
                        tmpname, fname, strerror(errno) ));
 
915
                unlink(tmpname);
 
916
                goto done;
 
917
        }
 
918
 
 
919
        DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
 
920
                "file %s with realm %s KDC list = %s\n",
 
921
                fname, realm_upper, kdc_ip_string));
 
922
 
 
923
        /* Set the environment variable to this file. */
 
924
        setenv("KRB5_CONFIG", fname, 1);
 
925
 
 
926
        result = true;
 
927
 
 
928
#if defined(OVERWRITE_SYSTEM_KRB5_CONF)
 
929
 
 
930
#define SYSTEM_KRB5_CONF_PATH "/etc/krb5.conf"
 
931
        /* Insanity, sheer insanity..... */
 
932
 
 
933
        if (strequal(realm, lp_realm())) {
 
934
                char linkpath[PATH_MAX+1];
 
935
                int lret;
 
936
 
 
937
                lret = readlink(SYSTEM_KRB5_CONF_PATH, linkpath, sizeof(linkpath)-1);
 
938
                if (lret != -1) {
 
939
                        linkpath[lret] = '\0';
 
940
                }
 
941
 
 
942
                if (lret != -1 || strcmp(linkpath, fname) == 0) {
 
943
                        /* Symlink already exists. */
 
944
                        goto done;
 
945
                }
 
946
 
 
947
                /* Try and replace with a symlink. */
 
948
                if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
 
949
                        const char *newpath = SYSTEM_KRB5_CONF_PATH ## ".saved";
 
950
                        if (errno != EEXIST) {
 
951
                                DEBUG(0,("create_local_private_krb5_conf_for_domain: symlink "
 
952
                                        "of %s to %s failed. Errno %s\n",
 
953
                                        fname, SYSTEM_KRB5_CONF_PATH, strerror(errno) ));
 
954
                                goto done; /* Not a fatal error. */
 
955
                        }
 
956
 
 
957
                        /* Yes, this is a race conditon... too bad. */
 
958
                        if (rename(SYSTEM_KRB5_CONF_PATH, newpath) == -1) {
 
959
                                DEBUG(0,("create_local_private_krb5_conf_for_domain: rename "
 
960
                                        "of %s to %s failed. Errno %s\n",
 
961
                                        SYSTEM_KRB5_CONF_PATH, newpath,
 
962
                                        strerror(errno) ));
 
963
                                goto done; /* Not a fatal error. */
 
964
                        }
 
965
 
 
966
                        if (symlink(fname, SYSTEM_KRB5_CONF_PATH) == -1) {
 
967
                                DEBUG(0,("create_local_private_krb5_conf_for_domain: "
 
968
                                        "forced symlink of %s to /etc/krb5.conf failed. Errno %s\n",
 
969
                                        fname, strerror(errno) ));
 
970
                                goto done; /* Not a fatal error. */
 
971
                        }
 
972
                }
 
973
        }
 
974
#endif
 
975
 
 
976
done:
 
977
        TALLOC_FREE(tmpname);
 
978
        TALLOC_FREE(dname);
 
979
 
 
980
        return result;
 
981
}
 
982
#endif