r18257: Order the GENSEC modules, with unknown modules last.
[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 "auth/kerberos/kerberos.h"
28 #include "librpc/gen_ndr/krb5pac.h"
29 #include "auth/auth.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "auth/auth_sam.h"
32 #include "librpc/rpc/dcerpc.h"
33
34 enum gensec_gssapi_sasl_state 
35 {
36         STAGE_GSS_NEG,
37         STAGE_SASL_SSF_NEG,
38         STAGE_SASL_SSF_ACCEPT,
39         STAGE_DONE
40 };
41
42 #define NEG_SEAL 0x4
43 #define NEG_SIGN 0x2
44 #define NEG_NONE 0x1
45
46 struct gensec_gssapi_state {
47         gss_ctx_id_t gssapi_context;
48         struct gss_channel_bindings_struct *input_chan_bindings;
49         gss_name_t server_name;
50         gss_name_t client_name;
51         OM_uint32 want_flags, got_flags;
52         const gss_OID_desc *gss_oid;
53
54         DATA_BLOB session_key;
55         DATA_BLOB pac;
56
57         struct smb_krb5_context *smb_krb5_context;
58         struct gssapi_creds_container *client_cred;
59         struct gssapi_creds_container *server_cred;
60
61         gss_cred_id_t delegated_cred_handle;
62
63         BOOL sasl; /* We have two different mechs in this file: One
64                     * for SASL wrapped GSSAPI and another for normal
65                     * GSSAPI */
66         enum gensec_gssapi_sasl_state sasl_state;
67         uint8_t sasl_protection; /* What was negotiated at the SASL
68                                   * layer, independent of the GSSAPI
69                                   * layer... */
70
71         size_t max_wrap_buf_size;
72 };
73
74 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
75 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
76
77 static char *gssapi_error_string(TALLOC_CTX *mem_ctx, 
78                                  OM_uint32 maj_stat, OM_uint32 min_stat)
79 {
80         OM_uint32 disp_min_stat, disp_maj_stat;
81         gss_buffer_desc maj_error_message;
82         gss_buffer_desc min_error_message;
83         OM_uint32 msg_ctx = 0;
84
85         char *ret;
86
87         maj_error_message.value = NULL;
88         min_error_message.value = NULL;
89         
90         disp_maj_stat = gss_display_status(&disp_min_stat, maj_stat, GSS_C_GSS_CODE,
91                            GSS_C_NULL_OID, &msg_ctx, &maj_error_message);
92         disp_maj_stat = gss_display_status(&disp_min_stat, min_stat, GSS_C_MECH_CODE,
93                            GSS_C_NULL_OID, &msg_ctx, &min_error_message);
94         ret = talloc_asprintf(mem_ctx, "%s: %s", (char *)maj_error_message.value, (char *)min_error_message.value);
95
96         gss_release_buffer(&disp_min_stat, &maj_error_message);
97         gss_release_buffer(&disp_min_stat, &min_error_message);
98
99         return ret;
100 }
101
102
103 static int gensec_gssapi_destory(struct gensec_gssapi_state *gensec_gssapi_state)
104 {
105         OM_uint32 maj_stat, min_stat;
106         
107         if (gensec_gssapi_state->delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
108                 maj_stat = gss_release_cred(&min_stat, 
109                                             &gensec_gssapi_state->delegated_cred_handle);
110         }
111
112         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
113                 maj_stat = gss_delete_sec_context (&min_stat,
114                                                    &gensec_gssapi_state->gssapi_context,
115                                                    GSS_C_NO_BUFFER);
116         }
117
118         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
119                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
120         }
121         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
122                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
123         }
124         return 0;
125 }
126
127 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
128 {
129         struct gensec_gssapi_state *gensec_gssapi_state;
130         krb5_error_code ret;
131         
132         gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
133         if (!gensec_gssapi_state) {
134                 return NT_STATUS_NO_MEMORY;
135         }
136         
137         gensec_gssapi_state->max_wrap_buf_size
138                 = lp_parm_int(-1, "gensec_gssapi", "max wrap buf size", 65536);
139                 
140         gensec_gssapi_state->sasl = False;
141         gensec_gssapi_state->sasl_state = STAGE_GSS_NEG;
142
143         gensec_security->private_data = gensec_gssapi_state;
144
145         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
146         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
147         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
148
149         /* TODO: Fill in channel bindings */
150         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
151         
152         gensec_gssapi_state->want_flags = 0;
153         if (lp_parm_bool(-1, "gensec_gssapi", "mutual", True)) {
154                 gensec_gssapi_state->want_flags |= GSS_C_MUTUAL_FLAG;
155         }
156         if (lp_parm_bool(-1, "gensec_gssapi", "delegation", True)) {
157                 gensec_gssapi_state->want_flags |= GSS_C_DELEG_FLAG;
158         }
159         if (lp_parm_bool(-1, "gensec_gssapi", "sequence", True)) {
160                 gensec_gssapi_state->want_flags |= GSS_C_SEQUENCE_FLAG;
161         }
162
163         gensec_gssapi_state->got_flags = 0;
164
165         gensec_gssapi_state->session_key = data_blob(NULL, 0);
166         gensec_gssapi_state->pac = data_blob(NULL, 0);
167
168         gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
169
170         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
171
172         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
173                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
174         }
175         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
176                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
177         }
178         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
179                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
180         }
181
182         gensec_gssapi_state->gss_oid = gss_mech_krb5;
183         
184         ret = smb_krb5_init_context(gensec_gssapi_state, 
185                                     &gensec_gssapi_state->smb_krb5_context);
186         if (ret) {
187                 DEBUG(1,("gensec_krb5_start: krb5_init_context failed (%s)\n",                                  
188                          error_message(ret)));
189                 return NT_STATUS_INTERNAL_ERROR;
190         }
191         return NT_STATUS_OK;
192 }
193
194 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
195 {
196         NTSTATUS nt_status;
197         int ret;
198         struct gensec_gssapi_state *gensec_gssapi_state;
199         struct cli_credentials *machine_account;
200         struct gssapi_creds_container *gcc;
201
202         nt_status = gensec_gssapi_start(gensec_security);
203         if (!NT_STATUS_IS_OK(nt_status)) {
204                 return nt_status;
205         }
206
207         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
208
209         machine_account = gensec_get_credentials(gensec_security);
210         
211         if (!machine_account) {
212                 DEBUG(3, ("No machine account credentials specified\n"));
213                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
214         } else {
215                 ret = cli_credentials_get_server_gss_creds(machine_account, &gcc);
216                 if (ret) {
217                         DEBUG(1, ("Aquiring acceptor credentials failed: %s\n", 
218                                   error_message(ret)));
219                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
220                 }
221         }
222
223         gensec_gssapi_state->server_cred = gcc;
224         return NT_STATUS_OK;
225
226 }
227
228 static NTSTATUS gensec_gssapi_sasl_server_start(struct gensec_security *gensec_security)
229 {
230         NTSTATUS nt_status;
231         struct gensec_gssapi_state *gensec_gssapi_state;
232         nt_status = gensec_gssapi_server_start(gensec_security);
233
234         if (NT_STATUS_IS_OK(nt_status)) {
235                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
236                 gensec_gssapi_state->sasl = True;
237         }
238         return nt_status;
239 }
240
241 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
242 {
243         struct gensec_gssapi_state *gensec_gssapi_state;
244         struct cli_credentials *creds = gensec_get_credentials(gensec_security);
245         krb5_error_code ret;
246         NTSTATUS nt_status;
247         gss_buffer_desc name_token;
248         gss_OID name_type;
249         OM_uint32 maj_stat, min_stat;
250         const char *hostname = gensec_get_target_hostname(gensec_security);
251         const char *principal;
252         struct gssapi_creds_container *gcc;
253
254         if (!hostname) {
255                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
256                 return NT_STATUS_INVALID_PARAMETER;
257         }
258         if (is_ipaddress(hostname)) {
259                 DEBUG(2, ("Cannot do GSSAPI to an IP address\n"));
260                 return NT_STATUS_INVALID_PARAMETER;
261         }
262         if (strcmp(hostname, "localhost") == 0) {
263                 DEBUG(2, ("GSSAPI to 'localhost' does not make sense\n"));
264                 return NT_STATUS_INVALID_PARAMETER;
265         }
266
267         if (((gensec_security->want_features & GENSEC_FEATURE_SIGN)
268              || (gensec_security->want_features & GENSEC_FEATURE_SEAL))
269             && (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE)
270             && !lp_parm_bool(-1, "gensec_gssapi", "dce_signseal", 
271                              cli_credentials_get_kerberos_state(creds) == CRED_MUST_USE_KERBEROS)) {
272                 DEBUG(2, ("GSSAPI sign/seal disabled for DCE/RPC. "));
273                 return NT_STATUS_INVALID_PARAMETER;
274         }
275
276         nt_status = gensec_gssapi_start(gensec_security);
277         if (!NT_STATUS_IS_OK(nt_status)) {
278                 return nt_status;
279         }
280
281         gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
282
283         principal = gensec_get_target_principal(gensec_security);
284         if (principal && lp_client_use_spnego_principal()) {
285                 name_token.value  = discard_const_p(uint8_t, principal);
286                 name_token.length = strlen(principal);
287
288                 name_type = GSS_C_NULL_OID;
289         } else {
290                 principal = talloc_asprintf(gensec_gssapi_state, "%s@%s", 
291                                             gensec_get_target_service(gensec_security), 
292                                             hostname);
293
294                 name_token.value  = discard_const_p(uint8_t, principal);
295                 name_token.length = strlen(principal);
296
297                 name_type = GSS_C_NT_HOSTBASED_SERVICE;
298         }               
299
300         maj_stat = gss_import_name (&min_stat,
301                                     &name_token,
302                                     name_type,
303                                     &gensec_gssapi_state->server_name);
304         if (maj_stat) {
305                 DEBUG(2, ("GSS Import name of %s failed: %s\n",
306                           (char *)name_token.value,
307                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
308                 return NT_STATUS_INVALID_PARAMETER;
309         }
310
311         ret = cli_credentials_get_client_gss_creds(creds, &gcc);
312         switch (ret) {
313         case 0:
314                 break;
315         case KRB5_KDC_UNREACH:
316                 DEBUG(3, ("Cannot reach a KDC we require\n"));
317                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
318         default:
319                 DEBUG(1, ("Aquiring initiator credentails failed\n"));
320                 return NT_STATUS_UNSUCCESSFUL;
321         }
322
323         gensec_gssapi_state->client_cred = gcc;
324
325         return NT_STATUS_OK;
326 }
327
328 static NTSTATUS gensec_gssapi_sasl_client_start(struct gensec_security *gensec_security)
329 {
330         NTSTATUS nt_status;
331         struct gensec_gssapi_state *gensec_gssapi_state;
332         nt_status = gensec_gssapi_client_start(gensec_security);
333
334         if (NT_STATUS_IS_OK(nt_status)) {
335                 gensec_gssapi_state = talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
336                 gensec_gssapi_state->sasl = True;
337         }
338         return nt_status;
339 }
340
341
342 /**
343  * Check if the packet is one for this mechansim
344  * 
345  * @param gensec_security GENSEC state
346  * @param in The request, as a DATA_BLOB
347  * @return Error, INVALID_PARAMETER if it's not a packet for us
348  *                or NT_STATUS_OK if the packet is ok. 
349  */
350
351 static NTSTATUS gensec_gssapi_magic(struct gensec_security *gensec_security, 
352                                     const DATA_BLOB *in) 
353 {
354         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
355                 return NT_STATUS_OK;
356         } else {
357                 return NT_STATUS_INVALID_PARAMETER;
358         }
359 }
360
361
362 /**
363  * Next state function for the GSSAPI GENSEC mechanism
364  * 
365  * @param gensec_gssapi_state GSSAPI State
366  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
367  * @param in The request, as a DATA_BLOB
368  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
369  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
370  *                or NT_STATUS_OK if the user is authenticated. 
371  */
372
373 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
374                                    TALLOC_CTX *out_mem_ctx, 
375                                    const DATA_BLOB in, DATA_BLOB *out) 
376 {
377         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
378         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
379         OM_uint32 maj_stat, min_stat;
380         OM_uint32 min_stat2;
381         gss_buffer_desc input_token, output_token;
382         gss_OID gss_oid_p;
383         input_token.length = in.length;
384         input_token.value = in.data;
385
386         switch (gensec_gssapi_state->sasl_state) {
387         case STAGE_GSS_NEG:
388         {
389                 switch (gensec_security->gensec_role) {
390                 case GENSEC_CLIENT:
391                 {
392                         maj_stat = gss_init_sec_context(&min_stat, 
393                                                         gensec_gssapi_state->client_cred->creds,
394                                                         &gensec_gssapi_state->gssapi_context, 
395                                                         gensec_gssapi_state->server_name, 
396                                                         discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
397                                                         gensec_gssapi_state->want_flags, 
398                                                         0, 
399                                                         gensec_gssapi_state->input_chan_bindings,
400                                                         &input_token, 
401                                                         NULL, 
402                                                         &output_token, 
403                                                         &gensec_gssapi_state->got_flags, /* ret flags */
404                                                         NULL);
405                         break;
406                 }
407                 case GENSEC_SERVER:
408                 {
409                         maj_stat = gss_accept_sec_context(&min_stat, 
410                                                           &gensec_gssapi_state->gssapi_context, 
411                                                           gensec_gssapi_state->server_cred->creds,
412                                                           &input_token, 
413                                                           gensec_gssapi_state->input_chan_bindings,
414                                                           &gensec_gssapi_state->client_name, 
415                                                           &gss_oid_p,
416                                                           &output_token, 
417                                                           &gensec_gssapi_state->got_flags, 
418                                                           NULL, 
419                                                           &gensec_gssapi_state->delegated_cred_handle);
420                         gensec_gssapi_state->gss_oid = gss_oid_p;
421                         break;
422                 }
423                 default:
424                         return NT_STATUS_INVALID_PARAMETER;
425                         
426                 }
427
428                 if (maj_stat == GSS_S_COMPLETE) {
429                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
430                         gss_release_buffer(&min_stat2, &output_token);
431                         
432                         if (gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG) {
433                                 DEBUG(5, ("gensec_gssapi: credentials were delegated\n"));
434                         } else {
435                                 DEBUG(5, ("gensec_gssapi: NO credentials were delegated\n"));
436                         }
437
438                         /* We may have been invoked as SASL, so there
439                          * is more work to do */
440                         if (gensec_gssapi_state->sasl) {
441                                 /* Due to a very subtle interaction
442                                  * with SASL and the LDAP libs, we
443                                  * must ensure the data pointer is 
444                                  * != NULL, but the length is 0.  
445                                  *
446                                  * This ensures we send a 'zero
447                                  * length' (rather than NULL) response 
448                                  */
449                                 
450                                 if (!out->data) {
451                                         out->data = (uint8_t *)talloc_strdup(out_mem_ctx, "\0");
452                                 }
453
454                                 gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_NEG;
455                                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
456                         } else {
457                                 gensec_gssapi_state->sasl_state = STAGE_DONE;
458
459                                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
460                                         DEBUG(5, ("GSSAPI Connection will be cryptographicly sealed\n"));
461                                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
462                                         DEBUG(5, ("GSSAPI Connection will be cryptographicly signed\n"));
463                                 } else {
464                                         DEBUG(5, ("GSSAPI Connection will have no cryptographic protection\n"));
465                                 }
466
467                                 return NT_STATUS_OK;
468                         }
469                 } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
470                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
471                         gss_release_buffer(&min_stat2, &output_token);
472                         
473                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
474                 } else if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
475                            && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
476                                       gensec_gssapi_state->gss_oid->length) == 0)) {
477                         switch (min_stat) {
478                         case KRB5_KDC_UNREACH:
479                                 DEBUG(3, ("Cannot reach a KDC we require: %s\n",
480                                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
481                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
482                         case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
483                                 DEBUG(3, ("Server is not registered with our KDC: %s\n", 
484                                           gssapi_error_string(gensec_gssapi_state, maj_stat, min_stat)));
485                                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
486                         case KRB5KRB_AP_ERR_MSG_TYPE:
487                                 /* garbage input, possibly from the auto-mech detection */
488                                 return NT_STATUS_INVALID_PARAMETER;
489                         default:
490                                 DEBUG(1, ("GSS(krb5) Update failed: %s\n", 
491                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
492                                 return nt_status;
493                         }
494                 } else {
495                         DEBUG(1, ("GSS Update failed: %s\n", 
496                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
497                         return nt_status;
498                 }
499                 break;
500         }
501
502         /* These last two stages are only done if we were invoked as SASL */
503         case STAGE_SASL_SSF_NEG:
504         {
505                 switch (gensec_security->gensec_role) {
506                 case GENSEC_CLIENT:
507                 {
508                         uint8_t maxlength_proposed[4]; 
509                         uint8_t maxlength_accepted[4]; 
510                         uint8_t security_supported;
511                         int conf_state;
512                         gss_qop_t qop_state;
513                         input_token.length = in.length;
514                         input_token.value = in.data;
515
516                         /* As a client, we have just send a
517                          * zero-length blob to the server (after the
518                          * normal GSSAPI exchange), and it has replied
519                          * with it's SASL negotiation */
520                         
521                         maj_stat = gss_unwrap(&min_stat, 
522                                               gensec_gssapi_state->gssapi_context, 
523                                               &input_token,
524                                               &output_token, 
525                                               &conf_state,
526                                               &qop_state);
527                         if (GSS_ERROR(maj_stat)) {
528                                 DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
529                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
530                                 return NT_STATUS_ACCESS_DENIED;
531                         }
532                         
533                         if (output_token.length < 4) {
534                                 return NT_STATUS_INVALID_PARAMETER;
535                         }
536
537                         memcpy(maxlength_proposed, output_token.value, 4);
538                         gss_release_buffer(&min_stat, &output_token);
539
540                         /* first byte is the proposed security */
541                         security_supported = maxlength_proposed[0];
542                         maxlength_proposed[0] = '\0';
543                         
544                         /* Rest is the proposed max wrap length */
545                         gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_proposed, 0), 
546                                                                      gensec_gssapi_state->max_wrap_buf_size);
547                         gensec_gssapi_state->sasl_protection = 0;
548                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
549                                 if (security_supported & NEG_SEAL) {
550                                         gensec_gssapi_state->sasl_protection |= NEG_SEAL;
551                                 }
552                         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
553                                 if (security_supported & NEG_SIGN) {
554                                         gensec_gssapi_state->sasl_protection |= NEG_SIGN;
555                                 }
556                         } else if (security_supported & NEG_NONE) {
557                                 gensec_gssapi_state->sasl_protection |= NEG_NONE;
558                         } else {
559                                 DEBUG(1, ("Remote server does not support unprotected connections"));
560                                 return NT_STATUS_ACCESS_DENIED;
561                         }
562
563                         /* Send back the negotiated max length */
564
565                         RSIVAL(maxlength_accepted, 0, gensec_gssapi_state->max_wrap_buf_size);
566
567                         maxlength_accepted[0] = gensec_gssapi_state->sasl_protection;
568                         
569                         input_token.value = maxlength_accepted;
570                         input_token.length = sizeof(maxlength_accepted);
571
572                         maj_stat = gss_wrap(&min_stat, 
573                                             gensec_gssapi_state->gssapi_context, 
574                                             False,
575                                             GSS_C_QOP_DEFAULT,
576                                             &input_token,
577                                             &conf_state,
578                                             &output_token);
579                         if (GSS_ERROR(maj_stat)) {
580                                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
581                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
582                                 return NT_STATUS_ACCESS_DENIED;
583                         }
584                         
585                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
586                         gss_release_buffer(&min_stat, &output_token);
587
588                         /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
589                         gensec_gssapi_state->sasl_state = STAGE_DONE;
590
591                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
592                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly sealed\n"));
593                         } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
594                                 DEBUG(3, ("SASL/GSSAPI Connection to server will be cryptographicly signed\n"));
595                         } else {
596                                 DEBUG(3, ("SASL/GSSAPI Connection to server will have no cryptographicly protection\n"));
597                         }
598
599                         return NT_STATUS_OK;
600                 }
601                 case GENSEC_SERVER:
602                 {
603                         uint8_t maxlength_proposed[4]; 
604                         uint8_t security_supported = 0x0;
605                         int conf_state;
606
607                         /* As a server, we have just been sent a zero-length blob (note this, but it isn't fatal) */
608                         if (in.length != 0) {
609                                 DEBUG(1, ("SASL/GSSAPI: client sent non-zero length starting SASL negotiation!\n"));
610                         }
611                         
612                         /* Give the client some idea what we will support */
613                           
614                         RSIVAL(maxlength_proposed, 0, gensec_gssapi_state->max_wrap_buf_size);
615                         /* first byte is the proposed security */
616                         maxlength_proposed[0] = '\0';
617                         
618                         gensec_gssapi_state->sasl_protection = 0;
619                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
620                                 security_supported |= NEG_SEAL;
621                         } 
622                         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
623                                 security_supported |= NEG_SIGN;
624                         }
625                         if (security_supported == 0) {
626                                 /* If we don't support anything, this must be 0 */
627                                 RSIVAL(maxlength_proposed, 0, 0x0);
628                         }
629
630                         /* TODO:  We may not wish to support this */
631                         security_supported |= NEG_NONE;
632                         maxlength_proposed[0] = security_supported;
633                         
634                         input_token.value = maxlength_proposed;
635                         input_token.length = sizeof(maxlength_proposed);
636
637                         maj_stat = gss_wrap(&min_stat, 
638                                             gensec_gssapi_state->gssapi_context, 
639                                             False,
640                                             GSS_C_QOP_DEFAULT,
641                                             &input_token,
642                                             &conf_state,
643                                             &output_token);
644                         if (GSS_ERROR(maj_stat)) {
645                                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
646                                           gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
647                                 return NT_STATUS_ACCESS_DENIED;
648                         }
649                         
650                         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
651                         gss_release_buffer(&min_stat, &output_token);
652
653                         gensec_gssapi_state->sasl_state = STAGE_SASL_SSF_ACCEPT;
654                         return NT_STATUS_MORE_PROCESSING_REQUIRED;
655                 }
656                 default:
657                         return NT_STATUS_INVALID_PARAMETER;
658                         
659                 }
660         }
661         /* This is s server-only stage */
662         case STAGE_SASL_SSF_ACCEPT:
663         {
664                 uint8_t maxlength_accepted[4]; 
665                 uint8_t security_accepted;
666                 int conf_state;
667                 gss_qop_t qop_state;
668                 input_token.length = in.length;
669                 input_token.value = in.data;
670                         
671                 maj_stat = gss_unwrap(&min_stat, 
672                                       gensec_gssapi_state->gssapi_context, 
673                                       &input_token,
674                                       &output_token, 
675                                       &conf_state,
676                                       &qop_state);
677                 if (GSS_ERROR(maj_stat)) {
678                         DEBUG(1, ("gensec_gssapi_update: GSS UnWrap of SASL protection negotiation failed: %s\n", 
679                                   gssapi_error_string(out_mem_ctx, maj_stat, min_stat)));
680                         return NT_STATUS_ACCESS_DENIED;
681                 }
682                         
683                 if (output_token.length < 4) {
684                         return NT_STATUS_INVALID_PARAMETER;
685                 }
686
687                 memcpy(maxlength_accepted, output_token.value, 4);
688                 gss_release_buffer(&min_stat, &output_token);
689                 
690                 /* first byte is the proposed security */
691                 security_accepted = maxlength_accepted[0];
692                 maxlength_accepted[0] = '\0';
693                 
694                 /* Rest is the proposed max wrap length */
695                 gensec_gssapi_state->max_wrap_buf_size = MIN(RIVAL(maxlength_accepted, 0), 
696                                                              gensec_gssapi_state->max_wrap_buf_size);
697
698                 gensec_gssapi_state->sasl_protection = 0;
699                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
700                         if (security_accepted & NEG_SEAL) {
701                                 gensec_gssapi_state->sasl_protection |= NEG_SEAL;
702                         }
703                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
704                         if (security_accepted & NEG_SIGN) {
705                                 gensec_gssapi_state->sasl_protection |= NEG_SIGN;
706                         }
707                 } else if (security_accepted & NEG_NONE) {
708                         gensec_gssapi_state->sasl_protection |= NEG_NONE;
709                 } else {
710                         DEBUG(1, ("Remote client does not support unprotected connections, but we failed to negotiate anything better"));
711                         return NT_STATUS_ACCESS_DENIED;
712                 }
713
714                 /* quirk:  This changes the value that gensec_have_feature returns, to be that after SASL negotiation */
715                 gensec_gssapi_state->sasl_state = STAGE_DONE;
716                 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
717                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly sealed\n"));
718                 } else if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
719                         DEBUG(5, ("SASL/GSSAPI Connection from client will be cryptographicly signed\n"));
720                 } else {
721                         DEBUG(5, ("SASL/GSSAPI Connection from client will have no cryptographic protection\n"));
722                 }
723
724                 *out = data_blob(NULL, 0);
725                 return NT_STATUS_OK;    
726         }
727         default:
728                 return NT_STATUS_INVALID_PARAMETER;
729         }
730 }
731
732 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
733                                    TALLOC_CTX *mem_ctx, 
734                                    const DATA_BLOB *in, 
735                                    DATA_BLOB *out)
736 {
737         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
738         OM_uint32 maj_stat, min_stat;
739         gss_buffer_desc input_token, output_token;
740         int conf_state;
741         input_token.length = in->length;
742         input_token.value = in->data;
743
744         maj_stat = gss_wrap(&min_stat, 
745                             gensec_gssapi_state->gssapi_context, 
746                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
747                             GSS_C_QOP_DEFAULT,
748                             &input_token,
749                             &conf_state,
750                             &output_token);
751         if (GSS_ERROR(maj_stat)) {
752                 DEBUG(1, ("gensec_gssapi_wrap: GSS Wrap failed: %s\n", 
753                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
754                 return NT_STATUS_ACCESS_DENIED;
755         }
756
757         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
758         gss_release_buffer(&min_stat, &output_token);
759
760         if (gensec_gssapi_state->sasl) {
761                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
762                 if (max_wrapped_size < out->length) {
763                         DEBUG(1, ("gensec_gssapi_wrap: when wrapped, INPUT data (%u) is grew to be larger than SASL negotiated maximum output size (%u > %u)\n",
764                                   in->length, 
765                                   out->length, 
766                                   (unsigned int)max_wrapped_size));
767                         return NT_STATUS_INVALID_PARAMETER;
768                 }
769         }
770         
771         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
772             && !conf_state) {
773                 return NT_STATUS_ACCESS_DENIED;
774         }
775         return NT_STATUS_OK;
776 }
777
778 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
779                                      TALLOC_CTX *mem_ctx, 
780                                      const DATA_BLOB *in, 
781                                      DATA_BLOB *out)
782 {
783         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
784         OM_uint32 maj_stat, min_stat;
785         gss_buffer_desc input_token, output_token;
786         int conf_state;
787         gss_qop_t qop_state;
788         input_token.length = in->length;
789         input_token.value = in->data;
790         
791         if (gensec_gssapi_state->sasl) {
792                 size_t max_wrapped_size = gensec_gssapi_max_wrapped_size(gensec_security);
793                 if (max_wrapped_size < in->length) {
794                         DEBUG(1, ("gensec_gssapi_unwrap: WRAPPED data is larger than SASL negotiated maximum size\n"));
795                         return NT_STATUS_INVALID_PARAMETER;
796                 }
797         }
798         
799         maj_stat = gss_unwrap(&min_stat, 
800                               gensec_gssapi_state->gssapi_context, 
801                               &input_token,
802                               &output_token, 
803                               &conf_state,
804                               &qop_state);
805         if (GSS_ERROR(maj_stat)) {
806                 DEBUG(1, ("gensec_gssapi_unwrap: GSS UnWrap failed: %s\n", 
807                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
808                 return NT_STATUS_ACCESS_DENIED;
809         }
810
811         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
812         gss_release_buffer(&min_stat, &output_token);
813         
814         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
815             && !conf_state) {
816                 return NT_STATUS_ACCESS_DENIED;
817         }
818         return NT_STATUS_OK;
819 }
820
821 /* Find out the size of the signature, assuming (incorrectly) that it
822  * GSSAPI provides any guarantees as to it's size.
823  *
824  * This is needed by the DCE/RPC code, which uses AEAD 
825  * (signed headers, including signature legnth and a sealed body)
826  */
827 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size) 
828 {
829         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
830         OM_uint32 maj_stat, min_stat;
831         OM_uint32 output_size;
832         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
833             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
834                        gensec_gssapi_state->gss_oid->length) != 0)) {
835                 DEBUG(1, ("NO sig size available for this mech\n"));
836                 return 0;
837         }
838                 
839         maj_stat = gsskrb5_wrap_size(&min_stat, 
840                                      gensec_gssapi_state->gssapi_context,
841                                      gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
842                                      GSS_C_QOP_DEFAULT,
843                                      data_size, 
844                                      &output_size);
845         if (GSS_ERROR(maj_stat)) {
846                 TALLOC_CTX *mem_ctx = talloc_new(NULL); 
847                 DEBUG(1, ("gensec_gssapi_sig_size: determinaing signature size with gsskrb5_wrap_size failed: %s\n", 
848                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
849                 talloc_free(mem_ctx);
850                 return 0;
851         }
852
853         if (output_size < data_size) {
854                 return 0;
855         }
856
857         /* The difference between the max output and the max input must be the signature */
858         return output_size - data_size;
859 }
860
861 /* Find out the maximum input size negotiated on this connection */
862
863 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security) 
864 {
865         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
866         OM_uint32 maj_stat, min_stat;
867         OM_uint32 max_input_size;
868
869         maj_stat = gss_wrap_size_limit(&min_stat, 
870                                        gensec_gssapi_state->gssapi_context,
871                                        gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
872                                        GSS_C_QOP_DEFAULT,
873                                        gensec_gssapi_state->max_wrap_buf_size,
874                                        &max_input_size);
875         if (GSS_ERROR(maj_stat)) {
876                 TALLOC_CTX *mem_ctx = talloc_new(NULL); 
877                 DEBUG(1, ("gensec_gssapi_max_input_size: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
878                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
879                 talloc_free(mem_ctx);
880                 return 0;
881         }
882
883         return max_input_size;
884 }
885
886 /* Find out the maximum output size negotiated on this connection */
887 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security) 
888 {
889         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
890         return gensec_gssapi_state->max_wrap_buf_size;
891 }
892
893 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
894                                           TALLOC_CTX *mem_ctx, 
895                                           uint8_t *data, size_t length, 
896                                           const uint8_t *whole_pdu, size_t pdu_length, 
897                                           DATA_BLOB *sig)
898 {
899         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
900         OM_uint32 maj_stat, min_stat;
901         gss_buffer_desc input_token, output_token;
902         int conf_state;
903         ssize_t sig_length;
904
905         input_token.length = length;
906         input_token.value = data;
907         
908         maj_stat = gss_wrap(&min_stat, 
909                             gensec_gssapi_state->gssapi_context,
910                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
911                             GSS_C_QOP_DEFAULT,
912                             &input_token,
913                             &conf_state,
914                             &output_token);
915         if (GSS_ERROR(maj_stat)) {
916                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", 
917                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
918                 return NT_STATUS_ACCESS_DENIED;
919         }
920
921         sig_length = gensec_gssapi_sig_size(gensec_security, length);
922
923         /* Caller must pad to right boundary */
924         if (output_token.length != (length + sig_length)) {
925                 DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n", 
926                           (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
927                 return NT_STATUS_INTERNAL_ERROR;
928         }
929
930         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
931         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
932
933         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
934         dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
935         dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
936
937         gss_release_buffer(&min_stat, &output_token);
938
939         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
940             && !conf_state) {
941                 return NT_STATUS_ACCESS_DENIED;
942         }
943         return NT_STATUS_OK;
944 }
945
946 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
947                                             TALLOC_CTX *mem_ctx, 
948                                             uint8_t *data, size_t length, 
949                                             const uint8_t *whole_pdu, size_t pdu_length,
950                                             const DATA_BLOB *sig)
951 {
952         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
953         OM_uint32 maj_stat, min_stat;
954         gss_buffer_desc input_token, output_token;
955         int conf_state;
956         gss_qop_t qop_state;
957         DATA_BLOB in;
958
959         dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
960
961         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
962
963         memcpy(in.data, sig->data, sig->length);
964         memcpy(in.data + sig->length, data, length);
965
966         input_token.length = in.length;
967         input_token.value = in.data;
968         
969         maj_stat = gss_unwrap(&min_stat, 
970                               gensec_gssapi_state->gssapi_context, 
971                               &input_token,
972                               &output_token, 
973                               &conf_state,
974                               &qop_state);
975         if (GSS_ERROR(maj_stat)) {
976                 DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
977                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
978                 return NT_STATUS_ACCESS_DENIED;
979         }
980
981         if (output_token.length != length) {
982                 return NT_STATUS_INTERNAL_ERROR;
983         }
984
985         memcpy(data, output_token.value, length);
986
987         gss_release_buffer(&min_stat, &output_token);
988         
989         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
990             && !conf_state) {
991                 return NT_STATUS_ACCESS_DENIED;
992         }
993         return NT_STATUS_OK;
994 }
995
996 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
997                                           TALLOC_CTX *mem_ctx, 
998                                           const uint8_t *data, size_t length, 
999                                           const uint8_t *whole_pdu, size_t pdu_length, 
1000                                           DATA_BLOB *sig)
1001 {
1002         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1003         OM_uint32 maj_stat, min_stat;
1004         gss_buffer_desc input_token, output_token;
1005         int conf_state;
1006         ssize_t sig_length = 0;
1007
1008         input_token.length = length;
1009         input_token.value = discard_const_p(uint8_t *, data);
1010
1011         maj_stat = gss_wrap(&min_stat, 
1012                             gensec_gssapi_state->gssapi_context,
1013                             0,
1014                             GSS_C_QOP_DEFAULT,
1015                             &input_token,
1016                             &conf_state,
1017                             &output_token);
1018         if (GSS_ERROR(maj_stat)) {
1019                 DEBUG(1, ("GSS Wrap failed: %s\n", 
1020                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
1021                 return NT_STATUS_ACCESS_DENIED;
1022         }
1023
1024         if (output_token.length < length) {
1025                 return NT_STATUS_INTERNAL_ERROR;
1026         }
1027
1028         sig_length = gensec_gssapi_sig_size(gensec_security, length);
1029
1030         /* Caller must pad to right boundary */
1031         if (output_token.length != (length + sig_length)) {
1032                 DEBUG(1, ("gensec_gssapi_sign_packet: GSS Wrap length [%ld] does not match caller length [%ld] plus sig size [%ld] = [%ld]\n", 
1033                           (long)output_token.length, (long)length, (long)sig_length, (long)(length + sig_length)));
1034                 return NT_STATUS_INTERNAL_ERROR;
1035         }
1036
1037         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
1038
1039         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1040
1041         gss_release_buffer(&min_stat, &output_token);
1042
1043         return NT_STATUS_OK;
1044 }
1045
1046 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
1047                                            TALLOC_CTX *mem_ctx, 
1048                                            const uint8_t *data, size_t length, 
1049                                            const uint8_t *whole_pdu, size_t pdu_length, 
1050                                            const DATA_BLOB *sig)
1051 {
1052         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1053         OM_uint32 maj_stat, min_stat;
1054         gss_buffer_desc input_token, output_token;
1055         int conf_state;
1056         gss_qop_t qop_state;
1057         DATA_BLOB in;
1058
1059         dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
1060
1061         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
1062
1063         memcpy(in.data, sig->data, sig->length);
1064         memcpy(in.data + sig->length, data, length);
1065
1066         input_token.length = in.length;
1067         input_token.value = in.data;
1068         
1069         maj_stat = gss_unwrap(&min_stat, 
1070                               gensec_gssapi_state->gssapi_context, 
1071                               &input_token,
1072                               &output_token, 
1073                               &conf_state,
1074                               &qop_state);
1075         if (GSS_ERROR(maj_stat)) {
1076                 DEBUG(1, ("GSS UnWrap failed: %s\n", 
1077                           gssapi_error_string(mem_ctx, maj_stat, min_stat)));
1078                 return NT_STATUS_ACCESS_DENIED;
1079         }
1080
1081         if (output_token.length != length) {
1082                 return NT_STATUS_INTERNAL_ERROR;
1083         }
1084
1085         gss_release_buffer(&min_stat, &output_token);
1086
1087         return NT_STATUS_OK;
1088 }
1089
1090 /* Try to figure out what features we actually got on the connection */
1091 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
1092                                        uint32_t feature) 
1093 {
1094         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1095         if (feature & GENSEC_FEATURE_SIGN) {
1096                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1097                 if (gensec_gssapi_state->sasl 
1098                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1099                         return ((gensec_gssapi_state->sasl_protection & NEG_SIGN) 
1100                                 && (gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG));
1101                 }
1102                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
1103         }
1104         if (feature & GENSEC_FEATURE_SEAL) {
1105                 /* If we are going GSSAPI SASL, then we honour the second negotiation */
1106                 if (gensec_gssapi_state->sasl 
1107                     && gensec_gssapi_state->sasl_state == STAGE_DONE) {
1108                         return ((gensec_gssapi_state->sasl_protection & NEG_SEAL) 
1109                                  && (gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG));
1110                 }
1111                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
1112         }
1113         if (feature & GENSEC_FEATURE_SESSION_KEY) {
1114                 /* Only for GSSAPI/Krb5 */
1115                 if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1116                     && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, gensec_gssapi_state->gss_oid->length) == 0)) {
1117                         return True;
1118                 }
1119         }
1120         if (feature & GENSEC_FEATURE_DCE_STYLE) {
1121                 return gensec_gssapi_state->got_flags & GSS_C_DCE_STYLE;
1122         }
1123         /* We can always do async (rather than strict request/reply) packets.  */
1124         if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
1125                 return True;
1126         }
1127         return False;
1128 }
1129
1130 /*
1131  * Extract the 'sesssion key' needed by SMB signing and ncacn_np 
1132  * (for encrypting some passwords).
1133  * 
1134  * This breaks all the abstractions, but what do you expect...
1135  */
1136 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
1137                                           DATA_BLOB *session_key) 
1138 {
1139         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1140         
1141         if (gensec_gssapi_state->session_key.data) {
1142                 *session_key = gensec_gssapi_state->session_key;
1143                 return NT_STATUS_OK;
1144         }
1145
1146         /* Ensure we only call this for GSSAPI/krb5, otherwise things
1147          * could get very ugly */
1148         if ((gensec_gssapi_state->gss_oid->length == gss_mech_krb5->length)
1149             && (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
1150                        gensec_gssapi_state->gss_oid->length) == 0)) {
1151                 OM_uint32 maj_stat, min_stat;
1152                 gss_buffer_desc skey;
1153                 
1154                 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 
1155                                                         gensec_gssapi_state->gssapi_context, 
1156                                                         &skey);
1157                 
1158                 if (maj_stat == 0) {
1159                         DEBUG(10, ("Got KRB5 session key of length %d\n",  
1160                                    (int)skey.length));
1161                         gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state, 
1162                                                                             skey.value, skey.length);
1163                         *session_key = gensec_gssapi_state->session_key;
1164                         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
1165                         
1166                         gss_release_buffer(&min_stat, &skey);
1167                         return NT_STATUS_OK;
1168                 }
1169                 return NT_STATUS_NO_USER_SESSION_KEY;
1170         }
1171         
1172         DEBUG(1, ("NO session key for this mech\n"));
1173         return NT_STATUS_NO_USER_SESSION_KEY;
1174 }
1175
1176
1177 /* Get some basic (and authorization) information about the user on
1178  * this session.  This uses either the PAC (if present) or a local
1179  * database lookup */
1180 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
1181                                            struct auth_session_info **_session_info) 
1182 {
1183         NTSTATUS nt_status;
1184         TALLOC_CTX *mem_ctx;
1185         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
1186         struct auth_serversupplied_info *server_info = NULL;
1187         struct auth_session_info *session_info = NULL;
1188         struct PAC_LOGON_INFO *logon_info;
1189         OM_uint32 maj_stat, min_stat;
1190         gss_buffer_desc name_token;
1191         gss_buffer_desc pac;
1192         krb5_keyblock *keyblock;
1193         time_t authtime;
1194         krb5_principal principal;
1195         char *principal_string;
1196         DATA_BLOB pac_blob;
1197         
1198         if ((gensec_gssapi_state->gss_oid->length != gss_mech_krb5->length)
1199             || (memcmp(gensec_gssapi_state->gss_oid->elements, gss_mech_krb5->elements, 
1200                        gensec_gssapi_state->gss_oid->length) != 0)) {
1201                 DEBUG(1, ("NO session info available for this mech\n"));
1202                 return NT_STATUS_INVALID_PARAMETER;
1203         }
1204                 
1205         mem_ctx = talloc_named(gensec_gssapi_state, 0, "gensec_gssapi_session_info context"); 
1206         NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
1207
1208         maj_stat = gss_display_name (&min_stat,
1209                                      gensec_gssapi_state->client_name,
1210                                      &name_token,
1211                                      NULL);
1212         if (maj_stat) {
1213                 talloc_free(mem_ctx);
1214                 return NT_STATUS_FOOBAR;
1215         }
1216
1217         principal_string = talloc_strndup(mem_ctx, name_token.value, name_token.length);
1218
1219         gss_release_buffer(&min_stat, &name_token);
1220
1221         if (!principal_string) {
1222                 talloc_free(mem_ctx);
1223                 return NT_STATUS_NO_MEMORY;
1224         }
1225
1226         maj_stat = gss_krb5_copy_service_keyblock(&min_stat, 
1227                                                   gensec_gssapi_state->gssapi_context, 
1228                                                   &keyblock);
1229
1230         if (maj_stat == 0) {
1231                 maj_stat = gsskrb5_extract_authtime_from_sec_context(&min_stat,
1232                                                                      gensec_gssapi_state->gssapi_context, 
1233                                                                      &authtime);
1234         }
1235
1236         if (maj_stat == 0) {
1237                 maj_stat = gsskrb5_extract_authz_data_from_sec_context(&min_stat, 
1238                                                                        gensec_gssapi_state->gssapi_context, 
1239                                                                        KRB5_AUTHDATA_WIN2K_PAC,
1240                                                                        &pac);
1241         }
1242
1243         if (maj_stat == 0) {
1244                 pac_blob = data_blob_talloc(mem_ctx, pac.value, pac.length);
1245                 gss_release_buffer(&min_stat, &pac);
1246         }
1247         
1248         /* IF we have the PAC - otherwise we need to get this
1249          * data from elsewere - local ldb, or (TODO) lookup of some
1250          * kind... 
1251          */
1252         if (maj_stat == 0) {
1253                 krb5_error_code ret;
1254
1255                 ret = krb5_parse_name(gensec_gssapi_state->smb_krb5_context->krb5_context,
1256                                       principal_string, &principal);
1257                 if (ret) {
1258                         talloc_free(mem_ctx);
1259                         return NT_STATUS_INVALID_PARAMETER;
1260                 }
1261                 
1262                 /* decode and verify the pac */
1263                 nt_status = kerberos_pac_logon_info(mem_ctx, &logon_info, pac_blob,
1264                                                     gensec_gssapi_state->smb_krb5_context->krb5_context,
1265                                                     NULL, keyblock, principal, authtime, NULL);
1266                 krb5_free_principal(gensec_gssapi_state->smb_krb5_context->krb5_context, principal);
1267
1268                 if (NT_STATUS_IS_OK(nt_status)) {
1269                         union netr_Validation validation;
1270                         validation.sam3 = &logon_info->info3;
1271                         nt_status = make_server_info_netlogon_validation(gensec_gssapi_state, 
1272                                                                          NULL,
1273                                                                          3, &validation,
1274                                                                          &server_info); 
1275                         if (!NT_STATUS_IS_OK(nt_status)) {
1276                                 talloc_free(mem_ctx);
1277                                 return nt_status;
1278                         }
1279                 } else {
1280                         maj_stat = 1;
1281                 }
1282         }
1283         
1284         if (maj_stat) {
1285                 DEBUG(1, ("Unable to use PAC, resorting to local user lookup!\n"));
1286                 nt_status = sam_get_server_info_principal(mem_ctx, principal_string,
1287                                                           &server_info);
1288
1289                 if (!NT_STATUS_IS_OK(nt_status)) {
1290                         talloc_free(mem_ctx);
1291                         return nt_status;
1292                 }
1293         }
1294
1295         /* references the server_info into the session_info */
1296         nt_status = auth_generate_session_info(mem_ctx, server_info, &session_info);
1297         if (!NT_STATUS_IS_OK(nt_status)) {
1298                 talloc_free(mem_ctx);
1299                 return nt_status;
1300         }
1301
1302         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
1303         if (!NT_STATUS_IS_OK(nt_status)) {
1304                 talloc_free(mem_ctx);
1305                 return nt_status;
1306         }
1307
1308         if (!(gensec_gssapi_state->got_flags & GSS_C_DELEG_FLAG)) {
1309                 DEBUG(10, ("gensec_gssapi: NO delegated credentials supplied by client\n"));
1310         } else {
1311                 krb5_error_code ret;
1312                 DEBUG(10, ("gensec_gssapi: delegated credentials supplied by client\n"));
1313                 session_info->credentials = cli_credentials_init(session_info);
1314                 if (!session_info->credentials) {
1315                         talloc_free(mem_ctx);
1316                         return NT_STATUS_NO_MEMORY;
1317                 }
1318
1319                 cli_credentials_set_conf(session_info->credentials);
1320                 
1321                 ret = cli_credentials_set_client_gss_creds(session_info->credentials, 
1322                                                            gensec_gssapi_state->delegated_cred_handle,
1323                                                            CRED_SPECIFIED);
1324                 if (ret) {
1325                         talloc_free(mem_ctx);
1326                         return NT_STATUS_NO_MEMORY;
1327                 }
1328                 /* It has been taken from this place... */
1329                 gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
1330         }
1331         talloc_steal(gensec_gssapi_state, session_info);
1332         talloc_free(mem_ctx);
1333         *_session_info = session_info;
1334
1335         return NT_STATUS_OK;
1336 }
1337
1338 static const char *gensec_gssapi_krb5_oids[] = { 
1339         GENSEC_OID_KERBEROS5,
1340         GENSEC_OID_KERBEROS5_OLD,
1341         NULL 
1342 };
1343
1344 /* As a server, this could in theory accept any GSSAPI mech */
1345 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
1346         .name           = "gssapi_krb5",
1347         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
1348         .oid            = gensec_gssapi_krb5_oids,
1349         .client_start   = gensec_gssapi_client_start,
1350         .server_start   = gensec_gssapi_server_start,
1351         .magic          = gensec_gssapi_magic,
1352         .update         = gensec_gssapi_update,
1353         .session_key    = gensec_gssapi_session_key,
1354         .session_info   = gensec_gssapi_session_info,
1355         .sig_size       = gensec_gssapi_sig_size,
1356         .sign_packet    = gensec_gssapi_sign_packet,
1357         .check_packet   = gensec_gssapi_check_packet,
1358         .seal_packet    = gensec_gssapi_seal_packet,
1359         .unseal_packet  = gensec_gssapi_unseal_packet,
1360         .wrap           = gensec_gssapi_wrap,
1361         .unwrap         = gensec_gssapi_unwrap,
1362         .have_feature   = gensec_gssapi_have_feature,
1363         .enabled        = True,
1364         .kerberos       = True,
1365         .priority       = GENSEC_GSSAPI
1366 };
1367
1368 /* As a server, this could in theory accept any GSSAPI mech */
1369 static const struct gensec_security_ops gensec_gssapi_sasl_krb5_security_ops = {
1370         .name             = "gssapi_krb5_sasl",
1371         .sasl_name        = "GSSAPI",
1372         .client_start     = gensec_gssapi_sasl_client_start,
1373         .server_start     = gensec_gssapi_sasl_server_start,
1374         .update           = gensec_gssapi_update,
1375         .session_key      = gensec_gssapi_session_key,
1376         .session_info     = gensec_gssapi_session_info,
1377         .max_input_size   = gensec_gssapi_max_input_size,
1378         .max_wrapped_size = gensec_gssapi_max_wrapped_size,
1379         .wrap             = gensec_gssapi_wrap,
1380         .unwrap           = gensec_gssapi_unwrap,
1381         .have_feature     = gensec_gssapi_have_feature,
1382         .enabled          = True,
1383         .kerberos         = True,
1384         .priority         = GENSEC_GSSAPI
1385 };
1386
1387 NTSTATUS gensec_gssapi_init(void)
1388 {
1389         NTSTATUS ret;
1390
1391         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
1392         if (!NT_STATUS_IS_OK(ret)) {
1393                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1394                         gensec_gssapi_krb5_security_ops.name));
1395                 return ret;
1396         }
1397
1398         ret = gensec_register(&gensec_gssapi_sasl_krb5_security_ops);
1399         if (!NT_STATUS_IS_OK(ret)) {
1400                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1401                         gensec_gssapi_sasl_krb5_security_ops.name));
1402                 return ret;
1403         }
1404
1405         return ret;
1406 }