Fix bug #9130 - Certain xattrs cause Windows error 0x800700FF
[Samba/vl.git] / auth / gensec / gensec_start.c
blobd3145ec581d2a5c2755955bf591d31d3792e922e
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 * The intended logic is:
57 * if we are in the default AUTO have kerberos:
58 * - take a reference to the master list
59 * otherwise
60 * - always add spnego then:
61 * - if we 'MUST' have kerberos:
62 * only add kerberos mechs
63 * - if we 'DONT' want kerberos':
64 * only add non-kerberos mechs
66 * Once we get things like NegoEx or moonshot, this will of course get
67 * more compplex.
70 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
71 struct gensec_security_ops **old_gensec_list,
72 struct cli_credentials *creds)
74 struct gensec_security_ops **new_gensec_list;
75 int i, j, num_mechs_in;
76 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
78 if (creds) {
79 use_kerberos = cli_credentials_get_kerberos_state(creds);
82 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
83 if (!talloc_reference(mem_ctx, old_gensec_list)) {
84 return NULL;
86 return old_gensec_list;
89 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
90 /* noop */
93 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, 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 found_spnego = false;
102 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
103 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
104 new_gensec_list[j] = old_gensec_list[i];
105 j++;
106 found_spnego = true;
107 break;
110 if (found_spnego) {
111 continue;
113 switch (use_kerberos) {
114 case CRED_DONT_USE_KERBEROS:
115 if (old_gensec_list[i]->kerberos == false) {
116 new_gensec_list[j] = old_gensec_list[i];
117 j++;
119 break;
120 case CRED_MUST_USE_KERBEROS:
121 if (old_gensec_list[i]->kerberos == true) {
122 new_gensec_list[j] = old_gensec_list[i];
123 j++;
125 break;
126 default:
127 /* Can't happen or invalid parameter */
128 return NULL;
131 new_gensec_list[j] = NULL;
133 return new_gensec_list;
136 _PUBLIC_ struct gensec_security_ops **gensec_security_mechs(
137 struct gensec_security *gensec_security,
138 TALLOC_CTX *mem_ctx)
140 struct gensec_security_ops **backends;
141 if (!gensec_security) {
142 backends = gensec_security_all();
143 if (!talloc_reference(mem_ctx, backends)) {
144 return NULL;
146 return backends;
147 } else {
148 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
149 if (gensec_security->settings->backends) {
150 backends = gensec_security->settings->backends;
151 } else {
152 backends = gensec_security_all();
154 if (!creds) {
155 if (!talloc_reference(mem_ctx, backends)) {
156 return NULL;
158 return backends;
160 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
164 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
165 uint8_t auth_type)
167 int i;
168 struct gensec_security_ops **backends;
169 const struct gensec_security_ops *backend;
170 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
171 if (!mem_ctx) {
172 return NULL;
174 backends = gensec_security_mechs(gensec_security, mem_ctx);
175 for (i=0; backends && backends[i]; i++) {
176 if (!gensec_security_ops_enabled(backends[i], gensec_security))
177 continue;
178 if (backends[i]->auth_type == auth_type) {
179 backend = backends[i];
180 talloc_free(mem_ctx);
181 return backend;
184 talloc_free(mem_ctx);
186 return NULL;
189 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
190 struct gensec_security *gensec_security,
191 const char *oid_string)
193 int i, j;
194 struct gensec_security_ops **backends;
195 const struct gensec_security_ops *backend;
196 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
197 if (!mem_ctx) {
198 return NULL;
200 backends = gensec_security_mechs(gensec_security, mem_ctx);
201 for (i=0; backends && backends[i]; i++) {
202 if (gensec_security != NULL &&
203 !gensec_security_ops_enabled(backends[i],
204 gensec_security))
205 continue;
206 if (backends[i]->oid) {
207 for (j=0; backends[i]->oid[j]; j++) {
208 if (backends[i]->oid[j] &&
209 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
210 backend = backends[i];
211 talloc_free(mem_ctx);
212 return backend;
217 talloc_free(mem_ctx);
219 return NULL;
222 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
223 struct gensec_security *gensec_security,
224 const char *sasl_name)
226 int i;
227 struct gensec_security_ops **backends;
228 const struct gensec_security_ops *backend;
229 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
230 if (!mem_ctx) {
231 return NULL;
233 backends = gensec_security_mechs(gensec_security, mem_ctx);
234 for (i=0; backends && backends[i]; i++) {
235 if (!gensec_security_ops_enabled(backends[i], gensec_security))
236 continue;
237 if (backends[i]->sasl_name
238 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
239 backend = backends[i];
240 talloc_free(mem_ctx);
241 return backend;
244 talloc_free(mem_ctx);
246 return NULL;
249 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
250 const char *name)
252 int i;
253 struct gensec_security_ops **backends;
254 const struct gensec_security_ops *backend;
255 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
256 if (!mem_ctx) {
257 return NULL;
259 backends = gensec_security_mechs(gensec_security, mem_ctx);
260 for (i=0; backends && backends[i]; i++) {
261 if (gensec_security != NULL &&
262 !gensec_security_ops_enabled(backends[i], gensec_security))
263 continue;
264 if (backends[i]->name
265 && (strcmp(backends[i]->name, name) == 0)) {
266 backend = backends[i];
267 talloc_free(mem_ctx);
268 return backend;
271 talloc_free(mem_ctx);
272 return NULL;
276 * Return a unique list of security subsystems from those specified in
277 * the list of SASL names.
279 * Use the list of enabled GENSEC mechanisms from the credentials
280 * attached to the gensec_security, and return in our preferred order.
283 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
284 TALLOC_CTX *mem_ctx,
285 const char **sasl_names)
287 const struct gensec_security_ops **backends_out;
288 struct gensec_security_ops **backends;
289 int i, k, sasl_idx;
290 int num_backends_out = 0;
292 if (!sasl_names) {
293 return NULL;
296 backends = gensec_security_mechs(gensec_security, mem_ctx);
298 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
299 if (!backends_out) {
300 return NULL;
302 backends_out[0] = NULL;
304 /* Find backends in our preferred order, by walking our list,
305 * then looking in the supplied list */
306 for (i=0; backends && backends[i]; i++) {
307 if (gensec_security != NULL &&
308 !gensec_security_ops_enabled(backends[i], gensec_security))
309 continue;
310 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
311 if (!backends[i]->sasl_name ||
312 !(strcmp(backends[i]->sasl_name,
313 sasl_names[sasl_idx]) == 0)) {
314 continue;
317 for (k=0; backends_out[k]; k++) {
318 if (backends_out[k] == backends[i]) {
319 break;
323 if (k < num_backends_out) {
324 /* already in there */
325 continue;
328 backends_out = talloc_realloc(mem_ctx, backends_out,
329 const struct gensec_security_ops *,
330 num_backends_out + 2);
331 if (!backends_out) {
332 return NULL;
335 backends_out[num_backends_out] = backends[i];
336 num_backends_out++;
337 backends_out[num_backends_out] = NULL;
340 return backends_out;
344 * Return a unique list of security subsystems from those specified in
345 * the OID list. That is, where two OIDs refer to the same module,
346 * return that module only once.
348 * Use the list of enabled GENSEC mechanisms from the credentials
349 * attached to the gensec_security, and return in our preferred order.
352 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
353 struct gensec_security *gensec_security,
354 TALLOC_CTX *mem_ctx,
355 const char **oid_strings,
356 const char *skip)
358 struct gensec_security_ops_wrapper *backends_out;
359 struct gensec_security_ops **backends;
360 int i, j, k, oid_idx;
361 int num_backends_out = 0;
363 if (!oid_strings) {
364 return NULL;
367 backends = gensec_security_mechs(gensec_security, gensec_security);
369 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
370 if (!backends_out) {
371 return NULL;
373 backends_out[0].op = NULL;
374 backends_out[0].oid = NULL;
376 /* Find backends in our preferred order, by walking our list,
377 * then looking in the supplied list */
378 for (i=0; backends && backends[i]; i++) {
379 if (gensec_security != NULL &&
380 !gensec_security_ops_enabled(backends[i], gensec_security))
381 continue;
382 if (!backends[i]->oid) {
383 continue;
385 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
386 if (strcmp(oid_strings[oid_idx], skip) == 0) {
387 continue;
390 for (j=0; backends[i]->oid[j]; j++) {
391 if (!backends[i]->oid[j] ||
392 !(strcmp(backends[i]->oid[j],
393 oid_strings[oid_idx]) == 0)) {
394 continue;
397 for (k=0; backends_out[k].op; k++) {
398 if (backends_out[k].op == backends[i]) {
399 break;
403 if (k < num_backends_out) {
404 /* already in there */
405 continue;
408 backends_out = talloc_realloc(mem_ctx, backends_out,
409 struct gensec_security_ops_wrapper,
410 num_backends_out + 2);
411 if (!backends_out) {
412 return NULL;
415 backends_out[num_backends_out].op = backends[i];
416 backends_out[num_backends_out].oid = backends[i]->oid[j];
417 num_backends_out++;
418 backends_out[num_backends_out].op = NULL;
419 backends_out[num_backends_out].oid = NULL;
423 return backends_out;
427 * Return OIDS from the security subsystems listed
430 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
431 TALLOC_CTX *mem_ctx,
432 struct gensec_security_ops **ops,
433 const char *skip)
435 int i;
436 int j = 0;
437 int k;
438 const char **oid_list;
439 if (!ops) {
440 return NULL;
442 oid_list = talloc_array(mem_ctx, const char *, 1);
443 if (!oid_list) {
444 return NULL;
447 for (i=0; ops && ops[i]; i++) {
448 if (gensec_security != NULL &&
449 !gensec_security_ops_enabled(ops[i], gensec_security)) {
450 continue;
452 if (!ops[i]->oid) {
453 continue;
456 for (k = 0; ops[i]->oid[k]; k++) {
457 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
458 } else {
459 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
460 if (!oid_list) {
461 return NULL;
463 oid_list[j] = ops[i]->oid[k];
464 j++;
468 oid_list[j] = NULL;
469 return oid_list;
474 * Return OIDS from the security subsystems listed
477 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
478 const struct gensec_security_ops_wrapper *wops)
480 int i;
481 int j = 0;
482 int k;
483 const char **oid_list;
484 if (!wops) {
485 return NULL;
487 oid_list = talloc_array(mem_ctx, const char *, 1);
488 if (!oid_list) {
489 return NULL;
492 for (i=0; wops[i].op; i++) {
493 if (!wops[i].op->oid) {
494 continue;
497 for (k = 0; wops[i].op->oid[k]; k++) {
498 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
499 if (!oid_list) {
500 return NULL;
502 oid_list[j] = wops[i].op->oid[k];
503 j++;
506 oid_list[j] = NULL;
507 return oid_list;
512 * Return all the security subsystems currently enabled on a GENSEC context.
514 * This is taken from a list attached to the cli_credentials, and
515 * skips the OID in 'skip'. (Typically the SPNEGO OID)
519 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
520 TALLOC_CTX *mem_ctx,
521 const char *skip)
523 struct gensec_security_ops **ops
524 = gensec_security_mechs(gensec_security, mem_ctx);
525 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
529 Start the GENSEC system, returning a context pointer.
530 @param mem_ctx The parent TALLOC memory context.
531 @param gensec_security Returned GENSEC context pointer.
532 @note The mem_ctx is only a parent and may be NULL.
533 @note, the auth context is moved to be a referenced pointer of the
534 @ gensec_security return
536 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
537 struct gensec_settings *settings,
538 struct auth4_context *auth_context,
539 struct gensec_security **gensec_security)
541 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
542 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
544 (*gensec_security)->max_update_size = 0;
546 SMB_ASSERT(settings->lp_ctx != NULL);
547 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
549 /* We need to reference this, not steal, as the caller may be
550 * python, which won't like it if we steal it's object away
551 * from it */
552 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
554 return NT_STATUS_OK;
558 * Start a GENSEC subcontext, with a copy of the properties of the parent
559 * @param mem_ctx The parent TALLOC memory context.
560 * @param parent The parent GENSEC context
561 * @param gensec_security Returned GENSEC context pointer.
562 * @note Used by SPNEGO in particular, for the actual implementation mechanism
565 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
566 struct gensec_security *parent,
567 struct gensec_security **gensec_security)
569 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
570 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
572 (**gensec_security) = *parent;
573 (*gensec_security)->ops = NULL;
574 (*gensec_security)->private_data = NULL;
576 (*gensec_security)->subcontext = true;
577 (*gensec_security)->want_features = parent->want_features;
578 (*gensec_security)->max_update_size = parent->max_update_size;
579 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
580 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
581 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
582 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
584 return NT_STATUS_OK;
588 Start the GENSEC system, in client mode, returning a context pointer.
589 @param mem_ctx The parent TALLOC memory context.
590 @param gensec_security Returned GENSEC context pointer.
591 @note The mem_ctx is only a parent and may be NULL.
593 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
594 struct gensec_security **gensec_security,
595 struct gensec_settings *settings)
597 NTSTATUS status;
599 if (settings == NULL) {
600 DEBUG(0,("gensec_client_start: no settings given!\n"));
601 return NT_STATUS_INTERNAL_ERROR;
604 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
605 if (!NT_STATUS_IS_OK(status)) {
606 return status;
608 (*gensec_security)->gensec_role = GENSEC_CLIENT;
610 return status;
616 Start the GENSEC system, in server mode, returning a context pointer.
617 @param mem_ctx The parent TALLOC memory context.
618 @param gensec_security Returned GENSEC context pointer.
619 @note The mem_ctx is only a parent and may be NULL.
621 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
622 struct gensec_settings *settings,
623 struct auth4_context *auth_context,
624 struct gensec_security **gensec_security)
626 NTSTATUS status;
628 if (!settings) {
629 DEBUG(0,("gensec_server_start: no settings given!\n"));
630 return NT_STATUS_INTERNAL_ERROR;
633 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
634 if (!NT_STATUS_IS_OK(status)) {
635 return status;
637 (*gensec_security)->gensec_role = GENSEC_SERVER;
639 return status;
642 NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
644 NTSTATUS status;
645 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
646 gensec_security->subcontext ? "sub" : "",
647 gensec_security->ops->name));
648 switch (gensec_security->gensec_role) {
649 case GENSEC_CLIENT:
650 if (gensec_security->ops->client_start) {
651 status = gensec_security->ops->client_start(gensec_security);
652 if (!NT_STATUS_IS_OK(status)) {
653 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
654 gensec_security->ops->name, nt_errstr(status)));
656 return status;
658 break;
659 case GENSEC_SERVER:
660 if (gensec_security->ops->server_start) {
661 status = gensec_security->ops->server_start(gensec_security);
662 if (!NT_STATUS_IS_OK(status)) {
663 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
664 gensec_security->ops->name, nt_errstr(status)));
666 return status;
668 break;
670 return NT_STATUS_INVALID_PARAMETER;
674 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
678 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
679 const struct gensec_security_ops *ops)
681 gensec_security->ops = ops;
682 return gensec_start_mech(gensec_security);
687 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
688 * @param gensec_security GENSEC context pointer.
689 * @param auth_type DCERPC auth type
690 * @param auth_level DCERPC auth level
693 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
694 uint8_t auth_type, uint8_t auth_level)
696 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
697 if (!gensec_security->ops) {
698 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
699 return NT_STATUS_INVALID_PARAMETER;
701 gensec_security->dcerpc_auth_level = auth_level;
702 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
703 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
704 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
705 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
706 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
707 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
708 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
709 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
710 /* Default features */
711 } else {
712 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
713 auth_level));
714 return NT_STATUS_INVALID_PARAMETER;
717 return gensec_start_mech(gensec_security);
720 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
722 const struct gensec_security_ops *ops;
723 ops = gensec_security_by_authtype(gensec_security, authtype);
724 if (ops) {
725 return ops->name;
727 return NULL;
731 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
732 const char *oid_string)
734 const struct gensec_security_ops *ops;
735 ops = gensec_security_by_oid(gensec_security, oid_string);
736 if (ops) {
737 return ops->name;
739 return oid_string;
743 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
745 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
746 * well-known #define to hook it in.
749 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
750 const char *mech_oid)
752 SMB_ASSERT(gensec_security != NULL);
754 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
755 if (!gensec_security->ops) {
756 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
757 return NT_STATUS_INVALID_PARAMETER;
759 return gensec_start_mech(gensec_security);
763 * Start a GENSEC sub-mechanism by a well know SASL name
767 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
768 const char *sasl_name)
770 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
771 if (!gensec_security->ops) {
772 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
773 return NT_STATUS_INVALID_PARAMETER;
775 return gensec_start_mech(gensec_security);
779 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
783 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
784 const char **sasl_names)
786 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
787 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
788 const struct gensec_security_ops **ops;
789 int i;
790 if (!mem_ctx) {
791 return NT_STATUS_NO_MEMORY;
793 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
794 if (!ops || !*ops) {
795 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
796 str_list_join(mem_ctx,
797 sasl_names, ' ')));
798 talloc_free(mem_ctx);
799 return NT_STATUS_INVALID_PARAMETER;
801 for (i=0; ops[i]; i++) {
802 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
803 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
804 break;
807 talloc_free(mem_ctx);
808 return nt_status;
812 * Start a GENSEC sub-mechanism by an internal name
816 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
817 const char *name)
819 gensec_security->ops = gensec_security_by_name(gensec_security, name);
820 if (!gensec_security->ops) {
821 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
822 return NT_STATUS_INVALID_PARAMETER;
824 return gensec_start_mech(gensec_security);
828 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
832 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
834 gensec_security->credentials = talloc_reference(gensec_security, credentials);
835 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
836 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
837 return NT_STATUS_OK;
841 register a GENSEC backend.
843 The 'name' can be later used by other backends to find the operations
844 structure for this backend.
846 _PUBLIC_ NTSTATUS gensec_register(const struct gensec_security_ops *ops)
848 if (gensec_security_by_name(NULL, ops->name) != NULL) {
849 /* its already registered! */
850 DEBUG(0,("GENSEC backend '%s' already registered\n",
851 ops->name));
852 return NT_STATUS_OBJECT_NAME_COLLISION;
855 generic_security_ops = talloc_realloc(talloc_autofree_context(),
856 generic_security_ops,
857 struct gensec_security_ops *,
858 gensec_num_backends+2);
859 if (!generic_security_ops) {
860 return NT_STATUS_NO_MEMORY;
863 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
864 gensec_num_backends++;
865 generic_security_ops[gensec_num_backends] = NULL;
867 DEBUG(3,("GENSEC backend '%s' registered\n",
868 ops->name));
870 return NT_STATUS_OK;
874 return the GENSEC interface version, and the size of some critical types
875 This can be used by backends to either detect compilation errors, or provide
876 multiple implementations for different smbd compilation options in one module
878 const struct gensec_critical_sizes *gensec_interface_version(void)
880 static const struct gensec_critical_sizes critical_sizes = {
881 GENSEC_INTERFACE_VERSION,
882 sizeof(struct gensec_security_ops),
883 sizeof(struct gensec_security),
886 return &critical_sizes;
889 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
890 return (*gs2)->priority - (*gs1)->priority;
893 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
895 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
898 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
900 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
904 initialise the GENSEC subsystem
906 _PUBLIC_ NTSTATUS gensec_init(void)
908 static bool initialized = false;
909 #define _MODULE_PROTO(init) extern NTSTATUS init(void);
910 #ifdef STATIC_gensec_MODULES
911 STATIC_gensec_MODULES_PROTO;
912 init_module_fn static_init[] = { STATIC_gensec_MODULES };
913 #else
914 init_module_fn *static_init = NULL;
915 #endif
916 init_module_fn *shared_init;
918 if (initialized) return NT_STATUS_OK;
919 initialized = true;
921 shared_init = load_samba_modules(NULL, "gensec");
923 run_init_functions(static_init);
924 run_init_functions(shared_init);
926 talloc_free(shared_init);
928 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
930 return NT_STATUS_OK;