r11514: Fixup debug message
[kai/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         struct keytab_container *keytab;
47         struct gssapi_creds_container *client_cred;
48
49         gss_cred_id_t cred;
50         gss_cred_id_t delegated_cred_handle;
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         if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
89                 maj_stat = gss_release_cred(&min_stat, 
90                                             &gensec_gssapi_state->delegated_cred_handle);
91         }
92
93         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
94                 maj_stat = gss_delete_sec_context (&min_stat,
95                                                    &gensec_gssapi_state->gssapi_context,
96                                                    GSS_C_NO_BUFFER);
97         }
98
99         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
100                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
101         }
102         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
103                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
104         }
105         return 0;
106 }
107
108 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
109 {
110         struct gensec_gssapi_state *gensec_gssapi_state;
111         krb5_error_code ret;
112         
113         gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
114         if (!gensec_gssapi_state) {
115                 return NT_STATUS_NO_MEMORY;
116         }
117
118         gensec_security->private_data = gensec_gssapi_state;
119
120         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
121         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
122         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
123
124         /* TODO: Fill in channel bindings */
125         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
126         
127         gensec_gssapi_state->want_flags = 0;
128         if (lp_parm_bool(-1, "gensec_gssapi", "mutual", True)) {
129                 gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
130         }
131         if (lp_parm_bool(-1, "gensec_gssapi", "delegation", True)) {
132                 gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
133         }
134
135         gensec_gssapi_state->got_flags = 0;
136
137         gensec_gssapi_state->session_key = data_blob(NULL, 0);
138         gensec_gssapi_state->pac = data_blob(NULL, 0);
139
140         gensec_gssapi_state->cred = GSS_C_NO_CREDENTIAL;
141         gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
142
143         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
144
145         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
146                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
147         }
148         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
149                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
150         }
151         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
152                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
153         }
154
155         gensec_gssapi_state->gss_oid = gss_mech_krb5;
156         
157         ret = smb_krb5_init_context(gensec_gssapi_state, 
158                                     &gensec_gssapi_state->smb_krb5_context);
159         if (ret) {
160                 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",                                  
161                          error_message(ret)));
162                 return NT_STATUS_INTERNAL_ERROR;
163         }
164         return NT_STATUS_OK;
165 }
166
167 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
168 {
169         NTSTATUS nt_status;
170         OM_uint32 maj_stat, min_stat;
171         int ret;
172         const char *principal;
173         struct gensec_gssapi_state *gensec_gssapi_state;
174         struct cli_credentials *machine_account;
175
176         nt_status = gensec_gssapi_start(gensec_security);
177         if (!NT_STATUS_IS_OK(nt_status)) {
178                 return nt_status;
179         }
180
181         gensec_gssapi_state = gensec_security->private_data;
182
183         machine_account = gensec_get_credentials(gensec_security);
184         
185         if (!machine_account) {
186                 DEBUG(3, ("No machine account credentials specified\n"));
187                 return NT_STATUS_INVALID_PARAMETER;
188         } else {
189                 ret = cli_credentials_get_keytab(machine_account, &gensec_gssapi_state->keytab);
190                 if (ret) {
191                         DEBUG(3, ("Could not create memory keytab!\n"));
192                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
193                 }
194         }
195
196         principal = cli_credentials_get_principal(machine_account, 
197                                                   machine_account);
198
199         /* This might have been explicity set to NULL, ie use what the client calls us */
200         if (principal) {
201                 gss_buffer_desc name_token;
202
203                 name_token.value  = discard_const_p(uint8_t, principal);
204                 name_token.length = strlen(principal);
205                 
206                 maj_stat = gss_import_name (&min_stat,
207                                             &name_token,
208                                             GSS_C_NT_USER_NAME,
209                                             &gensec_gssapi_state->server_name);
210
211                 if (maj_stat) {
212                         DEBUG(2, ("GSS Import name of %s failed: %s\n",
213                                   (char *)name_token.value,
214                                   gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
215                         return NT_STATUS_UNSUCCESSFUL;
216                 }
217         } else {
218                 gensec_gssapi_state->server_name = GSS_C_NO_NAME;
219         }
220
221         maj_stat = gsskrb5_acquire_cred(&min_stat, 
222                                         gensec_gssapi_state->keytab->keytab, 
223                                         gensec_gssapi_state->server_name,
224                                         GSS_C_INDEFINITE,
225                                         GSS_C_NULL_OID_SET,
226                                         GSS_C_ACCEPT,
227                                         &gensec_gssapi_state->cred,
228                                         NULL, 
229                                         NULL);
230         if (maj_stat) {
231                 DEBUG(1, ("Aquiring acceptor credentails failed: %s\n", 
232                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
233                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
234         }
235
236         return NT_STATUS_OK;
237
238 }
239
240 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
241 {
242         struct gensec_gssapi_state *gensec_gssapi_state;
243         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
244         krb5_error_code ret;
245         NTSTATUS nt_status;
246         gss_buffer_desc name_token;
247         gss_OID name_type;
248         OM_uint32 maj_stat, min_stat;
249         const char *hostname = gensec_get_target_hostname(gensec_security);
250         const char *principal;
251         struct gssapi_creds_container *gcc;
252
253         if (!hostname) {
254                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
255                 return NT_STATUS_INVALID_PARAMETER;
256         }
257         if (is_ipaddress(hostname)) {
258                 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
259                 return NT_STATUS_INVALID_PARAMETER;
260         }
261         if (strequal(hostname, "localhost")) {
262                 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
263                 return NT_STATUS_INVALID_PARAMETER;
264         }
265
266         nt_status = gensec_gssapi_start(gensec_security);
267         if (!NT_STATUS_IS_OK(nt_status)) {
268                 return nt_status;
269         }
270
271         gensec_gssapi_state = gensec_security->private_data;
272
273         principal = gensec_get_target_principal(gensec_security);
274         if (principal && lp_client_use_spnego_principal()) {
275                 name_token.value  = discard_const_p(uint8_t, principal);
276                 name_token.length = strlen(principal);
277
278                 name_type = GSS_C_NULL_OID;
279         } else {
280                 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s", 
281                                             gensec_get_target_service(gensec_security), 
282                                             hostname);
283
284                 name_token.value  = discard_const_p(uint8_t, principal);
285                 name_token.length = strlen(principal);
286
287                 name_type = GSS_C_NT_HOSTBASED_SERVICE;
288         }               
289
290         maj_stat = gss_import_name (&min_stat,
291                                     &name_token,
292                                     name_type,
293                                     &gensec_gssapi_state->server_name);
294         if (maj_stat) {
295                 DEBUG(2, ("GSS Import name of %s failed: %s\n",
296                           (char *)name_token.value,
297                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
298                 return NT_STATUS_INVALID_PARAMETER;
299         }
300
301         ret = cli_credentials_get_client_gss_creds(creds, &gcc);
302         switch (ret) {
303         case 0:
304                 break;
305         case KRB5_KDC_UNREACH:
306                 DEBUG(3, ("Cannot reach a KDC we require\n"));
307                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
308         default:
309                 DEBUG(1, ("Aquiring initiator credentails failed\n"));
310                 return NT_STATUS_UNSUCCESSFUL;
311         }
312
313         gensec_gssapi_state->client_cred = gcc;
314
315         return NT_STATUS_OK;
316 }
317
318
319 /**
320  * Check if the packet is one for this mechansim
321  * 
322  * @param gensec_security GENSEC state
323  * @param in The request, as a DATA_BLOB
324  * @return Error, INVALID_PARAMETER if it's not a packet for us
325  *                or NT_STATUS_OK if the packet is ok. 
326  */
327
328 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, 
329                                     const DATA_BLOB *in) 
330 {
331         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
332                 return NT_STATUS_OK;
333         } else {
334                 return NT_STATUS_INVALID_PARAMETER;
335         }
336 }
337
338
339 /**
340  * Next state function for the GSSAPI GENSEC mechanism
341  * 
342  * @param gensec_gssapi_state GSSAPI State
343  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
344  * @param in The request, as a DATA_BLOB
345  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
346  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
347  *                or NT_STATUS_OK if the user is authenticated. 
348  */
349
350 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
351                                    TALLOC_CTX *out_mem_ctx, 
352                                    const DATA_BLOB in, DATA_BLOB *out) 
353 {
354         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
355         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
356         OM_uint32 maj_stat, min_stat;
357         OM_uint32 min_stat2;
358         gss_buffer_desc input_token, output_token;
359         gss_OID gss_oid_p;
360         input_token.length = in.length;
361         input_token.value = in.data;
362
363         switch (gensec_security->gensec_role) {
364         case GENSEC_CLIENT:
365         {
366                 maj_stat = gss_init_sec_context(&min_stat, 
367                                                 gensec_gssapi_state->client_cred->creds,
368                                                 &gensec_gssapi_state->gssapi_context, 
369                                                 gensec_gssapi_state->server_name, 
370                                                 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
371                                                 gensec_gssapi_state->want_flags, 
372                                                 0, 
373                                                 gensec_gssapi_state->input_chan_bindings,
374                                                 &input_token, 
375                                                 NULL, 
376                                                 &output_token, 
377                                                 &gensec_gssapi_state->got_flags, /* ret flags */
378                                                 NULL);
379                 break;
380         }
381         case GENSEC_SERVER:
382         {
383                 maj_stat = gss_accept_sec_context(&min_stat, 
384                                                   &gensec_gssapi_state->gssapi_context, 
385                                                   gensec_gssapi_state->cred,
386                                                   &input_token, 
387                                                   gensec_gssapi_state->input_chan_bindings,
388                                                   &gensec_gssapi_state->client_name, 
389                                                   &gss_oid_p,
390                                                   &output_token, 
391                                                   &gensec_gssapi_state->got_flags, 
392                                                   NULL, 
393                                                   &gensec_gssapi_state->delegated_cred_handle);
394                 gensec_gssapi_state->gss_oid = gss_oid_p;
395                 break;
396         }
397         default:
398                 return NT_STATUS_INVALID_PARAMETER;
399                 
400         }
401
402         if (maj_stat == GSS_S_COMPLETE) {
403                 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
404                 gss_release_buffer(&min_stat2, &output_token);
405
406                 if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
407                         DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
408                 } else {
409                         DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
410                 }
411
412                 return NT_STATUS_OK;
413         } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
414                 *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
415                 gss_release_buffer(&min_stat2, &output_token);
416
417                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
418         } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
419             && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
420                        gensec_gssapi_state->gss_oid->length) == 0)) {
421                 switch (min_stat) {
422                 case KRB5_KDC_UNREACH:
423                         DEBUG(3, ("Cannot reach a KDC we require: %s\n",
424                                   gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
425                         return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
426                 case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
427                         DEBUG(3, ("Server is not registered with our KDC: %s\n", 
428                                   gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
429                         return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
430                 case KRB5KRB_AP_ERR_MSG_TYPE:
431                         /* garbage input, possibly from the auto-mech detection */
432                         return NT_STATUS_INVALID_PARAMETER;
433                 default:
434                         DEBUG(1, ("GSS(krb5) Update failed: %s\n", 
435                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
436                         return nt_status;
437                 }
438         } else {
439                 DEBUG(1, ("GSS Update failed: %s\n", 
440                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
441                 return nt_status;
442         }
443 }
444
445 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
446                                    TALLOC_CTX *mem_ctx, 
447                                    const DATA_BLOB *in, 
448                                    DATA_BLOB *out)
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         input_token.length = in->length;
455         input_token.value = in->data;
456         
457         maj_stat = gss_wrap(&min_stat, 
458                             gensec_gssapi_state->gssapi_context, 
459                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
460                             GSS_C_QOP_DEFAULT,
461                             &input_token,
462                             &conf_state,
463                             &output_token);
464         if (GSS_ERROR(maj_stat)) {
465                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
466                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
467                 return NT_STATUS_ACCESS_DENIED;
468         }
469
470         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
471         gss_release_buffer(&min_stat, &output_token);
472
473         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
474             && !conf_state) {
475                 return NT_STATUS_ACCESS_DENIED;
476         }
477         return NT_STATUS_OK;
478 }
479
480 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
481                                      TALLOC_CTX *mem_ctx, 
482                                      const DATA_BLOB *in, 
483                                      DATA_BLOB *out)
484 {
485         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
486         OM_uint32 maj_stat, min_stat;
487         gss_buffer_desc input_token, output_token;
488         int conf_state;
489         gss_qop_t qop_state;
490         input_token.length = in->length;
491         input_token.value = in->data;
492         
493         maj_stat = gss_unwrap(&min_stat, 
494                               gensec_gssapi_state->gssapi_context, 
495                               &input_token,
496                               &output_token, 
497                               &conf_state,
498                               &qop_state);
499         if (GSS_ERROR(maj_stat)) {
500                 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", 
501                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
502                 return NT_STATUS_ACCESS_DENIED;
503         }
504
505         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
506         gss_release_buffer(&min_stat, &output_token);
507         
508         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
509             && !conf_state) {
510                 return NT_STATUS_ACCESS_DENIED;
511         }
512         return NT_STATUS_OK;
513 }
514
515 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size) 
516 {
517         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
518         OM_uint32 maj_stat, min_stat;
519         OM_uint32 output_size;
520         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
521             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
522                        gensec_gssapi_state->gss_oid->length) != 0)) {
523                 DEBUG(1, ("NO sig size available for this mech\n"));
524                 return 0;
525         }
526                 
527         maj_stat = gsskrb5_wrap_size(&min_stat, 
528                                      gensec_gssapi_state->gssapi_context,
529                                      gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
530                                      GSS_C_QOP_DEFAULT,
531                                      data_size, 
532                                      &output_size);
533         if (GSS_ERROR(maj_stat)) {
534                 TALLOC_CTX *mem_ctx = talloc_new(NULL); 
535                 DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
536                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
537                 talloc_free(mem_ctx);
538                 return 0;
539         }
540
541         if (output_size < data_size) {
542                 return 0;
543         }
544
545         /* The difference between the max output and the max input must be the signature */
546         return output_size - data_size;
547 }
548
549 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
550                                           TALLOC_CTX *mem_ctx, 
551                                           uint8_t *data, size_t length, 
552                                           const uint8_t *whole_pdu, size_t pdu_length, 
553                                           DATA_BLOB *sig)
554 {
555         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
556         OM_uint32 maj_stat, min_stat;
557         gss_buffer_desc input_token, output_token;
558         int conf_state;
559         ssize_t sig_length;
560
561         input_token.length = length;
562         input_token.value = data;
563         
564         maj_stat = gss_wrap(&min_stat, 
565                             gensec_gssapi_state->gssapi_context,
566                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
567                             GSS_C_QOP_DEFAULT,
568                             &input_token,
569                             &conf_state,
570                             &output_token);
571         if (GSS_ERROR(maj_stat)) {
572                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", 
573                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
574                 return NT_STATUS_ACCESS_DENIED;
575         }
576
577         sig_length = gensec_gssapi_sig_size(gensec_security, length);
578
579         /* Caller must pad to right boundary */
580         if (output_token.length != (length + sig_length)) {
581                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n", 
582                           output_token.length, length, sig_length, length + sig_length));
583                 return NT_STATUS_INTERNAL_ERROR;
584         }
585
586         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
587         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
588
589         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
590         dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
591         dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
592
593         gss_release_buffer(&min_stat, &output_token);
594
595         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
596             && !conf_state) {
597                 return NT_STATUS_ACCESS_DENIED;
598         }
599         return NT_STATUS_OK;
600 }
601
602 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
603                                             TALLOC_CTX *mem_ctx, 
604                                             uint8_t *data, size_t length, 
605                                             const uint8_t *whole_pdu, size_t pdu_length,
606                                             const DATA_BLOB *sig)
607 {
608         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
609         OM_uint32 maj_stat, min_stat;
610         gss_buffer_desc input_token, output_token;
611         int conf_state;
612         gss_qop_t qop_state;
613         DATA_BLOB in;
614
615         dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
616
617         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
618
619         memcpy(in.data, sig->data, sig->length);
620         memcpy(in.data + sig->length, data, length);
621
622         input_token.length = in.length;
623         input_token.value = in.data;
624         
625         maj_stat = gss_unwrap(&min_stat, 
626                               gensec_gssapi_state->gssapi_context, 
627                               &input_token,
628                               &output_token, 
629                               &conf_state,
630                               &qop_state);
631         if (GSS_ERROR(maj_stat)) {
632                 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
633                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
634                 return NT_STATUS_ACCESS_DENIED;
635         }
636
637         if (output_token.length != length) {
638                 return NT_STATUS_INTERNAL_ERROR;
639         }
640
641         memcpy(data, output_token.value, length);
642
643         gss_release_buffer(&min_stat, &output_token);
644         
645         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
646             && !conf_state) {
647                 return NT_STATUS_ACCESS_DENIED;
648         }
649         return NT_STATUS_OK;
650 }
651
652 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
653                                           TALLOC_CTX *mem_ctx, 
654                                           const uint8_t *data, size_t length, 
655                                           const uint8_t *whole_pdu, size_t pdu_length, 
656                                           DATA_BLOB *sig)
657 {
658         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
659         OM_uint32 maj_stat, min_stat;
660         gss_buffer_desc input_token, output_token;
661         int conf_state;
662         ssize_t sig_length = 0;
663
664         input_token.length = length;
665         input_token.value = discard_const_p(uint8_t *, data);
666
667         maj_stat = gss_wrap(&min_stat, 
668                             gensec_gssapi_state->gssapi_context,
669                             0,
670                             GSS_C_QOP_DEFAULT,
671                             &input_token,
672                             &conf_state,
673                             &output_token);
674         if (GSS_ERROR(maj_stat)) {
675                 DEBUG(1, ("GSS Wrap failed: %s\n", 
676                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
677                 return NT_STATUS_ACCESS_DENIED;
678         }
679
680         if (output_token.length < length) {
681                 return NT_STATUS_INTERNAL_ERROR;
682         }
683
684         sig_length = gensec_gssapi_sig_size(gensec_security, length);
685
686         /* Caller must pad to right boundary */
687         if (output_token.length != (length + sig_length)) {
688                 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n", 
689                           output_token.length, length, sig_length, length + sig_length));
690                 return NT_STATUS_INTERNAL_ERROR;
691         }
692
693         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
694
695         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
696
697         gss_release_buffer(&min_stat, &output_token);
698
699         return NT_STATUS_OK;
700 }
701
702 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
703                                            TALLOC_CTX *mem_ctx, 
704                                            const uint8_t *data, size_t length, 
705                                            const uint8_t *whole_pdu, size_t pdu_length, 
706                                            const DATA_BLOB *sig)
707 {
708         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
709         OM_uint32 maj_stat, min_stat;
710         gss_buffer_desc input_token, output_token;
711         int conf_state;
712         gss_qop_t qop_state;
713         DATA_BLOB in;
714
715         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
716
717         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
718
719         memcpy(in.data, sig->data, sig->length);
720         memcpy(in.data + sig->length, data, length);
721
722         input_token.length = in.length;
723         input_token.value = in.data;
724         
725         maj_stat = gss_unwrap(&min_stat, 
726                               gensec_gssapi_state->gssapi_context, 
727                               &input_token,
728                               &output_token, 
729                               &conf_state,
730                               &qop_state);
731         if (GSS_ERROR(maj_stat)) {
732                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
733                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
734                 return NT_STATUS_ACCESS_DENIED;
735         }
736
737         if (output_token.length != length) {
738                 return NT_STATUS_INTERNAL_ERROR;
739         }
740
741         gss_release_buffer(&min_stat, &output_token);
742
743         return NT_STATUS_OK;
744 }
745
746 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
747                                        uint32_t feature) 
748 {
749         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
750         if (feature & GENSEC_FEATURE_SIGN) {
751                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
752         }
753         if (feature & GENSEC_FEATURE_SEAL) {
754                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
755         }
756         if (feature & GENSEC_FEATURE_SESSION_KEY) {
757                 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
758                     && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
759                         return True;
760                 }
761         }
762         if (feature & GENSEC_FEATURE_DCE_STYLE) {
763                 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
764         }
765         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
766                 return True;
767         }
768         return False;
769 }
770
771 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
772                                           DATA_BLOB *session_key) 
773 {
774         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
775         
776         if (gensec_gssapi_state->session_key.data) {
777                 *session_key = gensec_gssapi_state->session_key;
778                 return NT_STATUS_OK;
779         }
780
781         /* Ensure we only call this for GSSAPI/krb5, otherwise things could get very ugly */
782         if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
783             && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
784                        gensec_gssapi_state->gss_oid->length) == 0)) {
785                 OM_uint32 maj_stat, min_stat;
786                 gss_buffer_desc skey;
787                 
788                 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 
789                                                         gensec_gssapi_state->gssapi_context, 
790                                                         &skey);
791                 
792                 if (maj_stat == 0) {
793                         DEBUG(10, ("Got KRB5 session key of length %d\n",  
794                                    (int)skey.length));
795                         gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state, 
796                                                                             skey.value, skey.length);
797                         *session_key = gensec_gssapi_state->session_key;
798                         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
799                         
800                         gss_release_buffer(&min_stat, &skey);
801                         return NT_STATUS_OK;
802                 }
803                 return NT_STATUS_NO_USER_SESSION_KEY;
804         }
805         
806         DEBUG(1, ("NO session key for this mech\n"));
807         return NT_STATUS_NO_USER_SESSION_KEY;
808 }
809
810 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
811                                          struct auth_session_info **_session_info) 
812 {
813         NTSTATUS nt_status;
814         TALLOC_CTX *mem_ctx;
815         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
816         struct auth_serversupplied_info *server_info = NULL;
817         struct auth_session_info *session_info = NULL;
818         struct PAC_LOGON_INFO *logon_info;
819         OM_uint32 maj_stat, min_stat;
820         gss_buffer_desc name_token;
821         gss_buffer_desc pac;
822         krb5_keyblock *keyblock;
823         time_t authtime;
824         krb5_principal principal;
825         char *principal_string;
826         DATA_BLOB pac_blob;
827         
828         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
829             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
830                        gensec_gssapi_state->gss_oid->length) != 0)) {
831                 DEBUG(1, ("NO session info available for this mech\n"));
832                 return NT_STATUS_INVALID_PARAMETER;
833         }
834                 
835         mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context"); 
836         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
837
838         maj_stat = gss_display_name (&min_stat,
839                                      gensec_gssapi_state->client_name,
840                                      &name_token,
841                                      NULL);
842         if (maj_stat) {
843                 return NT_STATUS_FOOBAR;
844         }
845
846         principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
847
848         gss_release_buffer(&min_stat, &name_token);
849
850         if (!principal_string) {
851                 talloc_free(mem_ctx);
852                 return NT_STATUS_NO_MEMORY;
853         }
854
855         maj_stat = gss_krb5_copy_service_keyblock(&min_stat, 
856                                                   gensec_gssapi_state->gssapi_context, 
857                                                   &keyblock);
858
859         if (maj_stat == 0) {
860                 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
861                                                                      gensec_gssapi_state->gssapi_context, 
862                                                                      &authtime);
863         }
864
865         if (maj_stat == 0) {
866                 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 
867                                                                        gensec_gssapi_state->gssapi_context, 
868                                                                        KRB5_AUTHDATA_WIN2K_PAC,
869                                                                        &pac);
870         }
871
872         if (maj_stat == 0) {
873                 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
874                 gss_release_buffer(&min_stat, &pac);
875         }
876         
877         /* IF we have the PAC - otherwise we need to get this
878          * data from elsewere - local ldb, or (TODO) lookup of some
879          * kind... 
880          */
881         if (maj_stat == 0) {
882                 krb5_error_code ret;
883
884                 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
885                                       principal_string, &principal);
886                 if (ret) {
887                         talloc_free(mem_ctx);
888                         return NT_STATUS_INVALID_PARAMETER;
889                 }
890                 
891                 /* decode and verify the pac */
892                 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
893                                                     gensec_gssapi_state->smb_krb5_context->krb5_context,
894                                                     NULL, keyblock, principal, authtime);
895                 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
896
897                 if (NT_STATUS_IS_OK(nt_status)) {
898                         union netr_Validation validation;
899                         validation.sam3 = &logon_info->info3;
900                         nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, 
901                                                                          NULL,
902                                                                          3, &validation,
903                                                                          &server_info); 
904                         if (!NT_STATUS_IS_OK(nt_status)) {
905                                 talloc_free(mem_ctx);
906                                 return nt_status;
907                         }
908                 } else {
909                         maj_stat = 1;
910                 }
911         }
912         
913         if (maj_stat) {
914                 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
915                 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
916                                                           &server_info);
917
918                 if (!NT_STATUS_IS_OK(nt_status)) {
919                         talloc_free(mem_ctx);
920                         return nt_status;
921                 }
922         }
923
924         /* references the server_info into the session_info */
925         nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
926         talloc_free(mem_ctx);
927         talloc_free(server_info);
928         NT_STATUS_NOT_OK_RETURN(nt_status);
929
930         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
931         NT_STATUS_NOT_OK_RETURN(nt_status);
932
933         if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
934                 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
935         } else {
936                 krb5_error_code ret;
937                 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
938                 session_info->credentials = cli_credentials_init(session_info);
939                 if (!session_info->credentials) {
940                         return NT_STATUS_NO_MEMORY;
941                 }
942
943                 cli_credentials_set_conf(session_info->credentials);
944                 
945                 ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
946                                                            gensec_gssapi_state->delegated_cred_handle,
947                                                            CRED_SPECIFIED);
948                 if (ret) {
949                         return NT_STATUS_NO_MEMORY;
950                 }
951                 /* It has been taken from this place... */
952                 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
953         }
954         *_session_info = session_info;
955
956         return NT_STATUS_OK;
957 }
958
959 static const char *gensec_gssapi_krb5_oids[] = { 
960         GENSEC_OID_KERBEROS5,
961         GENSEC_OID_KERBEROS5_OLD,
962         NULL 
963 };
964
965 /* As a server, this could in theory accept any GSSAPI mech */
966 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
967         .name           = "gssapi_krb5",
968         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
969         .oid            = gensec_gssapi_krb5_oids,
970         .client_start   = gensec_gssapi_client_start,
971         .server_start   = gensec_gssapi_server_start,
972         .magic          = gensec_gssapi_magic,
973         .update         = gensec_gssapi_update,
974         .session_key    = gensec_gssapi_session_key,
975         .session_info   = gensec_gssapi_session_info,
976         .sig_size       = gensec_gssapi_sig_size,
977         .sign_packet    = gensec_gssapi_sign_packet,
978         .check_packet   = gensec_gssapi_check_packet,
979         .seal_packet    = gensec_gssapi_seal_packet,
980         .unseal_packet  = gensec_gssapi_unseal_packet,
981         .wrap           = gensec_gssapi_wrap,
982         .unwrap         = gensec_gssapi_unwrap,
983         .have_feature   = gensec_gssapi_have_feature,
984         .enabled        = True
985 };
986
987 NTSTATUS gensec_gssapi_init(void)
988 {
989         NTSTATUS ret;
990
991         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
992         if (!NT_STATUS_IS_OK(ret)) {
993                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
994                         gensec_gssapi_krb5_security_ops.name));
995                 return ret;
996         }
997
998         return ret;
999 }