lib: Make time-basic a library
[Samba.git] / auth / gensec / gensec_start.c
blobbe316978a0b77ce7687d724c58d0d0d23cdab505
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;
728 * We need to reset sign/seal in order to reset it.
729 * We may got some default features inherited by the credentials
731 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
732 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
733 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
734 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
735 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
736 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
737 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
738 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
739 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
740 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
741 /* Default features */
742 } else {
743 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
744 auth_level));
745 return NT_STATUS_INVALID_PARAMETER;
748 return gensec_start_mech(gensec_security);
751 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
753 const struct gensec_security_ops *ops;
754 ops = gensec_security_by_auth_type(gensec_security, authtype);
755 if (ops) {
756 return ops->name;
758 return NULL;
762 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
763 const char *oid_string)
765 const struct gensec_security_ops *ops;
766 ops = gensec_security_by_oid(gensec_security, oid_string);
767 if (ops) {
768 return ops->name;
770 return oid_string;
774 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
776 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
777 * well-known #define to hook it in.
780 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
781 const char *mech_oid)
783 SMB_ASSERT(gensec_security != NULL);
785 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
786 if (!gensec_security->ops) {
787 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
788 return NT_STATUS_INVALID_PARAMETER;
790 return gensec_start_mech(gensec_security);
794 * Start a GENSEC sub-mechanism by a well know SASL name
798 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
799 const char *sasl_name)
801 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
802 if (!gensec_security->ops) {
803 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
804 return NT_STATUS_INVALID_PARAMETER;
806 return gensec_start_mech(gensec_security);
810 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
814 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
815 const char **sasl_names)
817 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
818 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
819 const struct gensec_security_ops **ops;
820 int i;
821 if (!mem_ctx) {
822 return NT_STATUS_NO_MEMORY;
824 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
825 if (!ops || !*ops) {
826 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
827 str_list_join(mem_ctx,
828 sasl_names, ' ')));
829 talloc_free(mem_ctx);
830 return NT_STATUS_INVALID_PARAMETER;
832 for (i=0; ops[i]; i++) {
833 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
834 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
835 break;
838 talloc_free(mem_ctx);
839 return nt_status;
843 * Start a GENSEC sub-mechanism by an internal name
847 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
848 const char *name)
850 gensec_security->ops = gensec_security_by_name(gensec_security, name);
851 if (!gensec_security->ops) {
852 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
853 return NT_STATUS_INVALID_PARAMETER;
855 return gensec_start_mech(gensec_security);
859 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
863 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
865 gensec_security->credentials = talloc_reference(gensec_security, credentials);
866 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
867 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
868 return NT_STATUS_OK;
872 register a GENSEC backend.
874 The 'name' can be later used by other backends to find the operations
875 structure for this backend.
877 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
879 if (gensec_security_by_name(NULL, ops->name) != NULL) {
880 /* its already registered! */
881 DEBUG(0,("GENSEC backend '%s' already registered\n",
882 ops->name));
883 return NT_STATUS_OBJECT_NAME_COLLISION;
886 generic_security_ops = talloc_realloc(talloc_autofree_context(),
887 generic_security_ops,
888 const struct gensec_security_ops *,
889 gensec_num_backends+2);
890 if (!generic_security_ops) {
891 return NT_STATUS_NO_MEMORY;
894 generic_security_ops[gensec_num_backends] = ops;
895 gensec_num_backends++;
896 generic_security_ops[gensec_num_backends] = NULL;
898 DEBUG(3,("GENSEC backend '%s' registered\n",
899 ops->name));
901 return NT_STATUS_OK;
905 return the GENSEC interface version, and the size of some critical types
906 This can be used by backends to either detect compilation errors, or provide
907 multiple implementations for different smbd compilation options in one module
909 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
911 static const struct gensec_critical_sizes critical_sizes = {
912 GENSEC_INTERFACE_VERSION,
913 sizeof(struct gensec_security_ops),
914 sizeof(struct gensec_security),
917 return &critical_sizes;
920 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
921 return (*gs2)->priority - (*gs1)->priority;
924 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
926 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
929 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
931 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
935 initialise the GENSEC subsystem
937 _PUBLIC_ NTSTATUS gensec_init(void)
939 static bool initialized = false;
940 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
941 #ifdef STATIC_gensec_MODULES
942 STATIC_gensec_MODULES_PROTO;
943 init_module_fn static_init[] = { STATIC_gensec_MODULES };
944 #else
945 init_module_fn *static_init = NULL;
946 #endif
947 init_module_fn *shared_init;
949 if (initialized) return NT_STATUS_OK;
950 initialized = true;
952 shared_init = load_samba_modules(NULL, "gensec");
954 run_init_functions(static_init);
955 run_init_functions(shared_init);
957 talloc_free(shared_init);
959 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
961 return NT_STATUS_OK;