dcerpc-gssapi: add function to retrieve client name
[Samba.git] / source3 / librpc / rpc / dcerpc_gssapi.c
blobaf94b66780d6011ff363ee0506d251005c6b83d6
1 /*
2 * GSSAPI Security Extensions
3 * RPC Pipe client and server routines
4 * Copyright (C) Simo Sorce 2010.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 /* We support only GSSAPI/KRB5 here */
22 #include "includes.h"
23 #include "dcerpc_gssapi.h"
25 #if defined(HAVE_KRB5) && defined(HAVE_GSSAPI_GSSAPI_EXT_H) && defined(HAVE_GSS_WRAP_IOV)
27 #include "smb_krb5.h"
28 #include "dcerpc_krb5.h"
30 #include <gssapi/gssapi.h>
31 #include <gssapi/gssapi_krb5.h>
32 #include <gssapi/gssapi_ext.h>
34 #ifndef GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
35 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
36 #define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
37 #endif
39 gss_OID_desc gse_sesskey_inq_oid = {
40 GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH,
41 (void *)GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
44 #ifndef GSS_KRB5_SESSION_KEY_ENCTYPE_OID
45 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH 10
46 #define GSS_KRB5_SESSION_KEY_ENCTYPE_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x04"
47 #endif
49 gss_OID_desc gse_sesskeytype_oid = {
50 GSS_KRB5_SESSION_KEY_ENCTYPE_OID_LENGTH,
51 (void *)GSS_KRB5_SESSION_KEY_ENCTYPE_OID
54 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH 12
55 /* EXTRACTION OID AUTHZ ID */
56 #define GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0a" "\x01"
58 gss_OID_desc gse_authz_data_oid = {
59 GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID_LENGTH,
60 (void *)GSE_EXTRACT_RELEVANT_AUTHZ_DATA_OID
63 #ifndef GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
64 #define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH 11
65 #define GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0c"
66 #endif
68 gss_OID_desc gse_authtime_oid = {
69 GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID_LENGTH,
70 (void *)GSS_KRB5_EXTRACT_AUTHTIME_FROM_SEC_CONTEXT_OID
73 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
75 struct gse_context {
76 krb5_context k5ctx;
77 krb5_ccache ccache;
78 krb5_keytab keytab;
80 gss_ctx_id_t gss_ctx;
82 gss_OID_desc gss_mech;
83 OM_uint32 gss_c_flags;
84 gss_cred_id_t creds;
85 gss_name_t server_name;
87 gss_OID ret_mech;
88 OM_uint32 ret_flags;
89 gss_cred_id_t delegated_creds;
90 gss_name_t client_name;
92 bool spnego_wrap;
93 bool more_processing;
94 bool authenticated;
97 /* free non talloc dependent contexts */
98 static int gse_context_destructor(void *ptr)
100 struct gse_context *gse_ctx;
101 OM_uint32 gss_min, gss_maj;
103 gse_ctx = talloc_get_type_abort(ptr, struct gse_context);
104 if (gse_ctx->k5ctx) {
105 if (gse_ctx->ccache) {
106 krb5_cc_close(gse_ctx->k5ctx, gse_ctx->ccache);
107 gse_ctx->ccache = NULL;
109 if (gse_ctx->keytab) {
110 krb5_kt_close(gse_ctx->k5ctx, gse_ctx->keytab);
111 gse_ctx->keytab = NULL;
113 krb5_free_context(gse_ctx->k5ctx);
114 gse_ctx->k5ctx = NULL;
116 if (gse_ctx->gss_ctx != GSS_C_NO_CONTEXT) {
117 gss_maj = gss_delete_sec_context(&gss_min,
118 &gse_ctx->gss_ctx,
119 GSS_C_NO_BUFFER);
121 if (gse_ctx->server_name) {
122 gss_maj = gss_release_name(&gss_min,
123 &gse_ctx->server_name);
125 if (gse_ctx->client_name) {
126 gss_maj = gss_release_name(&gss_min,
127 &gse_ctx->client_name);
129 if (gse_ctx->creds) {
130 gss_maj = gss_release_cred(&gss_min,
131 &gse_ctx->creds);
133 if (gse_ctx->delegated_creds) {
134 gss_maj = gss_release_cred(&gss_min,
135 &gse_ctx->delegated_creds);
137 if (gse_ctx->ret_mech) {
138 gss_maj = gss_release_oid(&gss_min,
139 &gse_ctx->ret_mech);
141 return 0;
144 static NTSTATUS gse_context_init(TALLOC_CTX *mem_ctx,
145 enum dcerpc_AuthType auth_type,
146 enum dcerpc_AuthLevel auth_level,
147 const char *ccache_name,
148 uint32_t add_gss_c_flags,
149 struct gse_context **_gse_ctx)
151 struct gse_context *gse_ctx;
152 krb5_error_code k5ret;
153 NTSTATUS status;
155 gse_ctx = talloc_zero(mem_ctx, struct gse_context);
156 if (!gse_ctx) {
157 return NT_STATUS_NO_MEMORY;
159 talloc_set_destructor((TALLOC_CTX *)gse_ctx, gse_context_destructor);
161 memcpy(&gse_ctx->gss_mech, gss_mech_krb5, sizeof(gss_OID_desc));
163 switch (auth_type) {
164 case DCERPC_AUTH_TYPE_SPNEGO:
165 gse_ctx->spnego_wrap = true;
166 break;
167 case DCERPC_AUTH_TYPE_KRB5:
168 gse_ctx->spnego_wrap = false;
169 break;
170 default:
171 status = NT_STATUS_INVALID_PARAMETER;
172 goto err_out;
175 gse_ctx->gss_c_flags = GSS_C_MUTUAL_FLAG |
176 GSS_C_DELEG_FLAG |
177 GSS_C_DELEG_POLICY_FLAG |
178 GSS_C_REPLAY_FLAG |
179 GSS_C_SEQUENCE_FLAG;
180 switch (auth_level) {
181 case DCERPC_AUTH_LEVEL_INTEGRITY:
182 gse_ctx->gss_c_flags |= GSS_C_INTEG_FLAG;
183 break;
184 case DCERPC_AUTH_LEVEL_PRIVACY:
185 gse_ctx->gss_c_flags |= GSS_C_CONF_FLAG;
186 break;
187 default:
188 break;
191 gse_ctx->gss_c_flags |= add_gss_c_flags;
193 /* Initialize Kerberos Context */
194 initialize_krb5_error_table();
196 k5ret = krb5_init_context(&gse_ctx->k5ctx);
197 if (k5ret) {
198 DEBUG(0, ("Failed to initialize kerberos context! (%s)\n",
199 error_message(k5ret)));
200 status = NT_STATUS_INTERNAL_ERROR;
201 goto err_out;
204 if (!ccache_name) {
205 ccache_name = krb5_cc_default_name(gse_ctx->k5ctx);
207 k5ret = krb5_cc_resolve(gse_ctx->k5ctx, ccache_name,
208 &gse_ctx->ccache);
209 if (k5ret) {
210 DEBUG(1, ("Failed to resolve credential cache! (%s)\n",
211 error_message(k5ret)));
212 status = NT_STATUS_INTERNAL_ERROR;
213 goto err_out;
216 /* TODO: Should we enforce a enc_types list ?
217 ret = krb5_set_default_tgs_ktypes(gse_ctx->k5ctx, enc_types);
220 *_gse_ctx = gse_ctx;
221 return NT_STATUS_OK;
223 err_out:
224 TALLOC_FREE(gse_ctx);
225 return status;
228 NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
229 enum dcerpc_AuthType auth_type,
230 enum dcerpc_AuthLevel auth_level,
231 const char *ccache_name,
232 const char *server,
233 const char *service,
234 const char *username,
235 const char *password,
236 uint32_t add_gss_c_flags,
237 struct gse_context **_gse_ctx)
239 struct gse_context *gse_ctx;
240 OM_uint32 gss_maj, gss_min;
241 gss_buffer_desc name_buffer = {0, NULL};
242 gss_OID_set_desc mech_set;
243 NTSTATUS status;
245 if (!server || !service) {
246 return NT_STATUS_INVALID_PARAMETER;
249 status = gse_context_init(mem_ctx, auth_type, auth_level,
250 ccache_name, add_gss_c_flags,
251 &gse_ctx);
252 if (!NT_STATUS_IS_OK(status)) {
253 return NT_STATUS_NO_MEMORY;
256 name_buffer.value = talloc_asprintf(gse_ctx,
257 "%s@%s", service, server);
258 if (!name_buffer.value) {
259 status = NT_STATUS_NO_MEMORY;
260 goto err_out;
262 name_buffer.length = strlen((char *)name_buffer.value);
263 gss_maj = gss_import_name(&gss_min, &name_buffer,
264 GSS_C_NT_HOSTBASED_SERVICE,
265 &gse_ctx->server_name);
266 if (gss_maj) {
267 DEBUG(0, ("gss_import_name failed for %s, with [%s]\n",
268 (char *)name_buffer.value,
269 gse_errstr(gse_ctx, gss_maj, gss_min)));
270 status = NT_STATUS_INTERNAL_ERROR;
271 goto err_out;
274 /* TODO: get krb5 ticket using username/password, if no valid
275 * one already available in ccache */
277 mech_set.count = 1;
278 mech_set.elements = &gse_ctx->gss_mech;
280 gss_maj = gss_acquire_cred(&gss_min,
281 GSS_C_NO_NAME,
282 GSS_C_INDEFINITE,
283 &mech_set,
284 GSS_C_INITIATE,
285 &gse_ctx->creds,
286 NULL, NULL);
287 if (gss_maj) {
288 DEBUG(0, ("gss_acquire_creds failed for %s, with [%s]\n",
289 (char *)name_buffer.value,
290 gse_errstr(gse_ctx, gss_maj, gss_min)));
291 status = NT_STATUS_INTERNAL_ERROR;
292 goto err_out;
295 *_gse_ctx = gse_ctx;
296 TALLOC_FREE(name_buffer.value);
297 return NT_STATUS_OK;
299 err_out:
300 TALLOC_FREE(name_buffer.value);
301 TALLOC_FREE(gse_ctx);
302 return status;
305 NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
306 struct gse_context *gse_ctx,
307 DATA_BLOB *token_in,
308 DATA_BLOB *token_out)
310 OM_uint32 gss_maj, gss_min;
311 gss_buffer_desc in_data;
312 gss_buffer_desc out_data;
313 DATA_BLOB blob = data_blob_null;
314 NTSTATUS status;
316 in_data.value = token_in->data;
317 in_data.length = token_in->length;
319 gss_maj = gss_init_sec_context(&gss_min,
320 gse_ctx->creds,
321 &gse_ctx->gss_ctx,
322 gse_ctx->server_name,
323 &gse_ctx->gss_mech,
324 gse_ctx->gss_c_flags,
325 0, GSS_C_NO_CHANNEL_BINDINGS,
326 &in_data, NULL, &out_data,
327 NULL, NULL);
328 switch (gss_maj) {
329 case GSS_S_COMPLETE:
330 /* we are done with it */
331 gse_ctx->more_processing = false;
332 status = NT_STATUS_OK;
333 break;
334 case GSS_S_CONTINUE_NEEDED:
335 /* we will need a third leg */
336 gse_ctx->more_processing = true;
337 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
338 status = NT_STATUS_OK;
339 break;
340 default:
341 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
342 gse_errstr(talloc_tos(), gss_maj, gss_min)));
343 status = NT_STATUS_INTERNAL_ERROR;
344 goto done;
347 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
348 if (!blob.data) {
349 status = NT_STATUS_NO_MEMORY;
352 gss_maj = gss_release_buffer(&gss_min, &out_data);
354 done:
355 *token_out = blob;
356 return status;
359 NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
360 enum dcerpc_AuthType auth_type,
361 enum dcerpc_AuthLevel auth_level,
362 uint32_t add_gss_c_flags,
363 const char *server,
364 const char *keytab_name,
365 struct gse_context **_gse_ctx)
367 struct gse_context *gse_ctx;
368 OM_uint32 gss_maj, gss_min;
369 gss_OID_set_desc mech_set;
370 krb5_error_code ret;
371 const char *ktname;
372 NTSTATUS status;
374 status = gse_context_init(mem_ctx, auth_type, auth_level,
375 NULL, add_gss_c_flags, &gse_ctx);
376 if (!NT_STATUS_IS_OK(status)) {
377 return NT_STATUS_NO_MEMORY;
380 if (!keytab_name) {
381 ret = smb_krb5_get_server_keytab(gse_ctx->k5ctx,
382 &gse_ctx->keytab);
383 if (ret) {
384 status = NT_STATUS_INTERNAL_ERROR;
385 goto done;
387 ret = smb_krb5_keytab_name(gse_ctx, gse_ctx->k5ctx,
388 gse_ctx->keytab, &ktname);
389 if (ret) {
390 status = NT_STATUS_INTERNAL_ERROR;
391 goto done;
393 } else {
394 ktname = keytab_name;
397 /* FIXME!!!
398 * This call sets the default keytab for the whole server, not
399 * just for this context. Need to find a way that does not alter
400 * the state of the whole server ... */
401 ret = gsskrb5_register_acceptor_identity(ktname);
402 if (ret) {
403 status = NT_STATUS_INTERNAL_ERROR;
404 goto done;
407 mech_set.count = 1;
408 mech_set.elements = &gse_ctx->gss_mech;
410 gss_maj = gss_acquire_cred(&gss_min,
411 GSS_C_NO_NAME,
412 GSS_C_INDEFINITE,
413 &mech_set,
414 GSS_C_ACCEPT,
415 &gse_ctx->creds,
416 NULL, NULL);
417 if (gss_maj) {
418 DEBUG(0, ("gss_acquire_creds failed with [%s]\n",
419 gse_errstr(gse_ctx, gss_maj, gss_min)));
420 status = NT_STATUS_INTERNAL_ERROR;
421 goto done;
424 status = NT_STATUS_OK;
426 done:
427 if (!NT_STATUS_IS_OK(status)) {
428 TALLOC_FREE(gse_ctx);
431 *_gse_ctx = gse_ctx;
432 return status;
435 NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
436 struct gse_context *gse_ctx,
437 DATA_BLOB *token_in,
438 DATA_BLOB *token_out)
440 OM_uint32 gss_maj, gss_min;
441 gss_buffer_desc in_data;
442 gss_buffer_desc out_data;
443 DATA_BLOB blob = data_blob_null;
444 NTSTATUS status;
446 in_data.value = token_in->data;
447 in_data.length = token_in->length;
449 gss_maj = gss_accept_sec_context(&gss_min,
450 &gse_ctx->gss_ctx,
451 gse_ctx->creds,
452 &in_data,
453 GSS_C_NO_CHANNEL_BINDINGS,
454 &gse_ctx->client_name,
455 &gse_ctx->ret_mech,
456 &out_data,
457 &gse_ctx->ret_flags, NULL,
458 &gse_ctx->delegated_creds);
459 switch (gss_maj) {
460 case GSS_S_COMPLETE:
461 /* we are done with it */
462 gse_ctx->more_processing = false;
463 gse_ctx->authenticated = true;
464 status = NT_STATUS_OK;
465 break;
466 case GSS_S_CONTINUE_NEEDED:
467 /* we will need a third leg */
468 gse_ctx->more_processing = true;
469 /* status = NT_STATUS_MORE_PROCESSING_REQUIRED; */
470 status = NT_STATUS_OK;
471 break;
472 default:
473 DEBUG(0, ("gss_init_sec_context failed with [%s]\n",
474 gse_errstr(talloc_tos(), gss_maj, gss_min)));
476 if (gse_ctx->gss_ctx) {
477 gss_delete_sec_context(&gss_min,
478 &gse_ctx->gss_ctx,
479 GSS_C_NO_BUFFER);
482 status = NT_STATUS_INTERNAL_ERROR;
483 goto done;
486 /* we may be told to return nothing */
487 if (out_data.length) {
488 blob = data_blob_talloc(mem_ctx, out_data.value, out_data.length);
489 if (!blob.data) {
490 status = NT_STATUS_NO_MEMORY;
492 gss_maj = gss_release_buffer(&gss_min, &out_data);
496 done:
497 *token_out = blob;
498 return status;
501 NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
503 if (!gse_ctx->authenticated) {
504 return NT_STATUS_INVALID_HANDLE;
507 if (memcmp(gse_ctx->ret_mech,
508 gss_mech_krb5, sizeof(gss_OID_desc)) != 0) {
509 return NT_STATUS_ACCESS_DENIED;
512 /* GSS_C_MUTUAL_FLAG */
513 if (gse_ctx->gss_c_flags & GSS_C_MUTUAL_FLAG) {
514 if (!(gse_ctx->ret_flags & GSS_C_MUTUAL_FLAG)) {
515 return NT_STATUS_ACCESS_DENIED;
519 /* GSS_C_DELEG_FLAG */
520 /* GSS_C_DELEG_POLICY_FLAG */
521 /* GSS_C_REPLAY_FLAG */
522 /* GSS_C_SEQUENCE_FLAG */
524 /* GSS_C_INTEG_FLAG */
525 if (gse_ctx->gss_c_flags & GSS_C_INTEG_FLAG) {
526 if (!(gse_ctx->ret_flags & GSS_C_INTEG_FLAG)) {
527 return NT_STATUS_ACCESS_DENIED;
531 /* GSS_C_CONF_FLAG */
532 if (gse_ctx->gss_c_flags & GSS_C_CONF_FLAG) {
533 if (!(gse_ctx->ret_flags & GSS_C_CONF_FLAG)) {
534 return NT_STATUS_ACCESS_DENIED;
538 return NT_STATUS_OK;
541 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min)
543 OM_uint32 gss_min, gss_maj;
544 gss_buffer_desc msg_min;
545 gss_buffer_desc msg_maj;
546 OM_uint32 msg_ctx = 0;
548 char *errstr = NULL;
550 ZERO_STRUCT(msg_min);
551 ZERO_STRUCT(msg_maj);
553 gss_maj = gss_display_status(&gss_min, maj, GSS_C_GSS_CODE,
554 GSS_C_NO_OID, &msg_ctx, &msg_maj);
555 if (gss_maj) {
556 goto done;
558 gss_maj = gss_display_status(&gss_min, min, GSS_C_MECH_CODE,
559 (gss_OID)discard_const(gss_mech_krb5),
560 &msg_ctx, &msg_min);
561 if (gss_maj) {
562 goto done;
565 errstr = talloc_strndup(mem_ctx,
566 (char *)msg_maj.value,
567 msg_maj.length);
568 if (!errstr) {
569 goto done;
571 errstr = talloc_strdup_append_buffer(errstr, ": ");
572 if (!errstr) {
573 goto done;
575 errstr = talloc_strndup_append_buffer(errstr,
576 (char *)msg_min.value,
577 msg_min.length);
578 if (!errstr) {
579 goto done;
582 done:
583 if (msg_min.value) {
584 gss_maj = gss_release_buffer(&gss_min, &msg_min);
586 if (msg_maj.value) {
587 gss_maj = gss_release_buffer(&gss_min, &msg_maj);
589 return errstr;
592 bool gse_require_more_processing(struct gse_context *gse_ctx)
594 return gse_ctx->more_processing;
597 DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
598 struct gse_context *gse_ctx)
600 OM_uint32 gss_min, gss_maj;
601 gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
602 DATA_BLOB ret;
604 gss_maj = gss_inquire_sec_context_by_oid(
605 &gss_min, gse_ctx->gss_ctx,
606 &gse_sesskey_inq_oid, &set);
607 if (gss_maj) {
608 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
609 gse_errstr(talloc_tos(), gss_maj, gss_min)));
610 return data_blob_null;
613 if ((set == GSS_C_NO_BUFFER_SET) ||
614 (set->count != 2) ||
615 (memcmp(set->elements[1].value,
616 gse_sesskeytype_oid.elements,
617 gse_sesskeytype_oid.length) != 0)) {
618 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
619 "OID for data in results:\n"));
620 dump_data(1, (uint8_t *)set->elements[1].value,
621 set->elements[1].length);
622 return data_blob_null;
625 ret = data_blob_talloc(mem_ctx, set->elements[0].value,
626 set->elements[0].length);
628 gss_maj = gss_release_buffer_set(&gss_min, &set);
629 return ret;
632 NTSTATUS gse_get_client_name(struct gse_context *gse_ctx,
633 TALLOC_CTX *mem_ctx, char **cli_name)
635 OM_uint32 gss_min, gss_maj;
636 gss_buffer_desc name_buffer;
638 if (!gse_ctx->authenticated) {
639 return NT_STATUS_ACCESS_DENIED;
642 if (!gse_ctx->client_name) {
643 return NT_STATUS_NOT_FOUND;
646 /* TODO: check OID matches KRB5 Principal Name OID ? */
648 gss_maj = gss_display_name(&gss_min,
649 gse_ctx->client_name,
650 &name_buffer, NULL);
651 if (gss_maj) {
652 DEBUG(0, ("gss_display_name failed [%s]\n",
653 gse_errstr(talloc_tos(), gss_maj, gss_min)));
654 return NT_STATUS_INTERNAL_ERROR;
657 *cli_name = talloc_strndup(talloc_tos(),
658 (char *)name_buffer.value,
659 name_buffer.length);
661 gss_maj = gss_release_buffer(&gss_min, &name_buffer);
663 if (!*cli_name) {
664 return NT_STATUS_NO_MEMORY;
667 return NT_STATUS_OK;
670 NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
671 TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
673 OM_uint32 gss_min, gss_maj;
674 gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
676 if (!gse_ctx->authenticated) {
677 return NT_STATUS_ACCESS_DENIED;
680 gss_maj = gss_inquire_sec_context_by_oid(
681 &gss_min, gse_ctx->gss_ctx,
682 &gse_authz_data_oid, &set);
683 if (gss_maj) {
684 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
685 gse_errstr(talloc_tos(), gss_maj, gss_min)));
686 return NT_STATUS_NOT_FOUND;
689 if (set == GSS_C_NO_BUFFER_SET) {
690 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
691 "data in results.\n"));
692 return NT_STATUS_INTERNAL_ERROR;
695 /* for now we just hope it is the first value */
696 *pac = data_blob_talloc(mem_ctx,
697 set->elements[0].value,
698 set->elements[0].length);
700 gss_maj = gss_release_buffer_set(&gss_min, &set);
702 return NT_STATUS_OK;
705 NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
707 OM_uint32 gss_min, gss_maj;
708 gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
709 int32_t tkttime;
711 if (!gse_ctx->authenticated) {
712 return NT_STATUS_ACCESS_DENIED;
715 gss_maj = gss_inquire_sec_context_by_oid(
716 &gss_min, gse_ctx->gss_ctx,
717 &gse_authtime_oid, &set);
718 if (gss_maj) {
719 DEBUG(0, ("gss_inquire_sec_context_by_oid failed [%s]\n",
720 gse_errstr(talloc_tos(), gss_maj, gss_min)));
721 return NT_STATUS_NOT_FOUND;
724 if ((set == GSS_C_NO_BUFFER_SET) || (set->count != 1) != 0) {
725 DEBUG(0, ("gss_inquire_sec_context_by_oid returned unknown "
726 "data in results.\n"));
727 return NT_STATUS_INTERNAL_ERROR;
730 if (set->elements[0].length != sizeof(int32_t)) {
731 DEBUG(0, ("Invalid authtime size!\n"));
732 return NT_STATUS_INTERNAL_ERROR;
735 tkttime = *((int32_t *)set->elements[0].value);
737 gss_maj = gss_release_buffer_set(&gss_min, &set);
739 *authtime = (time_t)tkttime;
740 return NT_STATUS_OK;
743 size_t gse_get_signature_length(struct gse_context *gse_ctx,
744 int seal, size_t payload_size)
746 OM_uint32 gss_min, gss_maj;
747 gss_iov_buffer_desc iov[2];
748 uint8_t fakebuf[payload_size];
749 int sealed;
751 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
752 iov[0].buffer.value = NULL;
753 iov[0].buffer.length = 0;
754 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
755 iov[1].buffer.value = fakebuf;
756 iov[1].buffer.length = payload_size;
758 gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gss_ctx,
759 seal, GSS_C_QOP_DEFAULT,
760 &sealed, iov, 2);
761 if (gss_maj) {
762 DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
763 gse_errstr(talloc_tos(), gss_maj, gss_min)));
764 return 0;
767 return iov[0].buffer.length;
770 NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
771 DATA_BLOB *data, DATA_BLOB *signature)
773 OM_uint32 gss_min, gss_maj;
774 gss_iov_buffer_desc iov[2];
775 int req_seal = 1; /* setting to 1 means we request sign+seal */
776 int sealed;
777 NTSTATUS status;
779 /* allocate the memory ourselves so we do not need to talloc_memdup */
780 signature->length = gse_get_signature_length(gse_ctx, 1, data->length);
781 if (!signature->length) {
782 return NT_STATUS_INTERNAL_ERROR;
784 signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
785 if (!signature->data) {
786 return NT_STATUS_NO_MEMORY;
788 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
789 iov[0].buffer.value = signature->data;
790 iov[0].buffer.length = signature->length;
792 /* data is encrypted in place, which is ok */
793 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
794 iov[1].buffer.value = data->data;
795 iov[1].buffer.length = data->length;
797 gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gss_ctx,
798 req_seal, GSS_C_QOP_DEFAULT,
799 &sealed, iov, 2);
800 if (gss_maj) {
801 DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
802 gse_errstr(talloc_tos(), gss_maj, gss_min)));
803 status = NT_STATUS_ACCESS_DENIED;
804 goto done;
807 if (!sealed) {
808 DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
809 status = NT_STATUS_ACCESS_DENIED;
810 goto done;
813 status = NT_STATUS_OK;
815 DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
816 (int)iov[1].buffer.length, (int)iov[0].buffer.length));
818 done:
819 return status;
822 NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
823 DATA_BLOB *data, DATA_BLOB *signature)
825 OM_uint32 gss_min, gss_maj;
826 gss_iov_buffer_desc iov[2];
827 int sealed;
828 NTSTATUS status;
830 iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
831 iov[0].buffer.value = signature->data;
832 iov[0].buffer.length = signature->length;
834 /* data is decrypted in place, which is ok */
835 iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
836 iov[1].buffer.value = data->data;
837 iov[1].buffer.length = data->length;
839 gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gss_ctx,
840 &sealed, NULL, iov, 2);
841 if (gss_maj) {
842 DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
843 gse_errstr(talloc_tos(), gss_maj, gss_min)));
844 status = NT_STATUS_ACCESS_DENIED;
845 goto done;
848 if (!sealed) {
849 DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
850 status = NT_STATUS_ACCESS_DENIED;
851 goto done;
854 status = NT_STATUS_OK;
856 DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
857 (int)iov[1].buffer.length, (int)iov[0].buffer.length));
859 done:
860 return status;
863 NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
864 DATA_BLOB *data, DATA_BLOB *signature)
866 OM_uint32 gss_min, gss_maj;
867 gss_buffer_desc in_data = { 0, NULL };
868 gss_buffer_desc out_data = { 0, NULL};
869 NTSTATUS status;
871 in_data.value = data->data;
872 in_data.length = data->length;
874 gss_maj = gss_get_mic(&gss_min, gse_ctx->gss_ctx,
875 GSS_C_QOP_DEFAULT,
876 &in_data, &out_data);
877 if (gss_maj) {
878 DEBUG(0, ("gss_get_mic failed with [%s]\n",
879 gse_errstr(talloc_tos(), gss_maj, gss_min)));
880 status = NT_STATUS_ACCESS_DENIED;
881 goto done;
884 *signature = data_blob_talloc(mem_ctx,
885 out_data.value, out_data.length);
886 if (!signature->data) {
887 status = NT_STATUS_NO_MEMORY;
888 goto done;
891 status = NT_STATUS_OK;
893 done:
894 if (out_data.value) {
895 gss_maj = gss_release_buffer(&gss_min, &out_data);
897 return status;
900 NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
901 DATA_BLOB *data, DATA_BLOB *signature)
903 OM_uint32 gss_min, gss_maj;
904 gss_buffer_desc in_data = { 0, NULL };
905 gss_buffer_desc in_token = { 0, NULL};
906 NTSTATUS status;
908 in_data.value = data->data;
909 in_data.length = data->length;
910 in_token.value = signature->data;
911 in_token.length = signature->length;
913 gss_maj = gss_verify_mic(&gss_min, gse_ctx->gss_ctx,
914 &in_data, &in_token, NULL);
915 if (gss_maj) {
916 DEBUG(0, ("gss_verify_mic failed with [%s]\n",
917 gse_errstr(talloc_tos(), gss_maj, gss_min)));
918 status = NT_STATUS_ACCESS_DENIED;
919 goto done;
922 status = NT_STATUS_OK;
924 done:
925 return status;
928 #else
930 NTSTATUS gse_init_client(TALLOC_CTX *mem_ctx,
931 enum dcerpc_AuthType auth_type,
932 enum dcerpc_AuthLevel auth_level,
933 const char *ccache_name,
934 const char *server,
935 const char *service,
936 const char *username,
937 const char *password,
938 uint32_t add_gss_c_flags,
939 struct gse_context **_gse_ctx)
941 return NT_STATUS_NOT_IMPLEMENTED;
944 NTSTATUS gse_get_client_auth_token(TALLOC_CTX *mem_ctx,
945 struct gse_context *gse_ctx,
946 DATA_BLOB *token_in,
947 DATA_BLOB *token_out)
949 return NT_STATUS_NOT_IMPLEMENTED;
952 NTSTATUS gse_init_server(TALLOC_CTX *mem_ctx,
953 enum dcerpc_AuthType auth_type,
954 enum dcerpc_AuthLevel auth_level,
955 uint32_t add_gss_c_flags,
956 const char *server,
957 const char *keytab,
958 struct gse_context **_gse_ctx)
960 return NT_STATUS_NOT_IMPLEMENTED;
963 NTSTATUS gse_get_server_auth_token(TALLOC_CTX *mem_ctx,
964 struct gse_context *gse_ctx,
965 DATA_BLOB *token_in,
966 DATA_BLOB *token_out)
968 return NT_STATUS_NOT_IMPLEMENTED;
971 NTSTATUS gse_verify_server_auth_flags(struct gse_context *gse_ctx)
973 return NT_STATUS_NOT_IMPLEMENTED;
976 bool gse_require_more_processing(struct gse_context *gse_ctx)
978 return false;
981 DATA_BLOB gse_get_session_key(TALLOC_CTX *mem_ctx,
982 struct gse_context *gse_ctx)
984 return data_blob_null;
987 NTSTATUS gse_get_client_name(struct gse_context *gse_ctx,
988 TALLOC_CTX *mem_ctx, char **client_name)
990 return NT_STATUS_NOT_IMPLEMENTED;
993 NTSTATUS gse_get_authz_data(struct gse_context *gse_ctx,
994 TALLOC_CTX *mem_ctx, DATA_BLOB *pac)
996 return NT_STATUS_NOT_IMPLEMENTED;
999 NTSTATUS gse_get_authtime(struct gse_context *gse_ctx, time_t *authtime)
1001 return NT_STATUS_NOT_IMPLEMENTED;
1004 size_t gse_get_signature_length(struct gse_context *gse_ctx,
1005 int seal, size_t payload_size)
1007 return 0;
1010 NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1011 DATA_BLOB *data, DATA_BLOB *signature)
1013 return NT_STATUS_NOT_IMPLEMENTED;
1016 NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1017 DATA_BLOB *data, DATA_BLOB *signature)
1019 return NT_STATUS_NOT_IMPLEMENTED;
1022 NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1023 DATA_BLOB *data, DATA_BLOB *signature)
1025 return NT_STATUS_NOT_IMPLEMENTED;
1028 NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
1029 DATA_BLOB *data, DATA_BLOB *signature)
1031 return NT_STATUS_NOT_IMPLEMENTED;
1034 #endif /* HAVE_KRB5 && HAVE_GSSAPI_EXT_H && HAVE_GSS_WRAP_IOV */