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 "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 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 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)
484 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
485 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
487 (*gensec_security)->ops = NULL;
489 ZERO_STRUCT((*gensec_security)->target);
490 ZERO_STRUCT((*gensec_security)->peer_addr);
491 ZERO_STRUCT((*gensec_security)->my_addr);
493 (*gensec_security)->subcontext = false;
494 (*gensec_security)->want_features = 0;
497 ev = event_context_init(*gensec_security);
499 talloc_free(*gensec_security);
500 return NT_STATUS_NO_MEMORY;
504 (*gensec_security)->event_ctx = ev;
505 (*gensec_security)->msg_ctx = msg;
506 (*gensec_security)->lp_ctx = lp_ctx;
512 * Start a GENSEC subcontext, with a copy of the properties of the parent
513 * @param mem_ctx The parent TALLOC memory context.
514 * @param parent The parent GENSEC context
515 * @param gensec_security Returned GENSEC context pointer.
516 * @note Used by SPNEGO in particular, for the actual implementation mechanism
519 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
520 struct gensec_security *parent,
521 struct gensec_security **gensec_security)
523 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
524 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
526 (**gensec_security) = *parent;
527 (*gensec_security)->ops = NULL;
528 (*gensec_security)->private_data = NULL;
530 (*gensec_security)->subcontext = true;
531 (*gensec_security)->event_ctx = parent->event_ctx;
532 (*gensec_security)->msg_ctx = parent->msg_ctx;
533 (*gensec_security)->lp_ctx = parent->lp_ctx;
539 Start the GENSEC system, in client mode, returning a context pointer.
540 @param mem_ctx The parent TALLOC memory context.
541 @param gensec_security Returned GENSEC context pointer.
542 @note The mem_ctx is only a parent and may be NULL.
544 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
545 struct gensec_security **gensec_security,
546 struct event_context *ev,
547 struct loadparm_context *lp_ctx)
550 struct event_context *new_ev = NULL;
553 new_ev = event_context_init(mem_ctx);
554 NT_STATUS_HAVE_NO_MEMORY(new_ev);
558 status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
559 if (!NT_STATUS_IS_OK(status)) {
563 talloc_steal((*gensec_security), new_ev);
564 (*gensec_security)->gensec_role = GENSEC_CLIENT;
570 Start the GENSEC system, in server mode, returning a context pointer.
571 @param mem_ctx The parent TALLOC memory context.
572 @param gensec_security Returned GENSEC context pointer.
573 @note The mem_ctx is only a parent and may be NULL.
575 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
576 struct event_context *ev,
577 struct loadparm_context *lp_ctx,
578 struct messaging_context *msg,
579 struct gensec_security **gensec_security)
584 DEBUG(0,("gensec_server_start: no event context given!\n"));
585 return NT_STATUS_INTERNAL_ERROR;
589 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
590 return NT_STATUS_INTERNAL_ERROR;
593 status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
594 if (!NT_STATUS_IS_OK(status)) {
597 (*gensec_security)->gensec_role = GENSEC_SERVER;
602 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
605 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
606 gensec_security->subcontext ? "sub" : "",
607 gensec_security->ops->name));
608 switch (gensec_security->gensec_role) {
610 if (gensec_security->ops->client_start) {
611 status = gensec_security->ops->client_start(gensec_security);
612 if (!NT_STATUS_IS_OK(status)) {
613 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
614 gensec_security->ops->name, nt_errstr(status)));
620 if (gensec_security->ops->server_start) {
621 status = gensec_security->ops->server_start(gensec_security);
622 if (!NT_STATUS_IS_OK(status)) {
623 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
624 gensec_security->ops->name, nt_errstr(status)));
630 return NT_STATUS_INVALID_PARAMETER;
634 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
635 * @param gensec_security GENSEC context pointer.
636 * @param auth_type DCERPC auth type
637 * @param auth_level DCERPC auth level
640 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
641 uint8_t auth_type, uint8_t auth_level)
643 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
644 if (!gensec_security->ops) {
645 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
646 return NT_STATUS_INVALID_PARAMETER;
648 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
649 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
650 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
651 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
652 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
653 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
654 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
655 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
656 /* Default features */
658 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
660 return NT_STATUS_INVALID_PARAMETER;
663 return gensec_start_mech(gensec_security);
666 const char *gensec_get_name_by_authtype(uint8_t authtype)
668 const struct gensec_security_ops *ops;
669 ops = gensec_security_by_authtype(NULL, authtype);
677 const char *gensec_get_name_by_oid(const char *oid_string)
679 const struct gensec_security_ops *ops;
680 ops = gensec_security_by_oid(NULL, oid_string);
689 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
693 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
694 const struct gensec_security_ops *ops)
696 gensec_security->ops = ops;
697 return gensec_start_mech(gensec_security);
701 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
703 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
704 * well-known #define to hook it in.
707 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
708 const char *mech_oid)
710 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
711 if (!gensec_security->ops) {
712 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
713 return NT_STATUS_INVALID_PARAMETER;
715 return gensec_start_mech(gensec_security);
719 * Start a GENSEC sub-mechanism by a well know SASL name
723 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
724 const char *sasl_name)
726 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
727 if (!gensec_security->ops) {
728 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
729 return NT_STATUS_INVALID_PARAMETER;
731 return gensec_start_mech(gensec_security);
735 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
739 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
740 const char **sasl_names)
742 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
743 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
744 const struct gensec_security_ops **ops;
747 return NT_STATUS_NO_MEMORY;
749 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
751 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
752 str_list_join(mem_ctx,
754 talloc_free(mem_ctx);
755 return NT_STATUS_INVALID_PARAMETER;
757 for (i=0; ops[i]; i++) {
758 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
759 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
763 talloc_free(mem_ctx);
768 * Start a GENSEC sub-mechanism by an internal name
772 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
775 gensec_security->ops = gensec_security_by_name(gensec_security, name);
776 if (!gensec_security->ops) {
777 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
778 return NT_STATUS_INVALID_PARAMETER;
780 return gensec_start_mech(gensec_security);
784 wrappers for the gensec function pointers
786 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
788 uint8_t *data, size_t length,
789 const uint8_t *whole_pdu, size_t pdu_length,
790 const DATA_BLOB *sig)
792 if (!gensec_security->ops->unseal_packet) {
793 return NT_STATUS_NOT_IMPLEMENTED;
795 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
796 return NT_STATUS_INVALID_PARAMETER;
799 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
801 whole_pdu, pdu_length,
805 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
807 const uint8_t *data, size_t length,
808 const uint8_t *whole_pdu, size_t pdu_length,
809 const DATA_BLOB *sig)
811 if (!gensec_security->ops->check_packet) {
812 return NT_STATUS_NOT_IMPLEMENTED;
814 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
815 return NT_STATUS_INVALID_PARAMETER;
818 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
821 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
823 uint8_t *data, size_t length,
824 const uint8_t *whole_pdu, size_t pdu_length,
827 if (!gensec_security->ops->seal_packet) {
828 return NT_STATUS_NOT_IMPLEMENTED;
830 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
831 return NT_STATUS_INVALID_PARAMETER;
834 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
837 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
839 const uint8_t *data, size_t length,
840 const uint8_t *whole_pdu, size_t pdu_length,
843 if (!gensec_security->ops->sign_packet) {
844 return NT_STATUS_NOT_IMPLEMENTED;
846 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
847 return NT_STATUS_INVALID_PARAMETER;
850 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
853 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
855 if (!gensec_security->ops->sig_size) {
858 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
862 return gensec_security->ops->sig_size(gensec_security, data_size);
865 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
867 if (!gensec_security->ops->max_wrapped_size) {
871 return gensec_security->ops->max_wrapped_size(gensec_security);
874 size_t gensec_max_input_size(struct gensec_security *gensec_security)
876 if (!gensec_security->ops->max_input_size) {
877 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
880 return gensec_security->ops->max_input_size(gensec_security);
883 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
888 if (!gensec_security->ops->wrap) {
889 return NT_STATUS_NOT_IMPLEMENTED;
891 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
894 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
899 if (!gensec_security->ops->unwrap) {
900 return NT_STATUS_NOT_IMPLEMENTED;
902 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
905 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
906 DATA_BLOB *session_key)
908 if (!gensec_security->ops->session_key) {
909 return NT_STATUS_NOT_IMPLEMENTED;
911 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
912 return NT_STATUS_NO_USER_SESSION_KEY;
915 return gensec_security->ops->session_key(gensec_security, session_key);
919 * Return the credentials of a logged on user, including session keys
922 * Only valid after a successful authentication
924 * May only be called once per authentication.
928 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
929 struct auth_session_info **session_info)
931 if (!gensec_security->ops->session_info) {
932 return NT_STATUS_NOT_IMPLEMENTED;
934 return gensec_security->ops->session_info(gensec_security, session_info);
938 * Next state function for the GENSEC state machine
940 * @param gensec_security GENSEC State
941 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
942 * @param in The request, as a DATA_BLOB
943 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
944 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
945 * or NT_STATUS_OK if the user is authenticated.
948 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
949 const DATA_BLOB in, DATA_BLOB *out)
951 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
954 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
955 struct timeval t, void *ptr)
957 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
958 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
959 req->callback.fn(req, req->callback.private_data);
963 * Next state function for the GENSEC state machine async version
965 * @param gensec_security GENSEC State
966 * @param in The request, as a DATA_BLOB
967 * @param callback The function that will be called when the operation is
968 * finished, it should return gensec_update_recv() to get output
969 * @param private_data A private pointer that will be passed to the callback function
972 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
973 void (*callback)(struct gensec_update_request *req, void *private_data),
976 struct gensec_update_request *req = NULL;
977 struct timed_event *te = NULL;
979 req = talloc(gensec_security, struct gensec_update_request);
980 if (!req) goto failed;
981 req->gensec_security = gensec_security;
983 req->out = data_blob(NULL, 0);
984 req->callback.fn = callback;
985 req->callback.private_data = private_data;
987 te = event_add_timed(gensec_security->event_ctx, req,
989 gensec_update_async_timed_handler, req);
990 if (!te) goto failed;
996 callback(NULL, private_data);
1000 * Next state function for the GENSEC state machine
1002 * @param req GENSEC update request state
1003 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1004 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1005 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1006 * or NT_STATUS_OK if the user is authenticated.
1008 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1012 NT_STATUS_HAVE_NO_MEMORY(req);
1015 talloc_steal(out_mem_ctx, out->data);
1016 status = req->status;
1023 * Set the requirement for a certain feature on the connection
1027 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1030 gensec_security->want_features |= feature;
1034 * Check the requirement for a certain feature on the connection
1038 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1041 if (!gensec_security->ops->have_feature) {
1045 /* We might 'have' features that we don't 'want', because the
1046 * other end demanded them, or we can't neotiate them off */
1047 return gensec_security->ops->have_feature(gensec_security, feature);
1051 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1055 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1057 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1058 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1059 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1060 return NT_STATUS_OK;
1064 * Return the credentials structure associated with a GENSEC context
1068 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1070 if (!gensec_security) {
1073 return gensec_security->credentials;
1077 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1081 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1083 gensec_security->target.service = talloc_strdup(gensec_security, service);
1084 if (!gensec_security->target.service) {
1085 return NT_STATUS_NO_MEMORY;
1087 return NT_STATUS_OK;
1090 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1092 if (gensec_security->target.service) {
1093 return gensec_security->target.service;
1100 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1104 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1106 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1107 if (hostname && !gensec_security->target.hostname) {
1108 return NT_STATUS_NO_MEMORY;
1110 return NT_STATUS_OK;
1113 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1115 /* We allow the target hostname to be overriden for testing purposes */
1116 const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1117 if (target_hostname) {
1118 return target_hostname;
1121 if (gensec_security->target.hostname) {
1122 return gensec_security->target.hostname;
1125 /* We could add use the 'set sockaddr' call, and do a reverse
1126 * lookup, but this would be both insecure (compromising the
1127 * way kerberos works) and add DNS timeouts */
1132 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1134 * This is so that kerberos can include these addresses in
1135 * cryptographic tokens, to avoid certain attacks.
1138 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1140 gensec_security->my_addr = my_addr;
1141 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1142 return NT_STATUS_NO_MEMORY;
1144 return NT_STATUS_OK;
1147 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1149 gensec_security->peer_addr = peer_addr;
1150 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1151 return NT_STATUS_NO_MEMORY;
1153 return NT_STATUS_OK;
1156 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1158 if (gensec_security->my_addr) {
1159 return gensec_security->my_addr;
1162 /* We could add a 'set sockaddr' call, and do a lookup. This
1163 * would avoid needing to do system calls if nothing asks. */
1167 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1169 if (gensec_security->peer_addr) {
1170 return gensec_security->peer_addr;
1173 /* We could add a 'set sockaddr' call, and do a lookup. This
1174 * would avoid needing to do system calls if nothing asks.
1175 * However, this is not appropriate for the peer addres on
1176 * datagram sockets */
1183 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1184 * - ensures it is talloc()ed
1188 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1190 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1191 if (!gensec_security->target.principal) {
1192 return NT_STATUS_NO_MEMORY;
1194 return NT_STATUS_OK;
1197 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1199 if (gensec_security->target.principal) {
1200 return gensec_security->target.principal;
1207 register a GENSEC backend.
1209 The 'name' can be later used by other backends to find the operations
1210 structure for this backend.
1212 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1214 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1215 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1216 return NT_STATUS_OK;
1219 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1220 /* its already registered! */
1221 DEBUG(0,("GENSEC backend '%s' already registered\n",
1223 return NT_STATUS_OBJECT_NAME_COLLISION;
1226 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1227 generic_security_ops,
1228 struct gensec_security_ops *,
1229 gensec_num_backends+2);
1230 if (!generic_security_ops) {
1231 return NT_STATUS_NO_MEMORY;
1234 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1235 gensec_num_backends++;
1236 generic_security_ops[gensec_num_backends] = NULL;
1238 DEBUG(3,("GENSEC backend '%s' registered\n",
1241 return NT_STATUS_OK;
1245 return the GENSEC interface version, and the size of some critical types
1246 This can be used by backends to either detect compilation errors, or provide
1247 multiple implementations for different smbd compilation options in one module
1249 const struct gensec_critical_sizes *gensec_interface_version(void)
1251 static const struct gensec_critical_sizes critical_sizes = {
1252 GENSEC_INTERFACE_VERSION,
1253 sizeof(struct gensec_security_ops),
1254 sizeof(struct gensec_security),
1257 return &critical_sizes;
1260 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1261 return (*gs2)->priority - (*gs1)->priority;
1265 initialise the GENSEC subsystem
1267 NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1269 static bool initialized = false;
1271 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1272 init_module_fn *shared_init;
1274 if (initialized) return NT_STATUS_OK;
1277 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1279 run_init_functions(static_init);
1280 run_init_functions(shared_init);
1282 talloc_free(shared_init);
1284 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1286 return NT_STATUS_OK;