gensec: Fix a memory corruption in gensec_use_kerberos_mechs
[Samba.git] / auth / gensec / gensec_start.c
blobab092a7bb17b5355fbf34b90a175bb6aa6071f54
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/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "lib/param/param.h"
31 #include "lib/util/tsort.h"
32 #include "lib/util/samba_modules.h"
34 /* the list of currently registered GENSEC backends */
35 static struct gensec_security_ops **generic_security_ops;
36 static int gensec_num_backends;
38 /* Return all the registered mechs. Don't modify the return pointer,
39 * but you may talloc_reference it if convient */
40 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
42 return generic_security_ops;
45 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
47 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
50 /* Sometimes we want to force only kerberos, sometimes we want to
51 * force it's avoidance. The old list could be either
52 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
53 * an existing list we have trimmed down) */
55 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
56 struct gensec_security_ops **old_gensec_list,
57 struct cli_credentials *creds)
59 struct gensec_security_ops **new_gensec_list;
60 int i, j, num_mechs_in;
61 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
63 if (creds) {
64 use_kerberos = cli_credentials_get_kerberos_state(creds);
67 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
68 if (!talloc_reference(mem_ctx, old_gensec_list)) {
69 return NULL;
71 return old_gensec_list;
74 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
75 /* noop */
78 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *,
79 num_mechs_in*2 + 1);
80 if (!new_gensec_list) {
81 return NULL;
84 j = 0;
85 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
86 int oid_idx;
88 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
89 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
90 new_gensec_list[j] = old_gensec_list[i];
91 j++;
92 break;
95 switch (use_kerberos) {
96 case CRED_DONT_USE_KERBEROS:
97 if (old_gensec_list[i]->kerberos == false) {
98 new_gensec_list[j] = old_gensec_list[i];
99 j++;
101 break;
102 case CRED_MUST_USE_KERBEROS:
103 if (old_gensec_list[i]->kerberos == true) {
104 new_gensec_list[j] = old_gensec_list[i];
105 j++;
107 break;
108 default:
109 /* Can't happen or invalid parameter */
110 return NULL;
113 new_gensec_list[j] = NULL;
115 return new_gensec_list;
118 _PUBLIC_ struct gensec_security_ops **gensec_security_mechs(
119 struct gensec_security *gensec_security,
120 TALLOC_CTX *mem_ctx)
122 struct gensec_security_ops **backends;
123 if (!gensec_security) {
124 backends = gensec_security_all();
125 if (!talloc_reference(mem_ctx, backends)) {
126 return NULL;
128 return backends;
129 } else {
130 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
131 if (gensec_security->settings->backends) {
132 backends = gensec_security->settings->backends;
133 } else {
134 backends = gensec_security_all();
136 if (!creds) {
137 if (!talloc_reference(mem_ctx, backends)) {
138 return NULL;
140 return backends;
142 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
146 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
147 uint8_t auth_type)
149 int i;
150 struct gensec_security_ops **backends;
151 const struct gensec_security_ops *backend;
152 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
153 if (!mem_ctx) {
154 return NULL;
156 backends = gensec_security_mechs(gensec_security, mem_ctx);
157 for (i=0; backends && backends[i]; i++) {
158 if (!gensec_security_ops_enabled(backends[i], gensec_security))
159 continue;
160 if (backends[i]->auth_type == auth_type) {
161 backend = backends[i];
162 talloc_free(mem_ctx);
163 return backend;
166 talloc_free(mem_ctx);
168 return NULL;
171 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
172 struct gensec_security *gensec_security,
173 const char *oid_string)
175 int i, j;
176 struct gensec_security_ops **backends;
177 const struct gensec_security_ops *backend;
178 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
179 if (!mem_ctx) {
180 return NULL;
182 backends = gensec_security_mechs(gensec_security, mem_ctx);
183 for (i=0; backends && backends[i]; i++) {
184 if (gensec_security != NULL &&
185 !gensec_security_ops_enabled(backends[i],
186 gensec_security))
187 continue;
188 if (backends[i]->oid) {
189 for (j=0; backends[i]->oid[j]; j++) {
190 if (backends[i]->oid[j] &&
191 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
192 backend = backends[i];
193 talloc_free(mem_ctx);
194 return backend;
199 talloc_free(mem_ctx);
201 return NULL;
204 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
205 struct gensec_security *gensec_security,
206 const char *sasl_name)
208 int i;
209 struct gensec_security_ops **backends;
210 const struct gensec_security_ops *backend;
211 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
212 if (!mem_ctx) {
213 return NULL;
215 backends = gensec_security_mechs(gensec_security, mem_ctx);
216 for (i=0; backends && backends[i]; i++) {
217 if (!gensec_security_ops_enabled(backends[i], gensec_security))
218 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 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
232 const char *name)
234 int i;
235 struct gensec_security_ops **backends;
236 const struct gensec_security_ops *backend;
237 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
238 if (!mem_ctx) {
239 return NULL;
241 backends = gensec_security_mechs(gensec_security, mem_ctx);
242 for (i=0; backends && backends[i]; i++) {
243 if (gensec_security != NULL &&
244 !gensec_security_ops_enabled(backends[i], gensec_security))
245 continue;
246 if (backends[i]->name
247 && (strcmp(backends[i]->name, name) == 0)) {
248 backend = backends[i];
249 talloc_free(mem_ctx);
250 return backend;
253 talloc_free(mem_ctx);
254 return NULL;
258 * Return a unique list of security subsystems from those specified in
259 * the list of SASL names.
261 * Use the list of enabled GENSEC mechanisms from the credentials
262 * attached to the gensec_security, and return in our preferred order.
265 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
266 TALLOC_CTX *mem_ctx,
267 const char **sasl_names)
269 const struct gensec_security_ops **backends_out;
270 struct gensec_security_ops **backends;
271 int i, k, sasl_idx;
272 int num_backends_out = 0;
274 if (!sasl_names) {
275 return NULL;
278 backends = gensec_security_mechs(gensec_security, mem_ctx);
280 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
281 if (!backends_out) {
282 return NULL;
284 backends_out[0] = NULL;
286 /* Find backends in our preferred order, by walking our list,
287 * then looking in the supplied list */
288 for (i=0; backends && backends[i]; i++) {
289 if (gensec_security != NULL &&
290 !gensec_security_ops_enabled(backends[i], gensec_security))
291 continue;
292 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
293 if (!backends[i]->sasl_name ||
294 !(strcmp(backends[i]->sasl_name,
295 sasl_names[sasl_idx]) == 0)) {
296 continue;
299 for (k=0; backends_out[k]; k++) {
300 if (backends_out[k] == backends[i]) {
301 break;
305 if (k < num_backends_out) {
306 /* already in there */
307 continue;
310 backends_out = talloc_realloc(mem_ctx, backends_out,
311 const struct gensec_security_ops *,
312 num_backends_out + 2);
313 if (!backends_out) {
314 return NULL;
317 backends_out[num_backends_out] = backends[i];
318 num_backends_out++;
319 backends_out[num_backends_out] = NULL;
322 return backends_out;
326 * Return a unique list of security subsystems from those specified in
327 * the OID list. That is, where two OIDs refer to the same module,
328 * return that module only once.
330 * Use the list of enabled GENSEC mechanisms from the credentials
331 * attached to the gensec_security, and return in our preferred order.
334 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
335 struct gensec_security *gensec_security,
336 TALLOC_CTX *mem_ctx,
337 const char **oid_strings,
338 const char *skip)
340 struct gensec_security_ops_wrapper *backends_out;
341 struct gensec_security_ops **backends;
342 int i, j, k, oid_idx;
343 int num_backends_out = 0;
345 if (!oid_strings) {
346 return NULL;
349 backends = gensec_security_mechs(gensec_security, gensec_security);
351 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
352 if (!backends_out) {
353 return NULL;
355 backends_out[0].op = NULL;
356 backends_out[0].oid = NULL;
358 /* Find backends in our preferred order, by walking our list,
359 * then looking in the supplied list */
360 for (i=0; backends && backends[i]; i++) {
361 if (gensec_security != NULL &&
362 !gensec_security_ops_enabled(backends[i], gensec_security))
363 continue;
364 if (!backends[i]->oid) {
365 continue;
367 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
368 if (strcmp(oid_strings[oid_idx], skip) == 0) {
369 continue;
372 for (j=0; backends[i]->oid[j]; j++) {
373 if (!backends[i]->oid[j] ||
374 !(strcmp(backends[i]->oid[j],
375 oid_strings[oid_idx]) == 0)) {
376 continue;
379 for (k=0; backends_out[k].op; k++) {
380 if (backends_out[k].op == backends[i]) {
381 break;
385 if (k < num_backends_out) {
386 /* already in there */
387 continue;
390 backends_out = talloc_realloc(mem_ctx, backends_out,
391 struct gensec_security_ops_wrapper,
392 num_backends_out + 2);
393 if (!backends_out) {
394 return NULL;
397 backends_out[num_backends_out].op = backends[i];
398 backends_out[num_backends_out].oid = backends[i]->oid[j];
399 num_backends_out++;
400 backends_out[num_backends_out].op = NULL;
401 backends_out[num_backends_out].oid = NULL;
405 return backends_out;
409 * Return OIDS from the security subsystems listed
412 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
413 TALLOC_CTX *mem_ctx,
414 struct gensec_security_ops **ops,
415 const char *skip)
417 int i;
418 int j = 0;
419 int k;
420 const char **oid_list;
421 if (!ops) {
422 return NULL;
424 oid_list = talloc_array(mem_ctx, const char *, 1);
425 if (!oid_list) {
426 return NULL;
429 for (i=0; ops && ops[i]; i++) {
430 if (gensec_security != NULL &&
431 !gensec_security_ops_enabled(ops[i], gensec_security)) {
432 continue;
434 if (!ops[i]->oid) {
435 continue;
438 for (k = 0; ops[i]->oid[k]; k++) {
439 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
440 } else {
441 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
442 if (!oid_list) {
443 return NULL;
445 oid_list[j] = ops[i]->oid[k];
446 j++;
450 oid_list[j] = NULL;
451 return oid_list;
456 * Return OIDS from the security subsystems listed
459 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
460 const struct gensec_security_ops_wrapper *wops)
462 int i;
463 int j = 0;
464 int k;
465 const char **oid_list;
466 if (!wops) {
467 return NULL;
469 oid_list = talloc_array(mem_ctx, const char *, 1);
470 if (!oid_list) {
471 return NULL;
474 for (i=0; wops[i].op; i++) {
475 if (!wops[i].op->oid) {
476 continue;
479 for (k = 0; wops[i].op->oid[k]; k++) {
480 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
481 if (!oid_list) {
482 return NULL;
484 oid_list[j] = wops[i].op->oid[k];
485 j++;
488 oid_list[j] = NULL;
489 return oid_list;
494 * Return all the security subsystems currently enabled on a GENSEC context.
496 * This is taken from a list attached to the cli_credentials, and
497 * skips the OID in 'skip'. (Typically the SPNEGO OID)
501 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
502 TALLOC_CTX *mem_ctx,
503 const char *skip)
505 struct gensec_security_ops **ops
506 = gensec_security_mechs(gensec_security, mem_ctx);
507 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
511 Start the GENSEC system, returning a context pointer.
512 @param mem_ctx The parent TALLOC memory context.
513 @param gensec_security Returned GENSEC context pointer.
514 @note The mem_ctx is only a parent and may be NULL.
515 @note, the auth context is moved to be a referenced pointer of the
516 @ gensec_security return
518 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
519 struct gensec_settings *settings,
520 struct auth4_context *auth_context,
521 struct gensec_security **gensec_security)
523 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
524 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
526 (*gensec_security)->max_update_size = 0;
528 SMB_ASSERT(settings->lp_ctx != NULL);
529 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
531 /* We need to reference this, not steal, as the caller may be
532 * python, which won't like it if we steal it's object away
533 * from it */
534 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
536 return NT_STATUS_OK;
540 * Start a GENSEC subcontext, with a copy of the properties of the parent
541 * @param mem_ctx The parent TALLOC memory context.
542 * @param parent The parent GENSEC context
543 * @param gensec_security Returned GENSEC context pointer.
544 * @note Used by SPNEGO in particular, for the actual implementation mechanism
547 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
548 struct gensec_security *parent,
549 struct gensec_security **gensec_security)
551 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
552 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
554 (**gensec_security) = *parent;
555 (*gensec_security)->ops = NULL;
556 (*gensec_security)->private_data = NULL;
558 (*gensec_security)->subcontext = true;
559 (*gensec_security)->want_features = parent->want_features;
560 (*gensec_security)->max_update_size = parent->max_update_size;
561 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
562 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
563 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
564 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
566 return NT_STATUS_OK;
570 Start the GENSEC system, in client mode, returning a context pointer.
571 @param mem_ctx The parent TALLOC memory context.
572 @param gensec_security Returned GENSEC context pointer.
573 @note The mem_ctx is only a parent and may be NULL.
575 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
576 struct gensec_security **gensec_security,
577 struct gensec_settings *settings)
579 NTSTATUS status;
581 if (settings == NULL) {
582 DEBUG(0,("gensec_client_start: no settings given!\n"));
583 return NT_STATUS_INTERNAL_ERROR;
586 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
587 if (!NT_STATUS_IS_OK(status)) {
588 return status;
590 (*gensec_security)->gensec_role = GENSEC_CLIENT;
592 return status;
598 Start the GENSEC system, in server mode, returning a context pointer.
599 @param mem_ctx The parent TALLOC memory context.
600 @param gensec_security Returned GENSEC context pointer.
601 @note The mem_ctx is only a parent and may be NULL.
603 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
604 struct gensec_settings *settings,
605 struct auth4_context *auth_context,
606 struct gensec_security **gensec_security)
608 NTSTATUS status;
610 if (!settings) {
611 DEBUG(0,("gensec_server_start: no settings given!\n"));
612 return NT_STATUS_INTERNAL_ERROR;
615 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
616 if (!NT_STATUS_IS_OK(status)) {
617 return status;
619 (*gensec_security)->gensec_role = GENSEC_SERVER;
621 return status;
624 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
626 NTSTATUS status;
627 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
628 gensec_security->subcontext ? "sub" : "",
629 gensec_security->ops->name));
630 switch (gensec_security->gensec_role) {
631 case GENSEC_CLIENT:
632 if (gensec_security->ops->client_start) {
633 status = gensec_security->ops->client_start(gensec_security);
634 if (!NT_STATUS_IS_OK(status)) {
635 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
636 gensec_security->ops->name, nt_errstr(status)));
638 return status;
640 break;
641 case GENSEC_SERVER:
642 if (gensec_security->ops->server_start) {
643 status = gensec_security->ops->server_start(gensec_security);
644 if (!NT_STATUS_IS_OK(status)) {
645 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
646 gensec_security->ops->name, nt_errstr(status)));
648 return status;
650 break;
652 return NT_STATUS_INVALID_PARAMETER;
656 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
660 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
661 const struct gensec_security_ops *ops)
663 gensec_security->ops = ops;
664 return gensec_start_mech(gensec_security);
669 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
670 * @param gensec_security GENSEC context pointer.
671 * @param auth_type DCERPC auth type
672 * @param auth_level DCERPC auth level
675 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
676 uint8_t auth_type, uint8_t auth_level)
678 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
679 if (!gensec_security->ops) {
680 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
681 return NT_STATUS_INVALID_PARAMETER;
683 gensec_security->dcerpc_auth_level = auth_level;
684 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
685 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
686 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
687 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
688 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
689 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
690 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
691 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
692 /* Default features */
693 } else {
694 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
695 auth_level));
696 return NT_STATUS_INVALID_PARAMETER;
699 return gensec_start_mech(gensec_security);
702 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
704 const struct gensec_security_ops *ops;
705 ops = gensec_security_by_authtype(gensec_security, authtype);
706 if (ops) {
707 return ops->name;
709 return NULL;
713 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
714 const char *oid_string)
716 const struct gensec_security_ops *ops;
717 ops = gensec_security_by_oid(gensec_security, oid_string);
718 if (ops) {
719 return ops->name;
721 return oid_string;
725 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
727 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
728 * well-known #define to hook it in.
731 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
732 const char *mech_oid)
734 SMB_ASSERT(gensec_security != NULL);
736 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
737 if (!gensec_security->ops) {
738 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
739 return NT_STATUS_INVALID_PARAMETER;
741 return gensec_start_mech(gensec_security);
745 * Start a GENSEC sub-mechanism by a well know SASL name
749 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
750 const char *sasl_name)
752 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
753 if (!gensec_security->ops) {
754 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
755 return NT_STATUS_INVALID_PARAMETER;
757 return gensec_start_mech(gensec_security);
761 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
765 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
766 const char **sasl_names)
768 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
769 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
770 const struct gensec_security_ops **ops;
771 int i;
772 if (!mem_ctx) {
773 return NT_STATUS_NO_MEMORY;
775 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
776 if (!ops || !*ops) {
777 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
778 str_list_join(mem_ctx,
779 sasl_names, ' ')));
780 talloc_free(mem_ctx);
781 return NT_STATUS_INVALID_PARAMETER;
783 for (i=0; ops[i]; i++) {
784 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
785 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
786 break;
789 talloc_free(mem_ctx);
790 return nt_status;
794 * Start a GENSEC sub-mechanism by an internal name
798 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
799 const char *name)
801 gensec_security->ops = gensec_security_by_name(gensec_security, name);
802 if (!gensec_security->ops) {
803 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
804 return NT_STATUS_INVALID_PARAMETER;
806 return gensec_start_mech(gensec_security);
810 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
814 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
816 gensec_security->credentials = talloc_reference(gensec_security, credentials);
817 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
818 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
819 return NT_STATUS_OK;
823 register a GENSEC backend.
825 The 'name' can be later used by other backends to find the operations
826 structure for this backend.
828 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
830 if (gensec_security_by_name(NULL, ops->name) != NULL) {
831 /* its already registered! */
832 DEBUG(0,("GENSEC backend '%s' already registered\n",
833 ops->name));
834 return NT_STATUS_OBJECT_NAME_COLLISION;
837 generic_security_ops = talloc_realloc(talloc_autofree_context(),
838 generic_security_ops,
839 struct gensec_security_ops *,
840 gensec_num_backends+2);
841 if (!generic_security_ops) {
842 return NT_STATUS_NO_MEMORY;
845 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
846 gensec_num_backends++;
847 generic_security_ops[gensec_num_backends] = NULL;
849 DEBUG(3,("GENSEC backend '%s' registered\n",
850 ops->name));
852 return NT_STATUS_OK;
856 return the GENSEC interface version, and the size of some critical types
857 This can be used by backends to either detect compilation errors, or provide
858 multiple implementations for different smbd compilation options in one module
860 const struct gensec_critical_sizes *gensec_interface_version(void)
862 static const struct gensec_critical_sizes critical_sizes = {
863 GENSEC_INTERFACE_VERSION,
864 sizeof(struct gensec_security_ops),
865 sizeof(struct gensec_security),
868 return &critical_sizes;
871 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
872 return (*gs2)->priority - (*gs1)->priority;
875 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
877 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
880 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
882 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
886 initialise the GENSEC subsystem
888 _PUBLIC_ NTSTATUS gensec_init(void)
890 static bool initialized = false;
891 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
892 #ifdef STATIC_gensec_MODULES
893 STATIC_gensec_MODULES_PROTO;
894 init_module_fn static_init[] = { STATIC_gensec_MODULES };
895 #else
896 init_module_fn *static_init = NULL;
897 #endif
898 init_module_fn *shared_init;
900 if (initialized) return NT_STATUS_OK;
901 initialized = true;
903 shared_init = load_samba_modules(NULL, "gensec");
905 run_init_functions(static_init);
906 run_init_functions(shared_init);
908 talloc_free(shared_init);
910 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
912 return NT_STATUS_OK;