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"
29 /* the list of currently registered GENSEC backends */
30 static struct gensec_security_ops **generic_security_ops;
31 static int gensec_num_backends;
33 /* Return all the registered mechs. Don't modify the return pointer,
34 * but you may talloc_reference it if convient */
35 struct gensec_security_ops **gensec_security_all(void)
37 return generic_security_ops;
40 /* Sometimes we want to force only kerberos, sometimes we want to
41 * force it's avoidance. The old list could be either
42 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
43 * an existing list we have trimmed down) */
45 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
46 struct gensec_security_ops **old_gensec_list,
47 enum credentials_use_kerberos use_kerberos)
49 struct gensec_security_ops **new_gensec_list;
50 int i, j, num_mechs_in;
52 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
53 talloc_reference(mem_ctx, old_gensec_list);
54 return old_gensec_list;
57 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
61 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
62 if (!new_gensec_list) {
67 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
69 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
70 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
71 new_gensec_list[j] = old_gensec_list[i];
76 switch (use_kerberos) {
77 case CRED_DONT_USE_KERBEROS:
78 if (old_gensec_list[i]->kerberos == False) {
79 new_gensec_list[j] = old_gensec_list[i];
83 case CRED_MUST_USE_KERBEROS:
84 if (old_gensec_list[i]->kerberos == True) {
85 new_gensec_list[j] = old_gensec_list[i];
89 case CRED_AUTO_USE_KERBEROS:
93 new_gensec_list[j] = NULL;
95 return new_gensec_list;
98 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
101 struct gensec_security_ops **backends;
102 backends = gensec_security_all();
103 if (!gensec_security) {
104 talloc_reference(mem_ctx, backends);
107 enum credentials_use_kerberos use_kerberos;
108 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
110 talloc_reference(mem_ctx, backends);
113 use_kerberos = cli_credentials_get_kerberos_state(creds);
114 return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
118 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
122 struct gensec_security_ops **backends;
123 const struct gensec_security_ops *backend;
124 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
128 backends = gensec_security_mechs(gensec_security, mem_ctx);
129 for (i=0; backends && backends[i]; i++) {
130 if (backends[i]->auth_type == auth_type) {
131 backend = backends[i];
132 talloc_free(mem_ctx);
136 talloc_free(mem_ctx);
141 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
142 const char *oid_string)
145 struct gensec_security_ops **backends;
146 const struct gensec_security_ops *backend;
147 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
151 backends = gensec_security_mechs(gensec_security, mem_ctx);
152 for (i=0; backends && backends[i]; i++) {
153 if (backends[i]->oid) {
154 for (j=0; backends[i]->oid[j]; j++) {
155 if (backends[i]->oid[j] &&
156 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
157 backend = backends[i];
158 talloc_free(mem_ctx);
164 talloc_free(mem_ctx);
169 static const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
170 const char *sasl_name)
173 struct gensec_security_ops **backends;
174 const struct gensec_security_ops *backend;
175 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
179 backends = gensec_security_mechs(gensec_security, mem_ctx);
180 for (i=0; backends && backends[i]; i++) {
181 if (backends[i]->sasl_name
182 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
183 backend = backends[i];
184 talloc_free(mem_ctx);
188 talloc_free(mem_ctx);
193 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
197 struct gensec_security_ops **backends;
198 const struct gensec_security_ops *backend;
199 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
203 backends = gensec_security_mechs(gensec_security, mem_ctx);
204 for (i=0; backends && backends[i]; i++) {
205 if (backends[i]->name
206 && (strcmp(backends[i]->name, name) == 0)) {
207 backend = backends[i];
208 talloc_free(mem_ctx);
212 talloc_free(mem_ctx);
217 * Return a unique list of security subsystems from those specified in
218 * the list of SASL names.
220 * Use the list of enabled GENSEC mechanisms from the credentials
221 * attached to the gensec_security, and return in our preferred order.
224 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
226 const char **sasl_names)
228 const struct gensec_security_ops **backends_out;
229 struct gensec_security_ops **backends;
231 int num_backends_out = 0;
237 backends = gensec_security_mechs(gensec_security, mem_ctx);
239 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
243 backends_out[0] = NULL;
245 /* Find backends in our preferred order, by walking our list,
246 * then looking in the supplied list */
247 for (i=0; backends && backends[i]; i++) {
248 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
249 if (!backends[i]->sasl_name ||
250 !(strcmp(backends[i]->sasl_name,
251 sasl_names[sasl_idx]) == 0)) {
255 for (k=0; backends_out[k]; k++) {
256 if (backends_out[k] == backends[i]) {
261 if (k < num_backends_out) {
262 /* already in there */
266 backends_out = talloc_realloc(mem_ctx, backends_out,
267 const struct gensec_security_ops *,
268 num_backends_out + 2);
273 backends_out[num_backends_out] = backends[i];
275 backends_out[num_backends_out] = NULL;
282 * Return a unique list of security subsystems from those specified in
283 * the OID list. That is, where two OIDs refer to the same module,
284 * return that module only once.
286 * Use the list of enabled GENSEC mechanisms from the credentials
287 * attached to the gensec_security, and return in our preferred order.
290 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
292 const char **oid_strings,
295 struct gensec_security_ops_wrapper *backends_out;
296 struct gensec_security_ops **backends;
297 int i, j, k, oid_idx;
298 int num_backends_out = 0;
304 backends = gensec_security_mechs(gensec_security, gensec_security);
306 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
310 backends_out[0].op = NULL;
311 backends_out[0].oid = NULL;
313 /* Find backends in our preferred order, by walking our list,
314 * then looking in the supplied list */
315 for (i=0; backends && backends[i]; i++) {
316 if (!backends[i]->oid) {
319 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
320 if (strcmp(oid_strings[oid_idx], skip) == 0) {
324 for (j=0; backends[i]->oid[j]; j++) {
325 if (!backends[i]->oid[j] ||
326 !(strcmp(backends[i]->oid[j],
327 oid_strings[oid_idx]) == 0)) {
331 for (k=0; backends_out[k].op; k++) {
332 if (backends_out[k].op == backends[i]) {
337 if (k < num_backends_out) {
338 /* already in there */
342 backends_out = talloc_realloc(mem_ctx, backends_out,
343 struct gensec_security_ops_wrapper,
344 num_backends_out + 2);
349 backends_out[num_backends_out].op = backends[i];
350 backends_out[num_backends_out].oid = backends[i]->oid[j];
352 backends_out[num_backends_out].op = NULL;
353 backends_out[num_backends_out].oid = NULL;
361 * Return OIDS from the security subsystems listed
364 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
365 struct gensec_security_ops **ops,
371 const char **oid_list;
375 oid_list = talloc_array(mem_ctx, const char *, 1);
380 for (i=0; ops && ops[i]; i++) {
385 for (k = 0; ops[i]->oid[k]; k++) {
386 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
388 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
392 oid_list[j] = ops[i]->oid[k];
403 * Return OIDS from the security subsystems listed
406 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
407 const struct gensec_security_ops_wrapper *wops)
412 const char **oid_list;
416 oid_list = talloc_array(mem_ctx, const char *, 1);
421 for (i=0; wops[i].op; i++) {
422 if (!wops[i].op->oid) {
426 for (k = 0; wops[i].op->oid[k]; k++) {
427 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
431 oid_list[j] = wops[i].op->oid[k];
441 * Return all the security subsystems currently enabled on a GENSEC context.
443 * This is taken from a list attached to the cli_credentails, and
444 * skips the OID in 'skip'. (Typically the SPNEGO OID)
448 const char **gensec_security_oids(struct gensec_security *gensec_security,
452 struct gensec_security_ops **ops
453 = gensec_security_mechs(gensec_security, mem_ctx);
454 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
460 Start the GENSEC system, returning a context pointer.
461 @param mem_ctx The parent TALLOC memory context.
462 @param gensec_security Returned GENSEC context pointer.
463 @note The mem_ctx is only a parent and may be NULL.
465 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
466 struct gensec_security **gensec_security,
467 struct event_context *ev)
469 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
470 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
472 (*gensec_security)->ops = NULL;
474 ZERO_STRUCT((*gensec_security)->target);
475 ZERO_STRUCT((*gensec_security)->peer_addr);
476 ZERO_STRUCT((*gensec_security)->my_addr);
478 (*gensec_security)->subcontext = False;
479 (*gensec_security)->want_features = 0;
482 ev = event_context_init(*gensec_security);
484 talloc_free(*gensec_security);
485 return NT_STATUS_NO_MEMORY;
489 (*gensec_security)->event_ctx = ev;
495 * Start a GENSEC subcontext, with a copy of the properties of the parent
496 * @param mem_ctx The parent TALLOC memory context.
497 * @param parent The parent GENSEC context
498 * @param gensec_security Returned GENSEC context pointer.
499 * @note Used by SPNEGO in particular, for the actual implementation mechanism
502 NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
503 struct gensec_security *parent,
504 struct gensec_security **gensec_security)
506 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
507 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
509 (**gensec_security) = *parent;
510 (*gensec_security)->ops = NULL;
511 (*gensec_security)->private_data = NULL;
513 (*gensec_security)->subcontext = True;
514 (*gensec_security)->event_ctx = parent->event_ctx;
520 Start the GENSEC system, in client mode, returning a context pointer.
521 @param mem_ctx The parent TALLOC memory context.
522 @param gensec_security Returned GENSEC context pointer.
523 @note The mem_ctx is only a parent and may be NULL.
525 NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
526 struct gensec_security **gensec_security,
527 struct event_context *ev)
530 status = gensec_start(mem_ctx, gensec_security, ev);
531 if (!NT_STATUS_IS_OK(status)) {
534 (*gensec_security)->gensec_role = GENSEC_CLIENT;
540 Start the GENSEC system, in server 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 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
546 struct gensec_security **gensec_security,
547 struct event_context *ev)
550 status = gensec_start(mem_ctx, gensec_security, ev);
551 if (!NT_STATUS_IS_OK(status)) {
554 (*gensec_security)->gensec_role = GENSEC_SERVER;
559 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
562 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
563 gensec_security->subcontext ? "sub" : "",
564 gensec_security->ops->name));
565 switch (gensec_security->gensec_role) {
567 if (gensec_security->ops->client_start) {
568 status = gensec_security->ops->client_start(gensec_security);
569 if (!NT_STATUS_IS_OK(status)) {
570 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
571 gensec_security->ops->name, nt_errstr(status)));
576 if (gensec_security->ops->server_start) {
577 status = gensec_security->ops->server_start(gensec_security);
578 if (!NT_STATUS_IS_OK(status)) {
579 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
580 gensec_security->ops->name, nt_errstr(status)));
585 return NT_STATUS_INVALID_PARAMETER;
589 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
590 * @param gensec_security GENSEC context pointer.
591 * @param auth_type DCERPC auth type
592 * @param auth_level DCERPC auth level
595 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
596 uint8_t auth_type, uint8_t auth_level)
598 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
599 if (!gensec_security->ops) {
600 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
601 return NT_STATUS_INVALID_PARAMETER;
603 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
604 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
605 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
606 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
607 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
608 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
609 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
610 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
611 /* Default features */
613 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
615 return NT_STATUS_INVALID_PARAMETER;
618 return gensec_start_mech(gensec_security);
621 const char *gensec_get_name_by_authtype(uint8_t authtype)
623 const struct gensec_security_ops *ops;
624 ops = gensec_security_by_authtype(NULL, authtype);
632 const char *gensec_get_name_by_oid(const char *oid_string)
634 const struct gensec_security_ops *ops;
635 ops = gensec_security_by_oid(NULL, oid_string);
644 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
648 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
649 const struct gensec_security_ops *ops)
651 gensec_security->ops = ops;
652 return gensec_start_mech(gensec_security);
656 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
658 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
659 * well-known #define to hook it in.
662 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
663 const char *mech_oid)
665 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
666 if (!gensec_security->ops) {
667 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
668 return NT_STATUS_INVALID_PARAMETER;
670 return gensec_start_mech(gensec_security);
674 * Start a GENSEC sub-mechanism by a well know SASL name
678 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
679 const char *sasl_name)
681 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
682 if (!gensec_security->ops) {
683 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
684 return NT_STATUS_INVALID_PARAMETER;
686 return gensec_start_mech(gensec_security);
690 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
694 NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
695 const char **sasl_names)
698 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
699 const struct gensec_security_ops **ops;
701 return NT_STATUS_NO_MEMORY;
703 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
705 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
706 str_list_join(mem_ctx,
708 talloc_free(mem_ctx);
709 return NT_STATUS_INVALID_PARAMETER;
711 nt_status = gensec_start_mech_by_ops(gensec_security, ops[0]);
712 talloc_free(mem_ctx);
717 * Start a GENSEC sub-mechanism by an internal name
721 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
724 gensec_security->ops = gensec_security_by_name(gensec_security, name);
725 if (!gensec_security->ops) {
726 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
727 return NT_STATUS_INVALID_PARAMETER;
729 return gensec_start_mech(gensec_security);
733 wrappers for the gensec function pointers
735 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
737 uint8_t *data, size_t length,
738 const uint8_t *whole_pdu, size_t pdu_length,
739 const DATA_BLOB *sig)
741 if (!gensec_security->ops->unseal_packet) {
742 return NT_STATUS_NOT_IMPLEMENTED;
744 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
745 return NT_STATUS_INVALID_PARAMETER;
748 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
750 whole_pdu, pdu_length,
754 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
756 const uint8_t *data, size_t length,
757 const uint8_t *whole_pdu, size_t pdu_length,
758 const DATA_BLOB *sig)
760 if (!gensec_security->ops->check_packet) {
761 return NT_STATUS_NOT_IMPLEMENTED;
763 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
764 return NT_STATUS_INVALID_PARAMETER;
767 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
770 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
772 uint8_t *data, size_t length,
773 const uint8_t *whole_pdu, size_t pdu_length,
776 if (!gensec_security->ops->seal_packet) {
777 return NT_STATUS_NOT_IMPLEMENTED;
779 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
780 return NT_STATUS_INVALID_PARAMETER;
783 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
786 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
788 const uint8_t *data, size_t length,
789 const uint8_t *whole_pdu, size_t pdu_length,
792 if (!gensec_security->ops->sign_packet) {
793 return NT_STATUS_NOT_IMPLEMENTED;
795 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
796 return NT_STATUS_INVALID_PARAMETER;
799 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
802 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
804 if (!gensec_security->ops->sig_size) {
807 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
811 return gensec_security->ops->sig_size(gensec_security, data_size);
814 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
819 if (!gensec_security->ops->wrap) {
820 return NT_STATUS_NOT_IMPLEMENTED;
822 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
825 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
830 if (!gensec_security->ops->unwrap) {
831 return NT_STATUS_NOT_IMPLEMENTED;
833 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
836 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
837 DATA_BLOB *session_key)
839 if (!gensec_security->ops->session_key) {
840 return NT_STATUS_NOT_IMPLEMENTED;
842 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
843 return NT_STATUS_NO_USER_SESSION_KEY;
846 return gensec_security->ops->session_key(gensec_security, session_key);
850 * Return the credentials of a logged on user, including session keys
853 * Only valid after a successful authentication
855 * May only be called once per authentication.
859 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
860 struct auth_session_info **session_info)
862 if (!gensec_security->ops->session_info) {
863 return NT_STATUS_NOT_IMPLEMENTED;
865 return gensec_security->ops->session_info(gensec_security, session_info);
869 * Next state function for the GENSEC state machine
871 * @param gensec_security GENSEC State
872 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
873 * @param in The request, as a DATA_BLOB
874 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
875 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
876 * or NT_STATUS_OK if the user is authenticated.
879 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
880 const DATA_BLOB in, DATA_BLOB *out)
882 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
886 * Set the requirement for a certain feature on the connection
890 void gensec_want_feature(struct gensec_security *gensec_security,
893 gensec_security->want_features |= feature;
897 * Check the requirement for a certain feature on the connection
901 BOOL gensec_have_feature(struct gensec_security *gensec_security,
904 if (!gensec_security->ops->have_feature) {
908 /* Can only 'have' a feature if you already 'want'ed it */
909 if (gensec_security->want_features & feature) {
910 return gensec_security->ops->have_feature(gensec_security, feature);
916 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
920 NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
922 gensec_security->credentials = talloc_reference(gensec_security, credentials);
927 * Return the credentials structure associated with a GENSEC context
931 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
933 if (!gensec_security) {
936 return gensec_security->credentials;
940 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
944 NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
946 gensec_security->target.service = talloc_strdup(gensec_security, service);
947 if (!gensec_security->target.service) {
948 return NT_STATUS_NO_MEMORY;
953 const char *gensec_get_target_service(struct gensec_security *gensec_security)
955 if (gensec_security->target.service) {
956 return gensec_security->target.service;
963 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
967 NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
969 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
970 if (!gensec_security->target.hostname) {
971 return NT_STATUS_NO_MEMORY;
976 const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
978 if (gensec_security->target.hostname) {
979 return gensec_security->target.hostname;
982 /* We could add use the 'set sockaddr' call, and do a reverse
983 * lookup, but this would be both insecure (compromising the
984 * way kerberos works) and add DNS timeouts */
989 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
991 * This is so that kerberos can include these addresses in
992 * cryptographic tokens, to avoid certain attacks.
995 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
997 gensec_security->my_addr = my_addr;
998 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
999 return NT_STATUS_NO_MEMORY;
1001 return NT_STATUS_OK;
1004 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1006 gensec_security->peer_addr = peer_addr;
1007 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1008 return NT_STATUS_NO_MEMORY;
1010 return NT_STATUS_OK;
1013 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1015 if (gensec_security->my_addr) {
1016 return gensec_security->my_addr;
1019 /* We could add a 'set sockaddr' call, and do a lookup. This
1020 * would avoid needing to do system calls if nothing asks. */
1024 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1026 if (gensec_security->peer_addr) {
1027 return gensec_security->peer_addr;
1030 /* We could add a 'set sockaddr' call, and do a lookup. This
1031 * would avoid needing to do system calls if nothing asks.
1032 * However, this is not appropriate for the peer addres on
1033 * datagram sockets */
1040 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1041 * - ensures it is talloc()ed
1045 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1047 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1048 if (!gensec_security->target.principal) {
1049 return NT_STATUS_NO_MEMORY;
1051 return NT_STATUS_OK;
1054 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1056 if (gensec_security->target.principal) {
1057 return gensec_security->target.principal;
1064 register a GENSEC backend.
1066 The 'name' can be later used by other backends to find the operations
1067 structure for this backend.
1069 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1071 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1072 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1073 return NT_STATUS_OK;
1076 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1077 /* its already registered! */
1078 DEBUG(0,("GENSEC backend '%s' already registered\n",
1080 return NT_STATUS_OBJECT_NAME_COLLISION;
1083 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1084 generic_security_ops,
1085 struct gensec_security_ops *,
1086 gensec_num_backends+2);
1087 if (!generic_security_ops) {
1088 smb_panic("out of memory (or failed to realloc referenced memory) in gensec_register");
1091 generic_security_ops[gensec_num_backends] = discard_const(ops);
1092 gensec_num_backends++;
1093 generic_security_ops[gensec_num_backends] = NULL;
1095 DEBUG(3,("GENSEC backend '%s' registered\n",
1098 return NT_STATUS_OK;
1102 return the GENSEC interface version, and the size of some critical types
1103 This can be used by backends to either detect compilation errors, or provide
1104 multiple implementations for different smbd compilation options in one module
1106 const struct gensec_critical_sizes *gensec_interface_version(void)
1108 static const struct gensec_critical_sizes critical_sizes = {
1109 GENSEC_INTERFACE_VERSION,
1110 sizeof(struct gensec_security_ops),
1111 sizeof(struct gensec_security),
1114 return &critical_sizes;
1118 initialise the GENSEC subsystem
1120 NTSTATUS gensec_init(void)
1122 static BOOL initialized = False;
1124 init_module_fn static_init[] = STATIC_GENSEC_MODULES;
1125 init_module_fn *shared_init = load_samba_modules(NULL, "gensec");
1127 if (initialized) return NT_STATUS_OK;
1130 run_init_functions(static_init);
1131 run_init_functions(shared_init);
1133 talloc_free(shared_init);
1135 return NT_STATUS_OK;