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 "lib/events/events.h"
25 #include "librpc/rpc/dcerpc.h"
26 #include "auth/credentials/credentials.h"
27 #include "auth/gensec/gensec.h"
28 #include "param/param.h"
30 /* the list of currently registered GENSEC backends */
31 static struct gensec_security_ops **generic_security_ops;
32 static int gensec_num_backends;
34 /* Return all the registered mechs. Don't modify the return pointer,
35 * but you may talloc_reference it if convient */
36 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
38 return generic_security_ops;
41 bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security)
43 return lp_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled);
46 /* Sometimes we want to force only kerberos, sometimes we want to
47 * force it's avoidance. The old list could be either
48 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
49 * an existing list we have trimmed down) */
51 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
52 struct gensec_security_ops **old_gensec_list,
53 struct cli_credentials *creds)
55 struct gensec_security_ops **new_gensec_list;
56 int i, j, num_mechs_in;
57 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
60 use_kerberos = cli_credentials_get_kerberos_state(creds);
63 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
64 if (!talloc_reference(mem_ctx, old_gensec_list)) {
67 return old_gensec_list;
70 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
74 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
75 if (!new_gensec_list) {
80 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
83 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
84 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
85 new_gensec_list[j] = old_gensec_list[i];
90 switch (use_kerberos) {
91 case CRED_DONT_USE_KERBEROS:
92 if (old_gensec_list[i]->kerberos == false) {
93 new_gensec_list[j] = old_gensec_list[i];
97 case CRED_MUST_USE_KERBEROS:
98 if (old_gensec_list[i]->kerberos == true) {
99 new_gensec_list[j] = old_gensec_list[i];
104 /* Can't happen or invalid parameter */
108 new_gensec_list[j] = NULL;
110 return new_gensec_list;
113 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
116 struct gensec_security_ops **backends;
117 backends = gensec_security_all();
118 if (!gensec_security) {
119 if (!talloc_reference(mem_ctx, backends)) {
124 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
126 if (!talloc_reference(mem_ctx, backends)) {
131 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
135 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
139 struct gensec_security_ops **backends;
140 const struct gensec_security_ops *backend;
141 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
145 backends = gensec_security_mechs(gensec_security, mem_ctx);
146 for (i=0; backends && backends[i]; i++) {
147 if (!gensec_security_ops_enabled(backends[i], gensec_security))
149 if (backends[i]->auth_type == auth_type) {
150 backend = backends[i];
151 talloc_free(mem_ctx);
155 talloc_free(mem_ctx);
160 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
161 const char *oid_string)
164 struct gensec_security_ops **backends;
165 const struct gensec_security_ops *backend;
166 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
170 backends = gensec_security_mechs(gensec_security, mem_ctx);
171 for (i=0; backends && backends[i]; i++) {
172 if (gensec_security != NULL &&
173 !gensec_security_ops_enabled(backends[i],
176 if (backends[i]->oid) {
177 for (j=0; backends[i]->oid[j]; j++) {
178 if (backends[i]->oid[j] &&
179 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
180 backend = backends[i];
181 talloc_free(mem_ctx);
187 talloc_free(mem_ctx);
192 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
193 const char *sasl_name)
196 struct gensec_security_ops **backends;
197 const struct gensec_security_ops *backend;
198 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
202 backends = gensec_security_mechs(gensec_security, mem_ctx);
203 for (i=0; backends && backends[i]; i++) {
204 if (!gensec_security_ops_enabled(backends[i], gensec_security))
206 if (backends[i]->sasl_name
207 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
208 backend = backends[i];
209 talloc_free(mem_ctx);
213 talloc_free(mem_ctx);
218 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
222 struct gensec_security_ops **backends;
223 const struct gensec_security_ops *backend;
224 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
228 backends = gensec_security_mechs(gensec_security, mem_ctx);
229 for (i=0; backends && backends[i]; i++) {
230 if (gensec_security != NULL &&
231 !gensec_security_ops_enabled(backends[i], gensec_security))
233 if (backends[i]->name
234 && (strcmp(backends[i]->name, name) == 0)) {
235 backend = backends[i];
236 talloc_free(mem_ctx);
240 talloc_free(mem_ctx);
245 * Return a unique list of security subsystems from those specified in
246 * the list of SASL names.
248 * Use the list of enabled GENSEC mechanisms from the credentials
249 * attached to the gensec_security, and return in our preferred order.
252 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
254 const char **sasl_names)
256 const struct gensec_security_ops **backends_out;
257 struct gensec_security_ops **backends;
259 int num_backends_out = 0;
265 backends = gensec_security_mechs(gensec_security, mem_ctx);
267 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
271 backends_out[0] = NULL;
273 /* Find backends in our preferred order, by walking our list,
274 * then looking in the supplied list */
275 for (i=0; backends && backends[i]; i++) {
276 if (gensec_security != NULL &&
277 !gensec_security_ops_enabled(backends[i], gensec_security))
279 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
280 if (!backends[i]->sasl_name ||
281 !(strcmp(backends[i]->sasl_name,
282 sasl_names[sasl_idx]) == 0)) {
286 for (k=0; backends_out[k]; k++) {
287 if (backends_out[k] == backends[i]) {
292 if (k < num_backends_out) {
293 /* already in there */
297 backends_out = talloc_realloc(mem_ctx, backends_out,
298 const struct gensec_security_ops *,
299 num_backends_out + 2);
304 backends_out[num_backends_out] = backends[i];
306 backends_out[num_backends_out] = NULL;
313 * Return a unique list of security subsystems from those specified in
314 * the OID list. That is, where two OIDs refer to the same module,
315 * return that module only once.
317 * Use the list of enabled GENSEC mechanisms from the credentials
318 * attached to the gensec_security, and return in our preferred order.
321 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
323 const char **oid_strings,
326 struct gensec_security_ops_wrapper *backends_out;
327 struct gensec_security_ops **backends;
328 int i, j, k, oid_idx;
329 int num_backends_out = 0;
335 backends = gensec_security_mechs(gensec_security, gensec_security);
337 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
341 backends_out[0].op = NULL;
342 backends_out[0].oid = NULL;
344 /* Find backends in our preferred order, by walking our list,
345 * then looking in the supplied list */
346 for (i=0; backends && backends[i]; i++) {
347 if (gensec_security != NULL &&
348 !gensec_security_ops_enabled(backends[i], gensec_security))
350 if (!backends[i]->oid) {
353 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
354 if (strcmp(oid_strings[oid_idx], skip) == 0) {
358 for (j=0; backends[i]->oid[j]; j++) {
359 if (!backends[i]->oid[j] ||
360 !(strcmp(backends[i]->oid[j],
361 oid_strings[oid_idx]) == 0)) {
365 for (k=0; backends_out[k].op; k++) {
366 if (backends_out[k].op == backends[i]) {
371 if (k < num_backends_out) {
372 /* already in there */
376 backends_out = talloc_realloc(mem_ctx, backends_out,
377 struct gensec_security_ops_wrapper,
378 num_backends_out + 2);
383 backends_out[num_backends_out].op = backends[i];
384 backends_out[num_backends_out].oid = backends[i]->oid[j];
386 backends_out[num_backends_out].op = NULL;
387 backends_out[num_backends_out].oid = NULL;
395 * Return OIDS from the security subsystems listed
398 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
400 struct gensec_security_ops **ops,
406 const char **oid_list;
410 oid_list = talloc_array(mem_ctx, const char *, 1);
415 for (i=0; ops && ops[i]; i++) {
416 if (gensec_security != NULL &&
417 !gensec_security_ops_enabled(ops[i], gensec_security)) {
424 for (k = 0; ops[i]->oid[k]; k++) {
425 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
427 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
431 oid_list[j] = ops[i]->oid[k];
442 * Return OIDS from the security subsystems listed
445 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
446 const struct gensec_security_ops_wrapper *wops)
451 const char **oid_list;
455 oid_list = talloc_array(mem_ctx, const char *, 1);
460 for (i=0; wops[i].op; i++) {
461 if (!wops[i].op->oid) {
465 for (k = 0; wops[i].op->oid[k]; k++) {
466 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
470 oid_list[j] = wops[i].op->oid[k];
480 * Return all the security subsystems currently enabled on a GENSEC context.
482 * This is taken from a list attached to the cli_credentials, and
483 * skips the OID in 'skip'. (Typically the SPNEGO OID)
487 const char **gensec_security_oids(struct gensec_security *gensec_security,
491 struct gensec_security_ops **ops
492 = gensec_security_mechs(gensec_security, mem_ctx);
493 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
499 Start the GENSEC system, returning a context pointer.
500 @param mem_ctx The parent TALLOC memory context.
501 @param gensec_security Returned GENSEC context pointer.
502 @note The mem_ctx is only a parent and may be NULL.
503 @note, the auth context is moved to be a child of the
504 @ gensec_security return
506 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
507 struct tevent_context *ev,
508 struct gensec_settings *settings,
509 struct auth_context *auth_context,
510 struct gensec_security **gensec_security)
513 DEBUG(0, ("No event context available!\n"));
514 return NT_STATUS_INTERNAL_ERROR;
517 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
518 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
520 (*gensec_security)->ops = NULL;
521 (*gensec_security)->private_data = NULL;
523 ZERO_STRUCT((*gensec_security)->target);
524 ZERO_STRUCT((*gensec_security)->peer_addr);
525 ZERO_STRUCT((*gensec_security)->my_addr);
527 (*gensec_security)->subcontext = false;
528 (*gensec_security)->want_features = 0;
530 (*gensec_security)->event_ctx = ev;
531 SMB_ASSERT(settings->lp_ctx != NULL);
532 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
533 (*gensec_security)->auth_context = talloc_steal(*gensec_security, auth_context);
539 * Start a GENSEC subcontext, with a copy of the properties of the parent
540 * @param mem_ctx The parent TALLOC memory context.
541 * @param parent The parent GENSEC context
542 * @param gensec_security Returned GENSEC context pointer.
543 * @note Used by SPNEGO in particular, for the actual implementation mechanism
546 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
547 struct gensec_security *parent,
548 struct gensec_security **gensec_security)
550 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
551 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
553 (**gensec_security) = *parent;
554 (*gensec_security)->ops = NULL;
555 (*gensec_security)->private_data = NULL;
557 (*gensec_security)->subcontext = true;
558 (*gensec_security)->want_features = parent->want_features;
559 (*gensec_security)->event_ctx = parent->event_ctx;
560 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
561 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
562 (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context);
568 Start the GENSEC system, in client mode, 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.
573 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
574 struct gensec_security **gensec_security,
575 struct tevent_context *ev,
576 struct gensec_settings *settings)
580 if (settings == NULL) {
581 DEBUG(0,("gensec_client_start: no settings given!\n"));
582 return NT_STATUS_INTERNAL_ERROR;
585 status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
586 if (!NT_STATUS_IS_OK(status)) {
589 (*gensec_security)->gensec_role = GENSEC_CLIENT;
595 Start the GENSEC system, in server mode, returning a context pointer.
596 @param mem_ctx The parent TALLOC memory context.
597 @param gensec_security Returned GENSEC context pointer.
598 @note The mem_ctx is only a parent and may be NULL.
600 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
601 struct tevent_context *ev,
602 struct gensec_settings *settings,
603 struct auth_context *auth_context,
604 struct gensec_security **gensec_security)
609 DEBUG(0,("gensec_server_start: no event context given!\n"));
610 return NT_STATUS_INTERNAL_ERROR;
614 DEBUG(0,("gensec_server_start: no settings given!\n"));
615 return NT_STATUS_INTERNAL_ERROR;
618 status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security);
619 if (!NT_STATUS_IS_OK(status)) {
622 (*gensec_security)->gensec_role = GENSEC_SERVER;
627 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
630 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
631 gensec_security->subcontext ? "sub" : "",
632 gensec_security->ops->name));
633 switch (gensec_security->gensec_role) {
635 if (gensec_security->ops->client_start) {
636 status = gensec_security->ops->client_start(gensec_security);
637 if (!NT_STATUS_IS_OK(status)) {
638 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
639 gensec_security->ops->name, nt_errstr(status)));
645 if (gensec_security->ops->server_start) {
646 status = gensec_security->ops->server_start(gensec_security);
647 if (!NT_STATUS_IS_OK(status)) {
648 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
649 gensec_security->ops->name, nt_errstr(status)));
655 return NT_STATUS_INVALID_PARAMETER;
659 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
660 * @param gensec_security GENSEC context pointer.
661 * @param auth_type DCERPC auth type
662 * @param auth_level DCERPC auth level
665 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
666 uint8_t auth_type, uint8_t auth_level)
668 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
669 if (!gensec_security->ops) {
670 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
671 return NT_STATUS_INVALID_PARAMETER;
673 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
674 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
675 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
676 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
677 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
678 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
679 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
680 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
681 /* Default features */
683 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
685 return NT_STATUS_INVALID_PARAMETER;
688 return gensec_start_mech(gensec_security);
691 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
693 const struct gensec_security_ops *ops;
694 ops = gensec_security_by_authtype(gensec_security, authtype);
702 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
703 const char *oid_string)
705 const struct gensec_security_ops *ops;
706 ops = gensec_security_by_oid(gensec_security, oid_string);
715 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
719 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
720 const struct gensec_security_ops *ops)
722 gensec_security->ops = ops;
723 return gensec_start_mech(gensec_security);
727 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
729 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
730 * well-known #define to hook it in.
733 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
734 const char *mech_oid)
736 SMB_ASSERT(gensec_security != NULL);
738 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
739 if (!gensec_security->ops) {
740 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
741 return NT_STATUS_INVALID_PARAMETER;
743 return gensec_start_mech(gensec_security);
747 * Start a GENSEC sub-mechanism by a well know SASL name
751 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
752 const char *sasl_name)
754 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
755 if (!gensec_security->ops) {
756 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
757 return NT_STATUS_INVALID_PARAMETER;
759 return gensec_start_mech(gensec_security);
763 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
767 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
768 const char **sasl_names)
770 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
771 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
772 const struct gensec_security_ops **ops;
775 return NT_STATUS_NO_MEMORY;
777 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
779 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
780 str_list_join(mem_ctx,
782 talloc_free(mem_ctx);
783 return NT_STATUS_INVALID_PARAMETER;
785 for (i=0; ops[i]; i++) {
786 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
787 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
791 talloc_free(mem_ctx);
796 * Start a GENSEC sub-mechanism by an internal name
800 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
803 gensec_security->ops = gensec_security_by_name(gensec_security, name);
804 if (!gensec_security->ops) {
805 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
806 return NT_STATUS_INVALID_PARAMETER;
808 return gensec_start_mech(gensec_security);
812 wrappers for the gensec function pointers
814 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
816 uint8_t *data, size_t length,
817 const uint8_t *whole_pdu, size_t pdu_length,
818 const DATA_BLOB *sig)
820 if (!gensec_security->ops->unseal_packet) {
821 return NT_STATUS_NOT_IMPLEMENTED;
823 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
824 return NT_STATUS_INVALID_PARAMETER;
827 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
829 whole_pdu, pdu_length,
833 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
835 const uint8_t *data, size_t length,
836 const uint8_t *whole_pdu, size_t pdu_length,
837 const DATA_BLOB *sig)
839 if (!gensec_security->ops->check_packet) {
840 return NT_STATUS_NOT_IMPLEMENTED;
842 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
843 return NT_STATUS_INVALID_PARAMETER;
846 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
849 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
851 uint8_t *data, size_t length,
852 const uint8_t *whole_pdu, size_t pdu_length,
855 if (!gensec_security->ops->seal_packet) {
856 return NT_STATUS_NOT_IMPLEMENTED;
858 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
859 return NT_STATUS_INVALID_PARAMETER;
862 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
865 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
867 const uint8_t *data, size_t length,
868 const uint8_t *whole_pdu, size_t pdu_length,
871 if (!gensec_security->ops->sign_packet) {
872 return NT_STATUS_NOT_IMPLEMENTED;
874 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
875 return NT_STATUS_INVALID_PARAMETER;
878 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
881 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
883 if (!gensec_security->ops->sig_size) {
886 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
890 return gensec_security->ops->sig_size(gensec_security, data_size);
893 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
895 if (!gensec_security->ops->max_wrapped_size) {
899 return gensec_security->ops->max_wrapped_size(gensec_security);
902 size_t gensec_max_input_size(struct gensec_security *gensec_security)
904 if (!gensec_security->ops->max_input_size) {
905 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
908 return gensec_security->ops->max_input_size(gensec_security);
911 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
916 if (!gensec_security->ops->wrap) {
917 return NT_STATUS_NOT_IMPLEMENTED;
919 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
922 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
927 if (!gensec_security->ops->unwrap) {
928 return NT_STATUS_NOT_IMPLEMENTED;
930 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
933 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
934 DATA_BLOB *session_key)
936 if (!gensec_security->ops->session_key) {
937 return NT_STATUS_NOT_IMPLEMENTED;
939 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
940 return NT_STATUS_NO_USER_SESSION_KEY;
943 return gensec_security->ops->session_key(gensec_security, session_key);
947 * Return the credentials of a logged on user, including session keys
950 * Only valid after a successful authentication
952 * May only be called once per authentication.
956 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
957 struct auth_session_info **session_info)
959 if (!gensec_security->ops->session_info) {
960 return NT_STATUS_NOT_IMPLEMENTED;
962 return gensec_security->ops->session_info(gensec_security, session_info);
966 * Next state function for the GENSEC state machine
968 * @param gensec_security GENSEC State
969 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
970 * @param in The request, as a DATA_BLOB
971 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
972 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
973 * or NT_STATUS_OK if the user is authenticated.
976 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
977 const DATA_BLOB in, DATA_BLOB *out)
979 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
982 static void gensec_update_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
983 struct timeval t, void *ptr)
985 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
986 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
987 req->callback.fn(req, req->callback.private_data);
991 * Next state function for the GENSEC state machine async version
993 * @param gensec_security GENSEC State
994 * @param in The request, as a DATA_BLOB
995 * @param callback The function that will be called when the operation is
996 * finished, it should return gensec_update_recv() to get output
997 * @param private_data A private pointer that will be passed to the callback function
1000 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
1001 void (*callback)(struct gensec_update_request *req, void *private_data),
1004 struct gensec_update_request *req = NULL;
1005 struct tevent_timer *te = NULL;
1007 req = talloc(gensec_security, struct gensec_update_request);
1008 if (!req) goto failed;
1009 req->gensec_security = gensec_security;
1011 req->out = data_blob(NULL, 0);
1012 req->callback.fn = callback;
1013 req->callback.private_data = private_data;
1015 te = event_add_timed(gensec_security->event_ctx, req,
1017 gensec_update_async_timed_handler, req);
1018 if (!te) goto failed;
1024 callback(NULL, private_data);
1028 * Next state function for the GENSEC state machine
1030 * @param req GENSEC update request state
1031 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1032 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1033 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1034 * or NT_STATUS_OK if the user is authenticated.
1036 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1040 NT_STATUS_HAVE_NO_MEMORY(req);
1043 talloc_steal(out_mem_ctx, out->data);
1044 status = req->status;
1051 * Set the requirement for a certain feature on the connection
1055 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1058 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1059 gensec_security->want_features |= feature;
1062 gensec_security->ops->want_feature(gensec_security, feature);
1066 * Check the requirement for a certain feature on the connection
1070 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1073 if (!gensec_security->ops->have_feature) {
1077 /* We might 'have' features that we don't 'want', because the
1078 * other end demanded them, or we can't neotiate them off */
1079 return gensec_security->ops->have_feature(gensec_security, feature);
1083 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1087 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1089 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1090 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1091 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1092 return NT_STATUS_OK;
1096 * Return the credentials structure associated with a GENSEC context
1100 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1102 if (!gensec_security) {
1105 return gensec_security->credentials;
1109 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1113 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1115 gensec_security->target.service = talloc_strdup(gensec_security, service);
1116 if (!gensec_security->target.service) {
1117 return NT_STATUS_NO_MEMORY;
1119 return NT_STATUS_OK;
1122 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1124 if (gensec_security->target.service) {
1125 return gensec_security->target.service;
1132 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1136 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1138 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1139 if (hostname && !gensec_security->target.hostname) {
1140 return NT_STATUS_NO_MEMORY;
1142 return NT_STATUS_OK;
1145 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1147 /* We allow the target hostname to be overriden for testing purposes */
1148 if (gensec_security->settings->target_hostname) {
1149 return gensec_security->settings->target_hostname;
1152 if (gensec_security->target.hostname) {
1153 return gensec_security->target.hostname;
1156 /* We could add use the 'set sockaddr' call, and do a reverse
1157 * lookup, but this would be both insecure (compromising the
1158 * way kerberos works) and add DNS timeouts */
1163 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1165 * This is so that kerberos can include these addresses in
1166 * cryptographic tokens, to avoid certain attacks.
1169 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1171 gensec_security->my_addr = my_addr;
1172 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1173 return NT_STATUS_NO_MEMORY;
1175 return NT_STATUS_OK;
1178 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1180 gensec_security->peer_addr = peer_addr;
1181 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1182 return NT_STATUS_NO_MEMORY;
1184 return NT_STATUS_OK;
1187 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1189 if (gensec_security->my_addr) {
1190 return gensec_security->my_addr;
1193 /* We could add a 'set sockaddr' call, and do a lookup. This
1194 * would avoid needing to do system calls if nothing asks. */
1198 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1200 if (gensec_security->peer_addr) {
1201 return gensec_security->peer_addr;
1204 /* We could add a 'set sockaddr' call, and do a lookup. This
1205 * would avoid needing to do system calls if nothing asks.
1206 * However, this is not appropriate for the peer addres on
1207 * datagram sockets */
1214 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1215 * - ensures it is talloc()ed
1219 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1221 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1222 if (!gensec_security->target.principal) {
1223 return NT_STATUS_NO_MEMORY;
1225 return NT_STATUS_OK;
1228 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1230 if (gensec_security->target.principal) {
1231 return gensec_security->target.principal;
1238 register a GENSEC backend.
1240 The 'name' can be later used by other backends to find the operations
1241 structure for this backend.
1243 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1245 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1246 /* its already registered! */
1247 DEBUG(0,("GENSEC backend '%s' already registered\n",
1249 return NT_STATUS_OBJECT_NAME_COLLISION;
1252 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1253 generic_security_ops,
1254 struct gensec_security_ops *,
1255 gensec_num_backends+2);
1256 if (!generic_security_ops) {
1257 return NT_STATUS_NO_MEMORY;
1260 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1261 gensec_num_backends++;
1262 generic_security_ops[gensec_num_backends] = NULL;
1264 DEBUG(3,("GENSEC backend '%s' registered\n",
1267 return NT_STATUS_OK;
1271 return the GENSEC interface version, and the size of some critical types
1272 This can be used by backends to either detect compilation errors, or provide
1273 multiple implementations for different smbd compilation options in one module
1275 const struct gensec_critical_sizes *gensec_interface_version(void)
1277 static const struct gensec_critical_sizes critical_sizes = {
1278 GENSEC_INTERFACE_VERSION,
1279 sizeof(struct gensec_security_ops),
1280 sizeof(struct gensec_security),
1283 return &critical_sizes;
1286 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1287 return (*gs2)->priority - (*gs1)->priority;
1290 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1292 return lp_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1295 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1297 return lp_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1301 initialise the GENSEC subsystem
1303 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1305 static bool initialized = false;
1306 extern NTSTATUS gensec_sasl_init(void);
1307 extern NTSTATUS gensec_krb5_init(void);
1308 extern NTSTATUS gensec_schannel_init(void);
1309 extern NTSTATUS gensec_spnego_init(void);
1310 extern NTSTATUS gensec_gssapi_init(void);
1311 extern NTSTATUS gensec_ntlmssp_init(void);
1313 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1314 init_module_fn *shared_init;
1316 if (initialized) return NT_STATUS_OK;
1319 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1321 run_init_functions(static_init);
1322 run_init_functions(shared_init);
1324 talloc_free(shared_init);
1326 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1328 return NT_STATUS_OK;