8ee0c182081dfbc2781dd412db78dceaf19c269c
[samba.git] / source / 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
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 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
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_AUTH
33
34 static const gss_OID_desc gensec_gss_krb5_mechanism_oid_desc =
35         {9, (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
36
37 static const gss_OID_desc gensec_gss_spnego_mechanism_oid_desc =
38         {6, (void *)discard_const_p(char, "\x2b\x06\x01\x05\x05\x02")};
39
40 struct gensec_gssapi_state {
41         gss_ctx_id_t gssapi_context;
42         struct gss_channel_bindings_struct *input_chan_bindings;
43         gss_name_t server_name;
44         gss_name_t client_name;
45         OM_uint32 want_flags, got_flags;
46         const gss_OID_desc *gss_oid;
47
48         DATA_BLOB session_key;
49         DATA_BLOB pac;
50 };
51 static int gensec_gssapi_destory(void *ptr) 
52 {
53         struct gensec_gssapi_state *gensec_gssapi_state = ptr;
54         OM_uint32 maj_stat, min_stat;
55
56         if (gensec_gssapi_state->gssapi_context != GSS_C_NO_CONTEXT) {
57                 maj_stat = gss_delete_sec_context (&min_stat,
58                                                    &gensec_gssapi_state->gssapi_context,
59                                                    GSS_C_NO_BUFFER);
60         }
61
62         if (gensec_gssapi_state->server_name != GSS_C_NO_NAME) {
63                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->server_name);
64         }
65         if (gensec_gssapi_state->client_name != GSS_C_NO_NAME) {
66                 maj_stat = gss_release_name(&min_stat, &gensec_gssapi_state->client_name);
67         }
68         return 0;
69 }
70
71 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
72 {
73         struct gensec_gssapi_state *gensec_gssapi_state;
74
75         gensec_gssapi_state = talloc(gensec_security, struct gensec_gssapi_state);
76         if (!gensec_gssapi_state) {
77                 return NT_STATUS_NO_MEMORY;
78         }
79
80         gensec_security->private_data = gensec_gssapi_state;
81
82         gensec_gssapi_state->gssapi_context = GSS_C_NO_CONTEXT;
83         gensec_gssapi_state->server_name = GSS_C_NO_NAME;
84         gensec_gssapi_state->client_name = GSS_C_NO_NAME;
85
86         talloc_set_destructor(gensec_gssapi_state, gensec_gssapi_destory); 
87
88         /* TODO: Fill in channel bindings */
89         gensec_gssapi_state->input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
90         
91         gensec_gssapi_state->want_flags = 0;
92         gensec_gssapi_state->got_flags = 0;
93
94         gensec_gssapi_state->session_key = data_blob(NULL, 0);
95         gensec_gssapi_state->pac = data_blob(NULL, 0);
96
97         if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) {
98 #ifndef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
99                 /* GSSAPI won't give us the session keys, without the right hook */
100                 return NT_STATUS_INVALID_PARAMETER;
101 #endif
102         }
103         if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
104                 gensec_gssapi_state->want_flags |= GSS_C_INTEG_FLAG;
105         }
106         if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
107                 gensec_gssapi_state->want_flags |= GSS_C_CONF_FLAG;
108         }
109         if (gensec_security->want_features & GENSEC_FEATURE_DCE_STYLE) {
110 #ifndef GSS_C_DCE_STYLE
111                 /* GSSAPI won't give us the session keys, without the right hook */
112                 return NT_STATUS_INVALID_PARAMETER;
113 #else
114                 gensec_gssapi_state->want_flags |= GSS_C_DCE_STYLE;
115 #endif
116         }
117
118         if ((strcmp(gensec_security->ops->oid, GENSEC_OID_KERBEROS5) == 0)
119                 || (strcmp(gensec_security->ops->oid, GENSEC_OID_KERBEROS5_OLD) == 0)) {
120                 gensec_gssapi_state->gss_oid = &gensec_gss_krb5_mechanism_oid_desc;
121         } else if (strcmp(gensec_security->ops->oid, GENSEC_OID_SPNEGO) == 0) {
122                 gensec_gssapi_state->gss_oid = &gensec_gss_spnego_mechanism_oid_desc;
123         } else {
124                 DEBUG(1, ("gensec_gssapi incorrectly configured - cannot determine gss OID from %s\n", 
125                           gensec_security->ops->oid));
126                 return NT_STATUS_INVALID_PARAMETER;
127         }
128
129         return NT_STATUS_OK;
130 }
131
132 static NTSTATUS gensec_gssapi_server_start(struct gensec_security *gensec_security)
133 {
134         NTSTATUS nt_status;
135         struct gensec_gssapi_state *gensec_gssapi_state;
136
137         nt_status = gensec_gssapi_start(gensec_security);
138         if (!NT_STATUS_IS_OK(nt_status)) {
139                 return nt_status;
140         }
141
142         gensec_gssapi_state = gensec_security->private_data;
143
144         return NT_STATUS_OK;
145 }
146
147 static NTSTATUS gensec_gssapi_client_start(struct gensec_security *gensec_security)
148 {
149         struct gensec_gssapi_state *gensec_gssapi_state;
150         NTSTATUS nt_status;
151         gss_buffer_desc name_token;
152         OM_uint32 maj_stat, min_stat;
153
154         gss_OID_desc hostbased = {10, 
155                                   (void *)discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12"
156                                                           "\x01\x02\x01\x04")};
157
158         nt_status = gensec_gssapi_start(gensec_security);
159         if (!NT_STATUS_IS_OK(nt_status)) {
160                 return nt_status;
161         }
162
163         gensec_gssapi_state = gensec_security->private_data;
164
165         name_token.value = talloc_asprintf(gensec_gssapi_state, "%s@%s", gensec_get_target_service(gensec_security), 
166                                            gensec_get_target_hostname(gensec_security));
167         DEBUG(0, ("name: %s\n", (char *)name_token.value));
168         name_token.length = strlen(name_token.value);
169
170         maj_stat = gss_import_name (&min_stat,
171                                     &name_token,
172                                     &hostbased,
173                                     &gensec_gssapi_state->server_name);
174
175
176         if (maj_stat) {
177                 return NT_STATUS_UNSUCCESSFUL;
178         }
179         return NT_STATUS_OK;
180 }
181
182
183
184 /**
185  * Next state function for the GSSAPI GENSEC mechanism
186  * 
187  * @param gensec_gssapi_state GSSAPI State
188  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
189  * @param in The request, as a DATA_BLOB
190  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
191  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
192  *                or NT_STATUS_OK if the user is authenticated. 
193  */
194
195 static NTSTATUS gensec_gssapi_update(struct gensec_security *gensec_security, 
196                                    TALLOC_CTX *out_mem_ctx, 
197                                    const DATA_BLOB in, DATA_BLOB *out) 
198 {
199         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
200         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
201         OM_uint32 maj_stat, min_stat;
202         OM_uint32 min_stat2;
203         gss_buffer_desc input_token, output_token;
204         gss_OID gss_oid_p;
205         input_token.length = in.length;
206         input_token.value = in.data;
207
208         switch (gensec_security->gensec_role) {
209         case GENSEC_CLIENT:
210         {
211                 maj_stat = gss_init_sec_context(&min_stat, 
212                                                 GSS_C_NO_CREDENTIAL, 
213                                                 &gensec_gssapi_state->gssapi_context, 
214                                                 gensec_gssapi_state->server_name, 
215                                                 discard_const_p(gss_OID_desc, gensec_gssapi_state->gss_oid),
216                                                 gensec_gssapi_state->want_flags, 
217                                                 0, 
218                                                 gensec_gssapi_state->input_chan_bindings,
219                                                 &input_token, 
220                                                 NULL, 
221                                                 &output_token, 
222                                                 &gensec_gssapi_state->got_flags, /* ret flags */
223                                                 NULL);
224                 break;
225         }
226         case GENSEC_SERVER:
227         {
228                 maj_stat = gss_accept_sec_context(&min_stat, 
229                                                   &gensec_gssapi_state->gssapi_context, 
230                                                   GSS_C_NO_CREDENTIAL, 
231                                                   &input_token, 
232                                                   gensec_gssapi_state->input_chan_bindings,
233                                                   &gensec_gssapi_state->client_name, 
234                                                   &gss_oid_p,
235                                                   &output_token, 
236                                                   &gensec_gssapi_state->got_flags, 
237                                                   NULL, 
238                                                   NULL);
239                 gensec_gssapi_state->gss_oid = gss_oid_p;
240                 break;
241         }
242         default:
243                 return NT_STATUS_INVALID_PARAMETER;
244                 
245         }
246
247         *out = data_blob_talloc(out_mem_ctx, output_token.value, output_token.length);
248         gss_release_buffer(&min_stat2, &output_token);
249
250         if (maj_stat == GSS_S_COMPLETE) {
251                 return NT_STATUS_OK;
252         } else if (maj_stat == GSS_S_CONTINUE_NEEDED) {
253                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
254         } else {
255                 gss_buffer_desc msg1, msg2;
256                 OM_uint32 msg_ctx = 0;
257                 
258                 msg1.value = NULL;
259                 msg2.value = NULL;
260                 gss_display_status(&min_stat2, maj_stat, GSS_C_GSS_CODE,
261                                    GSS_C_NULL_OID, &msg_ctx, &msg1);
262                 gss_display_status(&min_stat2, min_stat, GSS_C_MECH_CODE,
263                                    GSS_C_NULL_OID, &msg_ctx, &msg2);
264                 DEBUG(1, ("gensec_gssapi_update: %s : %s\n", (char *)msg1.value, (char *)msg2.value));
265                 gss_release_buffer(&min_stat2, &msg1);
266                 gss_release_buffer(&min_stat2, &msg2);
267
268                 return nt_status;
269         }
270         
271 }
272
273 static NTSTATUS gensec_gssapi_wrap(struct gensec_security *gensec_security, 
274                                    TALLOC_CTX *mem_ctx, 
275                                    const DATA_BLOB *in, 
276                                    DATA_BLOB *out)
277 {
278         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
279         OM_uint32 maj_stat, min_stat;
280         gss_buffer_desc input_token, output_token;
281         int conf_state;
282         input_token.length = in->length;
283         input_token.value = in->data;
284         
285         maj_stat = gss_wrap(&min_stat, 
286                             gensec_gssapi_state->gssapi_context, 
287                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
288                             GSS_C_QOP_DEFAULT,
289                             &input_token,
290                             &conf_state,
291                             &output_token);
292         if (GSS_ERROR(maj_stat)) {
293                 return NT_STATUS_ACCESS_DENIED;
294         }
295         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
296
297         gss_release_buffer(&min_stat, &output_token);
298
299         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
300             && !conf_state) {
301                 return NT_STATUS_ACCESS_DENIED;
302         }
303         return NT_STATUS_OK;
304 }
305
306 static NTSTATUS gensec_gssapi_unwrap(struct gensec_security *gensec_security, 
307                                      TALLOC_CTX *mem_ctx, 
308                                      const DATA_BLOB *in, 
309                                      DATA_BLOB *out)
310 {
311         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
312         OM_uint32 maj_stat, min_stat;
313         gss_buffer_desc input_token, output_token;
314         int conf_state;
315         gss_qop_t qop_state;
316         input_token.length = in->length;
317         input_token.value = in->data;
318         
319         maj_stat = gss_unwrap(&min_stat, 
320                               gensec_gssapi_state->gssapi_context, 
321                               &input_token,
322                               &output_token, 
323                               &conf_state,
324                               &qop_state);
325         if (GSS_ERROR(maj_stat)) {
326                 return NT_STATUS_ACCESS_DENIED;
327         }
328         *out = data_blob_talloc(mem_ctx, output_token.value, output_token.length);
329
330         gss_release_buffer(&min_stat, &output_token);
331         
332         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
333             && !conf_state) {
334                 return NT_STATUS_ACCESS_DENIED;
335         }
336         return NT_STATUS_OK;
337 }
338
339 static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security) 
340 {
341         /* not const but work for DCERPC packets and arcfour */
342         return 45;
343 }
344
345 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
346                                           TALLOC_CTX *mem_ctx, 
347                                           uint8_t *data, size_t length, 
348                                           const uint8_t *whole_pdu, size_t pdu_length, 
349                                           DATA_BLOB *sig)
350 {
351         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
352         OM_uint32 maj_stat, min_stat;
353         gss_buffer_desc input_token, output_token;
354         int conf_state;
355         ssize_t sig_length = 0;
356
357         input_token.length = length;
358         input_token.value = data;
359         
360         maj_stat = gss_wrap(&min_stat, 
361                             gensec_gssapi_state->gssapi_context,
362                             gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
363                             GSS_C_QOP_DEFAULT,
364                             &input_token,
365                             &conf_state,
366                             &output_token);
367         if (GSS_ERROR(maj_stat)) {
368                 return NT_STATUS_ACCESS_DENIED;
369         }
370
371         if (output_token.length < length) {
372                 return NT_STATUS_INTERNAL_ERROR;
373         }
374
375         sig_length = 45;
376
377         memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
378         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
379
380 DEBUG(0,("gensec_gssapi_seal_packet: siglen: %d inlen: %d, wrap_len: %d\n", sig->length, length, output_token.length - sig_length));
381 dump_data(0,sig->data, sig->length);
382 dump_data(0,data, length);
383 dump_data(0,((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
384
385         gss_release_buffer(&min_stat, &output_token);
386
387         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
388             && !conf_state) {
389                 return NT_STATUS_ACCESS_DENIED;
390         }
391         return NT_STATUS_OK;
392 }
393
394 static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_security, 
395                                             TALLOC_CTX *mem_ctx, 
396                                             uint8_t *data, size_t length, 
397                                             const uint8_t *whole_pdu, size_t pdu_length,
398                                             const DATA_BLOB *sig)
399 {
400         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
401         OM_uint32 maj_stat, min_stat;
402         gss_buffer_desc input_token, output_token;
403         int conf_state;
404         gss_qop_t qop_state;
405         DATA_BLOB in;
406
407 DEBUG(0,("gensec_gssapi_unseal_packet: siglen: %d\n", sig->length));
408 dump_data(0,sig->data, sig->length);
409
410         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
411
412         memcpy(in.data, sig->data, sig->length);
413         memcpy(in.data + sig->length, data, length);
414
415         input_token.length = in.length;
416         input_token.value = in.data;
417         
418         maj_stat = gss_unwrap(&min_stat, 
419                               gensec_gssapi_state->gssapi_context, 
420                               &input_token,
421                               &output_token, 
422                               &conf_state,
423                               &qop_state);
424         if (GSS_ERROR(maj_stat)) {
425                 return NT_STATUS_ACCESS_DENIED;
426         }
427
428         if (output_token.length != length) {
429                 return NT_STATUS_INTERNAL_ERROR;
430         }
431
432         memcpy(data, output_token.value, length);
433
434         gss_release_buffer(&min_stat, &output_token);
435         
436         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
437             && !conf_state) {
438                 return NT_STATUS_ACCESS_DENIED;
439         }
440         return NT_STATUS_OK;
441 }
442
443 static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_security, 
444                                           TALLOC_CTX *mem_ctx, 
445                                           const uint8_t *data, size_t length, 
446                                           const uint8_t *whole_pdu, size_t pdu_length, 
447                                           DATA_BLOB *sig)
448 {
449         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
450         OM_uint32 maj_stat, min_stat;
451         gss_buffer_desc input_token, output_token;
452         int conf_state;
453         ssize_t sig_length = 0;
454
455         input_token.length = length;
456         input_token.value = discard_const_p(uint8_t *, data);
457
458         maj_stat = gss_wrap(&min_stat, 
459                             gensec_gssapi_state->gssapi_context,
460                             0,
461                             GSS_C_QOP_DEFAULT,
462                             &input_token,
463                             &conf_state,
464                             &output_token);
465         if (GSS_ERROR(maj_stat)) {
466                 return NT_STATUS_ACCESS_DENIED;
467         }
468
469         if (output_token.length < length) {
470                 return NT_STATUS_INTERNAL_ERROR;
471         }
472
473         sig_length = 45;
474
475         /*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
476         *sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
477
478 DEBUG(0,("gensec_gssapi_sign_packet: siglen: %d\n", sig->length));
479 dump_data(0,sig->data, sig->length);
480
481         gss_release_buffer(&min_stat, &output_token);
482
483         return NT_STATUS_OK;
484 }
485
486 static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_security, 
487                                            TALLOC_CTX *mem_ctx, 
488                                            const uint8_t *data, size_t length, 
489                                            const uint8_t *whole_pdu, size_t pdu_length, 
490                                            const DATA_BLOB *sig)
491 {
492         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
493         OM_uint32 maj_stat, min_stat;
494         gss_buffer_desc input_token, output_token;
495         int conf_state;
496         gss_qop_t qop_state;
497         DATA_BLOB in;
498
499 DEBUG(0,("gensec_gssapi_check_packet: siglen: %d\n", sig->length));
500 dump_data(0,sig->data, sig->length);
501
502         in = data_blob_talloc(mem_ctx, NULL, sig->length + length);
503
504         memcpy(in.data, sig->data, sig->length);
505         memcpy(in.data + sig->length, data, length);
506
507         input_token.length = in.length;
508         input_token.value = in.data;
509         
510         maj_stat = gss_unwrap(&min_stat, 
511                               gensec_gssapi_state->gssapi_context, 
512                               &input_token,
513                               &output_token, 
514                               &conf_state,
515                               &qop_state);
516         if (GSS_ERROR(maj_stat)) {
517                 return NT_STATUS_ACCESS_DENIED;
518         }
519
520         if (output_token.length != length) {
521                 return NT_STATUS_INTERNAL_ERROR;
522         }
523
524         /*memcpy(data, output_token.value, length);*/
525
526         gss_release_buffer(&min_stat, &output_token);
527
528         return NT_STATUS_OK;
529 }
530
531 static BOOL gensec_gssapi_have_feature(struct gensec_security *gensec_security, 
532                                        uint32_t feature) 
533 {
534         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
535         if (feature & GENSEC_FEATURE_SIGN) {
536                 return gensec_gssapi_state->got_flags & GSS_C_INTEG_FLAG;
537         }
538         if (feature & GENSEC_FEATURE_SEAL) {
539                 return gensec_gssapi_state->got_flags & GSS_C_CONF_FLAG;
540         }
541         if (feature & GENSEC_FEATURE_SESSION_KEY) {
542 #ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
543                 if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
544                     && (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, gensec_gssapi_state->gss_oid->length) == 0)) {
545                         return True;
546                 }
547         }
548 #endif 
549         return False;
550 }
551
552 static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_security, 
553                                           DATA_BLOB *session_key) 
554 {
555         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
556         
557         if (gensec_gssapi_state->session_key.data) {
558                 *session_key = gensec_gssapi_state->session_key;
559                 return NT_STATUS_OK;
560         }
561
562 #ifdef HAVE_GSSKRB5_GET_INITIATOR_SUBKEY
563         if ((gensec_gssapi_state->gss_oid->length == gensec_gss_krb5_mechanism_oid_desc.length)
564             && (memcmp(gensec_gssapi_state->gss_oid->elements, gensec_gss_krb5_mechanism_oid_desc.elements, gensec_gssapi_state->gss_oid->length) == 0)) {
565                 OM_uint32 maj_stat, min_stat;
566                 gss_buffer_desc skey;
567                 
568                 maj_stat = gsskrb5_get_initiator_subkey(&min_stat, 
569                                                         gensec_gssapi_state->gssapi_context, 
570                                                         &skey);
571                 
572                 if (maj_stat == 0) {
573                         DEBUG(10, ("Got KRB5 session key of length %d\n",  skey.length));
574                         gensec_gssapi_state->session_key = data_blob_talloc(gensec_gssapi_state, 
575                                                                             skey.value, skey.length);
576                         *session_key = gensec_gssapi_state->session_key;
577                         dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
578                         
579                         gss_release_buffer(&min_stat, &skey);
580                         return NT_STATUS_OK;
581                 }
582                 return NT_STATUS_NO_USER_SESSION_KEY;
583         }
584 #endif
585         
586         DEBUG(1, ("NO session key for this mech\n"));
587         return NT_STATUS_NO_USER_SESSION_KEY;
588 }
589
590 static NTSTATUS gensec_gssapi_session_info(struct gensec_security *gensec_security,
591                                          struct auth_session_info **_session_info) 
592 {
593         NTSTATUS nt_status;
594         struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
595         struct auth_serversupplied_info *server_info = NULL;
596         struct auth_session_info *session_info = NULL;
597         char *p;
598         char *principal;
599         const char *account_name;
600         const char *realm;
601         OM_uint32 maj_stat, min_stat;
602         gss_buffer_desc name_token;
603         
604         maj_stat = gss_display_name (&min_stat,
605                                      gensec_gssapi_state->client_name,
606                                      &name_token,
607                                      NULL);
608         if (maj_stat) {
609                 return NT_STATUS_FOOBAR;
610         }
611
612         principal = talloc_strndup(gensec_gssapi_state, name_token.value, name_token.length);
613
614         gss_release_buffer(&min_stat, &name_token);
615
616         NT_STATUS_HAVE_NO_MEMORY(principal);
617
618         p = strchr(principal, '@');
619         if (p) {
620                 *p = '\0';
621                 p++;
622                 realm = p;
623         } else {
624                 realm = lp_realm();
625         }
626         account_name = principal;
627
628         /* IF we have the PAC - otherwise we need to get this
629          * data from elsewere - local ldb, or (TODO) lookup of some
630          * kind... 
631          *
632          * when heimdal can generate the PAC, we should fail if there's
633          * no PAC present
634          */
635
636         {
637                 DATA_BLOB user_sess_key = data_blob(NULL, 0);
638                 DATA_BLOB lm_sess_key = data_blob(NULL, 0);
639                 /* TODO: should we pass the krb5 session key in here? */
640                 nt_status = sam_get_server_info(gensec_gssapi_state, account_name, realm,
641                                                 user_sess_key, lm_sess_key,
642                                                 &server_info);
643                 talloc_free(principal);
644                 NT_STATUS_NOT_OK_RETURN(nt_status);
645         }
646
647         /* references the server_info into the session_info */
648         nt_status = auth_generate_session_info(gensec_gssapi_state, server_info, &session_info);
649         talloc_free(server_info);
650         NT_STATUS_NOT_OK_RETURN(nt_status);
651
652         nt_status = gensec_gssapi_session_key(gensec_security, &session_info->session_key);
653         NT_STATUS_NOT_OK_RETURN(nt_status);
654
655         *_session_info = session_info;
656
657         return NT_STATUS_OK;
658 }
659
660 /* As a server, this could in theory accept any GSSAPI mech */
661 static const struct gensec_security_ops gensec_gssapi_krb5_security_ops = {
662         .name           = "gssapi_krb5",
663         .sasl_name      = "GSSAPI",
664         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
665         .oid            = GENSEC_OID_KERBEROS5,
666         .client_start   = gensec_gssapi_client_start,
667         .server_start   = gensec_gssapi_server_start,
668         .update         = gensec_gssapi_update,
669         .session_key    = gensec_gssapi_session_key,
670         .session_info   = gensec_gssapi_session_info,
671         .sig_size       = gensec_gssapi_sig_size,
672         .sign_packet    = gensec_gssapi_sign_packet,
673         .check_packet   = gensec_gssapi_check_packet,
674         .seal_packet    = gensec_gssapi_seal_packet,
675         .unseal_packet  = gensec_gssapi_unseal_packet,
676         .wrap           = gensec_gssapi_wrap,
677         .unwrap         = gensec_gssapi_unwrap,
678         .have_feature   = gensec_gssapi_have_feature,
679         .enabled        = False
680
681 };
682
683 /* As a server, this could in theory accept any GSSAPI mech */
684 static const struct gensec_security_ops gensec_gssapi_ms_krb5_security_ops = {
685         .name           = "gssapi_ms_krb5",
686         .oid            = GENSEC_OID_KERBEROS5_OLD,
687         .client_start   = gensec_gssapi_client_start,
688         .server_start   = gensec_gssapi_server_start,
689         .update         = gensec_gssapi_update,
690         .session_key    = gensec_gssapi_session_key,
691         .session_info   = gensec_gssapi_session_info,
692         .sig_size       = gensec_gssapi_sig_size,
693         .sign_packet    = gensec_gssapi_sign_packet,
694         .check_packet   = gensec_gssapi_check_packet,
695         .seal_packet    = gensec_gssapi_seal_packet,
696         .unseal_packet  = gensec_gssapi_unseal_packet,
697         .wrap           = gensec_gssapi_wrap,
698         .unwrap         = gensec_gssapi_unwrap,
699         .have_feature   = gensec_gssapi_have_feature,
700         .enabled        = False
701
702 };
703
704 static const struct gensec_security_ops gensec_gssapi_spnego_security_ops = {
705         .name           = "gssapi_spnego",
706         .sasl_name      = "GSS-SPNEGO",
707         .oid            = GENSEC_OID_SPNEGO,
708         .client_start   = gensec_gssapi_client_start,
709         .server_start   = gensec_gssapi_server_start,
710         .update         = gensec_gssapi_update,
711         .session_key    = gensec_gssapi_session_key,
712         .sig_size       = gensec_gssapi_sig_size,
713         .sign_packet    = gensec_gssapi_sign_packet,
714         .check_packet   = gensec_gssapi_check_packet,
715         .seal_packet    = gensec_gssapi_seal_packet,
716         .unseal_packet  = gensec_gssapi_unseal_packet,
717         .wrap           = gensec_gssapi_wrap,
718         .unwrap         = gensec_gssapi_unwrap,
719         .have_feature   = gensec_gssapi_have_feature,
720         .enabled        = False
721 };
722
723 NTSTATUS gensec_gssapi_init(void)
724 {
725         NTSTATUS ret;
726
727         ret = gensec_register(&gensec_gssapi_krb5_security_ops);
728         if (!NT_STATUS_IS_OK(ret)) {
729                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
730                         gensec_gssapi_krb5_security_ops.name));
731                 return ret;
732         }
733
734
735         ret = gensec_register(&gensec_gssapi_ms_krb5_security_ops);
736         if (!NT_STATUS_IS_OK(ret)) {
737                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
738                         gensec_gssapi_ms_krb5_security_ops.name));
739                 return ret;
740         }
741
742         ret = gensec_register(&gensec_gssapi_spnego_security_ops);
743         if (!NT_STATUS_IS_OK(ret)) {
744                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
745                         gensec_gssapi_spnego_security_ops.name));
746                 return ret;
747         }
748
749         return ret;
750 }