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"
31 /* the list of currently registered GENSEC backends */
32 static struct gensec_security_ops **generic_security_ops;
33 static int gensec_num_backends;
35 /* Return all the registered mechs. Don't modify the return pointer,
36 * but you may talloc_reference it if convient */
37 struct gensec_security_ops **gensec_security_all(void)
39 return generic_security_ops;
42 /* Sometimes we want to force only kerberos, sometimes we want to
43 * force it's avoidance. The old list could be either
44 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
45 * an existing list we have trimmed down) */
47 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
48 struct gensec_security_ops **old_gensec_list,
49 enum credentials_use_kerberos use_kerberos)
51 struct gensec_security_ops **new_gensec_list;
52 int i, j, num_mechs_in;
54 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
55 if (!talloc_reference(mem_ctx, old_gensec_list)) {
58 return old_gensec_list;
61 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
65 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
66 if (!new_gensec_list) {
71 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
73 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
74 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
75 new_gensec_list[j] = old_gensec_list[i];
80 switch (use_kerberos) {
81 case CRED_DONT_USE_KERBEROS:
82 if (old_gensec_list[i]->kerberos == False) {
83 new_gensec_list[j] = old_gensec_list[i];
87 case CRED_MUST_USE_KERBEROS:
88 if (old_gensec_list[i]->kerberos == True) {
89 new_gensec_list[j] = old_gensec_list[i];
94 /* Can't happen or invalid parameter */
98 new_gensec_list[j] = NULL;
100 return new_gensec_list;
103 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
106 struct gensec_security_ops **backends;
107 backends = gensec_security_all();
108 if (!gensec_security) {
109 if (!talloc_reference(mem_ctx, backends)) {
114 enum credentials_use_kerberos use_kerberos;
115 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
117 if (!talloc_reference(mem_ctx, backends)) {
122 use_kerberos = cli_credentials_get_kerberos_state(creds);
123 return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
127 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
131 struct gensec_security_ops **backends;
132 const struct gensec_security_ops *backend;
133 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
137 backends = gensec_security_mechs(gensec_security, mem_ctx);
138 for (i=0; backends && backends[i]; i++) {
139 if (backends[i]->auth_type == auth_type) {
140 backend = backends[i];
141 talloc_free(mem_ctx);
145 talloc_free(mem_ctx);
150 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
151 const char *oid_string)
154 struct gensec_security_ops **backends;
155 const struct gensec_security_ops *backend;
156 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
160 backends = gensec_security_mechs(gensec_security, mem_ctx);
161 for (i=0; backends && backends[i]; i++) {
162 if (backends[i]->oid) {
163 for (j=0; backends[i]->oid[j]; j++) {
164 if (backends[i]->oid[j] &&
165 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
166 backend = backends[i];
167 talloc_free(mem_ctx);
173 talloc_free(mem_ctx);
178 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
179 const char *sasl_name)
182 struct gensec_security_ops **backends;
183 const struct gensec_security_ops *backend;
184 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
188 backends = gensec_security_mechs(gensec_security, mem_ctx);
189 for (i=0; backends && backends[i]; i++) {
190 if (backends[i]->sasl_name
191 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
192 backend = backends[i];
193 talloc_free(mem_ctx);
197 talloc_free(mem_ctx);
202 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
206 struct gensec_security_ops **backends;
207 const struct gensec_security_ops *backend;
208 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
212 backends = gensec_security_mechs(gensec_security, mem_ctx);
213 for (i=0; backends && backends[i]; i++) {
214 if (backends[i]->name
215 && (strcmp(backends[i]->name, name) == 0)) {
216 backend = backends[i];
217 talloc_free(mem_ctx);
221 talloc_free(mem_ctx);
226 * Return a unique list of security subsystems from those specified in
227 * the list of SASL names.
229 * Use the list of enabled GENSEC mechanisms from the credentials
230 * attached to the gensec_security, and return in our preferred order.
233 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
235 const char **sasl_names)
237 const struct gensec_security_ops **backends_out;
238 struct gensec_security_ops **backends;
240 int num_backends_out = 0;
246 backends = gensec_security_mechs(gensec_security, mem_ctx);
248 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
252 backends_out[0] = NULL;
254 /* Find backends in our preferred order, by walking our list,
255 * then looking in the supplied list */
256 for (i=0; backends && backends[i]; i++) {
257 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
258 if (!backends[i]->sasl_name ||
259 !(strcmp(backends[i]->sasl_name,
260 sasl_names[sasl_idx]) == 0)) {
264 for (k=0; backends_out[k]; k++) {
265 if (backends_out[k] == backends[i]) {
270 if (k < num_backends_out) {
271 /* already in there */
275 backends_out = talloc_realloc(mem_ctx, backends_out,
276 const struct gensec_security_ops *,
277 num_backends_out + 2);
282 backends_out[num_backends_out] = backends[i];
284 backends_out[num_backends_out] = NULL;
291 * Return a unique list of security subsystems from those specified in
292 * the OID list. That is, where two OIDs refer to the same module,
293 * return that module only once.
295 * Use the list of enabled GENSEC mechanisms from the credentials
296 * attached to the gensec_security, and return in our preferred order.
299 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
301 const char **oid_strings,
304 struct gensec_security_ops_wrapper *backends_out;
305 struct gensec_security_ops **backends;
306 int i, j, k, oid_idx;
307 int num_backends_out = 0;
313 backends = gensec_security_mechs(gensec_security, gensec_security);
315 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
319 backends_out[0].op = NULL;
320 backends_out[0].oid = NULL;
322 /* Find backends in our preferred order, by walking our list,
323 * then looking in the supplied list */
324 for (i=0; backends && backends[i]; i++) {
325 if (!backends[i]->oid) {
328 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
329 if (strcmp(oid_strings[oid_idx], skip) == 0) {
333 for (j=0; backends[i]->oid[j]; j++) {
334 if (!backends[i]->oid[j] ||
335 !(strcmp(backends[i]->oid[j],
336 oid_strings[oid_idx]) == 0)) {
340 for (k=0; backends_out[k].op; k++) {
341 if (backends_out[k].op == backends[i]) {
346 if (k < num_backends_out) {
347 /* already in there */
351 backends_out = talloc_realloc(mem_ctx, backends_out,
352 struct gensec_security_ops_wrapper,
353 num_backends_out + 2);
358 backends_out[num_backends_out].op = backends[i];
359 backends_out[num_backends_out].oid = backends[i]->oid[j];
361 backends_out[num_backends_out].op = NULL;
362 backends_out[num_backends_out].oid = NULL;
370 * Return OIDS from the security subsystems listed
373 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
374 struct gensec_security_ops **ops,
380 const char **oid_list;
384 oid_list = talloc_array(mem_ctx, const char *, 1);
389 for (i=0; ops && ops[i]; i++) {
394 for (k = 0; ops[i]->oid[k]; k++) {
395 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
397 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
401 oid_list[j] = ops[i]->oid[k];
412 * Return OIDS from the security subsystems listed
415 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
416 const struct gensec_security_ops_wrapper *wops)
421 const char **oid_list;
425 oid_list = talloc_array(mem_ctx, const char *, 1);
430 for (i=0; wops[i].op; i++) {
431 if (!wops[i].op->oid) {
435 for (k = 0; wops[i].op->oid[k]; k++) {
436 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
440 oid_list[j] = wops[i].op->oid[k];
450 * Return all the security subsystems currently enabled on a GENSEC context.
452 * This is taken from a list attached to the cli_credentails, and
453 * skips the OID in 'skip'. (Typically the SPNEGO OID)
457 const char **gensec_security_oids(struct gensec_security *gensec_security,
461 struct gensec_security_ops **ops
462 = gensec_security_mechs(gensec_security, mem_ctx);
463 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
469 Start the GENSEC system, returning a context pointer.
470 @param mem_ctx The parent TALLOC memory context.
471 @param gensec_security Returned GENSEC context pointer.
472 @note The mem_ctx is only a parent and may be NULL.
474 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
475 struct event_context *ev,
476 struct messaging_context *msg,
477 struct gensec_security **gensec_security)
479 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
480 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
482 (*gensec_security)->ops = NULL;
484 ZERO_STRUCT((*gensec_security)->target);
485 ZERO_STRUCT((*gensec_security)->peer_addr);
486 ZERO_STRUCT((*gensec_security)->my_addr);
488 (*gensec_security)->subcontext = False;
489 (*gensec_security)->want_features = 0;
492 ev = event_context_init(*gensec_security);
494 talloc_free(*gensec_security);
495 return NT_STATUS_NO_MEMORY;
499 (*gensec_security)->event_ctx = ev;
500 (*gensec_security)->msg_ctx = msg;
506 * Start a GENSEC subcontext, with a copy of the properties of the parent
507 * @param mem_ctx The parent TALLOC memory context.
508 * @param parent The parent GENSEC context
509 * @param gensec_security Returned GENSEC context pointer.
510 * @note Used by SPNEGO in particular, for the actual implementation mechanism
513 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
514 struct gensec_security *parent,
515 struct gensec_security **gensec_security)
517 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
518 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
520 (**gensec_security) = *parent;
521 (*gensec_security)->ops = NULL;
522 (*gensec_security)->private_data = NULL;
524 (*gensec_security)->subcontext = True;
525 (*gensec_security)->event_ctx = parent->event_ctx;
526 (*gensec_security)->msg_ctx = parent->msg_ctx;
532 Start the GENSEC system, in client mode, returning a context pointer.
533 @param mem_ctx The parent TALLOC memory context.
534 @param gensec_security Returned GENSEC context pointer.
535 @note The mem_ctx is only a parent and may be NULL.
537 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
538 struct gensec_security **gensec_security,
539 struct event_context *ev)
542 struct event_context *new_ev = NULL;
545 new_ev = event_context_init(mem_ctx);
546 NT_STATUS_HAVE_NO_MEMORY(new_ev);
550 status = gensec_start(mem_ctx, ev, NULL, gensec_security);
551 if (!NT_STATUS_IS_OK(status)) {
555 talloc_steal((*gensec_security), new_ev);
556 (*gensec_security)->gensec_role = GENSEC_CLIENT;
562 Start the GENSEC system, in server mode, returning a context pointer.
563 @param mem_ctx The parent TALLOC memory context.
564 @param gensec_security Returned GENSEC context pointer.
565 @note The mem_ctx is only a parent and may be NULL.
567 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
568 struct event_context *ev,
569 struct messaging_context *msg,
570 struct gensec_security **gensec_security)
575 DEBUG(0,("gensec_server_start: no event context given!\n"));
576 return NT_STATUS_INTERNAL_ERROR;
580 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
581 return NT_STATUS_INTERNAL_ERROR;
584 status = gensec_start(mem_ctx, ev, msg, gensec_security);
585 if (!NT_STATUS_IS_OK(status)) {
588 (*gensec_security)->gensec_role = GENSEC_SERVER;
593 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
596 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
597 gensec_security->subcontext ? "sub" : "",
598 gensec_security->ops->name));
599 switch (gensec_security->gensec_role) {
601 if (gensec_security->ops->client_start) {
602 status = gensec_security->ops->client_start(gensec_security);
603 if (!NT_STATUS_IS_OK(status)) {
604 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
605 gensec_security->ops->name, nt_errstr(status)));
611 if (gensec_security->ops->server_start) {
612 status = gensec_security->ops->server_start(gensec_security);
613 if (!NT_STATUS_IS_OK(status)) {
614 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
615 gensec_security->ops->name, nt_errstr(status)));
621 return NT_STATUS_INVALID_PARAMETER;
625 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
626 * @param gensec_security GENSEC context pointer.
627 * @param auth_type DCERPC auth type
628 * @param auth_level DCERPC auth level
631 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
632 uint8_t auth_type, uint8_t auth_level)
634 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
635 if (!gensec_security->ops) {
636 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
637 return NT_STATUS_INVALID_PARAMETER;
639 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
640 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
641 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
642 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
643 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
644 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
645 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
646 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
647 /* Default features */
649 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
651 return NT_STATUS_INVALID_PARAMETER;
654 return gensec_start_mech(gensec_security);
657 const char *gensec_get_name_by_authtype(uint8_t authtype)
659 const struct gensec_security_ops *ops;
660 ops = gensec_security_by_authtype(NULL, authtype);
668 const char *gensec_get_name_by_oid(const char *oid_string)
670 const struct gensec_security_ops *ops;
671 ops = gensec_security_by_oid(NULL, oid_string);
680 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
684 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
685 const struct gensec_security_ops *ops)
687 gensec_security->ops = ops;
688 return gensec_start_mech(gensec_security);
692 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
694 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
695 * well-known #define to hook it in.
698 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
699 const char *mech_oid)
701 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
702 if (!gensec_security->ops) {
703 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
704 return NT_STATUS_INVALID_PARAMETER;
706 return gensec_start_mech(gensec_security);
710 * Start a GENSEC sub-mechanism by a well know SASL name
714 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
715 const char *sasl_name)
717 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
718 if (!gensec_security->ops) {
719 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
720 return NT_STATUS_INVALID_PARAMETER;
722 return gensec_start_mech(gensec_security);
726 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
730 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
731 const char **sasl_names)
733 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
734 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
735 const struct gensec_security_ops **ops;
738 return NT_STATUS_NO_MEMORY;
740 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
742 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
743 str_list_join(mem_ctx,
745 talloc_free(mem_ctx);
746 return NT_STATUS_INVALID_PARAMETER;
748 for (i=0; ops[i]; i++) {
749 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
750 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
754 talloc_free(mem_ctx);
759 * Start a GENSEC sub-mechanism by an internal name
763 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
766 gensec_security->ops = gensec_security_by_name(gensec_security, name);
767 if (!gensec_security->ops) {
768 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
769 return NT_STATUS_INVALID_PARAMETER;
771 return gensec_start_mech(gensec_security);
775 wrappers for the gensec function pointers
777 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
779 uint8_t *data, size_t length,
780 const uint8_t *whole_pdu, size_t pdu_length,
781 const DATA_BLOB *sig)
783 if (!gensec_security->ops->unseal_packet) {
784 return NT_STATUS_NOT_IMPLEMENTED;
786 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
787 return NT_STATUS_INVALID_PARAMETER;
790 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
792 whole_pdu, pdu_length,
796 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
798 const uint8_t *data, size_t length,
799 const uint8_t *whole_pdu, size_t pdu_length,
800 const DATA_BLOB *sig)
802 if (!gensec_security->ops->check_packet) {
803 return NT_STATUS_NOT_IMPLEMENTED;
805 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
806 return NT_STATUS_INVALID_PARAMETER;
809 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
812 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
814 uint8_t *data, size_t length,
815 const uint8_t *whole_pdu, size_t pdu_length,
818 if (!gensec_security->ops->seal_packet) {
819 return NT_STATUS_NOT_IMPLEMENTED;
821 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
822 return NT_STATUS_INVALID_PARAMETER;
825 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
828 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
830 const uint8_t *data, size_t length,
831 const uint8_t *whole_pdu, size_t pdu_length,
834 if (!gensec_security->ops->sign_packet) {
835 return NT_STATUS_NOT_IMPLEMENTED;
837 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
838 return NT_STATUS_INVALID_PARAMETER;
841 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
844 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
846 if (!gensec_security->ops->sig_size) {
849 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
853 return gensec_security->ops->sig_size(gensec_security, data_size);
856 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
858 if (!gensec_security->ops->max_wrapped_size) {
862 return gensec_security->ops->max_wrapped_size(gensec_security);
865 size_t gensec_max_input_size(struct gensec_security *gensec_security)
867 if (!gensec_security->ops->max_input_size) {
868 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
871 return gensec_security->ops->max_input_size(gensec_security);
874 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
879 if (!gensec_security->ops->wrap) {
880 return NT_STATUS_NOT_IMPLEMENTED;
882 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
885 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
890 if (!gensec_security->ops->unwrap) {
891 return NT_STATUS_NOT_IMPLEMENTED;
893 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
896 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
897 DATA_BLOB *session_key)
899 if (!gensec_security->ops->session_key) {
900 return NT_STATUS_NOT_IMPLEMENTED;
902 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
903 return NT_STATUS_NO_USER_SESSION_KEY;
906 return gensec_security->ops->session_key(gensec_security, session_key);
910 * Return the credentials of a logged on user, including session keys
913 * Only valid after a successful authentication
915 * May only be called once per authentication.
919 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
920 struct auth_session_info **session_info)
922 if (!gensec_security->ops->session_info) {
923 return NT_STATUS_NOT_IMPLEMENTED;
925 return gensec_security->ops->session_info(gensec_security, session_info);
929 * Next state function for the GENSEC state machine
931 * @param gensec_security GENSEC State
932 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
933 * @param in The request, as a DATA_BLOB
934 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
935 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
936 * or NT_STATUS_OK if the user is authenticated.
939 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
940 const DATA_BLOB in, DATA_BLOB *out)
942 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
945 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
946 struct timeval t, void *ptr)
948 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
949 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
950 req->callback.fn(req, req->callback.private_data);
954 * Next state function for the GENSEC state machine async version
956 * @param gensec_security GENSEC State
957 * @param in The request, as a DATA_BLOB
958 * @param callback The function that will be called when the operation is
959 * finished, it should return gensec_update_recv() to get output
960 * @param private_data A private pointer that will be passed to the callback function
963 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
964 void (*callback)(struct gensec_update_request *req, void *private_data),
967 struct gensec_update_request *req = NULL;
968 struct timed_event *te = NULL;
970 req = talloc(gensec_security, struct gensec_update_request);
971 if (!req) goto failed;
972 req->gensec_security = gensec_security;
974 req->out = data_blob(NULL, 0);
975 req->callback.fn = callback;
976 req->callback.private_data = private_data;
978 te = event_add_timed(gensec_security->event_ctx, req,
980 gensec_update_async_timed_handler, req);
981 if (!te) goto failed;
987 callback(NULL, private_data);
991 * Next state function for the GENSEC state machine
993 * @param req GENSEC update request state
994 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
995 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
996 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
997 * or NT_STATUS_OK if the user is authenticated.
999 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1003 NT_STATUS_HAVE_NO_MEMORY(req);
1006 talloc_steal(out_mem_ctx, out->data);
1007 status = req->status;
1014 * Set the requirement for a certain feature on the connection
1018 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1021 gensec_security->want_features |= feature;
1025 * Check the requirement for a certain feature on the connection
1029 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
1032 if (!gensec_security->ops->have_feature) {
1036 /* We might 'have' features that we don't 'want', because the
1037 * other end demanded them, or we can't neotiate them off */
1038 return gensec_security->ops->have_feature(gensec_security, feature);
1042 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1046 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1048 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1049 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1050 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1051 return NT_STATUS_OK;
1055 * Return the credentials structure associated with a GENSEC context
1059 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1061 if (!gensec_security) {
1064 return gensec_security->credentials;
1068 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1072 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1074 gensec_security->target.service = talloc_strdup(gensec_security, service);
1075 if (!gensec_security->target.service) {
1076 return NT_STATUS_NO_MEMORY;
1078 return NT_STATUS_OK;
1081 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1083 if (gensec_security->target.service) {
1084 return gensec_security->target.service;
1091 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1095 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1097 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1098 if (hostname && !gensec_security->target.hostname) {
1099 return NT_STATUS_NO_MEMORY;
1101 return NT_STATUS_OK;
1104 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1106 /* We allow the target hostname to be overriden for testing purposes */
1107 const char *target_hostname = lp_parm_string(-1, "gensec", "target_hostname");
1108 if (target_hostname) {
1109 return target_hostname;
1112 if (gensec_security->target.hostname) {
1113 return gensec_security->target.hostname;
1116 /* We could add use the 'set sockaddr' call, and do a reverse
1117 * lookup, but this would be both insecure (compromising the
1118 * way kerberos works) and add DNS timeouts */
1123 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1125 * This is so that kerberos can include these addresses in
1126 * cryptographic tokens, to avoid certain attacks.
1129 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1131 gensec_security->my_addr = my_addr;
1132 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1133 return NT_STATUS_NO_MEMORY;
1135 return NT_STATUS_OK;
1138 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1140 gensec_security->peer_addr = peer_addr;
1141 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1142 return NT_STATUS_NO_MEMORY;
1144 return NT_STATUS_OK;
1147 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1149 if (gensec_security->my_addr) {
1150 return gensec_security->my_addr;
1153 /* We could add a 'set sockaddr' call, and do a lookup. This
1154 * would avoid needing to do system calls if nothing asks. */
1158 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1160 if (gensec_security->peer_addr) {
1161 return gensec_security->peer_addr;
1164 /* We could add a 'set sockaddr' call, and do a lookup. This
1165 * would avoid needing to do system calls if nothing asks.
1166 * However, this is not appropriate for the peer addres on
1167 * datagram sockets */
1174 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1175 * - ensures it is talloc()ed
1179 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1181 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1182 if (!gensec_security->target.principal) {
1183 return NT_STATUS_NO_MEMORY;
1185 return NT_STATUS_OK;
1188 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1190 if (gensec_security->target.principal) {
1191 return gensec_security->target.principal;
1198 register a GENSEC backend.
1200 The 'name' can be later used by other backends to find the operations
1201 structure for this backend.
1203 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1205 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1206 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1207 return NT_STATUS_OK;
1210 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1211 /* its already registered! */
1212 DEBUG(0,("GENSEC backend '%s' already registered\n",
1214 return NT_STATUS_OBJECT_NAME_COLLISION;
1217 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1218 generic_security_ops,
1219 struct gensec_security_ops *,
1220 gensec_num_backends+2);
1221 if (!generic_security_ops) {
1222 return NT_STATUS_NO_MEMORY;
1225 generic_security_ops[gensec_num_backends] = discard_const(ops);
1226 gensec_num_backends++;
1227 generic_security_ops[gensec_num_backends] = NULL;
1229 DEBUG(3,("GENSEC backend '%s' registered\n",
1232 return NT_STATUS_OK;
1236 return the GENSEC interface version, and the size of some critical types
1237 This can be used by backends to either detect compilation errors, or provide
1238 multiple implementations for different smbd compilation options in one module
1240 const struct gensec_critical_sizes *gensec_interface_version(void)
1242 static const struct gensec_critical_sizes critical_sizes = {
1243 GENSEC_INTERFACE_VERSION,
1244 sizeof(struct gensec_security_ops),
1245 sizeof(struct gensec_security),
1248 return &critical_sizes;
1251 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1252 return (*gs2)->priority - (*gs1)->priority;
1256 initialise the GENSEC subsystem
1258 NTSTATUS gensec_init(void)
1260 static BOOL initialized = False;
1262 init_module_fn static_init[] = STATIC_gensec_MODULES;
1263 init_module_fn *shared_init;
1265 if (initialized) return NT_STATUS_OK;
1268 shared_init = load_samba_modules(NULL, "gensec");
1270 run_init_functions(static_init);
1271 run_init_functions(shared_init);
1273 talloc_free(shared_init);
1275 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1277 return NT_STATUS_OK;