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