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