summaryrefslogtreecommitdiff
path: root/source4/auth/kerberos/kerberos_util.c
blob: 7945094be96de95c2625e9f350265ba0955ddf7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* 
   Unix SMB/CIFS implementation.

   Kerberos utility functions for GENSEC
   
   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "includes.h"
#include "system/kerberos.h"
#include "system/time.h"
#include "system/network.h"
#include "auth/kerberos/kerberos.h"
#include "auth/auth.h"

struct ccache_container {
	struct smb_krb5_context *smb_krb5_context;
	krb5_ccache ccache;
} ccache_container;

static int free_ccache(void *ptr) {
	struct ccache_container *ccc = ptr;
	/* current heimdal - 0.6.3, which we need anyway, fixes segfaults here */
	krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache);

	return 0;
}

/**
 * Return a freshly allocated ccache (destroyed by destructor on child
 * of parent_ctx), for a given set of client credentials 
 */

 NTSTATUS kinit_to_ccache(TALLOC_CTX *parent_ctx,
			  struct cli_credentials *credentials,
			  struct smb_krb5_context *smb_krb5_context,
			  krb5_ccache *ccache,
			  const char **ccache_name) 
{
	krb5_error_code ret;
	const char *password;
	char *ccache_string;
	time_t kdc_time = 0;
	struct ccache_container *mem_ctx = talloc(parent_ctx, struct ccache_container);

	if (!mem_ctx) {
		return NT_STATUS_NO_MEMORY;
	}

	password = cli_credentials_get_password(credentials);
	
	/* this string should be unique */
	ccache_string = talloc_asprintf(mem_ctx, "MEMORY:%s_%s", 
					cli_credentials_get_principal(credentials, mem_ctx), 
					generate_random_str(mem_ctx, 16));
	
	ret = krb5_cc_resolve(smb_krb5_context->krb5_context, ccache_string, ccache);
	if (ret) {
		DEBUG(1,("failed to generate a new krb5 keytab (%s): %s\n", 
			 ccache_string,
			 error_message(ret)));
		talloc_free(mem_ctx);
		return NT_STATUS_INTERNAL_ERROR;
	}

	mem_ctx->smb_krb5_context = talloc_reference(mem_ctx, smb_krb5_context);
	mem_ctx->ccache = *ccache;

	talloc_set_destructor(mem_ctx, free_ccache);
	ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, *ccache, 
					 cli_credentials_get_principal(credentials, mem_ctx), 
					 password, NULL, &kdc_time);
	
	/* cope with ticket being in the future due to clock skew */
	if ((unsigned)kdc_time > time(NULL)) {
		time_t t = time(NULL);
		int time_offset =(unsigned)kdc_time-t;
		DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
		krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0);
	}
	
	if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
		DEBUG(1,("kinit for %s failed (%s)\n", 
			 cli_credentials_get_principal(credentials, mem_ctx), 
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return NT_STATUS_TIME_DIFFERENCE_AT_DC;
	}
	if (ret) {
		DEBUG(1,("kinit for %s failed (%s)\n", 
			 cli_credentials_get_principal(credentials, mem_ctx), 
			 smb_get_krb5_error_message(smb_krb5_context->krb5_context, 
						    ret, mem_ctx)));
		talloc_free(mem_ctx);
		return NT_STATUS_WRONG_PASSWORD;
	} 
	*ccache_name = ccache_string;

	return NT_STATUS_OK;
}