r7968: Pull the PAC from within GSSAPI, rather than only when using our own
[kai/samba.git] / source4 / auth / kerberos / kerberos_pac.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Kerberos backend for GENSEC
5    
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
7    Copyright (C) Andrew Tridgell 2001
8    Copyright (C) Luke Howard 2002-2003
9    Copyright (C) Stefan Metzmacher 2004-2005
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27 #include "includes.h"
28 #include "system/kerberos.h"
29 #include "system/time.h"
30 #include "system/network.h"
31 #include "auth/kerberos/kerberos.h"
32 #include "librpc/gen_ndr/ndr_krb5pac.h"
33 #include "auth/auth.h"
34
35 #ifdef KRB5_DO_VERIFY_PAC
36 static NTSTATUS kerberos_pac_checksum(DATA_BLOB pac_data,
37                                          struct PAC_SIGNATURE_DATA *sig,
38                                          struct smb_krb5_context *smb_krb5_context,
39                                          uint32 keyusage)
40 {
41         krb5_error_code ret;
42         krb5_crypto crypto;
43         Checksum cksum;
44         int i;
45
46         cksum.cksumtype         = (CKSUMTYPE)sig->type;
47         cksum.checksum.length   = sizeof(sig->signature);
48         cksum.checksum.data     = sig->signature;
49
50
51         ret = krb5_crypto_init(smb_krb5_context->krb5_context,
52                                 &gensec_krb5_state->keyblock,
53                                 0,
54                                 &crypto);
55         if (ret) {
56                 DEBUG(0,("krb5_crypto_init() failed\n"));
57                 return NT_STATUS_FOOBAR;
58         }
59         for (i=0; i < 40; i++) {
60                 keyusage = i;
61                 ret = krb5_verify_checksum(smb_krb5_context->krb5_context,
62                                            crypto,
63                                            keyusage,
64                                            pac_data.data,
65                                            pac_data.length,
66                                            &cksum);
67                 if (!ret) {
68                         DEBUG(0,("PAC Verified: keyusage: %d\n", keyusage));
69                         break;
70                 }
71         }
72         krb5_crypto_destroy(smb_krb5_context->krb5_context, crypto);
73
74         if (ret) {
75                 DEBUG(0,("NOT verifying PAC checksums yet!\n"));
76                 //return NT_STATUS_LOGON_FAILURE;
77         } else {
78                 DEBUG(0,("PAC checksums verified!\n"));
79         }
80
81         return NT_STATUS_OK;
82 }
83 #endif
84
85 NTSTATUS kerberos_decode_pac(TALLOC_CTX *mem_ctx,
86                              struct PAC_LOGON_INFO **logon_info_out,
87                              DATA_BLOB blob,
88                              struct smb_krb5_context *smb_krb5_context)
89 {
90         NTSTATUS status;
91         struct PAC_SIGNATURE_DATA srv_sig;
92         struct PAC_SIGNATURE_DATA *srv_sig_ptr;
93         struct PAC_SIGNATURE_DATA kdc_sig;
94         struct PAC_SIGNATURE_DATA *kdc_sig_ptr;
95         struct PAC_LOGON_INFO *logon_info = NULL;
96         struct PAC_DATA pac_data;
97 #ifdef KRB5_DO_VERIFY_PAC
98         DATA_BLOB tmp_blob = data_blob(NULL, 0);
99 #endif
100         int i;
101
102         status = ndr_pull_struct_blob(&blob, mem_ctx, &pac_data,
103                                         (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
104         if (!NT_STATUS_IS_OK(status)) {
105                 DEBUG(0,("can't parse the PAC\n"));
106                 return status;
107         }
108         NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
109
110         if (pac_data.num_buffers < 3) {
111                 /* we need logon_ingo, service_key and kdc_key */
112                 DEBUG(0,("less than 3 PAC buffers\n"));
113                 return NT_STATUS_FOOBAR;
114         }
115
116         for (i=0; i < pac_data.num_buffers; i++) {
117                 switch (pac_data.buffers[i].type) {
118                         case PAC_TYPE_LOGON_INFO:
119                                 if (!pac_data.buffers[i].info) {
120                                         break;
121                                 }
122                                 logon_info = &pac_data.buffers[i].info->logon_info;
123                                 break;
124                         case PAC_TYPE_SRV_CHECKSUM:
125                                 if (!pac_data.buffers[i].info) {
126                                         break;
127                                 }
128                                 srv_sig_ptr = &pac_data.buffers[i].info->srv_cksum;
129                                 srv_sig = pac_data.buffers[i].info->srv_cksum;
130                                 break;
131                         case PAC_TYPE_KDC_CHECKSUM:
132                                 if (!pac_data.buffers[i].info) {
133                                         break;
134                                 }
135                                 kdc_sig_ptr = &pac_data.buffers[i].info->kdc_cksum;
136                                 kdc_sig = pac_data.buffers[i].info->kdc_cksum;
137                                 break;
138                         case PAC_TYPE_UNKNOWN_10:
139                                 break;
140                         default:
141                                 break;
142                 }
143         }
144
145         if (!logon_info) {
146                 DEBUG(0,("PAC no logon_info\n"));
147                 return NT_STATUS_FOOBAR;
148         }
149
150         if (!srv_sig_ptr) {
151                 DEBUG(0,("PAC no srv_key\n"));
152                 return NT_STATUS_FOOBAR;
153         }
154
155         if (!kdc_sig_ptr) {
156                 DEBUG(0,("PAC no kdc_key\n"));
157                 return NT_STATUS_FOOBAR;
158         }
159 #ifdef KRB5_DO_VERIFY_PAC
160         /* clear the kdc_key */
161 /*      memset((void *)kdc_sig_ptr , '\0', sizeof(*kdc_sig_ptr));*/
162
163         status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
164                                               (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
165         if (!NT_STATUS_IS_OK(status)) {
166                 return status;
167         }
168         status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
169                                         (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
170         if (!NT_STATUS_IS_OK(status)) {
171                 DEBUG(0,("can't parse the PAC\n"));
172                 return status;
173         }
174         /*NDR_PRINT_DEBUG(PAC_DATA, &pac_data);*/
175
176         /* verify by kdc_key */
177         status = kerberos_pac_checksum(tmp_blob, &kdc_sig, smb_krb5_context, 0);
178
179         if (!NT_STATUS_IS_OK(status)) {
180                 return status;
181         }
182
183         /* clear the service_key */
184 /*      memset((void *)srv_sig_ptr , '\0', sizeof(*srv_sig_ptr));*/
185
186         status = ndr_push_struct_blob(&tmp_blob, mem_ctx, &pac_data,
187                                               (ndr_push_flags_fn_t)ndr_push_PAC_DATA);
188         if (!NT_STATUS_IS_OK(status)) {
189                 return status;
190         }
191         status = ndr_pull_struct_blob(&tmp_blob, mem_ctx, &pac_data,
192                                         (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA);
193         if (!NT_STATUS_IS_OK(status)) {
194                 DEBUG(0,("can't parse the PAC\n"));
195                 return status;
196         }
197         NDR_PRINT_DEBUG(PAC_DATA, &pac_data);
198
199         /* verify by servie_key */
200         status = kerberos_pac_checksum(tmp_blob, &srv_sig, smb_krb5_context, 0);
201
202         if (!NT_STATUS_IS_OK(status)) {
203                 return status;
204         }
205 #endif
206         DEBUG(0,("account_name: %s [%s]\n",
207                  logon_info->info3.base.account_name.string, 
208                  logon_info->info3.base.full_name.string));
209         *logon_info_out = logon_info;
210
211         return status;
212 }
213