lib: Make time-basic a library
[Samba.git] / auth / gensec / gensec.c
blob9fd5f2545544304ec6005011ecdd4f6e3b62bdf9
1 /*
2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/network.h"
25 #define TEVENT_DEPRECATED 1
26 #include <tevent.h>
27 #include "lib/tsocket/tsocket.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "librpc/gen_ndr/dcerpc.h"
34 wrappers for the gensec function pointers
36 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
37 uint8_t *data, size_t length,
38 const uint8_t *whole_pdu, size_t pdu_length,
39 const DATA_BLOB *sig)
41 if (!gensec_security->ops->unseal_packet) {
42 return NT_STATUS_NOT_IMPLEMENTED;
44 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
45 return NT_STATUS_INVALID_PARAMETER;
47 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
48 return NT_STATUS_INVALID_PARAMETER;
50 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
51 return NT_STATUS_INVALID_PARAMETER;
54 return gensec_security->ops->unseal_packet(gensec_security,
55 data, length,
56 whole_pdu, pdu_length,
57 sig);
60 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
61 const uint8_t *data, size_t length,
62 const uint8_t *whole_pdu, size_t pdu_length,
63 const DATA_BLOB *sig)
65 if (!gensec_security->ops->check_packet) {
66 return NT_STATUS_NOT_IMPLEMENTED;
68 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
69 return NT_STATUS_INVALID_PARAMETER;
72 return gensec_security->ops->check_packet(gensec_security, data, length, whole_pdu, pdu_length, sig);
75 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
76 TALLOC_CTX *mem_ctx,
77 uint8_t *data, size_t length,
78 const uint8_t *whole_pdu, size_t pdu_length,
79 DATA_BLOB *sig)
81 if (!gensec_security->ops->seal_packet) {
82 return NT_STATUS_NOT_IMPLEMENTED;
84 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
85 return NT_STATUS_INVALID_PARAMETER;
87 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
88 return NT_STATUS_INVALID_PARAMETER;
90 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
91 return NT_STATUS_INVALID_PARAMETER;
94 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
97 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
98 TALLOC_CTX *mem_ctx,
99 const uint8_t *data, size_t length,
100 const uint8_t *whole_pdu, size_t pdu_length,
101 DATA_BLOB *sig)
103 if (!gensec_security->ops->sign_packet) {
104 return NT_STATUS_NOT_IMPLEMENTED;
106 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
107 return NT_STATUS_INVALID_PARAMETER;
110 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
113 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
115 if (!gensec_security->ops->sig_size) {
116 return 0;
118 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
119 return 0;
121 if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
122 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE)) {
123 return 0;
127 return gensec_security->ops->sig_size(gensec_security, data_size);
130 _PUBLIC_ size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
132 if (!gensec_security->ops->max_wrapped_size) {
133 return (1 << 17);
136 return gensec_security->ops->max_wrapped_size(gensec_security);
139 _PUBLIC_ size_t gensec_max_input_size(struct gensec_security *gensec_security)
141 if (!gensec_security->ops->max_input_size) {
142 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
145 return gensec_security->ops->max_input_size(gensec_security);
148 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
149 TALLOC_CTX *mem_ctx,
150 const DATA_BLOB *in,
151 DATA_BLOB *out)
153 if (!gensec_security->ops->wrap) {
154 return NT_STATUS_NOT_IMPLEMENTED;
156 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
159 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
160 TALLOC_CTX *mem_ctx,
161 const DATA_BLOB *in,
162 DATA_BLOB *out)
164 if (!gensec_security->ops->unwrap) {
165 return NT_STATUS_NOT_IMPLEMENTED;
167 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
170 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
171 TALLOC_CTX *mem_ctx,
172 DATA_BLOB *session_key)
174 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
175 return NT_STATUS_NO_USER_SESSION_KEY;
178 if (!gensec_security->ops->session_key) {
179 return NT_STATUS_NOT_IMPLEMENTED;
182 return gensec_security->ops->session_key(gensec_security, mem_ctx, session_key);
186 * Return the credentials of a logged on user, including session keys
187 * etc.
189 * Only valid after a successful authentication
191 * May only be called once per authentication.
195 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
196 TALLOC_CTX *mem_ctx,
197 struct auth_session_info **session_info)
199 if (!gensec_security->ops->session_info) {
200 return NT_STATUS_NOT_IMPLEMENTED;
202 return gensec_security->ops->session_info(gensec_security, mem_ctx, session_info);
205 _PUBLIC_ void gensec_set_max_update_size(struct gensec_security *gensec_security,
206 uint32_t max_update_size)
208 gensec_security->max_update_size = max_update_size;
211 _PUBLIC_ size_t gensec_max_update_size(struct gensec_security *gensec_security)
213 if (gensec_security->max_update_size == 0) {
214 return UINT32_MAX;
217 return gensec_security->max_update_size;
220 _PUBLIC_ NTSTATUS gensec_update_ev(struct gensec_security *gensec_security,
221 TALLOC_CTX *out_mem_ctx,
222 struct tevent_context *ev,
223 const DATA_BLOB in, DATA_BLOB *out)
225 NTSTATUS status;
226 const struct gensec_security_ops *ops = gensec_security->ops;
227 TALLOC_CTX *frame = NULL;
228 struct tevent_req *subreq = NULL;
229 bool ok;
231 if (ops->update_send == NULL) {
233 if (ev == NULL) {
234 frame = talloc_stackframe();
236 ev = samba_tevent_context_init(frame);
237 if (ev == NULL) {
238 status = NT_STATUS_NO_MEMORY;
239 goto fail;
243 * TODO: remove this hack once the backends
244 * are fixed.
246 tevent_loop_allow_nesting(ev);
249 status = ops->update(gensec_security, out_mem_ctx,
250 ev, in, out);
251 TALLOC_FREE(frame);
252 if (!NT_STATUS_IS_OK(status)) {
253 return status;
257 * Because callers using the
258 * gensec_start_mech_by_auth_type() never call
259 * gensec_want_feature(), it isn't sensible for them
260 * to have to call gensec_have_feature() manually, and
261 * these are not points of negotiation, but are
262 * asserted by the client
264 switch (gensec_security->dcerpc_auth_level) {
265 case DCERPC_AUTH_LEVEL_INTEGRITY:
266 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
267 DEBUG(0,("Did not manage to negotiate mandetory feature "
268 "SIGN for dcerpc auth_level %u\n",
269 gensec_security->dcerpc_auth_level));
270 return NT_STATUS_ACCESS_DENIED;
272 break;
273 case DCERPC_AUTH_LEVEL_PRIVACY:
274 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
275 DEBUG(0,("Did not manage to negotiate mandetory feature "
276 "SIGN for dcerpc auth_level %u\n",
277 gensec_security->dcerpc_auth_level));
278 return NT_STATUS_ACCESS_DENIED;
280 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
281 DEBUG(0,("Did not manage to negotiate mandetory feature "
282 "SEAL for dcerpc auth_level %u\n",
283 gensec_security->dcerpc_auth_level));
284 return NT_STATUS_ACCESS_DENIED;
286 break;
287 default:
288 break;
291 return NT_STATUS_OK;
294 frame = talloc_stackframe();
296 if (ev == NULL) {
297 ev = samba_tevent_context_init(frame);
298 if (ev == NULL) {
299 status = NT_STATUS_NO_MEMORY;
300 goto fail;
304 * TODO: remove this hack once the backends
305 * are fixed.
307 tevent_loop_allow_nesting(ev);
310 subreq = ops->update_send(frame, ev, gensec_security, in);
311 if (subreq == NULL) {
312 status = NT_STATUS_NO_MEMORY;
313 goto fail;
315 ok = tevent_req_poll_ntstatus(subreq, ev, &status);
316 if (!ok) {
317 goto fail;
319 status = ops->update_recv(subreq, out_mem_ctx, out);
320 fail:
321 TALLOC_FREE(frame);
322 return status;
326 * Next state function for the GENSEC state machine
328 * @param gensec_security GENSEC State
329 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
330 * @param in The request, as a DATA_BLOB
331 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
332 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
333 * or NT_STATUS_OK if the user is authenticated.
336 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security,
337 TALLOC_CTX *out_mem_ctx,
338 const DATA_BLOB in, DATA_BLOB *out)
340 return gensec_update_ev(gensec_security, out_mem_ctx, NULL, in, out);
343 struct gensec_update_state {
344 const struct gensec_security_ops *ops;
345 struct tevent_req *subreq;
346 struct gensec_security *gensec_security;
347 DATA_BLOB out;
350 * only for sync backends, we should remove this
351 * once all backends are async.
353 struct tevent_immediate *im;
354 DATA_BLOB in;
357 static void gensec_update_async_trigger(struct tevent_context *ctx,
358 struct tevent_immediate *im,
359 void *private_data);
360 static void gensec_update_subreq_done(struct tevent_req *subreq);
363 * Next state function for the GENSEC state machine async version
365 * @param mem_ctx The memory context for the request
366 * @param ev The event context for the request
367 * @param gensec_security GENSEC State
368 * @param in The request, as a DATA_BLOB
370 * @return The request handle or NULL on no memory failure
373 _PUBLIC_ struct tevent_req *gensec_update_send(TALLOC_CTX *mem_ctx,
374 struct tevent_context *ev,
375 struct gensec_security *gensec_security,
376 const DATA_BLOB in)
378 struct tevent_req *req;
379 struct gensec_update_state *state = NULL;
381 req = tevent_req_create(mem_ctx, &state,
382 struct gensec_update_state);
383 if (req == NULL) {
384 return NULL;
387 state->ops = gensec_security->ops;
388 state->gensec_security = gensec_security;
390 if (state->ops->update_send == NULL) {
391 state->in = in;
392 state->im = tevent_create_immediate(state);
393 if (tevent_req_nomem(state->im, req)) {
394 return tevent_req_post(req, ev);
397 tevent_schedule_immediate(state->im, ev,
398 gensec_update_async_trigger,
399 req);
401 return req;
404 state->subreq = state->ops->update_send(state, ev, gensec_security, in);
405 if (tevent_req_nomem(state->subreq, req)) {
406 return tevent_req_post(req, ev);
409 tevent_req_set_callback(state->subreq,
410 gensec_update_subreq_done,
411 req);
413 return req;
416 static void gensec_update_async_trigger(struct tevent_context *ctx,
417 struct tevent_immediate *im,
418 void *private_data)
420 struct tevent_req *req =
421 talloc_get_type_abort(private_data, struct tevent_req);
422 struct gensec_update_state *state =
423 tevent_req_data(req, struct gensec_update_state);
424 NTSTATUS status;
426 status = state->ops->update(state->gensec_security, state, ctx,
427 state->in, &state->out);
428 if (tevent_req_nterror(req, status)) {
429 return;
432 tevent_req_done(req);
435 static void gensec_update_subreq_done(struct tevent_req *subreq)
437 struct tevent_req *req =
438 tevent_req_callback_data(subreq,
439 struct tevent_req);
440 struct gensec_update_state *state =
441 tevent_req_data(req,
442 struct gensec_update_state);
443 NTSTATUS status;
445 state->subreq = NULL;
447 status = state->ops->update_recv(subreq, state, &state->out);
448 TALLOC_FREE(subreq);
449 if (tevent_req_nterror(req, status)) {
450 return;
454 * Because callers using the
455 * gensec_start_mech_by_authtype() never call
456 * gensec_want_feature(), it isn't sensible for them
457 * to have to call gensec_have_feature() manually, and
458 * these are not points of negotiation, but are
459 * asserted by the client
461 switch (state->gensec_security->dcerpc_auth_level) {
462 case DCERPC_AUTH_LEVEL_INTEGRITY:
463 if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
464 DEBUG(0,("Did not manage to negotiate mandetory feature "
465 "SIGN for dcerpc auth_level %u\n",
466 state->gensec_security->dcerpc_auth_level));
467 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
468 return;
470 break;
471 case DCERPC_AUTH_LEVEL_PRIVACY:
472 if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SIGN)) {
473 DEBUG(0,("Did not manage to negotiate mandetory feature "
474 "SIGN for dcerpc auth_level %u\n",
475 state->gensec_security->dcerpc_auth_level));
476 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
477 return;
479 if (!gensec_have_feature(state->gensec_security, GENSEC_FEATURE_SEAL)) {
480 DEBUG(0,("Did not manage to negotiate mandetory feature "
481 "SEAL for dcerpc auth_level %u\n",
482 state->gensec_security->dcerpc_auth_level));
483 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
484 return;
486 break;
487 default:
488 break;
491 tevent_req_done(req);
495 * Next state function for the GENSEC state machine
497 * @param req request state
498 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
499 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
500 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
501 * or NT_STATUS_OK if the user is authenticated.
503 _PUBLIC_ NTSTATUS gensec_update_recv(struct tevent_req *req,
504 TALLOC_CTX *out_mem_ctx,
505 DATA_BLOB *out)
507 struct gensec_update_state *state =
508 tevent_req_data(req, struct gensec_update_state);
509 NTSTATUS status;
511 if (tevent_req_is_nterror(req, &status)) {
512 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
513 tevent_req_received(req);
514 return status;
516 } else {
517 status = NT_STATUS_OK;
520 *out = state->out;
521 talloc_steal(out_mem_ctx, out->data);
523 tevent_req_received(req);
524 return status;
528 * Set the requirement for a certain feature on the connection
532 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
533 uint32_t feature)
535 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
536 gensec_security->want_features |= feature;
537 return;
539 gensec_security->ops->want_feature(gensec_security, feature);
543 * Check the requirement for a certain feature on the connection
547 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
548 uint32_t feature)
550 if (!gensec_security->ops || !gensec_security->ops->have_feature) {
551 return false;
554 /* We might 'have' features that we don't 'want', because the
555 * other end demanded them, or we can't neotiate them off */
556 return gensec_security->ops->have_feature(gensec_security, feature);
559 _PUBLIC_ NTTIME gensec_expire_time(struct gensec_security *gensec_security)
561 if (!gensec_security->ops->expire_time) {
562 return GENSEC_EXPIRE_TIME_INFINITY;
565 return gensec_security->ops->expire_time(gensec_security);
568 * Return the credentials structure associated with a GENSEC context
572 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
574 if (!gensec_security) {
575 return NULL;
577 return gensec_security->credentials;
581 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
585 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
587 gensec_security->target.service = talloc_strdup(gensec_security, service);
588 if (!gensec_security->target.service) {
589 return NT_STATUS_NO_MEMORY;
591 return NT_STATUS_OK;
594 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
596 if (gensec_security->target.service) {
597 return gensec_security->target.service;
600 return "host";
604 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
608 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
610 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
611 if (hostname && !gensec_security->target.hostname) {
612 return NT_STATUS_NO_MEMORY;
614 return NT_STATUS_OK;
617 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
619 /* We allow the target hostname to be overriden for testing purposes */
620 if (gensec_security->settings->target_hostname) {
621 return gensec_security->settings->target_hostname;
624 if (gensec_security->target.hostname) {
625 return gensec_security->target.hostname;
628 /* We could add use the 'set sockaddr' call, and do a reverse
629 * lookup, but this would be both insecure (compromising the
630 * way kerberos works) and add DNS timeouts */
631 return NULL;
635 * Set (and copy) local and peer socket addresses onto a socket
636 * context on the GENSEC context.
638 * This is so that kerberos can include these addresses in
639 * cryptographic tokens, to avoid certain attacks.
643 * @brief Set the local gensec address.
645 * @param gensec_security The gensec security context to use.
647 * @param remote The local address to set.
649 * @return On success NT_STATUS_OK is returned or an NT_STATUS
650 * error.
652 _PUBLIC_ NTSTATUS gensec_set_local_address(struct gensec_security *gensec_security,
653 const struct tsocket_address *local)
655 TALLOC_FREE(gensec_security->local_addr);
657 if (local == NULL) {
658 return NT_STATUS_OK;
661 gensec_security->local_addr = tsocket_address_copy(local, gensec_security);
662 if (gensec_security->local_addr == NULL) {
663 return NT_STATUS_NO_MEMORY;
666 return NT_STATUS_OK;
670 * @brief Set the remote gensec address.
672 * @param gensec_security The gensec security context to use.
674 * @param remote The remote address to set.
676 * @return On success NT_STATUS_OK is returned or an NT_STATUS
677 * error.
679 _PUBLIC_ NTSTATUS gensec_set_remote_address(struct gensec_security *gensec_security,
680 const struct tsocket_address *remote)
682 TALLOC_FREE(gensec_security->remote_addr);
684 if (remote == NULL) {
685 return NT_STATUS_OK;
688 gensec_security->remote_addr = tsocket_address_copy(remote, gensec_security);
689 if (gensec_security->remote_addr == NULL) {
690 return NT_STATUS_NO_MEMORY;
693 return NT_STATUS_OK;
697 * @brief Get the local address from a gensec security context.
699 * @param gensec_security The security context to get the address from.
701 * @return The address as tsocket_address which could be NULL if
702 * no address is set.
704 _PUBLIC_ const struct tsocket_address *gensec_get_local_address(struct gensec_security *gensec_security)
706 if (gensec_security == NULL) {
707 return NULL;
709 return gensec_security->local_addr;
713 * @brief Get the remote address from a gensec security context.
715 * @param gensec_security The security context to get the address from.
717 * @return The address as tsocket_address which could be NULL if
718 * no address is set.
720 _PUBLIC_ const struct tsocket_address *gensec_get_remote_address(struct gensec_security *gensec_security)
722 if (gensec_security == NULL) {
723 return NULL;
725 return gensec_security->remote_addr;
729 * Set the target principal (assuming it it known, say from the SPNEGO reply)
730 * - ensures it is talloc()ed
734 _PUBLIC_ NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
736 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
737 if (!gensec_security->target.principal) {
738 return NT_STATUS_NO_MEMORY;
740 return NT_STATUS_OK;
743 _PUBLIC_ const char *gensec_get_target_principal(struct gensec_security *gensec_security)
745 if (gensec_security->target.principal) {
746 return gensec_security->target.principal;
749 return NULL;