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