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