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/util/tsort.h"
33 #include "lib/util/samba_modules.h"
34 #include "lib/util/base64.h"
35 #include "lib/crypto/gnutls_helpers.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 (!samba_gnutls_weak_crypto_allowed() && ops
->weak_crypto
) {
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
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
81 static const struct gensec_security_ops
**gensec_use_kerberos_mechs(
83 const struct gensec_security_ops
* const *old_gensec_list
,
84 enum credentials_use_kerberos use_kerberos
,
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
++) {
94 new_gensec_list
= talloc_array(mem_ctx
,
95 const struct gensec_security_ops
*,
97 if (!new_gensec_list
) {
102 for (i
=0; old_gensec_list
&& old_gensec_list
[i
]; i
++) {
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
:
119 case CRED_USE_KERBEROS_DISABLED
:
120 if (old_gensec_list
[i
]->kerberos
== false) {
126 case CRED_USE_KERBEROS_REQUIRED
:
127 if (old_gensec_list
[i
]->kerberos
== true) {
133 /* Can't happen or invalid parameter */
141 new_gensec_list
[j
] = old_gensec_list
[i
];
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
,
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
);
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
)
193 const struct gensec_security_ops
**backends
;
194 const struct gensec_security_ops
*backend
;
195 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
],
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
);
216 talloc_free(mem_ctx
);
221 _PUBLIC_
const struct gensec_security_ops
*gensec_security_by_sasl_name(
222 struct gensec_security
*gensec_security
,
223 const char *sasl_name
)
226 const struct gensec_security_ops
**backends
;
227 const struct gensec_security_ops
*backend
;
228 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
)) {
238 if (backends
[i
]->sasl_name
239 && (strcmp(backends
[i
]->sasl_name
, sasl_name
) == 0)) {
240 backend
= backends
[i
];
241 talloc_free(mem_ctx
);
245 talloc_free(mem_ctx
);
250 _PUBLIC_
const struct gensec_security_ops
*gensec_security_by_auth_type(
251 struct gensec_security
*gensec_security
,
255 const struct gensec_security_ops
**backends
;
256 const struct gensec_security_ops
*backend
;
259 if (auth_type
== DCERPC_AUTH_TYPE_NONE
) {
263 mem_ctx
= talloc_new(gensec_security
);
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
)) {
273 if (backends
[i
]->auth_type
== auth_type
) {
274 backend
= backends
[i
];
275 talloc_free(mem_ctx
);
279 talloc_free(mem_ctx
);
284 const struct gensec_security_ops
*gensec_security_by_name(struct gensec_security
*gensec_security
,
288 const struct gensec_security_ops
**backends
;
289 const struct gensec_security_ops
*backend
;
290 TALLOC_CTX
*mem_ctx
= talloc_new(gensec_security
);
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
))
299 if (backends
[i
]->name
300 && (strcmp(backends
[i
]->name
, name
) == 0)) {
301 backend
= backends
[i
];
302 talloc_free(mem_ctx
);
306 talloc_free(mem_ctx
);
310 static const char **gensec_security_sasl_names_from_ops(
311 struct gensec_security
*gensec_security
,
313 const struct gensec_security_ops
* const *ops
)
315 const char **sasl_names
= NULL
;
316 size_t i
, sasl_names_count
= 0;
322 sasl_names
= talloc_array(mem_ctx
, const char *, 1);
323 if (sasl_names
== 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
) {
335 if (gensec_security
!= NULL
) {
336 if (!gensec_security_ops_enabled(ops
[i
],
341 role
= gensec_security
->gensec_role
;
346 if (ops
[i
]->client_start
== NULL
) {
351 if (ops
[i
]->server_start
== NULL
) {
357 tmp
= talloc_realloc(mem_ctx
,
360 sasl_names_count
+ 2);
362 TALLOC_FREE(sasl_names
);
367 sasl_names
[sasl_names_count
] = ops
[i
]->sasl_name
;
370 sasl_names
[sasl_names_count
] = NULL
;
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.
385 const char **gensec_security_sasl_names(struct gensec_security
*gensec_security
,
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
,
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
,
408 const char **sasl_names
)
410 const struct gensec_security_ops
**backends_out
;
411 const struct gensec_security_ops
**backends
;
413 int num_backends_out
= 0;
419 backends
= gensec_security_mechs(gensec_security
, mem_ctx
);
421 backends_out
= talloc_array(mem_ctx
, const struct gensec_security_ops
*, 1);
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
))
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)) {
440 for (k
=0; backends_out
[k
]; k
++) {
441 if (backends_out
[k
] == backends
[i
]) {
446 if (k
< num_backends_out
) {
447 /* already in there */
451 backends_out
= talloc_realloc(mem_ctx
, backends_out
,
452 const struct gensec_security_ops
*,
453 num_backends_out
+ 2);
458 backends_out
[num_backends_out
] = backends
[i
];
460 backends_out
[num_backends_out
] = NULL
;
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
,
478 const char * const *oid_strings
,
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;
490 backends
= gensec_security_mechs(gensec_security
, gensec_security
);
492 backends_out
= talloc_array(mem_ctx
, struct gensec_security_ops_wrapper
, 1);
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
))
505 if (!backends
[i
]->oid
) {
508 for (oid_idx
= 0; oid_strings
[oid_idx
]; oid_idx
++) {
509 if (strcmp(oid_strings
[oid_idx
], skip
) == 0) {
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)) {
520 for (k
=0; backends_out
[k
].op
; k
++) {
521 if (backends_out
[k
].op
== backends
[i
]) {
526 if (k
< num_backends_out
) {
527 /* already in there */
531 backends_out
= talloc_realloc(mem_ctx
, backends_out
,
532 struct gensec_security_ops_wrapper
,
533 num_backends_out
+ 2);
538 backends_out
[num_backends_out
].op
= backends
[i
];
539 backends_out
[num_backends_out
].oid
= backends
[i
]->oid
[j
];
541 backends_out
[num_backends_out
].op
= NULL
;
542 backends_out
[num_backends_out
].oid
= NULL
;
550 * Return OIDS from the security subsystems listed
553 static const char **gensec_security_oids_from_ops(
554 struct gensec_security
*gensec_security
,
556 const struct gensec_security_ops
* const *ops
,
562 const char **oid_list
;
566 oid_list
= talloc_array(mem_ctx
, const char *, 1);
571 for (i
=0; ops
&& ops
[i
]; i
++) {
572 if (gensec_security
!= NULL
&&
573 !gensec_security_ops_enabled(ops
[i
], gensec_security
)) {
580 for (k
= 0; ops
[i
]->oid
[k
]; k
++) {
581 if (skip
&& strcmp(skip
, ops
[i
]->oid
[k
])==0) {
583 oid_list
= talloc_realloc(mem_ctx
, oid_list
, const char *, j
+ 2);
587 oid_list
[j
] = ops
[i
]->oid
[k
];
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
)
607 const char **oid_list
;
611 oid_list
= talloc_array(mem_ctx
, const char *, 1);
616 for (i
=0; wops
[i
].op
; i
++) {
617 if (!wops
[i
].op
->oid
) {
621 for (k
= 0; wops
[i
].op
->oid
[k
]; k
++) {
622 oid_list
= talloc_realloc(mem_ctx
, oid_list
, const char *, j
+ 2);
626 oid_list
[j
] = wops
[i
].op
->oid
[k
];
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
,
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
;
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
697 (*gensec_security
)->auth_context
= talloc_reference(*gensec_security
, auth_context
);
699 talloc_set_destructor((*gensec_security
), gensec_security_destructor
);
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
);
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
;
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
)
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
)) {
776 (*gensec_security
)->gensec_role
= GENSEC_CLIENT
;
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
)
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
)) {
805 (*gensec_security
)->gensec_role
= GENSEC_SERVER
;
810 static NTSTATUS
gensec_start_mech(struct gensec_security
*gensec_security
)
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
);
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
,
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
) {
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
)));
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
)));
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 */
926 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
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
);
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
);
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
;
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
,
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
)) {
1021 talloc_free(mem_ctx
);
1026 * Start a GENSEC sub-mechanism by an internal name
1030 _PUBLIC_ NTSTATUS
gensec_start_mech_by_name(struct gensec_security
*gensec_security
,
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",
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",
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
};
1129 init_module_fn
*static_init
= NULL
;
1131 init_module_fn
*shared_init
;
1133 if (initialized
) return NT_STATUS_OK
;
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
;