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"
27 #include "librpc/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_proto.h"
31 #include "param/param.h"
33 /* the list of currently registered GENSEC backends */
34 static struct gensec_security_ops **generic_security_ops;
35 static int gensec_num_backends;
37 /* Return all the registered mechs. Don't modify the return pointer,
38 * but you may talloc_reference it if convient */
39 _PUBLIC_ struct gensec_security_ops **gensec_security_all(void)
41 return generic_security_ops;
44 /* Sometimes we want to force only kerberos, sometimes we want to
45 * force it's avoidance. The old list could be either
46 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
47 * an existing list we have trimmed down) */
49 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
50 struct gensec_security_ops **old_gensec_list,
51 struct cli_credentials *creds)
53 struct gensec_security_ops **new_gensec_list;
54 int i, j, num_mechs_in;
55 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
58 use_kerberos = cli_credentials_get_kerberos_state(creds);
61 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
62 if (!talloc_reference(mem_ctx, old_gensec_list)) {
65 return old_gensec_list;
68 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
72 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
73 if (!new_gensec_list) {
78 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
80 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
81 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
82 new_gensec_list[j] = old_gensec_list[i];
87 switch (use_kerberos) {
88 case CRED_DONT_USE_KERBEROS:
89 if (old_gensec_list[i]->kerberos == false) {
90 new_gensec_list[j] = old_gensec_list[i];
94 case CRED_MUST_USE_KERBEROS:
95 if (old_gensec_list[i]->kerberos == true) {
96 new_gensec_list[j] = old_gensec_list[i];
101 /* Can't happen or invalid parameter */
105 new_gensec_list[j] = NULL;
107 return new_gensec_list;
110 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
113 struct gensec_security_ops **backends;
114 backends = gensec_security_all();
115 if (!gensec_security) {
116 if (!talloc_reference(mem_ctx, backends)) {
121 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
123 if (!talloc_reference(mem_ctx, backends)) {
128 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
132 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
136 struct gensec_security_ops **backends;
137 const struct gensec_security_ops *backend;
138 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
142 backends = gensec_security_mechs(gensec_security, mem_ctx);
143 for (i=0; backends && backends[i]; i++) {
144 if (backends[i]->auth_type == auth_type) {
145 backend = backends[i];
146 talloc_free(mem_ctx);
150 talloc_free(mem_ctx);
155 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
156 const char *oid_string)
159 struct gensec_security_ops **backends;
160 const struct gensec_security_ops *backend;
161 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
165 backends = gensec_security_mechs(gensec_security, mem_ctx);
166 for (i=0; backends && backends[i]; i++) {
167 if (backends[i]->oid) {
168 for (j=0; backends[i]->oid[j]; j++) {
169 if (backends[i]->oid[j] &&
170 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
171 backend = backends[i];
172 talloc_free(mem_ctx);
178 talloc_free(mem_ctx);
183 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
184 const char *sasl_name)
187 struct gensec_security_ops **backends;
188 const struct gensec_security_ops *backend;
189 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
193 backends = gensec_security_mechs(gensec_security, mem_ctx);
194 for (i=0; backends && backends[i]; i++) {
195 if (backends[i]->sasl_name
196 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
197 backend = backends[i];
198 talloc_free(mem_ctx);
202 talloc_free(mem_ctx);
207 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
211 struct gensec_security_ops **backends;
212 const struct gensec_security_ops *backend;
213 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
217 backends = gensec_security_mechs(gensec_security, mem_ctx);
218 for (i=0; backends && backends[i]; i++) {
219 if (backends[i]->name
220 && (strcmp(backends[i]->name, name) == 0)) {
221 backend = backends[i];
222 talloc_free(mem_ctx);
226 talloc_free(mem_ctx);
231 * Return a unique list of security subsystems from those specified in
232 * the list of SASL names.
234 * Use the list of enabled GENSEC mechanisms from the credentials
235 * attached to the gensec_security, and return in our preferred order.
238 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
240 const char **sasl_names)
242 const struct gensec_security_ops **backends_out;
243 struct gensec_security_ops **backends;
245 int num_backends_out = 0;
251 backends = gensec_security_mechs(gensec_security, mem_ctx);
253 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
257 backends_out[0] = NULL;
259 /* Find backends in our preferred order, by walking our list,
260 * then looking in the supplied list */
261 for (i=0; backends && backends[i]; i++) {
262 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
263 if (!backends[i]->sasl_name ||
264 !(strcmp(backends[i]->sasl_name,
265 sasl_names[sasl_idx]) == 0)) {
269 for (k=0; backends_out[k]; k++) {
270 if (backends_out[k] == backends[i]) {
275 if (k < num_backends_out) {
276 /* already in there */
280 backends_out = talloc_realloc(mem_ctx, backends_out,
281 const struct gensec_security_ops *,
282 num_backends_out + 2);
287 backends_out[num_backends_out] = backends[i];
289 backends_out[num_backends_out] = NULL;
296 * Return a unique list of security subsystems from those specified in
297 * the OID list. That is, where two OIDs refer to the same module,
298 * return that module only once.
300 * Use the list of enabled GENSEC mechanisms from the credentials
301 * attached to the gensec_security, and return in our preferred order.
304 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
306 const char **oid_strings,
309 struct gensec_security_ops_wrapper *backends_out;
310 struct gensec_security_ops **backends;
311 int i, j, k, oid_idx;
312 int num_backends_out = 0;
318 backends = gensec_security_mechs(gensec_security, gensec_security);
320 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
324 backends_out[0].op = NULL;
325 backends_out[0].oid = NULL;
327 /* Find backends in our preferred order, by walking our list,
328 * then looking in the supplied list */
329 for (i=0; backends && backends[i]; i++) {
330 if (!backends[i]->oid) {
333 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
334 if (strcmp(oid_strings[oid_idx], skip) == 0) {
338 for (j=0; backends[i]->oid[j]; j++) {
339 if (!backends[i]->oid[j] ||
340 !(strcmp(backends[i]->oid[j],
341 oid_strings[oid_idx]) == 0)) {
345 for (k=0; backends_out[k].op; k++) {
346 if (backends_out[k].op == backends[i]) {
351 if (k < num_backends_out) {
352 /* already in there */
356 backends_out = talloc_realloc(mem_ctx, backends_out,
357 struct gensec_security_ops_wrapper,
358 num_backends_out + 2);
363 backends_out[num_backends_out].op = backends[i];
364 backends_out[num_backends_out].oid = backends[i]->oid[j];
366 backends_out[num_backends_out].op = NULL;
367 backends_out[num_backends_out].oid = NULL;
375 * Return OIDS from the security subsystems listed
378 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
379 struct gensec_security_ops **ops,
385 const char **oid_list;
389 oid_list = talloc_array(mem_ctx, const char *, 1);
394 for (i=0; ops && ops[i]; i++) {
399 for (k = 0; ops[i]->oid[k]; k++) {
400 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
402 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
406 oid_list[j] = ops[i]->oid[k];
417 * Return OIDS from the security subsystems listed
420 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
421 const struct gensec_security_ops_wrapper *wops)
426 const char **oid_list;
430 oid_list = talloc_array(mem_ctx, const char *, 1);
435 for (i=0; wops[i].op; i++) {
436 if (!wops[i].op->oid) {
440 for (k = 0; wops[i].op->oid[k]; k++) {
441 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
445 oid_list[j] = wops[i].op->oid[k];
455 * Return all the security subsystems currently enabled on a GENSEC context.
457 * This is taken from a list attached to the cli_credentials, and
458 * skips the OID in 'skip'. (Typically the SPNEGO OID)
462 const char **gensec_security_oids(struct gensec_security *gensec_security,
466 struct gensec_security_ops **ops
467 = gensec_security_mechs(gensec_security, mem_ctx);
468 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
474 Start the GENSEC system, returning a context pointer.
475 @param mem_ctx The parent TALLOC memory context.
476 @param gensec_security Returned GENSEC context pointer.
477 @note The mem_ctx is only a parent and may be NULL.
479 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
480 struct event_context *ev,
481 struct loadparm_context *lp_ctx,
482 struct messaging_context *msg,
483 struct gensec_security **gensec_security)
485 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
486 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
488 (*gensec_security)->ops = NULL;
490 ZERO_STRUCT((*gensec_security)->target);
491 ZERO_STRUCT((*gensec_security)->peer_addr);
492 ZERO_STRUCT((*gensec_security)->my_addr);
494 (*gensec_security)->subcontext = false;
495 (*gensec_security)->want_features = 0;
498 ev = event_context_init(*gensec_security);
500 talloc_free(*gensec_security);
501 return NT_STATUS_NO_MEMORY;
505 (*gensec_security)->event_ctx = ev;
506 (*gensec_security)->msg_ctx = msg;
507 (*gensec_security)->lp_ctx = lp_ctx;
513 * Start a GENSEC subcontext, with a copy of the properties of the parent
514 * @param mem_ctx The parent TALLOC memory context.
515 * @param parent The parent GENSEC context
516 * @param gensec_security Returned GENSEC context pointer.
517 * @note Used by SPNEGO in particular, for the actual implementation mechanism
520 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
521 struct gensec_security *parent,
522 struct gensec_security **gensec_security)
524 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
525 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
527 (**gensec_security) = *parent;
528 (*gensec_security)->ops = NULL;
529 (*gensec_security)->private_data = NULL;
531 (*gensec_security)->subcontext = true;
532 (*gensec_security)->event_ctx = parent->event_ctx;
533 (*gensec_security)->msg_ctx = parent->msg_ctx;
534 (*gensec_security)->lp_ctx = parent->lp_ctx;
540 Start the GENSEC system, in client mode, returning a context pointer.
541 @param mem_ctx The parent TALLOC memory context.
542 @param gensec_security Returned GENSEC context pointer.
543 @note The mem_ctx is only a parent and may be NULL.
545 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
546 struct gensec_security **gensec_security,
547 struct event_context *ev,
548 struct loadparm_context *lp_ctx)
551 struct event_context *new_ev = NULL;
554 new_ev = event_context_init(mem_ctx);
555 NT_STATUS_HAVE_NO_MEMORY(new_ev);
559 status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
560 if (!NT_STATUS_IS_OK(status)) {
564 talloc_steal((*gensec_security), new_ev);
565 (*gensec_security)->gensec_role = GENSEC_CLIENT;
571 Start the GENSEC system, in server mode, returning a context pointer.
572 @param mem_ctx The parent TALLOC memory context.
573 @param gensec_security Returned GENSEC context pointer.
574 @note The mem_ctx is only a parent and may be NULL.
576 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
577 struct event_context *ev,
578 struct loadparm_context *lp_ctx,
579 struct messaging_context *msg,
580 struct gensec_security **gensec_security)
585 DEBUG(0,("gensec_server_start: no event context given!\n"));
586 return NT_STATUS_INTERNAL_ERROR;
590 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
591 return NT_STATUS_INTERNAL_ERROR;
594 status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
595 if (!NT_STATUS_IS_OK(status)) {
598 (*gensec_security)->gensec_role = GENSEC_SERVER;
603 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
606 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
607 gensec_security->subcontext ? "sub" : "",
608 gensec_security->ops->name));
609 switch (gensec_security->gensec_role) {
611 if (gensec_security->ops->client_start) {
612 status = gensec_security->ops->client_start(gensec_security);
613 if (!NT_STATUS_IS_OK(status)) {
614 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
615 gensec_security->ops->name, nt_errstr(status)));
621 if (gensec_security->ops->server_start) {
622 status = gensec_security->ops->server_start(gensec_security);
623 if (!NT_STATUS_IS_OK(status)) {
624 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
625 gensec_security->ops->name, nt_errstr(status)));
631 return NT_STATUS_INVALID_PARAMETER;
635 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
636 * @param gensec_security GENSEC context pointer.
637 * @param auth_type DCERPC auth type
638 * @param auth_level DCERPC auth level
641 _PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
642 uint8_t auth_type, uint8_t auth_level)
644 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
645 if (!gensec_security->ops) {
646 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
647 return NT_STATUS_INVALID_PARAMETER;
649 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
650 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
651 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
652 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
653 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
654 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
655 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
656 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
657 /* Default features */
659 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
661 return NT_STATUS_INVALID_PARAMETER;
664 return gensec_start_mech(gensec_security);
667 _PUBLIC_ const char *gensec_get_name_by_authtype(uint8_t authtype)
669 const struct gensec_security_ops *ops;
670 ops = gensec_security_by_authtype(NULL, authtype);
678 _PUBLIC_ const char *gensec_get_name_by_oid(const char *oid_string)
680 const struct gensec_security_ops *ops;
681 ops = gensec_security_by_oid(NULL, oid_string);
690 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
694 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
695 const struct gensec_security_ops *ops)
697 gensec_security->ops = ops;
698 return gensec_start_mech(gensec_security);
702 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
704 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
705 * well-known #define to hook it in.
708 _PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
709 const char *mech_oid)
711 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
712 if (!gensec_security->ops) {
713 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
714 return NT_STATUS_INVALID_PARAMETER;
716 return gensec_start_mech(gensec_security);
720 * Start a GENSEC sub-mechanism by a well know SASL name
724 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
725 const char *sasl_name)
727 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
728 if (!gensec_security->ops) {
729 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
730 return NT_STATUS_INVALID_PARAMETER;
732 return gensec_start_mech(gensec_security);
736 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
740 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
741 const char **sasl_names)
743 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
744 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
745 const struct gensec_security_ops **ops;
748 return NT_STATUS_NO_MEMORY;
750 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
752 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
753 str_list_join(mem_ctx,
755 talloc_free(mem_ctx);
756 return NT_STATUS_INVALID_PARAMETER;
758 for (i=0; ops[i]; i++) {
759 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
760 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
764 talloc_free(mem_ctx);
769 * Start a GENSEC sub-mechanism by an internal name
773 _PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
776 gensec_security->ops = gensec_security_by_name(gensec_security, name);
777 if (!gensec_security->ops) {
778 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
779 return NT_STATUS_INVALID_PARAMETER;
781 return gensec_start_mech(gensec_security);
785 wrappers for the gensec function pointers
787 _PUBLIC_ NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
789 uint8_t *data, size_t length,
790 const uint8_t *whole_pdu, size_t pdu_length,
791 const DATA_BLOB *sig)
793 if (!gensec_security->ops->unseal_packet) {
794 return NT_STATUS_NOT_IMPLEMENTED;
796 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
797 return NT_STATUS_INVALID_PARAMETER;
800 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
802 whole_pdu, pdu_length,
806 _PUBLIC_ NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
808 const uint8_t *data, size_t length,
809 const uint8_t *whole_pdu, size_t pdu_length,
810 const DATA_BLOB *sig)
812 if (!gensec_security->ops->check_packet) {
813 return NT_STATUS_NOT_IMPLEMENTED;
815 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
816 return NT_STATUS_INVALID_PARAMETER;
819 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
822 _PUBLIC_ NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
824 uint8_t *data, size_t length,
825 const uint8_t *whole_pdu, size_t pdu_length,
828 if (!gensec_security->ops->seal_packet) {
829 return NT_STATUS_NOT_IMPLEMENTED;
831 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
832 return NT_STATUS_INVALID_PARAMETER;
835 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
838 _PUBLIC_ NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
840 const uint8_t *data, size_t length,
841 const uint8_t *whole_pdu, size_t pdu_length,
844 if (!gensec_security->ops->sign_packet) {
845 return NT_STATUS_NOT_IMPLEMENTED;
847 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
848 return NT_STATUS_INVALID_PARAMETER;
851 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
854 _PUBLIC_ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
856 if (!gensec_security->ops->sig_size) {
859 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
863 return gensec_security->ops->sig_size(gensec_security, data_size);
866 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
868 if (!gensec_security->ops->max_wrapped_size) {
872 return gensec_security->ops->max_wrapped_size(gensec_security);
875 size_t gensec_max_input_size(struct gensec_security *gensec_security)
877 if (!gensec_security->ops->max_input_size) {
878 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
881 return gensec_security->ops->max_input_size(gensec_security);
884 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
889 if (!gensec_security->ops->wrap) {
890 return NT_STATUS_NOT_IMPLEMENTED;
892 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
895 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
900 if (!gensec_security->ops->unwrap) {
901 return NT_STATUS_NOT_IMPLEMENTED;
903 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
906 _PUBLIC_ NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
907 DATA_BLOB *session_key)
909 if (!gensec_security->ops->session_key) {
910 return NT_STATUS_NOT_IMPLEMENTED;
912 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
913 return NT_STATUS_NO_USER_SESSION_KEY;
916 return gensec_security->ops->session_key(gensec_security, session_key);
920 * Return the credentials of a logged on user, including session keys
923 * Only valid after a successful authentication
925 * May only be called once per authentication.
929 _PUBLIC_ NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
930 struct auth_session_info **session_info)
932 if (!gensec_security->ops->session_info) {
933 return NT_STATUS_NOT_IMPLEMENTED;
935 return gensec_security->ops->session_info(gensec_security, session_info);
939 * Next state function for the GENSEC state machine
941 * @param gensec_security GENSEC State
942 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
943 * @param in The request, as a DATA_BLOB
944 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
945 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
946 * or NT_STATUS_OK if the user is authenticated.
949 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
950 const DATA_BLOB in, DATA_BLOB *out)
952 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
955 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
956 struct timeval t, void *ptr)
958 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
959 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
960 req->callback.fn(req, req->callback.private_data);
964 * Next state function for the GENSEC state machine async version
966 * @param gensec_security GENSEC State
967 * @param in The request, as a DATA_BLOB
968 * @param callback The function that will be called when the operation is
969 * finished, it should return gensec_update_recv() to get output
970 * @param private_data A private pointer that will be passed to the callback function
973 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
974 void (*callback)(struct gensec_update_request *req, void *private_data),
977 struct gensec_update_request *req = NULL;
978 struct timed_event *te = NULL;
980 req = talloc(gensec_security, struct gensec_update_request);
981 if (!req) goto failed;
982 req->gensec_security = gensec_security;
984 req->out = data_blob(NULL, 0);
985 req->callback.fn = callback;
986 req->callback.private_data = private_data;
988 te = event_add_timed(gensec_security->event_ctx, req,
990 gensec_update_async_timed_handler, req);
991 if (!te) goto failed;
997 callback(NULL, private_data);
1001 * Next state function for the GENSEC state machine
1003 * @param req GENSEC update request state
1004 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1005 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1006 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1007 * or NT_STATUS_OK if the user is authenticated.
1009 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1013 NT_STATUS_HAVE_NO_MEMORY(req);
1016 talloc_steal(out_mem_ctx, out->data);
1017 status = req->status;
1024 * Set the requirement for a certain feature on the connection
1028 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1031 gensec_security->want_features |= feature;
1035 * Check the requirement for a certain feature on the connection
1039 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1042 if (!gensec_security->ops->have_feature) {
1046 /* We might 'have' features that we don't 'want', because the
1047 * other end demanded them, or we can't neotiate them off */
1048 return gensec_security->ops->have_feature(gensec_security, feature);
1052 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1056 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1058 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1059 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1060 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1061 return NT_STATUS_OK;
1065 * Return the credentials structure associated with a GENSEC context
1069 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1071 if (!gensec_security) {
1074 return gensec_security->credentials;
1078 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1082 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1084 gensec_security->target.service = talloc_strdup(gensec_security, service);
1085 if (!gensec_security->target.service) {
1086 return NT_STATUS_NO_MEMORY;
1088 return NT_STATUS_OK;
1091 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1093 if (gensec_security->target.service) {
1094 return gensec_security->target.service;
1101 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1105 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1107 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1108 if (hostname && !gensec_security->target.hostname) {
1109 return NT_STATUS_NO_MEMORY;
1111 return NT_STATUS_OK;
1114 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1116 /* We allow the target hostname to be overriden for testing purposes */
1117 const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1118 if (target_hostname) {
1119 return target_hostname;
1122 if (gensec_security->target.hostname) {
1123 return gensec_security->target.hostname;
1126 /* We could add use the 'set sockaddr' call, and do a reverse
1127 * lookup, but this would be both insecure (compromising the
1128 * way kerberos works) and add DNS timeouts */
1133 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1135 * This is so that kerberos can include these addresses in
1136 * cryptographic tokens, to avoid certain attacks.
1139 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1141 gensec_security->my_addr = my_addr;
1142 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1143 return NT_STATUS_NO_MEMORY;
1145 return NT_STATUS_OK;
1148 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1150 gensec_security->peer_addr = peer_addr;
1151 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1152 return NT_STATUS_NO_MEMORY;
1154 return NT_STATUS_OK;
1157 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1159 if (gensec_security->my_addr) {
1160 return gensec_security->my_addr;
1163 /* We could add a 'set sockaddr' call, and do a lookup. This
1164 * would avoid needing to do system calls if nothing asks. */
1168 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1170 if (gensec_security->peer_addr) {
1171 return gensec_security->peer_addr;
1174 /* We could add a 'set sockaddr' call, and do a lookup. This
1175 * would avoid needing to do system calls if nothing asks.
1176 * However, this is not appropriate for the peer addres on
1177 * datagram sockets */
1184 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1185 * - ensures it is talloc()ed
1189 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1191 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1192 if (!gensec_security->target.principal) {
1193 return NT_STATUS_NO_MEMORY;
1195 return NT_STATUS_OK;
1198 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1200 if (gensec_security->target.principal) {
1201 return gensec_security->target.principal;
1208 register a GENSEC backend.
1210 The 'name' can be later used by other backends to find the operations
1211 structure for this backend.
1213 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1215 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1216 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1217 return NT_STATUS_OK;
1220 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1221 /* its already registered! */
1222 DEBUG(0,("GENSEC backend '%s' already registered\n",
1224 return NT_STATUS_OBJECT_NAME_COLLISION;
1227 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1228 generic_security_ops,
1229 struct gensec_security_ops *,
1230 gensec_num_backends+2);
1231 if (!generic_security_ops) {
1232 return NT_STATUS_NO_MEMORY;
1235 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1236 gensec_num_backends++;
1237 generic_security_ops[gensec_num_backends] = NULL;
1239 DEBUG(3,("GENSEC backend '%s' registered\n",
1242 return NT_STATUS_OK;
1246 return the GENSEC interface version, and the size of some critical types
1247 This can be used by backends to either detect compilation errors, or provide
1248 multiple implementations for different smbd compilation options in one module
1250 const struct gensec_critical_sizes *gensec_interface_version(void)
1252 static const struct gensec_critical_sizes critical_sizes = {
1253 GENSEC_INTERFACE_VERSION,
1254 sizeof(struct gensec_security_ops),
1255 sizeof(struct gensec_security),
1258 return &critical_sizes;
1261 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1262 return (*gs2)->priority - (*gs1)->priority;
1266 initialise the GENSEC subsystem
1268 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1270 static bool initialized = false;
1272 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1273 init_module_fn *shared_init;
1275 if (initialized) return NT_STATUS_OK;
1278 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1280 run_init_functions(static_init);
1281 run_init_functions(shared_init);
1283 talloc_free(shared_init);
1285 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1287 return NT_STATUS_OK;