2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
28 #include "librpc/rpc/dcerpc.h"
30 /* the list of currently registered GENSEC backends */
31 static struct gensec_security_ops **generic_security_ops;
32 static int gensec_num_backends;
34 /* Return all the registered mechs. Don't modify the return pointer,
35 * but you may talloc_reference it if convient */
36 struct gensec_security_ops **gensec_security_all(void)
38 return generic_security_ops;
41 /* Sometimes we want to force only kerberos, sometimes we want to
42 * force it's avoidance. The old list could be either
43 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
44 * an existing list we have trimmed down) */
46 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
47 struct gensec_security_ops **old_gensec_list,
48 enum credentials_use_kerberos use_kerberos)
50 struct gensec_security_ops **new_gensec_list;
51 int i, j, num_mechs_in;
53 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
54 talloc_reference(mem_ctx, old_gensec_list);
55 return old_gensec_list;
58 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
62 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
63 if (!new_gensec_list) {
68 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
70 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
71 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
72 new_gensec_list[j] = old_gensec_list[i];
77 switch (use_kerberos) {
78 case CRED_DONT_USE_KERBEROS:
79 if (old_gensec_list[i]->kerberos == False) {
80 new_gensec_list[j] = old_gensec_list[i];
84 case CRED_MUST_USE_KERBEROS:
85 if (old_gensec_list[i]->kerberos == True) {
86 new_gensec_list[j] = old_gensec_list[i];
90 case CRED_AUTO_USE_KERBEROS:
94 new_gensec_list[j] = NULL;
96 return new_gensec_list;
99 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
102 struct gensec_security_ops **backends;
103 backends = gensec_security_all();
104 if (!gensec_security) {
105 talloc_reference(mem_ctx, backends);
108 enum credentials_use_kerberos use_kerberos;
109 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
111 talloc_reference(mem_ctx, backends);
114 use_kerberos = cli_credentials_get_kerberos_state(creds);
115 return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
119 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
123 struct gensec_security_ops **backends;
124 const struct gensec_security_ops *backend;
125 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
129 backends = gensec_security_mechs(gensec_security, mem_ctx);
130 for (i=0; backends && backends[i]; i++) {
131 if (backends[i]->auth_type == auth_type) {
132 backend = backends[i];
133 talloc_free(mem_ctx);
137 talloc_free(mem_ctx);
142 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
143 const char *oid_string)
146 struct gensec_security_ops **backends;
147 const struct gensec_security_ops *backend;
148 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
152 backends = gensec_security_mechs(gensec_security, mem_ctx);
153 for (i=0; backends && backends[i]; i++) {
154 if (backends[i]->oid) {
155 for (j=0; backends[i]->oid[j]; j++) {
156 if (backends[i]->oid[j] &&
157 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
158 backend = backends[i];
159 talloc_free(mem_ctx);
165 talloc_free(mem_ctx);
170 static const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
171 const char *sasl_name)
174 struct gensec_security_ops **backends;
175 const struct gensec_security_ops *backend;
176 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
180 backends = gensec_security_mechs(gensec_security, mem_ctx);
181 for (i=0; backends && backends[i]; i++) {
182 if (backends[i]->sasl_name
183 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
184 backend = backends[i];
185 talloc_free(mem_ctx);
189 talloc_free(mem_ctx);
194 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
198 struct gensec_security_ops **backends;
199 const struct gensec_security_ops *backend;
200 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
204 backends = gensec_security_mechs(gensec_security, mem_ctx);
205 for (i=0; backends && backends[i]; i++) {
206 if (backends[i]->name
207 && (strcmp(backends[i]->name, name) == 0)) {
208 backend = backends[i];
209 talloc_free(mem_ctx);
213 talloc_free(mem_ctx);
218 * Return a unique list of security subsystems from those specified in
219 * the list of SASL names.
221 * Use the list of enabled GENSEC mechanisms from the credentials
222 * attached to the gensec_security, and return in our preferred order.
225 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
227 const char **sasl_names)
229 const struct gensec_security_ops **backends_out;
230 struct gensec_security_ops **backends;
232 int num_backends_out = 0;
238 backends = gensec_security_mechs(gensec_security, mem_ctx);
240 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
244 backends_out[0] = NULL;
246 /* Find backends in our preferred order, by walking our list,
247 * then looking in the supplied list */
248 for (i=0; backends && backends[i]; i++) {
249 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
250 if (!backends[i]->sasl_name ||
251 !(strcmp(backends[i]->sasl_name,
252 sasl_names[sasl_idx]) == 0)) {
256 for (k=0; backends_out[k]; k++) {
257 if (backends_out[k] == backends[i]) {
262 if (k < num_backends_out) {
263 /* already in there */
267 backends_out = talloc_realloc(mem_ctx, backends_out,
268 const struct gensec_security_ops *,
269 num_backends_out + 2);
274 backends_out[num_backends_out] = backends[i];
276 backends_out[num_backends_out] = NULL;
283 * Return a unique list of security subsystems from those specified in
284 * the OID list. That is, where two OIDs refer to the same module,
285 * return that module only once.
287 * Use the list of enabled GENSEC mechanisms from the credentials
288 * attached to the gensec_security, and return in our preferred order.
291 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
293 const char **oid_strings,
296 struct gensec_security_ops_wrapper *backends_out;
297 struct gensec_security_ops **backends;
298 int i, j, k, oid_idx;
299 int num_backends_out = 0;
305 backends = gensec_security_mechs(gensec_security, gensec_security);
307 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
311 backends_out[0].op = NULL;
312 backends_out[0].oid = NULL;
314 /* Find backends in our preferred order, by walking our list,
315 * then looking in the supplied list */
316 for (i=0; backends && backends[i]; i++) {
317 if (!backends[i]->oid) {
320 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
321 if (strcmp(oid_strings[oid_idx], skip) == 0) {
325 for (j=0; backends[i]->oid[j]; j++) {
326 if (!backends[i]->oid[j] ||
327 !(strcmp(backends[i]->oid[j],
328 oid_strings[oid_idx]) == 0)) {
332 for (k=0; backends_out[k].op; k++) {
333 if (backends_out[k].op == backends[i]) {
338 if (k < num_backends_out) {
339 /* already in there */
343 backends_out = talloc_realloc(mem_ctx, backends_out,
344 struct gensec_security_ops_wrapper,
345 num_backends_out + 2);
350 backends_out[num_backends_out].op = backends[i];
351 backends_out[num_backends_out].oid = backends[i]->oid[j];
353 backends_out[num_backends_out].op = NULL;
354 backends_out[num_backends_out].oid = NULL;
362 * Return OIDS from the security subsystems listed
365 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
366 struct gensec_security_ops **ops,
372 const char **oid_list;
376 oid_list = talloc_array(mem_ctx, const char *, 1);
381 for (i=0; ops && ops[i]; i++) {
386 for (k = 0; ops[i]->oid[k]; k++) {
387 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
389 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
393 oid_list[j] = ops[i]->oid[k];
404 * Return OIDS from the security subsystems listed
407 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
408 const struct gensec_security_ops_wrapper *wops)
413 const char **oid_list;
417 oid_list = talloc_array(mem_ctx, const char *, 1);
422 for (i=0; wops[i].op; i++) {
423 if (!wops[i].op->oid) {
427 for (k = 0; wops[i].op->oid[k]; k++) {
428 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
432 oid_list[j] = wops[i].op->oid[k];
442 * Return all the security subsystems currently enabled on a GENSEC context.
444 * This is taken from a list attached to the cli_credentails, and
445 * skips the OID in 'skip'. (Typically the SPNEGO OID)
449 const char **gensec_security_oids(struct gensec_security *gensec_security,
453 struct gensec_security_ops **ops
454 = gensec_security_mechs(gensec_security, mem_ctx);
455 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
461 Start the GENSEC system, returning a context pointer.
462 @param mem_ctx The parent TALLOC memory context.
463 @param gensec_security Returned GENSEC context pointer.
464 @note The mem_ctx is only a parent and may be NULL.
466 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
467 struct gensec_security **gensec_security,
468 struct event_context *ev)
470 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
471 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
473 (*gensec_security)->ops = NULL;
475 ZERO_STRUCT((*gensec_security)->target);
476 ZERO_STRUCT((*gensec_security)->peer_addr);
477 ZERO_STRUCT((*gensec_security)->my_addr);
479 (*gensec_security)->subcontext = False;
480 (*gensec_security)->want_features = 0;
483 ev = event_context_init(*gensec_security);
485 talloc_free(*gensec_security);
486 return NT_STATUS_NO_MEMORY;
490 (*gensec_security)->event_ctx = ev;
496 * Start a GENSEC subcontext, with a copy of the properties of the parent
497 * @param mem_ctx The parent TALLOC memory context.
498 * @param parent The parent GENSEC context
499 * @param gensec_security Returned GENSEC context pointer.
500 * @note Used by SPNEGO in particular, for the actual implementation mechanism
503 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
504 struct gensec_security *parent,
505 struct gensec_security **gensec_security)
507 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
508 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
510 (**gensec_security) = *parent;
511 (*gensec_security)->ops = NULL;
512 (*gensec_security)->private_data = NULL;
514 (*gensec_security)->subcontext = True;
515 (*gensec_security)->event_ctx = parent->event_ctx;
521 Start the GENSEC system, in client mode, returning a context pointer.
522 @param mem_ctx The parent TALLOC memory context.
523 @param gensec_security Returned GENSEC context pointer.
524 @note The mem_ctx is only a parent and may be NULL.
526 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
527 struct gensec_security **gensec_security,
528 struct event_context *ev)
531 status = gensec_start(mem_ctx, gensec_security, ev);
532 if (!NT_STATUS_IS_OK(status)) {
535 (*gensec_security)->gensec_role = GENSEC_CLIENT;
541 Start the GENSEC system, in server mode, returning a context pointer.
542 @param mem_ctx The parent TALLOC memory context.
543 @param gensec_security Returned GENSEC context pointer.
544 @note The mem_ctx is only a parent and may be NULL.
546 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
547 struct gensec_security **gensec_security,
548 struct event_context *ev)
551 status = gensec_start(mem_ctx, gensec_security, ev);
552 if (!NT_STATUS_IS_OK(status)) {
555 (*gensec_security)->gensec_role = GENSEC_SERVER;
560 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
563 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
564 gensec_security->subcontext ? "sub" : "",
565 gensec_security->ops->name));
566 switch (gensec_security->gensec_role) {
568 if (gensec_security->ops->client_start) {
569 status = gensec_security->ops->client_start(gensec_security);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
572 gensec_security->ops->name, nt_errstr(status)));
578 if (gensec_security->ops->server_start) {
579 status = gensec_security->ops->server_start(gensec_security);
580 if (!NT_STATUS_IS_OK(status)) {
581 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
582 gensec_security->ops->name, nt_errstr(status)));
588 return NT_STATUS_INVALID_PARAMETER;
592 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
593 * @param gensec_security GENSEC context pointer.
594 * @param auth_type DCERPC auth type
595 * @param auth_level DCERPC auth level
598 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
599 uint8_t auth_type, uint8_t auth_level)
601 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
602 if (!gensec_security->ops) {
603 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
604 return NT_STATUS_INVALID_PARAMETER;
606 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
607 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
608 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
609 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
610 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
611 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
612 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
613 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
614 /* Default features */
616 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
618 return NT_STATUS_INVALID_PARAMETER;
621 return gensec_start_mech(gensec_security);
624 const char *gensec_get_name_by_authtype(uint8_t authtype)
626 const struct gensec_security_ops *ops;
627 ops = gensec_security_by_authtype(NULL, authtype);
635 const char *gensec_get_name_by_oid(const char *oid_string)
637 const struct gensec_security_ops *ops;
638 ops = gensec_security_by_oid(NULL, oid_string);
647 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
651 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
652 const struct gensec_security_ops *ops)
654 gensec_security->ops = ops;
655 return gensec_start_mech(gensec_security);
659 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
661 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
662 * well-known #define to hook it in.
665 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
666 const char *mech_oid)
668 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
669 if (!gensec_security->ops) {
670 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
671 return NT_STATUS_INVALID_PARAMETER;
673 return gensec_start_mech(gensec_security);
677 * Start a GENSEC sub-mechanism by a well know SASL name
681 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
682 const char *sasl_name)
684 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
685 if (!gensec_security->ops) {
686 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
687 return NT_STATUS_INVALID_PARAMETER;
689 return gensec_start_mech(gensec_security);
693 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
697 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
698 const char **sasl_names)
701 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
702 const struct gensec_security_ops **ops;
704 return NT_STATUS_NO_MEMORY;
706 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
708 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
709 str_list_join(mem_ctx,
711 talloc_free(mem_ctx);
712 return NT_STATUS_INVALID_PARAMETER;
714 nt_status = gensec_start_mech_by_ops(gensec_security, ops[0]);
715 talloc_free(mem_ctx);
720 * Start a GENSEC sub-mechanism by an internal name
724 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
727 gensec_security->ops = gensec_security_by_name(gensec_security, name);
728 if (!gensec_security->ops) {
729 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
730 return NT_STATUS_INVALID_PARAMETER;
732 return gensec_start_mech(gensec_security);
736 wrappers for the gensec function pointers
738 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
740 uint8_t *data, size_t length,
741 const uint8_t *whole_pdu, size_t pdu_length,
742 const DATA_BLOB *sig)
744 if (!gensec_security->ops->unseal_packet) {
745 return NT_STATUS_NOT_IMPLEMENTED;
747 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
748 return NT_STATUS_INVALID_PARAMETER;
751 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
753 whole_pdu, pdu_length,
757 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
759 const uint8_t *data, size_t length,
760 const uint8_t *whole_pdu, size_t pdu_length,
761 const DATA_BLOB *sig)
763 if (!gensec_security->ops->check_packet) {
764 return NT_STATUS_NOT_IMPLEMENTED;
766 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
767 return NT_STATUS_INVALID_PARAMETER;
770 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
773 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
775 uint8_t *data, size_t length,
776 const uint8_t *whole_pdu, size_t pdu_length,
779 if (!gensec_security->ops->seal_packet) {
780 return NT_STATUS_NOT_IMPLEMENTED;
782 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
783 return NT_STATUS_INVALID_PARAMETER;
786 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
789 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
791 const uint8_t *data, size_t length,
792 const uint8_t *whole_pdu, size_t pdu_length,
795 if (!gensec_security->ops->sign_packet) {
796 return NT_STATUS_NOT_IMPLEMENTED;
798 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
799 return NT_STATUS_INVALID_PARAMETER;
802 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
805 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
807 if (!gensec_security->ops->sig_size) {
810 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
814 return gensec_security->ops->sig_size(gensec_security, data_size);
817 _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
822 if (!gensec_security->ops->wrap) {
823 return NT_STATUS_NOT_IMPLEMENTED;
825 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
828 _PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
833 if (!gensec_security->ops->unwrap) {
834 return NT_STATUS_NOT_IMPLEMENTED;
836 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
839 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
840 DATA_BLOB *session_key)
842 if (!gensec_security->ops->session_key) {
843 return NT_STATUS_NOT_IMPLEMENTED;
845 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
846 return NT_STATUS_NO_USER_SESSION_KEY;
849 return gensec_security->ops->session_key(gensec_security, session_key);
853 * Return the credentials of a logged on user, including session keys
856 * Only valid after a successful authentication
858 * May only be called once per authentication.
862 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
863 struct auth_session_info **session_info)
865 if (!gensec_security->ops->session_info) {
866 return NT_STATUS_NOT_IMPLEMENTED;
868 return gensec_security->ops->session_info(gensec_security, session_info);
872 * Next state function for the GENSEC state machine
874 * @param gensec_security GENSEC State
875 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
876 * @param in The request, as a DATA_BLOB
877 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
878 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
879 * or NT_STATUS_OK if the user is authenticated.
882 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
883 const DATA_BLOB in, DATA_BLOB *out)
885 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
889 * Set the requirement for a certain feature on the connection
893 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
896 gensec_security->want_features |= feature;
900 * Check the requirement for a certain feature on the connection
904 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
907 if (!gensec_security->ops->have_feature) {
911 /* Can only 'have' a feature if you already 'want'ed it */
912 if (gensec_security->want_features & feature) {
913 return gensec_security->ops->have_feature(gensec_security, feature);
919 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
923 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
925 gensec_security->credentials = talloc_reference(gensec_security, credentials);
930 * Return the credentials structure associated with a GENSEC context
934 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
936 if (!gensec_security) {
939 return gensec_security->credentials;
943 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
947 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
949 gensec_security->target.service = talloc_strdup(gensec_security, service);
950 if (!gensec_security->target.service) {
951 return NT_STATUS_NO_MEMORY;
956 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
958 if (gensec_security->target.service) {
959 return gensec_security->target.service;
966 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
970 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
972 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
973 if (!gensec_security->target.hostname) {
974 return NT_STATUS_NO_MEMORY;
979 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
981 /* We allow the target hostname to be overriden for testing purposes */
982 const char *target_hostname = lp_parm_string(-1, "gensec", "target_hostname");
983 if (target_hostname) {
984 return target_hostname;
987 if (gensec_security->target.hostname) {
988 return gensec_security->target.hostname;
991 /* We could add use the 'set sockaddr' call, and do a reverse
992 * lookup, but this would be both insecure (compromising the
993 * way kerberos works) and add DNS timeouts */
998 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1000 * This is so that kerberos can include these addresses in
1001 * cryptographic tokens, to avoid certain attacks.
1004 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1006 gensec_security->my_addr = my_addr;
1007 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1008 return NT_STATUS_NO_MEMORY;
1010 return NT_STATUS_OK;
1013 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1015 gensec_security->peer_addr = peer_addr;
1016 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1017 return NT_STATUS_NO_MEMORY;
1019 return NT_STATUS_OK;
1022 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1024 if (gensec_security->my_addr) {
1025 return gensec_security->my_addr;
1028 /* We could add a 'set sockaddr' call, and do a lookup. This
1029 * would avoid needing to do system calls if nothing asks. */
1033 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1035 if (gensec_security->peer_addr) {
1036 return gensec_security->peer_addr;
1039 /* We could add a 'set sockaddr' call, and do a lookup. This
1040 * would avoid needing to do system calls if nothing asks.
1041 * However, this is not appropriate for the peer addres on
1042 * datagram sockets */
1049 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1050 * - ensures it is talloc()ed
1054 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1056 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1057 if (!gensec_security->target.principal) {
1058 return NT_STATUS_NO_MEMORY;
1060 return NT_STATUS_OK;
1063 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1065 if (gensec_security->target.principal) {
1066 return gensec_security->target.principal;
1073 register a GENSEC backend.
1075 The 'name' can be later used by other backends to find the operations
1076 structure for this backend.
1078 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1080 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1081 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1082 return NT_STATUS_OK;
1085 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1086 /* its already registered! */
1087 DEBUG(0,("GENSEC backend '%s' already registered\n",
1089 return NT_STATUS_OBJECT_NAME_COLLISION;
1092 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1093 generic_security_ops,
1094 struct gensec_security_ops *,
1095 gensec_num_backends+2);
1096 if (!generic_security_ops) {
1097 return NT_STATUS_NO_MEMORY;
1100 generic_security_ops[gensec_num_backends] = discard_const(ops);
1101 gensec_num_backends++;
1102 generic_security_ops[gensec_num_backends] = NULL;
1104 DEBUG(3,("GENSEC backend '%s' registered\n",
1107 return NT_STATUS_OK;
1111 return the GENSEC interface version, and the size of some critical types
1112 This can be used by backends to either detect compilation errors, or provide
1113 multiple implementations for different smbd compilation options in one module
1115 const struct gensec_critical_sizes *gensec_interface_version(void)
1117 static const struct gensec_critical_sizes critical_sizes = {
1118 GENSEC_INTERFACE_VERSION,
1119 sizeof(struct gensec_security_ops),
1120 sizeof(struct gensec_security),
1123 return &critical_sizes;
1127 initialise the GENSEC subsystem
1129 NTSTATUS gensec_init(void)
1131 static BOOL initialized = False;
1133 init_module_fn static_init[] = STATIC_gensec_MODULES;
1134 init_module_fn *shared_init;
1136 if (initialized) return NT_STATUS_OK;
1139 shared_init = load_samba_modules(NULL, "gensec");
1141 run_init_functions(static_init);
1142 run_init_functions(shared_init);
1144 talloc_free(shared_init);
1146 return NT_STATUS_OK;