s4:dsdb/tests: let the user_account_control.py test recover from a previous failure
[Samba.git] / auth / gensec / gensec_start.c
blob1e616277dad41c9d1c9f28af1974a05061b779b1
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"
34 #include "lib/util/base64.h"
36 /* the list of currently registered GENSEC backends */
37 static const struct gensec_security_ops **generic_security_ops;
38 static int gensec_num_backends;
40 /* Return all the registered mechs. Don't modify the return pointer,
41 * but you may talloc_referen it if convient */
42 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
44 return generic_security_ops;
47 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
49 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
52 /* Sometimes we want to force only kerberos, sometimes we want to
53 * force it's avoidance. The old list could be either
54 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
55 * an existing list we have trimmed down)
57 * The intended logic is:
59 * if we are in the default AUTO have kerberos:
60 * - take a reference to the master list
61 * otherwise
62 * - always add spnego then:
63 * - if we 'MUST' have kerberos:
64 * only add kerberos mechs
65 * - if we 'DONT' want kerberos':
66 * only add non-kerberos mechs
68 * Once we get things like NegoEx or moonshot, this will of course get
69 * more compplex.
72 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
73 const struct gensec_security_ops * const *old_gensec_list,
74 struct cli_credentials *creds)
76 const struct gensec_security_ops **new_gensec_list;
77 int i, j, num_mechs_in;
78 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
79 bool keep_schannel = false;
81 if (creds) {
82 use_kerberos = cli_credentials_get_kerberos_state(creds);
83 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
84 keep_schannel = true;
88 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
89 /* noop */
92 new_gensec_list = talloc_array(mem_ctx,
93 const struct gensec_security_ops *,
94 num_mechs_in + 1);
95 if (!new_gensec_list) {
96 return NULL;
99 j = 0;
100 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
101 int oid_idx;
102 bool keep = false;
104 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
105 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
106 keep = true;
107 break;
111 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
112 keep = keep_schannel;
115 switch (use_kerberos) {
116 case CRED_AUTO_USE_KERBEROS:
117 keep = true;
118 break;
120 case CRED_DONT_USE_KERBEROS:
121 if (old_gensec_list[i]->kerberos == false) {
122 keep = true;
125 break;
127 case CRED_MUST_USE_KERBEROS:
128 if (old_gensec_list[i]->kerberos == true) {
129 keep = true;
132 break;
133 default:
134 /* Can't happen or invalid parameter */
135 return NULL;
138 if (!keep) {
139 continue;
142 new_gensec_list[j] = old_gensec_list[i];
143 j++;
145 new_gensec_list[j] = NULL;
147 return new_gensec_list;
150 _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
151 struct gensec_security *gensec_security,
152 TALLOC_CTX *mem_ctx)
154 struct cli_credentials *creds = NULL;
155 const struct gensec_security_ops * const *backends = gensec_security_all();
157 if (gensec_security != NULL) {
158 creds = gensec_get_credentials(gensec_security);
160 if (gensec_security->settings->backends) {
161 backends = gensec_security->settings->backends;
165 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
169 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
170 struct gensec_security *gensec_security,
171 const char *oid_string)
173 int i, j;
174 const struct gensec_security_ops **backends;
175 const struct gensec_security_ops *backend;
176 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
177 if (!mem_ctx) {
178 return NULL;
180 backends = gensec_security_mechs(gensec_security, mem_ctx);
181 for (i=0; backends && backends[i]; i++) {
182 if (gensec_security != NULL &&
183 !gensec_security_ops_enabled(backends[i],
184 gensec_security))
185 continue;
186 if (backends[i]->oid) {
187 for (j=0; backends[i]->oid[j]; j++) {
188 if (backends[i]->oid[j] &&
189 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
190 backend = backends[i];
191 talloc_free(mem_ctx);
192 return backend;
197 talloc_free(mem_ctx);
199 return NULL;
202 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
203 struct gensec_security *gensec_security,
204 const char *sasl_name)
206 int i;
207 const struct gensec_security_ops **backends;
208 const struct gensec_security_ops *backend;
209 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
210 if (!mem_ctx) {
211 return NULL;
213 backends = gensec_security_mechs(gensec_security, mem_ctx);
214 for (i=0; backends && backends[i]; i++) {
215 if (gensec_security != NULL &&
216 !gensec_security_ops_enabled(backends[i], gensec_security)) {
217 continue;
219 if (backends[i]->sasl_name
220 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
221 backend = backends[i];
222 talloc_free(mem_ctx);
223 return backend;
226 talloc_free(mem_ctx);
228 return NULL;
231 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
232 struct gensec_security *gensec_security,
233 uint32_t auth_type)
235 int i;
236 const struct gensec_security_ops **backends;
237 const struct gensec_security_ops *backend;
238 TALLOC_CTX *mem_ctx;
240 if (auth_type == DCERPC_AUTH_TYPE_NONE) {
241 return NULL;
244 mem_ctx = talloc_new(gensec_security);
245 if (!mem_ctx) {
246 return NULL;
248 backends = gensec_security_mechs(gensec_security, mem_ctx);
249 for (i=0; backends && backends[i]; i++) {
250 if (gensec_security != NULL &&
251 !gensec_security_ops_enabled(backends[i], gensec_security)) {
252 continue;
254 if (backends[i]->auth_type == auth_type) {
255 backend = backends[i];
256 talloc_free(mem_ctx);
257 return backend;
260 talloc_free(mem_ctx);
262 return NULL;
265 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
266 const char *name)
268 int i;
269 const struct gensec_security_ops **backends;
270 const struct gensec_security_ops *backend;
271 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
272 if (!mem_ctx) {
273 return NULL;
275 backends = gensec_security_mechs(gensec_security, mem_ctx);
276 for (i=0; backends && backends[i]; i++) {
277 if (gensec_security != NULL &&
278 !gensec_security_ops_enabled(backends[i], gensec_security))
279 continue;
280 if (backends[i]->name
281 && (strcmp(backends[i]->name, name) == 0)) {
282 backend = backends[i];
283 talloc_free(mem_ctx);
284 return backend;
287 talloc_free(mem_ctx);
288 return NULL;
292 * Return a unique list of security subsystems from those specified in
293 * the list of SASL names.
295 * Use the list of enabled GENSEC mechanisms from the credentials
296 * attached to the gensec_security, and return in our preferred order.
299 static const struct gensec_security_ops **gensec_security_by_sasl_list(
300 struct gensec_security *gensec_security,
301 TALLOC_CTX *mem_ctx,
302 const char **sasl_names)
304 const struct gensec_security_ops **backends_out;
305 const struct gensec_security_ops **backends;
306 int i, k, sasl_idx;
307 int num_backends_out = 0;
309 if (!sasl_names) {
310 return NULL;
313 backends = gensec_security_mechs(gensec_security, mem_ctx);
315 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
316 if (!backends_out) {
317 return NULL;
319 backends_out[0] = NULL;
321 /* Find backends in our preferred order, by walking our list,
322 * then looking in the supplied list */
323 for (i=0; backends && backends[i]; i++) {
324 if (gensec_security != NULL &&
325 !gensec_security_ops_enabled(backends[i], gensec_security))
326 continue;
327 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
328 if (!backends[i]->sasl_name ||
329 !(strcmp(backends[i]->sasl_name,
330 sasl_names[sasl_idx]) == 0)) {
331 continue;
334 for (k=0; backends_out[k]; k++) {
335 if (backends_out[k] == backends[i]) {
336 break;
340 if (k < num_backends_out) {
341 /* already in there */
342 continue;
345 backends_out = talloc_realloc(mem_ctx, backends_out,
346 const struct gensec_security_ops *,
347 num_backends_out + 2);
348 if (!backends_out) {
349 return NULL;
352 backends_out[num_backends_out] = backends[i];
353 num_backends_out++;
354 backends_out[num_backends_out] = NULL;
357 return backends_out;
361 * Return a unique list of security subsystems from those specified in
362 * the OID list. That is, where two OIDs refer to the same module,
363 * return that module only once.
365 * Use the list of enabled GENSEC mechanisms from the credentials
366 * attached to the gensec_security, and return in our preferred order.
369 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
370 struct gensec_security *gensec_security,
371 TALLOC_CTX *mem_ctx,
372 const char * const *oid_strings,
373 const char *skip)
375 struct gensec_security_ops_wrapper *backends_out;
376 const struct gensec_security_ops **backends;
377 int i, j, k, oid_idx;
378 int num_backends_out = 0;
380 if (!oid_strings) {
381 return NULL;
384 backends = gensec_security_mechs(gensec_security, gensec_security);
386 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
387 if (!backends_out) {
388 return NULL;
390 backends_out[0].op = NULL;
391 backends_out[0].oid = NULL;
393 /* Find backends in our preferred order, by walking our list,
394 * then looking in the supplied list */
395 for (i=0; backends && backends[i]; i++) {
396 if (gensec_security != NULL &&
397 !gensec_security_ops_enabled(backends[i], gensec_security))
398 continue;
399 if (!backends[i]->oid) {
400 continue;
402 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
403 if (strcmp(oid_strings[oid_idx], skip) == 0) {
404 continue;
407 for (j=0; backends[i]->oid[j]; j++) {
408 if (!backends[i]->oid[j] ||
409 !(strcmp(backends[i]->oid[j],
410 oid_strings[oid_idx]) == 0)) {
411 continue;
414 for (k=0; backends_out[k].op; k++) {
415 if (backends_out[k].op == backends[i]) {
416 break;
420 if (k < num_backends_out) {
421 /* already in there */
422 continue;
425 backends_out = talloc_realloc(mem_ctx, backends_out,
426 struct gensec_security_ops_wrapper,
427 num_backends_out + 2);
428 if (!backends_out) {
429 return NULL;
432 backends_out[num_backends_out].op = backends[i];
433 backends_out[num_backends_out].oid = backends[i]->oid[j];
434 num_backends_out++;
435 backends_out[num_backends_out].op = NULL;
436 backends_out[num_backends_out].oid = NULL;
440 return backends_out;
444 * Return OIDS from the security subsystems listed
447 static const char **gensec_security_oids_from_ops(
448 struct gensec_security *gensec_security,
449 TALLOC_CTX *mem_ctx,
450 const struct gensec_security_ops * const *ops,
451 const char *skip)
453 int i;
454 int j = 0;
455 int k;
456 const char **oid_list;
457 if (!ops) {
458 return NULL;
460 oid_list = talloc_array(mem_ctx, const char *, 1);
461 if (!oid_list) {
462 return NULL;
465 for (i=0; ops && ops[i]; i++) {
466 if (gensec_security != NULL &&
467 !gensec_security_ops_enabled(ops[i], gensec_security)) {
468 continue;
470 if (!ops[i]->oid) {
471 continue;
474 for (k = 0; ops[i]->oid[k]; k++) {
475 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
476 } else {
477 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
478 if (!oid_list) {
479 return NULL;
481 oid_list[j] = ops[i]->oid[k];
482 j++;
486 oid_list[j] = NULL;
487 return oid_list;
492 * Return OIDS from the security subsystems listed
495 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
496 const struct gensec_security_ops_wrapper *wops)
498 int i;
499 int j = 0;
500 int k;
501 const char **oid_list;
502 if (!wops) {
503 return NULL;
505 oid_list = talloc_array(mem_ctx, const char *, 1);
506 if (!oid_list) {
507 return NULL;
510 for (i=0; wops[i].op; i++) {
511 if (!wops[i].op->oid) {
512 continue;
515 for (k = 0; wops[i].op->oid[k]; k++) {
516 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
517 if (!oid_list) {
518 return NULL;
520 oid_list[j] = wops[i].op->oid[k];
521 j++;
524 oid_list[j] = NULL;
525 return oid_list;
530 * Return all the security subsystems currently enabled on a GENSEC context.
532 * This is taken from a list attached to the cli_credentials, and
533 * skips the OID in 'skip'. (Typically the SPNEGO OID)
537 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
538 TALLOC_CTX *mem_ctx,
539 const char *skip)
541 const struct gensec_security_ops **ops;
543 ops = gensec_security_mechs(gensec_security, mem_ctx);
545 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
549 Start the GENSEC system, returning a context pointer.
550 @param mem_ctx The parent TALLOC memory context.
551 @param gensec_security Returned GENSEC context pointer.
552 @note The mem_ctx is only a parent and may be NULL.
553 @note, the auth context is moved to be a referenced pointer of the
554 @ gensec_security return
556 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
557 struct gensec_settings *settings,
558 struct auth4_context *auth_context,
559 struct gensec_security **gensec_security)
561 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
562 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
564 (*gensec_security)->max_update_size = 0;
566 SMB_ASSERT(settings->lp_ctx != NULL);
567 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
569 /* We need to reference this, not steal, as the caller may be
570 * python, which won't like it if we steal it's object away
571 * from it */
572 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
574 return NT_STATUS_OK;
578 * Start a GENSEC subcontext, with a copy of the properties of the parent
579 * @param mem_ctx The parent TALLOC memory context.
580 * @param parent The parent GENSEC context
581 * @param gensec_security Returned GENSEC context pointer.
582 * @note Used by SPNEGO in particular, for the actual implementation mechanism
585 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
586 struct gensec_security *parent,
587 struct gensec_security **gensec_security)
589 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
590 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
592 (**gensec_security) = *parent;
593 (*gensec_security)->ops = NULL;
594 (*gensec_security)->private_data = NULL;
596 (*gensec_security)->subcontext = true;
597 (*gensec_security)->want_features = parent->want_features;
598 (*gensec_security)->max_update_size = parent->max_update_size;
599 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
600 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
601 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
602 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
604 return NT_STATUS_OK;
608 Start the GENSEC system, in client mode, returning a context pointer.
609 @param mem_ctx The parent TALLOC memory context.
610 @param gensec_security Returned GENSEC context pointer.
611 @note The mem_ctx is only a parent and may be NULL.
613 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
614 struct gensec_security **gensec_security,
615 struct gensec_settings *settings)
617 NTSTATUS status;
619 if (settings == NULL) {
620 DEBUG(0,("gensec_client_start: no settings given!\n"));
621 return NT_STATUS_INTERNAL_ERROR;
624 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
625 if (!NT_STATUS_IS_OK(status)) {
626 return status;
628 (*gensec_security)->gensec_role = GENSEC_CLIENT;
630 return status;
636 Start the GENSEC system, in server mode, returning a context pointer.
637 @param mem_ctx The parent TALLOC memory context.
638 @param gensec_security Returned GENSEC context pointer.
639 @note The mem_ctx is only a parent and may be NULL.
641 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
642 struct gensec_settings *settings,
643 struct auth4_context *auth_context,
644 struct gensec_security **gensec_security)
646 NTSTATUS status;
648 if (!settings) {
649 DEBUG(0,("gensec_server_start: no settings given!\n"));
650 return NT_STATUS_INTERNAL_ERROR;
653 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
654 if (!NT_STATUS_IS_OK(status)) {
655 return status;
657 (*gensec_security)->gensec_role = GENSEC_SERVER;
659 return status;
662 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
664 NTSTATUS status;
666 if (gensec_security->credentials) {
667 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
668 if (forced_mech &&
669 (gensec_security->ops->sasl_name == NULL ||
670 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
671 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
672 "did not match forced mechanism %s\n",
673 gensec_security->ops->name,
674 gensec_security->ops->sasl_name,
675 forced_mech));
676 return NT_STATUS_INVALID_PARAMETER;
679 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
680 gensec_security->subcontext ? "sub" : "",
681 gensec_security->ops->name));
682 switch (gensec_security->gensec_role) {
683 case GENSEC_CLIENT:
684 if (gensec_security->ops->client_start) {
685 status = gensec_security->ops->client_start(gensec_security);
686 if (!NT_STATUS_IS_OK(status)) {
687 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
688 gensec_security->ops->name, nt_errstr(status)));
690 return status;
692 break;
693 case GENSEC_SERVER:
694 if (gensec_security->ops->server_start) {
695 status = gensec_security->ops->server_start(gensec_security);
696 if (!NT_STATUS_IS_OK(status)) {
697 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
698 gensec_security->ops->name, nt_errstr(status)));
700 return status;
702 break;
704 return NT_STATUS_INVALID_PARAMETER;
708 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
712 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
713 const struct gensec_security_ops *ops)
715 gensec_security->ops = ops;
716 return gensec_start_mech(gensec_security);
721 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
722 * @param gensec_security GENSEC context pointer.
723 * @param auth_type DCERPC auth type
724 * @param auth_level DCERPC auth level
727 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
728 uint8_t auth_type, uint8_t auth_level)
730 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
731 if (!gensec_security->ops) {
732 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
733 return NT_STATUS_INVALID_PARAMETER;
735 gensec_security->dcerpc_auth_level = auth_level;
737 * We need to reset sign/seal in order to reset it.
738 * We may got some default features inherited by the credentials
740 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
741 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
742 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
743 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
744 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
745 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
746 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
747 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
748 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
749 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
750 /* Default features */
751 } else {
752 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
753 auth_level));
754 return NT_STATUS_INVALID_PARAMETER;
757 return gensec_start_mech(gensec_security);
760 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
762 const struct gensec_security_ops *ops;
763 ops = gensec_security_by_auth_type(gensec_security, authtype);
764 if (ops) {
765 return ops->name;
767 return NULL;
771 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
772 const char *oid_string)
774 const struct gensec_security_ops *ops;
775 ops = gensec_security_by_oid(gensec_security, oid_string);
776 if (ops) {
777 return ops->name;
779 return oid_string;
783 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
785 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
786 * well-known #define to hook it in.
789 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
790 const char *mech_oid)
792 SMB_ASSERT(gensec_security != NULL);
794 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
795 if (!gensec_security->ops) {
796 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
797 return NT_STATUS_INVALID_PARAMETER;
799 return gensec_start_mech(gensec_security);
803 * Start a GENSEC sub-mechanism by a well know SASL name
807 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
808 const char *sasl_name)
810 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
811 if (!gensec_security->ops) {
812 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
813 return NT_STATUS_INVALID_PARAMETER;
815 return gensec_start_mech(gensec_security);
819 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
823 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
824 const char **sasl_names)
826 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
827 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
828 const struct gensec_security_ops **ops;
829 int i;
830 if (!mem_ctx) {
831 return NT_STATUS_NO_MEMORY;
833 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
834 if (!ops || !*ops) {
835 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
836 str_list_join(mem_ctx,
837 sasl_names, ' ')));
838 talloc_free(mem_ctx);
839 return NT_STATUS_INVALID_PARAMETER;
841 for (i=0; ops[i]; i++) {
842 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
843 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
844 break;
847 talloc_free(mem_ctx);
848 return nt_status;
852 * Start a GENSEC sub-mechanism by an internal name
856 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
857 const char *name)
859 gensec_security->ops = gensec_security_by_name(gensec_security, name);
860 if (!gensec_security->ops) {
861 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
862 return NT_STATUS_INVALID_PARAMETER;
864 return gensec_start_mech(gensec_security);
868 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
872 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
874 gensec_security->credentials = talloc_reference(gensec_security, credentials);
875 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
876 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
877 return NT_STATUS_OK;
881 register a GENSEC backend.
883 The 'name' can be later used by other backends to find the operations
884 structure for this backend.
886 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
888 if (gensec_security_by_name(NULL, ops->name) != NULL) {
889 /* its already registered! */
890 DEBUG(0,("GENSEC backend '%s' already registered\n",
891 ops->name));
892 return NT_STATUS_OBJECT_NAME_COLLISION;
895 generic_security_ops = talloc_realloc(talloc_autofree_context(),
896 generic_security_ops,
897 const struct gensec_security_ops *,
898 gensec_num_backends+2);
899 if (!generic_security_ops) {
900 return NT_STATUS_NO_MEMORY;
903 generic_security_ops[gensec_num_backends] = ops;
904 gensec_num_backends++;
905 generic_security_ops[gensec_num_backends] = NULL;
907 DEBUG(3,("GENSEC backend '%s' registered\n",
908 ops->name));
910 return NT_STATUS_OK;
914 return the GENSEC interface version, and the size of some critical types
915 This can be used by backends to either detect compilation errors, or provide
916 multiple implementations for different smbd compilation options in one module
918 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
920 static const struct gensec_critical_sizes critical_sizes = {
921 GENSEC_INTERFACE_VERSION,
922 sizeof(struct gensec_security_ops),
923 sizeof(struct gensec_security),
926 return &critical_sizes;
929 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
930 return (*gs2)->priority - (*gs1)->priority;
933 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
935 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
938 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
940 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
944 initialise the GENSEC subsystem
946 _PUBLIC_ NTSTATUS gensec_init(void)
948 static bool initialized = false;
949 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
950 #ifdef STATIC_gensec_MODULES
951 STATIC_gensec_MODULES_PROTO;
952 init_module_fn static_init[] = { STATIC_gensec_MODULES };
953 #else
954 init_module_fn *static_init = NULL;
955 #endif
956 init_module_fn *shared_init;
958 if (initialized) return NT_STATUS_OK;
959 initialized = true;
961 shared_init = load_samba_modules(NULL, "gensec");
963 run_init_functions(static_init);
964 run_init_functions(shared_init);
966 talloc_free(shared_init);
968 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
970 return NT_STATUS_OK;