s3:winbind: Store canonical principal and realm in ccache entry
[Samba.git] / auth / gensec / gensec_start.c
blob906e3ee302cdaec6517fd96e393d90b22171aa38
1 /*
2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/network.h"
25 #include "tevent.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "librpc/gen_ndr/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "lib/param/param.h"
32 #include "lib/util/tsort.h"
33 #include "lib/util/samba_modules.h"
34 #include "lib/util/base64.h"
35 #include "lib/crypto/gnutls_helpers.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 (!samba_gnutls_weak_crypto_allowed() && ops->weak_crypto) {
55 ok = false;
58 return ok;
61 /* Sometimes we want to force only kerberos, sometimes we want to
62 * force it's avoidance. The old list could be either
63 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
64 * an existing list we have trimmed down)
66 * The intended logic is:
68 * if we are in the default AUTO have kerberos:
69 * - take a reference to the master list
70 * otherwise
71 * - always add spnego then:
72 * - if we 'MUST' have kerberos:
73 * only add kerberos mechs
74 * - if we 'DONT' want kerberos':
75 * only add non-kerberos mechs
77 * Once we get things like NegoEx or moonshot, this will of course get
78 * more compplex.
81 static const struct gensec_security_ops **gensec_use_kerberos_mechs(
82 TALLOC_CTX *mem_ctx,
83 const struct gensec_security_ops * const *old_gensec_list,
84 enum credentials_use_kerberos use_kerberos,
85 bool keep_schannel)
87 const struct gensec_security_ops **new_gensec_list;
88 int i, j, num_mechs_in;
90 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
91 /* noop */
94 new_gensec_list = talloc_array(mem_ctx,
95 const struct gensec_security_ops *,
96 num_mechs_in + 1);
97 if (!new_gensec_list) {
98 return NULL;
101 j = 0;
102 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
103 bool keep = false;
106 * We want to keep SPNGEO and other backends
108 keep = old_gensec_list[i]->glue;
110 if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
111 keep = keep_schannel;
114 switch (use_kerberos) {
115 case CRED_USE_KERBEROS_DESIRED:
116 keep = true;
117 break;
119 case CRED_USE_KERBEROS_DISABLED:
120 if (old_gensec_list[i]->kerberos == false) {
121 keep = true;
124 break;
126 case CRED_USE_KERBEROS_REQUIRED:
127 if (old_gensec_list[i]->kerberos == true) {
128 keep = true;
131 break;
132 default:
133 /* Can't happen or invalid parameter */
134 return NULL;
137 if (!keep) {
138 continue;
141 new_gensec_list[j] = old_gensec_list[i];
142 j++;
144 new_gensec_list[j] = NULL;
146 return new_gensec_list;
149 _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
150 struct gensec_security *gensec_security,
151 TALLOC_CTX *mem_ctx)
153 const struct gensec_security_ops * const *backends =
154 generic_security_ops;
155 enum credentials_use_kerberos use_kerberos = CRED_USE_KERBEROS_DESIRED;
156 bool keep_schannel = false;
158 if (gensec_security != NULL) {
159 struct cli_credentials *creds = NULL;
161 creds = gensec_get_credentials(gensec_security);
162 if (creds != NULL) {
163 use_kerberos = cli_credentials_get_kerberos_state(creds);
164 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
165 keep_schannel = true;
169 * Even if Kerberos is set to REQUIRED, keep the
170 * schannel auth mechanism that machine accounts are
171 * able to authenticate via netlogon.
173 if (gensec_security->gensec_role == GENSEC_SERVER) {
174 keep_schannel = true;
178 if (gensec_security->settings->backends) {
179 backends = gensec_security->settings->backends;
183 return gensec_use_kerberos_mechs(mem_ctx, backends,
184 use_kerberos, keep_schannel);
188 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
189 struct gensec_security *gensec_security,
190 const char *oid_string)
192 int i, j;
193 const struct gensec_security_ops **backends;
194 const struct gensec_security_ops *backend;
195 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
196 if (!mem_ctx) {
197 return NULL;
199 backends = gensec_security_mechs(gensec_security, mem_ctx);
200 for (i=0; backends && backends[i]; i++) {
201 if (gensec_security != NULL &&
202 !gensec_security_ops_enabled(backends[i],
203 gensec_security))
204 continue;
205 if (backends[i]->oid) {
206 for (j=0; backends[i]->oid[j]; j++) {
207 if (backends[i]->oid[j] &&
208 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
209 backend = backends[i];
210 talloc_free(mem_ctx);
211 return backend;
216 talloc_free(mem_ctx);
218 return NULL;
221 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
222 struct gensec_security *gensec_security,
223 const char *sasl_name)
225 int i;
226 const struct gensec_security_ops **backends;
227 const struct gensec_security_ops *backend;
228 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
229 if (!mem_ctx) {
230 return NULL;
232 backends = gensec_security_mechs(gensec_security, mem_ctx);
233 for (i=0; backends && backends[i]; i++) {
234 if (gensec_security != NULL &&
235 !gensec_security_ops_enabled(backends[i], gensec_security)) {
236 continue;
238 if (backends[i]->sasl_name
239 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
240 backend = backends[i];
241 talloc_free(mem_ctx);
242 return backend;
245 talloc_free(mem_ctx);
247 return NULL;
250 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
251 struct gensec_security *gensec_security,
252 uint32_t auth_type)
254 int i;
255 const struct gensec_security_ops **backends;
256 const struct gensec_security_ops *backend;
257 TALLOC_CTX *mem_ctx;
259 if (auth_type == DCERPC_AUTH_TYPE_NONE) {
260 return NULL;
263 mem_ctx = talloc_new(gensec_security);
264 if (!mem_ctx) {
265 return NULL;
267 backends = gensec_security_mechs(gensec_security, mem_ctx);
268 for (i=0; backends && backends[i]; i++) {
269 if (gensec_security != NULL &&
270 !gensec_security_ops_enabled(backends[i], gensec_security)) {
271 continue;
273 if (backends[i]->auth_type == auth_type) {
274 backend = backends[i];
275 talloc_free(mem_ctx);
276 return backend;
279 talloc_free(mem_ctx);
281 return NULL;
284 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
285 const char *name)
287 int i;
288 const struct gensec_security_ops **backends;
289 const struct gensec_security_ops *backend;
290 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
291 if (!mem_ctx) {
292 return NULL;
294 backends = gensec_security_mechs(gensec_security, mem_ctx);
295 for (i=0; backends && backends[i]; i++) {
296 if (gensec_security != NULL &&
297 !gensec_security_ops_enabled(backends[i], gensec_security))
298 continue;
299 if (backends[i]->name
300 && (strcmp(backends[i]->name, name) == 0)) {
301 backend = backends[i];
302 talloc_free(mem_ctx);
303 return backend;
306 talloc_free(mem_ctx);
307 return NULL;
310 static const char **gensec_security_sasl_names_from_ops(
311 struct gensec_security *gensec_security,
312 TALLOC_CTX *mem_ctx,
313 const struct gensec_security_ops * const *ops)
315 const char **sasl_names = NULL;
316 size_t i, sasl_names_count = 0;
318 if (ops == NULL) {
319 return NULL;
322 sasl_names = talloc_array(mem_ctx, const char *, 1);
323 if (sasl_names == NULL) {
324 return NULL;
327 for (i = 0; ops[i] != NULL; i++) {
328 enum gensec_role role = GENSEC_SERVER;
329 const char **tmp = NULL;
331 if (ops[i]->sasl_name == NULL) {
332 continue;
335 if (gensec_security != NULL) {
336 if (!gensec_security_ops_enabled(ops[i],
337 gensec_security)) {
338 continue;
341 role = gensec_security->gensec_role;
344 switch (role) {
345 case GENSEC_CLIENT:
346 if (ops[i]->client_start == NULL) {
347 continue;
349 break;
350 case GENSEC_SERVER:
351 if (ops[i]->server_start == NULL) {
352 continue;
354 break;
357 tmp = talloc_realloc(mem_ctx,
358 sasl_names,
359 const char *,
360 sasl_names_count + 2);
361 if (tmp == NULL) {
362 TALLOC_FREE(sasl_names);
363 return NULL;
365 sasl_names = tmp;
367 sasl_names[sasl_names_count] = ops[i]->sasl_name;
368 sasl_names_count++;
370 sasl_names[sasl_names_count] = NULL;
372 return sasl_names;
376 * @brief Get the sasl names from the gensec security context.
378 * @param[in] gensec_security The gensec security context.
380 * @param[in] mem_ctx The memory context to allocate memory on.
382 * @return An allocated array with sasl names, NULL on error.
384 _PUBLIC_
385 const char **gensec_security_sasl_names(struct gensec_security *gensec_security,
386 TALLOC_CTX *mem_ctx)
388 const struct gensec_security_ops **ops = NULL;
390 ops = gensec_security_mechs(gensec_security, mem_ctx);
392 return gensec_security_sasl_names_from_ops(gensec_security,
393 mem_ctx,
394 ops);
398 * Return a unique list of security subsystems from those specified in
399 * the list of SASL names.
401 * Use the list of enabled GENSEC mechanisms from the credentials
402 * attached to the gensec_security, and return in our preferred order.
405 static const struct gensec_security_ops **gensec_security_by_sasl_list(
406 struct gensec_security *gensec_security,
407 TALLOC_CTX *mem_ctx,
408 const char **sasl_names)
410 const struct gensec_security_ops **backends_out;
411 const struct gensec_security_ops **backends;
412 int i, k, sasl_idx;
413 int num_backends_out = 0;
415 if (!sasl_names) {
416 return NULL;
419 backends = gensec_security_mechs(gensec_security, mem_ctx);
421 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
422 if (!backends_out) {
423 return NULL;
425 backends_out[0] = NULL;
427 /* Find backends in our preferred order, by walking our list,
428 * then looking in the supplied list */
429 for (i=0; backends && backends[i]; i++) {
430 if (gensec_security != NULL &&
431 !gensec_security_ops_enabled(backends[i], gensec_security))
432 continue;
433 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
434 if (!backends[i]->sasl_name ||
435 !(strcmp(backends[i]->sasl_name,
436 sasl_names[sasl_idx]) == 0)) {
437 continue;
440 for (k=0; backends_out[k]; k++) {
441 if (backends_out[k] == backends[i]) {
442 break;
446 if (k < num_backends_out) {
447 /* already in there */
448 continue;
451 backends_out = talloc_realloc(mem_ctx, backends_out,
452 const struct gensec_security_ops *,
453 num_backends_out + 2);
454 if (!backends_out) {
455 return NULL;
458 backends_out[num_backends_out] = backends[i];
459 num_backends_out++;
460 backends_out[num_backends_out] = NULL;
463 return backends_out;
467 * Return a unique list of security subsystems from those specified in
468 * the OID list. That is, where two OIDs refer to the same module,
469 * return that module only once.
471 * Use the list of enabled GENSEC mechanisms from the credentials
472 * attached to the gensec_security, and return in our preferred order.
475 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
476 struct gensec_security *gensec_security,
477 TALLOC_CTX *mem_ctx,
478 const char * const *oid_strings,
479 const char *skip)
481 struct gensec_security_ops_wrapper *backends_out;
482 const struct gensec_security_ops **backends;
483 int i, j, k, oid_idx;
484 int num_backends_out = 0;
486 if (!oid_strings) {
487 return NULL;
490 backends = gensec_security_mechs(gensec_security, gensec_security);
492 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
493 if (!backends_out) {
494 return NULL;
496 backends_out[0].op = NULL;
497 backends_out[0].oid = NULL;
499 /* Find backends in our preferred order, by walking our list,
500 * then looking in the supplied list */
501 for (i=0; backends && backends[i]; i++) {
502 if (gensec_security != NULL &&
503 !gensec_security_ops_enabled(backends[i], gensec_security))
504 continue;
505 if (!backends[i]->oid) {
506 continue;
508 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
509 if (strcmp(oid_strings[oid_idx], skip) == 0) {
510 continue;
513 for (j=0; backends[i]->oid[j]; j++) {
514 if (!backends[i]->oid[j] ||
515 !(strcmp(backends[i]->oid[j],
516 oid_strings[oid_idx]) == 0)) {
517 continue;
520 for (k=0; backends_out[k].op; k++) {
521 if (backends_out[k].op == backends[i]) {
522 break;
526 if (k < num_backends_out) {
527 /* already in there */
528 continue;
531 backends_out = talloc_realloc(mem_ctx, backends_out,
532 struct gensec_security_ops_wrapper,
533 num_backends_out + 2);
534 if (!backends_out) {
535 return NULL;
538 backends_out[num_backends_out].op = backends[i];
539 backends_out[num_backends_out].oid = backends[i]->oid[j];
540 num_backends_out++;
541 backends_out[num_backends_out].op = NULL;
542 backends_out[num_backends_out].oid = NULL;
546 return backends_out;
550 * Return OIDS from the security subsystems listed
553 static const char **gensec_security_oids_from_ops(
554 struct gensec_security *gensec_security,
555 TALLOC_CTX *mem_ctx,
556 const struct gensec_security_ops * const *ops,
557 const char *skip)
559 int i;
560 int j = 0;
561 int k;
562 const char **oid_list;
563 if (!ops) {
564 return NULL;
566 oid_list = talloc_array(mem_ctx, const char *, 1);
567 if (!oid_list) {
568 return NULL;
571 for (i=0; ops && ops[i]; i++) {
572 if (gensec_security != NULL &&
573 !gensec_security_ops_enabled(ops[i], gensec_security)) {
574 continue;
576 if (!ops[i]->oid) {
577 continue;
580 for (k = 0; ops[i]->oid[k]; k++) {
581 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
582 } else {
583 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
584 if (!oid_list) {
585 return NULL;
587 oid_list[j] = ops[i]->oid[k];
588 j++;
592 oid_list[j] = NULL;
593 return oid_list;
598 * Return OIDS from the security subsystems listed
601 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
602 const struct gensec_security_ops_wrapper *wops)
604 int i;
605 int j = 0;
606 int k;
607 const char **oid_list;
608 if (!wops) {
609 return NULL;
611 oid_list = talloc_array(mem_ctx, const char *, 1);
612 if (!oid_list) {
613 return NULL;
616 for (i=0; wops[i].op; i++) {
617 if (!wops[i].op->oid) {
618 continue;
621 for (k = 0; wops[i].op->oid[k]; k++) {
622 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
623 if (!oid_list) {
624 return NULL;
626 oid_list[j] = wops[i].op->oid[k];
627 j++;
630 oid_list[j] = NULL;
631 return oid_list;
636 * Return all the security subsystems currently enabled on a GENSEC context.
638 * This is taken from a list attached to the cli_credentials, and
639 * skips the OID in 'skip'. (Typically the SPNEGO OID)
643 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
644 TALLOC_CTX *mem_ctx,
645 const char *skip)
647 const struct gensec_security_ops **ops;
649 ops = gensec_security_mechs(gensec_security, mem_ctx);
651 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
654 static int gensec_security_destructor(struct gensec_security *gctx)
656 if (gctx->parent_security != NULL) {
657 if (gctx->parent_security->child_security == gctx) {
658 gctx->parent_security->child_security = NULL;
660 gctx->parent_security = NULL;
663 if (gctx->child_security != NULL) {
664 if (gctx->child_security->parent_security == gctx) {
665 gctx->child_security->parent_security = NULL;
667 gctx->child_security = NULL;
670 return 0;
674 Start the GENSEC system, returning a context pointer.
675 @param mem_ctx The parent TALLOC memory context.
676 @param gensec_security Returned GENSEC context pointer.
677 @note The mem_ctx is only a parent and may be NULL.
678 @note, the auth context is moved to be a referenced pointer of the
679 @ gensec_security return
681 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
682 struct gensec_settings *settings,
683 struct auth4_context *auth_context,
684 struct gensec_security **gensec_security)
686 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
687 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
689 (*gensec_security)->max_update_size = 0;
691 SMB_ASSERT(settings->lp_ctx != NULL);
692 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
694 /* We need to reference this, not steal, as the caller may be
695 * python, which won't like it if we steal it's object away
696 * from it */
697 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
699 talloc_set_destructor((*gensec_security), gensec_security_destructor);
700 return NT_STATUS_OK;
704 * Start a GENSEC subcontext, with a copy of the properties of the parent
705 * @param mem_ctx The parent TALLOC memory context.
706 * @param parent The parent GENSEC context
707 * @param gensec_security Returned GENSEC context pointer.
708 * @note Used by SPNEGO in particular, for the actual implementation mechanism
711 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
712 struct gensec_security *parent,
713 struct gensec_security **gensec_security)
715 if (parent->child_security != NULL) {
716 return NT_STATUS_INTERNAL_ERROR;
719 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
720 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
722 (**gensec_security) = *parent;
723 (*gensec_security)->ops = NULL;
724 (*gensec_security)->private_data = NULL;
725 (*gensec_security)->update_busy_ptr = NULL;
727 (*gensec_security)->subcontext = true;
728 (*gensec_security)->want_features = parent->want_features;
729 (*gensec_security)->max_update_size = parent->max_update_size;
730 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
731 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
732 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
733 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
735 talloc_set_destructor((*gensec_security), gensec_security_destructor);
736 return NT_STATUS_OK;
739 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
740 struct gensec_security *child)
742 if (parent->child_security != NULL) {
743 return NT_STATUS_INTERNAL_ERROR;
746 if (child->parent_security != NULL) {
747 return NT_STATUS_INTERNAL_ERROR;
750 parent->child_security = child;
751 child->parent_security = parent;
752 return NT_STATUS_OK;
756 Start the GENSEC system, in client mode, returning a context pointer.
757 @param mem_ctx The parent TALLOC memory context.
758 @param gensec_security Returned GENSEC context pointer.
759 @note The mem_ctx is only a parent and may be NULL.
761 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
762 struct gensec_security **gensec_security,
763 struct gensec_settings *settings)
765 NTSTATUS status;
767 if (settings == NULL) {
768 DEBUG(0,("gensec_client_start: no settings given!\n"));
769 return NT_STATUS_INTERNAL_ERROR;
772 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
773 if (!NT_STATUS_IS_OK(status)) {
774 return status;
776 (*gensec_security)->gensec_role = GENSEC_CLIENT;
778 return status;
784 Start the GENSEC system, in server mode, returning a context pointer.
785 @param mem_ctx The parent TALLOC memory context.
786 @param gensec_security Returned GENSEC context pointer.
787 @note The mem_ctx is only a parent and may be NULL.
789 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
790 struct gensec_settings *settings,
791 struct auth4_context *auth_context,
792 struct gensec_security **gensec_security)
794 NTSTATUS status;
796 if (!settings) {
797 DEBUG(0,("gensec_server_start: no settings given!\n"));
798 return NT_STATUS_INTERNAL_ERROR;
801 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
802 if (!NT_STATUS_IS_OK(status)) {
803 return status;
805 (*gensec_security)->gensec_role = GENSEC_SERVER;
807 return status;
810 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
812 NTSTATUS status;
815 * Callers sometimes just reuse a context, we should
816 * clear the internal state before starting it again.
818 talloc_unlink(gensec_security, gensec_security->private_data);
819 gensec_security->private_data = NULL;
821 if (gensec_security->child_security != NULL) {
823 * The talloc_unlink(.., gensec_security->private_data)
824 * should have cleared this via
825 * gensec_security_destructor().
827 return NT_STATUS_INTERNAL_ERROR;
830 if (gensec_security->credentials) {
831 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
832 if (forced_mech &&
833 (gensec_security->ops->sasl_name == NULL ||
834 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
835 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
836 "did not match forced mechanism %s\n",
837 gensec_security->ops->name,
838 gensec_security->ops->sasl_name,
839 forced_mech));
840 return NT_STATUS_INVALID_PARAMETER;
843 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
844 gensec_security->subcontext ? "sub" : "",
845 gensec_security->ops->name));
846 switch (gensec_security->gensec_role) {
847 case GENSEC_CLIENT:
848 if (gensec_security->ops->client_start) {
849 status = gensec_security->ops->client_start(gensec_security);
850 if (!NT_STATUS_IS_OK(status)) {
851 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
852 gensec_security->ops->name, nt_errstr(status)));
854 return status;
856 break;
857 case GENSEC_SERVER:
858 if (gensec_security->ops->server_start) {
859 status = gensec_security->ops->server_start(gensec_security);
860 if (!NT_STATUS_IS_OK(status)) {
861 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
862 gensec_security->ops->name, nt_errstr(status)));
864 return status;
866 break;
868 return NT_STATUS_INVALID_PARAMETER;
872 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
876 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
877 const struct gensec_security_ops *ops)
879 gensec_security->ops = ops;
880 return gensec_start_mech(gensec_security);
885 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
886 * @param gensec_security GENSEC context pointer.
887 * @param auth_type DCERPC auth type
888 * @param auth_level DCERPC auth level
891 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
892 uint8_t auth_type, uint8_t auth_level)
894 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
895 if (!gensec_security->ops) {
896 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
897 return NT_STATUS_INVALID_PARAMETER;
899 gensec_security->dcerpc_auth_level = auth_level;
901 * We need to reset sign/seal in order to reset it.
902 * We may got some default features inherited by the credentials
904 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
905 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
906 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
907 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
908 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
909 if (gensec_security->gensec_role == GENSEC_CLIENT) {
910 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
912 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
914 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
915 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
917 if (gensec_security->gensec_role == GENSEC_CLIENT) {
918 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
920 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
921 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
922 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
923 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
924 /* Default features */
925 } else {
926 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
927 auth_level));
928 return NT_STATUS_INVALID_PARAMETER;
931 return gensec_start_mech(gensec_security);
934 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
936 const struct gensec_security_ops *ops;
937 ops = gensec_security_by_auth_type(gensec_security, authtype);
938 if (ops) {
939 return ops->name;
941 return NULL;
945 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
946 const char *oid_string)
948 const struct gensec_security_ops *ops;
949 ops = gensec_security_by_oid(gensec_security, oid_string);
950 if (ops) {
951 return ops->name;
953 return oid_string;
957 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
959 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
960 * well-known #define to hook it in.
963 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
964 const char *mech_oid)
966 SMB_ASSERT(gensec_security != NULL);
968 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
969 if (!gensec_security->ops) {
970 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
971 return NT_STATUS_INVALID_PARAMETER;
973 return gensec_start_mech(gensec_security);
977 * Start a GENSEC sub-mechanism by a well know SASL name
981 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
982 const char *sasl_name)
984 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
985 if (!gensec_security->ops) {
986 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
987 return NT_STATUS_INVALID_PARAMETER;
989 return gensec_start_mech(gensec_security);
993 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
997 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
998 const char **sasl_names)
1000 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
1001 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
1002 const struct gensec_security_ops **ops;
1003 int i;
1004 if (!mem_ctx) {
1005 return NT_STATUS_NO_MEMORY;
1007 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
1008 if (!ops || !*ops) {
1009 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
1010 str_list_join(mem_ctx,
1011 sasl_names, ' ')));
1012 talloc_free(mem_ctx);
1013 return NT_STATUS_INVALID_PARAMETER;
1015 for (i=0; ops[i]; i++) {
1016 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
1017 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
1018 break;
1021 talloc_free(mem_ctx);
1022 return nt_status;
1026 * Start a GENSEC sub-mechanism by an internal name
1030 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
1031 const char *name)
1033 gensec_security->ops = gensec_security_by_name(gensec_security, name);
1034 if (!gensec_security->ops) {
1035 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
1036 return NT_STATUS_INVALID_PARAMETER;
1038 return gensec_start_mech(gensec_security);
1042 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1046 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1048 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1049 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1050 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1051 return NT_STATUS_OK;
1055 register a GENSEC backend.
1057 The 'name' can be later used by other backends to find the operations
1058 structure for this backend.
1060 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
1061 const struct gensec_security_ops *ops)
1063 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1064 /* its already registered! */
1065 DEBUG(0,("GENSEC backend '%s' already registered\n",
1066 ops->name));
1067 return NT_STATUS_OBJECT_NAME_COLLISION;
1070 generic_security_ops = talloc_realloc(ctx,
1071 generic_security_ops,
1072 const struct gensec_security_ops *,
1073 gensec_num_backends+2);
1074 if (!generic_security_ops) {
1075 return NT_STATUS_NO_MEMORY;
1078 generic_security_ops[gensec_num_backends] = ops;
1079 gensec_num_backends++;
1080 generic_security_ops[gensec_num_backends] = NULL;
1082 DEBUG(3,("GENSEC backend '%s' registered\n",
1083 ops->name));
1085 return NT_STATUS_OK;
1089 return the GENSEC interface version, and the size of some critical types
1090 This can be used by backends to either detect compilation errors, or provide
1091 multiple implementations for different smbd compilation options in one module
1093 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
1095 static const struct gensec_critical_sizes critical_sizes = {
1096 GENSEC_INTERFACE_VERSION,
1097 sizeof(struct gensec_security_ops),
1098 sizeof(struct gensec_security),
1101 return &critical_sizes;
1104 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
1105 return (*gs2)->priority - (*gs1)->priority;
1108 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1110 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1113 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1115 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1119 initialise the GENSEC subsystem
1121 _PUBLIC_ NTSTATUS gensec_init(void)
1123 static bool initialized = false;
1124 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1125 #ifdef STATIC_gensec_MODULES
1126 STATIC_gensec_MODULES_PROTO;
1127 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1128 #else
1129 init_module_fn *static_init = NULL;
1130 #endif
1131 init_module_fn *shared_init;
1133 if (initialized) return NT_STATUS_OK;
1134 initialized = true;
1136 shared_init = load_samba_modules(NULL, "gensec");
1138 run_init_functions(NULL, static_init);
1139 run_init_functions(NULL, shared_init);
1141 talloc_free(shared_init);
1143 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1145 return NT_STATUS_OK;