s3: smbd: We can now remove the 'bool dfs_path' parameter from filename_convert().
[Samba.git] / auth / gensec / gensec_start.c
blobc1affd6218afed170cc038242fab87ced2d55be1
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 /* the list of currently registered GENSEC backends */
37 static const struct gensec_security_ops **generic_security_ops;
38 static int gensec_num_backends;
40 /* Return all the registered mechs. Don't modify the return pointer,
41 * but you may talloc_referen it if convient */
42 _PUBLIC_ const struct gensec_security_ops * const *gensec_security_all(void)
44 return generic_security_ops;
47 bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
49 return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
52 /* Sometimes we want to force only kerberos, sometimes we want to
53 * force it's avoidance. The old list could be either
54 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
55 * an existing list we have trimmed down)
57 * The intended logic is:
59 * if we are in the default AUTO have kerberos:
60 * - take a reference to the master list
61 * otherwise
62 * - always add spnego then:
63 * - if we 'MUST' have kerberos:
64 * only add kerberos mechs
65 * - if we 'DONT' want kerberos':
66 * only add non-kerberos mechs
68 * Once we get things like NegoEx or moonshot, this will of course get
69 * more compplex.
72 _PUBLIC_ const struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
73 const struct gensec_security_ops * const *old_gensec_list,
74 struct cli_credentials *creds)
76 const struct gensec_security_ops **new_gensec_list;
77 int i, j, num_mechs_in;
78 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
79 bool keep_schannel = false;
81 if (creds) {
82 use_kerberos = cli_credentials_get_kerberos_state(creds);
83 if (cli_credentials_get_netlogon_creds(creds) != NULL) {
84 keep_schannel = true;
88 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
89 /* noop */
92 new_gensec_list = talloc_array(mem_ctx,
93 const struct gensec_security_ops *,
94 num_mechs_in + 1);
95 if (!new_gensec_list) {
96 return NULL;
99 j = 0;
100 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
101 int oid_idx;
102 bool keep = false;
104 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
105 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
106 keep = true;
107 break;
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;
620 (*gensec_security)->subcontext = true;
621 (*gensec_security)->want_features = parent->want_features;
622 (*gensec_security)->max_update_size = parent->max_update_size;
623 (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
624 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
625 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
626 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
628 talloc_set_destructor((*gensec_security), gensec_security_destructor);
629 return NT_STATUS_OK;
632 _PUBLIC_ NTSTATUS gensec_child_ready(struct gensec_security *parent,
633 struct gensec_security *child)
635 if (parent->child_security != NULL) {
636 return NT_STATUS_INTERNAL_ERROR;
639 if (child->parent_security != NULL) {
640 return NT_STATUS_INTERNAL_ERROR;
643 parent->child_security = child;
644 child->parent_security = parent;
645 return NT_STATUS_OK;
649 Start the GENSEC system, in client mode, returning a context pointer.
650 @param mem_ctx The parent TALLOC memory context.
651 @param gensec_security Returned GENSEC context pointer.
652 @note The mem_ctx is only a parent and may be NULL.
654 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
655 struct gensec_security **gensec_security,
656 struct gensec_settings *settings)
658 NTSTATUS status;
660 if (settings == NULL) {
661 DEBUG(0,("gensec_client_start: no settings given!\n"));
662 return NT_STATUS_INTERNAL_ERROR;
665 status = gensec_start(mem_ctx, settings, NULL, gensec_security);
666 if (!NT_STATUS_IS_OK(status)) {
667 return status;
669 (*gensec_security)->gensec_role = GENSEC_CLIENT;
671 return status;
677 Start the GENSEC system, in server mode, returning a context pointer.
678 @param mem_ctx The parent TALLOC memory context.
679 @param gensec_security Returned GENSEC context pointer.
680 @note The mem_ctx is only a parent and may be NULL.
682 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
683 struct gensec_settings *settings,
684 struct auth4_context *auth_context,
685 struct gensec_security **gensec_security)
687 NTSTATUS status;
689 if (!settings) {
690 DEBUG(0,("gensec_server_start: no settings given!\n"));
691 return NT_STATUS_INTERNAL_ERROR;
694 status = gensec_start(mem_ctx, settings, auth_context, gensec_security);
695 if (!NT_STATUS_IS_OK(status)) {
696 return status;
698 (*gensec_security)->gensec_role = GENSEC_SERVER;
700 return status;
703 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
705 NTSTATUS status;
708 * Callers sometimes just reuse a context, we should
709 * clear the internal state before starting it again.
711 talloc_unlink(gensec_security, gensec_security->private_data);
712 gensec_security->private_data = NULL;
714 if (gensec_security->child_security != NULL) {
716 * The talloc_unlink(.., gensec_security->private_data)
717 * should have cleared this via
718 * gensec_security_destructor().
720 return NT_STATUS_INTERNAL_ERROR;
723 if (gensec_security->credentials) {
724 const char *forced_mech = cli_credentials_get_forced_sasl_mech(gensec_security->credentials);
725 if (forced_mech &&
726 (gensec_security->ops->sasl_name == NULL ||
727 strcasecmp(forced_mech, gensec_security->ops->sasl_name) != 0)) {
728 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
729 "did not match forced mechanism %s\n",
730 gensec_security->ops->name,
731 gensec_security->ops->sasl_name,
732 forced_mech));
733 return NT_STATUS_INVALID_PARAMETER;
736 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
737 gensec_security->subcontext ? "sub" : "",
738 gensec_security->ops->name));
739 switch (gensec_security->gensec_role) {
740 case GENSEC_CLIENT:
741 if (gensec_security->ops->client_start) {
742 status = gensec_security->ops->client_start(gensec_security);
743 if (!NT_STATUS_IS_OK(status)) {
744 DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n",
745 gensec_security->ops->name, nt_errstr(status)));
747 return status;
749 break;
750 case GENSEC_SERVER:
751 if (gensec_security->ops->server_start) {
752 status = gensec_security->ops->server_start(gensec_security);
753 if (!NT_STATUS_IS_OK(status)) {
754 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
755 gensec_security->ops->name, nt_errstr(status)));
757 return status;
759 break;
761 return NT_STATUS_INVALID_PARAMETER;
765 * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO
769 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
770 const struct gensec_security_ops *ops)
772 gensec_security->ops = ops;
773 return gensec_start_mech(gensec_security);
778 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
779 * @param gensec_security GENSEC context pointer.
780 * @param auth_type DCERPC auth type
781 * @param auth_level DCERPC auth level
784 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
785 uint8_t auth_type, uint8_t auth_level)
787 gensec_security->ops = gensec_security_by_auth_type(gensec_security, auth_type);
788 if (!gensec_security->ops) {
789 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
790 return NT_STATUS_INVALID_PARAMETER;
792 gensec_security->dcerpc_auth_level = auth_level;
794 * We need to reset sign/seal in order to reset it.
795 * We may got some default features inherited by the credentials
797 gensec_security->want_features &= ~GENSEC_FEATURE_SIGN;
798 gensec_security->want_features &= ~GENSEC_FEATURE_SEAL;
799 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
800 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
801 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
802 if (gensec_security->gensec_role == GENSEC_CLIENT) {
803 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
805 } else if (auth_level == DCERPC_AUTH_LEVEL_PACKET) {
807 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
808 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
810 if (gensec_security->gensec_role == GENSEC_CLIENT) {
811 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
813 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
814 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
815 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
816 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
817 /* Default features */
818 } else {
819 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
820 auth_level));
821 return NT_STATUS_INVALID_PARAMETER;
824 return gensec_start_mech(gensec_security);
827 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
829 const struct gensec_security_ops *ops;
830 ops = gensec_security_by_auth_type(gensec_security, authtype);
831 if (ops) {
832 return ops->name;
834 return NULL;
838 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
839 const char *oid_string)
841 const struct gensec_security_ops *ops;
842 ops = gensec_security_by_oid(gensec_security, oid_string);
843 if (ops) {
844 return ops->name;
846 return oid_string;
850 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
852 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
853 * well-known #define to hook it in.
856 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
857 const char *mech_oid)
859 SMB_ASSERT(gensec_security != NULL);
861 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
862 if (!gensec_security->ops) {
863 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
864 return NT_STATUS_INVALID_PARAMETER;
866 return gensec_start_mech(gensec_security);
870 * Start a GENSEC sub-mechanism by a well know SASL name
874 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
875 const char *sasl_name)
877 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
878 if (!gensec_security->ops) {
879 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
880 return NT_STATUS_INVALID_PARAMETER;
882 return gensec_start_mech(gensec_security);
886 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
890 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
891 const char **sasl_names)
893 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
894 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
895 const struct gensec_security_ops **ops;
896 int i;
897 if (!mem_ctx) {
898 return NT_STATUS_NO_MEMORY;
900 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
901 if (!ops || !*ops) {
902 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
903 str_list_join(mem_ctx,
904 sasl_names, ' ')));
905 talloc_free(mem_ctx);
906 return NT_STATUS_INVALID_PARAMETER;
908 for (i=0; ops[i]; i++) {
909 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
910 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
911 break;
914 talloc_free(mem_ctx);
915 return nt_status;
919 * Start a GENSEC sub-mechanism by an internal name
923 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
924 const char *name)
926 gensec_security->ops = gensec_security_by_name(gensec_security, name);
927 if (!gensec_security->ops) {
928 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
929 return NT_STATUS_INVALID_PARAMETER;
931 return gensec_start_mech(gensec_security);
935 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
939 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
941 gensec_security->credentials = talloc_reference(gensec_security, credentials);
942 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
943 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
944 return NT_STATUS_OK;
948 register a GENSEC backend.
950 The 'name' can be later used by other backends to find the operations
951 structure for this backend.
953 _PUBLIC_ NTSTATUS gensec_register(TALLOC_CTX *ctx,
954 const struct gensec_security_ops *ops)
956 if (gensec_security_by_name(NULL, ops->name) != NULL) {
957 /* its already registered! */
958 DEBUG(0,("GENSEC backend '%s' already registered\n",
959 ops->name));
960 return NT_STATUS_OBJECT_NAME_COLLISION;
963 generic_security_ops = talloc_realloc(ctx,
964 generic_security_ops,
965 const struct gensec_security_ops *,
966 gensec_num_backends+2);
967 if (!generic_security_ops) {
968 return NT_STATUS_NO_MEMORY;
971 generic_security_ops[gensec_num_backends] = ops;
972 gensec_num_backends++;
973 generic_security_ops[gensec_num_backends] = NULL;
975 DEBUG(3,("GENSEC backend '%s' registered\n",
976 ops->name));
978 return NT_STATUS_OK;
982 return the GENSEC interface version, and the size of some critical types
983 This can be used by backends to either detect compilation errors, or provide
984 multiple implementations for different smbd compilation options in one module
986 _PUBLIC_ const struct gensec_critical_sizes *gensec_interface_version(void)
988 static const struct gensec_critical_sizes critical_sizes = {
989 GENSEC_INTERFACE_VERSION,
990 sizeof(struct gensec_security_ops),
991 sizeof(struct gensec_security),
994 return &critical_sizes;
997 static int sort_gensec(const struct gensec_security_ops **gs1, const struct gensec_security_ops **gs2) {
998 return (*gs2)->priority - (*gs1)->priority;
1001 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1003 return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1006 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1008 return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1012 initialise the GENSEC subsystem
1014 _PUBLIC_ NTSTATUS gensec_init(void)
1016 static bool initialized = false;
1017 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1018 #ifdef STATIC_gensec_MODULES
1019 STATIC_gensec_MODULES_PROTO;
1020 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1021 #else
1022 init_module_fn *static_init = NULL;
1023 #endif
1024 init_module_fn *shared_init;
1026 if (initialized) return NT_STATUS_OK;
1027 initialized = true;
1029 shared_init = load_samba_modules(NULL, "gensec");
1031 run_init_functions(NULL, static_init);
1032 run_init_functions(NULL, shared_init);
1034 talloc_free(shared_init);
1036 TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec);
1038 return NT_STATUS_OK;