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"
26 #include "librpc/rpc/dcerpc.h"
27 #include "auth/credentials/credentials.h"
28 #include "auth/gensec/gensec.h"
29 #include "param/param.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 struct cli_credentials *creds)
51 struct gensec_security_ops **new_gensec_list;
52 int i, j, num_mechs_in;
53 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
56 use_kerberos = cli_credentials_get_kerberos_state(creds);
59 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
60 if (!talloc_reference(mem_ctx, old_gensec_list)) {
63 return old_gensec_list;
66 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
70 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
71 if (!new_gensec_list) {
76 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
78 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
79 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
80 new_gensec_list[j] = old_gensec_list[i];
85 switch (use_kerberos) {
86 case CRED_DONT_USE_KERBEROS:
87 if (old_gensec_list[i]->kerberos == false) {
88 new_gensec_list[j] = old_gensec_list[i];
92 case CRED_MUST_USE_KERBEROS:
93 if (old_gensec_list[i]->kerberos == true) {
94 new_gensec_list[j] = old_gensec_list[i];
99 /* Can't happen or invalid parameter */
103 new_gensec_list[j] = NULL;
105 return new_gensec_list;
108 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
111 struct gensec_security_ops **backends;
112 backends = gensec_security_all();
113 if (!gensec_security) {
114 if (!talloc_reference(mem_ctx, backends)) {
119 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
121 if (!talloc_reference(mem_ctx, backends)) {
126 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
130 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
134 struct gensec_security_ops **backends;
135 const struct gensec_security_ops *backend;
136 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
140 backends = gensec_security_mechs(gensec_security, mem_ctx);
141 for (i=0; backends && backends[i]; i++) {
142 if (backends[i]->auth_type == auth_type) {
143 backend = backends[i];
144 talloc_free(mem_ctx);
148 talloc_free(mem_ctx);
153 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
154 const char *oid_string)
157 struct gensec_security_ops **backends;
158 const struct gensec_security_ops *backend;
159 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
163 backends = gensec_security_mechs(gensec_security, mem_ctx);
164 for (i=0; backends && backends[i]; i++) {
165 if (backends[i]->oid) {
166 for (j=0; backends[i]->oid[j]; j++) {
167 if (backends[i]->oid[j] &&
168 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
169 backend = backends[i];
170 talloc_free(mem_ctx);
176 talloc_free(mem_ctx);
181 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
182 const char *sasl_name)
185 struct gensec_security_ops **backends;
186 const struct gensec_security_ops *backend;
187 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
191 backends = gensec_security_mechs(gensec_security, mem_ctx);
192 for (i=0; backends && backends[i]; i++) {
193 if (backends[i]->sasl_name
194 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
195 backend = backends[i];
196 talloc_free(mem_ctx);
200 talloc_free(mem_ctx);
205 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
209 struct gensec_security_ops **backends;
210 const struct gensec_security_ops *backend;
211 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
215 backends = gensec_security_mechs(gensec_security, mem_ctx);
216 for (i=0; backends && backends[i]; i++) {
217 if (backends[i]->name
218 && (strcmp(backends[i]->name, name) == 0)) {
219 backend = backends[i];
220 talloc_free(mem_ctx);
224 talloc_free(mem_ctx);
229 * Return a unique list of security subsystems from those specified in
230 * the list of SASL names.
232 * Use the list of enabled GENSEC mechanisms from the credentials
233 * attached to the gensec_security, and return in our preferred order.
236 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
238 const char **sasl_names)
240 const struct gensec_security_ops **backends_out;
241 struct gensec_security_ops **backends;
243 int num_backends_out = 0;
249 backends = gensec_security_mechs(gensec_security, mem_ctx);
251 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
255 backends_out[0] = NULL;
257 /* Find backends in our preferred order, by walking our list,
258 * then looking in the supplied list */
259 for (i=0; backends && backends[i]; i++) {
260 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
261 if (!backends[i]->sasl_name ||
262 !(strcmp(backends[i]->sasl_name,
263 sasl_names[sasl_idx]) == 0)) {
267 for (k=0; backends_out[k]; k++) {
268 if (backends_out[k] == backends[i]) {
273 if (k < num_backends_out) {
274 /* already in there */
278 backends_out = talloc_realloc(mem_ctx, backends_out,
279 const struct gensec_security_ops *,
280 num_backends_out + 2);
285 backends_out[num_backends_out] = backends[i];
287 backends_out[num_backends_out] = NULL;
294 * Return a unique list of security subsystems from those specified in
295 * the OID list. That is, where two OIDs refer to the same module,
296 * return that module only once.
298 * Use the list of enabled GENSEC mechanisms from the credentials
299 * attached to the gensec_security, and return in our preferred order.
302 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
304 const char **oid_strings,
307 struct gensec_security_ops_wrapper *backends_out;
308 struct gensec_security_ops **backends;
309 int i, j, k, oid_idx;
310 int num_backends_out = 0;
316 backends = gensec_security_mechs(gensec_security, gensec_security);
318 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
322 backends_out[0].op = NULL;
323 backends_out[0].oid = NULL;
325 /* Find backends in our preferred order, by walking our list,
326 * then looking in the supplied list */
327 for (i=0; backends && backends[i]; i++) {
328 if (!backends[i]->oid) {
331 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
332 if (strcmp(oid_strings[oid_idx], skip) == 0) {
336 for (j=0; backends[i]->oid[j]; j++) {
337 if (!backends[i]->oid[j] ||
338 !(strcmp(backends[i]->oid[j],
339 oid_strings[oid_idx]) == 0)) {
343 for (k=0; backends_out[k].op; k++) {
344 if (backends_out[k].op == backends[i]) {
349 if (k < num_backends_out) {
350 /* already in there */
354 backends_out = talloc_realloc(mem_ctx, backends_out,
355 struct gensec_security_ops_wrapper,
356 num_backends_out + 2);
361 backends_out[num_backends_out].op = backends[i];
362 backends_out[num_backends_out].oid = backends[i]->oid[j];
364 backends_out[num_backends_out].op = NULL;
365 backends_out[num_backends_out].oid = NULL;
373 * Return OIDS from the security subsystems listed
376 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
377 struct gensec_security_ops **ops,
383 const char **oid_list;
387 oid_list = talloc_array(mem_ctx, const char *, 1);
392 for (i=0; ops && ops[i]; i++) {
397 for (k = 0; ops[i]->oid[k]; k++) {
398 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
400 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
404 oid_list[j] = ops[i]->oid[k];
415 * Return OIDS from the security subsystems listed
418 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
419 const struct gensec_security_ops_wrapper *wops)
424 const char **oid_list;
428 oid_list = talloc_array(mem_ctx, const char *, 1);
433 for (i=0; wops[i].op; i++) {
434 if (!wops[i].op->oid) {
438 for (k = 0; wops[i].op->oid[k]; k++) {
439 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
443 oid_list[j] = wops[i].op->oid[k];
453 * Return all the security subsystems currently enabled on a GENSEC context.
455 * This is taken from a list attached to the cli_credentials, and
456 * skips the OID in 'skip'. (Typically the SPNEGO OID)
460 const char **gensec_security_oids(struct gensec_security *gensec_security,
464 struct gensec_security_ops **ops
465 = gensec_security_mechs(gensec_security, mem_ctx);
466 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
472 Start the GENSEC system, returning a context pointer.
473 @param mem_ctx The parent TALLOC memory context.
474 @param gensec_security Returned GENSEC context pointer.
475 @note The mem_ctx is only a parent and may be NULL.
477 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
478 struct event_context *ev,
479 struct loadparm_context *lp_ctx,
480 struct messaging_context *msg,
481 struct gensec_security **gensec_security)
483 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
484 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
486 (*gensec_security)->ops = NULL;
488 ZERO_STRUCT((*gensec_security)->target);
489 ZERO_STRUCT((*gensec_security)->peer_addr);
490 ZERO_STRUCT((*gensec_security)->my_addr);
492 (*gensec_security)->subcontext = false;
493 (*gensec_security)->want_features = 0;
496 ev = event_context_init(*gensec_security);
498 talloc_free(*gensec_security);
499 return NT_STATUS_NO_MEMORY;
503 (*gensec_security)->event_ctx = ev;
504 (*gensec_security)->msg_ctx = msg;
505 (*gensec_security)->lp_ctx = lp_ctx;
511 * Start a GENSEC subcontext, with a copy of the properties of the parent
512 * @param mem_ctx The parent TALLOC memory context.
513 * @param parent The parent GENSEC context
514 * @param gensec_security Returned GENSEC context pointer.
515 * @note Used by SPNEGO in particular, for the actual implementation mechanism
518 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
519 struct gensec_security *parent,
520 struct gensec_security **gensec_security)
522 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
523 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
525 (**gensec_security) = *parent;
526 (*gensec_security)->ops = NULL;
527 (*gensec_security)->private_data = NULL;
529 (*gensec_security)->subcontext = true;
530 (*gensec_security)->event_ctx = parent->event_ctx;
531 (*gensec_security)->msg_ctx = parent->msg_ctx;
532 (*gensec_security)->lp_ctx = parent->lp_ctx;
538 Start the GENSEC system, in client mode, returning a context pointer.
539 @param mem_ctx The parent TALLOC memory context.
540 @param gensec_security Returned GENSEC context pointer.
541 @note The mem_ctx is only a parent and may be NULL.
543 _PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx,
544 struct gensec_security **gensec_security,
545 struct event_context *ev,
546 struct loadparm_context *lp_ctx)
549 struct event_context *new_ev = NULL;
552 new_ev = event_context_init(mem_ctx);
553 NT_STATUS_HAVE_NO_MEMORY(new_ev);
557 status = gensec_start(mem_ctx, ev, lp_ctx, NULL, gensec_security);
558 if (!NT_STATUS_IS_OK(status)) {
562 talloc_steal((*gensec_security), new_ev);
563 (*gensec_security)->gensec_role = GENSEC_CLIENT;
569 Start the GENSEC system, in server mode, returning a context pointer.
570 @param mem_ctx The parent TALLOC memory context.
571 @param gensec_security Returned GENSEC context pointer.
572 @note The mem_ctx is only a parent and may be NULL.
574 NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
575 struct event_context *ev,
576 struct loadparm_context *lp_ctx,
577 struct messaging_context *msg,
578 struct gensec_security **gensec_security)
583 DEBUG(0,("gensec_server_start: no event context given!\n"));
584 return NT_STATUS_INTERNAL_ERROR;
588 DEBUG(0,("gensec_server_start: no messaging context given!\n"));
589 return NT_STATUS_INTERNAL_ERROR;
592 status = gensec_start(mem_ctx, ev, lp_ctx, msg, gensec_security);
593 if (!NT_STATUS_IS_OK(status)) {
596 (*gensec_security)->gensec_role = GENSEC_SERVER;
601 static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
604 DEBUG(5, ("Starting GENSEC %smechanism %s\n",
605 gensec_security->subcontext ? "sub" : "",
606 gensec_security->ops->name));
607 switch (gensec_security->gensec_role) {
609 if (gensec_security->ops->client_start) {
610 status = gensec_security->ops->client_start(gensec_security);
611 if (!NT_STATUS_IS_OK(status)) {
612 DEBUG(2, ("Failed to start GENSEC client mech %s: %s\n",
613 gensec_security->ops->name, nt_errstr(status)));
619 if (gensec_security->ops->server_start) {
620 status = gensec_security->ops->server_start(gensec_security);
621 if (!NT_STATUS_IS_OK(status)) {
622 DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
623 gensec_security->ops->name, nt_errstr(status)));
629 return NT_STATUS_INVALID_PARAMETER;
633 * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number
634 * @param gensec_security GENSEC context pointer.
635 * @param auth_type DCERPC auth type
636 * @param auth_level DCERPC auth level
639 NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
640 uint8_t auth_type, uint8_t auth_level)
642 gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type);
643 if (!gensec_security->ops) {
644 DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type));
645 return NT_STATUS_INVALID_PARAMETER;
647 gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE);
648 gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES);
649 if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
650 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
651 } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
652 gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
653 gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
654 } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
655 /* Default features */
657 DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n",
659 return NT_STATUS_INVALID_PARAMETER;
662 return gensec_start_mech(gensec_security);
665 const char *gensec_get_name_by_authtype(uint8_t authtype)
667 const struct gensec_security_ops *ops;
668 ops = gensec_security_by_authtype(NULL, authtype);
676 const char *gensec_get_name_by_oid(const char *oid_string)
678 const struct gensec_security_ops *ops;
679 ops = gensec_security_by_oid(NULL, oid_string);
688 * Start a GENSEC sub-mechanism with a specifed mechansim structure, used in SPNEGO
692 NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security,
693 const struct gensec_security_ops *ops)
695 gensec_security->ops = ops;
696 return gensec_start_mech(gensec_security);
700 * Start a GENSEC sub-mechanism by OID, used in SPNEGO
702 * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a
703 * well-known #define to hook it in.
706 NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
707 const char *mech_oid)
709 gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid);
710 if (!gensec_security->ops) {
711 DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
712 return NT_STATUS_INVALID_PARAMETER;
714 return gensec_start_mech(gensec_security);
718 * Start a GENSEC sub-mechanism by a well know SASL name
722 NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
723 const char *sasl_name)
725 gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name);
726 if (!gensec_security->ops) {
727 DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
728 return NT_STATUS_INVALID_PARAMETER;
730 return gensec_start_mech(gensec_security);
734 * Start a GENSEC sub-mechanism with the preferred option from a SASL name list
738 _PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security,
739 const char **sasl_names)
741 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
742 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
743 const struct gensec_security_ops **ops;
746 return NT_STATUS_NO_MEMORY;
748 ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names);
750 DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n",
751 str_list_join(mem_ctx,
753 talloc_free(mem_ctx);
754 return NT_STATUS_INVALID_PARAMETER;
756 for (i=0; ops[i]; i++) {
757 nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]);
758 if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) {
762 talloc_free(mem_ctx);
767 * Start a GENSEC sub-mechanism by an internal name
771 NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security,
774 gensec_security->ops = gensec_security_by_name(gensec_security, name);
775 if (!gensec_security->ops) {
776 DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name));
777 return NT_STATUS_INVALID_PARAMETER;
779 return gensec_start_mech(gensec_security);
783 wrappers for the gensec function pointers
785 NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
787 uint8_t *data, size_t length,
788 const uint8_t *whole_pdu, size_t pdu_length,
789 const DATA_BLOB *sig)
791 if (!gensec_security->ops->unseal_packet) {
792 return NT_STATUS_NOT_IMPLEMENTED;
794 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
795 return NT_STATUS_INVALID_PARAMETER;
798 return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
800 whole_pdu, pdu_length,
804 NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
806 const uint8_t *data, size_t length,
807 const uint8_t *whole_pdu, size_t pdu_length,
808 const DATA_BLOB *sig)
810 if (!gensec_security->ops->check_packet) {
811 return NT_STATUS_NOT_IMPLEMENTED;
813 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
814 return NT_STATUS_INVALID_PARAMETER;
817 return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
820 NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
822 uint8_t *data, size_t length,
823 const uint8_t *whole_pdu, size_t pdu_length,
826 if (!gensec_security->ops->seal_packet) {
827 return NT_STATUS_NOT_IMPLEMENTED;
829 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
830 return NT_STATUS_INVALID_PARAMETER;
833 return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
836 NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
838 const uint8_t *data, size_t length,
839 const uint8_t *whole_pdu, size_t pdu_length,
842 if (!gensec_security->ops->sign_packet) {
843 return NT_STATUS_NOT_IMPLEMENTED;
845 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
846 return NT_STATUS_INVALID_PARAMETER;
849 return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
852 size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
854 if (!gensec_security->ops->sig_size) {
857 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
861 return gensec_security->ops->sig_size(gensec_security, data_size);
864 size_t gensec_max_wrapped_size(struct gensec_security *gensec_security)
866 if (!gensec_security->ops->max_wrapped_size) {
870 return gensec_security->ops->max_wrapped_size(gensec_security);
873 size_t gensec_max_input_size(struct gensec_security *gensec_security)
875 if (!gensec_security->ops->max_input_size) {
876 return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17);
879 return gensec_security->ops->max_input_size(gensec_security);
882 NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
887 if (!gensec_security->ops->wrap) {
888 return NT_STATUS_NOT_IMPLEMENTED;
890 return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
893 NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
898 if (!gensec_security->ops->unwrap) {
899 return NT_STATUS_NOT_IMPLEMENTED;
901 return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
904 NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
905 DATA_BLOB *session_key)
907 if (!gensec_security->ops->session_key) {
908 return NT_STATUS_NOT_IMPLEMENTED;
910 if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SESSION_KEY)) {
911 return NT_STATUS_NO_USER_SESSION_KEY;
914 return gensec_security->ops->session_key(gensec_security, session_key);
918 * Return the credentials of a logged on user, including session keys
921 * Only valid after a successful authentication
923 * May only be called once per authentication.
927 NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
928 struct auth_session_info **session_info)
930 if (!gensec_security->ops->session_info) {
931 return NT_STATUS_NOT_IMPLEMENTED;
933 return gensec_security->ops->session_info(gensec_security, session_info);
937 * Next state function for the GENSEC state machine
939 * @param gensec_security GENSEC State
940 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
941 * @param in The request, as a DATA_BLOB
942 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
943 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
944 * or NT_STATUS_OK if the user is authenticated.
947 _PUBLIC_ NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
948 const DATA_BLOB in, DATA_BLOB *out)
950 return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
953 static void gensec_update_async_timed_handler(struct event_context *ev, struct timed_event *te,
954 struct timeval t, void *ptr)
956 struct gensec_update_request *req = talloc_get_type(ptr, struct gensec_update_request);
957 req->status = req->gensec_security->ops->update(req->gensec_security, req, req->in, &req->out);
958 req->callback.fn(req, req->callback.private_data);
962 * Next state function for the GENSEC state machine async version
964 * @param gensec_security GENSEC State
965 * @param in The request, as a DATA_BLOB
966 * @param callback The function that will be called when the operation is
967 * finished, it should return gensec_update_recv() to get output
968 * @param private_data A private pointer that will be passed to the callback function
971 _PUBLIC_ void gensec_update_send(struct gensec_security *gensec_security, const DATA_BLOB in,
972 void (*callback)(struct gensec_update_request *req, void *private_data),
975 struct gensec_update_request *req = NULL;
976 struct timed_event *te = NULL;
978 req = talloc(gensec_security, struct gensec_update_request);
979 if (!req) goto failed;
980 req->gensec_security = gensec_security;
982 req->out = data_blob(NULL, 0);
983 req->callback.fn = callback;
984 req->callback.private_data = private_data;
986 te = event_add_timed(gensec_security->event_ctx, req,
988 gensec_update_async_timed_handler, req);
989 if (!te) goto failed;
995 callback(NULL, private_data);
999 * Next state function for the GENSEC state machine
1001 * @param req GENSEC update request state
1002 * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
1003 * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
1004 * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
1005 * or NT_STATUS_OK if the user is authenticated.
1007 _PUBLIC_ NTSTATUS gensec_update_recv(struct gensec_update_request *req, TALLOC_CTX *out_mem_ctx, DATA_BLOB *out)
1011 NT_STATUS_HAVE_NO_MEMORY(req);
1014 talloc_steal(out_mem_ctx, out->data);
1015 status = req->status;
1022 * Set the requirement for a certain feature on the connection
1026 _PUBLIC_ void gensec_want_feature(struct gensec_security *gensec_security,
1029 gensec_security->want_features |= feature;
1033 * Check the requirement for a certain feature on the connection
1037 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1040 if (!gensec_security->ops->have_feature) {
1044 /* We might 'have' features that we don't 'want', because the
1045 * other end demanded them, or we can't neotiate them off */
1046 return gensec_security->ops->have_feature(gensec_security, feature);
1050 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1054 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1056 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1057 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1058 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1059 return NT_STATUS_OK;
1063 * Return the credentials structure associated with a GENSEC context
1067 struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1069 if (!gensec_security) {
1072 return gensec_security->credentials;
1076 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1080 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1082 gensec_security->target.service = talloc_strdup(gensec_security, service);
1083 if (!gensec_security->target.service) {
1084 return NT_STATUS_NO_MEMORY;
1086 return NT_STATUS_OK;
1089 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1091 if (gensec_security->target.service) {
1092 return gensec_security->target.service;
1099 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1103 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1105 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1106 if (hostname && !gensec_security->target.hostname) {
1107 return NT_STATUS_NO_MEMORY;
1109 return NT_STATUS_OK;
1112 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1114 /* We allow the target hostname to be overriden for testing purposes */
1115 const char *target_hostname = lp_parm_string(gensec_security->lp_ctx, NULL, "gensec", "target_hostname");
1116 if (target_hostname) {
1117 return target_hostname;
1120 if (gensec_security->target.hostname) {
1121 return gensec_security->target.hostname;
1124 /* We could add use the 'set sockaddr' call, and do a reverse
1125 * lookup, but this would be both insecure (compromising the
1126 * way kerberos works) and add DNS timeouts */
1131 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1133 * This is so that kerberos can include these addresses in
1134 * cryptographic tokens, to avoid certain attacks.
1137 NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1139 gensec_security->my_addr = my_addr;
1140 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1141 return NT_STATUS_NO_MEMORY;
1143 return NT_STATUS_OK;
1146 NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1148 gensec_security->peer_addr = peer_addr;
1149 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1150 return NT_STATUS_NO_MEMORY;
1152 return NT_STATUS_OK;
1155 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1157 if (gensec_security->my_addr) {
1158 return gensec_security->my_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. */
1166 struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1168 if (gensec_security->peer_addr) {
1169 return gensec_security->peer_addr;
1172 /* We could add a 'set sockaddr' call, and do a lookup. This
1173 * would avoid needing to do system calls if nothing asks.
1174 * However, this is not appropriate for the peer addres on
1175 * datagram sockets */
1182 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1183 * - ensures it is talloc()ed
1187 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1189 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1190 if (!gensec_security->target.principal) {
1191 return NT_STATUS_NO_MEMORY;
1193 return NT_STATUS_OK;
1196 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1198 if (gensec_security->target.principal) {
1199 return gensec_security->target.principal;
1206 register a GENSEC backend.
1208 The 'name' can be later used by other backends to find the operations
1209 structure for this backend.
1211 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1213 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1214 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1215 return NT_STATUS_OK;
1218 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1219 /* its already registered! */
1220 DEBUG(0,("GENSEC backend '%s' already registered\n",
1222 return NT_STATUS_OBJECT_NAME_COLLISION;
1225 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1226 generic_security_ops,
1227 struct gensec_security_ops *,
1228 gensec_num_backends+2);
1229 if (!generic_security_ops) {
1230 return NT_STATUS_NO_MEMORY;
1233 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1234 gensec_num_backends++;
1235 generic_security_ops[gensec_num_backends] = NULL;
1237 DEBUG(3,("GENSEC backend '%s' registered\n",
1240 return NT_STATUS_OK;
1244 return the GENSEC interface version, and the size of some critical types
1245 This can be used by backends to either detect compilation errors, or provide
1246 multiple implementations for different smbd compilation options in one module
1248 const struct gensec_critical_sizes *gensec_interface_version(void)
1250 static const struct gensec_critical_sizes critical_sizes = {
1251 GENSEC_INTERFACE_VERSION,
1252 sizeof(struct gensec_security_ops),
1253 sizeof(struct gensec_security),
1256 return &critical_sizes;
1259 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1260 return (*gs2)->priority - (*gs1)->priority;
1264 initialise the GENSEC subsystem
1266 NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1268 static bool initialized = false;
1269 extern NTSTATUS gensec_sasl_init(void);
1270 extern NTSTATUS gensec_krb5_init(void);
1271 extern NTSTATUS gensec_schannel_init(void);
1272 extern NTSTATUS gensec_spnego_init(void);
1273 extern NTSTATUS gensec_gssapi_init(void);
1274 extern NTSTATUS gensec_ntlmssp_init(void);
1276 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1277 init_module_fn *shared_init;
1279 if (initialized) return NT_STATUS_OK;
1282 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1284 run_init_functions(static_init);
1285 run_init_functions(shared_init);
1287 talloc_free(shared_init);
1289 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1291 return NT_STATUS_OK;