r9728: A *major* update to the credentials system, to incorporate the
[kamenim/samba-autobuild/.git] / source4 / auth / gensec / gensec_gssapi.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Kerberos backend for GENSEC
5    
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2004-2005
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "system/kerberos.h"
27 #include "system/network.h"
28 #include "auth/kerberos/kerberos.h"
29 #include "librpc/gen_ndr/ndr_krb5pac.h"
30 #include "auth/auth.h"
31
32 struct gensec_gssapi_state {
33         gss_ctx_id_t gssapi_context;
34         struct gss_channel_bindings_struct *input_chan_bindings;
35         gss_name_t server_name;
36         gss_name_t client_name;
37         OM_uint32 want_flags, got_flags;
38         const gss_OID_desc *gss_oid;
39
40         DATA_BLOB session_key;
41         DATA_BLOB pac;
42
43         struct smb_krb5_context *smb_krb5_context;
44         krb5_ccache ccache;
45         const char *ccache_name;
46         krb5_keytab keytab;
47
48         gss_cred_id_t cred;
49 };
50
51 static char *gssapi_error_string(TALLOC_CTX *mem_ctx, 
52                                  OM_uint32 maj_stat, OM_uint32 min_stat)
53 {
54         OM_uint32 disp_min_stat, disp_maj_stat;
55         gss_buffer_desc maj_error_message;
56         gss_buffer_desc min_error_message;
57         OM_uint32 msg_ctx = 0;
58
59         char *ret;
60
61         maj_error_message.value = NULL;
62         min_error_message.value = NULL;
63         
64         disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
65                            GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
66         disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
67                            GSS_C_NULL_OID, &msg_ctx, &min_error_message);
68         ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
69
70         gss_release_buffer(&disp_min_stat, &maj_error_message);
71         gss_release_buffer(&disp_min_stat, &min_error_message);
72
73         return ret;
74 }
75
76
77 static int gensec_gssapi_destory(void *ptr) 
78 {
79         struct gensec_gssapi_state *gensec_gssapi_state = ptr;
80         OM_uint32 maj_stat, min_stat;
81         
82         if (gensec_gssapi_state->cred != GSS_C_NO_CREDENTIAL) {
83                 maj_stat = gss_release_cred(&min_stat, 
84                                             &gensec_gssapi_state->cred);
85         }
86
87         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
88                 maj_stat = gss_delete_sec_context (&min_stat,
89                                                    &gensec_gssapi_state->gssapi_context,
90                                                    GSS_C_NO_BUFFER);
91         }
92
93         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
94                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
95         }
96         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
97                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
98         }
99         return 0;
100 }
101
102 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
103 {
104         struct gensec_gssapi_state *gensec_gssapi_state;
105         krb5_error_code ret;
106         
107         gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
108         if (!gensec_gssapi_state) {
109                 return NT_STATUS_NO_MEMORY;
110         }
111
112         gensec_security->private_data = gensec_gssapi_state;
113
114         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
115         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
116         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
117
118         /* TODO: Fill in channel bindings */
119         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
120         
121         gensec_gssapi_state->want_flags = 0;
122         gensec_gssapi_state->got_flags = 0;
123
124         gensec_gssapi_state->session_key = data_blob(NULL, 0);
125         gensec_gssapi_state->pac = data_blob(NULL, 0);
126
127         gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
128
129         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
130
131         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
132                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
133         }
134         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
135                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
136         }
137         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
138                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
139         }
140
141         gensec_gssapi_state->gss_oid = gss_mech_krb5;
142         
143         ret = smb_krb5_init_context(gensec_gssapi_state, 
144                                     &gensec_gssapi_state->smb_krb5_context);
145         if (ret) {
146                 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",                                  
147                          error_message(ret)));
148                 return NT_STATUS_INTERNAL_ERROR;
149         }
150         return NT_STATUS_OK;
151 }
152
153 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
154 {
155         NTSTATUS nt_status;
156         OM_uint32 maj_stat, min_stat;
157         struct gensec_gssapi_state *gensec_gssapi_state;
158         struct cli_credentials *machine_account;
159
160         nt_status = gensec_gssapi_start(gensec_security);
161         if (!NT_STATUS_IS_OK(nt_status)) {
162                 return nt_status;
163         }
164
165         gensec_gssapi_state = gensec_security->private_data;
166
167         machine_account = cli_credentials_init(gensec_gssapi_state);
168         cli_credentials_set_conf(machine_account);
169         nt_status = cli_credentials_set_machine_account(machine_account);
170         
171         if (!NT_STATUS_IS_OK(nt_status)) {
172                 DEBUG(3, ("Could not obtain machine account credentials from the local database\n"));
173                 talloc_free(machine_account);
174                 return nt_status;
175         } else {
176                 nt_status = create_memory_keytab(gensec_gssapi_state,
177                                                  machine_account, 
178                                                  gensec_gssapi_state->smb_krb5_context,
179                                                  &gensec_gssapi_state->keytab);
180                 talloc_free(machine_account);
181                 if (!NT_STATUS_IS_OK(nt_status)) {
182                         DEBUG(3, ("Could not create memory keytab!\n"));
183                         talloc_free(machine_account);
184                         return nt_status;
185                 }
186         }
187
188         maj_stat = gsskrb5_acquire_cred(&min_stat, 
189                                         gensec_gssapi_state->keytab, NULL,
190                                         NULL,
191                                         GSS_C_INDEFINITE,
192                                         GSS_C_NULL_OID_SET,
193                                         GSS_C_ACCEPT,
194                                         &gensec_gssapi_state->cred,
195                                         NULL, 
196                                         NULL);
197         if (maj_stat) {
198                 DEBUG(1, ("Aquiring acceptor credentails failed: %s\n", 
199                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
200                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
201         }
202
203         return NT_STATUS_OK;
204
205 }
206
207 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
208 {
209         struct gensec_gssapi_state *gensec_gssapi_state;
210         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
211         struct ccache_container *ccache;
212         krb5_error_code ret;
213         NTSTATUS nt_status;
214         gss_buffer_desc name_token;
215         OM_uint32 maj_stat, min_stat;
216         const char *hostname = gensec_get_target_hostname(gensec_security);
217
218         if (!hostname) {
219                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
220                 return NT_STATUS_INVALID_PARAMETER;
221         }
222         if (is_ipaddress(hostname)) {
223                 DEBUG(2, ("Cannot do GSSAPI to a IP address"));
224                 return NT_STATUS_INVALID_PARAMETER;
225         }
226
227         nt_status = gensec_gssapi_start(gensec_security);
228         if (!NT_STATUS_IS_OK(nt_status)) {
229                 return nt_status;
230         }
231
232         gensec_gssapi_state = gensec_security->private_data;
233
234         name_token.value = talloc_asprintf(gensec_gssapi_state, "%s@%s", 
235                                            gensec_get_target_service(gensec_security), 
236                                            hostname);
237         name_token.length = strlen(name_token.value);
238
239         maj_stat = gss_import_name (&min_stat,
240                                     &name_token,
241                                     GSS_C_NT_HOSTBASED_SERVICE,
242                                     &gensec_gssapi_state->server_name);
243         if (maj_stat) {
244                 DEBUG(2, ("GSS Import name of %s failed: %s\n",
245                           (char *)name_token.value,
246                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
247                 return NT_STATUS_INVALID_PARAMETER;
248         }
249
250         ret = cli_credentials_get_ccache(creds, 
251                                          &ccache);
252         if (ret) {
253                 DEBUG(1, ("Failed to get CCACHE for gensec_gssapi: %s\n", error_message(ret)));
254                 return NT_STATUS_UNSUCCESSFUL;
255         }
256
257         name_token.value = cli_credentials_get_principal(creds, 
258                                                          gensec_gssapi_state);
259         name_token.length = strlen(name_token.value);
260
261         maj_stat = gss_import_name (&min_stat,
262                                     &name_token,
263                                     GSS_C_NT_USER_NAME,
264                                     &gensec_gssapi_state->client_name);
265         if (maj_stat) {
266                 DEBUG(2, ("GSS Import name of %s failed: %s\n",
267                           (char *)name_token.value,
268                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
269                 return NT_STATUS_UNSUCCESSFUL;
270         }
271
272         maj_stat = gsskrb5_acquire_cred(&min_stat, 
273                                         NULL, ccache->ccache,
274                                         gensec_gssapi_state->client_name,
275                                         GSS_C_INDEFINITE,
276                                         GSS_C_NULL_OID_SET,
277                                         GSS_C_INITIATE,
278                                         &gensec_gssapi_state->cred,
279                                         NULL, 
280                                         NULL);
281         if (maj_stat) {
282                 DEBUG(1, ("Aquiring initiator credentails failed: %s\n", 
283                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
284                 return NT_STATUS_UNSUCCESSFUL;
285         }
286
287         return NT_STATUS_OK;
288 }
289
290
291 /**
292  * Check if the packet is one for this mechansim
293  * 
294  * @param gensec_security GENSEC state
295  * @param in The request, as a DATA_BLOB
296  * @return Error, INVALID_PARAMETER if it's not a packet for us
297  *                or NT_STATUS_OK if the packet is ok. 
298  */
299
300 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, 
301                                     const DATA_BLOB *in) 
302 {
303         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
304                 return NT_STATUS_OK;
305         } else {
306                 return NT_STATUS_INVALID_PARAMETER;
307         }
308 }
309
310
311 /**
312  * Next state function for the GSSAPI GENSEC mechanism
313  * 
314  * @param gensec_gssapi_state GSSAPI State
315  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
316  * @param in The request, as a DATA_BLOB
317  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
318  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
319  *                or NT_STATUS_OK if the user is authenticated. 
320  */
321
322 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
323                                    TALLOC_CTX *out_mem_ctx, 
324                                    const DATA_BLOB in, DATA_BLOB *out) 
325 {
326         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
327         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
328         OM_uint32 maj_stat, min_stat;
329         OM_uint32 min_stat2;
330         gss_buffer_desc input_token, output_token;
331         gss_OID gss_oid_p;
332         input_token.length = in.length;
333         input_token.value = in.data;
334
335         switch (gensec_security->gensec_role) {
336         case GENSEC_CLIENT:
337         {
338                 maj_stat = gss_init_sec_context(&min_stat, 
339                                                 gensec_gssapi_state->cred,
340                                                 &gensec_gssapi_state->gssapi_context, 
341                                                 gensec_gssapi_state->server_name, 
342                                                 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
343                                                 gensec_gssapi_state->want_flags, 
344                                                 0, 
345                                                 gensec_gssapi_state->input_chan_bindings,
346                                                 &input_token, 
347                                                 NULL, 
348                                                 &output_token, 
349                                                 &gensec_gssapi_state->got_flags, /* ret flags */
350                                                 NULL);
351                 break;
352         }
353         case GENSEC_SERVER:
354         {
355                 maj_stat = gss_accept_sec_context(&min_stat, 
356                                                   &gensec_gssapi_state->gssapi_context, 
357                                                   gensec_gssapi_state->cred,
358                                                   &input_token, 
359                                                   gensec_gssapi_state->input_chan_bindings,
360                                                   &gensec_gssapi_state->client_name, 
361                                                   &gss_oid_p,
362                                                   &output_token, 
363                                                   &gensec_gssapi_state->got_flags, 
364                                                   NULL, 
365                                                   NULL);
366                 gensec_gssapi_state->gss_oid = gss_oid_p;
367                 break;
368         }
369         default:
370                 return NT_STATUS_INVALID_PARAMETER;
371                 
372         }
373
374         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
375         gss_release_buffer(&min_stat2, &output_token);
376
377         if (maj_stat == GSS_S_COMPLETE) {
378                 return NT_STATUS_OK;
379         } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
380                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
381         } else {
382                 if (maj_stat == GSS_S_FAILURE
383                     && (min_stat == KRB5KRB_AP_ERR_BADVERSION || min_stat == KRB5KRB_AP_ERR_MSG_TYPE)) {
384                         /* garbage input, possibly from the auto-mech detection */
385                         return NT_STATUS_INVALID_PARAMETER;
386                 }
387                 DEBUG(1, ("GSS Update failed: %s\n", 
388                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
389                 return nt_status;
390         }
391 }
392
393 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
394                                    TALLOC_CTX *mem_ctx, 
395                                    const DATA_BLOB *in, 
396                                    DATA_BLOB *out)
397 {
398         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
399         OM_uint32 maj_stat, min_stat;
400         gss_buffer_desc input_token, output_token;
401         int conf_state;
402         input_token.length = in->length;
403         input_token.value = in->data;
404         
405         maj_stat = gss_wrap(&min_stat, 
406                             gensec_gssapi_state->gssapi_context, 
407                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
408                             GSS_C_QOP_DEFAULT,
409                             &input_token,
410                             &conf_state,
411                             &output_token);
412         if (GSS_ERROR(maj_stat)) {
413                 DEBUG(1, ("GSS Wrap failed: %s\n", 
414                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
415                 return NT_STATUS_ACCESS_DENIED;
416         }
417         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
418
419         gss_release_buffer(&min_stat, &output_token);
420
421         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
422             && !conf_state) {
423                 return NT_STATUS_ACCESS_DENIED;
424         }
425         return NT_STATUS_OK;
426 }
427
428 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
429                                      TALLOC_CTX *mem_ctx, 
430                                      const DATA_BLOB *in, 
431                                      DATA_BLOB *out)
432 {
433         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
434         OM_uint32 maj_stat, min_stat;
435         gss_buffer_desc input_token, output_token;
436         int conf_state;
437         gss_qop_t qop_state;
438         input_token.length = in->length;
439         input_token.value = in->data;
440         
441         maj_stat = gss_unwrap(&min_stat, 
442                               gensec_gssapi_state->gssapi_context, 
443                               &input_token,
444                               &output_token, 
445                               &conf_state,
446                               &qop_state);
447         if (GSS_ERROR(maj_stat)) {
448                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
449                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
450                 return NT_STATUS_ACCESS_DENIED;
451         }
452         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
453
454         gss_release_buffer(&min_stat, &output_token);
455         
456         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
457             && !conf_state) {
458                 return NT_STATUS_ACCESS_DENIED;
459         }
460         return NT_STATUS_OK;
461 }
462
463 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security) 
464 {
465         /* not const but work for DCERPC packets and arcfour */
466         return 45;
467 }
468
469 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
470                                           TALLOC_CTX *mem_ctx, 
471                                           uint8_t *data, size_t length, 
472                                           const uint8_t *whole_pdu, size_t pdu_length, 
473                                           DATA_BLOB *sig)
474 {
475         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
476         OM_uint32 maj_stat, min_stat;
477         gss_buffer_desc input_token, output_token;
478         int conf_state;
479         ssize_t sig_length = 0;
480
481         input_token.length = length;
482         input_token.value = data;
483         
484         maj_stat = gss_wrap(&min_stat, 
485                             gensec_gssapi_state->gssapi_context,
486                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
487                             GSS_C_QOP_DEFAULT,
488                             &input_token,
489                             &conf_state,
490                             &output_token);
491         if (GSS_ERROR(maj_stat)) {
492                 DEBUG(1, ("GSS Wrap failed: %s\n", 
493                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
494                 return NT_STATUS_ACCESS_DENIED;
495         }
496
497         if (output_token.length < length) {
498                 return NT_STATUS_INTERNAL_ERROR;
499         }
500
501         sig_length = 45;
502
503         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
504         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
505
506         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
507         dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
508         dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
509
510         gss_release_buffer(&min_stat, &output_token);
511
512         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
513             && !conf_state) {
514                 return NT_STATUS_ACCESS_DENIED;
515         }
516         return NT_STATUS_OK;
517 }
518
519 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
520                                             TALLOC_CTX *mem_ctx, 
521                                             uint8_t *data, size_t length, 
522                                             const uint8_t *whole_pdu, size_t pdu_length,
523                                             const DATA_BLOB *sig)
524 {
525         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
526         OM_uint32 maj_stat, min_stat;
527         gss_buffer_desc input_token, output_token;
528         int conf_state;
529         gss_qop_t qop_state;
530         DATA_BLOB in;
531
532         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
533
534         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
535
536         memcpy(in.data, sig->data, sig->length);
537         memcpy(in.data + sig->length, data, length);
538
539         input_token.length = in.length;
540         input_token.value = in.data;
541         
542         maj_stat = gss_unwrap(&min_stat, 
543                               gensec_gssapi_state->gssapi_context, 
544                               &input_token,
545                               &output_token, 
546                               &conf_state,
547                               &qop_state);
548         if (GSS_ERROR(maj_stat)) {
549                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
550                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
551                 return NT_STATUS_ACCESS_DENIED;
552         }
553
554         if (output_token.length != length) {
555                 return NT_STATUS_INTERNAL_ERROR;
556         }
557
558         memcpy(data, output_token.value, length);
559
560         gss_release_buffer(&min_stat, &output_token);
561         
562         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
563             && !conf_state) {
564                 return NT_STATUS_ACCESS_DENIED;
565         }
566         return NT_STATUS_OK;
567 }
568
569 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
570                                           TALLOC_CTX *mem_ctx, 
571                                           const uint8_t *data, size_t length, 
572                                           const uint8_t *whole_pdu, size_t pdu_length, 
573                                           DATA_BLOB *sig)
574 {
575         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
576         OM_uint32 maj_stat, min_stat;
577         gss_buffer_desc input_token, output_token;
578         int conf_state;
579         ssize_t sig_length = 0;
580
581         input_token.length = length;
582         input_token.value = discard_const_p(uint8_t *, data);
583
584         maj_stat = gss_wrap(&min_stat, 
585                             gensec_gssapi_state->gssapi_context,
586                             0,
587                             GSS_C_QOP_DEFAULT,
588                             &input_token,
589                             &conf_state,
590                             &output_token);
591         if (GSS_ERROR(maj_stat)) {
592                 DEBUG(1, ("GSS Wrap failed: %s\n", 
593                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
594                 return NT_STATUS_ACCESS_DENIED;
595         }
596
597         if (output_token.length < length) {
598                 return NT_STATUS_INTERNAL_ERROR;
599         }
600
601         sig_length = 45;
602
603         /*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
604         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
605
606         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
607
608         gss_release_buffer(&min_stat, &output_token);
609
610         return NT_STATUS_OK;
611 }
612
613 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
614                                            TALLOC_CTX *mem_ctx, 
615                                            const uint8_t *data, size_t length, 
616                                            const uint8_t *whole_pdu, size_t pdu_length, 
617                                            const DATA_BLOB *sig)
618 {
619         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
620         OM_uint32 maj_stat, min_stat;
621         gss_buffer_desc input_token, output_token;
622         int conf_state;
623         gss_qop_t qop_state;
624         DATA_BLOB in;
625
626         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
627
628         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
629
630         memcpy(in.data, sig->data, sig->length);
631         memcpy(in.data + sig->length, data, length);
632
633         input_token.length = in.length;
634         input_token.value = in.data;
635         
636         maj_stat = gss_unwrap(&min_stat, 
637                               gensec_gssapi_state->gssapi_context, 
638                               &input_token,
639                               &output_token, 
640                               &conf_state,
641                               &qop_state);
642         if (GSS_ERROR(maj_stat)) {
643                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
644                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
645                 return NT_STATUS_ACCESS_DENIED;
646         }
647
648         if (output_token.length != length) {
649                 return NT_STATUS_INTERNAL_ERROR;
650         }
651
652         gss_release_buffer(&min_stat, &output_token);
653
654         return NT_STATUS_OK;
655 }
656
657 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
658                                        uint32_t feature) 
659 {
660         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
661         if (feature & GENSEC_FEATURE_SIGN) {
662                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
663         }
664         if (feature & GENSEC_FEATURE_SEAL) {
665                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
666         }
667         if (feature & GENSEC_FEATURE_SESSION_KEY) {
668                 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
669                     && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
670                         return True;
671                 }
672         }
673         if (feature & GENSEC_FEATURE_DCE_STYLE) {
674                 return True;
675         }
676         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
677                 return True;
678         }
679         return False;
680 }
681
682 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
683                                           DATA_BLOB *session_key) 
684 {
685         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
686         
687         if (gensec_gssapi_state->session_key.data) {
688                 *session_key = gensec_gssapi_state->session_key;
689                 return NT_STATUS_OK;
690         }
691
692         /* Ensure we only call this for GSSAPI/krb5, otherwise things could get very ugly */
693         if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
694             && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
695                        gensec_gssapi_state->gss_oid->length) == 0)) {
696                 OM_uint32 maj_stat, min_stat;
697                 gss_buffer_desc skey;
698                 
699                 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 
700                                                         gensec_gssapi_state->gssapi_context, 
701                                                         &skey);
702                 
703                 if (maj_stat == 0) {
704                         DEBUG(10, ("Got KRB5 session key of length %d\n",  
705                                    (int)skey.length));
706                         gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state, 
707                                                                             skey.value, skey.length);
708                         *session_key = gensec_gssapi_state->session_key;
709                         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
710                         
711                         gss_release_buffer(&min_stat, &skey);
712                         return NT_STATUS_OK;
713                 }
714                 return NT_STATUS_NO_USER_SESSION_KEY;
715         }
716         
717         DEBUG(1, ("NO session key for this mech\n"));
718         return NT_STATUS_NO_USER_SESSION_KEY;
719 }
720
721 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
722                                          struct auth_session_info **_session_info) 
723 {
724         NTSTATUS nt_status;
725         TALLOC_CTX *mem_ctx;
726         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
727         struct auth_serversupplied_info *server_info = NULL;
728         struct auth_session_info *session_info = NULL;
729         struct PAC_LOGON_INFO *logon_info;
730         char *p;
731         char *principal;
732         const char *account_name;
733         const char *realm;
734         OM_uint32 maj_stat, min_stat;
735         gss_buffer_desc name_token;
736         gss_buffer_desc pac;
737         krb5_keyblock *keyblock;
738         
739         mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context"); 
740         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
741
742         maj_stat = gss_display_name (&min_stat,
743                                      gensec_gssapi_state->client_name,
744                                      &name_token,
745                                      NULL);
746         if (maj_stat) {
747                 return NT_STATUS_FOOBAR;
748         }
749
750         principal = talloc_strndup(mem_ctx, name_token.value, name_token.length);
751
752         gss_release_buffer(&min_stat, &name_token);
753
754         if (!principal) {
755                 talloc_free(mem_ctx);
756                 return NT_STATUS_NO_MEMORY;
757         }
758
759         p = strchr(principal, '@');
760         if (p) {
761                 *p = '\0';
762                 p++;
763                 realm = p;
764         } else {
765                 realm = lp_realm();
766         }
767         account_name = principal;
768         
769         maj_stat = gss_krb5_copy_service_keyblock(&min_stat, 
770                                                   gensec_gssapi_state->gssapi_context, 
771                                                   &keyblock);
772
773         maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 
774                                                                gensec_gssapi_state->gssapi_context, 
775                                                                KRB5_AUTHDATA_IF_RELEVANT,
776                                                                &pac);
777         
778         if (maj_stat == 0) {
779                 DATA_BLOB pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
780                 pac_blob = unwrap_pac(mem_ctx, &pac_blob);
781                 gss_release_buffer(&min_stat, &pac);
782                 
783                 /* decode and verify the pac */
784                 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
785                                                     gensec_gssapi_state->smb_krb5_context->krb5_context,
786                                                     NULL, keyblock);
787
788                 if (NT_STATUS_IS_OK(nt_status)) {
789                         union netr_Validation validation;
790                         validation.sam3 = &logon_info->info3;
791                         nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, 
792                                                                          account_name,
793                                                                          3, &validation,
794                                                                          &server_info); 
795                         if (!NT_STATUS_IS_OK(nt_status)) {
796                                 talloc_free(mem_ctx);
797                                 return nt_status;
798                         }
799                 } else {
800                         maj_stat = 1;
801                 }
802         }
803         
804         if (maj_stat) {
805                 /* IF we have the PAC - otherwise we need to get this
806                  * data from elsewere - local ldb, or (TODO) lookup of some
807                  * kind... 
808                  *
809                  * when heimdal can generate the PAC, we should fail if there's
810                  * no PAC present
811                  */
812
813                 DATA_BLOB user_sess_key = data_blob(NULL, 0);
814                 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
815                 /* TODO: should we pass the krb5 session key in here? */
816                 nt_status = sam_get_server_info(mem_ctx, account_name, realm,
817                                                 user_sess_key, lm_sess_key,
818                                                 &server_info);
819                 if (!NT_STATUS_IS_OK(nt_status)) {
820                         talloc_free(mem_ctx);
821                         return nt_status;
822                 }
823         }
824
825         /* references the server_info into the session_info */
826         nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
827         talloc_free(server_info);
828         NT_STATUS_NOT_OK_RETURN(nt_status);
829
830         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
831         NT_STATUS_NOT_OK_RETURN(nt_status);
832
833         *_session_info = session_info;
834
835         return NT_STATUS_OK;
836 }
837
838 static const char *gensec_krb5_oids[] = { 
839         GENSEC_OID_KERBEROS5,
840         GENSEC_OID_KERBEROS5_OLD,
841         NULL 
842 };
843
844 /* As a server, this could in theory accept any GSSAPI mech */
845 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
846         .name           = "gssapi_krb5",
847         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
848         .oid            = gensec_krb5_oids,
849         .client_start   = gensec_gssapi_client_start,
850         .server_start   = gensec_gssapi_server_start,
851         .magic          = gensec_gssapi_magic,
852         .update         = gensec_gssapi_update,
853         .session_key    = gensec_gssapi_session_key,
854         .session_info   = gensec_gssapi_session_info,
855         .sig_size       = gensec_gssapi_sig_size,
856         .sign_packet    = gensec_gssapi_sign_packet,
857         .check_packet   = gensec_gssapi_check_packet,
858         .seal_packet    = gensec_gssapi_seal_packet,
859         .unseal_packet  = gensec_gssapi_unseal_packet,
860         .wrap           = gensec_gssapi_wrap,
861         .unwrap         = gensec_gssapi_unwrap,
862         .have_feature   = gensec_gssapi_have_feature,
863         .enabled        = False
864 };
865
866 NTSTATUS gensec_gssapi_init(void)
867 {
868         NTSTATUS ret;
869
870         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
871         if (!NT_STATUS_IS_OK(ret)) {
872                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
873                         gensec_gssapi_krb5_security_ops.name));
874                 return ret;
875         }
876
877         return ret;
878 }