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 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "auth/auth.h"
26 #include "lib/events/events.h"
28 #include "librpc/rpc/dcerpc.h"
30 /* the list of currently registered GENSEC backends */
31 static struct gensec_security_ops **generic_security_ops;
32 static int gensec_num_backends;
34 /* Return all the registered mechs. Don't modify the return pointer,
35 * but you may talloc_reference it if convient */
36 struct gensec_security_ops **gensec_security_all(void)
38 return generic_security_ops;
41 /* Sometimes we want to force only kerberos, sometimes we want to
42 * force it's avoidance. The old list could be either
43 * gensec_security_all(), or from cli_credentials_gensec_list() (ie,
44 * an existing list we have trimmed down) */
46 struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
47 struct gensec_security_ops **old_gensec_list,
48 enum credentials_use_kerberos use_kerberos)
50 struct gensec_security_ops **new_gensec_list;
51 int i, j, num_mechs_in;
53 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
54 if (!talloc_reference(mem_ctx, old_gensec_list)) {
57 return old_gensec_list;
60 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
64 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
65 if (!new_gensec_list) {
70 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
72 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
73 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
74 new_gensec_list[j] = old_gensec_list[i];
79 switch (use_kerberos) {
80 case CRED_DONT_USE_KERBEROS:
81 if (old_gensec_list[i]->kerberos == False) {
82 new_gensec_list[j] = old_gensec_list[i];
86 case CRED_MUST_USE_KERBEROS:
87 if (old_gensec_list[i]->kerberos == True) {
88 new_gensec_list[j] = old_gensec_list[i];
93 /* Can't happen or invalid parameter */
97 new_gensec_list[j] = NULL;
99 return new_gensec_list;
102 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
105 struct gensec_security_ops **backends;
106 backends = gensec_security_all();
107 if (!gensec_security) {
108 if (!talloc_reference(mem_ctx, backends)) {
113 enum credentials_use_kerberos use_kerberos;
114 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
116 if (!talloc_reference(mem_ctx, backends)) {
121 use_kerberos = cli_credentials_get_kerberos_state(creds);
122 return gensec_use_kerberos_mechs(mem_ctx, backends, use_kerberos);
126 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
130 struct gensec_security_ops **backends;
131 const struct gensec_security_ops *backend;
132 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
136 backends = gensec_security_mechs(gensec_security, mem_ctx);
137 for (i=0; backends && backends[i]; i++) {
138 if (backends[i]->auth_type == auth_type) {
139 backend = backends[i];
140 talloc_free(mem_ctx);
144 talloc_free(mem_ctx);
149 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
150 const char *oid_string)
153 struct gensec_security_ops **backends;
154 const struct gensec_security_ops *backend;
155 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
159 backends = gensec_security_mechs(gensec_security, mem_ctx);
160 for (i=0; backends && backends[i]; i++) {
161 if (backends[i]->oid) {
162 for (j=0; backends[i]->oid[j]; j++) {
163 if (backends[i]->oid[j] &&
164 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
165 backend = backends[i];
166 talloc_free(mem_ctx);
172 talloc_free(mem_ctx);
177 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
178 const char *sasl_name)
181 struct gensec_security_ops **backends;
182 const struct gensec_security_ops *backend;
183 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
187 backends = gensec_security_mechs(gensec_security, mem_ctx);
188 for (i=0; backends && backends[i]; i++) {
189 if (backends[i]->sasl_name
190 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
191 backend = backends[i];
192 talloc_free(mem_ctx);
196 talloc_free(mem_ctx);
201 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
205 struct gensec_security_ops **backends;
206 const struct gensec_security_ops *backend;
207 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
211 backends = gensec_security_mechs(gensec_security, mem_ctx);
212 for (i=0; backends && backends[i]; i++) {
213 if (backends[i]->name
214 && (strcmp(backends[i]->name, name) == 0)) {
215 backend = backends[i];
216 talloc_free(mem_ctx);
220 talloc_free(mem_ctx);
225 * Return a unique list of security subsystems from those specified in
226 * the list of SASL names.
228 * Use the list of enabled GENSEC mechanisms from the credentials
229 * attached to the gensec_security, and return in our preferred order.
232 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
234 const char **sasl_names)
236 const struct gensec_security_ops **backends_out;
237 struct gensec_security_ops **backends;
239 int num_backends_out = 0;
245 backends = gensec_security_mechs(gensec_security, mem_ctx);
247 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
251 backends_out[0] = NULL;
253 /* Find backends in our preferred order, by walking our list,
254 * then looking in the supplied list */
255 for (i=0; backends && backends[i]; i++) {
256 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
257 if (!backends[i]->sasl_name ||
258 !(strcmp(backends[i]->sasl_name,
259 sasl_names[sasl_idx]) == 0)) {
263 for (k=0; backends_out[k]; k++) {
264 if (backends_out[k] == backends[i]) {
269 if (k < num_backends_out) {
270 /* already in there */
274 backends_out = talloc_realloc(mem_ctx, backends_out,
275 const struct gensec_security_ops *,
276 num_backends_out + 2);
281 backends_out[num_backends_out] = backends[i];
283 backends_out[num_backends_out] = NULL;
290 * Return a unique list of security subsystems from those specified in
291 * the OID list. That is, where two OIDs refer to the same module,
292 * return that module only once.
294 * Use the list of enabled GENSEC mechanisms from the credentials
295 * attached to the gensec_security, and return in our preferred order.
298 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
300 const char **oid_strings,
303 struct gensec_security_ops_wrapper *backends_out;
304 struct gensec_security_ops **backends;
305 int i, j, k, oid_idx;
306 int num_backends_out = 0;
312 backends = gensec_security_mechs(gensec_security, gensec_security);
314 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
318 backends_out[0].op = NULL;
319 backends_out[0].oid = NULL;
321 /* Find backends in our preferred order, by walking our list,
322 * then looking in the supplied list */
323 for (i=0; backends && backends[i]; i++) {
324 if (!backends[i]->oid) {
327 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
328 if (strcmp(oid_strings[oid_idx], skip) == 0) {
332 for (j=0; backends[i]->oid[j]; j++) {
333 if (!backends[i]->oid[j] ||
334 !(strcmp(backends[i]->oid[j],
335 oid_strings[oid_idx]) == 0)) {
339 for (k=0; backends_out[k].op; k++) {
340 if (backends_out[k].op == backends[i]) {
345 if (k < num_backends_out) {
346 /* already in there */
350 backends_out = talloc_realloc(mem_ctx, backends_out,
351 struct gensec_security_ops_wrapper,
352 num_backends_out + 2);
357 backends_out[num_backends_out].op = backends[i];
358 backends_out[num_backends_out].oid = backends[i]->oid[j];
360 backends_out[num_backends_out].op = NULL;
361 backends_out[num_backends_out].oid = NULL;
369 * Return OIDS from the security subsystems listed
372 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
373 struct gensec_security_ops **ops,
379 const char **oid_list;
383 oid_list = talloc_array(mem_ctx, const char *, 1);
388 for (i=0; ops && ops[i]; i++) {
393 for (k = 0; ops[i]->oid[k]; k++) {
394 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
396 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
400 oid_list[j] = ops[i]->oid[k];
411 * Return OIDS from the security subsystems listed
414 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
415 const struct gensec_security_ops_wrapper *wops)
420 const char **oid_list;
424 oid_list = talloc_array(mem_ctx, const char *, 1);
429 for (i=0; wops[i].op; i++) {
430 if (!wops[i].op->oid) {
434 for (k = 0; wops[i].op->oid[k]; k++) {
435 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
439 oid_list[j] = wops[i].op->oid[k];
449 * Return all the security subsystems currently enabled on a GENSEC context.
451 * This is taken from a list attached to the cli_credentails, and
452 * skips the OID in 'skip'. (Typically the SPNEGO OID)
456 const char **gensec_security_oids(struct gensec_security *gensec_security,
460 struct gensec_security_ops **ops
461 = gensec_security_mechs(gensec_security, mem_ctx);
462 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
468 Start the GENSEC system, returning a context pointer.
469 @param mem_ctx The parent TALLOC memory context.
470 @param gensec_security Returned GENSEC context pointer.
471 @note The mem_ctx is only a parent and may be NULL.
473 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
474 struct event_context *ev,
475 struct messaging_context *msg,
476 struct gensec_security **gensec_security)
478 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
479 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
481 (*gensec_security)->ops = NULL;
483 ZERO_STRUCT((*gensec_security)->target);
484 ZERO_STRUCT((*gensec_security)->peer_addr);
485 ZERO_STRUCT((*gensec_security)->my_addr);
487 (*gensec_security)->subcontext = False;
488 (*gensec_security)->want_features = 0;
491 ev = event_context_init(*gensec_security);
493 talloc_free(*gensec_security);
494 return NT_STATUS_NO_MEMORY;
498 (*gensec_security)->event_ctx = ev;
499 (*gensec_security)->msg_ctx = msg;
505 * Start a GENSEC subcontext, with a copy of the properties of the parent
506 * @param mem_ctx The parent TALLOC memory context.
507 * @param parent The parent GENSEC context
508 * @param gensec_security Returned GENSEC context pointer.
509 * @note Used by SPNEGO in particular, for the actual implementation mechanism
512 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
513 struct gensec_security *parent,
514 struct gensec_security **gensec_security)
516 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
517 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
519 (**gensec_security) = *parent;
520 (*gensec_security)->ops = NULL;
521 (*gensec_security)->private_data = NULL;
523 (*gensec_security)->subcontext = True;
524 (*gensec_security)->event_ctx = parent->event_ctx;
525 (*gensec_security)->msg_ctx = parent->msg_ctx;
531 Start the GENSEC system, in client mode, returning a context pointer.
532 @param mem_ctx The parent TALLOC memory context.
533 @param gensec_security Returned GENSEC context pointer.
534 @note The mem_ctx is only a parent and may be NULL.
536 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
537 struct gensec_security **gensec_security,
538 struct event_context *ev)
541 struct event_context *new_ev = NULL;
544 new_ev = event_context_init(mem_ctx);
545 NT_STATUS_HAVE_NO_MEMORY(new_ev);
549 status = gensec_start(mem_ctx, ev, NULL, gensec_security);
550 if (!NT_STATUS_IS_OK(status)) {
554 talloc_steal((*gensec_security), new_ev);
555 (*gensec_security)->gensec_role = GENSEC_CLIENT;
561 Start the GENSEC system, in server mode, returning a context pointer.
562 @param mem_ctx The parent TALLOC memory context.
563 @param gensec_security Returned GENSEC context pointer.
564 @note The mem_ctx is only a parent and may be NULL.
566 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
567 struct event_context *ev,
568 struct messaging_context *msg,
569 struct gensec_security **gensec_security)
574 DEBUG(0,("gensec_server_start: no event context given!\n"));
575 return NT_STATUS_INTERNAL_ERROR;
579 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
580 return NT_STATUS_INTERNAL_ERROR;
583 status = gensec_start(mem_ctx, ev, msg, gensec_security);
584 if (!NT_STATUS_IS_OK(status)) {
587 (*gensec_security)->gensec_role = GENSEC_SERVER;
592 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
595 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
596 gensec_security->subcontext ? "sub" : "",
597 gensec_security->ops->name));
598 switch (gensec_security->gensec_role) {
600 if (gensec_security->ops->client_start) {
601 status = gensec_security->ops->client_start(gensec_security);
602 if (!NT_STATUS_IS_OK(status)) {
603 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
604 gensec_security->ops->name, nt_errstr(status)));
610 if (gensec_security->ops->server_start) {
611 status = gensec_security->ops->server_start(gensec_security);
612 if (!NT_STATUS_IS_OK(status)) {
613 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
614 gensec_security->ops->name, nt_errstr(status)));
620 return NT_STATUS_INVALID_PARAMETER;
624 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
625 * @param gensec_security GENSEC context pointer.
626 * @param auth_type DCERPC auth type
627 * @param auth_level DCERPC auth level
630 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
631 uint8_t auth_type, uint8_t auth_level)
633 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
634 if (!gensec_security->ops) {
635 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
636 return NT_STATUS_INVALID_PARAMETER;
638 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
639 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
640 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
641 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
642 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
643 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
644 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
645 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
646 /* Default features */
648 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
650 return NT_STATUS_INVALID_PARAMETER;
653 return gensec_start_mech(gensec_security);
656 const char *gensec_get_name_by_authtype(uint8_t authtype)
658 const struct gensec_security_ops *ops;
659 ops = gensec_security_by_authtype(NULL, authtype);
667 const char *gensec_get_name_by_oid(const char *oid_string)
669 const struct gensec_security_ops *ops;
670 ops = gensec_security_by_oid(NULL, oid_string);
679 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
683 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
684 const struct gensec_security_ops *ops)
686 gensec_security->ops = ops;
687 return gensec_start_mech(gensec_security);
691 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
693 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
694 * well-known #define to hook it in.
697 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
698 const char *mech_oid)
700 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
701 if (!gensec_security->ops) {
702 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
703 return NT_STATUS_INVALID_PARAMETER;
705 return gensec_start_mech(gensec_security);
709 * Start a GENSEC sub-mechanism by a well know SASL name
713 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
714 const char *sasl_name)
716 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
717 if (!gensec_security->ops) {
718 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
719 return NT_STATUS_INVALID_PARAMETER;
721 return gensec_start_mech(gensec_security);
725 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
729 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
730 const char **sasl_names)
733 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
734 const struct gensec_security_ops **ops;
737 return NT_STATUS_NO_MEMORY;
739 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
741 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
742 str_list_join(mem_ctx,
744 talloc_free(mem_ctx);
745 return NT_STATUS_INVALID_PARAMETER;
747 for (i=0; ops[i]; i++) {
748 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
749 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
753 talloc_free(mem_ctx);
758 * Start a GENSEC sub-mechanism by an internal name
762 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
765 gensec_security->ops = gensec_security_by_name(gensec_security, name);
766 if (!gensec_security->ops) {
767 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
768 return NT_STATUS_INVALID_PARAMETER;
770 return gensec_start_mech(gensec_security);
774 wrappers for the gensec function pointers
776 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
778 uint8_t *data, size_t length,
779 const uint8_t *whole_pdu, size_t pdu_length,
780 const DATA_BLOB *sig)
782 if (!gensec_security->ops->unseal_packet) {
783 return NT_STATUS_NOT_IMPLEMENTED;
785 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
786 return NT_STATUS_INVALID_PARAMETER;
789 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
791 whole_pdu, pdu_length,
795 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
797 const uint8_t *data, size_t length,
798 const uint8_t *whole_pdu, size_t pdu_length,
799 const DATA_BLOB *sig)
801 if (!gensec_security->ops->check_packet) {
802 return NT_STATUS_NOT_IMPLEMENTED;
804 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
805 return NT_STATUS_INVALID_PARAMETER;
808 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
811 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
813 uint8_t *data, size_t length,
814 const uint8_t *whole_pdu, size_t pdu_length,
817 if (!gensec_security->ops->seal_packet) {
818 return NT_STATUS_NOT_IMPLEMENTED;
820 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
821 return NT_STATUS_INVALID_PARAMETER;
824 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
827 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
829 const uint8_t *data, size_t length,
830 const uint8_t *whole_pdu, size_t pdu_length,
833 if (!gensec_security->ops->sign_packet) {
834 return NT_STATUS_NOT_IMPLEMENTED;
836 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
837 return NT_STATUS_INVALID_PARAMETER;
840 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
843 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
845 if (!gensec_security->ops->sig_size) {
848 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
852 return gensec_security->ops->sig_size(gensec_security, data_size);
855 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
857 if (!gensec_security->ops->max_wrapped_size) {
861 return gensec_security->ops->max_wrapped_size(gensec_security);
864 size_t gensec_max_input_size(struct gensec_security *gensec_security)
866 if (!gensec_security->ops->max_input_size) {
867 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
870 return gensec_security->ops->max_input_size(gensec_security);
873 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
878 if (!gensec_security->ops->wrap) {
879 return NT_STATUS_NOT_IMPLEMENTED;
881 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
884 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
889 if (!gensec_security->ops->unwrap) {
890 return NT_STATUS_NOT_IMPLEMENTED;
892 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
895 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
896 DATA_BLOB *session_key)
898 if (!gensec_security->ops->session_key) {
899 return NT_STATUS_NOT_IMPLEMENTED;
901 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
902 return NT_STATUS_NO_USER_SESSION_KEY;
905 return gensec_security->ops->session_key(gensec_security, session_key);
909 * Return the credentials of a logged on user, including session keys
912 * Only valid after a successful authentication
914 * May only be called once per authentication.
918 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
919 struct auth_session_info **session_info)
921 if (!gensec_security->ops->session_info) {
922 return NT_STATUS_NOT_IMPLEMENTED;
924 return gensec_security->ops->session_info(gensec_security, session_info);
928 * Next state function for the GENSEC state machine
930 * @param gensec_security GENSEC State
931 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
932 * @param in The request, as a DATA_BLOB
933 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
934 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
935 * or NT_STATUS_OK if the user is authenticated.
938 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
939 const DATA_BLOB in, DATA_BLOB *out)
941 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
944 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
945 struct timeval t, void *ptr)
947 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
948 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
949 req->callback.fn(req, req->callback.private_data);
953 * Next state function for the GENSEC state machine async version
955 * @param gensec_security GENSEC State
956 * @param in The request, as a DATA_BLOB
957 * @param callback The function that will be called when the operation is
958 * finished, it should return gensec_update_recv() to get output
959 * @param private_data A private pointer that will be passed to the callback function
962 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
963 void (*callback)(struct gensec_update_request *req, void *private_data),
966 struct gensec_update_request *req = NULL;
967 struct timed_event *te = NULL;
969 req = talloc(gensec_security, struct gensec_update_request);
970 if (!req) goto failed;
971 req->gensec_security = gensec_security;
973 req->out = data_blob(NULL, 0);
974 req->callback.fn = callback;
975 req->callback.private_data = private_data;
977 te = event_add_timed(gensec_security->event_ctx, req,
979 gensec_update_async_timed_handler, req);
980 if (!te) goto failed;
986 callback(NULL, private_data);
990 * Next state function for the GENSEC state machine
992 * @param req GENSEC update request state
993 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
994 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
995 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
996 * or NT_STATUS_OK if the user is authenticated.
998 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1002 NT_STATUS_HAVE_NO_MEMORY(req);
1005 talloc_steal(out_mem_ctx, out->data);
1006 status = req->status;
1013 * Set the requirement for a certain feature on the connection
1017 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1020 gensec_security->want_features |= feature;
1024 * Check the requirement for a certain feature on the connection
1028 _PUBLIC_ BOOL gensec_have_feature(struct gensec_security *gensec_security,
1031 if (!gensec_security->ops->have_feature) {
1035 /* We might 'have' features that we don't 'want', because the
1036 * other end demanded them, or we can't neotiate them off */
1037 return gensec_security->ops->have_feature(gensec_security, feature);
1041 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1045 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1047 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1048 return NT_STATUS_OK;
1052 * Return the credentials structure associated with a GENSEC context
1056 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1058 if (!gensec_security) {
1061 return gensec_security->credentials;
1065 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1069 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1071 gensec_security->target.service = talloc_strdup(gensec_security, service);
1072 if (!gensec_security->target.service) {
1073 return NT_STATUS_NO_MEMORY;
1075 return NT_STATUS_OK;
1078 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1080 if (gensec_security->target.service) {
1081 return gensec_security->target.service;
1088 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1092 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1094 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1095 if (!gensec_security->target.hostname) {
1096 return NT_STATUS_NO_MEMORY;
1098 return NT_STATUS_OK;
1101 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1103 /* We allow the target hostname to be overriden for testing purposes */
1104 const char *target_hostname = lp_parm_string(-1, "gensec", "target_hostname");
1105 if (target_hostname) {
1106 return target_hostname;
1109 if (gensec_security->target.hostname) {
1110 return gensec_security->target.hostname;
1113 /* We could add use the 'set sockaddr' call, and do a reverse
1114 * lookup, but this would be both insecure (compromising the
1115 * way kerberos works) and add DNS timeouts */
1120 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1122 * This is so that kerberos can include these addresses in
1123 * cryptographic tokens, to avoid certain attacks.
1126 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1128 gensec_security->my_addr = my_addr;
1129 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1130 return NT_STATUS_NO_MEMORY;
1132 return NT_STATUS_OK;
1135 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1137 gensec_security->peer_addr = peer_addr;
1138 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1139 return NT_STATUS_NO_MEMORY;
1141 return NT_STATUS_OK;
1144 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1146 if (gensec_security->my_addr) {
1147 return gensec_security->my_addr;
1150 /* We could add a 'set sockaddr' call, and do a lookup. This
1151 * would avoid needing to do system calls if nothing asks. */
1155 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1157 if (gensec_security->peer_addr) {
1158 return gensec_security->peer_addr;
1161 /* We could add a 'set sockaddr' call, and do a lookup. This
1162 * would avoid needing to do system calls if nothing asks.
1163 * However, this is not appropriate for the peer addres on
1164 * datagram sockets */
1171 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1172 * - ensures it is talloc()ed
1176 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1178 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1179 if (!gensec_security->target.principal) {
1180 return NT_STATUS_NO_MEMORY;
1182 return NT_STATUS_OK;
1185 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1187 if (gensec_security->target.principal) {
1188 return gensec_security->target.principal;
1195 register a GENSEC backend.
1197 The 'name' can be later used by other backends to find the operations
1198 structure for this backend.
1200 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1202 if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
1203 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1204 return NT_STATUS_OK;
1207 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1208 /* its already registered! */
1209 DEBUG(0,("GENSEC backend '%s' already registered\n",
1211 return NT_STATUS_OBJECT_NAME_COLLISION;
1214 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1215 generic_security_ops,
1216 struct gensec_security_ops *,
1217 gensec_num_backends+2);
1218 if (!generic_security_ops) {
1219 return NT_STATUS_NO_MEMORY;
1222 generic_security_ops[gensec_num_backends] = discard_const(ops);
1223 gensec_num_backends++;
1224 generic_security_ops[gensec_num_backends] = NULL;
1226 DEBUG(3,("GENSEC backend '%s' registered\n",
1229 return NT_STATUS_OK;
1233 return the GENSEC interface version, and the size of some critical types
1234 This can be used by backends to either detect compilation errors, or provide
1235 multiple implementations for different smbd compilation options in one module
1237 const struct gensec_critical_sizes *gensec_interface_version(void)
1239 static const struct gensec_critical_sizes critical_sizes = {
1240 GENSEC_INTERFACE_VERSION,
1241 sizeof(struct gensec_security_ops),
1242 sizeof(struct gensec_security),
1245 return &critical_sizes;
1248 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1249 return (*gs2)->priority - (*gs1)->priority;
1253 initialise the GENSEC subsystem
1255 NTSTATUS gensec_init(void)
1257 static BOOL initialized = False;
1259 init_module_fn static_init[] = STATIC_gensec_MODULES;
1260 init_module_fn *shared_init;
1262 if (initialized) return NT_STATUS_OK;
1265 shared_init = load_samba_modules(NULL, "gensec");
1267 run_init_functions(static_init);
1268 run_init_functions(shared_init);
1270 talloc_free(shared_init);
1272 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1274 return NT_STATUS_OK;