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 "system/network.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "librpc/gen_ndr/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "lib/param/param.h"
32 #include "lib/util/tsort.h"
33 #include "lib/util/samba_modules.h"
34 #include "lib/util/base64.h"
35 #include "lib/crypto/gnutls_helpers.h"
38 #define DBGC_CLASS DBGC_AUTH
40 /* the list of currently registered GENSEC backends */
41 static const struct gensec_security_ops **generic_security_ops;
42 static int gensec_num_backends;
44 /* Return all the registered mechs. Don't modify the return pointer,
45 * but you may talloc_referen it if convient */
46 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
48 return generic_security_ops;
51 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
53 bool ok = lpcfg_parm_bool(security->settings->lp_ctx,
59 if (!samba_gnutls_weak_crypto_allowed() && ops->weak_crypto) {
66 /* Sometimes we want to force only kerberos, sometimes we want to
67 * force it's avoidance. The old list could be either
68 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
69 * an existing list we have trimmed down)
71 * The intended logic is:
73 * if we are in the default AUTO have kerberos:
74 * - take a reference to the master list
76 * - always add spnego then:
77 * - if we 'MUST' have kerberos:
78 * only add kerberos mechs
79 * - if we 'DONT' want kerberos':
80 * only add non-kerberos mechs
82 * Once we get things like NegoEx or moonshot, this will of course get
86 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
87 const struct gensec_security_ops * const *old_gensec_list,
88 struct cli_credentials *creds)
90 const struct gensec_security_ops **new_gensec_list;
91 int i, j, num_mechs_in;
92 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
93 bool keep_schannel = false;
96 use_kerberos = cli_credentials_get_kerberos_state(creds);
97 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
102 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
106 new_gensec_list = talloc_array(mem_ctx,
107 const struct gensec_security_ops *,
109 if (!new_gensec_list) {
114 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
118 * We want to keep SPNGEO and other backends
120 keep = old_gensec_list[i]->glue;
122 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
123 keep = keep_schannel;
126 switch (use_kerberos) {
127 case CRED_AUTO_USE_KERBEROS:
131 case CRED_DONT_USE_KERBEROS:
132 if (old_gensec_list[i]->kerberos == false) {
138 case CRED_MUST_USE_KERBEROS:
139 if (old_gensec_list[i]->kerberos == true) {
145 /* Can't happen or invalid parameter */
153 new_gensec_list[j] = old_gensec_list[i];
156 new_gensec_list[j] = NULL;
158 return new_gensec_list;
161 _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
162 struct gensec_security *gensec_security,
165 struct cli_credentials *creds = NULL;
166 const struct gensec_security_ops * const *backends = gensec_security_all();
168 if (gensec_security != NULL) {
169 creds = gensec_get_credentials(gensec_security);
171 if (gensec_security->settings->backends) {
172 backends = gensec_security->settings->backends;
176 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
180 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
181 struct gensec_security *gensec_security,
182 const char *oid_string)
185 const struct gensec_security_ops **backends;
186 const struct gensec_security_ops *backend;
187 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
191 backends = gensec_security_mechs(gensec_security, mem_ctx);
192 for (i=0; backends && backends[i]; i++) {
193 if (gensec_security != NULL &&
194 !gensec_security_ops_enabled(backends[i],
197 if (backends[i]->oid) {
198 for (j=0; backends[i]->oid[j]; j++) {
199 if (backends[i]->oid[j] &&
200 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
201 backend = backends[i];
202 talloc_free(mem_ctx);
208 talloc_free(mem_ctx);
213 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
214 struct gensec_security *gensec_security,
215 const char *sasl_name)
218 const struct gensec_security_ops **backends;
219 const struct gensec_security_ops *backend;
220 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
224 backends = gensec_security_mechs(gensec_security, mem_ctx);
225 for (i=0; backends && backends[i]; i++) {
226 if (gensec_security != NULL &&
227 !gensec_security_ops_enabled(backends[i], gensec_security)) {
230 if (backends[i]->sasl_name
231 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
232 backend = backends[i];
233 talloc_free(mem_ctx);
237 talloc_free(mem_ctx);
242 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
243 struct gensec_security *gensec_security,
247 const struct gensec_security_ops **backends;
248 const struct gensec_security_ops *backend;
251 if (auth_type == DCERPC_AUTH_TYPE_NONE) {
255 mem_ctx = talloc_new(gensec_security);
259 backends = gensec_security_mechs(gensec_security, mem_ctx);
260 for (i=0; backends && backends[i]; i++) {
261 if (gensec_security != NULL &&
262 !gensec_security_ops_enabled(backends[i], gensec_security)) {
265 if (backends[i]->auth_type == auth_type) {
266 backend = backends[i];
267 talloc_free(mem_ctx);
271 talloc_free(mem_ctx);
276 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
280 const struct gensec_security_ops **backends;
281 const struct gensec_security_ops *backend;
282 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
286 backends = gensec_security_mechs(gensec_security, mem_ctx);
287 for (i=0; backends && backends[i]; i++) {
288 if (gensec_security != NULL &&
289 !gensec_security_ops_enabled(backends[i], gensec_security))
291 if (backends[i]->name
292 && (strcmp(backends[i]->name, name) == 0)) {
293 backend = backends[i];
294 talloc_free(mem_ctx);
298 talloc_free(mem_ctx);
303 * Return a unique list of security subsystems from those specified in
304 * the list of SASL names.
306 * Use the list of enabled GENSEC mechanisms from the credentials
307 * attached to the gensec_security, and return in our preferred order.
310 static const struct gensec_security_ops **gensec_security_by_sasl_list(
311 struct gensec_security *gensec_security,
313 const char **sasl_names)
315 const struct gensec_security_ops **backends_out;
316 const struct gensec_security_ops **backends;
318 int num_backends_out = 0;
324 backends = gensec_security_mechs(gensec_security, mem_ctx);
326 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
330 backends_out[0] = NULL;
332 /* Find backends in our preferred order, by walking our list,
333 * then looking in the supplied list */
334 for (i=0; backends && backends[i]; i++) {
335 if (gensec_security != NULL &&
336 !gensec_security_ops_enabled(backends[i], gensec_security))
338 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
339 if (!backends[i]->sasl_name ||
340 !(strcmp(backends[i]->sasl_name,
341 sasl_names[sasl_idx]) == 0)) {
345 for (k=0; backends_out[k]; k++) {
346 if (backends_out[k] == backends[i]) {
351 if (k < num_backends_out) {
352 /* already in there */
356 backends_out = talloc_realloc(mem_ctx, backends_out,
357 const struct gensec_security_ops *,
358 num_backends_out + 2);
363 backends_out[num_backends_out] = backends[i];
365 backends_out[num_backends_out] = NULL;
372 * Return a unique list of security subsystems from those specified in
373 * the OID list. That is, where two OIDs refer to the same module,
374 * return that module only once.
376 * Use the list of enabled GENSEC mechanisms from the credentials
377 * attached to the gensec_security, and return in our preferred order.
380 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
381 struct gensec_security *gensec_security,
383 const char * const *oid_strings,
386 struct gensec_security_ops_wrapper *backends_out;
387 const struct gensec_security_ops **backends;
388 int i, j, k, oid_idx;
389 int num_backends_out = 0;
395 backends = gensec_security_mechs(gensec_security, gensec_security);
397 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
401 backends_out[0].op = NULL;
402 backends_out[0].oid = NULL;
404 /* Find backends in our preferred order, by walking our list,
405 * then looking in the supplied list */
406 for (i=0; backends && backends[i]; i++) {
407 if (gensec_security != NULL &&
408 !gensec_security_ops_enabled(backends[i], gensec_security))
410 if (!backends[i]->oid) {
413 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
414 if (strcmp(oid_strings[oid_idx], skip) == 0) {
418 for (j=0; backends[i]->oid[j]; j++) {
419 if (!backends[i]->oid[j] ||
420 !(strcmp(backends[i]->oid[j],
421 oid_strings[oid_idx]) == 0)) {
425 for (k=0; backends_out[k].op; k++) {
426 if (backends_out[k].op == backends[i]) {
431 if (k < num_backends_out) {
432 /* already in there */
436 backends_out = talloc_realloc(mem_ctx, backends_out,
437 struct gensec_security_ops_wrapper,
438 num_backends_out + 2);
443 backends_out[num_backends_out].op = backends[i];
444 backends_out[num_backends_out].oid = backends[i]->oid[j];
446 backends_out[num_backends_out].op = NULL;
447 backends_out[num_backends_out].oid = NULL;
455 * Return OIDS from the security subsystems listed
458 static const char **gensec_security_oids_from_ops(
459 struct gensec_security *gensec_security,
461 const struct gensec_security_ops * const *ops,
467 const char **oid_list;
471 oid_list = talloc_array(mem_ctx, const char *, 1);
476 for (i=0; ops && ops[i]; i++) {
477 if (gensec_security != NULL &&
478 !gensec_security_ops_enabled(ops[i], gensec_security)) {
485 for (k = 0; ops[i]->oid[k]; k++) {
486 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
488 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
492 oid_list[j] = ops[i]->oid[k];
503 * Return OIDS from the security subsystems listed
506 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
507 const struct gensec_security_ops_wrapper *wops)
512 const char **oid_list;
516 oid_list = talloc_array(mem_ctx, const char *, 1);
521 for (i=0; wops[i].op; i++) {
522 if (!wops[i].op->oid) {
526 for (k = 0; wops[i].op->oid[k]; k++) {
527 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
531 oid_list[j] = wops[i].op->oid[k];
541 * Return all the security subsystems currently enabled on a GENSEC context.
543 * This is taken from a list attached to the cli_credentials, and
544 * skips the OID in 'skip'. (Typically the SPNEGO OID)
548 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
552 const struct gensec_security_ops **ops;
554 ops = gensec_security_mechs(gensec_security, mem_ctx);
556 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
559 static int gensec_security_destructor(struct gensec_security *gctx)
561 if (gctx->parent_security != NULL) {
562 if (gctx->parent_security->child_security == gctx) {
563 gctx->parent_security->child_security = NULL;
565 gctx->parent_security = NULL;
568 if (gctx->child_security != NULL) {
569 if (gctx->child_security->parent_security == gctx) {
570 gctx->child_security->parent_security = NULL;
572 gctx->child_security = NULL;
579 Start the GENSEC system, returning a context pointer.
580 @param mem_ctx The parent TALLOC memory context.
581 @param gensec_security Returned GENSEC context pointer.
582 @note The mem_ctx is only a parent and may be NULL.
583 @note, the auth context is moved to be a referenced pointer of the
584 @ gensec_security return
586 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
587 struct gensec_settings *settings,
588 struct auth4_context *auth_context,
589 struct gensec_security **gensec_security)
591 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
592 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
594 (*gensec_security)->max_update_size = 0;
596 SMB_ASSERT(settings->lp_ctx != NULL);
597 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
599 /* We need to reference this, not steal, as the caller may be
600 * python, which won't like it if we steal it's object away
602 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
604 talloc_set_destructor((*gensec_security), gensec_security_destructor);
609 * Start a GENSEC subcontext, with a copy of the properties of the parent
610 * @param mem_ctx The parent TALLOC memory context.
611 * @param parent The parent GENSEC context
612 * @param gensec_security Returned GENSEC context pointer.
613 * @note Used by SPNEGO in particular, for the actual implementation mechanism
616 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
617 struct gensec_security *parent,
618 struct gensec_security **gensec_security)
620 if (parent->child_security != NULL) {
621 return NT_STATUS_INTERNAL_ERROR;
624 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
625 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
627 (**gensec_security) = *parent;
628 (*gensec_security)->ops = NULL;
629 (*gensec_security)->private_data = NULL;
630 (*gensec_security)->update_busy_ptr = NULL;
632 (*gensec_security)->subcontext = true;
633 (*gensec_security)->want_features = parent->want_features;
634 (*gensec_security)->max_update_size = parent->max_update_size;
635 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
636 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
637 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
638 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
640 talloc_set_destructor((*gensec_security), gensec_security_destructor);
644 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
645 struct gensec_security *child)
647 if (parent->child_security != NULL) {
648 return NT_STATUS_INTERNAL_ERROR;
651 if (child->parent_security != NULL) {
652 return NT_STATUS_INTERNAL_ERROR;
655 parent->child_security = child;
656 child->parent_security = parent;
661 Start the GENSEC system, in client mode, returning a context pointer.
662 @param mem_ctx The parent TALLOC memory context.
663 @param gensec_security Returned GENSEC context pointer.
664 @note The mem_ctx is only a parent and may be NULL.
666 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
667 struct gensec_security **gensec_security,
668 struct gensec_settings *settings)
672 if (settings == NULL) {
673 DEBUG(0,("gensec_client_start: no settings given!\n"));
674 return NT_STATUS_INTERNAL_ERROR;
677 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
678 if (!NT_STATUS_IS_OK(status)) {
681 (*gensec_security)->gensec_role = GENSEC_CLIENT;
689 Start the GENSEC system, in server mode, returning a context pointer.
690 @param mem_ctx The parent TALLOC memory context.
691 @param gensec_security Returned GENSEC context pointer.
692 @note The mem_ctx is only a parent and may be NULL.
694 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
695 struct gensec_settings *settings,
696 struct auth4_context *auth_context,
697 struct gensec_security **gensec_security)
702 DEBUG(0,("gensec_server_start: no settings given!\n"));
703 return NT_STATUS_INTERNAL_ERROR;
706 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
707 if (!NT_STATUS_IS_OK(status)) {
710 (*gensec_security)->gensec_role = GENSEC_SERVER;
715 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
720 * Callers sometimes just reuse a context, we should
721 * clear the internal state before starting it again.
723 talloc_unlink(gensec_security, gensec_security->private_data);
724 gensec_security->private_data = NULL;
726 if (gensec_security->child_security != NULL) {
728 * The talloc_unlink(.., gensec_security->private_data)
729 * should have cleared this via
730 * gensec_security_destructor().
732 return NT_STATUS_INTERNAL_ERROR;
735 if (gensec_security->credentials) {
736 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
738 (gensec_security->ops->sasl_name == NULL ||
739 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
740 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
741 "did not match forced mechanism %s\n",
742 gensec_security->ops->name,
743 gensec_security->ops->sasl_name,
745 return NT_STATUS_INVALID_PARAMETER;
748 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
749 gensec_security->subcontext ? "sub" : "",
750 gensec_security->ops->name));
751 switch (gensec_security->gensec_role) {
753 if (gensec_security->ops->client_start) {
754 status = gensec_security->ops->client_start(gensec_security);
755 if (!NT_STATUS_IS_OK(status)) {
756 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
757 gensec_security->ops->name, nt_errstr(status)));
763 if (gensec_security->ops->server_start) {
764 status = gensec_security->ops->server_start(gensec_security);
765 if (!NT_STATUS_IS_OK(status)) {
766 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
767 gensec_security->ops->name, nt_errstr(status)));
773 return NT_STATUS_INVALID_PARAMETER;
777 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
781 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
782 const struct gensec_security_ops *ops)
784 gensec_security->ops = ops;
785 return gensec_start_mech(gensec_security);
790 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
791 * @param gensec_security GENSEC context pointer.
792 * @param auth_type DCERPC auth type
793 * @param auth_level DCERPC auth level
796 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
797 uint8_t auth_type, uint8_t auth_level)
799 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
800 if (!gensec_security->ops) {
801 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
802 return NT_STATUS_INVALID_PARAMETER;
804 gensec_security->dcerpc_auth_level = auth_level;
806 * We need to reset sign/seal in order to reset it.
807 * We may got some default features inherited by the credentials
809 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
810 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
811 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
812 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
813 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
814 if (gensec_security->gensec_role == GENSEC_CLIENT) {
815 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
817 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
819 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
820 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
822 if (gensec_security->gensec_role == GENSEC_CLIENT) {
823 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
825 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
826 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
827 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
828 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
829 /* Default features */
831 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
833 return NT_STATUS_INVALID_PARAMETER;
836 return gensec_start_mech(gensec_security);
839 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
841 const struct gensec_security_ops *ops;
842 ops = gensec_security_by_auth_type(gensec_security, authtype);
850 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
851 const char *oid_string)
853 const struct gensec_security_ops *ops;
854 ops = gensec_security_by_oid(gensec_security, oid_string);
862 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
864 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
865 * well-known #define to hook it in.
868 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
869 const char *mech_oid)
871 SMB_ASSERT(gensec_security != NULL);
873 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
874 if (!gensec_security->ops) {
875 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
876 return NT_STATUS_INVALID_PARAMETER;
878 return gensec_start_mech(gensec_security);
882 * Start a GENSEC sub-mechanism by a well know SASL name
886 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
887 const char *sasl_name)
889 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
890 if (!gensec_security->ops) {
891 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
892 return NT_STATUS_INVALID_PARAMETER;
894 return gensec_start_mech(gensec_security);
898 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
902 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
903 const char **sasl_names)
905 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
906 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
907 const struct gensec_security_ops **ops;
910 return NT_STATUS_NO_MEMORY;
912 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
914 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
915 str_list_join(mem_ctx,
917 talloc_free(mem_ctx);
918 return NT_STATUS_INVALID_PARAMETER;
920 for (i=0; ops[i]; i++) {
921 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
922 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
926 talloc_free(mem_ctx);
931 * Start a GENSEC sub-mechanism by an internal name
935 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
938 gensec_security->ops = gensec_security_by_name(gensec_security, name);
939 if (!gensec_security->ops) {
940 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
941 return NT_STATUS_INVALID_PARAMETER;
943 return gensec_start_mech(gensec_security);
947 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
951 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
953 gensec_security->credentials = talloc_reference(gensec_security, credentials);
954 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
955 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
960 register a GENSEC backend.
962 The 'name' can be later used by other backends to find the operations
963 structure for this backend.
965 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
966 const struct gensec_security_ops *ops)
968 if (gensec_security_by_name(NULL, ops->name) != NULL) {
969 /* its already registered! */
970 DEBUG(0,("GENSEC backend '%s' already registered\n",
972 return NT_STATUS_OBJECT_NAME_COLLISION;
975 generic_security_ops = talloc_realloc(ctx,
976 generic_security_ops,
977 const struct gensec_security_ops *,
978 gensec_num_backends+2);
979 if (!generic_security_ops) {
980 return NT_STATUS_NO_MEMORY;
983 generic_security_ops[gensec_num_backends] = ops;
984 gensec_num_backends++;
985 generic_security_ops[gensec_num_backends] = NULL;
987 DEBUG(3,("GENSEC backend '%s' registered\n",
994 return the GENSEC interface version, and the size of some critical types
995 This can be used by backends to either detect compilation errors, or provide
996 multiple implementations for different smbd compilation options in one module
998 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
1000 static const struct gensec_critical_sizes critical_sizes = {
1001 GENSEC_INTERFACE_VERSION,
1002 sizeof(struct gensec_security_ops),
1003 sizeof(struct gensec_security),
1006 return &critical_sizes;
1009 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
1010 return (*gs2)->priority - (*gs1)->priority;
1013 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1015 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1018 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1020 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1024 initialise the GENSEC subsystem
1026 _PUBLIC_ NTSTATUS gensec_init(void)
1028 static bool initialized = false;
1029 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1030 #ifdef STATIC_gensec_MODULES
1031 STATIC_gensec_MODULES_PROTO;
1032 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1034 init_module_fn *static_init = NULL;
1036 init_module_fn *shared_init;
1038 if (initialized) return NT_STATUS_OK;
1041 shared_init = load_samba_modules(NULL, "gensec");
1043 run_init_functions(NULL, static_init);
1044 run_init_functions(NULL, shared_init);
1046 talloc_free(shared_init);
1048 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1050 return NT_STATUS_OK;