s3:libsmb: allow -U"\\administrator" to work
[Samba.git] / auth / gensec / gensec_start.c
blob50f4de731100851dbb1c7b1747846d42332a503d
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"
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_AUTH
39 /* the list of currently registered GENSEC backends */
40 static const struct gensec_security_ops **generic_security_ops;
41 static int gensec_num_backends;
43 /* Return all the registered mechs. Don't modify the return pointer,
44 * but you may talloc_referen it if convient */
45 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
47 return generic_security_ops;
50 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
52 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
55 /* Sometimes we want to force only kerberos, sometimes we want to
56 * force it's avoidance. The old list could be either
57 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
58 * an existing list we have trimmed down)
60 * The intended logic is:
62 * if we are in the default AUTO have kerberos:
63 * - take a reference to the master list
64 * otherwise
65 * - always add spnego then:
66 * - if we 'MUST' have kerberos:
67 * only add kerberos mechs
68 * - if we 'DONT' want kerberos':
69 * only add non-kerberos mechs
71 * Once we get things like NegoEx or moonshot, this will of course get
72 * more compplex.
75 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
76 const struct gensec_security_ops * const *old_gensec_list,
77 struct cli_credentials *creds)
79 const struct gensec_security_ops **new_gensec_list;
80 int i, j, num_mechs_in;
81 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
82 bool keep_schannel = false;
84 if (creds) {
85 use_kerberos = cli_credentials_get_kerberos_state(creds);
86 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
87 keep_schannel = true;
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 SPNGEO 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_AUTO_USE_KERBEROS:
117 keep = true;
118 break;
120 case CRED_DONT_USE_KERBEROS:
121 if (old_gensec_list[i]->kerberos == false) {
122 keep = true;
125 break;
127 case CRED_MUST_USE_KERBEROS:
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 struct cli_credentials *creds = NULL;
155 const struct gensec_security_ops * const *backends = gensec_security_all();
157 if (gensec_security != NULL) {
158 creds = gensec_get_credentials(gensec_security);
160 if (gensec_security->settings->backends) {
161 backends = gensec_security->settings->backends;
165 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
169 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
170 struct gensec_security *gensec_security,
171 const char *oid_string)
173 int i, j;
174 const struct gensec_security_ops **backends;
175 const struct gensec_security_ops *backend;
176 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
177 if (!mem_ctx) {
178 return NULL;
180 backends = gensec_security_mechs(gensec_security, mem_ctx);
181 for (i=0; backends && backends[i]; i++) {
182 if (gensec_security != NULL &&
183 !gensec_security_ops_enabled(backends[i],
184 gensec_security))
185 continue;
186 if (backends[i]->oid) {
187 for (j=0; backends[i]->oid[j]; j++) {
188 if (backends[i]->oid[j] &&
189 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
190 backend = backends[i];
191 talloc_free(mem_ctx);
192 return backend;
197 talloc_free(mem_ctx);
199 return NULL;
202 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
203 struct gensec_security *gensec_security,
204 const char *sasl_name)
206 int i;
207 const struct gensec_security_ops **backends;
208 const struct gensec_security_ops *backend;
209 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
210 if (!mem_ctx) {
211 return NULL;
213 backends = gensec_security_mechs(gensec_security, mem_ctx);
214 for (i=0; backends && backends[i]; i++) {
215 if (gensec_security != NULL &&
216 !gensec_security_ops_enabled(backends[i], gensec_security)) {
217 continue;
219 if (backends[i]->sasl_name
220 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
221 backend = backends[i];
222 talloc_free(mem_ctx);
223 return backend;
226 talloc_free(mem_ctx);
228 return NULL;
231 _PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
232 struct gensec_security *gensec_security,
233 uint32_t auth_type)
235 int i;
236 const struct gensec_security_ops **backends;
237 const struct gensec_security_ops *backend;
238 TALLOC_CTX *mem_ctx;
240 if (auth_type == DCERPC_AUTH_TYPE_NONE) {
241 return NULL;
244 mem_ctx = talloc_new(gensec_security);
245 if (!mem_ctx) {
246 return NULL;
248 backends = gensec_security_mechs(gensec_security, mem_ctx);
249 for (i=0; backends && backends[i]; i++) {
250 if (gensec_security != NULL &&
251 !gensec_security_ops_enabled(backends[i], gensec_security)) {
252 continue;
254 if (backends[i]->auth_type == auth_type) {
255 backend = backends[i];
256 talloc_free(mem_ctx);
257 return backend;
260 talloc_free(mem_ctx);
262 return NULL;
265 const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
266 const char *name)
268 int i;
269 const struct gensec_security_ops **backends;
270 const struct gensec_security_ops *backend;
271 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
272 if (!mem_ctx) {
273 return NULL;
275 backends = gensec_security_mechs(gensec_security, mem_ctx);
276 for (i=0; backends && backends[i]; i++) {
277 if (gensec_security != NULL &&
278 !gensec_security_ops_enabled(backends[i], gensec_security))
279 continue;
280 if (backends[i]->name
281 && (strcmp(backends[i]->name, name) == 0)) {
282 backend = backends[i];
283 talloc_free(mem_ctx);
284 return backend;
287 talloc_free(mem_ctx);
288 return NULL;
292 * Return a unique list of security subsystems from those specified in
293 * the list of SASL names.
295 * Use the list of enabled GENSEC mechanisms from the credentials
296 * attached to the gensec_security, and return in our preferred order.
299 static const struct gensec_security_ops **gensec_security_by_sasl_list(
300 struct gensec_security *gensec_security,
301 TALLOC_CTX *mem_ctx,
302 const char **sasl_names)
304 const struct gensec_security_ops **backends_out;
305 const struct gensec_security_ops **backends;
306 int i, k, sasl_idx;
307 int num_backends_out = 0;
309 if (!sasl_names) {
310 return NULL;
313 backends = gensec_security_mechs(gensec_security, mem_ctx);
315 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
316 if (!backends_out) {
317 return NULL;
319 backends_out[0] = NULL;
321 /* Find backends in our preferred order, by walking our list,
322 * then looking in the supplied list */
323 for (i=0; backends && backends[i]; i++) {
324 if (gensec_security != NULL &&
325 !gensec_security_ops_enabled(backends[i], gensec_security))
326 continue;
327 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
328 if (!backends[i]->sasl_name ||
329 !(strcmp(backends[i]->sasl_name,
330 sasl_names[sasl_idx]) == 0)) {
331 continue;
334 for (k=0; backends_out[k]; k++) {
335 if (backends_out[k] == backends[i]) {
336 break;
340 if (k < num_backends_out) {
341 /* already in there */
342 continue;
345 backends_out = talloc_realloc(mem_ctx, backends_out,
346 const struct gensec_security_ops *,
347 num_backends_out + 2);
348 if (!backends_out) {
349 return NULL;
352 backends_out[num_backends_out] = backends[i];
353 num_backends_out++;
354 backends_out[num_backends_out] = NULL;
357 return backends_out;
361 * Return a unique list of security subsystems from those specified in
362 * the OID list. That is, where two OIDs refer to the same module,
363 * return that module only once.
365 * Use the list of enabled GENSEC mechanisms from the credentials
366 * attached to the gensec_security, and return in our preferred order.
369 _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
370 struct gensec_security *gensec_security,
371 TALLOC_CTX *mem_ctx,
372 const char * const *oid_strings,
373 const char *skip)
375 struct gensec_security_ops_wrapper *backends_out;
376 const struct gensec_security_ops **backends;
377 int i, j, k, oid_idx;
378 int num_backends_out = 0;
380 if (!oid_strings) {
381 return NULL;
384 backends = gensec_security_mechs(gensec_security, gensec_security);
386 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
387 if (!backends_out) {
388 return NULL;
390 backends_out[0].op = NULL;
391 backends_out[0].oid = NULL;
393 /* Find backends in our preferred order, by walking our list,
394 * then looking in the supplied list */
395 for (i=0; backends && backends[i]; i++) {
396 if (gensec_security != NULL &&
397 !gensec_security_ops_enabled(backends[i], gensec_security))
398 continue;
399 if (!backends[i]->oid) {
400 continue;
402 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
403 if (strcmp(oid_strings[oid_idx], skip) == 0) {
404 continue;
407 for (j=0; backends[i]->oid[j]; j++) {
408 if (!backends[i]->oid[j] ||
409 !(strcmp(backends[i]->oid[j],
410 oid_strings[oid_idx]) == 0)) {
411 continue;
414 for (k=0; backends_out[k].op; k++) {
415 if (backends_out[k].op == backends[i]) {
416 break;
420 if (k < num_backends_out) {
421 /* already in there */
422 continue;
425 backends_out = talloc_realloc(mem_ctx, backends_out,
426 struct gensec_security_ops_wrapper,
427 num_backends_out + 2);
428 if (!backends_out) {
429 return NULL;
432 backends_out[num_backends_out].op = backends[i];
433 backends_out[num_backends_out].oid = backends[i]->oid[j];
434 num_backends_out++;
435 backends_out[num_backends_out].op = NULL;
436 backends_out[num_backends_out].oid = NULL;
440 return backends_out;
444 * Return OIDS from the security subsystems listed
447 static const char **gensec_security_oids_from_ops(
448 struct gensec_security *gensec_security,
449 TALLOC_CTX *mem_ctx,
450 const struct gensec_security_ops * const *ops,
451 const char *skip)
453 int i;
454 int j = 0;
455 int k;
456 const char **oid_list;
457 if (!ops) {
458 return NULL;
460 oid_list = talloc_array(mem_ctx, const char *, 1);
461 if (!oid_list) {
462 return NULL;
465 for (i=0; ops && ops[i]; i++) {
466 if (gensec_security != NULL &&
467 !gensec_security_ops_enabled(ops[i], gensec_security)) {
468 continue;
470 if (!ops[i]->oid) {
471 continue;
474 for (k = 0; ops[i]->oid[k]; k++) {
475 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
476 } else {
477 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
478 if (!oid_list) {
479 return NULL;
481 oid_list[j] = ops[i]->oid[k];
482 j++;
486 oid_list[j] = NULL;
487 return oid_list;
492 * Return OIDS from the security subsystems listed
495 _PUBLIC_ const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
496 const struct gensec_security_ops_wrapper *wops)
498 int i;
499 int j = 0;
500 int k;
501 const char **oid_list;
502 if (!wops) {
503 return NULL;
505 oid_list = talloc_array(mem_ctx, const char *, 1);
506 if (!oid_list) {
507 return NULL;
510 for (i=0; wops[i].op; i++) {
511 if (!wops[i].op->oid) {
512 continue;
515 for (k = 0; wops[i].op->oid[k]; k++) {
516 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
517 if (!oid_list) {
518 return NULL;
520 oid_list[j] = wops[i].op->oid[k];
521 j++;
524 oid_list[j] = NULL;
525 return oid_list;
530 * Return all the security subsystems currently enabled on a GENSEC context.
532 * This is taken from a list attached to the cli_credentials, and
533 * skips the OID in 'skip'. (Typically the SPNEGO OID)
537 _PUBLIC_ const char **gensec_security_oids(struct gensec_security *gensec_security,
538 TALLOC_CTX *mem_ctx,
539 const char *skip)
541 const struct gensec_security_ops **ops;
543 ops = gensec_security_mechs(gensec_security, mem_ctx);
545 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
548 static int gensec_security_destructor(struct gensec_security *gctx)
550 if (gctx->parent_security != NULL) {
551 if (gctx->parent_security->child_security == gctx) {
552 gctx->parent_security->child_security = NULL;
554 gctx->parent_security = NULL;
557 if (gctx->child_security != NULL) {
558 if (gctx->child_security->parent_security == gctx) {
559 gctx->child_security->parent_security = NULL;
561 gctx->child_security = NULL;
564 return 0;
568 Start the GENSEC system, returning a context pointer.
569 @param mem_ctx The parent TALLOC memory context.
570 @param gensec_security Returned GENSEC context pointer.
571 @note The mem_ctx is only a parent and may be NULL.
572 @note, the auth context is moved to be a referenced pointer of the
573 @ gensec_security return
575 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
576 struct gensec_settings *settings,
577 struct auth4_context *auth_context,
578 struct gensec_security **gensec_security)
580 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
581 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
583 (*gensec_security)->max_update_size = 0;
585 SMB_ASSERT(settings->lp_ctx != NULL);
586 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
588 /* We need to reference this, not steal, as the caller may be
589 * python, which won't like it if we steal it's object away
590 * from it */
591 (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context);
593 talloc_set_destructor((*gensec_security), gensec_security_destructor);
594 return NT_STATUS_OK;
598 * Start a GENSEC subcontext, with a copy of the properties of the parent
599 * @param mem_ctx The parent TALLOC memory context.
600 * @param parent The parent GENSEC context
601 * @param gensec_security Returned GENSEC context pointer.
602 * @note Used by SPNEGO in particular, for the actual implementation mechanism
605 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
606 struct gensec_security *parent,
607 struct gensec_security **gensec_security)
609 if (parent->child_security != NULL) {
610 return NT_STATUS_INTERNAL_ERROR;
613 (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
614 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
616 (**gensec_security) = *parent;
617 (*gensec_security)->ops = NULL;
618 (*gensec_security)->private_data = NULL;
619 (*gensec_security)->update_busy_ptr = NULL;
621 (*gensec_security)->subcontext = true;
622 (*gensec_security)->want_features = parent->want_features;
623 (*gensec_security)->max_update_size = parent->max_update_size;
624 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
625 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
626 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
627 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
629 talloc_set_destructor((*gensec_security), gensec_security_destructor);
630 return NT_STATUS_OK;
633 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
634 struct gensec_security *child)
636 if (parent->child_security != NULL) {
637 return NT_STATUS_INTERNAL_ERROR;
640 if (child->parent_security != NULL) {
641 return NT_STATUS_INTERNAL_ERROR;
644 parent->child_security = child;
645 child->parent_security = parent;
646 return NT_STATUS_OK;
650 Start the GENSEC system, in client mode, returning a context pointer.
651 @param mem_ctx The parent TALLOC memory context.
652 @param gensec_security Returned GENSEC context pointer.
653 @note The mem_ctx is only a parent and may be NULL.
655 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
656 struct gensec_security **gensec_security,
657 struct gensec_settings *settings)
659 NTSTATUS status;
661 if (settings == NULL) {
662 DEBUG(0,("gensec_client_start: no settings given!\n"));
663 return NT_STATUS_INTERNAL_ERROR;
666 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
667 if (!NT_STATUS_IS_OK(status)) {
668 return status;
670 (*gensec_security)->gensec_role = GENSEC_CLIENT;
672 return status;
678 Start the GENSEC system, in server mode, returning a context pointer.
679 @param mem_ctx The parent TALLOC memory context.
680 @param gensec_security Returned GENSEC context pointer.
681 @note The mem_ctx is only a parent and may be NULL.
683 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
684 struct gensec_settings *settings,
685 struct auth4_context *auth_context,
686 struct gensec_security **gensec_security)
688 NTSTATUS status;
690 if (!settings) {
691 DEBUG(0,("gensec_server_start: no settings given!\n"));
692 return NT_STATUS_INTERNAL_ERROR;
695 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
696 if (!NT_STATUS_IS_OK(status)) {
697 return status;
699 (*gensec_security)->gensec_role = GENSEC_SERVER;
701 return status;
704 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
706 NTSTATUS status;
709 * Callers sometimes just reuse a context, we should
710 * clear the internal state before starting it again.
712 talloc_unlink(gensec_security, gensec_security->private_data);
713 gensec_security->private_data = NULL;
715 if (gensec_security->child_security != NULL) {
717 * The talloc_unlink(.., gensec_security->private_data)
718 * should have cleared this via
719 * gensec_security_destructor().
721 return NT_STATUS_INTERNAL_ERROR;
724 if (gensec_security->credentials) {
725 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
726 if (forced_mech &&
727 (gensec_security->ops->sasl_name == NULL ||
728 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
729 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
730 "did not match forced mechanism %s\n",
731 gensec_security->ops->name,
732 gensec_security->ops->sasl_name,
733 forced_mech));
734 return NT_STATUS_INVALID_PARAMETER;
737 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
738 gensec_security->subcontext ? "sub" : "",
739 gensec_security->ops->name));
740 switch (gensec_security->gensec_role) {
741 case GENSEC_CLIENT:
742 if (gensec_security->ops->client_start) {
743 status = gensec_security->ops->client_start(gensec_security);
744 if (!NT_STATUS_IS_OK(status)) {
745 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
746 gensec_security->ops->name, nt_errstr(status)));
748 return status;
750 break;
751 case GENSEC_SERVER:
752 if (gensec_security->ops->server_start) {
753 status = gensec_security->ops->server_start(gensec_security);
754 if (!NT_STATUS_IS_OK(status)) {
755 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
756 gensec_security->ops->name, nt_errstr(status)));
758 return status;
760 break;
762 return NT_STATUS_INVALID_PARAMETER;
766 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
770 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
771 const struct gensec_security_ops *ops)
773 gensec_security->ops = ops;
774 return gensec_start_mech(gensec_security);
779 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
780 * @param gensec_security GENSEC context pointer.
781 * @param auth_type DCERPC auth type
782 * @param auth_level DCERPC auth level
785 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
786 uint8_t auth_type, uint8_t auth_level)
788 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
789 if (!gensec_security->ops) {
790 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
791 return NT_STATUS_INVALID_PARAMETER;
793 gensec_security->dcerpc_auth_level = auth_level;
795 * We need to reset sign/seal in order to reset it.
796 * We may got some default features inherited by the credentials
798 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
799 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
800 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
801 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
802 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
803 if (gensec_security->gensec_role == GENSEC_CLIENT) {
804 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
806 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
808 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
809 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
811 if (gensec_security->gensec_role == GENSEC_CLIENT) {
812 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
814 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
815 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
816 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
817 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
818 /* Default features */
819 } else {
820 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
821 auth_level));
822 return NT_STATUS_INVALID_PARAMETER;
825 return gensec_start_mech(gensec_security);
828 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
830 const struct gensec_security_ops *ops;
831 ops = gensec_security_by_auth_type(gensec_security, authtype);
832 if (ops) {
833 return ops->name;
835 return NULL;
839 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
840 const char *oid_string)
842 const struct gensec_security_ops *ops;
843 ops = gensec_security_by_oid(gensec_security, oid_string);
844 if (ops) {
845 return ops->name;
847 return oid_string;
851 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
853 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
854 * well-known #define to hook it in.
857 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
858 const char *mech_oid)
860 SMB_ASSERT(gensec_security != NULL);
862 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
863 if (!gensec_security->ops) {
864 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
865 return NT_STATUS_INVALID_PARAMETER;
867 return gensec_start_mech(gensec_security);
871 * Start a GENSEC sub-mechanism by a well know SASL name
875 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
876 const char *sasl_name)
878 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
879 if (!gensec_security->ops) {
880 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
881 return NT_STATUS_INVALID_PARAMETER;
883 return gensec_start_mech(gensec_security);
887 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
891 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
892 const char **sasl_names)
894 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
895 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
896 const struct gensec_security_ops **ops;
897 int i;
898 if (!mem_ctx) {
899 return NT_STATUS_NO_MEMORY;
901 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
902 if (!ops || !*ops) {
903 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
904 str_list_join(mem_ctx,
905 sasl_names, ' ')));
906 talloc_free(mem_ctx);
907 return NT_STATUS_INVALID_PARAMETER;
909 for (i=0; ops[i]; i++) {
910 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
911 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
912 break;
915 talloc_free(mem_ctx);
916 return nt_status;
920 * Start a GENSEC sub-mechanism by an internal name
924 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
925 const char *name)
927 gensec_security->ops = gensec_security_by_name(gensec_security, name);
928 if (!gensec_security->ops) {
929 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
930 return NT_STATUS_INVALID_PARAMETER;
932 return gensec_start_mech(gensec_security);
936 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
940 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
942 gensec_security->credentials = talloc_reference(gensec_security, credentials);
943 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
944 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
945 return NT_STATUS_OK;
949 register a GENSEC backend.
951 The 'name' can be later used by other backends to find the operations
952 structure for this backend.
954 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
955 const struct gensec_security_ops *ops)
957 if (gensec_security_by_name(NULL, ops->name) != NULL) {
958 /* its already registered! */
959 DEBUG(0,("GENSEC backend '%s' already registered\n",
960 ops->name));
961 return NT_STATUS_OBJECT_NAME_COLLISION;
964 generic_security_ops = talloc_realloc(ctx,
965 generic_security_ops,
966 const struct gensec_security_ops *,
967 gensec_num_backends+2);
968 if (!generic_security_ops) {
969 return NT_STATUS_NO_MEMORY;
972 generic_security_ops[gensec_num_backends] = ops;
973 gensec_num_backends++;
974 generic_security_ops[gensec_num_backends] = NULL;
976 DEBUG(3,("GENSEC backend '%s' registered\n",
977 ops->name));
979 return NT_STATUS_OK;
983 return the GENSEC interface version, and the size of some critical types
984 This can be used by backends to either detect compilation errors, or provide
985 multiple implementations for different smbd compilation options in one module
987 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
989 static const struct gensec_critical_sizes critical_sizes = {
990 GENSEC_INTERFACE_VERSION,
991 sizeof(struct gensec_security_ops),
992 sizeof(struct gensec_security),
995 return &critical_sizes;
998 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
999 return (*gs2)->priority - (*gs1)->priority;
1002 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1004 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1007 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1009 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1013 initialise the GENSEC subsystem
1015 _PUBLIC_ NTSTATUS gensec_init(void)
1017 static bool initialized = false;
1018 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1019 #ifdef STATIC_gensec_MODULES
1020 STATIC_gensec_MODULES_PROTO;
1021 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1022 #else
1023 init_module_fn *static_init = NULL;
1024 #endif
1025 init_module_fn *shared_init;
1027 if (initialized) return NT_STATUS_OK;
1028 initialized = true;
1030 shared_init = load_samba_modules(NULL, "gensec");
1032 run_init_functions(NULL, static_init);
1033 run_init_functions(NULL, shared_init);
1035 talloc_free(shared_init);
1037 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1039 return NT_STATUS_OK;