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