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