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/>.
24 #include "system/network.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"
38 #define DBGC_CLASS DBGC_AUTH
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
,
54 if (ops
->weak_crypto
&&
55 lpcfg_weak_crypto(security
->settings
->lp_ctx
) != SAMBA_WEAK_CRYPTO_ALLOWED
) {
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
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
82 static const struct gensec_security_ops
**gensec_use_kerberos_mechs(
84 const struct gensec_security_ops
* const *old_gensec_list
,
85 enum credentials_use_kerberos use_kerberos
,
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
++) {
95 new_gensec_list
= talloc_array(mem_ctx
,
96 const struct gensec_security_ops
*,
98 if (!new_gensec_list
) {
103 for (i
=0; old_gensec_list
&& old_gensec_list
[i
]; i
++) {
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
:
120 case CRED_USE_KERBEROS_DISABLED
:
121 if (old_gensec_list
[i
]->kerberos
== false) {
127 case CRED_USE_KERBEROS_REQUIRED
:
128 if (old_gensec_list
[i
]->kerberos
== true) {
134 /* Can't happen or invalid parameter */
142 new_gensec_list
[j
] = old_gensec_list
[i
];
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
,
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
);
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
)
194 const struct gensec_security_ops
**backends
;
195 const struct gensec_security_ops
*backend
;
196 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
],
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
);
217 talloc_free(mem_ctx
);
222 _PUBLIC_
const struct gensec_security_ops
*gensec_security_by_sasl_name(
223 struct gensec_security
*gensec_security
,
224 const char *sasl_name
)
227 const struct gensec_security_ops
**backends
;
228 const struct gensec_security_ops
*backend
;
229 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
)) {
239 if (backends
[i
]->sasl_name
240 && (strcmp(backends
[i
]->sasl_name
, sasl_name
) == 0)) {
241 backend
= backends
[i
];
242 talloc_free(mem_ctx
);
246 talloc_free(mem_ctx
);
251 _PUBLIC_
const struct gensec_security_ops
*gensec_security_by_auth_type(
252 struct gensec_security
*gensec_security
,
256 const struct gensec_security_ops
**backends
;
257 const struct gensec_security_ops
*backend
;
260 if (auth_type
== DCERPC_AUTH_TYPE_NONE
) {
264 mem_ctx
= talloc_new(gensec_security
);
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
)) {
274 if (backends
[i
]->auth_type
== auth_type
) {
275 backend
= backends
[i
];
276 talloc_free(mem_ctx
);
280 talloc_free(mem_ctx
);
285 const struct gensec_security_ops
*gensec_security_by_name(struct gensec_security
*gensec_security
,
289 const struct gensec_security_ops
**backends
;
290 const struct gensec_security_ops
*backend
;
291 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
))
300 if (backends
[i
]->name
301 && (strcmp(backends
[i
]->name
, name
) == 0)) {
302 backend
= backends
[i
];
303 talloc_free(mem_ctx
);
307 talloc_free(mem_ctx
);
311 static const char **gensec_security_sasl_names_from_ops(
312 struct gensec_security
*gensec_security
,
314 const struct gensec_security_ops
* const *ops
)
316 const char **sasl_names
= NULL
;
317 size_t i
, sasl_names_count
= 0;
323 sasl_names
= talloc_array(mem_ctx
, const char *, 1);
324 if (sasl_names
== 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
) {
336 if (gensec_security
!= NULL
) {
337 if (!gensec_security_ops_enabled(ops
[i
],
342 role
= gensec_security
->gensec_role
;
347 if (ops
[i
]->client_start
== NULL
) {
352 if (ops
[i
]->server_start
== NULL
) {
358 tmp
= talloc_realloc(mem_ctx
,
361 sasl_names_count
+ 2);
363 TALLOC_FREE(sasl_names
);
368 sasl_names
[sasl_names_count
] = ops
[i
]->sasl_name
;
371 sasl_names
[sasl_names_count
] = NULL
;
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.
386 const char **gensec_security_sasl_names(struct gensec_security
*gensec_security
,
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
,
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
,
409 const char **sasl_names
)
411 const struct gensec_security_ops
**backends_out
;
412 const struct gensec_security_ops
**backends
;
414 int num_backends_out
= 0;
420 backends
= gensec_security_mechs(gensec_security
, mem_ctx
);
422 backends_out
= talloc_array(mem_ctx
, const struct gensec_security_ops
*, 1);
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
))
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)) {
441 for (k
=0; backends_out
[k
]; k
++) {
442 if (backends_out
[k
] == backends
[i
]) {
447 if (k
< num_backends_out
) {
448 /* already in there */
452 backends_out
= talloc_realloc(mem_ctx
, backends_out
,
453 const struct gensec_security_ops
*,
454 num_backends_out
+ 2);
459 backends_out
[num_backends_out
] = backends
[i
];
461 backends_out
[num_backends_out
] = NULL
;
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
,
479 const char * const *oid_strings
,
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;
491 backends
= gensec_security_mechs(gensec_security
, gensec_security
);
493 backends_out
= talloc_array(mem_ctx
, struct gensec_security_ops_wrapper
, 1);
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
))
506 if (!backends
[i
]->oid
) {
509 for (oid_idx
= 0; oid_strings
[oid_idx
]; oid_idx
++) {
510 if (strcmp(oid_strings
[oid_idx
], skip
) == 0) {
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)) {
521 for (k
=0; backends_out
[k
].op
; k
++) {
522 if (backends_out
[k
].op
== backends
[i
]) {
527 if (k
< num_backends_out
) {
528 /* already in there */
532 backends_out
= talloc_realloc(mem_ctx
, backends_out
,
533 struct gensec_security_ops_wrapper
,
534 num_backends_out
+ 2);
539 backends_out
[num_backends_out
].op
= backends
[i
];
540 backends_out
[num_backends_out
].oid
= backends
[i
]->oid
[j
];
542 backends_out
[num_backends_out
].op
= NULL
;
543 backends_out
[num_backends_out
].oid
= NULL
;
551 * Return OIDS from the security subsystems listed
554 static const char **gensec_security_oids_from_ops(
555 struct gensec_security
*gensec_security
,
557 const struct gensec_security_ops
* const *ops
,
563 const char **oid_list
;
567 oid_list
= talloc_array(mem_ctx
, const char *, 1);
572 for (i
=0; ops
&& ops
[i
]; i
++) {
573 if (gensec_security
!= NULL
&&
574 !gensec_security_ops_enabled(ops
[i
], gensec_security
)) {
581 for (k
= 0; ops
[i
]->oid
[k
]; k
++) {
582 if (skip
&& strcmp(skip
, ops
[i
]->oid
[k
])==0) {
584 oid_list
= talloc_realloc(mem_ctx
, oid_list
, const char *, j
+ 2);
588 oid_list
[j
] = ops
[i
]->oid
[k
];
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
)
608 const char **oid_list
;
612 oid_list
= talloc_array(mem_ctx
, const char *, 1);
617 for (i
=0; wops
[i
].op
; i
++) {
618 if (!wops
[i
].op
->oid
) {
622 for (k
= 0; wops
[i
].op
->oid
[k
]; k
++) {
623 oid_list
= talloc_realloc(mem_ctx
, oid_list
, const char *, j
+ 2);
627 oid_list
[j
] = wops
[i
].op
->oid
[k
];
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
,
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
;
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
698 (*gensec_security
)->auth_context
= talloc_reference(*gensec_security
, auth_context
);
700 talloc_set_destructor((*gensec_security
), gensec_security_destructor
);
705 * Start a GENSEC subcontext, with a copy of the properties of the parent
706 * @param mem_ctx The parent TALLOC memory context.
707 * @param parent The parent GENSEC context
708 * @param gensec_security Returned GENSEC context pointer.
709 * @note Used by SPNEGO in particular, for the actual implementation mechanism
712 _PUBLIC_ NTSTATUS
gensec_subcontext_start(TALLOC_CTX
*mem_ctx
,
713 struct gensec_security
*parent
,
714 struct gensec_security
**gensec_security
)
716 if (parent
->child_security
!= NULL
) {
717 return NT_STATUS_INTERNAL_ERROR
;
720 (*gensec_security
) = talloc_zero(mem_ctx
, struct gensec_security
);
721 NT_STATUS_HAVE_NO_MEMORY(*gensec_security
);
723 (**gensec_security
) = *parent
;
724 (*gensec_security
)->ops
= NULL
;
725 (*gensec_security
)->private_data
= NULL
;
726 (*gensec_security
)->update_busy_ptr
= NULL
;
728 (*gensec_security
)->subcontext
= true;
729 (*gensec_security
)->want_features
= parent
->want_features
;
730 (*gensec_security
)->max_update_size
= parent
->max_update_size
;
731 (*gensec_security
)->dcerpc_auth_level
= parent
->dcerpc_auth_level
;
732 (*gensec_security
)->auth_context
= talloc_reference(*gensec_security
, parent
->auth_context
);
733 (*gensec_security
)->settings
= talloc_reference(*gensec_security
, parent
->settings
);
734 (*gensec_security
)->auth_context
= talloc_reference(*gensec_security
, parent
->auth_context
);
736 talloc_set_destructor((*gensec_security
), gensec_security_destructor
);
740 _PUBLIC_ NTSTATUS
gensec_child_ready(struct gensec_security
*parent
,
741 struct gensec_security
*child
)
743 if (parent
->child_security
!= NULL
) {
744 return NT_STATUS_INTERNAL_ERROR
;
747 if (child
->parent_security
!= NULL
) {
748 return NT_STATUS_INTERNAL_ERROR
;
751 parent
->child_security
= child
;
752 child
->parent_security
= parent
;
757 Start the GENSEC system, in client mode, returning a context pointer.
758 @param mem_ctx The parent TALLOC memory context.
759 @param gensec_security Returned GENSEC context pointer.
760 @note The mem_ctx is only a parent and may be NULL.
762 _PUBLIC_ NTSTATUS
gensec_client_start(TALLOC_CTX
*mem_ctx
,
763 struct gensec_security
**gensec_security
,
764 struct gensec_settings
*settings
)
768 if (settings
== NULL
) {
769 DEBUG(0,("gensec_client_start: no settings given!\n"));
770 return NT_STATUS_INTERNAL_ERROR
;
773 status
= gensec_start(mem_ctx
, settings
, NULL
, gensec_security
);
774 if (!NT_STATUS_IS_OK(status
)) {
777 (*gensec_security
)->gensec_role
= GENSEC_CLIENT
;
785 Start the GENSEC system, in server mode, returning a context pointer.
786 @param mem_ctx The parent TALLOC memory context.
787 @param gensec_security Returned GENSEC context pointer.
788 @note The mem_ctx is only a parent and may be NULL.
790 _PUBLIC_ NTSTATUS
gensec_server_start(TALLOC_CTX
*mem_ctx
,
791 struct gensec_settings
*settings
,
792 struct auth4_context
*auth_context
,
793 struct gensec_security
**gensec_security
)
798 DEBUG(0,("gensec_server_start: no settings given!\n"));
799 return NT_STATUS_INTERNAL_ERROR
;
802 status
= gensec_start(mem_ctx
, settings
, auth_context
, gensec_security
);
803 if (!NT_STATUS_IS_OK(status
)) {
806 (*gensec_security
)->gensec_role
= GENSEC_SERVER
;
811 static NTSTATUS
gensec_start_mech(struct gensec_security
*gensec_security
)
816 * Callers sometimes just reuse a context, we should
817 * clear the internal state before starting it again.
819 talloc_unlink(gensec_security
, gensec_security
->private_data
);
820 gensec_security
->private_data
= NULL
;
822 if (gensec_security
->child_security
!= NULL
) {
824 * The talloc_unlink(.., gensec_security->private_data)
825 * should have cleared this via
826 * gensec_security_destructor().
828 return NT_STATUS_INTERNAL_ERROR
;
831 if (gensec_security
->credentials
) {
832 const char *forced_mech
= cli_credentials_get_forced_sasl_mech(gensec_security
->credentials
);
834 (gensec_security
->ops
->sasl_name
== NULL
||
835 strcasecmp(forced_mech
, gensec_security
->ops
->sasl_name
) != 0)) {
836 DEBUG(5, ("GENSEC mechanism %s (%s) skipped, as it "
837 "did not match forced mechanism %s\n",
838 gensec_security
->ops
->name
,
839 gensec_security
->ops
->sasl_name
,
841 return NT_STATUS_INVALID_PARAMETER
;
844 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
845 gensec_security
->subcontext
? "sub" : "",
846 gensec_security
->ops
->name
));
847 switch (gensec_security
->gensec_role
) {
849 if (gensec_security
->ops
->client_start
) {
850 status
= gensec_security
->ops
->client_start(gensec_security
);
851 if (!NT_STATUS_IS_OK(status
)) {
852 DEBUG(gensec_security
->subcontext
?4:2, ("Failed to start GENSEC client mech %s: %s\n",
853 gensec_security
->ops
->name
, nt_errstr(status
)));
859 if (gensec_security
->ops
->server_start
) {
860 status
= gensec_security
->ops
->server_start(gensec_security
);
861 if (!NT_STATUS_IS_OK(status
)) {
862 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
863 gensec_security
->ops
->name
, nt_errstr(status
)));
869 return NT_STATUS_INVALID_PARAMETER
;
873 * Start a GENSEC sub-mechanism with a specified mechanism structure, used in SPNEGO
877 NTSTATUS
gensec_start_mech_by_ops(struct gensec_security
*gensec_security
,
878 const struct gensec_security_ops
*ops
)
880 gensec_security
->ops
= ops
;
881 return gensec_start_mech(gensec_security
);
886 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
887 * @param gensec_security GENSEC context pointer.
888 * @param auth_type DCERPC auth type
889 * @param auth_level DCERPC auth level
892 _PUBLIC_ NTSTATUS
gensec_start_mech_by_authtype(struct gensec_security
*gensec_security
,
893 uint8_t auth_type
, uint8_t auth_level
)
895 gensec_security
->ops
= gensec_security_by_auth_type(gensec_security
, auth_type
);
896 if (!gensec_security
->ops
) {
897 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type
));
898 return NT_STATUS_INVALID_PARAMETER
;
900 gensec_security
->dcerpc_auth_level
= auth_level
;
902 * We need to reset sign/seal in order to reset it.
903 * We may got some default features inherited by the credentials
905 gensec_security
->want_features
&= ~GENSEC_FEATURE_SIGN
;
906 gensec_security
->want_features
&= ~GENSEC_FEATURE_SEAL
;
907 gensec_want_feature(gensec_security
, GENSEC_FEATURE_DCE_STYLE
);
908 gensec_want_feature(gensec_security
, GENSEC_FEATURE_ASYNC_REPLIES
);
909 if (auth_level
== DCERPC_AUTH_LEVEL_INTEGRITY
) {
910 if (gensec_security
->gensec_role
== GENSEC_CLIENT
) {
911 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
913 } else if (auth_level
== DCERPC_AUTH_LEVEL_PACKET
) {
915 * For connection oriented DCERPC DCERPC_AUTH_LEVEL_PACKET (4)
916 * has the same behavior as DCERPC_AUTH_LEVEL_INTEGRITY (5).
918 if (gensec_security
->gensec_role
== GENSEC_CLIENT
) {
919 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
921 } else if (auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
922 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SIGN
);
923 gensec_want_feature(gensec_security
, GENSEC_FEATURE_SEAL
);
924 } else if (auth_level
== DCERPC_AUTH_LEVEL_CONNECT
) {
925 /* Default features */
927 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
929 return NT_STATUS_INVALID_PARAMETER
;
932 return gensec_start_mech(gensec_security
);
935 _PUBLIC_
const char *gensec_get_name_by_authtype(struct gensec_security
*gensec_security
, uint8_t authtype
)
937 const struct gensec_security_ops
*ops
;
938 ops
= gensec_security_by_auth_type(gensec_security
, authtype
);
946 _PUBLIC_
const char *gensec_get_name_by_oid(struct gensec_security
*gensec_security
,
947 const char *oid_string
)
949 const struct gensec_security_ops
*ops
;
950 ops
= gensec_security_by_oid(gensec_security
, oid_string
);
958 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
960 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
961 * well-known #define to hook it in.
964 _PUBLIC_ NTSTATUS
gensec_start_mech_by_oid(struct gensec_security
*gensec_security
,
965 const char *mech_oid
)
967 SMB_ASSERT(gensec_security
!= NULL
);
969 gensec_security
->ops
= gensec_security_by_oid(gensec_security
, mech_oid
);
970 if (!gensec_security
->ops
) {
971 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid
));
972 return NT_STATUS_INVALID_PARAMETER
;
974 return gensec_start_mech(gensec_security
);
978 * Start a GENSEC sub-mechanism by a well known SASL name
982 _PUBLIC_ NTSTATUS
gensec_start_mech_by_sasl_name(struct gensec_security
*gensec_security
,
983 const char *sasl_name
)
985 gensec_security
->ops
= gensec_security_by_sasl_name(gensec_security
, sasl_name
);
986 if (!gensec_security
->ops
) {
987 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name
));
988 return NT_STATUS_INVALID_PARAMETER
;
990 return gensec_start_mech(gensec_security
);
994 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
998 _PUBLIC_ NTSTATUS
gensec_start_mech_by_sasl_list(struct gensec_security
*gensec_security
,
999 const char **sasl_names
)
1001 NTSTATUS nt_status
= NT_STATUS_INVALID_PARAMETER
;
1002 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
1003 const struct gensec_security_ops
**ops
;
1006 return NT_STATUS_NO_MEMORY
;
1008 ops
= gensec_security_by_sasl_list(gensec_security
, mem_ctx
, sasl_names
);
1009 if (!ops
|| !*ops
) {
1010 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
1011 str_list_join(mem_ctx
,
1013 talloc_free(mem_ctx
);
1014 return NT_STATUS_INVALID_PARAMETER
;
1016 for (i
=0; ops
[i
]; i
++) {
1017 nt_status
= gensec_start_mech_by_ops(gensec_security
, ops
[i
]);
1018 if (!NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_PARAMETER
)) {
1022 talloc_free(mem_ctx
);
1027 * Start a GENSEC sub-mechanism by an internal name
1031 _PUBLIC_ NTSTATUS
gensec_start_mech_by_name(struct gensec_security
*gensec_security
,
1034 gensec_security
->ops
= gensec_security_by_name(gensec_security
, name
);
1035 if (!gensec_security
->ops
) {
1036 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name
));
1037 return NT_STATUS_INVALID_PARAMETER
;
1039 return gensec_start_mech(gensec_security
);
1043 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1047 _PUBLIC_ NTSTATUS
gensec_set_credentials(struct gensec_security
*gensec_security
, struct cli_credentials
*credentials
)
1049 gensec_security
->credentials
= talloc_reference(gensec_security
, credentials
);
1050 NT_STATUS_HAVE_NO_MEMORY(gensec_security
->credentials
);
1051 gensec_want_feature(gensec_security
, cli_credentials_get_gensec_features(gensec_security
->credentials
));
1052 return NT_STATUS_OK
;
1056 register a GENSEC backend.
1058 The 'name' can be later used by other backends to find the operations
1059 structure for this backend.
1061 _PUBLIC_ NTSTATUS
gensec_register(TALLOC_CTX
*ctx
,
1062 const struct gensec_security_ops
*ops
)
1064 if (gensec_security_by_name(NULL
, ops
->name
) != NULL
) {
1065 /* its already registered! */
1066 DEBUG(0,("GENSEC backend '%s' already registered\n",
1068 return NT_STATUS_OBJECT_NAME_COLLISION
;
1071 generic_security_ops
= talloc_realloc(ctx
,
1072 generic_security_ops
,
1073 const struct gensec_security_ops
*,
1074 gensec_num_backends
+2);
1075 if (!generic_security_ops
) {
1076 return NT_STATUS_NO_MEMORY
;
1079 generic_security_ops
[gensec_num_backends
] = ops
;
1080 gensec_num_backends
++;
1081 generic_security_ops
[gensec_num_backends
] = NULL
;
1083 DEBUG(3,("GENSEC backend '%s' registered\n",
1086 return NT_STATUS_OK
;
1090 return the GENSEC interface version, and the size of some critical types
1091 This can be used by backends to either detect compilation errors, or provide
1092 multiple implementations for different smbd compilation options in one module
1094 _PUBLIC_
const struct gensec_critical_sizes
*gensec_interface_version(void)
1096 static const struct gensec_critical_sizes critical_sizes
= {
1097 GENSEC_INTERFACE_VERSION
,
1098 sizeof(struct gensec_security_ops
),
1099 sizeof(struct gensec_security
),
1102 return &critical_sizes
;
1105 static int sort_gensec(const struct gensec_security_ops
**gs1
, const struct gensec_security_ops
**gs2
) {
1106 return (*gs2
)->priority
- (*gs1
)->priority
;
1109 int gensec_setting_int(struct gensec_settings
*settings
, const char *mechanism
, const char *name
, int default_value
)
1111 return lpcfg_parm_int(settings
->lp_ctx
, NULL
, mechanism
, name
, default_value
);
1114 bool gensec_setting_bool(struct gensec_settings
*settings
, const char *mechanism
, const char *name
, bool default_value
)
1116 return lpcfg_parm_bool(settings
->lp_ctx
, NULL
, mechanism
, name
, default_value
);
1120 initialise the GENSEC subsystem
1122 _PUBLIC_ NTSTATUS
gensec_init(void)
1124 static bool initialized
= false;
1125 #define _MODULE_PROTO(init) extern NTSTATUS init(TALLOC_CTX *);
1126 #ifdef STATIC_gensec_MODULES
1127 STATIC_gensec_MODULES_PROTO
;
1128 init_module_fn static_init
[] = { STATIC_gensec_MODULES
};
1130 init_module_fn
*static_init
= NULL
;
1132 init_module_fn
*shared_init
;
1134 if (initialized
) return NT_STATUS_OK
;
1137 shared_init
= load_samba_modules(NULL
, "gensec");
1139 run_init_functions(NULL
, static_init
);
1140 run_init_functions(NULL
, shared_init
);
1142 talloc_free(shared_init
);
1144 TYPESAFE_QSORT(generic_security_ops
, gensec_num_backends
, sort_gensec
);
1146 return NT_STATUS_OK
;