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 /* Sometimes we want to force only kerberos, sometimes we want to
44 * force it's avoidance. The old list could be either
45 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
46 * an existing list we have trimmed down) */
48 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
49 struct gensec_security_ops **old_gensec_list,
50 struct cli_credentials *creds)
52 struct gensec_security_ops **new_gensec_list;
53 int i, j, num_mechs_in;
54 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
57 use_kerberos = cli_credentials_get_kerberos_state(creds);
60 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
61 if (!talloc_reference(mem_ctx, old_gensec_list)) {
64 return old_gensec_list;
67 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
71 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
72 if (!new_gensec_list) {
77 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
79 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
80 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
81 new_gensec_list[j] = old_gensec_list[i];
86 switch (use_kerberos) {
87 case CRED_DONT_USE_KERBEROS:
88 if (old_gensec_list[i]->kerberos == false) {
89 new_gensec_list[j] = old_gensec_list[i];
93 case CRED_MUST_USE_KERBEROS:
94 if (old_gensec_list[i]->kerberos == true) {
95 new_gensec_list[j] = old_gensec_list[i];
100 /* Can't happen or invalid parameter */
104 new_gensec_list[j] = NULL;
106 return new_gensec_list;
109 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
112 struct gensec_security_ops **backends;
113 backends = gensec_security_all();
114 if (!gensec_security) {
115 if (!talloc_reference(mem_ctx, backends)) {
120 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
122 if (!talloc_reference(mem_ctx, backends)) {
127 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
131 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
135 struct gensec_security_ops **backends;
136 const struct gensec_security_ops *backend;
137 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
141 backends = gensec_security_mechs(gensec_security, mem_ctx);
142 for (i=0; backends && backends[i]; i++) {
143 if (backends[i]->auth_type == auth_type) {
144 backend = backends[i];
145 talloc_free(mem_ctx);
149 talloc_free(mem_ctx);
154 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
155 const char *oid_string)
158 struct gensec_security_ops **backends;
159 const struct gensec_security_ops *backend;
160 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
164 backends = gensec_security_mechs(gensec_security, mem_ctx);
165 for (i=0; backends && backends[i]; i++) {
166 if (backends[i]->oid) {
167 for (j=0; backends[i]->oid[j]; j++) {
168 if (backends[i]->oid[j] &&
169 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
170 backend = backends[i];
171 talloc_free(mem_ctx);
177 talloc_free(mem_ctx);
182 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
183 const char *sasl_name)
186 struct gensec_security_ops **backends;
187 const struct gensec_security_ops *backend;
188 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
192 backends = gensec_security_mechs(gensec_security, mem_ctx);
193 for (i=0; backends && backends[i]; i++) {
194 if (backends[i]->sasl_name
195 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
196 backend = backends[i];
197 talloc_free(mem_ctx);
201 talloc_free(mem_ctx);
206 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
210 struct gensec_security_ops **backends;
211 const struct gensec_security_ops *backend;
212 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
216 backends = gensec_security_mechs(gensec_security, mem_ctx);
217 for (i=0; backends && backends[i]; i++) {
218 if (backends[i]->name
219 && (strcmp(backends[i]->name, name) == 0)) {
220 backend = backends[i];
221 talloc_free(mem_ctx);
225 talloc_free(mem_ctx);
230 * Return a unique list of security subsystems from those specified in
231 * the list of SASL names.
233 * Use the list of enabled GENSEC mechanisms from the credentials
234 * attached to the gensec_security, and return in our preferred order.
237 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
239 const char **sasl_names)
241 const struct gensec_security_ops **backends_out;
242 struct gensec_security_ops **backends;
244 int num_backends_out = 0;
250 backends = gensec_security_mechs(gensec_security, mem_ctx);
252 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
256 backends_out[0] = NULL;
258 /* Find backends in our preferred order, by walking our list,
259 * then looking in the supplied list */
260 for (i=0; backends && backends[i]; i++) {
261 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
262 if (!backends[i]->sasl_name ||
263 !(strcmp(backends[i]->sasl_name,
264 sasl_names[sasl_idx]) == 0)) {
268 for (k=0; backends_out[k]; k++) {
269 if (backends_out[k] == backends[i]) {
274 if (k < num_backends_out) {
275 /* already in there */
279 backends_out = talloc_realloc(mem_ctx, backends_out,
280 const struct gensec_security_ops *,
281 num_backends_out + 2);
286 backends_out[num_backends_out] = backends[i];
288 backends_out[num_backends_out] = NULL;
295 * Return a unique list of security subsystems from those specified in
296 * the OID list. That is, where two OIDs refer to the same module,
297 * return that module only once.
299 * Use the list of enabled GENSEC mechanisms from the credentials
300 * attached to the gensec_security, and return in our preferred order.
303 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
305 const char **oid_strings,
308 struct gensec_security_ops_wrapper *backends_out;
309 struct gensec_security_ops **backends;
310 int i, j, k, oid_idx;
311 int num_backends_out = 0;
317 backends = gensec_security_mechs(gensec_security, gensec_security);
319 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
323 backends_out[0].op = NULL;
324 backends_out[0].oid = NULL;
326 /* Find backends in our preferred order, by walking our list,
327 * then looking in the supplied list */
328 for (i=0; backends && backends[i]; i++) {
329 if (!backends[i]->oid) {
332 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
333 if (strcmp(oid_strings[oid_idx], skip) == 0) {
337 for (j=0; backends[i]->oid[j]; j++) {
338 if (!backends[i]->oid[j] ||
339 !(strcmp(backends[i]->oid[j],
340 oid_strings[oid_idx]) == 0)) {
344 for (k=0; backends_out[k].op; k++) {
345 if (backends_out[k].op == backends[i]) {
350 if (k < num_backends_out) {
351 /* already in there */
355 backends_out = talloc_realloc(mem_ctx, backends_out,
356 struct gensec_security_ops_wrapper,
357 num_backends_out + 2);
362 backends_out[num_backends_out].op = backends[i];
363 backends_out[num_backends_out].oid = backends[i]->oid[j];
365 backends_out[num_backends_out].op = NULL;
366 backends_out[num_backends_out].oid = NULL;
374 * Return OIDS from the security subsystems listed
377 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
378 struct gensec_security_ops **ops,
384 const char **oid_list;
388 oid_list = talloc_array(mem_ctx, const char *, 1);
393 for (i=0; ops && ops[i]; i++) {
398 for (k = 0; ops[i]->oid[k]; k++) {
399 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
401 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
405 oid_list[j] = ops[i]->oid[k];
416 * Return OIDS from the security subsystems listed
419 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
420 const struct gensec_security_ops_wrapper *wops)
425 const char **oid_list;
429 oid_list = talloc_array(mem_ctx, const char *, 1);
434 for (i=0; wops[i].op; i++) {
435 if (!wops[i].op->oid) {
439 for (k = 0; wops[i].op->oid[k]; k++) {
440 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
444 oid_list[j] = wops[i].op->oid[k];
454 * Return all the security subsystems currently enabled on a GENSEC context.
456 * This is taken from a list attached to the cli_credentials, and
457 * skips the OID in 'skip'. (Typically the SPNEGO OID)
461 const char **gensec_security_oids(struct gensec_security *gensec_security,
465 struct gensec_security_ops **ops
466 = gensec_security_mechs(gensec_security, mem_ctx);
467 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
473 Start the GENSEC system, returning a context pointer.
474 @param mem_ctx The parent TALLOC memory context.
475 @param gensec_security Returned GENSEC context pointer.
476 @note The mem_ctx is only a parent and may be NULL.
478 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
479 struct event_context *ev,
480 struct loadparm_context *lp_ctx,
481 struct messaging_context *msg,
482 struct gensec_security **gensec_security)
485 DEBUG(0, ("No event context available!\n"));
486 return NT_STATUS_INTERNAL_ERROR;
489 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
490 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
492 (*gensec_security)->ops = NULL;
494 ZERO_STRUCT((*gensec_security)->target);
495 ZERO_STRUCT((*gensec_security)->peer_addr);
496 ZERO_STRUCT((*gensec_security)->my_addr);
498 (*gensec_security)->subcontext = false;
499 (*gensec_security)->want_features = 0;
501 (*gensec_security)->event_ctx = ev;
502 (*gensec_security)->msg_ctx = msg;
503 (*gensec_security)->lp_ctx = lp_ctx;
509 * Start a GENSEC subcontext, with a copy of the properties of the parent
510 * @param mem_ctx The parent TALLOC memory context.
511 * @param parent The parent GENSEC context
512 * @param gensec_security Returned GENSEC context pointer.
513 * @note Used by SPNEGO in particular, for the actual implementation mechanism
516 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
517 struct gensec_security *parent,
518 struct gensec_security **gensec_security)
520 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
521 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
523 (**gensec_security) = *parent;
524 (*gensec_security)->ops = NULL;
525 (*gensec_security)->private_data = NULL;
527 (*gensec_security)->subcontext = true;
528 (*gensec_security)->event_ctx = parent->event_ctx;
529 (*gensec_security)->msg_ctx = parent->msg_ctx;
530 (*gensec_security)->lp_ctx = parent->lp_ctx;
536 Start the GENSEC system, in client mode, returning a context pointer.
537 @param mem_ctx The parent TALLOC memory context.
538 @param gensec_security Returned GENSEC context pointer.
539 @note The mem_ctx is only a parent and may be NULL.
541 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
542 struct gensec_security **gensec_security,
543 struct event_context *ev,
544 struct loadparm_context *lp_ctx)
548 status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
549 if (!NT_STATUS_IS_OK(status)) {
552 (*gensec_security)->gensec_role = GENSEC_CLIENT;
558 Start the GENSEC system, in server mode, returning a context pointer.
559 @param mem_ctx The parent TALLOC memory context.
560 @param gensec_security Returned GENSEC context pointer.
561 @note The mem_ctx is only a parent and may be NULL.
563 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
564 struct event_context *ev,
565 struct loadparm_context *lp_ctx,
566 struct messaging_context *msg,
567 struct gensec_security **gensec_security)
572 DEBUG(0,("gensec_server_start: no event context given!\n"));
573 return NT_STATUS_INTERNAL_ERROR;
577 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
578 return NT_STATUS_INTERNAL_ERROR;
581 status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
582 if (!NT_STATUS_IS_OK(status)) {
585 (*gensec_security)->gensec_role = GENSEC_SERVER;
590 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
593 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
594 gensec_security->subcontext ? "sub" : "",
595 gensec_security->ops->name));
596 switch (gensec_security->gensec_role) {
598 if (gensec_security->ops->client_start) {
599 status = gensec_security->ops->client_start(gensec_security);
600 if (!NT_STATUS_IS_OK(status)) {
601 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
602 gensec_security->ops->name, nt_errstr(status)));
608 if (gensec_security->ops->server_start) {
609 status = gensec_security->ops->server_start(gensec_security);
610 if (!NT_STATUS_IS_OK(status)) {
611 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
612 gensec_security->ops->name, nt_errstr(status)));
618 return NT_STATUS_INVALID_PARAMETER;
622 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
623 * @param gensec_security GENSEC context pointer.
624 * @param auth_type DCERPC auth type
625 * @param auth_level DCERPC auth level
628 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
629 uint8_t auth_type, uint8_t auth_level)
631 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
632 if (!gensec_security->ops) {
633 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
634 return NT_STATUS_INVALID_PARAMETER;
636 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
637 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
638 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
639 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
640 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
641 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
642 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
643 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
644 /* Default features */
646 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
648 return NT_STATUS_INVALID_PARAMETER;
651 return gensec_start_mech(gensec_security);
654 _PUBLIC_ const char *gensec_get_name_by_authtype(uint8_t authtype)
656 const struct gensec_security_ops *ops;
657 ops = gensec_security_by_authtype(NULL, authtype);
665 _PUBLIC_ const char *gensec_get_name_by_oid(const char *oid_string)
667 const struct gensec_security_ops *ops;
668 ops = gensec_security_by_oid(NULL, oid_string);
677 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
681 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
682 const struct gensec_security_ops *ops)
684 gensec_security->ops = ops;
685 return gensec_start_mech(gensec_security);
689 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
691 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
692 * well-known #define to hook it in.
695 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
696 const char *mech_oid)
698 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
699 if (!gensec_security->ops) {
700 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
701 return NT_STATUS_INVALID_PARAMETER;
703 return gensec_start_mech(gensec_security);
707 * Start a GENSEC sub-mechanism by a well know SASL name
711 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
712 const char *sasl_name)
714 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
715 if (!gensec_security->ops) {
716 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
717 return NT_STATUS_INVALID_PARAMETER;
719 return gensec_start_mech(gensec_security);
723 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
727 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
728 const char **sasl_names)
730 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
731 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
732 const struct gensec_security_ops **ops;
735 return NT_STATUS_NO_MEMORY;
737 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
739 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
740 str_list_join(mem_ctx,
742 talloc_free(mem_ctx);
743 return NT_STATUS_INVALID_PARAMETER;
745 for (i=0; ops[i]; i++) {
746 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
747 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
751 talloc_free(mem_ctx);
756 * Start a GENSEC sub-mechanism by an internal name
760 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
763 gensec_security->ops = gensec_security_by_name(gensec_security, name);
764 if (!gensec_security->ops) {
765 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
766 return NT_STATUS_INVALID_PARAMETER;
768 return gensec_start_mech(gensec_security);
772 wrappers for the gensec function pointers
774 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
776 uint8_t *data, size_t length,
777 const uint8_t *whole_pdu, size_t pdu_length,
778 const DATA_BLOB *sig)
780 if (!gensec_security->ops->unseal_packet) {
781 return NT_STATUS_NOT_IMPLEMENTED;
783 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
784 return NT_STATUS_INVALID_PARAMETER;
787 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
789 whole_pdu, pdu_length,
793 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
795 const uint8_t *data, size_t length,
796 const uint8_t *whole_pdu, size_t pdu_length,
797 const DATA_BLOB *sig)
799 if (!gensec_security->ops->check_packet) {
800 return NT_STATUS_NOT_IMPLEMENTED;
802 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
803 return NT_STATUS_INVALID_PARAMETER;
806 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
809 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
811 uint8_t *data, size_t length,
812 const uint8_t *whole_pdu, size_t pdu_length,
815 if (!gensec_security->ops->seal_packet) {
816 return NT_STATUS_NOT_IMPLEMENTED;
818 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
819 return NT_STATUS_INVALID_PARAMETER;
822 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
825 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
827 const uint8_t *data, size_t length,
828 const uint8_t *whole_pdu, size_t pdu_length,
831 if (!gensec_security->ops->sign_packet) {
832 return NT_STATUS_NOT_IMPLEMENTED;
834 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
835 return NT_STATUS_INVALID_PARAMETER;
838 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
841 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
843 if (!gensec_security->ops->sig_size) {
846 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
850 return gensec_security->ops->sig_size(gensec_security, data_size);
853 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
855 if (!gensec_security->ops->max_wrapped_size) {
859 return gensec_security->ops->max_wrapped_size(gensec_security);
862 size_t gensec_max_input_size(struct gensec_security *gensec_security)
864 if (!gensec_security->ops->max_input_size) {
865 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
868 return gensec_security->ops->max_input_size(gensec_security);
871 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
876 if (!gensec_security->ops->wrap) {
877 return NT_STATUS_NOT_IMPLEMENTED;
879 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
882 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
887 if (!gensec_security->ops->unwrap) {
888 return NT_STATUS_NOT_IMPLEMENTED;
890 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
893 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
894 DATA_BLOB *session_key)
896 if (!gensec_security->ops->session_key) {
897 return NT_STATUS_NOT_IMPLEMENTED;
899 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
900 return NT_STATUS_NO_USER_SESSION_KEY;
903 return gensec_security->ops->session_key(gensec_security, session_key);
907 * Return the credentials of a logged on user, including session keys
910 * Only valid after a successful authentication
912 * May only be called once per authentication.
916 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
917 struct auth_session_info **session_info)
919 if (!gensec_security->ops->session_info) {
920 return NT_STATUS_NOT_IMPLEMENTED;
922 return gensec_security->ops->session_info(gensec_security, session_info);
926 * Next state function for the GENSEC state machine
928 * @param gensec_security GENSEC State
929 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
930 * @param in The request, as a DATA_BLOB
931 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
932 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
933 * or NT_STATUS_OK if the user is authenticated.
936 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
937 const DATA_BLOB in, DATA_BLOB *out)
939 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
942 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
943 struct timeval t, void *ptr)
945 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
946 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
947 req->callback.fn(req, req->callback.private_data);
951 * Next state function for the GENSEC state machine async version
953 * @param gensec_security GENSEC State
954 * @param in The request, as a DATA_BLOB
955 * @param callback The function that will be called when the operation is
956 * finished, it should return gensec_update_recv() to get output
957 * @param private_data A private pointer that will be passed to the callback function
960 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
961 void (*callback)(struct gensec_update_request *req, void *private_data),
964 struct gensec_update_request *req = NULL;
965 struct timed_event *te = NULL;
967 req = talloc(gensec_security, struct gensec_update_request);
968 if (!req) goto failed;
969 req->gensec_security = gensec_security;
971 req->out = data_blob(NULL, 0);
972 req->callback.fn = callback;
973 req->callback.private_data = private_data;
975 te = event_add_timed(gensec_security->event_ctx, req,
977 gensec_update_async_timed_handler, req);
978 if (!te) goto failed;
984 callback(NULL, private_data);
988 * Next state function for the GENSEC state machine
990 * @param req GENSEC update request state
991 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
992 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
993 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
994 * or NT_STATUS_OK if the user is authenticated.
996 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1000 NT_STATUS_HAVE_NO_MEMORY(req);
1003 talloc_steal(out_mem_ctx, out->data);
1004 status = req->status;
1011 * Set the requirement for a certain feature on the connection
1015 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1018 gensec_security->want_features |= feature;
1022 * Check the requirement for a certain feature on the connection
1026 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1029 if (!gensec_security->ops->have_feature) {
1033 /* We might 'have' features that we don't 'want', because the
1034 * other end demanded them, or we can't neotiate them off */
1035 return gensec_security->ops->have_feature(gensec_security, feature);
1039 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1043 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1045 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1046 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1047 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1048 return NT_STATUS_OK;
1052 * Return the credentials structure associated with a GENSEC context
1056 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1058 if (!gensec_security) {
1061 return gensec_security->credentials;
1065 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1069 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1071 gensec_security->target.service = talloc_strdup(gensec_security, service);
1072 if (!gensec_security->target.service) {
1073 return NT_STATUS_NO_MEMORY;
1075 return NT_STATUS_OK;
1078 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1080 if (gensec_security->target.service) {
1081 return gensec_security->target.service;
1088 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1092 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1094 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1095 if (hostname && !gensec_security->target.hostname) {
1096 return NT_STATUS_NO_MEMORY;
1098 return NT_STATUS_OK;
1101 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1103 /* We allow the target hostname to be overriden for testing purposes */
1104 const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1105 if (target_hostname) {
1106 return target_hostname;
1109 if (gensec_security->target.hostname) {
1110 return gensec_security->target.hostname;
1113 /* We could add use the 'set sockaddr' call, and do a reverse
1114 * lookup, but this would be both insecure (compromising the
1115 * way kerberos works) and add DNS timeouts */
1120 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1122 * This is so that kerberos can include these addresses in
1123 * cryptographic tokens, to avoid certain attacks.
1126 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1128 gensec_security->my_addr = my_addr;
1129 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1130 return NT_STATUS_NO_MEMORY;
1132 return NT_STATUS_OK;
1135 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1137 gensec_security->peer_addr = peer_addr;
1138 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1139 return NT_STATUS_NO_MEMORY;
1141 return NT_STATUS_OK;
1144 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1146 if (gensec_security->my_addr) {
1147 return gensec_security->my_addr;
1150 /* We could add a 'set sockaddr' call, and do a lookup. This
1151 * would avoid needing to do system calls if nothing asks. */
1155 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1157 if (gensec_security->peer_addr) {
1158 return gensec_security->peer_addr;
1161 /* We could add a 'set sockaddr' call, and do a lookup. This
1162 * would avoid needing to do system calls if nothing asks.
1163 * However, this is not appropriate for the peer addres on
1164 * datagram sockets */
1171 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1172 * - ensures it is talloc()ed
1176 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1178 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1179 if (!gensec_security->target.principal) {
1180 return NT_STATUS_NO_MEMORY;
1182 return NT_STATUS_OK;
1185 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1187 if (gensec_security->target.principal) {
1188 return gensec_security->target.principal;
1195 register a GENSEC backend.
1197 The 'name' can be later used by other backends to find the operations
1198 structure for this backend.
1200 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1202 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1203 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1204 return NT_STATUS_OK;
1207 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1208 /* its already registered! */
1209 DEBUG(0,("GENSEC backend '%s' already registered\n",
1211 return NT_STATUS_OBJECT_NAME_COLLISION;
1214 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1215 generic_security_ops,
1216 struct gensec_security_ops *,
1217 gensec_num_backends+2);
1218 if (!generic_security_ops) {
1219 return NT_STATUS_NO_MEMORY;
1222 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1223 gensec_num_backends++;
1224 generic_security_ops[gensec_num_backends] = NULL;
1226 DEBUG(3,("GENSEC backend '%s' registered\n",
1229 return NT_STATUS_OK;
1233 return the GENSEC interface version, and the size of some critical types
1234 This can be used by backends to either detect compilation errors, or provide
1235 multiple implementations for different smbd compilation options in one module
1237 const struct gensec_critical_sizes *gensec_interface_version(void)
1239 static const struct gensec_critical_sizes critical_sizes = {
1240 GENSEC_INTERFACE_VERSION,
1241 sizeof(struct gensec_security_ops),
1242 sizeof(struct gensec_security),
1245 return &critical_sizes;
1248 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1249 return (*gs2)->priority - (*gs1)->priority;
1253 initialise the GENSEC subsystem
1255 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1257 static bool initialized = false;
1258 extern NTSTATUS gensec_sasl_init(void);
1259 extern NTSTATUS gensec_krb5_init(void);
1260 extern NTSTATUS gensec_schannel_init(void);
1261 extern NTSTATUS gensec_spnego_init(void);
1262 extern NTSTATUS gensec_gssapi_init(void);
1263 extern NTSTATUS gensec_ntlmssp_init(void);
1265 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1266 init_module_fn *shared_init;
1268 if (initialized) return NT_STATUS_OK;
1271 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1273 run_init_functions(static_init);
1274 run_init_functions(shared_init);
1276 talloc_free(shared_init);
1278 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1280 return NT_STATUS_OK;