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 "auth/gensec/gensec_proto.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 _PUBLIC_ 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 _PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx,
49 struct gensec_security_ops **old_gensec_list,
50 struct cli_credentials *creds)
52 struct gensec_security_ops **new_gensec_list;
53 int i, j, num_mechs_in;
54 enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS;
57 use_kerberos = cli_credentials_get_kerberos_state(creds);
60 if (use_kerberos == CRED_AUTO_USE_KERBEROS) {
61 if (!talloc_reference(mem_ctx, old_gensec_list)) {
64 return old_gensec_list;
67 for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
71 new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1);
72 if (!new_gensec_list) {
77 for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
79 for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) {
80 if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) {
81 new_gensec_list[j] = old_gensec_list[i];
86 switch (use_kerberos) {
87 case CRED_DONT_USE_KERBEROS:
88 if (old_gensec_list[i]->kerberos == false) {
89 new_gensec_list[j] = old_gensec_list[i];
93 case CRED_MUST_USE_KERBEROS:
94 if (old_gensec_list[i]->kerberos == true) {
95 new_gensec_list[j] = old_gensec_list[i];
100 /* Can't happen or invalid parameter */
104 new_gensec_list[j] = NULL;
106 return new_gensec_list;
109 struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security,
112 struct gensec_security_ops **backends;
113 backends = gensec_security_all();
114 if (!gensec_security) {
115 if (!talloc_reference(mem_ctx, backends)) {
120 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
122 if (!talloc_reference(mem_ctx, backends)) {
127 return gensec_use_kerberos_mechs(mem_ctx, backends, creds);
131 static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security,
135 struct gensec_security_ops **backends;
136 const struct gensec_security_ops *backend;
137 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
141 backends = gensec_security_mechs(gensec_security, mem_ctx);
142 for (i=0; backends && backends[i]; i++) {
143 if (backends[i]->auth_type == auth_type) {
144 backend = backends[i];
145 talloc_free(mem_ctx);
149 talloc_free(mem_ctx);
154 const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security,
155 const char *oid_string)
158 struct gensec_security_ops **backends;
159 const struct gensec_security_ops *backend;
160 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
164 backends = gensec_security_mechs(gensec_security, mem_ctx);
165 for (i=0; backends && backends[i]; i++) {
166 if (backends[i]->oid) {
167 for (j=0; backends[i]->oid[j]; j++) {
168 if (backends[i]->oid[j] &&
169 (strcmp(backends[i]->oid[j], oid_string) == 0)) {
170 backend = backends[i];
171 talloc_free(mem_ctx);
177 talloc_free(mem_ctx);
182 const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security,
183 const char *sasl_name)
186 struct gensec_security_ops **backends;
187 const struct gensec_security_ops *backend;
188 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
192 backends = gensec_security_mechs(gensec_security, mem_ctx);
193 for (i=0; backends && backends[i]; i++) {
194 if (backends[i]->sasl_name
195 && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
196 backend = backends[i];
197 talloc_free(mem_ctx);
201 talloc_free(mem_ctx);
206 static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
210 struct gensec_security_ops **backends;
211 const struct gensec_security_ops *backend;
212 TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
216 backends = gensec_security_mechs(gensec_security, mem_ctx);
217 for (i=0; backends && backends[i]; i++) {
218 if (backends[i]->name
219 && (strcmp(backends[i]->name, name) == 0)) {
220 backend = backends[i];
221 talloc_free(mem_ctx);
225 talloc_free(mem_ctx);
230 * Return a unique list of security subsystems from those specified in
231 * the list of SASL names.
233 * Use the list of enabled GENSEC mechanisms from the credentials
234 * attached to the gensec_security, and return in our preferred order.
237 const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security,
239 const char **sasl_names)
241 const struct gensec_security_ops **backends_out;
242 struct gensec_security_ops **backends;
244 int num_backends_out = 0;
250 backends = gensec_security_mechs(gensec_security, mem_ctx);
252 backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1);
256 backends_out[0] = NULL;
258 /* Find backends in our preferred order, by walking our list,
259 * then looking in the supplied list */
260 for (i=0; backends && backends[i]; i++) {
261 for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
262 if (!backends[i]->sasl_name ||
263 !(strcmp(backends[i]->sasl_name,
264 sasl_names[sasl_idx]) == 0)) {
268 for (k=0; backends_out[k]; k++) {
269 if (backends_out[k] == backends[i]) {
274 if (k < num_backends_out) {
275 /* already in there */
279 backends_out = talloc_realloc(mem_ctx, backends_out,
280 const struct gensec_security_ops *,
281 num_backends_out + 2);
286 backends_out[num_backends_out] = backends[i];
288 backends_out[num_backends_out] = NULL;
295 * Return a unique list of security subsystems from those specified in
296 * the OID list. That is, where two OIDs refer to the same module,
297 * return that module only once.
299 * Use the list of enabled GENSEC mechanisms from the credentials
300 * attached to the gensec_security, and return in our preferred order.
303 const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security,
305 const char **oid_strings,
308 struct gensec_security_ops_wrapper *backends_out;
309 struct gensec_security_ops **backends;
310 int i, j, k, oid_idx;
311 int num_backends_out = 0;
317 backends = gensec_security_mechs(gensec_security, gensec_security);
319 backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1);
323 backends_out[0].op = NULL;
324 backends_out[0].oid = NULL;
326 /* Find backends in our preferred order, by walking our list,
327 * then looking in the supplied list */
328 for (i=0; backends && backends[i]; i++) {
329 if (!backends[i]->oid) {
332 for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) {
333 if (strcmp(oid_strings[oid_idx], skip) == 0) {
337 for (j=0; backends[i]->oid[j]; j++) {
338 if (!backends[i]->oid[j] ||
339 !(strcmp(backends[i]->oid[j],
340 oid_strings[oid_idx]) == 0)) {
344 for (k=0; backends_out[k].op; k++) {
345 if (backends_out[k].op == backends[i]) {
350 if (k < num_backends_out) {
351 /* already in there */
355 backends_out = talloc_realloc(mem_ctx, backends_out,
356 struct gensec_security_ops_wrapper,
357 num_backends_out + 2);
362 backends_out[num_backends_out].op = backends[i];
363 backends_out[num_backends_out].oid = backends[i]->oid[j];
365 backends_out[num_backends_out].op = NULL;
366 backends_out[num_backends_out].oid = NULL;
374 * Return OIDS from the security subsystems listed
377 const char **gensec_security_oids_from_ops(TALLOC_CTX *mem_ctx,
378 struct gensec_security_ops **ops,
384 const char **oid_list;
388 oid_list = talloc_array(mem_ctx, const char *, 1);
393 for (i=0; ops && ops[i]; i++) {
398 for (k = 0; ops[i]->oid[k]; k++) {
399 if (skip && strcmp(skip, ops[i]->oid[k])==0) {
401 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
405 oid_list[j] = ops[i]->oid[k];
416 * Return OIDS from the security subsystems listed
419 const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx,
420 const struct gensec_security_ops_wrapper *wops)
425 const char **oid_list;
429 oid_list = talloc_array(mem_ctx, const char *, 1);
434 for (i=0; wops[i].op; i++) {
435 if (!wops[i].op->oid) {
439 for (k = 0; wops[i].op->oid[k]; k++) {
440 oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2);
444 oid_list[j] = wops[i].op->oid[k];
454 * Return all the security subsystems currently enabled on a GENSEC context.
456 * This is taken from a list attached to the cli_credentials, and
457 * skips the OID in 'skip'. (Typically the SPNEGO OID)
461 const char **gensec_security_oids(struct gensec_security *gensec_security,
465 struct gensec_security_ops **ops
466 = gensec_security_mechs(gensec_security, mem_ctx);
467 return gensec_security_oids_from_ops(mem_ctx, ops, skip);
473 Start the GENSEC system, returning a context pointer.
474 @param mem_ctx The parent TALLOC memory context.
475 @param gensec_security Returned GENSEC context pointer.
476 @note The mem_ctx is only a parent and may be NULL.
478 static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
479 struct event_context *ev,
480 struct gensec_settings *settings,
481 struct messaging_context *msg,
482 struct gensec_security **gensec_security)
485 DEBUG(0, ("No event context available!\n"));
486 return NT_STATUS_INTERNAL_ERROR;
489 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
490 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
492 (*gensec_security)->ops = NULL;
493 (*gensec_security)->private_data = NULL;
495 ZERO_STRUCT((*gensec_security)->target);
496 ZERO_STRUCT((*gensec_security)->peer_addr);
497 ZERO_STRUCT((*gensec_security)->my_addr);
499 (*gensec_security)->subcontext = false;
500 (*gensec_security)->want_features = 0;
502 (*gensec_security)->event_ctx = ev;
503 (*gensec_security)->msg_ctx = msg;
504 (*gensec_security)->settings = talloc_reference(*gensec_security, settings);
510 * Start a GENSEC subcontext, with a copy of the properties of the parent
511 * @param mem_ctx The parent TALLOC memory context.
512 * @param parent The parent GENSEC context
513 * @param gensec_security Returned GENSEC context pointer.
514 * @note Used by SPNEGO in particular, for the actual implementation mechanism
517 _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
518 struct gensec_security *parent,
519 struct gensec_security **gensec_security)
521 (*gensec_security) = talloc(mem_ctx, struct gensec_security);
522 NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
524 (**gensec_security) = *parent;
525 (*gensec_security)->ops = NULL;
526 (*gensec_security)->private_data = NULL;
528 (*gensec_security)->subcontext = true;
529 (*gensec_security)->want_features = parent->want_features;
530 (*gensec_security)->event_ctx = parent->event_ctx;
531 (*gensec_security)->msg_ctx = parent->msg_ctx;
532 (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings);
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 gensec_settings *settings)
550 status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security);
551 if (!NT_STATUS_IS_OK(status)) {
554 (*gensec_security)->gensec_role = GENSEC_CLIENT;
560 Start the GENSEC system, in server mode, returning a context pointer.
561 @param mem_ctx The parent TALLOC memory context.
562 @param gensec_security Returned GENSEC context pointer.
563 @note The mem_ctx is only a parent and may be NULL.
565 _PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx,
566 struct event_context *ev,
567 struct gensec_settings *settings,
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, settings, 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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)
732 NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER;
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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 _PUBLIC_ 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 if (!gensec_security->ops || !gensec_security->ops->want_feature) {
1021 gensec_security->want_features |= feature;
1024 gensec_security->ops->want_feature(gensec_security, feature);
1028 * Check the requirement for a certain feature on the connection
1032 _PUBLIC_ bool gensec_have_feature(struct gensec_security *gensec_security,
1035 if (!gensec_security->ops->have_feature) {
1039 /* We might 'have' features that we don't 'want', because the
1040 * other end demanded them, or we can't neotiate them off */
1041 return gensec_security->ops->have_feature(gensec_security, feature);
1045 * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context
1049 _PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
1051 gensec_security->credentials = talloc_reference(gensec_security, credentials);
1052 NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials);
1053 gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials));
1054 return NT_STATUS_OK;
1058 * Return the credentials structure associated with a GENSEC context
1062 _PUBLIC_ struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
1064 if (!gensec_security) {
1067 return gensec_security->credentials;
1071 * Set the target service (such as 'http' or 'host') on a GENSEC context - ensures it is talloc()ed
1075 _PUBLIC_ NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
1077 gensec_security->target.service = talloc_strdup(gensec_security, service);
1078 if (!gensec_security->target.service) {
1079 return NT_STATUS_NO_MEMORY;
1081 return NT_STATUS_OK;
1084 _PUBLIC_ const char *gensec_get_target_service(struct gensec_security *gensec_security)
1086 if (gensec_security->target.service) {
1087 return gensec_security->target.service;
1094 * Set the target hostname (suitable for kerberos resolutation) on a GENSEC context - ensures it is talloc()ed
1098 _PUBLIC_ NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
1100 gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
1101 if (hostname && !gensec_security->target.hostname) {
1102 return NT_STATUS_NO_MEMORY;
1104 return NT_STATUS_OK;
1107 _PUBLIC_ const char *gensec_get_target_hostname(struct gensec_security *gensec_security)
1109 /* We allow the target hostname to be overriden for testing purposes */
1110 if (gensec_security->settings->target_hostname) {
1111 return gensec_security->settings->target_hostname;
1114 if (gensec_security->target.hostname) {
1115 return gensec_security->target.hostname;
1118 /* We could add use the 'set sockaddr' call, and do a reverse
1119 * lookup, but this would be both insecure (compromising the
1120 * way kerberos works) and add DNS timeouts */
1125 * Set (and talloc_reference) local and peer socket addresses onto a socket context on the GENSEC context
1127 * This is so that kerberos can include these addresses in
1128 * cryptographic tokens, to avoid certain attacks.
1131 _PUBLIC_ NTSTATUS gensec_set_my_addr(struct gensec_security *gensec_security, struct socket_address *my_addr)
1133 gensec_security->my_addr = my_addr;
1134 if (my_addr && !talloc_reference(gensec_security, my_addr)) {
1135 return NT_STATUS_NO_MEMORY;
1137 return NT_STATUS_OK;
1140 _PUBLIC_ NTSTATUS gensec_set_peer_addr(struct gensec_security *gensec_security, struct socket_address *peer_addr)
1142 gensec_security->peer_addr = peer_addr;
1143 if (peer_addr && !talloc_reference(gensec_security, peer_addr)) {
1144 return NT_STATUS_NO_MEMORY;
1146 return NT_STATUS_OK;
1149 struct socket_address *gensec_get_my_addr(struct gensec_security *gensec_security)
1151 if (gensec_security->my_addr) {
1152 return gensec_security->my_addr;
1155 /* We could add a 'set sockaddr' call, and do a lookup. This
1156 * would avoid needing to do system calls if nothing asks. */
1160 _PUBLIC_ struct socket_address *gensec_get_peer_addr(struct gensec_security *gensec_security)
1162 if (gensec_security->peer_addr) {
1163 return gensec_security->peer_addr;
1166 /* We could add a 'set sockaddr' call, and do a lookup. This
1167 * would avoid needing to do system calls if nothing asks.
1168 * However, this is not appropriate for the peer addres on
1169 * datagram sockets */
1176 * Set the target principal (assuming it it known, say from the SPNEGO reply)
1177 * - ensures it is talloc()ed
1181 NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
1183 gensec_security->target.principal = talloc_strdup(gensec_security, principal);
1184 if (!gensec_security->target.principal) {
1185 return NT_STATUS_NO_MEMORY;
1187 return NT_STATUS_OK;
1190 const char *gensec_get_target_principal(struct gensec_security *gensec_security)
1192 if (gensec_security->target.principal) {
1193 return gensec_security->target.principal;
1200 register a GENSEC backend.
1202 The 'name' can be later used by other backends to find the operations
1203 structure for this backend.
1205 NTSTATUS gensec_register(const struct gensec_security_ops *ops)
1207 if (!lp_parm_bool(global_loadparm, NULL, "gensec", ops->name, ops->enabled)) {
1208 DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
1209 return NT_STATUS_OK;
1212 if (gensec_security_by_name(NULL, ops->name) != NULL) {
1213 /* its already registered! */
1214 DEBUG(0,("GENSEC backend '%s' already registered\n",
1216 return NT_STATUS_OBJECT_NAME_COLLISION;
1219 generic_security_ops = talloc_realloc(talloc_autofree_context(),
1220 generic_security_ops,
1221 struct gensec_security_ops *,
1222 gensec_num_backends+2);
1223 if (!generic_security_ops) {
1224 return NT_STATUS_NO_MEMORY;
1227 generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops);
1228 gensec_num_backends++;
1229 generic_security_ops[gensec_num_backends] = NULL;
1231 DEBUG(3,("GENSEC backend '%s' registered\n",
1234 return NT_STATUS_OK;
1238 return the GENSEC interface version, and the size of some critical types
1239 This can be used by backends to either detect compilation errors, or provide
1240 multiple implementations for different smbd compilation options in one module
1242 const struct gensec_critical_sizes *gensec_interface_version(void)
1244 static const struct gensec_critical_sizes critical_sizes = {
1245 GENSEC_INTERFACE_VERSION,
1246 sizeof(struct gensec_security_ops),
1247 sizeof(struct gensec_security),
1250 return &critical_sizes;
1253 static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) {
1254 return (*gs2)->priority - (*gs1)->priority;
1257 int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value)
1259 return lp_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value);
1262 bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value)
1264 return lp_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value);
1268 initialise the GENSEC subsystem
1270 _PUBLIC_ NTSTATUS gensec_init(struct loadparm_context *lp_ctx)
1272 static bool initialized = false;
1273 extern NTSTATUS gensec_sasl_init(void);
1274 extern NTSTATUS gensec_krb5_init(void);
1275 extern NTSTATUS gensec_schannel_init(void);
1276 extern NTSTATUS gensec_spnego_init(void);
1277 extern NTSTATUS gensec_gssapi_init(void);
1278 extern NTSTATUS gensec_ntlmssp_init(void);
1280 init_module_fn static_init[] = { STATIC_gensec_MODULES };
1281 init_module_fn *shared_init;
1283 if (initialized) return NT_STATUS_OK;
1286 shared_init = load_samba_modules(NULL, lp_ctx, "gensec");
1288 run_init_functions(static_init);
1289 run_init_functions(shared_init);
1291 talloc_free(shared_init);
1293 qsort(generic_security_ops, gensec_num_backends, sizeof(*generic_security_ops), QSORT_CAST sort_gensec);
1295 return NT_STATUS_OK;