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 if (gensec_security->target.hostname) {
982 return gensec_security->target.hostname;
985 /* We could add use the 'set sockaddr' call, and do a reverse
986 * lookup, but this would be both insecure (compromising the
987 * way kerberos works) and add DNS timeouts */
992 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
994 * This is so that kerberos can include these addresses in
995 * cryptographic tokens, to avoid certain attacks.
998 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1000 gensec_security->my_addr = my_addr;
1001 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1002 return NT_STATUS_NO_MEMORY;
1004 return NT_STATUS_OK;
1007 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1009 gensec_security->peer_addr = peer_addr;
1010 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1011 return NT_STATUS_NO_MEMORY;
1013 return NT_STATUS_OK;
1016 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1018 if (gensec_security->my_addr) {
1019 return gensec_security->my_addr;
1022 /* We could add a 'set sockaddr' call, and do a lookup. This
1023 * would avoid needing to do system calls if nothing asks. */
1027 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1029 if (gensec_security->peer_addr) {
1030 return gensec_security->peer_addr;
1033 /* We could add a 'set sockaddr' call, and do a lookup. This
1034 * would avoid needing to do system calls if nothing asks.
1035 * However, this is not appropriate for the peer addres on
1036 * datagram sockets */
1043 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1044 * - ensures it is talloc()ed
1048 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1050 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1051 if (!gensec_security->target.principal) {
1052 return NT_STATUS_NO_MEMORY;
1054 return NT_STATUS_OK;
1057 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1059 if (gensec_security->target.principal) {
1060 return gensec_security->target.principal;
1067 register a GENSEC backend.
1069 The 'name' can be later used by other backends to find the operations
1070 structure for this backend.
1072 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1074 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1075 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1076 return NT_STATUS_OK;
1079 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1080 /* its already registered! */
1081 DEBUG(0,("GENSEC backend '%s' already registered\n",
1083 return NT_STATUS_OBJECT_NAME_COLLISION;
1086 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1087 generic_security_ops,
1088 struct gensec_security_ops *,
1089 gensec_num_backends+2);
1090 if (!generic_security_ops) {
1091 smb_panic("out of memory (or failed to realloc referenced memory) in gensec_register");
1094 generic_security_ops[gensec_num_backends] = discard_const(ops);
1095 gensec_num_backends++;
1096 generic_security_ops[gensec_num_backends] = NULL;
1098 DEBUG(3,("GENSEC backend '%s' registered\n",
1101 return NT_STATUS_OK;
1105 return the GENSEC interface version, and the size of some critical types
1106 This can be used by backends to either detect compilation errors, or provide
1107 multiple implementations for different smbd compilation options in one module
1109 const struct gensec_critical_sizes *gensec_interface_version(void)
1111 static const struct gensec_critical_sizes critical_sizes = {
1112 GENSEC_INTERFACE_VERSION,
1113 sizeof(struct gensec_security_ops),
1114 sizeof(struct gensec_security),
1117 return &critical_sizes;
1121 initialise the GENSEC subsystem
1123 NTSTATUS gensec_init(void)
1125 static BOOL initialized = False;
1127 init_module_fn static_init[] = STATIC_gensec_MODULES;
1128 init_module_fn *shared_init = load_samba_modules(NULL, "gensec");
1130 if (initialized) return NT_STATUS_OK;
1133 run_init_functions(static_init);
1134 run_init_functions(shared_init);
1136 talloc_free(shared_init);
1138 return NT_STATUS_OK;