util_sd: Make server conncection optional
[Samba.git] / auth / gensec / gensec_start.c
blob955cc36f4cb37ab2653bfcdba8fe9d46379677b9
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 #include "tevent.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"
35 /* the list of currently registered GENSEC backends */
36 static const struct gensec_security_ops **generic_security_ops;
37 static int gensec_num_backends;
39 /* Return all the registered mechs. Don't modify the return pointer,
40 * but you may talloc_referen it if convient */
41 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
43 return generic_security_ops;
46 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
48 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
51 /* Sometimes we want to force only kerberos, sometimes we want to
52 * force it's avoidance. The old list could be either
53 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
54 * an existing list we have trimmed down)
56 * The intended logic is:
58 * if we are in the default AUTO have kerberos:
59 * - take a reference to the master list
60 * otherwise
61 * - always add spnego then:
62 * - if we 'MUST' have kerberos:
63 * only add kerberos mechs
64 * - if we 'DONT' want kerberos':
65 * only add non-kerberos mechs
67 * Once we get things like NegoEx or moonshot, this will of course get
68 * more compplex.
71 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
72 const struct gensec_security_ops * const *old_gensec_list,
73 struct cli_credentials *creds)
75 const struct gensec_security_ops **new_gensec_list;
76 int i, j, num_mechs_in;
77 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
78 bool keep_schannel = false;
80 if (creds) {
81 use_kerberos = cli_credentials_get_kerberos_state(creds);
82 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
83 keep_schannel = true;
87 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
88 /* noop */
91 new_gensec_list = talloc_array(mem_ctx,
92 const struct gensec_security_ops *,
93 num_mechs_in + 1);
94 if (!new_gensec_list) {
95 return NULL;
98 j = 0;
99 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
100 int oid_idx;
101 bool keep = false;
103 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
104 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
105 keep = true;
106 break;
110 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
111 keep = keep_schannel;
114 switch (use_kerberos) {
115 case CRED_AUTO_USE_KERBEROS:
116 keep = true;
117 break;
119 case CRED_DONT_USE_KERBEROS:
120 if (old_gensec_list[i]->kerberos == false) {
121 keep = true;
124 break;
126 case CRED_MUST_USE_KERBEROS:
127 if (old_gensec_list[i]->kerberos == true) {
128 keep = true;
131 break;
132 default:
133 /* Can't happen or invalid parameter */
134 return NULL;
137 if (!keep) {
138 continue;
141 new_gensec_list[j] = old_gensec_list[i];
142 j++;
144 new_gensec_list[j] = NULL;
146 return new_gensec_list;
149 _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
150 struct gensec_security *gensec_security,
151 TALLOC_CTX *mem_ctx)
153 struct cli_credentials *creds = NULL;
154 const struct gensec_security_ops * const *backends = gensec_security_all();
156 if (gensec_security != NULL) {
157 creds = gensec_get_credentials(gensec_security);
159 if (gensec_security->settings->backends) {
160 backends = gensec_security->settings->backends;
164 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
168 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
169 struct gensec_security *gensec_security,
170 const char *oid_string)
172 int i, j;
173 const struct gensec_security_ops **backends;
174 const struct gensec_security_ops *backend;
175 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
176 if (!mem_ctx) {
177 return NULL;
179 backends = gensec_security_mechs(gensec_security, mem_ctx);
180 for (i=0; backends && backends[i]; i++) {
181 if (gensec_security != NULL &&
182 !gensec_security_ops_enabled(backends[i],
183 gensec_security))
184 continue;
185 if (backends[i]->oid) {
186 for (j=0; backends[i]->oid[j]; j++) {
187 if (backends[i]->oid[j] &&
188 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
189 backend = backends[i];
190 talloc_free(mem_ctx);
191 return backend;
196 talloc_free(mem_ctx);
198 return NULL;
201 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
202 struct gensec_security *gensec_security,
203 const char *sasl_name)
205 int i;
206 const struct gensec_security_ops **backends;
207 const struct gensec_security_ops *backend;
208 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
209 if (!mem_ctx) {
210 return NULL;
212 backends = gensec_security_mechs(gensec_security, mem_ctx);
213 for (i=0; backends && backends[i]; i++) {
214 if (!gensec_security_ops_enabled(backends[i], gensec_security))
215 continue;
216 if (backends[i]->sasl_name
217 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
218 backend = backends[i];
219 talloc_free(mem_ctx);
220 return backend;
223 talloc_free(mem_ctx);
225 return NULL;
228 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
229 struct gensec_security *gensec_security,
230 uint32_t auth_type)
232 int i;
233 const struct gensec_security_ops **backends;
234 const struct gensec_security_ops *backend;
235 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
236 if (!mem_ctx) {
237 return NULL;
239 backends = gensec_security_mechs(gensec_security, mem_ctx);
240 for (i=0; backends && backends[i]; i++) {
241 if (gensec_security != NULL &&
242 !gensec_security_ops_enabled(backends[i], gensec_security)) {
243 continue;
245 if (backends[i]->auth_type == auth_type) {
246 backend = backends[i];
247 talloc_free(mem_ctx);
248 return backend;
251 talloc_free(mem_ctx);
253 return NULL;
256 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
257 const char *name)
259 int i;
260 const struct gensec_security_ops **backends;
261 const struct gensec_security_ops *backend;
262 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
263 if (!mem_ctx) {
264 return NULL;
266 backends = gensec_security_mechs(gensec_security, mem_ctx);
267 for (i=0; backends && backends[i]; i++) {
268 if (gensec_security != NULL &&
269 !gensec_security_ops_enabled(backends[i], gensec_security))
270 continue;
271 if (backends[i]->name
272 && (strcmp(backends[i]->name, name) == 0)) {
273 backend = backends[i];
274 talloc_free(mem_ctx);
275 return backend;
278 talloc_free(mem_ctx);
279 return NULL;
283 * Return a unique list of security subsystems from those specified in
284 * the list of SASL names.
286 * Use the list of enabled GENSEC mechanisms from the credentials
287 * attached to the gensec_security, and return in our preferred order.
290 static const struct gensec_security_ops **gensec_security_by_sasl_list(
291 struct gensec_security *gensec_security,
292 TALLOC_CTX *mem_ctx,
293 const char **sasl_names)
295 const struct gensec_security_ops **backends_out;
296 const struct gensec_security_ops **backends;
297 int i, k, sasl_idx;
298 int num_backends_out = 0;
300 if (!sasl_names) {
301 return NULL;
304 backends = gensec_security_mechs(gensec_security, mem_ctx);
306 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
307 if (!backends_out) {
308 return NULL;
310 backends_out[0] = NULL;
312 /* Find backends in our preferred order, by walking our list,
313 * then looking in the supplied list */
314 for (i=0; backends && backends[i]; i++) {
315 if (gensec_security != NULL &&
316 !gensec_security_ops_enabled(backends[i], gensec_security))
317 continue;
318 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
319 if (!backends[i]->sasl_name ||
320 !(strcmp(backends[i]->sasl_name,
321 sasl_names[sasl_idx]) == 0)) {
322 continue;
325 for (k=0; backends_out[k]; k++) {
326 if (backends_out[k] == backends[i]) {
327 break;
331 if (k < num_backends_out) {
332 /* already in there */
333 continue;
336 backends_out = talloc_realloc(mem_ctx, backends_out,
337 const struct gensec_security_ops *,
338 num_backends_out + 2);
339 if (!backends_out) {
340 return NULL;
343 backends_out[num_backends_out] = backends[i];
344 num_backends_out++;
345 backends_out[num_backends_out] = NULL;
348 return backends_out;
352 * Return a unique list of security subsystems from those specified in
353 * the OID list. That is, where two OIDs refer to the same module,
354 * return that module only once.
356 * Use the list of enabled GENSEC mechanisms from the credentials
357 * attached to the gensec_security, and return in our preferred order.
360 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
361 struct gensec_security *gensec_security,
362 TALLOC_CTX *mem_ctx,
363 const char * const *oid_strings,
364 const char *skip)
366 struct gensec_security_ops_wrapper *backends_out;
367 const struct gensec_security_ops **backends;
368 int i, j, k, oid_idx;
369 int num_backends_out = 0;
371 if (!oid_strings) {
372 return NULL;
375 backends = gensec_security_mechs(gensec_security, gensec_security);
377 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
378 if (!backends_out) {
379 return NULL;
381 backends_out[0].op = NULL;
382 backends_out[0].oid = NULL;
384 /* Find backends in our preferred order, by walking our list,
385 * then looking in the supplied list */
386 for (i=0; backends && backends[i]; i++) {
387 if (gensec_security != NULL &&
388 !gensec_security_ops_enabled(backends[i], gensec_security))
389 continue;
390 if (!backends[i]->oid) {
391 continue;
393 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
394 if (strcmp(oid_strings[oid_idx], skip) == 0) {
395 continue;
398 for (j=0; backends[i]->oid[j]; j++) {
399 if (!backends[i]->oid[j] ||
400 !(strcmp(backends[i]->oid[j],
401 oid_strings[oid_idx]) == 0)) {
402 continue;
405 for (k=0; backends_out[k].op; k++) {
406 if (backends_out[k].op == backends[i]) {
407 break;
411 if (k < num_backends_out) {
412 /* already in there */
413 continue;
416 backends_out = talloc_realloc(mem_ctx, backends_out,
417 struct gensec_security_ops_wrapper,
418 num_backends_out + 2);
419 if (!backends_out) {
420 return NULL;
423 backends_out[num_backends_out].op = backends[i];
424 backends_out[num_backends_out].oid = backends[i]->oid[j];
425 num_backends_out++;
426 backends_out[num_backends_out].op = NULL;
427 backends_out[num_backends_out].oid = NULL;
431 return backends_out;
435 * Return OIDS from the security subsystems listed
438 static const char **gensec_security_oids_from_ops(
439 struct gensec_security *gensec_security,
440 TALLOC_CTX *mem_ctx,
441 const struct gensec_security_ops * const *ops,
442 const char *skip)
444 int i;
445 int j = 0;
446 int k;
447 const char **oid_list;
448 if (!ops) {
449 return NULL;
451 oid_list = talloc_array(mem_ctx, const char *, 1);
452 if (!oid_list) {
453 return NULL;
456 for (i=0; ops && ops[i]; i++) {
457 if (gensec_security != NULL &&
458 !gensec_security_ops_enabled(ops[i], gensec_security)) {
459 continue;
461 if (!ops[i]->oid) {
462 continue;
465 for (k = 0; ops[i]->oid[k]; k++) {
466 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
467 } else {
468 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
469 if (!oid_list) {
470 return NULL;
472 oid_list[j] = ops[i]->oid[k];
473 j++;
477 oid_list[j] = NULL;
478 return oid_list;
483 * Return OIDS from the security subsystems listed
486 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
487 const struct gensec_security_ops_wrapper *wops)
489 int i;
490 int j = 0;
491 int k;
492 const char **oid_list;
493 if (!wops) {
494 return NULL;
496 oid_list = talloc_array(mem_ctx, const char *, 1);
497 if (!oid_list) {
498 return NULL;
501 for (i=0; wops[i].op; i++) {
502 if (!wops[i].op->oid) {
503 continue;
506 for (k = 0; wops[i].op->oid[k]; k++) {
507 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
508 if (!oid_list) {
509 return NULL;
511 oid_list[j] = wops[i].op->oid[k];
512 j++;
515 oid_list[j] = NULL;
516 return oid_list;
521 * Return all the security subsystems currently enabled on a GENSEC context.
523 * This is taken from a list attached to the cli_credentials, and
524 * skips the OID in 'skip'. (Typically the SPNEGO OID)
528 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
529 TALLOC_CTX *mem_ctx,
530 const char *skip)
532 const struct gensec_security_ops **ops;
534 ops = gensec_security_mechs(gensec_security, mem_ctx);
536 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
540 Start the GENSEC system, returning a context pointer.
541 @param mem_ctx The parent TALLOC memory context.
542 @param gensec_security Returned GENSEC context pointer.
543 @note The mem_ctx is only a parent and may be NULL.
544 @note, the auth context is moved to be a referenced pointer of the
545 @ gensec_security return
547 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
548 struct gensec_settings *settings,
549 struct auth4_context *auth_context,
550 struct gensec_security **gensec_security)
552 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
553 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
555 (*gensec_security)->max_update_size = 0;
557 SMB_ASSERT(settings->lp_ctx != NULL);
558 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
560 /* We need to reference this, not steal, as the caller may be
561 * python, which won't like it if we steal it's object away
562 * from it */
563 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
565 return NT_STATUS_OK;
569 * Start a GENSEC subcontext, with a copy of the properties of the parent
570 * @param mem_ctx The parent TALLOC memory context.
571 * @param parent The parent GENSEC context
572 * @param gensec_security Returned GENSEC context pointer.
573 * @note Used by SPNEGO in particular, for the actual implementation mechanism
576 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
577 struct gensec_security *parent,
578 struct gensec_security **gensec_security)
580 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
581 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
583 (**gensec_security) = *parent;
584 (*gensec_security)->ops = NULL;
585 (*gensec_security)->private_data = NULL;
587 (*gensec_security)->subcontext = true;
588 (*gensec_security)->want_features = parent->want_features;
589 (*gensec_security)->max_update_size = parent->max_update_size;
590 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
591 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
592 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
593 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
595 return NT_STATUS_OK;
599 Start the GENSEC system, in client mode, returning a context pointer.
600 @param mem_ctx The parent TALLOC memory context.
601 @param gensec_security Returned GENSEC context pointer.
602 @note The mem_ctx is only a parent and may be NULL.
604 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
605 struct gensec_security **gensec_security,
606 struct gensec_settings *settings)
608 NTSTATUS status;
610 if (settings == NULL) {
611 DEBUG(0,("gensec_client_start: no settings given!\n"));
612 return NT_STATUS_INTERNAL_ERROR;
615 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
616 if (!NT_STATUS_IS_OK(status)) {
617 return status;
619 (*gensec_security)->gensec_role = GENSEC_CLIENT;
621 return status;
627 Start the GENSEC system, in server mode, returning a context pointer.
628 @param mem_ctx The parent TALLOC memory context.
629 @param gensec_security Returned GENSEC context pointer.
630 @note The mem_ctx is only a parent and may be NULL.
632 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
633 struct gensec_settings *settings,
634 struct auth4_context *auth_context,
635 struct gensec_security **gensec_security)
637 NTSTATUS status;
639 if (!settings) {
640 DEBUG(0,("gensec_server_start: no settings given!\n"));
641 return NT_STATUS_INTERNAL_ERROR;
644 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
645 if (!NT_STATUS_IS_OK(status)) {
646 return status;
648 (*gensec_security)->gensec_role = GENSEC_SERVER;
650 return status;
653 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
655 NTSTATUS status;
657 if (gensec_security->credentials) {
658 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
659 if (forced_mech &&
660 (gensec_security->ops->sasl_name == NULL ||
661 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
662 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
663 "did not match forced mechanism %s\n",
664 gensec_security->ops->name,
665 gensec_security->ops->sasl_name,
666 forced_mech));
667 return NT_STATUS_INVALID_PARAMETER;
670 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
671 gensec_security->subcontext ? "sub" : "",
672 gensec_security->ops->name));
673 switch (gensec_security->gensec_role) {
674 case GENSEC_CLIENT:
675 if (gensec_security->ops->client_start) {
676 status = gensec_security->ops->client_start(gensec_security);
677 if (!NT_STATUS_IS_OK(status)) {
678 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
679 gensec_security->ops->name, nt_errstr(status)));
681 return status;
683 break;
684 case GENSEC_SERVER:
685 if (gensec_security->ops->server_start) {
686 status = gensec_security->ops->server_start(gensec_security);
687 if (!NT_STATUS_IS_OK(status)) {
688 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
689 gensec_security->ops->name, nt_errstr(status)));
691 return status;
693 break;
695 return NT_STATUS_INVALID_PARAMETER;
699 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
703 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
704 const struct gensec_security_ops *ops)
706 gensec_security->ops = ops;
707 return gensec_start_mech(gensec_security);
712 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
713 * @param gensec_security GENSEC context pointer.
714 * @param auth_type DCERPC auth type
715 * @param auth_level DCERPC auth level
718 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
719 uint8_t auth_type, uint8_t auth_level)
721 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
722 if (!gensec_security->ops) {
723 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
724 return NT_STATUS_INVALID_PARAMETER;
726 gensec_security->dcerpc_auth_level = auth_level;
727 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
728 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
729 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
730 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
731 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
732 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
733 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
734 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
735 /* Default features */
736 } else {
737 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
738 auth_level));
739 return NT_STATUS_INVALID_PARAMETER;
742 return gensec_start_mech(gensec_security);
745 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
747 const struct gensec_security_ops *ops;
748 ops = gensec_security_by_auth_type(gensec_security, authtype);
749 if (ops) {
750 return ops->name;
752 return NULL;
756 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
757 const char *oid_string)
759 const struct gensec_security_ops *ops;
760 ops = gensec_security_by_oid(gensec_security, oid_string);
761 if (ops) {
762 return ops->name;
764 return oid_string;
768 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
770 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
771 * well-known #define to hook it in.
774 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
775 const char *mech_oid)
777 SMB_ASSERT(gensec_security != NULL);
779 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
780 if (!gensec_security->ops) {
781 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
782 return NT_STATUS_INVALID_PARAMETER;
784 return gensec_start_mech(gensec_security);
788 * Start a GENSEC sub-mechanism by a well know SASL name
792 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
793 const char *sasl_name)
795 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
796 if (!gensec_security->ops) {
797 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
798 return NT_STATUS_INVALID_PARAMETER;
800 return gensec_start_mech(gensec_security);
804 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
808 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
809 const char **sasl_names)
811 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
812 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
813 const struct gensec_security_ops **ops;
814 int i;
815 if (!mem_ctx) {
816 return NT_STATUS_NO_MEMORY;
818 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
819 if (!ops || !*ops) {
820 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
821 str_list_join(mem_ctx,
822 sasl_names, ' ')));
823 talloc_free(mem_ctx);
824 return NT_STATUS_INVALID_PARAMETER;
826 for (i=0; ops[i]; i++) {
827 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
828 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
829 break;
832 talloc_free(mem_ctx);
833 return nt_status;
837 * Start a GENSEC sub-mechanism by an internal name
841 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
842 const char *name)
844 gensec_security->ops = gensec_security_by_name(gensec_security, name);
845 if (!gensec_security->ops) {
846 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
847 return NT_STATUS_INVALID_PARAMETER;
849 return gensec_start_mech(gensec_security);
853 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
857 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
859 gensec_security->credentials = talloc_reference(gensec_security, credentials);
860 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
861 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
862 return NT_STATUS_OK;
866 register a GENSEC backend.
868 The 'name' can be later used by other backends to find the operations
869 structure for this backend.
871 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
873 if (gensec_security_by_name(NULL, ops->name) != NULL) {
874 /* its already registered! */
875 DEBUG(0,("GENSEC backend '%s' already registered\n",
876 ops->name));
877 return NT_STATUS_OBJECT_NAME_COLLISION;
880 generic_security_ops = talloc_realloc(talloc_autofree_context(),
881 generic_security_ops,
882 const struct gensec_security_ops *,
883 gensec_num_backends+2);
884 if (!generic_security_ops) {
885 return NT_STATUS_NO_MEMORY;
888 generic_security_ops[gensec_num_backends] = ops;
889 gensec_num_backends++;
890 generic_security_ops[gensec_num_backends] = NULL;
892 DEBUG(3,("GENSEC backend '%s' registered\n",
893 ops->name));
895 return NT_STATUS_OK;
899 return the GENSEC interface version, and the size of some critical types
900 This can be used by backends to either detect compilation errors, or provide
901 multiple implementations for different smbd compilation options in one module
903 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
905 static const struct gensec_critical_sizes critical_sizes = {
906 GENSEC_INTERFACE_VERSION,
907 sizeof(struct gensec_security_ops),
908 sizeof(struct gensec_security),
911 return &critical_sizes;
914 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
915 return (*gs2)->priority - (*gs1)->priority;
918 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
920 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
923 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
925 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
929 initialise the GENSEC subsystem
931 _PUBLIC_ NTSTATUS gensec_init(void)
933 static bool initialized = false;
934 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
935 #ifdef STATIC_gensec_MODULES
936 STATIC_gensec_MODULES_PROTO;
937 init_module_fn static_init[] = { STATIC_gensec_MODULES };
938 #else
939 init_module_fn *static_init = NULL;
940 #endif
941 init_module_fn *shared_init;
943 if (initialized) return NT_STATUS_OK;
944 initialized = true;
946 shared_init = load_samba_modules(NULL, "gensec");
948 run_init_functions(static_init);
949 run_init_functions(shared_init);
951 talloc_free(shared_init);
953 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
955 return NT_STATUS_OK;