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 "auth/auth.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/gensec/gensec.h"
29 #include "auth/gensec/gensec_proto.h"
30 #include "param/param.h"
32 /* the list of currently registered GENSEC backends */
33 static struct gensec_security_ops **generic_security_ops;
34 static int gensec_num_backends;
36 /* Return all the registered mechs. Don't modify the return pointer,
37 * but you may talloc_reference it if convient */
38 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
40 return generic_security_ops;
43 bool gensec_security_ops_enabled(struct gensec_security_ops *ops,
44 struct loadparm_context *lp_ctx)
46 return lp_parm_bool(lp_ctx, NULL, "gensec", ops->name, ops->enabled);
49 /* Sometimes we want to force only kerberos, sometimes we want to
50 * force it's avoidance. The old list could be either
51 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
52 * an existing list we have trimmed down) */
54 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
55 struct gensec_security_ops **old_gensec_list,
56 struct cli_credentials *creds)
58 struct gensec_security_ops **new_gensec_list;
59 int i, j, num_mechs_in;
60 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
63 use_kerberos = cli_credentials_get_kerberos_state(creds);
66 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
67 if (!talloc_reference(mem_ctx, old_gensec_list)) {
70 return old_gensec_list;
73 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
77 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
78 if (!new_gensec_list) {
83 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
86 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
87 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
88 new_gensec_list[j] = old_gensec_list[i];
93 switch (use_kerberos) {
94 case CRED_DONT_USE_KERBEROS:
95 if (old_gensec_list[i]->kerberos == false) {
96 new_gensec_list[j] = old_gensec_list[i];
100 case CRED_MUST_USE_KERBEROS:
101 if (old_gensec_list[i]->kerberos == true) {
102 new_gensec_list[j] = old_gensec_list[i];
107 /* Can't happen or invalid parameter */
111 new_gensec_list[j] = NULL;
113 return new_gensec_list;
116 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
119 struct gensec_security_ops **backends;
120 backends = gensec_security_all();
121 if (!gensec_security) {
122 if (!talloc_reference(mem_ctx, backends)) {
127 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
129 if (!talloc_reference(mem_ctx, backends)) {
134 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
138 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
142 struct gensec_security_ops **backends;
143 const struct gensec_security_ops *backend;
144 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
148 backends = gensec_security_mechs(gensec_security, mem_ctx);
149 for (i=0; backends && backends[i]; i++) {
150 if (!gensec_security_ops_enabled(backends[i],
151 gensec_security->settings->lp_ctx))
153 if (backends[i]->auth_type == auth_type) {
154 backend = backends[i];
155 talloc_free(mem_ctx);
159 talloc_free(mem_ctx);
164 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
165 const char *oid_string)
168 struct gensec_security_ops **backends;
169 const struct gensec_security_ops *backend;
170 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
174 backends = gensec_security_mechs(gensec_security, mem_ctx);
175 for (i=0; backends && backends[i]; i++) {
176 if (gensec_security != NULL &&
177 !gensec_security_ops_enabled(backends[i],
178 gensec_security->settings->lp_ctx))
180 if (backends[i]->oid) {
181 for (j=0; backends[i]->oid[j]; j++) {
182 if (backends[i]->oid[j] &&
183 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
184 backend = backends[i];
185 talloc_free(mem_ctx);
191 talloc_free(mem_ctx);
196 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
197 const char *sasl_name)
200 struct gensec_security_ops **backends;
201 const struct gensec_security_ops *backend;
202 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
206 backends = gensec_security_mechs(gensec_security, mem_ctx);
207 for (i=0; backends && backends[i]; i++) {
208 if (!gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
210 if (backends[i]->sasl_name
211 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
212 backend = backends[i];
213 talloc_free(mem_ctx);
217 talloc_free(mem_ctx);
222 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
226 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->settings->lp_ctx))
237 if (backends[i]->name
238 && (strcmp(backends[i]->name, name) == 0)) {
239 backend = backends[i];
240 talloc_free(mem_ctx);
244 talloc_free(mem_ctx);
249 * Return a unique list of security subsystems from those specified in
250 * the list of SASL names.
252 * Use the list of enabled GENSEC mechanisms from the credentials
253 * attached to the gensec_security, and return in our preferred order.
256 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
258 const char **sasl_names)
260 const struct gensec_security_ops **backends_out;
261 struct gensec_security_ops **backends;
263 int num_backends_out = 0;
269 backends = gensec_security_mechs(gensec_security, mem_ctx);
271 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
275 backends_out[0] = NULL;
277 /* Find backends in our preferred order, by walking our list,
278 * then looking in the supplied list */
279 for (i=0; backends && backends[i]; i++) {
280 if (gensec_security != NULL &&
281 !gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
283 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
284 if (!backends[i]->sasl_name ||
285 !(strcmp(backends[i]->sasl_name,
286 sasl_names[sasl_idx]) == 0)) {
290 for (k=0; backends_out[k]; k++) {
291 if (backends_out[k] == backends[i]) {
296 if (k < num_backends_out) {
297 /* already in there */
301 backends_out = talloc_realloc(mem_ctx, backends_out,
302 const struct gensec_security_ops *,
303 num_backends_out + 2);
308 backends_out[num_backends_out] = backends[i];
310 backends_out[num_backends_out] = NULL;
317 * Return a unique list of security subsystems from those specified in
318 * the OID list. That is, where two OIDs refer to the same module,
319 * return that module only once.
321 * Use the list of enabled GENSEC mechanisms from the credentials
322 * attached to the gensec_security, and return in our preferred order.
325 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
327 const char **oid_strings,
330 struct gensec_security_ops_wrapper *backends_out;
331 struct gensec_security_ops **backends;
332 int i, j, k, oid_idx;
333 int num_backends_out = 0;
339 backends = gensec_security_mechs(gensec_security, gensec_security);
341 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
345 backends_out[0].op = NULL;
346 backends_out[0].oid = NULL;
348 /* Find backends in our preferred order, by walking our list,
349 * then looking in the supplied list */
350 for (i=0; backends && backends[i]; i++) {
351 if (gensec_security != NULL &&
352 !gensec_security_ops_enabled(backends[i], gensec_security->settings->lp_ctx))
354 if (!backends[i]->oid) {
357 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
358 if (strcmp(oid_strings[oid_idx], skip) == 0) {
362 for (j=0; backends[i]->oid[j]; j++) {
363 if (!backends[i]->oid[j] ||
364 !(strcmp(backends[i]->oid[j],
365 oid_strings[oid_idx]) == 0)) {
369 for (k=0; backends_out[k].op; k++) {
370 if (backends_out[k].op == backends[i]) {
375 if (k < num_backends_out) {
376 /* already in there */
380 backends_out = talloc_realloc(mem_ctx, backends_out,
381 struct gensec_security_ops_wrapper,
382 num_backends_out + 2);
387 backends_out[num_backends_out].op = backends[i];
388 backends_out[num_backends_out].oid = backends[i]->oid[j];
390 backends_out[num_backends_out].op = NULL;
391 backends_out[num_backends_out].oid = NULL;
399 * Return OIDS from the security subsystems listed
402 const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security,
404 struct gensec_security_ops **ops,
410 const char **oid_list;
414 oid_list = talloc_array(mem_ctx, const char *, 1);
419 for (i=0; ops && ops[i]; i++) {
420 if (gensec_security != NULL &&
421 !gensec_security_ops_enabled(ops[i], gensec_security->settings->lp_ctx)) {
428 for (k = 0; ops[i]->oid[k]; k++) {
429 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
431 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
435 oid_list[j] = ops[i]->oid[k];
446 * Return OIDS from the security subsystems listed
449 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
450 const struct gensec_security_ops_wrapper *wops)
455 const char **oid_list;
459 oid_list = talloc_array(mem_ctx, const char *, 1);
464 for (i=0; wops[i].op; i++) {
465 if (!wops[i].op->oid) {
469 for (k = 0; wops[i].op->oid[k]; k++) {
470 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
474 oid_list[j] = wops[i].op->oid[k];
484 * Return all the security subsystems currently enabled on a GENSEC context.
486 * This is taken from a list attached to the cli_credentials, and
487 * skips the OID in 'skip'. (Typically the SPNEGO OID)
491 const char **gensec_security_oids(struct gensec_security *gensec_security,
495 struct gensec_security_ops **ops
496 = gensec_security_mechs(gensec_security, mem_ctx);
497 return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip);
503 Start the GENSEC system, returning a context pointer.
504 @param mem_ctx The parent TALLOC memory context.
505 @param gensec_security Returned GENSEC context pointer.
506 @note The mem_ctx is only a parent and may be NULL.
508 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
509 struct tevent_context *ev,
510 struct gensec_settings *settings,
511 struct messaging_context *msg,
512 struct gensec_security **gensec_security)
515 DEBUG(0, ("No event context available!\n"));
516 return NT_STATUS_INTERNAL_ERROR;
519 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
520 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
522 (*gensec_security)->ops = NULL;
523 (*gensec_security)->private_data = NULL;
525 ZERO_STRUCT((*gensec_security)->target);
526 ZERO_STRUCT((*gensec_security)->peer_addr);
527 ZERO_STRUCT((*gensec_security)->my_addr);
529 (*gensec_security)->subcontext = false;
530 (*gensec_security)->want_features = 0;
532 (*gensec_security)->event_ctx = ev;
533 (*gensec_security)->msg_ctx = msg;
534 SMB_ASSERT(settings->lp_ctx != NULL);
535 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
541 * Start a GENSEC subcontext, with a copy of the properties of the parent
542 * @param mem_ctx The parent TALLOC memory context.
543 * @param parent The parent GENSEC context
544 * @param gensec_security Returned GENSEC context pointer.
545 * @note Used by SPNEGO in particular, for the actual implementation mechanism
548 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
549 struct gensec_security *parent,
550 struct gensec_security **gensec_security)
552 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
553 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
555 (**gensec_security) = *parent;
556 (*gensec_security)->ops = NULL;
557 (*gensec_security)->private_data = NULL;
559 (*gensec_security)->subcontext = true;
560 (*gensec_security)->want_features = parent->want_features;
561 (*gensec_security)->event_ctx = parent->event_ctx;
562 (*gensec_security)->msg_ctx = parent->msg_ctx;
563 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
569 Start the GENSEC system, in client mode, returning a context pointer.
570 @param mem_ctx The parent TALLOC memory context.
571 @param gensec_security Returned GENSEC context pointer.
572 @note The mem_ctx is only a parent and may be NULL.
574 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
575 struct gensec_security **gensec_security,
576 struct tevent_context *ev,
577 struct gensec_settings *settings)
581 if (settings == NULL) {
582 DEBUG(0,("gensec_client_start: no settings given!\n"));
583 return NT_STATUS_INTERNAL_ERROR;
586 status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
587 if (!NT_STATUS_IS_OK(status)) {
590 (*gensec_security)->gensec_role = GENSEC_CLIENT;
596 Start the GENSEC system, in server mode, returning a context pointer.
597 @param mem_ctx The parent TALLOC memory context.
598 @param gensec_security Returned GENSEC context pointer.
599 @note The mem_ctx is only a parent and may be NULL.
601 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
602 struct tevent_context *ev,
603 struct gensec_settings *settings,
604 struct messaging_context *msg,
605 struct gensec_security **gensec_security)
610 DEBUG(0,("gensec_server_start: no event context given!\n"));
611 return NT_STATUS_INTERNAL_ERROR;
615 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
616 return NT_STATUS_INTERNAL_ERROR;
620 DEBUG(0,("gensec_server_start: no settings given!\n"));
621 return NT_STATUS_INTERNAL_ERROR;
624 status = gensec_start(mem_ctx, ev, settings, msg, gensec_security);
625 if (!NT_STATUS_IS_OK(status)) {
628 (*gensec_security)->gensec_role = GENSEC_SERVER;
633 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
636 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
637 gensec_security->subcontext ? "sub" : "",
638 gensec_security->ops->name));
639 switch (gensec_security->gensec_role) {
641 if (gensec_security->ops->client_start) {
642 status = gensec_security->ops->client_start(gensec_security);
643 if (!NT_STATUS_IS_OK(status)) {
644 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
645 gensec_security->ops->name, nt_errstr(status)));
651 if (gensec_security->ops->server_start) {
652 status = gensec_security->ops->server_start(gensec_security);
653 if (!NT_STATUS_IS_OK(status)) {
654 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
655 gensec_security->ops->name, nt_errstr(status)));
661 return NT_STATUS_INVALID_PARAMETER;
665 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
666 * @param gensec_security GENSEC context pointer.
667 * @param auth_type DCERPC auth type
668 * @param auth_level DCERPC auth level
671 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
672 uint8_t auth_type, uint8_t auth_level)
674 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
675 if (!gensec_security->ops) {
676 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
677 return NT_STATUS_INVALID_PARAMETER;
679 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
680 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
681 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
682 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
683 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
684 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
685 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
686 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
687 /* Default features */
689 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
691 return NT_STATUS_INVALID_PARAMETER;
694 return gensec_start_mech(gensec_security);
697 _PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype)
699 const struct gensec_security_ops *ops;
700 ops = gensec_security_by_authtype(gensec_security, authtype);
708 _PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security,
709 const char *oid_string)
711 const struct gensec_security_ops *ops;
712 ops = gensec_security_by_oid(gensec_security, oid_string);
721 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
725 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
726 const struct gensec_security_ops *ops)
728 gensec_security->ops = ops;
729 return gensec_start_mech(gensec_security);
733 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
735 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
736 * well-known #define to hook it in.
739 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
740 const char *mech_oid)
742 SMB_ASSERT(gensec_security != NULL);
744 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
745 if (!gensec_security->ops) {
746 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
747 return NT_STATUS_INVALID_PARAMETER;
749 return gensec_start_mech(gensec_security);
753 * Start a GENSEC sub-mechanism by a well know SASL name
757 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
758 const char *sasl_name)
760 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
761 if (!gensec_security->ops) {
762 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
763 return NT_STATUS_INVALID_PARAMETER;
765 return gensec_start_mech(gensec_security);
769 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
773 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
774 const char **sasl_names)
776 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
777 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
778 const struct gensec_security_ops **ops;
781 return NT_STATUS_NO_MEMORY;
783 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
785 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
786 str_list_join(mem_ctx,
788 talloc_free(mem_ctx);
789 return NT_STATUS_INVALID_PARAMETER;
791 for (i=0; ops[i]; i++) {
792 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
793 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
797 talloc_free(mem_ctx);
802 * Start a GENSEC sub-mechanism by an internal name
806 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
809 gensec_security->ops = gensec_security_by_name(gensec_security, name);
810 if (!gensec_security->ops) {
811 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
812 return NT_STATUS_INVALID_PARAMETER;
814 return gensec_start_mech(gensec_security);
818 wrappers for the gensec function pointers
820 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
822 uint8_t *data, size_t length,
823 const uint8_t *whole_pdu, size_t pdu_length,
824 const DATA_BLOB *sig)
826 if (!gensec_security->ops->unseal_packet) {
827 return NT_STATUS_NOT_IMPLEMENTED;
829 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
830 return NT_STATUS_INVALID_PARAMETER;
833 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
835 whole_pdu, pdu_length,
839 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
841 const uint8_t *data, size_t length,
842 const uint8_t *whole_pdu, size_t pdu_length,
843 const DATA_BLOB *sig)
845 if (!gensec_security->ops->check_packet) {
846 return NT_STATUS_NOT_IMPLEMENTED;
848 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
849 return NT_STATUS_INVALID_PARAMETER;
852 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
855 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
857 uint8_t *data, size_t length,
858 const uint8_t *whole_pdu, size_t pdu_length,
861 if (!gensec_security->ops->seal_packet) {
862 return NT_STATUS_NOT_IMPLEMENTED;
864 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
865 return NT_STATUS_INVALID_PARAMETER;
868 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
871 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
873 const uint8_t *data, size_t length,
874 const uint8_t *whole_pdu, size_t pdu_length,
877 if (!gensec_security->ops->sign_packet) {
878 return NT_STATUS_NOT_IMPLEMENTED;
880 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
881 return NT_STATUS_INVALID_PARAMETER;
884 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
887 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
889 if (!gensec_security->ops->sig_size) {
892 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
896 return gensec_security->ops->sig_size(gensec_security, data_size);
899 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
901 if (!gensec_security->ops->max_wrapped_size) {
905 return gensec_security->ops->max_wrapped_size(gensec_security);
908 size_t gensec_max_input_size(struct gensec_security *gensec_security)
910 if (!gensec_security->ops->max_input_size) {
911 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
914 return gensec_security->ops->max_input_size(gensec_security);
917 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
922 if (!gensec_security->ops->wrap) {
923 return NT_STATUS_NOT_IMPLEMENTED;
925 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
928 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
933 if (!gensec_security->ops->unwrap) {
934 return NT_STATUS_NOT_IMPLEMENTED;
936 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
939 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
940 DATA_BLOB *session_key)
942 if (!gensec_security->ops->session_key) {
943 return NT_STATUS_NOT_IMPLEMENTED;
945 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
946 return NT_STATUS_NO_USER_SESSION_KEY;
949 return gensec_security->ops->session_key(gensec_security, session_key);
953 * Return the credentials of a logged on user, including session keys
956 * Only valid after a successful authentication
958 * May only be called once per authentication.
962 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
963 struct auth_session_info **session_info)
965 if (!gensec_security->ops->session_info) {
966 return NT_STATUS_NOT_IMPLEMENTED;
968 return gensec_security->ops->session_info(gensec_security, session_info);
972 * Next state function for the GENSEC state machine
974 * @param gensec_security GENSEC State
975 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
976 * @param in The request, as a DATA_BLOB
977 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
978 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
979 * or NT_STATUS_OK if the user is authenticated.
982 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
983 const DATA_BLOB in, DATA_BLOB *out)
985 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
988 static void gensec_update_async_timed_handler(struct tevent_context *ev, struct tevent_timer *te,
989 struct timeval t, void *ptr)
991 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
992 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
993 req->callback.fn(req, req->callback.private_data);
997 * Next state function for the GENSEC state machine async version
999 * @param gensec_security GENSEC State
1000 * @param in The request, as a DATA_BLOB
1001 * @param callback The function that will be called when the operation is
1002 * finished, it should return gensec_update_recv() to get output
1003 * @param private_data A private pointer that will be passed to the callback function
1006 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
1007 void (*callback)(struct gensec_update_request *req, void *private_data),
1010 struct gensec_update_request *req = NULL;
1011 struct tevent_timer *te = NULL;
1013 req = talloc(gensec_security, struct gensec_update_request);
1014 if (!req) goto failed;
1015 req->gensec_security = gensec_security;
1017 req->out = data_blob(NULL, 0);
1018 req->callback.fn = callback;
1019 req->callback.private_data = private_data;
1021 te = event_add_timed(gensec_security->event_ctx, req,
1023 gensec_update_async_timed_handler, req);
1024 if (!te) goto failed;
1030 callback(NULL, private_data);
1034 * Next state function for the GENSEC state machine
1036 * @param req GENSEC update request state
1037 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1038 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1039 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1040 * or NT_STATUS_OK if the user is authenticated.
1042 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1046 NT_STATUS_HAVE_NO_MEMORY(req);
1049 talloc_steal(out_mem_ctx, out->data);
1050 status = req->status;
1057 * Set the requirement for a certain feature on the connection
1061 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1064 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1065 gensec_security->want_features |= feature;
1068 gensec_security->ops->want_feature(gensec_security, feature);
1072 * Check the requirement for a certain feature on the connection
1076 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1079 if (!gensec_security->ops->have_feature) {
1083 /* We might 'have' features that we don't 'want', because the
1084 * other end demanded them, or we can't neotiate them off */
1085 return gensec_security->ops->have_feature(gensec_security, feature);
1089 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1093 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1095 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1096 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1097 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1098 return NT_STATUS_OK;
1102 * Return the credentials structure associated with a GENSEC context
1106 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1108 if (!gensec_security) {
1111 return gensec_security->credentials;
1115 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1119 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1121 gensec_security->target.service = talloc_strdup(gensec_security, service);
1122 if (!gensec_security->target.service) {
1123 return NT_STATUS_NO_MEMORY;
1125 return NT_STATUS_OK;
1128 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1130 if (gensec_security->target.service) {
1131 return gensec_security->target.service;
1138 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1142 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1144 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1145 if (hostname && !gensec_security->target.hostname) {
1146 return NT_STATUS_NO_MEMORY;
1148 return NT_STATUS_OK;
1151 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1153 /* We allow the target hostname to be overriden for testing purposes */
1154 if (gensec_security->settings->target_hostname) {
1155 return gensec_security->settings->target_hostname;
1158 if (gensec_security->target.hostname) {
1159 return gensec_security->target.hostname;
1162 /* We could add use the 'set sockaddr' call, and do a reverse
1163 * lookup, but this would be both insecure (compromising the
1164 * way kerberos works) and add DNS timeouts */
1169 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1171 * This is so that kerberos can include these addresses in
1172 * cryptographic tokens, to avoid certain attacks.
1175 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1177 gensec_security->my_addr = my_addr;
1178 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1179 return NT_STATUS_NO_MEMORY;
1181 return NT_STATUS_OK;
1184 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1186 gensec_security->peer_addr = peer_addr;
1187 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1188 return NT_STATUS_NO_MEMORY;
1190 return NT_STATUS_OK;
1193 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1195 if (gensec_security->my_addr) {
1196 return gensec_security->my_addr;
1199 /* We could add a 'set sockaddr' call, and do a lookup. This
1200 * would avoid needing to do system calls if nothing asks. */
1204 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1206 if (gensec_security->peer_addr) {
1207 return gensec_security->peer_addr;
1210 /* We could add a 'set sockaddr' call, and do a lookup. This
1211 * would avoid needing to do system calls if nothing asks.
1212 * However, this is not appropriate for the peer addres on
1213 * datagram sockets */
1220 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1221 * - ensures it is talloc()ed
1225 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1227 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1228 if (!gensec_security->target.principal) {
1229 return NT_STATUS_NO_MEMORY;
1231 return NT_STATUS_OK;
1234 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1236 if (gensec_security->target.principal) {
1237 return gensec_security->target.principal;
1244 register a GENSEC backend.
1246 The 'name' can be later used by other backends to find the operations
1247 structure for this backend.
1249 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1251 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1252 /* its already registered! */
1253 DEBUG(0,("GENSEC backend '%s' already registered\n",
1255 return NT_STATUS_OBJECT_NAME_COLLISION;
1258 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1259 generic_security_ops,
1260 struct gensec_security_ops *,
1261 gensec_num_backends+2);
1262 if (!generic_security_ops) {
1263 return NT_STATUS_NO_MEMORY;
1266 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1267 gensec_num_backends++;
1268 generic_security_ops[gensec_num_backends] = NULL;
1270 DEBUG(3,("GENSEC backend '%s' registered\n",
1273 return NT_STATUS_OK;
1277 return the GENSEC interface version, and the size of some critical types
1278 This can be used by backends to either detect compilation errors, or provide
1279 multiple implementations for different smbd compilation options in one module
1281 const struct gensec_critical_sizes *gensec_interface_version(void)
1283 static const struct gensec_critical_sizes critical_sizes = {
1284 GENSEC_INTERFACE_VERSION,
1285 sizeof(struct gensec_security_ops),
1286 sizeof(struct gensec_security),
1289 return &critical_sizes;
1292 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1293 return (*gs2)->priority - (*gs1)->priority;
1296 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1298 return lp_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1301 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1303 return lp_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1307 initialise the GENSEC subsystem
1309 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1311 static bool initialized = false;
1312 extern NTSTATUS gensec_sasl_init(void);
1313 extern NTSTATUS gensec_krb5_init(void);
1314 extern NTSTATUS gensec_schannel_init(void);
1315 extern NTSTATUS gensec_spnego_init(void);
1316 extern NTSTATUS gensec_gssapi_init(void);
1317 extern NTSTATUS gensec_ntlmssp_init(void);
1319 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1320 init_module_fn *shared_init;
1322 if (initialized) return NT_STATUS_OK;
1325 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1327 run_init_functions(static_init);
1328 run_init_functions(shared_init);
1330 talloc_free(shared_init);
1332 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1334 return NT_STATUS_OK;