r6800: A big GENSEC update:
[gd/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
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 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 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_AUTH
34
35 static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc =
36         {9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
37
38 struct gensec_gssapi_state {
39         gss_ctx_id_t gssapi_context;
40         struct gss_channel_bindings_struct *input_chan_bindings;
41         gss_name_t server_name;
42         gss_name_t client_name;
43         OM_uint32 want_flags, got_flags;
44         const gss_OID_desc *gss_oid;
45
46         DATA_BLOB session_key;
47         DATA_BLOB pac;
48
49         krb5_context krb5_context;
50         krb5_ccache ccache;
51         const char *ccache_name;
52
53         gss_cred_id_t cred;
54 };
55
56 static char *gssapi_error_string(TALLOC_CTX *mem_ctx, 
57                                  OM_uint32 maj_stat, OM_uint32 min_stat)
58 {
59         OM_uint32 disp_min_stat, disp_maj_stat;
60         gss_buffer_desc maj_error_message;
61         gss_buffer_desc min_error_message;
62         OM_uint32 msg_ctx = 0;
63
64         char *ret;
65
66         maj_error_message.value = NULL;
67         min_error_message.value = NULL;
68         
69         disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
70                            GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
71         disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
72                            GSS_C_NULL_OID, &msg_ctx, &min_error_message);
73         ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
74
75         gss_release_buffer(&disp_min_stat, &maj_error_message);
76         gss_release_buffer(&disp_min_stat, &min_error_message);
77
78         return ret;
79 }
80
81
82 static int gensec_gssapi_destory(void *ptr) 
83 {
84         struct gensec_gssapi_state *gensec_gssapi_state = ptr;
85         OM_uint32 maj_stat, min_stat;
86         
87         if (gensec_gssapi_state->cred != GSS_C_NO_CREDENTIAL) {
88                 maj_stat = gss_release_cred(&min_stat, 
89                                             &gensec_gssapi_state->cred);
90         }
91
92         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
93                 maj_stat = gss_delete_sec_context (&min_stat,
94                                                    &gensec_gssapi_state->gssapi_context,
95                                                    GSS_C_NO_BUFFER);
96         }
97
98         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
99                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
100         }
101         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
102                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
103         }
104         if (gensec_gssapi_state->krb5_context) {
105                 krb5_free_context(gensec_gssapi_state->krb5_context);
106         }
107         return 0;
108 }
109
110 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
111 {
112         struct gensec_gssapi_state *gensec_gssapi_state;
113         krb5_error_code ret;
114         
115         gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
116         if (!gensec_gssapi_state) {
117                 return NT_STATUS_NO_MEMORY;
118         }
119
120         gensec_security->private_data = gensec_gssapi_state;
121
122         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
123         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
124         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
125
126         /* TODO: Fill in channel bindings */
127         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
128         
129         gensec_gssapi_state->want_flags = 0;
130         gensec_gssapi_state->got_flags = 0;
131
132         gensec_gssapi_state->session_key = data_blob(NULL, 0);
133         gensec_gssapi_state->pac = data_blob(NULL, 0);
134
135         gensec_gssapi_state->krb5_context = NULL;
136
137         gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
138
139         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
140
141         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
142 #ifndef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
143                 /* GSSAPI won't give us the session keys, without the
144                  * right hooks.  This is critical when requested, so
145                  * fail outright. */
146                 return NT_STATUS_INVALID_PARAMETER;
147 #endif
148         }
149         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
150                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
151         }
152         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
153                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
154         }
155         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
156 #ifndef GSS_C_DCE_STYLE
157                 /* GSSAPI DCE_STYLE is critical when requested, so
158                  * fail outright */
159                 return NT_STATUS_INVALID_PARAMETER;
160 #else
161                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
162 #endif
163         }
164
165         gensec_gssapi_state->gss_oid = &gensec_gss_krb5_mechanism_oid_desc;
166         
167         ret = krb5_init_context(&gensec_gssapi_state->krb5_context);
168         if (ret) {
169                 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",                                  
170                          smb_get_krb5_error_message(gensec_gssapi_state->krb5_context, 
171                                                     ret, gensec_gssapi_state)));
172                 return NT_STATUS_INTERNAL_ERROR;
173         }
174         
175         if (lp_realm() && *lp_realm()) {
176                 char *upper_realm = strupper_talloc(gensec_gssapi_state, lp_realm());
177                 if (!upper_realm) {
178                         DEBUG(1,("gensec_krb5_start: could not uppercase realm: %s\n", lp_realm()));
179                         return NT_STATUS_NO_MEMORY;
180                 }
181                 ret = krb5_set_default_realm(gensec_gssapi_state->krb5_context, upper_realm);
182                 if (ret) {
183                         DEBUG(1,("gensec_krb5_start: krb5_set_default_realm failed (%s)\n", 
184                                  smb_get_krb5_error_message(gensec_gssapi_state->krb5_context, 
185                                                             ret, gensec_gssapi_state)));
186                         return NT_STATUS_INTERNAL_ERROR;
187                 }
188         }
189
190         return NT_STATUS_OK;
191 }
192
193 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
194 {
195         NTSTATUS nt_status;
196         struct gensec_gssapi_state *gensec_gssapi_state;
197
198         nt_status = gensec_gssapi_start(gensec_security);
199         if (!NT_STATUS_IS_OK(nt_status)) {
200                 return nt_status;
201         }
202
203         gensec_gssapi_state = gensec_security->private_data;
204
205         return NT_STATUS_OK;
206 }
207
208 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
209 {
210         struct gensec_gssapi_state *gensec_gssapi_state;
211         NTSTATUS nt_status;
212         gss_buffer_desc name_token;
213         OM_uint32 maj_stat, min_stat;
214         const char *ccache_name;
215
216         nt_status = gensec_gssapi_start(gensec_security);
217         if (!NT_STATUS_IS_OK(nt_status)) {
218                 return nt_status;
219         }
220
221         gensec_gssapi_state = gensec_security->private_data;
222
223         name_token.value = talloc_asprintf(gensec_gssapi_state, "%s@%s", gensec_get_target_service(gensec_security), 
224                                            gensec_get_target_hostname(gensec_security));
225         name_token.length = strlen(name_token.value);
226
227         maj_stat = gss_import_name (&min_stat,
228                                     &name_token,
229                                     GSS_C_NT_HOSTBASED_SERVICE,
230                                     &gensec_gssapi_state->server_name);
231         if (maj_stat) {
232                 DEBUG(1, ("GSS Import name of %s failed: %s\n",
233                           (char *)name_token.value,
234                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
235                 return NT_STATUS_UNSUCCESSFUL;
236         }
237
238         name_token.value = cli_credentials_get_principal(gensec_get_credentials(gensec_security), gensec_gssapi_state),
239         name_token.length = strlen(name_token.value);
240
241         maj_stat = gss_import_name (&min_stat,
242                                     &name_token,
243                                     GSS_C_NT_USER_NAME,
244                                     &gensec_gssapi_state->client_name);
245         if (maj_stat) {
246                 DEBUG(1, ("GSS Import name of %s failed: %s\n",
247                           (char *)name_token.value,
248                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
249                 return NT_STATUS_UNSUCCESSFUL;
250         }
251
252         initialize_krb5_error_table();
253         
254         nt_status = kinit_to_ccache(gensec_gssapi_state, 
255                                     gensec_get_credentials(gensec_security),
256                                     gensec_gssapi_state->krb5_context, 
257                                     &gensec_gssapi_state->ccache, &gensec_gssapi_state->ccache_name);
258         if (!NT_STATUS_IS_OK(nt_status)) {
259                 return nt_status;
260         }
261
262         maj_stat = gss_krb5_ccache_name(&min_stat, 
263                                         gensec_gssapi_state->ccache_name, 
264                                         NULL);
265         if (maj_stat) {
266                 DEBUG(1, ("GSS krb5 ccache set %s failed: %s\n",
267                           ccache_name,
268                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
269                 return NT_STATUS_UNSUCCESSFUL;
270         }
271
272         maj_stat = gss_acquire_cred(&min_stat, 
273                                     gensec_gssapi_state->client_name,
274                                     GSS_C_INDEFINITE,
275                                     GSS_C_NULL_OID_SET,
276                                     GSS_C_INITIATE,
277                                     &gensec_gssapi_state->cred,
278                                     NULL, 
279                                     NULL);
280         if (maj_stat) {
281                 DEBUG(1, ("Aquiring initiator credentails failed: %s\n", 
282                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
283                 return NT_STATUS_UNSUCCESSFUL;
284         }
285
286         return NT_STATUS_OK;
287 }
288
289
290
291 /**
292  * Next state function for the GSSAPI GENSEC mechanism
293  * 
294  * @param gensec_gssapi_state GSSAPI State
295  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
296  * @param in The request, as a DATA_BLOB
297  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
298  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
299  *                or NT_STATUS_OK if the user is authenticated. 
300  */
301
302 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
303                                    TALLOC_CTX *out_mem_ctx, 
304                                    const DATA_BLOB in, DATA_BLOB *out) 
305 {
306         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
307         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
308         OM_uint32 maj_stat, min_stat;
309         OM_uint32 min_stat2;
310         gss_buffer_desc input_token, output_token;
311         gss_OID gss_oid_p;
312         input_token.length = in.length;
313         input_token.value = in.data;
314
315         switch (gensec_security->gensec_role) {
316         case GENSEC_CLIENT:
317         {
318                 maj_stat = gss_init_sec_context(&min_stat, 
319                                                 GSS_C_NO_CREDENTIAL, 
320                                                 &gensec_gssapi_state->gssapi_context, 
321                                                 gensec_gssapi_state->server_name, 
322                                                 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
323                                                 gensec_gssapi_state->want_flags, 
324                                                 0, 
325                                                 gensec_gssapi_state->input_chan_bindings,
326                                                 &input_token, 
327                                                 NULL, 
328                                                 &output_token, 
329                                                 &gensec_gssapi_state->got_flags, /* ret flags */
330                                                 NULL);
331                 break;
332         }
333         case GENSEC_SERVER:
334         {
335                 maj_stat = gss_accept_sec_context(&min_stat, 
336                                                   &gensec_gssapi_state->gssapi_context, 
337                                                   GSS_C_NO_CREDENTIAL, 
338                                                   &input_token, 
339                                                   gensec_gssapi_state->input_chan_bindings,
340                                                   &gensec_gssapi_state->client_name, 
341                                                   &gss_oid_p,
342                                                   &output_token, 
343                                                   &gensec_gssapi_state->got_flags, 
344                                                   NULL, 
345                                                   NULL);
346                 gensec_gssapi_state->gss_oid = gss_oid_p;
347                 break;
348         }
349         default:
350                 return NT_STATUS_INVALID_PARAMETER;
351                 
352         }
353
354         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
355         gss_release_buffer(&min_stat2, &output_token);
356
357         if (maj_stat == GSS_S_COMPLETE) {
358                 return NT_STATUS_OK;
359         } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
360                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
361         } else {
362                 DEBUG(1, ("GSS Update failed: %s\n", 
363                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
364                 return nt_status;
365         }
366 }
367
368 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
369                                    TALLOC_CTX *mem_ctx, 
370                                    const DATA_BLOB *in, 
371                                    DATA_BLOB *out)
372 {
373         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
374         OM_uint32 maj_stat, min_stat;
375         gss_buffer_desc input_token, output_token;
376         int conf_state;
377         input_token.length = in->length;
378         input_token.value = in->data;
379         
380         maj_stat = gss_wrap(&min_stat, 
381                             gensec_gssapi_state->gssapi_context, 
382                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
383                             GSS_C_QOP_DEFAULT,
384                             &input_token,
385                             &conf_state,
386                             &output_token);
387         if (GSS_ERROR(maj_stat)) {
388                 DEBUG(1, ("GSS Wrap failed: %s\n", 
389                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
390                 return NT_STATUS_ACCESS_DENIED;
391         }
392         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
393
394         gss_release_buffer(&min_stat, &output_token);
395
396         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
397             && !conf_state) {
398                 return NT_STATUS_ACCESS_DENIED;
399         }
400         return NT_STATUS_OK;
401 }
402
403 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
404                                      TALLOC_CTX *mem_ctx, 
405                                      const DATA_BLOB *in, 
406                                      DATA_BLOB *out)
407 {
408         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
409         OM_uint32 maj_stat, min_stat;
410         gss_buffer_desc input_token, output_token;
411         int conf_state;
412         gss_qop_t qop_state;
413         input_token.length = in->length;
414         input_token.value = in->data;
415         
416         maj_stat = gss_unwrap(&min_stat, 
417                               gensec_gssapi_state->gssapi_context, 
418                               &input_token,
419                               &output_token, 
420                               &conf_state,
421                               &qop_state);
422         if (GSS_ERROR(maj_stat)) {
423                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
424                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
425                 return NT_STATUS_ACCESS_DENIED;
426         }
427         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
428
429         gss_release_buffer(&min_stat, &output_token);
430         
431         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
432             && !conf_state) {
433                 return NT_STATUS_ACCESS_DENIED;
434         }
435         return NT_STATUS_OK;
436 }
437
438 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security) 
439 {
440         /* not const but work for DCERPC packets and arcfour */
441         return 45;
442 }
443
444 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
445                                           TALLOC_CTX *mem_ctx, 
446                                           uint8_t *data, size_t length, 
447                                           const uint8_t *whole_pdu, size_t pdu_length, 
448                                           DATA_BLOB *sig)
449 {
450         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
451         OM_uint32 maj_stat, min_stat;
452         gss_buffer_desc input_token, output_token;
453         int conf_state;
454         ssize_t sig_length = 0;
455
456         input_token.length = length;
457         input_token.value = data;
458         
459         maj_stat = gss_wrap(&min_stat, 
460                             gensec_gssapi_state->gssapi_context,
461                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
462                             GSS_C_QOP_DEFAULT,
463                             &input_token,
464                             &conf_state,
465                             &output_token);
466         if (GSS_ERROR(maj_stat)) {
467                 DEBUG(1, ("GSS Wrap failed: %s\n", 
468                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
469                 return NT_STATUS_ACCESS_DENIED;
470         }
471
472         if (output_token.length < length) {
473                 return NT_STATUS_INTERNAL_ERROR;
474         }
475
476         sig_length = 45;
477
478         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
479         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
480
481         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
482         dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
483         dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
484
485         gss_release_buffer(&min_stat, &output_token);
486
487         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
488             && !conf_state) {
489                 return NT_STATUS_ACCESS_DENIED;
490         }
491         return NT_STATUS_OK;
492 }
493
494 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
495                                             TALLOC_CTX *mem_ctx, 
496                                             uint8_t *data, size_t length, 
497                                             const uint8_t *whole_pdu, size_t pdu_length,
498                                             const DATA_BLOB *sig)
499 {
500         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
501         OM_uint32 maj_stat, min_stat;
502         gss_buffer_desc input_token, output_token;
503         int conf_state;
504         gss_qop_t qop_state;
505         DATA_BLOB in;
506
507         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
508
509         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
510
511         memcpy(in.data, sig->data, sig->length);
512         memcpy(in.data + sig->length, data, length);
513
514         input_token.length = in.length;
515         input_token.value = in.data;
516         
517         maj_stat = gss_unwrap(&min_stat, 
518                               gensec_gssapi_state->gssapi_context, 
519                               &input_token,
520                               &output_token, 
521                               &conf_state,
522                               &qop_state);
523         if (GSS_ERROR(maj_stat)) {
524                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
525                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
526                 return NT_STATUS_ACCESS_DENIED;
527         }
528
529         if (output_token.length != length) {
530                 return NT_STATUS_INTERNAL_ERROR;
531         }
532
533         memcpy(data, output_token.value, length);
534
535         gss_release_buffer(&min_stat, &output_token);
536         
537         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
538             && !conf_state) {
539                 return NT_STATUS_ACCESS_DENIED;
540         }
541         return NT_STATUS_OK;
542 }
543
544 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
545                                           TALLOC_CTX *mem_ctx, 
546                                           const uint8_t *data, size_t length, 
547                                           const uint8_t *whole_pdu, size_t pdu_length, 
548                                           DATA_BLOB *sig)
549 {
550         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
551         OM_uint32 maj_stat, min_stat;
552         gss_buffer_desc input_token, output_token;
553         int conf_state;
554         ssize_t sig_length = 0;
555
556         input_token.length = length;
557         input_token.value = discard_const_p(uint8_t *, data);
558
559         maj_stat = gss_wrap(&min_stat, 
560                             gensec_gssapi_state->gssapi_context,
561                             0,
562                             GSS_C_QOP_DEFAULT,
563                             &input_token,
564                             &conf_state,
565                             &output_token);
566         if (GSS_ERROR(maj_stat)) {
567                 DEBUG(1, ("GSS Wrap failed: %s\n", 
568                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
569                 return NT_STATUS_ACCESS_DENIED;
570         }
571
572         if (output_token.length < length) {
573                 return NT_STATUS_INTERNAL_ERROR;
574         }
575
576         sig_length = 45;
577
578         /*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
579         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
580
581         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
582
583         gss_release_buffer(&min_stat, &output_token);
584
585         return NT_STATUS_OK;
586 }
587
588 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
589                                            TALLOC_CTX *mem_ctx, 
590                                            const uint8_t *data, size_t length, 
591                                            const uint8_t *whole_pdu, size_t pdu_length, 
592                                            const DATA_BLOB *sig)
593 {
594         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
595         OM_uint32 maj_stat, min_stat;
596         gss_buffer_desc input_token, output_token;
597         int conf_state;
598         gss_qop_t qop_state;
599         DATA_BLOB in;
600
601         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
602
603         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
604
605         memcpy(in.data, sig->data, sig->length);
606         memcpy(in.data + sig->length, data, length);
607
608         input_token.length = in.length;
609         input_token.value = in.data;
610         
611         maj_stat = gss_unwrap(&min_stat, 
612                               gensec_gssapi_state->gssapi_context, 
613                               &input_token,
614                               &output_token, 
615                               &conf_state,
616                               &qop_state);
617         if (GSS_ERROR(maj_stat)) {
618                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
619                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
620                 return NT_STATUS_ACCESS_DENIED;
621         }
622
623         if (output_token.length != length) {
624                 return NT_STATUS_INTERNAL_ERROR;
625         }
626
627         gss_release_buffer(&min_stat, &output_token);
628
629         return NT_STATUS_OK;
630 }
631
632 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
633                                        uint32_t feature) 
634 {
635         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
636         if (feature & GENSEC_FEATURE_SIGN) {
637                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
638         }
639         if (feature & GENSEC_FEATURE_SEAL) {
640                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
641         }
642         if (feature & GENSEC_FEATURE_SESSION_KEY) {
643 #ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
644                 if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
645                     && (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, gensec_gssapi_state->gss_oid->length) == 0)) {
646                         return True;
647                 }
648 #endif 
649         }
650         return False;
651 }
652
653 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
654                                           DATA_BLOB *session_key) 
655 {
656         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
657         
658         if (gensec_gssapi_state->session_key.data) {
659                 *session_key = gensec_gssapi_state->session_key;
660                 return NT_STATUS_OK;
661         }
662
663 #ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
664         /* Ensure we only call this for GSSAPI/krb5, otherwise things could get very ugly */
665         if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
666             && (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, 
667                        gensec_gssapi_state->gss_oid->length) == 0)) {
668                 OM_uint32 maj_stat, min_stat;
669                 gss_buffer_desc skey;
670                 
671                 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 
672                                                         gensec_gssapi_state->gssapi_context, 
673                                                         &skey);
674                 
675                 if (maj_stat == 0) {
676                         DEBUG(10, ("Got KRB5 session key of length %d\n",  skey.length));
677                         gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state, 
678                                                                             skey.value, skey.length);
679                         *session_key = gensec_gssapi_state->session_key;
680                         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
681                         
682                         gss_release_buffer(&min_stat, &skey);
683                         return NT_STATUS_OK;
684                 }
685                 return NT_STATUS_NO_USER_SESSION_KEY;
686         }
687 #endif
688         
689         DEBUG(1, ("NO session key for this mech\n"));
690         return NT_STATUS_NO_USER_SESSION_KEY;
691 }
692
693 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
694                                          struct auth_session_info **_session_info) 
695 {
696         NTSTATUS nt_status;
697         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
698         struct auth_serversupplied_info *server_info = NULL;
699         struct auth_session_info *session_info = NULL;
700         char *p;
701         char *principal;
702         const char *account_name;
703         const char *realm;
704         OM_uint32 maj_stat, min_stat;
705         gss_buffer_desc name_token;
706         
707         maj_stat = gss_display_name (&min_stat,
708                                      gensec_gssapi_state->client_name,
709                                      &name_token,
710                                      NULL);
711         if (maj_stat) {
712                 return NT_STATUS_FOOBAR;
713         }
714
715         principal = talloc_strndup(gensec_gssapi_state, name_token.value, name_token.length);
716
717         gss_release_buffer(&min_stat, &name_token);
718
719         NT_STATUS_HAVE_NO_MEMORY(principal);
720
721         p = strchr(principal, '@');
722         if (p) {
723                 *p = '\0';
724                 p++;
725                 realm = p;
726         } else {
727                 realm = lp_realm();
728         }
729         account_name = principal;
730
731         /* IF we have the PAC - otherwise we need to get this
732          * data from elsewere - local ldb, or (TODO) lookup of some
733          * kind... 
734          *
735          * when heimdal can generate the PAC, we should fail if there's
736          * no PAC present
737          */
738
739         {
740                 DATA_BLOB user_sess_key = data_blob(NULL, 0);
741                 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
742                 /* TODO: should we pass the krb5 session key in here? */
743                 nt_status = sam_get_server_info(gensec_gssapi_state, account_name, realm,
744                                                 user_sess_key, lm_sess_key,
745                                                 &server_info);
746                 talloc_free(principal);
747                 NT_STATUS_NOT_OK_RETURN(nt_status);
748         }
749
750         /* references the server_info into the session_info */
751         nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
752         talloc_free(server_info);
753         NT_STATUS_NOT_OK_RETURN(nt_status);
754
755         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
756         NT_STATUS_NOT_OK_RETURN(nt_status);
757
758         *_session_info = session_info;
759
760         return NT_STATUS_OK;
761 }
762
763 static const char *gensec_krb5_oids[] = { 
764         GENSEC_OID_KERBEROS5,
765         GENSEC_OID_KERBEROS5_OLD,
766         NULL 
767 };
768
769 /* As a server, this could in theory accept any GSSAPI mech */
770 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
771         .name           = "gssapi_krb5",
772         .oid            = gensec_krb5_oids,
773         .client_start   = gensec_gssapi_client_start,
774         .server_start   = gensec_gssapi_server_start,
775         .update         = gensec_gssapi_update,
776         .session_key    = gensec_gssapi_session_key,
777         .session_info   = gensec_gssapi_session_info,
778         .sig_size       = gensec_gssapi_sig_size,
779         .sign_packet    = gensec_gssapi_sign_packet,
780         .check_packet   = gensec_gssapi_check_packet,
781         .seal_packet    = gensec_gssapi_seal_packet,
782         .unseal_packet  = gensec_gssapi_unseal_packet,
783         .wrap           = gensec_gssapi_wrap,
784         .unwrap         = gensec_gssapi_unwrap,
785         .have_feature   = gensec_gssapi_have_feature,
786         .enabled        = False
787 };
788
789 NTSTATUS gensec_gssapi_init(void)
790 {
791         NTSTATUS ret;
792
793         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
794         if (!NT_STATUS_IS_OK(ret)) {
795                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
796                         gensec_gssapi_krb5_security_ops.name));
797                 return ret;
798         }
799
800         return ret;
801 }