s3:libads: add ads_connect_machine() helper
[Samba.git] / auth / gensec / gensec_start.c
blob4405aca278dfedce11a5a44052ffcfccfbe2aabe
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);
735 (*gensec_security)->channel_bindings = talloc_reference(*gensec_security, parent->channel_bindings);
737 talloc_set_destructor((*gensec_security), gensec_security_destructor);
738 return NT_STATUS_OK;
741 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
742 struct gensec_security *child)
744 if (parent->child_security != NULL) {
745 return NT_STATUS_INTERNAL_ERROR;
748 if (child->parent_security != NULL) {
749 return NT_STATUS_INTERNAL_ERROR;
752 parent->child_security = child;
753 child->parent_security = parent;
754 return NT_STATUS_OK;
758 Start the GENSEC system, in client mode, returning a context pointer.
759 @param mem_ctx The parent TALLOC memory context.
760 @param gensec_security Returned GENSEC context pointer.
761 @note The mem_ctx is only a parent and may be NULL.
763 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
764 struct gensec_security **gensec_security,
765 struct gensec_settings *settings)
767 NTSTATUS status;
769 if (settings == NULL) {
770 DEBUG(0,("gensec_client_start: no settings given!\n"));
771 return NT_STATUS_INTERNAL_ERROR;
774 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
775 if (!NT_STATUS_IS_OK(status)) {
776 return status;
778 (*gensec_security)->gensec_role = GENSEC_CLIENT;
780 return status;
786 Start the GENSEC system, in server mode, returning a context pointer.
787 @param mem_ctx The parent TALLOC memory context.
788 @param gensec_security Returned GENSEC context pointer.
789 @note The mem_ctx is only a parent and may be NULL.
791 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
792 struct gensec_settings *settings,
793 struct auth4_context *auth_context,
794 struct gensec_security **gensec_security)
796 NTSTATUS status;
798 if (!settings) {
799 DEBUG(0,("gensec_server_start: no settings given!\n"));
800 return NT_STATUS_INTERNAL_ERROR;
803 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
804 if (!NT_STATUS_IS_OK(status)) {
805 return status;
807 (*gensec_security)->gensec_role = GENSEC_SERVER;
809 return status;
812 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
814 NTSTATUS status;
817 * Callers sometimes just reuse a context, we should
818 * clear the internal state before starting it again.
820 talloc_unlink(gensec_security, gensec_security->private_data);
821 gensec_security->private_data = NULL;
823 if (gensec_security->child_security != NULL) {
825 * The talloc_unlink(.., gensec_security->private_data)
826 * should have cleared this via
827 * gensec_security_destructor().
829 return NT_STATUS_INTERNAL_ERROR;
832 if (gensec_security->credentials) {
833 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
834 if (forced_mech &&
835 (gensec_security->ops->sasl_name == NULL ||
836 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
837 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
838 "did not match forced mechanism %s\n",
839 gensec_security->ops->name,
840 gensec_security->ops->sasl_name,
841 forced_mech));
842 return NT_STATUS_INVALID_PARAMETER;
845 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
846 gensec_security->subcontext ? "sub" : "",
847 gensec_security->ops->name));
848 switch (gensec_security->gensec_role) {
849 case GENSEC_CLIENT:
850 if (gensec_security->ops->client_start) {
851 status = gensec_security->ops->client_start(gensec_security);
852 if (!NT_STATUS_IS_OK(status)) {
853 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
854 gensec_security->ops->name, nt_errstr(status)));
856 return status;
858 break;
859 case GENSEC_SERVER:
860 if (gensec_security->ops->server_start) {
861 status = gensec_security->ops->server_start(gensec_security);
862 if (!NT_STATUS_IS_OK(status)) {
863 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
864 gensec_security->ops->name, nt_errstr(status)));
866 return status;
868 break;
870 return NT_STATUS_INVALID_PARAMETER;
874 * Start a GENSEC sub-mechanism with a specified mechanism structure, used in SPNEGO
878 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
879 const struct gensec_security_ops *ops)
881 gensec_security->ops = ops;
882 return gensec_start_mech(gensec_security);
887 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
888 * @param gensec_security GENSEC context pointer.
889 * @param auth_type DCERPC auth type
890 * @param auth_level DCERPC auth level
893 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
894 uint8_t auth_type, uint8_t auth_level)
896 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
897 if (!gensec_security->ops) {
898 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
899 return NT_STATUS_INVALID_PARAMETER;
901 gensec_security->dcerpc_auth_level = auth_level;
903 * We need to reset sign/seal in order to reset it.
904 * We may got some default features inherited by the credentials
906 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
907 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
908 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
909 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
910 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
911 if (gensec_security->gensec_role == GENSEC_CLIENT) {
912 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
914 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
916 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
917 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
919 if (gensec_security->gensec_role == GENSEC_CLIENT) {
920 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
922 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
923 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
924 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
925 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
926 /* Default features */
927 } else {
928 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
929 auth_level));
930 return NT_STATUS_INVALID_PARAMETER;
933 return gensec_start_mech(gensec_security);
936 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
938 const struct gensec_security_ops *ops;
939 ops = gensec_security_by_auth_type(gensec_security, authtype);
940 if (ops) {
941 return ops->name;
943 return NULL;
947 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
948 const char *oid_string)
950 const struct gensec_security_ops *ops;
951 ops = gensec_security_by_oid(gensec_security, oid_string);
952 if (ops) {
953 return ops->name;
955 return oid_string;
959 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
961 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
962 * well-known #define to hook it in.
965 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
966 const char *mech_oid)
968 SMB_ASSERT(gensec_security != NULL);
970 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
971 if (!gensec_security->ops) {
972 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
973 return NT_STATUS_INVALID_PARAMETER;
975 return gensec_start_mech(gensec_security);
979 * Start a GENSEC sub-mechanism by a well known SASL name
983 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
984 const char *sasl_name)
986 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
987 if (!gensec_security->ops) {
988 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
989 return NT_STATUS_INVALID_PARAMETER;
991 return gensec_start_mech(gensec_security);
995 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
999 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
1000 const char **sasl_names)
1002 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
1003 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
1004 const struct gensec_security_ops **ops;
1005 int i;
1006 if (!mem_ctx) {
1007 return NT_STATUS_NO_MEMORY;
1009 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
1010 if (!ops || !*ops) {
1011 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
1012 str_list_join(mem_ctx,
1013 sasl_names, ' ')));
1014 talloc_free(mem_ctx);
1015 return NT_STATUS_INVALID_PARAMETER;
1017 for (i=0; ops[i]; i++) {
1018 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
1019 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
1020 break;
1023 talloc_free(mem_ctx);
1024 return nt_status;
1028 * Start a GENSEC sub-mechanism by an internal name
1032 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
1033 const char *name)
1035 gensec_security->ops = gensec_security_by_name(gensec_security, name);
1036 if (!gensec_security->ops) {
1037 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
1038 return NT_STATUS_INVALID_PARAMETER;
1040 return gensec_start_mech(gensec_security);
1044 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1048 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1050 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1051 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1052 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1053 return NT_STATUS_OK;
1057 register a GENSEC backend.
1059 The 'name' can be later used by other backends to find the operations
1060 structure for this backend.
1062 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
1063 const struct gensec_security_ops *ops)
1065 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1066 /* its already registered! */
1067 DEBUG(0,("GENSEC backend '%s' already registered\n",
1068 ops->name));
1069 return NT_STATUS_OBJECT_NAME_COLLISION;
1072 generic_security_ops = talloc_realloc(ctx,
1073 generic_security_ops,
1074 const struct gensec_security_ops *,
1075 gensec_num_backends+2);
1076 if (!generic_security_ops) {
1077 return NT_STATUS_NO_MEMORY;
1080 generic_security_ops[gensec_num_backends] = ops;
1081 gensec_num_backends++;
1082 generic_security_ops[gensec_num_backends] = NULL;
1084 DEBUG(3,("GENSEC backend '%s' registered\n",
1085 ops->name));
1087 return NT_STATUS_OK;
1091 return the GENSEC interface version, and the size of some critical types
1092 This can be used by backends to either detect compilation errors, or provide
1093 multiple implementations for different smbd compilation options in one module
1095 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
1097 static const struct gensec_critical_sizes critical_sizes = {
1098 GENSEC_INTERFACE_VERSION,
1099 sizeof(struct gensec_security_ops),
1100 sizeof(struct gensec_security),
1103 return &critical_sizes;
1106 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
1107 return NUMERIC_CMP((*gs2)->priority, (*gs1)->priority);
1110 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1112 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1115 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1117 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1121 initialise the GENSEC subsystem
1123 _PUBLIC_ NTSTATUS gensec_init(void)
1125 static bool initialized = false;
1126 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1127 #ifdef STATIC_gensec_MODULES
1128 STATIC_gensec_MODULES_PROTO;
1129 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1130 #else
1131 init_module_fn *static_init = NULL;
1132 #endif
1133 init_module_fn *shared_init;
1135 if (initialized) return NT_STATUS_OK;
1136 initialized = true;
1138 shared_init = load_samba_modules(NULL, "gensec");
1140 run_init_functions(NULL, static_init);
1141 run_init_functions(NULL, shared_init);
1143 talloc_free(shared_init);
1145 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1147 return NT_STATUS_OK;