2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "auth/auth.h"
25 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "param/param.h"
32 /* the list of currently registered GENSEC backends */
33 static struct gensec_security_ops **generic_security_ops;
34 static int gensec_num_backends;
36 /* Return all the registered mechs. Don't modify the return pointer,
37 * but you may talloc_reference it if convient */
38 struct gensec_security_ops **gensec_security_all(void)
40 return generic_security_ops;
43 /* Sometimes we want to force only kerberos, sometimes we want to
44 * force it's avoidance. The old list could be either
45 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
46 * an existing list we have trimmed down) */
48 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
49 struct gensec_security_ops **old_gensec_list,
50 enum credentials_use_kerberos use_kerberos)
52 struct gensec_security_ops **new_gensec_list;
53 int i, j, num_mechs_in;
55 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
56 if (!talloc_reference(mem_ctx, old_gensec_list)) {
59 return old_gensec_list;
62 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
66 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
67 if (!new_gensec_list) {
72 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
74 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
75 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
76 new_gensec_list[j] = old_gensec_list[i];
81 switch (use_kerberos) {
82 case CRED_DONT_USE_KERBEROS:
83 if (old_gensec_list[i]->kerberos == False) {
84 new_gensec_list[j] = old_gensec_list[i];
88 case CRED_MUST_USE_KERBEROS:
89 if (old_gensec_list[i]->kerberos == True) {
90 new_gensec_list[j] = old_gensec_list[i];
95 /* Can't happen or invalid parameter */
99 new_gensec_list[j] = NULL;
101 return new_gensec_list;
104 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
107 struct gensec_security_ops **backends;
108 backends = gensec_security_all();
109 if (!gensec_security) {
110 if (!talloc_reference(mem_ctx, backends)) {
115 enum credentials_use_kerberos use_kerberos;
116 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
118 if (!talloc_reference(mem_ctx, backends)) {
123 use_kerberos = cli_credentials_get_kerberos_state(creds);
124 return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
128 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
132 struct gensec_security_ops **backends;
133 const struct gensec_security_ops *backend;
134 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
138 backends = gensec_security_mechs(gensec_security, mem_ctx);
139 for (i=0; backends && backends[i]; i++) {
140 if (backends[i]->auth_type == auth_type) {
141 backend = backends[i];
142 talloc_free(mem_ctx);
146 talloc_free(mem_ctx);
151 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
152 const char *oid_string)
155 struct gensec_security_ops **backends;
156 const struct gensec_security_ops *backend;
157 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
161 backends = gensec_security_mechs(gensec_security, mem_ctx);
162 for (i=0; backends && backends[i]; i++) {
163 if (backends[i]->oid) {
164 for (j=0; backends[i]->oid[j]; j++) {
165 if (backends[i]->oid[j] &&
166 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
167 backend = backends[i];
168 talloc_free(mem_ctx);
174 talloc_free(mem_ctx);
179 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
180 const char *sasl_name)
183 struct gensec_security_ops **backends;
184 const struct gensec_security_ops *backend;
185 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
189 backends = gensec_security_mechs(gensec_security, mem_ctx);
190 for (i=0; backends && backends[i]; i++) {
191 if (backends[i]->sasl_name
192 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
193 backend = backends[i];
194 talloc_free(mem_ctx);
198 talloc_free(mem_ctx);
203 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
207 struct gensec_security_ops **backends;
208 const struct gensec_security_ops *backend;
209 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
213 backends = gensec_security_mechs(gensec_security, mem_ctx);
214 for (i=0; backends && backends[i]; i++) {
215 if (backends[i]->name
216 && (strcmp(backends[i]->name, name) == 0)) {
217 backend = backends[i];
218 talloc_free(mem_ctx);
222 talloc_free(mem_ctx);
227 * Return a unique list of security subsystems from those specified in
228 * the list of SASL names.
230 * Use the list of enabled GENSEC mechanisms from the credentials
231 * attached to the gensec_security, and return in our preferred order.
234 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
236 const char **sasl_names)
238 const struct gensec_security_ops **backends_out;
239 struct gensec_security_ops **backends;
241 int num_backends_out = 0;
247 backends = gensec_security_mechs(gensec_security, mem_ctx);
249 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
253 backends_out[0] = NULL;
255 /* Find backends in our preferred order, by walking our list,
256 * then looking in the supplied list */
257 for (i=0; backends && backends[i]; i++) {
258 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
259 if (!backends[i]->sasl_name ||
260 !(strcmp(backends[i]->sasl_name,
261 sasl_names[sasl_idx]) == 0)) {
265 for (k=0; backends_out[k]; k++) {
266 if (backends_out[k] == backends[i]) {
271 if (k < num_backends_out) {
272 /* already in there */
276 backends_out = talloc_realloc(mem_ctx, backends_out,
277 const struct gensec_security_ops *,
278 num_backends_out + 2);
283 backends_out[num_backends_out] = backends[i];
285 backends_out[num_backends_out] = NULL;
292 * Return a unique list of security subsystems from those specified in
293 * the OID list. That is, where two OIDs refer to the same module,
294 * return that module only once.
296 * Use the list of enabled GENSEC mechanisms from the credentials
297 * attached to the gensec_security, and return in our preferred order.
300 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
302 const char **oid_strings,
305 struct gensec_security_ops_wrapper *backends_out;
306 struct gensec_security_ops **backends;
307 int i, j, k, oid_idx;
308 int num_backends_out = 0;
314 backends = gensec_security_mechs(gensec_security, gensec_security);
316 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
320 backends_out[0].op = NULL;
321 backends_out[0].oid = NULL;
323 /* Find backends in our preferred order, by walking our list,
324 * then looking in the supplied list */
325 for (i=0; backends && backends[i]; i++) {
326 if (!backends[i]->oid) {
329 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
330 if (strcmp(oid_strings[oid_idx], skip) == 0) {
334 for (j=0; backends[i]->oid[j]; j++) {
335 if (!backends[i]->oid[j] ||
336 !(strcmp(backends[i]->oid[j],
337 oid_strings[oid_idx]) == 0)) {
341 for (k=0; backends_out[k].op; k++) {
342 if (backends_out[k].op == backends[i]) {
347 if (k < num_backends_out) {
348 /* already in there */
352 backends_out = talloc_realloc(mem_ctx, backends_out,
353 struct gensec_security_ops_wrapper,
354 num_backends_out + 2);
359 backends_out[num_backends_out].op = backends[i];
360 backends_out[num_backends_out].oid = backends[i]->oid[j];
362 backends_out[num_backends_out].op = NULL;
363 backends_out[num_backends_out].oid = NULL;
371 * Return OIDS from the security subsystems listed
374 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
375 struct gensec_security_ops **ops,
381 const char **oid_list;
385 oid_list = talloc_array(mem_ctx, const char *, 1);
390 for (i=0; ops && ops[i]; i++) {
395 for (k = 0; ops[i]->oid[k]; k++) {
396 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
398 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
402 oid_list[j] = ops[i]->oid[k];
413 * Return OIDS from the security subsystems listed
416 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
417 const struct gensec_security_ops_wrapper *wops)
422 const char **oid_list;
426 oid_list = talloc_array(mem_ctx, const char *, 1);
431 for (i=0; wops[i].op; i++) {
432 if (!wops[i].op->oid) {
436 for (k = 0; wops[i].op->oid[k]; k++) {
437 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
441 oid_list[j] = wops[i].op->oid[k];
451 * Return all the security subsystems currently enabled on a GENSEC context.
453 * This is taken from a list attached to the cli_credentails, and
454 * skips the OID in 'skip'. (Typically the SPNEGO OID)
458 const char **gensec_security_oids(struct gensec_security *gensec_security,
462 struct gensec_security_ops **ops
463 = gensec_security_mechs(gensec_security, mem_ctx);
464 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
470 Start the GENSEC system, returning a context pointer.
471 @param mem_ctx The parent TALLOC memory context.
472 @param gensec_security Returned GENSEC context pointer.
473 @note The mem_ctx is only a parent and may be NULL.
475 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
476 struct event_context *ev,
477 struct messaging_context *msg,
478 struct gensec_security **gensec_security)
480 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
481 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
483 (*gensec_security)->ops = NULL;
485 ZERO_STRUCT((*gensec_security)->target);
486 ZERO_STRUCT((*gensec_security)->peer_addr);
487 ZERO_STRUCT((*gensec_security)->my_addr);
489 (*gensec_security)->subcontext = False;
490 (*gensec_security)->want_features = 0;
493 ev = event_context_init(*gensec_security);
495 talloc_free(*gensec_security);
496 return NT_STATUS_NO_MEMORY;
500 (*gensec_security)->event_ctx = ev;
501 (*gensec_security)->msg_ctx = msg;
507 * Start a GENSEC subcontext, with a copy of the properties of the parent
508 * @param mem_ctx The parent TALLOC memory context.
509 * @param parent The parent GENSEC context
510 * @param gensec_security Returned GENSEC context pointer.
511 * @note Used by SPNEGO in particular, for the actual implementation mechanism
514 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
515 struct gensec_security *parent,
516 struct gensec_security **gensec_security)
518 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
519 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
521 (**gensec_security) = *parent;
522 (*gensec_security)->ops = NULL;
523 (*gensec_security)->private_data = NULL;
525 (*gensec_security)->subcontext = True;
526 (*gensec_security)->event_ctx = parent->event_ctx;
527 (*gensec_security)->msg_ctx = parent->msg_ctx;
533 Start the GENSEC system, in client mode, returning a context pointer.
534 @param mem_ctx The parent TALLOC memory context.
535 @param gensec_security Returned GENSEC context pointer.
536 @note The mem_ctx is only a parent and may be NULL.
538 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
539 struct gensec_security **gensec_security,
540 struct event_context *ev)
543 struct event_context *new_ev = NULL;
546 new_ev = event_context_init(mem_ctx);
547 NT_STATUS_HAVE_NO_MEMORY(new_ev);
551 status = gensec_start(mem_ctx, ev, NULL, gensec_security);
552 if (!NT_STATUS_IS_OK(status)) {
556 talloc_steal((*gensec_security), new_ev);
557 (*gensec_security)->gensec_role = GENSEC_CLIENT;
563 Start the GENSEC system, in server mode, returning a context pointer.
564 @param mem_ctx The parent TALLOC memory context.
565 @param gensec_security Returned GENSEC context pointer.
566 @note The mem_ctx is only a parent and may be NULL.
568 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
569 struct event_context *ev,
570 struct messaging_context *msg,
571 struct gensec_security **gensec_security)
576 DEBUG(0,("gensec_server_start: no event context given!\n"));
577 return NT_STATUS_INTERNAL_ERROR;
581 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
582 return NT_STATUS_INTERNAL_ERROR;
585 status = gensec_start(mem_ctx, ev, msg, gensec_security);
586 if (!NT_STATUS_IS_OK(status)) {
589 (*gensec_security)->gensec_role = GENSEC_SERVER;
594 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
597 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
598 gensec_security->subcontext ? "sub" : "",
599 gensec_security->ops->name));
600 switch (gensec_security->gensec_role) {
602 if (gensec_security->ops->client_start) {
603 status = gensec_security->ops->client_start(gensec_security);
604 if (!NT_STATUS_IS_OK(status)) {
605 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
606 gensec_security->ops->name, nt_errstr(status)));
612 if (gensec_security->ops->server_start) {
613 status = gensec_security->ops->server_start(gensec_security);
614 if (!NT_STATUS_IS_OK(status)) {
615 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
616 gensec_security->ops->name, nt_errstr(status)));
622 return NT_STATUS_INVALID_PARAMETER;
626 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
627 * @param gensec_security GENSEC context pointer.
628 * @param auth_type DCERPC auth type
629 * @param auth_level DCERPC auth level
632 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
633 uint8_t auth_type, uint8_t auth_level)
635 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
636 if (!gensec_security->ops) {
637 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
638 return NT_STATUS_INVALID_PARAMETER;
640 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
641 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
642 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
643 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
644 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
645 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
646 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
647 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
648 /* Default features */
650 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
652 return NT_STATUS_INVALID_PARAMETER;
655 return gensec_start_mech(gensec_security);
658 const char *gensec_get_name_by_authtype(uint8_t authtype)
660 const struct gensec_security_ops *ops;
661 ops = gensec_security_by_authtype(NULL, authtype);
669 const char *gensec_get_name_by_oid(const char *oid_string)
671 const struct gensec_security_ops *ops;
672 ops = gensec_security_by_oid(NULL, oid_string);
681 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
685 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
686 const struct gensec_security_ops *ops)
688 gensec_security->ops = ops;
689 return gensec_start_mech(gensec_security);
693 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
695 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
696 * well-known #define to hook it in.
699 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
700 const char *mech_oid)
702 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
703 if (!gensec_security->ops) {
704 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
705 return NT_STATUS_INVALID_PARAMETER;
707 return gensec_start_mech(gensec_security);
711 * Start a GENSEC sub-mechanism by a well know SASL name
715 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
716 const char *sasl_name)
718 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
719 if (!gensec_security->ops) {
720 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
721 return NT_STATUS_INVALID_PARAMETER;
723 return gensec_start_mech(gensec_security);
727 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
731 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
732 const char **sasl_names)
734 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
735 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
736 const struct gensec_security_ops **ops;
739 return NT_STATUS_NO_MEMORY;
741 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
743 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
744 str_list_join(mem_ctx,
746 talloc_free(mem_ctx);
747 return NT_STATUS_INVALID_PARAMETER;
749 for (i=0; ops[i]; i++) {
750 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
751 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
755 talloc_free(mem_ctx);
760 * Start a GENSEC sub-mechanism by an internal name
764 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
767 gensec_security->ops = gensec_security_by_name(gensec_security, name);
768 if (!gensec_security->ops) {
769 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
770 return NT_STATUS_INVALID_PARAMETER;
772 return gensec_start_mech(gensec_security);
776 wrappers for the gensec function pointers
778 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
780 uint8_t *data, size_t length,
781 const uint8_t *whole_pdu, size_t pdu_length,
782 const DATA_BLOB *sig)
784 if (!gensec_security->ops->unseal_packet) {
785 return NT_STATUS_NOT_IMPLEMENTED;
787 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
788 return NT_STATUS_INVALID_PARAMETER;
791 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
793 whole_pdu, pdu_length,
797 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
799 const uint8_t *data, size_t length,
800 const uint8_t *whole_pdu, size_t pdu_length,
801 const DATA_BLOB *sig)
803 if (!gensec_security->ops->check_packet) {
804 return NT_STATUS_NOT_IMPLEMENTED;
806 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
807 return NT_STATUS_INVALID_PARAMETER;
810 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
813 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
815 uint8_t *data, size_t length,
816 const uint8_t *whole_pdu, size_t pdu_length,
819 if (!gensec_security->ops->seal_packet) {
820 return NT_STATUS_NOT_IMPLEMENTED;
822 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
823 return NT_STATUS_INVALID_PARAMETER;
826 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
829 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
831 const uint8_t *data, size_t length,
832 const uint8_t *whole_pdu, size_t pdu_length,
835 if (!gensec_security->ops->sign_packet) {
836 return NT_STATUS_NOT_IMPLEMENTED;
838 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
839 return NT_STATUS_INVALID_PARAMETER;
842 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
845 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
847 if (!gensec_security->ops->sig_size) {
850 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
854 return gensec_security->ops->sig_size(gensec_security, data_size);
857 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
859 if (!gensec_security->ops->max_wrapped_size) {
863 return gensec_security->ops->max_wrapped_size(gensec_security);
866 size_t gensec_max_input_size(struct gensec_security *gensec_security)
868 if (!gensec_security->ops->max_input_size) {
869 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
872 return gensec_security->ops->max_input_size(gensec_security);
875 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
880 if (!gensec_security->ops->wrap) {
881 return NT_STATUS_NOT_IMPLEMENTED;
883 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
886 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
891 if (!gensec_security->ops->unwrap) {
892 return NT_STATUS_NOT_IMPLEMENTED;
894 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
897 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
898 DATA_BLOB *session_key)
900 if (!gensec_security->ops->session_key) {
901 return NT_STATUS_NOT_IMPLEMENTED;
903 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
904 return NT_STATUS_NO_USER_SESSION_KEY;
907 return gensec_security->ops->session_key(gensec_security, session_key);
911 * Return the credentials of a logged on user, including session keys
914 * Only valid after a successful authentication
916 * May only be called once per authentication.
920 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
921 struct auth_session_info **session_info)
923 if (!gensec_security->ops->session_info) {
924 return NT_STATUS_NOT_IMPLEMENTED;
926 return gensec_security->ops->session_info(gensec_security, session_info);
930 * Next state function for the GENSEC state machine
932 * @param gensec_security GENSEC State
933 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
934 * @param in The request, as a DATA_BLOB
935 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
936 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
937 * or NT_STATUS_OK if the user is authenticated.
940 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
941 const DATA_BLOB in, DATA_BLOB *out)
943 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
946 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
947 struct timeval t, void *ptr)
949 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
950 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
951 req->callback.fn(req, req->callback.private_data);
955 * Next state function for the GENSEC state machine async version
957 * @param gensec_security GENSEC State
958 * @param in The request, as a DATA_BLOB
959 * @param callback The function that will be called when the operation is
960 * finished, it should return gensec_update_recv() to get output
961 * @param private_data A private pointer that will be passed to the callback function
964 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
965 void (*callback)(struct gensec_update_request *req, void *private_data),
968 struct gensec_update_request *req = NULL;
969 struct timed_event *te = NULL;
971 req = talloc(gensec_security, struct gensec_update_request);
972 if (!req) goto failed;
973 req->gensec_security = gensec_security;
975 req->out = data_blob(NULL, 0);
976 req->callback.fn = callback;
977 req->callback.private_data = private_data;
979 te = event_add_timed(gensec_security->event_ctx, req,
981 gensec_update_async_timed_handler, req);
982 if (!te) goto failed;
988 callback(NULL, private_data);
992 * Next state function for the GENSEC state machine
994 * @param req GENSEC update request state
995 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
996 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
997 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
998 * or NT_STATUS_OK if the user is authenticated.
1000 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1004 NT_STATUS_HAVE_NO_MEMORY(req);
1007 talloc_steal(out_mem_ctx, out->data);
1008 status = req->status;
1015 * Set the requirement for a certain feature on the connection
1019 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1022 gensec_security->want_features |= feature;
1026 * Check the requirement for a certain feature on the connection
1030 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
1033 if (!gensec_security->ops->have_feature) {
1037 /* We might 'have' features that we don't 'want', because the
1038 * other end demanded them, or we can't neotiate them off */
1039 return gensec_security->ops->have_feature(gensec_security, feature);
1043 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1047 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1049 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1050 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1051 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1052 return NT_STATUS_OK;
1056 * Return the credentials structure associated with a GENSEC context
1060 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1062 if (!gensec_security) {
1065 return gensec_security->credentials;
1069 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1073 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1075 gensec_security->target.service = talloc_strdup(gensec_security, service);
1076 if (!gensec_security->target.service) {
1077 return NT_STATUS_NO_MEMORY;
1079 return NT_STATUS_OK;
1082 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1084 if (gensec_security->target.service) {
1085 return gensec_security->target.service;
1092 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1096 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1098 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1099 if (hostname && !gensec_security->target.hostname) {
1100 return NT_STATUS_NO_MEMORY;
1102 return NT_STATUS_OK;
1105 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1107 /* We allow the target hostname to be overriden for testing purposes */
1108 const char *target_hostname = lp_parm_string(-1, "gensec", "target_hostname");
1109 if (target_hostname) {
1110 return target_hostname;
1113 if (gensec_security->target.hostname) {
1114 return gensec_security->target.hostname;
1117 /* We could add use the 'set sockaddr' call, and do a reverse
1118 * lookup, but this would be both insecure (compromising the
1119 * way kerberos works) and add DNS timeouts */
1124 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1126 * This is so that kerberos can include these addresses in
1127 * cryptographic tokens, to avoid certain attacks.
1130 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1132 gensec_security->my_addr = my_addr;
1133 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1134 return NT_STATUS_NO_MEMORY;
1136 return NT_STATUS_OK;
1139 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1141 gensec_security->peer_addr = peer_addr;
1142 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1143 return NT_STATUS_NO_MEMORY;
1145 return NT_STATUS_OK;
1148 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1150 if (gensec_security->my_addr) {
1151 return gensec_security->my_addr;
1154 /* We could add a 'set sockaddr' call, and do a lookup. This
1155 * would avoid needing to do system calls if nothing asks. */
1159 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1161 if (gensec_security->peer_addr) {
1162 return gensec_security->peer_addr;
1165 /* We could add a 'set sockaddr' call, and do a lookup. This
1166 * would avoid needing to do system calls if nothing asks.
1167 * However, this is not appropriate for the peer addres on
1168 * datagram sockets */
1175 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1176 * - ensures it is talloc()ed
1180 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1182 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1183 if (!gensec_security->target.principal) {
1184 return NT_STATUS_NO_MEMORY;
1186 return NT_STATUS_OK;
1189 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1191 if (gensec_security->target.principal) {
1192 return gensec_security->target.principal;
1199 register a GENSEC backend.
1201 The 'name' can be later used by other backends to find the operations
1202 structure for this backend.
1204 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1206 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1207 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1208 return NT_STATUS_OK;
1211 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1212 /* its already registered! */
1213 DEBUG(0,("GENSEC backend '%s' already registered\n",
1215 return NT_STATUS_OBJECT_NAME_COLLISION;
1218 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1219 generic_security_ops,
1220 struct gensec_security_ops *,
1221 gensec_num_backends+2);
1222 if (!generic_security_ops) {
1223 return NT_STATUS_NO_MEMORY;
1226 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1227 gensec_num_backends++;
1228 generic_security_ops[gensec_num_backends] = NULL;
1230 DEBUG(3,("GENSEC backend '%s' registered\n",
1233 return NT_STATUS_OK;
1237 return the GENSEC interface version, and the size of some critical types
1238 This can be used by backends to either detect compilation errors, or provide
1239 multiple implementations for different smbd compilation options in one module
1241 const struct gensec_critical_sizes *gensec_interface_version(void)
1243 static const struct gensec_critical_sizes critical_sizes = {
1244 GENSEC_INTERFACE_VERSION,
1245 sizeof(struct gensec_security_ops),
1246 sizeof(struct gensec_security),
1249 return &critical_sizes;
1252 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1253 return (*gs2)->priority - (*gs1)->priority;
1257 initialise the GENSEC subsystem
1259 NTSTATUS gensec_init(void)
1261 static BOOL initialized = False;
1263 init_module_fn static_init[] = STATIC_gensec_MODULES;
1264 init_module_fn *shared_init;
1266 if (initialized) return NT_STATUS_OK;
1269 shared_init = load_samba_modules(NULL, "gensec");
1271 run_init_functions(static_init);
1272 run_init_functions(shared_init);
1274 talloc_free(shared_init);
1276 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1278 return NT_STATUS_OK;