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/>.
24 #include "auth/auth.h"
25 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "param/param.h"
32 /* the list of currently registered GENSEC backends */
33 static struct gensec_security_ops **generic_security_ops;
34 static int gensec_num_backends;
36 /* Return all the registered mechs. Don't modify the return pointer,
37 * but you may talloc_reference it if convient */
38 struct gensec_security_ops **gensec_security_all(void)
40 return generic_security_ops;
43 /* Sometimes we want to force only kerberos, sometimes we want to
44 * force it's avoidance. The old list could be either
45 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
46 * an existing list we have trimmed down) */
48 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
49 struct gensec_security_ops **old_gensec_list,
50 struct cli_credentials *creds)
52 struct gensec_security_ops **new_gensec_list;
53 int i, j, num_mechs_in;
54 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
57 use_kerberos = cli_credentials_get_kerberos_state(creds);
60 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
61 if (!talloc_reference(mem_ctx, old_gensec_list)) {
64 return old_gensec_list;
67 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
71 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
72 if (!new_gensec_list) {
77 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
79 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
80 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
81 new_gensec_list[j] = old_gensec_list[i];
86 switch (use_kerberos) {
87 case CRED_DONT_USE_KERBEROS:
88 if (old_gensec_list[i]->kerberos == False) {
89 new_gensec_list[j] = old_gensec_list[i];
93 case CRED_MUST_USE_KERBEROS:
94 if (old_gensec_list[i]->kerberos == True) {
95 new_gensec_list[j] = old_gensec_list[i];
100 /* Can't happen or invalid parameter */
104 new_gensec_list[j] = NULL;
106 return new_gensec_list;
109 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
112 struct gensec_security_ops **backends;
113 backends = gensec_security_all();
114 if (!gensec_security) {
115 if (!talloc_reference(mem_ctx, backends)) {
120 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
122 if (!talloc_reference(mem_ctx, backends)) {
127 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
131 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
135 struct gensec_security_ops **backends;
136 const struct gensec_security_ops *backend;
137 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
141 backends = gensec_security_mechs(gensec_security, mem_ctx);
142 for (i=0; backends && backends[i]; i++) {
143 if (backends[i]->auth_type == auth_type) {
144 backend = backends[i];
145 talloc_free(mem_ctx);
149 talloc_free(mem_ctx);
154 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
155 const char *oid_string)
158 struct gensec_security_ops **backends;
159 const struct gensec_security_ops *backend;
160 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
164 backends = gensec_security_mechs(gensec_security, mem_ctx);
165 for (i=0; backends && backends[i]; i++) {
166 if (backends[i]->oid) {
167 for (j=0; backends[i]->oid[j]; j++) {
168 if (backends[i]->oid[j] &&
169 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
170 backend = backends[i];
171 talloc_free(mem_ctx);
177 talloc_free(mem_ctx);
182 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
183 const char *sasl_name)
186 struct gensec_security_ops **backends;
187 const struct gensec_security_ops *backend;
188 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
192 backends = gensec_security_mechs(gensec_security, mem_ctx);
193 for (i=0; backends && backends[i]; i++) {
194 if (backends[i]->sasl_name
195 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
196 backend = backends[i];
197 talloc_free(mem_ctx);
201 talloc_free(mem_ctx);
206 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
210 struct gensec_security_ops **backends;
211 const struct gensec_security_ops *backend;
212 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
216 backends = gensec_security_mechs(gensec_security, mem_ctx);
217 for (i=0; backends && backends[i]; i++) {
218 if (backends[i]->name
219 && (strcmp(backends[i]->name, name) == 0)) {
220 backend = backends[i];
221 talloc_free(mem_ctx);
225 talloc_free(mem_ctx);
230 * Return a unique list of security subsystems from those specified in
231 * the list of SASL names.
233 * Use the list of enabled GENSEC mechanisms from the credentials
234 * attached to the gensec_security, and return in our preferred order.
237 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
239 const char **sasl_names)
241 const struct gensec_security_ops **backends_out;
242 struct gensec_security_ops **backends;
244 int num_backends_out = 0;
250 backends = gensec_security_mechs(gensec_security, mem_ctx);
252 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
256 backends_out[0] = NULL;
258 /* Find backends in our preferred order, by walking our list,
259 * then looking in the supplied list */
260 for (i=0; backends && backends[i]; i++) {
261 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
262 if (!backends[i]->sasl_name ||
263 !(strcmp(backends[i]->sasl_name,
264 sasl_names[sasl_idx]) == 0)) {
268 for (k=0; backends_out[k]; k++) {
269 if (backends_out[k] == backends[i]) {
274 if (k < num_backends_out) {
275 /* already in there */
279 backends_out = talloc_realloc(mem_ctx, backends_out,
280 const struct gensec_security_ops *,
281 num_backends_out + 2);
286 backends_out[num_backends_out] = backends[i];
288 backends_out[num_backends_out] = NULL;
295 * Return a unique list of security subsystems from those specified in
296 * the OID list. That is, where two OIDs refer to the same module,
297 * return that module only once.
299 * Use the list of enabled GENSEC mechanisms from the credentials
300 * attached to the gensec_security, and return in our preferred order.
303 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
305 const char **oid_strings,
308 struct gensec_security_ops_wrapper *backends_out;
309 struct gensec_security_ops **backends;
310 int i, j, k, oid_idx;
311 int num_backends_out = 0;
317 backends = gensec_security_mechs(gensec_security, gensec_security);
319 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
323 backends_out[0].op = NULL;
324 backends_out[0].oid = NULL;
326 /* Find backends in our preferred order, by walking our list,
327 * then looking in the supplied list */
328 for (i=0; backends && backends[i]; i++) {
329 if (!backends[i]->oid) {
332 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
333 if (strcmp(oid_strings[oid_idx], skip) == 0) {
337 for (j=0; backends[i]->oid[j]; j++) {
338 if (!backends[i]->oid[j] ||
339 !(strcmp(backends[i]->oid[j],
340 oid_strings[oid_idx]) == 0)) {
344 for (k=0; backends_out[k].op; k++) {
345 if (backends_out[k].op == backends[i]) {
350 if (k < num_backends_out) {
351 /* already in there */
355 backends_out = talloc_realloc(mem_ctx, backends_out,
356 struct gensec_security_ops_wrapper,
357 num_backends_out + 2);
362 backends_out[num_backends_out].op = backends[i];
363 backends_out[num_backends_out].oid = backends[i]->oid[j];
365 backends_out[num_backends_out].op = NULL;
366 backends_out[num_backends_out].oid = NULL;
374 * Return OIDS from the security subsystems listed
377 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
378 struct gensec_security_ops **ops,
384 const char **oid_list;
388 oid_list = talloc_array(mem_ctx, const char *, 1);
393 for (i=0; ops && ops[i]; i++) {
398 for (k = 0; ops[i]->oid[k]; k++) {
399 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
401 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
405 oid_list[j] = ops[i]->oid[k];
416 * Return OIDS from the security subsystems listed
419 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
420 const struct gensec_security_ops_wrapper *wops)
425 const char **oid_list;
429 oid_list = talloc_array(mem_ctx, const char *, 1);
434 for (i=0; wops[i].op; i++) {
435 if (!wops[i].op->oid) {
439 for (k = 0; wops[i].op->oid[k]; k++) {
440 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
444 oid_list[j] = wops[i].op->oid[k];
454 * Return all the security subsystems currently enabled on a GENSEC context.
456 * This is taken from a list attached to the cli_credentails, and
457 * skips the OID in 'skip'. (Typically the SPNEGO OID)
461 const char **gensec_security_oids(struct gensec_security *gensec_security,
465 struct gensec_security_ops **ops
466 = gensec_security_mechs(gensec_security, mem_ctx);
467 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
473 Start the GENSEC system, returning a context pointer.
474 @param mem_ctx The parent TALLOC memory context.
475 @param gensec_security Returned GENSEC context pointer.
476 @note The mem_ctx is only a parent and may be NULL.
478 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
479 struct event_context *ev,
480 struct messaging_context *msg,
481 struct gensec_security **gensec_security)
483 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
484 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
486 (*gensec_security)->ops = NULL;
488 ZERO_STRUCT((*gensec_security)->target);
489 ZERO_STRUCT((*gensec_security)->peer_addr);
490 ZERO_STRUCT((*gensec_security)->my_addr);
492 (*gensec_security)->subcontext = False;
493 (*gensec_security)->want_features = 0;
496 ev = event_context_init(*gensec_security);
498 talloc_free(*gensec_security);
499 return NT_STATUS_NO_MEMORY;
503 (*gensec_security)->event_ctx = ev;
504 (*gensec_security)->msg_ctx = msg;
510 * Start a GENSEC subcontext, with a copy of the properties of the parent
511 * @param mem_ctx The parent TALLOC memory context.
512 * @param parent The parent GENSEC context
513 * @param gensec_security Returned GENSEC context pointer.
514 * @note Used by SPNEGO in particular, for the actual implementation mechanism
517 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
518 struct gensec_security *parent,
519 struct gensec_security **gensec_security)
521 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
522 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
524 (**gensec_security) = *parent;
525 (*gensec_security)->ops = NULL;
526 (*gensec_security)->private_data = NULL;
528 (*gensec_security)->subcontext = True;
529 (*gensec_security)->event_ctx = parent->event_ctx;
530 (*gensec_security)->msg_ctx = parent->msg_ctx;
536 Start the GENSEC system, in client mode, returning a context pointer.
537 @param mem_ctx The parent TALLOC memory context.
538 @param gensec_security Returned GENSEC context pointer.
539 @note The mem_ctx is only a parent and may be NULL.
541 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
542 struct gensec_security **gensec_security,
543 struct event_context *ev)
546 struct event_context *new_ev = NULL;
549 new_ev = event_context_init(mem_ctx);
550 NT_STATUS_HAVE_NO_MEMORY(new_ev);
554 status = gensec_start(mem_ctx, ev, NULL, gensec_security);
555 if (!NT_STATUS_IS_OK(status)) {
559 talloc_steal((*gensec_security), new_ev);
560 (*gensec_security)->gensec_role = GENSEC_CLIENT;
566 Start the GENSEC system, in server mode, returning a context pointer.
567 @param mem_ctx The parent TALLOC memory context.
568 @param gensec_security Returned GENSEC context pointer.
569 @note The mem_ctx is only a parent and may be NULL.
571 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
572 struct event_context *ev,
573 struct messaging_context *msg,
574 struct gensec_security **gensec_security)
579 DEBUG(0,("gensec_server_start: no event context given!\n"));
580 return NT_STATUS_INTERNAL_ERROR;
584 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
585 return NT_STATUS_INTERNAL_ERROR;
588 status = gensec_start(mem_ctx, ev, msg, gensec_security);
589 if (!NT_STATUS_IS_OK(status)) {
592 (*gensec_security)->gensec_role = GENSEC_SERVER;
597 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
600 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
601 gensec_security->subcontext ? "sub" : "",
602 gensec_security->ops->name));
603 switch (gensec_security->gensec_role) {
605 if (gensec_security->ops->client_start) {
606 status = gensec_security->ops->client_start(gensec_security);
607 if (!NT_STATUS_IS_OK(status)) {
608 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
609 gensec_security->ops->name, nt_errstr(status)));
615 if (gensec_security->ops->server_start) {
616 status = gensec_security->ops->server_start(gensec_security);
617 if (!NT_STATUS_IS_OK(status)) {
618 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
619 gensec_security->ops->name, nt_errstr(status)));
625 return NT_STATUS_INVALID_PARAMETER;
629 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
630 * @param gensec_security GENSEC context pointer.
631 * @param auth_type DCERPC auth type
632 * @param auth_level DCERPC auth level
635 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
636 uint8_t auth_type, uint8_t auth_level)
638 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
639 if (!gensec_security->ops) {
640 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
641 return NT_STATUS_INVALID_PARAMETER;
643 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
644 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
645 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
646 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
647 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
648 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
649 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
650 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
651 /* Default features */
653 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
655 return NT_STATUS_INVALID_PARAMETER;
658 return gensec_start_mech(gensec_security);
661 const char *gensec_get_name_by_authtype(uint8_t authtype)
663 const struct gensec_security_ops *ops;
664 ops = gensec_security_by_authtype(NULL, authtype);
672 const char *gensec_get_name_by_oid(const char *oid_string)
674 const struct gensec_security_ops *ops;
675 ops = gensec_security_by_oid(NULL, oid_string);
684 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
688 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
689 const struct gensec_security_ops *ops)
691 gensec_security->ops = ops;
692 return gensec_start_mech(gensec_security);
696 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
698 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
699 * well-known #define to hook it in.
702 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
703 const char *mech_oid)
705 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
706 if (!gensec_security->ops) {
707 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
708 return NT_STATUS_INVALID_PARAMETER;
710 return gensec_start_mech(gensec_security);
714 * Start a GENSEC sub-mechanism by a well know SASL name
718 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
719 const char *sasl_name)
721 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
722 if (!gensec_security->ops) {
723 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
724 return NT_STATUS_INVALID_PARAMETER;
726 return gensec_start_mech(gensec_security);
730 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
734 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
735 const char **sasl_names)
737 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
738 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
739 const struct gensec_security_ops **ops;
742 return NT_STATUS_NO_MEMORY;
744 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
746 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
747 str_list_join(mem_ctx,
749 talloc_free(mem_ctx);
750 return NT_STATUS_INVALID_PARAMETER;
752 for (i=0; ops[i]; i++) {
753 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
754 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
758 talloc_free(mem_ctx);
763 * Start a GENSEC sub-mechanism by an internal name
767 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
770 gensec_security->ops = gensec_security_by_name(gensec_security, name);
771 if (!gensec_security->ops) {
772 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
773 return NT_STATUS_INVALID_PARAMETER;
775 return gensec_start_mech(gensec_security);
779 wrappers for the gensec function pointers
781 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
783 uint8_t *data, size_t length,
784 const uint8_t *whole_pdu, size_t pdu_length,
785 const DATA_BLOB *sig)
787 if (!gensec_security->ops->unseal_packet) {
788 return NT_STATUS_NOT_IMPLEMENTED;
790 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
791 return NT_STATUS_INVALID_PARAMETER;
794 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
796 whole_pdu, pdu_length,
800 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
802 const uint8_t *data, size_t length,
803 const uint8_t *whole_pdu, size_t pdu_length,
804 const DATA_BLOB *sig)
806 if (!gensec_security->ops->check_packet) {
807 return NT_STATUS_NOT_IMPLEMENTED;
809 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
810 return NT_STATUS_INVALID_PARAMETER;
813 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
816 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
818 uint8_t *data, size_t length,
819 const uint8_t *whole_pdu, size_t pdu_length,
822 if (!gensec_security->ops->seal_packet) {
823 return NT_STATUS_NOT_IMPLEMENTED;
825 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
826 return NT_STATUS_INVALID_PARAMETER;
829 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
832 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
834 const uint8_t *data, size_t length,
835 const uint8_t *whole_pdu, size_t pdu_length,
838 if (!gensec_security->ops->sign_packet) {
839 return NT_STATUS_NOT_IMPLEMENTED;
841 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
842 return NT_STATUS_INVALID_PARAMETER;
845 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
848 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
850 if (!gensec_security->ops->sig_size) {
853 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
857 return gensec_security->ops->sig_size(gensec_security, data_size);
860 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
862 if (!gensec_security->ops->max_wrapped_size) {
866 return gensec_security->ops->max_wrapped_size(gensec_security);
869 size_t gensec_max_input_size(struct gensec_security *gensec_security)
871 if (!gensec_security->ops->max_input_size) {
872 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
875 return gensec_security->ops->max_input_size(gensec_security);
878 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
883 if (!gensec_security->ops->wrap) {
884 return NT_STATUS_NOT_IMPLEMENTED;
886 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
889 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
894 if (!gensec_security->ops->unwrap) {
895 return NT_STATUS_NOT_IMPLEMENTED;
897 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
900 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
901 DATA_BLOB *session_key)
903 if (!gensec_security->ops->session_key) {
904 return NT_STATUS_NOT_IMPLEMENTED;
906 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
907 return NT_STATUS_NO_USER_SESSION_KEY;
910 return gensec_security->ops->session_key(gensec_security, session_key);
914 * Return the credentials of a logged on user, including session keys
917 * Only valid after a successful authentication
919 * May only be called once per authentication.
923 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
924 struct auth_session_info **session_info)
926 if (!gensec_security->ops->session_info) {
927 return NT_STATUS_NOT_IMPLEMENTED;
929 return gensec_security->ops->session_info(gensec_security, session_info);
933 * Next state function for the GENSEC state machine
935 * @param gensec_security GENSEC State
936 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
937 * @param in The request, as a DATA_BLOB
938 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
939 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
940 * or NT_STATUS_OK if the user is authenticated.
943 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
944 const DATA_BLOB in, DATA_BLOB *out)
946 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
949 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
950 struct timeval t, void *ptr)
952 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
953 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
954 req->callback.fn(req, req->callback.private_data);
958 * Next state function for the GENSEC state machine async version
960 * @param gensec_security GENSEC State
961 * @param in The request, as a DATA_BLOB
962 * @param callback The function that will be called when the operation is
963 * finished, it should return gensec_update_recv() to get output
964 * @param private_data A private pointer that will be passed to the callback function
967 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
968 void (*callback)(struct gensec_update_request *req, void *private_data),
971 struct gensec_update_request *req = NULL;
972 struct timed_event *te = NULL;
974 req = talloc(gensec_security, struct gensec_update_request);
975 if (!req) goto failed;
976 req->gensec_security = gensec_security;
978 req->out = data_blob(NULL, 0);
979 req->callback.fn = callback;
980 req->callback.private_data = private_data;
982 te = event_add_timed(gensec_security->event_ctx, req,
984 gensec_update_async_timed_handler, req);
985 if (!te) goto failed;
991 callback(NULL, private_data);
995 * Next state function for the GENSEC state machine
997 * @param req GENSEC update request state
998 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
999 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1000 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1001 * or NT_STATUS_OK if the user is authenticated.
1003 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1007 NT_STATUS_HAVE_NO_MEMORY(req);
1010 talloc_steal(out_mem_ctx, out->data);
1011 status = req->status;
1018 * Set the requirement for a certain feature on the connection
1022 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1025 gensec_security->want_features |= feature;
1029 * Check the requirement for a certain feature on the connection
1033 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
1036 if (!gensec_security->ops->have_feature) {
1040 /* We might 'have' features that we don't 'want', because the
1041 * other end demanded them, or we can't neotiate them off */
1042 return gensec_security->ops->have_feature(gensec_security, feature);
1046 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1050 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1052 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1053 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1054 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1055 return NT_STATUS_OK;
1059 * Return the credentials structure associated with a GENSEC context
1063 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1065 if (!gensec_security) {
1068 return gensec_security->credentials;
1072 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1076 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1078 gensec_security->target.service = talloc_strdup(gensec_security, service);
1079 if (!gensec_security->target.service) {
1080 return NT_STATUS_NO_MEMORY;
1082 return NT_STATUS_OK;
1085 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1087 if (gensec_security->target.service) {
1088 return gensec_security->target.service;
1095 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1099 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1101 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1102 if (hostname && !gensec_security->target.hostname) {
1103 return NT_STATUS_NO_MEMORY;
1105 return NT_STATUS_OK;
1108 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1110 /* We allow the target hostname to be overriden for testing purposes */
1111 const char *target_hostname = lp_parm_string(global_loadparm, NULL, "gensec", "target_hostname");
1112 if (target_hostname) {
1113 return target_hostname;
1116 if (gensec_security->target.hostname) {
1117 return gensec_security->target.hostname;
1120 /* We could add use the 'set sockaddr' call, and do a reverse
1121 * lookup, but this would be both insecure (compromising the
1122 * way kerberos works) and add DNS timeouts */
1127 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1129 * This is so that kerberos can include these addresses in
1130 * cryptographic tokens, to avoid certain attacks.
1133 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1135 gensec_security->my_addr = my_addr;
1136 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1137 return NT_STATUS_NO_MEMORY;
1139 return NT_STATUS_OK;
1142 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1144 gensec_security->peer_addr = peer_addr;
1145 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1146 return NT_STATUS_NO_MEMORY;
1148 return NT_STATUS_OK;
1151 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1153 if (gensec_security->my_addr) {
1154 return gensec_security->my_addr;
1157 /* We could add a 'set sockaddr' call, and do a lookup. This
1158 * would avoid needing to do system calls if nothing asks. */
1162 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1164 if (gensec_security->peer_addr) {
1165 return gensec_security->peer_addr;
1168 /* We could add a 'set sockaddr' call, and do a lookup. This
1169 * would avoid needing to do system calls if nothing asks.
1170 * However, this is not appropriate for the peer addres on
1171 * datagram sockets */
1178 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1179 * - ensures it is talloc()ed
1183 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1185 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1186 if (!gensec_security->target.principal) {
1187 return NT_STATUS_NO_MEMORY;
1189 return NT_STATUS_OK;
1192 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1194 if (gensec_security->target.principal) {
1195 return gensec_security->target.principal;
1202 register a GENSEC backend.
1204 The 'name' can be later used by other backends to find the operations
1205 structure for this backend.
1207 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1209 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1210 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1211 return NT_STATUS_OK;
1214 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1215 /* its already registered! */
1216 DEBUG(0,("GENSEC backend '%s' already registered\n",
1218 return NT_STATUS_OBJECT_NAME_COLLISION;
1221 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1222 generic_security_ops,
1223 struct gensec_security_ops *,
1224 gensec_num_backends+2);
1225 if (!generic_security_ops) {
1226 return NT_STATUS_NO_MEMORY;
1229 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1230 gensec_num_backends++;
1231 generic_security_ops[gensec_num_backends] = NULL;
1233 DEBUG(3,("GENSEC backend '%s' registered\n",
1236 return NT_STATUS_OK;
1240 return the GENSEC interface version, and the size of some critical types
1241 This can be used by backends to either detect compilation errors, or provide
1242 multiple implementations for different smbd compilation options in one module
1244 const struct gensec_critical_sizes *gensec_interface_version(void)
1246 static const struct gensec_critical_sizes critical_sizes = {
1247 GENSEC_INTERFACE_VERSION,
1248 sizeof(struct gensec_security_ops),
1249 sizeof(struct gensec_security),
1252 return &critical_sizes;
1255 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1256 return (*gs2)->priority - (*gs1)->priority;
1260 initialise the GENSEC subsystem
1262 NTSTATUS gensec_init(void)
1264 static BOOL initialized = False;
1266 init_module_fn static_init[] = STATIC_gensec_MODULES;
1267 init_module_fn *shared_init;
1269 if (initialized) return NT_STATUS_OK;
1272 shared_init = load_samba_modules(NULL, global_loadparm, "gensec");
1274 run_init_functions(static_init);
1275 run_init_functions(shared_init);
1277 talloc_free(shared_init);
1279 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1281 return NT_STATUS_OK;