python:tests: Raise exception of more specific type NotImplementedError
[Samba.git] / auth / gensec / gensec_start.c
blob072188a67522863c38a54282934cf569973073d6
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/param/loadparm.h"
33 #include "lib/util/tsort.h"
34 #include "lib/util/samba_modules.h"
35 #include "lib/util/base64.h"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_AUTH
40 #undef strcasecmp
42 /* the list of currently registered GENSEC backends */
43 static const struct gensec_security_ops **generic_security_ops;
44 static int gensec_num_backends;
46 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
48 bool ok = lpcfg_parm_bool(security->settings->lp_ctx,
49 NULL,
50 "gensec",
51 ops->name,
52 ops->enabled);
54 if (ops->weak_crypto &&
55 lpcfg_weak_crypto(security->settings->lp_ctx) != SAMBA_WEAK_CRYPTO_ALLOWED) {
56 ok = false;
59 return ok;
62 /* Sometimes we want to force only kerberos, sometimes we want to
63 * force it's avoidance. The old list could be either
64 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
65 * an existing list we have trimmed down)
67 * The intended logic is:
69 * if we are in the default AUTO have kerberos:
70 * - take a reference to the master list
71 * otherwise
72 * - always add spnego then:
73 * - if we 'MUST' have kerberos:
74 * only add kerberos mechs
75 * - if we 'DONT' want kerberos':
76 * only add non-kerberos mechs
78 * Once we get things like NegoEx or moonshot, this will of course get
79 * more complex.
82 static const struct gensec_security_ops **gensec_use_kerberos_mechs(
83 TALLOC_CTX *mem_ctx,
84 const struct gensec_security_ops * const *old_gensec_list,
85 enum credentials_use_kerberos use_kerberos,
86 bool keep_schannel)
88 const struct gensec_security_ops **new_gensec_list;
89 int i, j, num_mechs_in;
91 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
92 /* noop */
95 new_gensec_list = talloc_array(mem_ctx,
96 const struct gensec_security_ops *,
97 num_mechs_in + 1);
98 if (!new_gensec_list) {
99 return NULL;
102 j = 0;
103 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
104 bool keep = false;
107 * We want to keep SPNEGO and other backends
109 keep = old_gensec_list[i]->glue;
111 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
112 keep = keep_schannel;
115 switch (use_kerberos) {
116 case CRED_USE_KERBEROS_DESIRED:
117 keep = true;
118 break;
120 case CRED_USE_KERBEROS_DISABLED:
121 if (old_gensec_list[i]->kerberos == false) {
122 keep = true;
125 break;
127 case CRED_USE_KERBEROS_REQUIRED:
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 const struct gensec_security_ops * const *backends =
155 generic_security_ops;
156 enum credentials_use_kerberos use_kerberos = CRED_USE_KERBEROS_DESIRED;
157 bool keep_schannel = false;
159 if (gensec_security != NULL) {
160 struct cli_credentials *creds = NULL;
162 creds = gensec_get_credentials(gensec_security);
163 if (creds != NULL) {
164 use_kerberos = cli_credentials_get_kerberos_state(creds);
165 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
166 keep_schannel = true;
170 * Even if Kerberos is set to REQUIRED, keep the
171 * schannel auth mechanism so that machine accounts are
172 * able to authenticate via netlogon.
174 if (gensec_security->gensec_role == GENSEC_SERVER) {
175 keep_schannel = true;
179 if (gensec_security->settings->backends) {
180 backends = gensec_security->settings->backends;
184 return gensec_use_kerberos_mechs(mem_ctx, backends,
185 use_kerberos, keep_schannel);
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 const 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 const 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 != NULL &&
236 !gensec_security_ops_enabled(backends[i], gensec_security)) {
237 continue;
239 if (backends[i]->sasl_name
240 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
241 backend = backends[i];
242 talloc_free(mem_ctx);
243 return backend;
246 talloc_free(mem_ctx);
248 return NULL;
251 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
252 struct gensec_security *gensec_security,
253 uint32_t auth_type)
255 int i;
256 const struct gensec_security_ops **backends;
257 const struct gensec_security_ops *backend;
258 TALLOC_CTX *mem_ctx;
260 if (auth_type == DCERPC_AUTH_TYPE_NONE) {
261 return NULL;
264 mem_ctx = talloc_new(gensec_security);
265 if (!mem_ctx) {
266 return NULL;
268 backends = gensec_security_mechs(gensec_security, mem_ctx);
269 for (i=0; backends && backends[i]; i++) {
270 if (gensec_security != NULL &&
271 !gensec_security_ops_enabled(backends[i], gensec_security)) {
272 continue;
274 if (backends[i]->auth_type == auth_type) {
275 backend = backends[i];
276 talloc_free(mem_ctx);
277 return backend;
280 talloc_free(mem_ctx);
282 return NULL;
285 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
286 const char *name)
288 int i;
289 const struct gensec_security_ops **backends;
290 const struct gensec_security_ops *backend;
291 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
292 if (!mem_ctx) {
293 return NULL;
295 backends = gensec_security_mechs(gensec_security, mem_ctx);
296 for (i=0; backends && backends[i]; i++) {
297 if (gensec_security != NULL &&
298 !gensec_security_ops_enabled(backends[i], gensec_security))
299 continue;
300 if (backends[i]->name
301 && (strcmp(backends[i]->name, name) == 0)) {
302 backend = backends[i];
303 talloc_free(mem_ctx);
304 return backend;
307 talloc_free(mem_ctx);
308 return NULL;
311 static const char **gensec_security_sasl_names_from_ops(
312 struct gensec_security *gensec_security,
313 TALLOC_CTX *mem_ctx,
314 const struct gensec_security_ops * const *ops)
316 const char **sasl_names = NULL;
317 size_t i, sasl_names_count = 0;
319 if (ops == NULL) {
320 return NULL;
323 sasl_names = talloc_array(mem_ctx, const char *, 1);
324 if (sasl_names == NULL) {
325 return NULL;
328 for (i = 0; ops[i] != NULL; i++) {
329 enum gensec_role role = GENSEC_SERVER;
330 const char **tmp = NULL;
332 if (ops[i]->sasl_name == NULL) {
333 continue;
336 if (gensec_security != NULL) {
337 if (!gensec_security_ops_enabled(ops[i],
338 gensec_security)) {
339 continue;
342 role = gensec_security->gensec_role;
345 switch (role) {
346 case GENSEC_CLIENT:
347 if (ops[i]->client_start == NULL) {
348 continue;
350 break;
351 case GENSEC_SERVER:
352 if (ops[i]->server_start == NULL) {
353 continue;
355 break;
358 tmp = talloc_realloc(mem_ctx,
359 sasl_names,
360 const char *,
361 sasl_names_count + 2);
362 if (tmp == NULL) {
363 TALLOC_FREE(sasl_names);
364 return NULL;
366 sasl_names = tmp;
368 sasl_names[sasl_names_count] = ops[i]->sasl_name;
369 sasl_names_count++;
371 sasl_names[sasl_names_count] = NULL;
373 return sasl_names;
377 * @brief Get the sasl names from the gensec security context.
379 * @param[in] gensec_security The gensec security context.
381 * @param[in] mem_ctx The memory context to allocate memory on.
383 * @return An allocated array with sasl names, NULL on error.
385 _PUBLIC_
386 const char **gensec_security_sasl_names(struct gensec_security *gensec_security,
387 TALLOC_CTX *mem_ctx)
389 const struct gensec_security_ops **ops = NULL;
391 ops = gensec_security_mechs(gensec_security, mem_ctx);
393 return gensec_security_sasl_names_from_ops(gensec_security,
394 mem_ctx,
395 ops);
399 * Return a unique list of security subsystems from those specified in
400 * the list of SASL names.
402 * Use the list of enabled GENSEC mechanisms from the credentials
403 * attached to the gensec_security, and return in our preferred order.
406 static const struct gensec_security_ops **gensec_security_by_sasl_list(
407 struct gensec_security *gensec_security,
408 TALLOC_CTX *mem_ctx,
409 const char **sasl_names)
411 const struct gensec_security_ops **backends_out;
412 const struct gensec_security_ops **backends;
413 int i, k, sasl_idx;
414 int num_backends_out = 0;
416 if (!sasl_names) {
417 return NULL;
420 backends = gensec_security_mechs(gensec_security, mem_ctx);
422 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
423 if (!backends_out) {
424 return NULL;
426 backends_out[0] = NULL;
428 /* Find backends in our preferred order, by walking our list,
429 * then looking in the supplied list */
430 for (i=0; backends && backends[i]; i++) {
431 if (gensec_security != NULL &&
432 !gensec_security_ops_enabled(backends[i], gensec_security))
433 continue;
434 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
435 if (!backends[i]->sasl_name ||
436 !(strcmp(backends[i]->sasl_name,
437 sasl_names[sasl_idx]) == 0)) {
438 continue;
441 for (k=0; backends_out[k]; k++) {
442 if (backends_out[k] == backends[i]) {
443 break;
447 if (k < num_backends_out) {
448 /* already in there */
449 continue;
452 backends_out = talloc_realloc(mem_ctx, backends_out,
453 const struct gensec_security_ops *,
454 num_backends_out + 2);
455 if (!backends_out) {
456 return NULL;
459 backends_out[num_backends_out] = backends[i];
460 num_backends_out++;
461 backends_out[num_backends_out] = NULL;
464 return backends_out;
468 * Return a unique list of security subsystems from those specified in
469 * the OID list. That is, where two OIDs refer to the same module,
470 * return that module only once.
472 * Use the list of enabled GENSEC mechanisms from the credentials
473 * attached to the gensec_security, and return in our preferred order.
476 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
477 struct gensec_security *gensec_security,
478 TALLOC_CTX *mem_ctx,
479 const char * const *oid_strings,
480 const char *skip)
482 struct gensec_security_ops_wrapper *backends_out;
483 const struct gensec_security_ops **backends;
484 int i, j, k, oid_idx;
485 int num_backends_out = 0;
487 if (!oid_strings) {
488 return NULL;
491 backends = gensec_security_mechs(gensec_security, gensec_security);
493 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
494 if (!backends_out) {
495 return NULL;
497 backends_out[0].op = NULL;
498 backends_out[0].oid = NULL;
500 /* Find backends in our preferred order, by walking our list,
501 * then looking in the supplied list */
502 for (i=0; backends && backends[i]; i++) {
503 if (gensec_security != NULL &&
504 !gensec_security_ops_enabled(backends[i], gensec_security))
505 continue;
506 if (!backends[i]->oid) {
507 continue;
509 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
510 if (strcmp(oid_strings[oid_idx], skip) == 0) {
511 continue;
514 for (j=0; backends[i]->oid[j]; j++) {
515 if (!backends[i]->oid[j] ||
516 !(strcmp(backends[i]->oid[j],
517 oid_strings[oid_idx]) == 0)) {
518 continue;
521 for (k=0; backends_out[k].op; k++) {
522 if (backends_out[k].op == backends[i]) {
523 break;
527 if (k < num_backends_out) {
528 /* already in there */
529 continue;
532 backends_out = talloc_realloc(mem_ctx, backends_out,
533 struct gensec_security_ops_wrapper,
534 num_backends_out + 2);
535 if (!backends_out) {
536 return NULL;
539 backends_out[num_backends_out].op = backends[i];
540 backends_out[num_backends_out].oid = backends[i]->oid[j];
541 num_backends_out++;
542 backends_out[num_backends_out].op = NULL;
543 backends_out[num_backends_out].oid = NULL;
547 return backends_out;
551 * Return OIDS from the security subsystems listed
554 static const char **gensec_security_oids_from_ops(
555 struct gensec_security *gensec_security,
556 TALLOC_CTX *mem_ctx,
557 const struct gensec_security_ops * const *ops,
558 const char *skip)
560 int i;
561 int j = 0;
562 int k;
563 const char **oid_list;
564 if (!ops) {
565 return NULL;
567 oid_list = talloc_array(mem_ctx, const char *, 1);
568 if (!oid_list) {
569 return NULL;
572 for (i=0; ops && ops[i]; i++) {
573 if (gensec_security != NULL &&
574 !gensec_security_ops_enabled(ops[i], gensec_security)) {
575 continue;
577 if (!ops[i]->oid) {
578 continue;
581 for (k = 0; ops[i]->oid[k]; k++) {
582 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
583 } else {
584 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
585 if (!oid_list) {
586 return NULL;
588 oid_list[j] = ops[i]->oid[k];
589 j++;
593 oid_list[j] = NULL;
594 return oid_list;
599 * Return OIDS from the security subsystems listed
602 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
603 const struct gensec_security_ops_wrapper *wops)
605 int i;
606 int j = 0;
607 int k;
608 const char **oid_list;
609 if (!wops) {
610 return NULL;
612 oid_list = talloc_array(mem_ctx, const char *, 1);
613 if (!oid_list) {
614 return NULL;
617 for (i=0; wops[i].op; i++) {
618 if (!wops[i].op->oid) {
619 continue;
622 for (k = 0; wops[i].op->oid[k]; k++) {
623 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
624 if (!oid_list) {
625 return NULL;
627 oid_list[j] = wops[i].op->oid[k];
628 j++;
631 oid_list[j] = NULL;
632 return oid_list;
637 * Return all the security subsystems currently enabled on a GENSEC context.
639 * This is taken from a list attached to the cli_credentials, and
640 * skips the OID in 'skip'. (Typically the SPNEGO OID)
644 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
645 TALLOC_CTX *mem_ctx,
646 const char *skip)
648 const struct gensec_security_ops **ops;
650 ops = gensec_security_mechs(gensec_security, mem_ctx);
652 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
655 static int gensec_security_destructor(struct gensec_security *gctx)
657 if (gctx->parent_security != NULL) {
658 if (gctx->parent_security->child_security == gctx) {
659 gctx->parent_security->child_security = NULL;
661 gctx->parent_security = NULL;
664 if (gctx->child_security != NULL) {
665 if (gctx->child_security->parent_security == gctx) {
666 gctx->child_security->parent_security = NULL;
668 gctx->child_security = NULL;
671 return 0;
675 Start the GENSEC system, returning a context pointer.
676 @param mem_ctx The parent TALLOC memory context.
677 @param gensec_security Returned GENSEC context pointer.
678 @note The mem_ctx is only a parent and may be NULL.
679 @note, the auth context is moved to be a referenced pointer of the
680 @ gensec_security return
682 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
683 struct gensec_settings *settings,
684 struct auth4_context *auth_context,
685 struct gensec_security **gensec_security)
687 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
688 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
690 (*gensec_security)->max_update_size = 0;
692 SMB_ASSERT(settings->lp_ctx != NULL);
693 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
695 /* We need to reference this, not steal, as the caller may be
696 * python, which won't like it if we steal it's object away
697 * from it */
698 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
700 talloc_set_destructor((*gensec_security), gensec_security_destructor);
701 return NT_STATUS_OK;
705 * Start a GENSEC subcontext, with a copy of the properties of the parent
706 * @param mem_ctx The parent TALLOC memory context.
707 * @param parent The parent GENSEC context
708 * @param gensec_security Returned GENSEC context pointer.
709 * @note Used by SPNEGO in particular, for the actual implementation mechanism
712 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
713 struct gensec_security *parent,
714 struct gensec_security **gensec_security)
716 if (parent->child_security != NULL) {
717 return NT_STATUS_INTERNAL_ERROR;
720 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
721 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
723 (**gensec_security) = *parent;
724 (*gensec_security)->ops = NULL;
725 (*gensec_security)->private_data = NULL;
726 (*gensec_security)->update_busy_ptr = NULL;
728 (*gensec_security)->subcontext = true;
729 (*gensec_security)->want_features = parent->want_features;
730 (*gensec_security)->max_update_size = parent->max_update_size;
731 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
732 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
733 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
734 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
736 talloc_set_destructor((*gensec_security), gensec_security_destructor);
737 return NT_STATUS_OK;
740 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
741 struct gensec_security *child)
743 if (parent->child_security != NULL) {
744 return NT_STATUS_INTERNAL_ERROR;
747 if (child->parent_security != NULL) {
748 return NT_STATUS_INTERNAL_ERROR;
751 parent->child_security = child;
752 child->parent_security = parent;
753 return NT_STATUS_OK;
757 Start the GENSEC system, in client mode, returning a context pointer.
758 @param mem_ctx The parent TALLOC memory context.
759 @param gensec_security Returned GENSEC context pointer.
760 @note The mem_ctx is only a parent and may be NULL.
762 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
763 struct gensec_security **gensec_security,
764 struct gensec_settings *settings)
766 NTSTATUS status;
768 if (settings == NULL) {
769 DEBUG(0,("gensec_client_start: no settings given!\n"));
770 return NT_STATUS_INTERNAL_ERROR;
773 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
774 if (!NT_STATUS_IS_OK(status)) {
775 return status;
777 (*gensec_security)->gensec_role = GENSEC_CLIENT;
779 return status;
785 Start the GENSEC system, in server mode, returning a context pointer.
786 @param mem_ctx The parent TALLOC memory context.
787 @param gensec_security Returned GENSEC context pointer.
788 @note The mem_ctx is only a parent and may be NULL.
790 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
791 struct gensec_settings *settings,
792 struct auth4_context *auth_context,
793 struct gensec_security **gensec_security)
795 NTSTATUS status;
797 if (!settings) {
798 DEBUG(0,("gensec_server_start: no settings given!\n"));
799 return NT_STATUS_INTERNAL_ERROR;
802 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
803 if (!NT_STATUS_IS_OK(status)) {
804 return status;
806 (*gensec_security)->gensec_role = GENSEC_SERVER;
808 return status;
811 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
813 NTSTATUS status;
816 * Callers sometimes just reuse a context, we should
817 * clear the internal state before starting it again.
819 talloc_unlink(gensec_security, gensec_security->private_data);
820 gensec_security->private_data = NULL;
822 if (gensec_security->child_security != NULL) {
824 * The talloc_unlink(.., gensec_security->private_data)
825 * should have cleared this via
826 * gensec_security_destructor().
828 return NT_STATUS_INTERNAL_ERROR;
831 if (gensec_security->credentials) {
832 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
833 if (forced_mech &&
834 (gensec_security->ops->sasl_name == NULL ||
835 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
836 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
837 "did not match forced mechanism %s\n",
838 gensec_security->ops->name,
839 gensec_security->ops->sasl_name,
840 forced_mech));
841 return NT_STATUS_INVALID_PARAMETER;
844 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
845 gensec_security->subcontext ? "sub" : "",
846 gensec_security->ops->name));
847 switch (gensec_security->gensec_role) {
848 case GENSEC_CLIENT:
849 if (gensec_security->ops->client_start) {
850 status = gensec_security->ops->client_start(gensec_security);
851 if (!NT_STATUS_IS_OK(status)) {
852 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
853 gensec_security->ops->name, nt_errstr(status)));
855 return status;
857 break;
858 case GENSEC_SERVER:
859 if (gensec_security->ops->server_start) {
860 status = gensec_security->ops->server_start(gensec_security);
861 if (!NT_STATUS_IS_OK(status)) {
862 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
863 gensec_security->ops->name, nt_errstr(status)));
865 return status;
867 break;
869 return NT_STATUS_INVALID_PARAMETER;
873 * Start a GENSEC sub-mechanism with a specified mechanism structure, used in SPNEGO
877 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
878 const struct gensec_security_ops *ops)
880 gensec_security->ops = ops;
881 return gensec_start_mech(gensec_security);
886 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
887 * @param gensec_security GENSEC context pointer.
888 * @param auth_type DCERPC auth type
889 * @param auth_level DCERPC auth level
892 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
893 uint8_t auth_type, uint8_t auth_level)
895 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
896 if (!gensec_security->ops) {
897 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
898 return NT_STATUS_INVALID_PARAMETER;
900 gensec_security->dcerpc_auth_level = auth_level;
902 * We need to reset sign/seal in order to reset it.
903 * We may got some default features inherited by the credentials
905 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
906 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
907 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
908 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
909 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
910 if (gensec_security->gensec_role == GENSEC_CLIENT) {
911 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
913 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
915 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
916 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
918 if (gensec_security->gensec_role == GENSEC_CLIENT) {
919 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
921 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
922 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
923 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
924 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
925 /* Default features */
926 } else {
927 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
928 auth_level));
929 return NT_STATUS_INVALID_PARAMETER;
932 return gensec_start_mech(gensec_security);
935 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
937 const struct gensec_security_ops *ops;
938 ops = gensec_security_by_auth_type(gensec_security, authtype);
939 if (ops) {
940 return ops->name;
942 return NULL;
946 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
947 const char *oid_string)
949 const struct gensec_security_ops *ops;
950 ops = gensec_security_by_oid(gensec_security, oid_string);
951 if (ops) {
952 return ops->name;
954 return oid_string;
958 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
960 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
961 * well-known #define to hook it in.
964 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
965 const char *mech_oid)
967 SMB_ASSERT(gensec_security != NULL);
969 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
970 if (!gensec_security->ops) {
971 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
972 return NT_STATUS_INVALID_PARAMETER;
974 return gensec_start_mech(gensec_security);
978 * Start a GENSEC sub-mechanism by a well known SASL name
982 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
983 const char *sasl_name)
985 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
986 if (!gensec_security->ops) {
987 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
988 return NT_STATUS_INVALID_PARAMETER;
990 return gensec_start_mech(gensec_security);
994 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
998 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
999 const char **sasl_names)
1001 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
1002 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
1003 const struct gensec_security_ops **ops;
1004 int i;
1005 if (!mem_ctx) {
1006 return NT_STATUS_NO_MEMORY;
1008 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
1009 if (!ops || !*ops) {
1010 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
1011 str_list_join(mem_ctx,
1012 sasl_names, ' ')));
1013 talloc_free(mem_ctx);
1014 return NT_STATUS_INVALID_PARAMETER;
1016 for (i=0; ops[i]; i++) {
1017 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
1018 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
1019 break;
1022 talloc_free(mem_ctx);
1023 return nt_status;
1027 * Start a GENSEC sub-mechanism by an internal name
1031 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
1032 const char *name)
1034 gensec_security->ops = gensec_security_by_name(gensec_security, name);
1035 if (!gensec_security->ops) {
1036 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
1037 return NT_STATUS_INVALID_PARAMETER;
1039 return gensec_start_mech(gensec_security);
1043 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1047 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1049 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1050 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1051 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1052 return NT_STATUS_OK;
1056 register a GENSEC backend.
1058 The 'name' can be later used by other backends to find the operations
1059 structure for this backend.
1061 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
1062 const struct gensec_security_ops *ops)
1064 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1065 /* its already registered! */
1066 DEBUG(0,("GENSEC backend '%s' already registered\n",
1067 ops->name));
1068 return NT_STATUS_OBJECT_NAME_COLLISION;
1071 generic_security_ops = talloc_realloc(ctx,
1072 generic_security_ops,
1073 const struct gensec_security_ops *,
1074 gensec_num_backends+2);
1075 if (!generic_security_ops) {
1076 return NT_STATUS_NO_MEMORY;
1079 generic_security_ops[gensec_num_backends] = ops;
1080 gensec_num_backends++;
1081 generic_security_ops[gensec_num_backends] = NULL;
1083 DEBUG(3,("GENSEC backend '%s' registered\n",
1084 ops->name));
1086 return NT_STATUS_OK;
1090 return the GENSEC interface version, and the size of some critical types
1091 This can be used by backends to either detect compilation errors, or provide
1092 multiple implementations for different smbd compilation options in one module
1094 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
1096 static const struct gensec_critical_sizes critical_sizes = {
1097 GENSEC_INTERFACE_VERSION,
1098 sizeof(struct gensec_security_ops),
1099 sizeof(struct gensec_security),
1102 return &critical_sizes;
1105 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
1106 return (*gs2)->priority - (*gs1)->priority;
1109 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1111 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1114 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1116 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1120 initialise the GENSEC subsystem
1122 _PUBLIC_ NTSTATUS gensec_init(void)
1124 static bool initialized = false;
1125 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1126 #ifdef STATIC_gensec_MODULES
1127 STATIC_gensec_MODULES_PROTO;
1128 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1129 #else
1130 init_module_fn *static_init = NULL;
1131 #endif
1132 init_module_fn *shared_init;
1134 if (initialized) return NT_STATUS_OK;
1135 initialized = true;
1137 shared_init = load_samba_modules(NULL, "gensec");
1139 run_init_functions(NULL, static_init);
1140 run_init_functions(NULL, shared_init);
1142 talloc_free(shared_init);
1144 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1146 return NT_STATUS_OK;