From fe02752ed6493efb7af28faa3d64d9fd7895d6f1 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Oct 2011 17:24:12 +1100 Subject: auth: move gensec_start.c to the top level This does not change who uses gensec for now, but makes it possible to write new gensec modules outside source4/ Andrew Bartlett --- auth/gensec/gensec.pc.in | 11 + auth/gensec/gensec_start.c | 919 +++++++++++++++++++++++++++++++++++ auth/gensec/wscript_build | 14 +- source3/wscript_build | 2 +- source4/auth/gensec/cyrus_sasl.c | 1 + source4/auth/gensec/gensec.pc.in | 11 - source4/auth/gensec/gensec_start.c | 952 ------------------------------------- source4/auth/gensec/gensec_util.c | 59 +++ source4/auth/gensec/schannel.c | 1 + source4/auth/gensec/wscript_build | 13 +- source4/auth/ntlmssp/ntlmssp.c | 1 + 11 files changed, 1006 insertions(+), 978 deletions(-) create mode 100644 auth/gensec/gensec.pc.in create mode 100644 auth/gensec/gensec_start.c delete mode 100644 source4/auth/gensec/gensec.pc.in delete mode 100644 source4/auth/gensec/gensec_start.c create mode 100644 source4/auth/gensec/gensec_util.c diff --git a/auth/gensec/gensec.pc.in b/auth/gensec/gensec.pc.in new file mode 100644 index 0000000000..f32226d5e4 --- /dev/null +++ b/auth/gensec/gensec.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +modulesdir=${prefix}/modules/gensec + +Name: gensec +Description: Generic Security Library +Version: @PACKAGE_VERSION@ +Libs: @LIB_RPATH@ -L${libdir} -lgensec +Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c new file mode 100644 index 0000000000..1322469dbe --- /dev/null +++ b/auth/gensec/gensec_start.c @@ -0,0 +1,919 @@ +/* + Unix SMB/CIFS implementation. + + Generic Authentication Interface + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Bartlett 2004-2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "system/network.h" +#include "lib/events/events.h" +#include "lib/socket/socket.h" +#include "lib/tsocket/tsocket.h" +#include "../lib/util/tevent_ntstatus.h" +#include "librpc/rpc/dcerpc.h" +#include "auth/credentials/credentials.h" +#include "auth/gensec/gensec.h" +#include "auth/gensec/gensec_proto.h" +#include "auth/auth.h" +#include "auth/system_session_proto.h" +#include "param/param.h" +#include "lib/util/tsort.h" +#include "auth/gensec/gensec_toplevel_proto.h" +#include "lib/util/samba_modules.h" + +/* the list of currently registered GENSEC backends */ +static struct gensec_security_ops **generic_security_ops; +static int gensec_num_backends; + +/* Return all the registered mechs. Don't modify the return pointer, + * but you may talloc_reference it if convient */ +_PUBLIC_ struct gensec_security_ops **gensec_security_all(void) +{ + return generic_security_ops; +} + +bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security) +{ + return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled); +} + +/* Sometimes we want to force only kerberos, sometimes we want to + * force it's avoidance. The old list could be either + * gensec_security_all(), or from cli_credentials_gensec_list() (ie, + * an existing list we have trimmed down) */ + +_PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, + struct gensec_security_ops **old_gensec_list, + struct cli_credentials *creds) +{ + struct gensec_security_ops **new_gensec_list; + int i, j, num_mechs_in; + enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS; + + if (creds) { + use_kerberos = cli_credentials_get_kerberos_state(creds); + } + + if (use_kerberos == CRED_AUTO_USE_KERBEROS) { + if (!talloc_reference(mem_ctx, old_gensec_list)) { + return NULL; + } + return old_gensec_list; + } + + for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) { + /* noop */ + } + + new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1); + if (!new_gensec_list) { + return NULL; + } + + j = 0; + for (i=0; old_gensec_list && old_gensec_list[i]; i++) { + int oid_idx; + + for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) { + if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) { + new_gensec_list[j] = old_gensec_list[i]; + j++; + break; + } + } + switch (use_kerberos) { + case CRED_DONT_USE_KERBEROS: + if (old_gensec_list[i]->kerberos == false) { + new_gensec_list[j] = old_gensec_list[i]; + j++; + } + break; + case CRED_MUST_USE_KERBEROS: + if (old_gensec_list[i]->kerberos == true) { + new_gensec_list[j] = old_gensec_list[i]; + j++; + } + break; + default: + /* Can't happen or invalid parameter */ + return NULL; + } + } + new_gensec_list[j] = NULL; + + return new_gensec_list; +} + +struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx) +{ + struct gensec_security_ops **backends; + backends = gensec_security_all(); + if (!gensec_security) { + if (!talloc_reference(mem_ctx, backends)) { + return NULL; + } + return backends; + } else { + struct cli_credentials *creds = gensec_get_credentials(gensec_security); + if (!creds) { + if (!talloc_reference(mem_ctx, backends)) { + return NULL; + } + return backends; + } + return gensec_use_kerberos_mechs(mem_ctx, backends, creds); + } +} + +static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security, + uint8_t auth_type) +{ + int i; + struct gensec_security_ops **backends; + const struct gensec_security_ops *backend; + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + if (!mem_ctx) { + return NULL; + } + backends = gensec_security_mechs(gensec_security, mem_ctx); + for (i=0; backends && backends[i]; i++) { + if (!gensec_security_ops_enabled(backends[i], gensec_security)) + continue; + if (backends[i]->auth_type == auth_type) { + backend = backends[i]; + talloc_free(mem_ctx); + return backend; + } + } + talloc_free(mem_ctx); + + return NULL; +} + +const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security, + const char *oid_string) +{ + int i, j; + struct gensec_security_ops **backends; + const struct gensec_security_ops *backend; + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + if (!mem_ctx) { + return NULL; + } + backends = gensec_security_mechs(gensec_security, mem_ctx); + for (i=0; backends && backends[i]; i++) { + if (gensec_security != NULL && + !gensec_security_ops_enabled(backends[i], + gensec_security)) + continue; + if (backends[i]->oid) { + for (j=0; backends[i]->oid[j]; j++) { + if (backends[i]->oid[j] && + (strcmp(backends[i]->oid[j], oid_string) == 0)) { + backend = backends[i]; + talloc_free(mem_ctx); + return backend; + } + } + } + } + talloc_free(mem_ctx); + + return NULL; +} + +const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security, + const char *sasl_name) +{ + int i; + struct gensec_security_ops **backends; + const struct gensec_security_ops *backend; + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + if (!mem_ctx) { + return NULL; + } + backends = gensec_security_mechs(gensec_security, mem_ctx); + for (i=0; backends && backends[i]; i++) { + if (!gensec_security_ops_enabled(backends[i], gensec_security)) + continue; + if (backends[i]->sasl_name + && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) { + backend = backends[i]; + talloc_free(mem_ctx); + return backend; + } + } + talloc_free(mem_ctx); + + return NULL; +} + +static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security, + const char *name) +{ + int i; + struct gensec_security_ops **backends; + const struct gensec_security_ops *backend; + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + if (!mem_ctx) { + return NULL; + } + backends = gensec_security_mechs(gensec_security, mem_ctx); + for (i=0; backends && backends[i]; i++) { + if (gensec_security != NULL && + !gensec_security_ops_enabled(backends[i], gensec_security)) + continue; + if (backends[i]->name + && (strcmp(backends[i]->name, name) == 0)) { + backend = backends[i]; + talloc_free(mem_ctx); + return backend; + } + } + talloc_free(mem_ctx); + return NULL; +} + +/** + * Return a unique list of security subsystems from those specified in + * the list of SASL names. + * + * Use the list of enabled GENSEC mechanisms from the credentials + * attached to the gensec_security, and return in our preferred order. + */ + +const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const char **sasl_names) +{ + const struct gensec_security_ops **backends_out; + struct gensec_security_ops **backends; + int i, k, sasl_idx; + int num_backends_out = 0; + + if (!sasl_names) { + return NULL; + } + + backends = gensec_security_mechs(gensec_security, mem_ctx); + + backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1); + if (!backends_out) { + return NULL; + } + backends_out[0] = NULL; + + /* Find backends in our preferred order, by walking our list, + * then looking in the supplied list */ + for (i=0; backends && backends[i]; i++) { + if (gensec_security != NULL && + !gensec_security_ops_enabled(backends[i], gensec_security)) + continue; + for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) { + if (!backends[i]->sasl_name || + !(strcmp(backends[i]->sasl_name, + sasl_names[sasl_idx]) == 0)) { + continue; + } + + for (k=0; backends_out[k]; k++) { + if (backends_out[k] == backends[i]) { + break; + } + } + + if (k < num_backends_out) { + /* already in there */ + continue; + } + + backends_out = talloc_realloc(mem_ctx, backends_out, + const struct gensec_security_ops *, + num_backends_out + 2); + if (!backends_out) { + return NULL; + } + + backends_out[num_backends_out] = backends[i]; + num_backends_out++; + backends_out[num_backends_out] = NULL; + } + } + return backends_out; +} + +/** + * Return a unique list of security subsystems from those specified in + * the OID list. That is, where two OIDs refer to the same module, + * return that module only once. + * + * Use the list of enabled GENSEC mechanisms from the credentials + * attached to the gensec_security, and return in our preferred order. + */ + +const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const char **oid_strings, + const char *skip) +{ + struct gensec_security_ops_wrapper *backends_out; + struct gensec_security_ops **backends; + int i, j, k, oid_idx; + int num_backends_out = 0; + + if (!oid_strings) { + return NULL; + } + + backends = gensec_security_mechs(gensec_security, gensec_security); + + backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1); + if (!backends_out) { + return NULL; + } + backends_out[0].op = NULL; + backends_out[0].oid = NULL; + + /* Find backends in our preferred order, by walking our list, + * then looking in the supplied list */ + for (i=0; backends && backends[i]; i++) { + if (gensec_security != NULL && + !gensec_security_ops_enabled(backends[i], gensec_security)) + continue; + if (!backends[i]->oid) { + continue; + } + for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) { + if (strcmp(oid_strings[oid_idx], skip) == 0) { + continue; + } + + for (j=0; backends[i]->oid[j]; j++) { + if (!backends[i]->oid[j] || + !(strcmp(backends[i]->oid[j], + oid_strings[oid_idx]) == 0)) { + continue; + } + + for (k=0; backends_out[k].op; k++) { + if (backends_out[k].op == backends[i]) { + break; + } + } + + if (k < num_backends_out) { + /* already in there */ + continue; + } + + backends_out = talloc_realloc(mem_ctx, backends_out, + struct gensec_security_ops_wrapper, + num_backends_out + 2); + if (!backends_out) { + return NULL; + } + + backends_out[num_backends_out].op = backends[i]; + backends_out[num_backends_out].oid = backends[i]->oid[j]; + num_backends_out++; + backends_out[num_backends_out].op = NULL; + backends_out[num_backends_out].oid = NULL; + } + } + } + return backends_out; +} + +/** + * Return OIDS from the security subsystems listed + */ + +const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + struct gensec_security_ops **ops, + const char *skip) +{ + int i; + int j = 0; + int k; + const char **oid_list; + if (!ops) { + return NULL; + } + oid_list = talloc_array(mem_ctx, const char *, 1); + if (!oid_list) { + return NULL; + } + + for (i=0; ops && ops[i]; i++) { + if (gensec_security != NULL && + !gensec_security_ops_enabled(ops[i], gensec_security)) { + continue; + } + if (!ops[i]->oid) { + continue; + } + + for (k = 0; ops[i]->oid[k]; k++) { + if (skip && strcmp(skip, ops[i]->oid[k])==0) { + } else { + oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2); + if (!oid_list) { + return NULL; + } + oid_list[j] = ops[i]->oid[k]; + j++; + } + } + } + oid_list[j] = NULL; + return oid_list; +} + + +/** + * Return OIDS from the security subsystems listed + */ + +const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx, + const struct gensec_security_ops_wrapper *wops) +{ + int i; + int j = 0; + int k; + const char **oid_list; + if (!wops) { + return NULL; + } + oid_list = talloc_array(mem_ctx, const char *, 1); + if (!oid_list) { + return NULL; + } + + for (i=0; wops[i].op; i++) { + if (!wops[i].op->oid) { + continue; + } + + for (k = 0; wops[i].op->oid[k]; k++) { + oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2); + if (!oid_list) { + return NULL; + } + oid_list[j] = wops[i].op->oid[k]; + j++; + } + } + oid_list[j] = NULL; + return oid_list; +} + + +/** + * Return all the security subsystems currently enabled on a GENSEC context. + * + * This is taken from a list attached to the cli_credentials, and + * skips the OID in 'skip'. (Typically the SPNEGO OID) + * + */ + +const char **gensec_security_oids(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const char *skip) +{ + struct gensec_security_ops **ops + = gensec_security_mechs(gensec_security, mem_ctx); + return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip); +} + +/** + Start the GENSEC system, returning a context pointer. + @param mem_ctx The parent TALLOC memory context. + @param gensec_security Returned GENSEC context pointer. + @note The mem_ctx is only a parent and may be NULL. + @note, the auth context is moved to be a referenced pointer of the + @ gensec_security return +*/ +static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_settings *settings, + struct auth4_context *auth_context, + struct gensec_security **gensec_security) +{ + if (ev == NULL) { + DEBUG(0, ("No event context available!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security); + NT_STATUS_HAVE_NO_MEMORY(*gensec_security); + + (*gensec_security)->event_ctx = ev; + SMB_ASSERT(settings->lp_ctx != NULL); + (*gensec_security)->settings = talloc_reference(*gensec_security, settings); + + /* We need to reference this, not steal, as the caller may be + * python, which won't like it if we steal it's object away + * from it */ + (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context); + + return NT_STATUS_OK; +} + +/** + * Start a GENSEC subcontext, with a copy of the properties of the parent + * @param mem_ctx The parent TALLOC memory context. + * @param parent The parent GENSEC context + * @param gensec_security Returned GENSEC context pointer. + * @note Used by SPNEGO in particular, for the actual implementation mechanism + */ + +_PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, + struct gensec_security *parent, + struct gensec_security **gensec_security) +{ + (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security); + NT_STATUS_HAVE_NO_MEMORY(*gensec_security); + + (**gensec_security) = *parent; + (*gensec_security)->ops = NULL; + (*gensec_security)->private_data = NULL; + + (*gensec_security)->subcontext = true; + (*gensec_security)->want_features = parent->want_features; + (*gensec_security)->event_ctx = parent->event_ctx; + (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context); + (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings); + (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context); + + return NT_STATUS_OK; +} + +/** + Start the GENSEC system, in client mode, returning a context pointer. + @param mem_ctx The parent TALLOC memory context. + @param gensec_security Returned GENSEC context pointer. + @note The mem_ctx is only a parent and may be NULL. +*/ +_PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, + struct gensec_security **gensec_security, + struct tevent_context *ev, + struct gensec_settings *settings) +{ + NTSTATUS status; + + if (settings == NULL) { + DEBUG(0,("gensec_client_start: no settings given!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + (*gensec_security)->gensec_role = GENSEC_CLIENT; + + return status; +} + + + +/** + Start the GENSEC system, in server mode, returning a context pointer. + @param mem_ctx The parent TALLOC memory context. + @param gensec_security Returned GENSEC context pointer. + @note The mem_ctx is only a parent and may be NULL. +*/ +_PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct gensec_settings *settings, + struct auth4_context *auth_context, + struct gensec_security **gensec_security) +{ + NTSTATUS status; + + if (!ev) { + DEBUG(0,("gensec_server_start: no event context given!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + if (!settings) { + DEBUG(0,("gensec_server_start: no settings given!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + + status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + (*gensec_security)->gensec_role = GENSEC_SERVER; + + return status; +} + +NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) +{ + NTSTATUS status; + DEBUG(5, ("Starting GENSEC %smechanism %s\n", + gensec_security->subcontext ? "sub" : "", + gensec_security->ops->name)); + switch (gensec_security->gensec_role) { + case GENSEC_CLIENT: + if (gensec_security->ops->client_start) { + status = gensec_security->ops->client_start(gensec_security); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n", + gensec_security->ops->name, nt_errstr(status))); + } + return status; + } + break; + case GENSEC_SERVER: + if (gensec_security->ops->server_start) { + status = gensec_security->ops->server_start(gensec_security); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n", + gensec_security->ops->name, nt_errstr(status))); + } + return status; + } + break; + } + return NT_STATUS_INVALID_PARAMETER; +} + +/** + * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO + * + */ + +NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, + const struct gensec_security_ops *ops) +{ + gensec_security->ops = ops; + return gensec_start_mech(gensec_security); +} + + +/** + * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number + * @param gensec_security GENSEC context pointer. + * @param auth_type DCERPC auth type + * @param auth_level DCERPC auth level + */ + +_PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, + uint8_t auth_type, uint8_t auth_level) +{ + gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type); + if (!gensec_security->ops) { + DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type)); + return NT_STATUS_INVALID_PARAMETER; + } + gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE); + gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES); + if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { + gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); + } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { + gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); + gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL); + } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) { + /* Default features */ + } else { + DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", + auth_level)); + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_start_mech(gensec_security); +} + +_PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype) +{ + const struct gensec_security_ops *ops; + ops = gensec_security_by_authtype(gensec_security, authtype); + if (ops) { + return ops->name; + } + return NULL; +} + + +_PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security, + const char *oid_string) +{ + const struct gensec_security_ops *ops; + ops = gensec_security_by_oid(gensec_security, oid_string); + if (ops) { + return ops->name; + } + return oid_string; +} + +/** + * Start a GENSEC sub-mechanism by OID, used in SPNEGO + * + * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a + * well-known #define to hook it in. + */ + +_PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, + const char *mech_oid) +{ + SMB_ASSERT(gensec_security != NULL); + + gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid); + if (!gensec_security->ops) { + DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid)); + return NT_STATUS_INVALID_PARAMETER; + } + return gensec_start_mech(gensec_security); +} + +/** + * Start a GENSEC sub-mechanism by a well know SASL name + * + */ + +_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, + const char *sasl_name) +{ + gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name); + if (!gensec_security->ops) { + DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name)); + return NT_STATUS_INVALID_PARAMETER; + } + return gensec_start_mech(gensec_security); +} + +/** + * Start a GENSEC sub-mechanism with the preferred option from a SASL name list + * + */ + +_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, + const char **sasl_names) +{ + NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; + TALLOC_CTX *mem_ctx = talloc_new(gensec_security); + const struct gensec_security_ops **ops; + int i; + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names); + if (!ops || !*ops) { + DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", + str_list_join(mem_ctx, + sasl_names, ' '))); + talloc_free(mem_ctx); + return NT_STATUS_INVALID_PARAMETER; + } + for (i=0; ops[i]; i++) { + nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]); + if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { + break; + } + } + talloc_free(mem_ctx); + return nt_status; +} + +/** + * Start a GENSEC sub-mechanism by an internal name + * + */ + +_PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, + const char *name) +{ + gensec_security->ops = gensec_security_by_name(gensec_security, name); + if (!gensec_security->ops) { + DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name)); + return NT_STATUS_INVALID_PARAMETER; + } + return gensec_start_mech(gensec_security); +} + +/** + * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context + * + */ + +_PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) +{ + gensec_security->credentials = talloc_reference(gensec_security, credentials); + NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials); + gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials)); + return NT_STATUS_OK; +} + +/* + register a GENSEC backend. + + The 'name' can be later used by other backends to find the operations + structure for this backend. +*/ +NTSTATUS gensec_register(const struct gensec_security_ops *ops) +{ + if (gensec_security_by_name(NULL, ops->name) != NULL) { + /* its already registered! */ + DEBUG(0,("GENSEC backend '%s' already registered\n", + ops->name)); + return NT_STATUS_OBJECT_NAME_COLLISION; + } + + generic_security_ops = talloc_realloc(talloc_autofree_context(), + generic_security_ops, + struct gensec_security_ops *, + gensec_num_backends+2); + if (!generic_security_ops) { + return NT_STATUS_NO_MEMORY; + } + + generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops); + gensec_num_backends++; + generic_security_ops[gensec_num_backends] = NULL; + + DEBUG(3,("GENSEC backend '%s' registered\n", + ops->name)); + + return NT_STATUS_OK; +} + +/* + return the GENSEC interface version, and the size of some critical types + This can be used by backends to either detect compilation errors, or provide + multiple implementations for different smbd compilation options in one module +*/ +const struct gensec_critical_sizes *gensec_interface_version(void) +{ + static const struct gensec_critical_sizes critical_sizes = { + GENSEC_INTERFACE_VERSION, + sizeof(struct gensec_security_ops), + sizeof(struct gensec_security), + }; + + return &critical_sizes; +} + +static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) { + return (*gs2)->priority - (*gs1)->priority; +} + +int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value) +{ + return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value); +} + +bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value) +{ + return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value); +} + +/* + initialise the GENSEC subsystem +*/ +_PUBLIC_ NTSTATUS gensec_init(void) +{ + static bool initialized = false; +#define _MODULE_PROTO(init) extern NTSTATUS init(void); +#if _SAMBA_BUILD_ == 4 + STATIC_gensec_MODULES_PROTO; + init_module_fn static_init[] = { STATIC_gensec_MODULES }; +#else + init_module_fn *static_init = NULL; +#endif + init_module_fn *shared_init; + + if (initialized) return NT_STATUS_OK; + initialized = true; + + shared_init = load_samba_modules(NULL, "gensec"); + + run_init_functions(static_init); + run_init_functions(shared_init); + + talloc_free(shared_init); + + TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec); + + return NT_STATUS_OK; +} diff --git a/auth/gensec/wscript_build b/auth/gensec/wscript_build index a9203f801d..e3e9372c3d 100644 --- a/auth/gensec/wscript_build +++ b/auth/gensec/wscript_build @@ -1,7 +1,11 @@ #!/usr/bin/env python +bld.SAMBA_LIBRARY('gensec', + source='gensec.c gensec_start.c', + pc_files='gensec.pc', + autoproto='gensec_toplevel_proto.h', + public_deps='tevent-util samba-util errors LIBPACKET auth_system_session samba-modules gensec_util', + public_headers='gensec.h', + deps='com_err', + vnum='0.0.1' + ) -bld.SAMBA_SUBSYSTEM('gensec_runtime', - source='gensec.c', - deps='tevent-util tevent samba-util LIBTSOCKET', - public_headers='gensec.h', - autoproto='gensec_toplevel_proto.h') diff --git a/source3/wscript_build b/source3/wscript_build index 78b24746b3..c6a2dd5557 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -805,7 +805,7 @@ bld.SAMBA3_SUBSYSTEM('LIBSMB_ERR', bld.SAMBA3_SUBSYSTEM('LIBNTLMSSP', source=LIBNTLMSSP_SRC, - deps='LIBSMB_ERR NDR_NTLMSSP NTLMSSP_COMMON gensec_runtime', + deps='LIBSMB_ERR NDR_NTLMSSP NTLMSSP_COMMON gensec', vars=locals()) bld.SAMBA3_LIBRARY('libsmb', diff --git a/source4/auth/gensec/cyrus_sasl.c b/source4/auth/gensec/cyrus_sasl.c index 4a4422645d..136bb8d43a 100644 --- a/source4/auth/gensec/cyrus_sasl.c +++ b/source4/auth/gensec/cyrus_sasl.c @@ -24,6 +24,7 @@ #include "auth/credentials/credentials.h" #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_proto.h" +#include "auth/gensec/gensec_toplevel_proto.h" #include NTSTATUS gensec_sasl_init(void); diff --git a/source4/auth/gensec/gensec.pc.in b/source4/auth/gensec/gensec.pc.in deleted file mode 100644 index f32226d5e4..0000000000 --- a/source4/auth/gensec/gensec.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -modulesdir=${prefix}/modules/gensec - -Name: gensec -Description: Generic Security Library -Version: @PACKAGE_VERSION@ -Libs: @LIB_RPATH@ -L${libdir} -lgensec -Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/source4/auth/gensec/gensec_start.c b/source4/auth/gensec/gensec_start.c deleted file mode 100644 index 3150cced97..0000000000 --- a/source4/auth/gensec/gensec_start.c +++ /dev/null @@ -1,952 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Generic Authentication Interface - - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett 2004-2006 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#include "system/network.h" -#include "lib/events/events.h" -#include "lib/socket/socket.h" -#include "lib/tsocket/tsocket.h" -#include "../lib/util/tevent_ntstatus.h" -#include "librpc/rpc/dcerpc.h" -#include "auth/credentials/credentials.h" -#include "auth/gensec/gensec.h" -#include "auth/gensec/gensec_proto.h" -#include "auth/auth.h" -#include "auth/system_session_proto.h" -#include "param/param.h" -#include "lib/util/tsort.h" -#include "auth/gensec/gensec_toplevel_proto.h" -#include "lib/util/samba_modules.h" - -/* the list of currently registered GENSEC backends */ -static struct gensec_security_ops **generic_security_ops; -static int gensec_num_backends; - -/* Return all the registered mechs. Don't modify the return pointer, - * but you may talloc_reference it if convient */ -_PUBLIC_ struct gensec_security_ops **gensec_security_all(void) -{ - return generic_security_ops; -} - -bool gensec_security_ops_enabled(struct gensec_security_ops *ops, struct gensec_security *security) -{ - return lpcfg_parm_bool(security->settings->lp_ctx, NULL, "gensec", ops->name, ops->enabled); -} - -/* Sometimes we want to force only kerberos, sometimes we want to - * force it's avoidance. The old list could be either - * gensec_security_all(), or from cli_credentials_gensec_list() (ie, - * an existing list we have trimmed down) */ - -_PUBLIC_ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, - struct gensec_security_ops **old_gensec_list, - struct cli_credentials *creds) -{ - struct gensec_security_ops **new_gensec_list; - int i, j, num_mechs_in; - enum credentials_use_kerberos use_kerberos = CRED_AUTO_USE_KERBEROS; - - if (creds) { - use_kerberos = cli_credentials_get_kerberos_state(creds); - } - - if (use_kerberos == CRED_AUTO_USE_KERBEROS) { - if (!talloc_reference(mem_ctx, old_gensec_list)) { - return NULL; - } - return old_gensec_list; - } - - for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) { - /* noop */ - } - - new_gensec_list = talloc_array(mem_ctx, struct gensec_security_ops *, num_mechs_in + 1); - if (!new_gensec_list) { - return NULL; - } - - j = 0; - for (i=0; old_gensec_list && old_gensec_list[i]; i++) { - int oid_idx; - - for (oid_idx = 0; old_gensec_list[i]->oid && old_gensec_list[i]->oid[oid_idx]; oid_idx++) { - if (strcmp(old_gensec_list[i]->oid[oid_idx], GENSEC_OID_SPNEGO) == 0) { - new_gensec_list[j] = old_gensec_list[i]; - j++; - break; - } - } - switch (use_kerberos) { - case CRED_DONT_USE_KERBEROS: - if (old_gensec_list[i]->kerberos == false) { - new_gensec_list[j] = old_gensec_list[i]; - j++; - } - break; - case CRED_MUST_USE_KERBEROS: - if (old_gensec_list[i]->kerberos == true) { - new_gensec_list[j] = old_gensec_list[i]; - j++; - } - break; - default: - /* Can't happen or invalid parameter */ - return NULL; - } - } - new_gensec_list[j] = NULL; - - return new_gensec_list; -} - -struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx) -{ - struct gensec_security_ops **backends; - backends = gensec_security_all(); - if (!gensec_security) { - if (!talloc_reference(mem_ctx, backends)) { - return NULL; - } - return backends; - } else { - struct cli_credentials *creds = gensec_get_credentials(gensec_security); - if (!creds) { - if (!talloc_reference(mem_ctx, backends)) { - return NULL; - } - return backends; - } - return gensec_use_kerberos_mechs(mem_ctx, backends, creds); - } -} - -static const struct gensec_security_ops *gensec_security_by_authtype(struct gensec_security *gensec_security, - uint8_t auth_type) -{ - int i; - struct gensec_security_ops **backends; - const struct gensec_security_ops *backend; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); - if (!mem_ctx) { - return NULL; - } - backends = gensec_security_mechs(gensec_security, mem_ctx); - for (i=0; backends && backends[i]; i++) { - if (!gensec_security_ops_enabled(backends[i], gensec_security)) - continue; - if (backends[i]->auth_type == auth_type) { - backend = backends[i]; - talloc_free(mem_ctx); - return backend; - } - } - talloc_free(mem_ctx); - - return NULL; -} - -const struct gensec_security_ops *gensec_security_by_oid(struct gensec_security *gensec_security, - const char *oid_string) -{ - int i, j; - struct gensec_security_ops **backends; - const struct gensec_security_ops *backend; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); - if (!mem_ctx) { - return NULL; - } - backends = gensec_security_mechs(gensec_security, mem_ctx); - for (i=0; backends && backends[i]; i++) { - if (gensec_security != NULL && - !gensec_security_ops_enabled(backends[i], - gensec_security)) - continue; - if (backends[i]->oid) { - for (j=0; backends[i]->oid[j]; j++) { - if (backends[i]->oid[j] && - (strcmp(backends[i]->oid[j], oid_string) == 0)) { - backend = backends[i]; - talloc_free(mem_ctx); - return backend; - } - } - } - } - talloc_free(mem_ctx); - - return NULL; -} - -const struct gensec_security_ops *gensec_security_by_sasl_name(struct gensec_security *gensec_security, - const char *sasl_name) -{ - int i; - struct gensec_security_ops **backends; - const struct gensec_security_ops *backend; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); - if (!mem_ctx) { - return NULL; - } - backends = gensec_security_mechs(gensec_security, mem_ctx); - for (i=0; backends && backends[i]; i++) { - if (!gensec_security_ops_enabled(backends[i], gensec_security)) - continue; - if (backends[i]->sasl_name - && (strcmp(backends[i]->sasl_name, sasl_name) == 0)) { - backend = backends[i]; - talloc_free(mem_ctx); - return backend; - } - } - talloc_free(mem_ctx); - - return NULL; -} - -static const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security, - const char *name) -{ - int i; - struct gensec_security_ops **backends; - const struct gensec_security_ops *backend; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); - if (!mem_ctx) { - return NULL; - } - backends = gensec_security_mechs(gensec_security, mem_ctx); - for (i=0; backends && backends[i]; i++) { - if (gensec_security != NULL && - !gensec_security_ops_enabled(backends[i], gensec_security)) - continue; - if (backends[i]->name - && (strcmp(backends[i]->name, name) == 0)) { - backend = backends[i]; - talloc_free(mem_ctx); - return backend; - } - } - talloc_free(mem_ctx); - return NULL; -} - -/** - * Return a unique list of security subsystems from those specified in - * the list of SASL names. - * - * Use the list of enabled GENSEC mechanisms from the credentials - * attached to the gensec_security, and return in our preferred order. - */ - -const struct gensec_security_ops **gensec_security_by_sasl_list(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const char **sasl_names) -{ - const struct gensec_security_ops **backends_out; - struct gensec_security_ops **backends; - int i, k, sasl_idx; - int num_backends_out = 0; - - if (!sasl_names) { - return NULL; - } - - backends = gensec_security_mechs(gensec_security, mem_ctx); - - backends_out = talloc_array(mem_ctx, const struct gensec_security_ops *, 1); - if (!backends_out) { - return NULL; - } - backends_out[0] = NULL; - - /* Find backends in our preferred order, by walking our list, - * then looking in the supplied list */ - for (i=0; backends && backends[i]; i++) { - if (gensec_security != NULL && - !gensec_security_ops_enabled(backends[i], gensec_security)) - continue; - for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) { - if (!backends[i]->sasl_name || - !(strcmp(backends[i]->sasl_name, - sasl_names[sasl_idx]) == 0)) { - continue; - } - - for (k=0; backends_out[k]; k++) { - if (backends_out[k] == backends[i]) { - break; - } - } - - if (k < num_backends_out) { - /* already in there */ - continue; - } - - backends_out = talloc_realloc(mem_ctx, backends_out, - const struct gensec_security_ops *, - num_backends_out + 2); - if (!backends_out) { - return NULL; - } - - backends_out[num_backends_out] = backends[i]; - num_backends_out++; - backends_out[num_backends_out] = NULL; - } - } - return backends_out; -} - -/** - * Return a unique list of security subsystems from those specified in - * the OID list. That is, where two OIDs refer to the same module, - * return that module only once. - * - * Use the list of enabled GENSEC mechanisms from the credentials - * attached to the gensec_security, and return in our preferred order. - */ - -const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const char **oid_strings, - const char *skip) -{ - struct gensec_security_ops_wrapper *backends_out; - struct gensec_security_ops **backends; - int i, j, k, oid_idx; - int num_backends_out = 0; - - if (!oid_strings) { - return NULL; - } - - backends = gensec_security_mechs(gensec_security, gensec_security); - - backends_out = talloc_array(mem_ctx, struct gensec_security_ops_wrapper, 1); - if (!backends_out) { - return NULL; - } - backends_out[0].op = NULL; - backends_out[0].oid = NULL; - - /* Find backends in our preferred order, by walking our list, - * then looking in the supplied list */ - for (i=0; backends && backends[i]; i++) { - if (gensec_security != NULL && - !gensec_security_ops_enabled(backends[i], gensec_security)) - continue; - if (!backends[i]->oid) { - continue; - } - for (oid_idx = 0; oid_strings[oid_idx]; oid_idx++) { - if (strcmp(oid_strings[oid_idx], skip) == 0) { - continue; - } - - for (j=0; backends[i]->oid[j]; j++) { - if (!backends[i]->oid[j] || - !(strcmp(backends[i]->oid[j], - oid_strings[oid_idx]) == 0)) { - continue; - } - - for (k=0; backends_out[k].op; k++) { - if (backends_out[k].op == backends[i]) { - break; - } - } - - if (k < num_backends_out) { - /* already in there */ - continue; - } - - backends_out = talloc_realloc(mem_ctx, backends_out, - struct gensec_security_ops_wrapper, - num_backends_out + 2); - if (!backends_out) { - return NULL; - } - - backends_out[num_backends_out].op = backends[i]; - backends_out[num_backends_out].oid = backends[i]->oid[j]; - num_backends_out++; - backends_out[num_backends_out].op = NULL; - backends_out[num_backends_out].oid = NULL; - } - } - } - return backends_out; -} - -/** - * Return OIDS from the security subsystems listed - */ - -const char **gensec_security_oids_from_ops(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - struct gensec_security_ops **ops, - const char *skip) -{ - int i; - int j = 0; - int k; - const char **oid_list; - if (!ops) { - return NULL; - } - oid_list = talloc_array(mem_ctx, const char *, 1); - if (!oid_list) { - return NULL; - } - - for (i=0; ops && ops[i]; i++) { - if (gensec_security != NULL && - !gensec_security_ops_enabled(ops[i], gensec_security)) { - continue; - } - if (!ops[i]->oid) { - continue; - } - - for (k = 0; ops[i]->oid[k]; k++) { - if (skip && strcmp(skip, ops[i]->oid[k])==0) { - } else { - oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2); - if (!oid_list) { - return NULL; - } - oid_list[j] = ops[i]->oid[k]; - j++; - } - } - } - oid_list[j] = NULL; - return oid_list; -} - - -/** - * Return OIDS from the security subsystems listed - */ - -const char **gensec_security_oids_from_ops_wrapped(TALLOC_CTX *mem_ctx, - const struct gensec_security_ops_wrapper *wops) -{ - int i; - int j = 0; - int k; - const char **oid_list; - if (!wops) { - return NULL; - } - oid_list = talloc_array(mem_ctx, const char *, 1); - if (!oid_list) { - return NULL; - } - - for (i=0; wops[i].op; i++) { - if (!wops[i].op->oid) { - continue; - } - - for (k = 0; wops[i].op->oid[k]; k++) { - oid_list = talloc_realloc(mem_ctx, oid_list, const char *, j + 2); - if (!oid_list) { - return NULL; - } - oid_list[j] = wops[i].op->oid[k]; - j++; - } - } - oid_list[j] = NULL; - return oid_list; -} - - -/** - * Return all the security subsystems currently enabled on a GENSEC context. - * - * This is taken from a list attached to the cli_credentials, and - * skips the OID in 'skip'. (Typically the SPNEGO OID) - * - */ - -const char **gensec_security_oids(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const char *skip) -{ - struct gensec_security_ops **ops - = gensec_security_mechs(gensec_security, mem_ctx); - return gensec_security_oids_from_ops(gensec_security, mem_ctx, ops, skip); -} - -/** - Start the GENSEC system, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. - @note, the auth context is moved to be a referenced pointer of the - @ gensec_security return -*/ -static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct gensec_settings *settings, - struct auth4_context *auth_context, - struct gensec_security **gensec_security) -{ - if (ev == NULL) { - DEBUG(0, ("No event context available!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security); - NT_STATUS_HAVE_NO_MEMORY(*gensec_security); - - (*gensec_security)->event_ctx = ev; - SMB_ASSERT(settings->lp_ctx != NULL); - (*gensec_security)->settings = talloc_reference(*gensec_security, settings); - - /* We need to reference this, not steal, as the caller may be - * python, which won't like it if we steal it's object away - * from it */ - (*gensec_security)->auth_context = talloc_reference(*gensec_security, auth_context); - - return NT_STATUS_OK; -} - -/** - * Start a GENSEC subcontext, with a copy of the properties of the parent - * @param mem_ctx The parent TALLOC memory context. - * @param parent The parent GENSEC context - * @param gensec_security Returned GENSEC context pointer. - * @note Used by SPNEGO in particular, for the actual implementation mechanism - */ - -_PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx, - struct gensec_security *parent, - struct gensec_security **gensec_security) -{ - (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security); - NT_STATUS_HAVE_NO_MEMORY(*gensec_security); - - (**gensec_security) = *parent; - (*gensec_security)->ops = NULL; - (*gensec_security)->private_data = NULL; - - (*gensec_security)->subcontext = true; - (*gensec_security)->want_features = parent->want_features; - (*gensec_security)->event_ctx = parent->event_ctx; - (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context); - (*gensec_security)->settings = talloc_reference(*gensec_security, parent->settings); - (*gensec_security)->auth_context = talloc_reference(*gensec_security, parent->auth_context); - - return NT_STATUS_OK; -} - -/** - Start the GENSEC system, in client mode, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. -*/ -_PUBLIC_ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, - struct gensec_security **gensec_security, - struct tevent_context *ev, - struct gensec_settings *settings) -{ - NTSTATUS status; - - if (settings == NULL) { - DEBUG(0,("gensec_client_start: no settings given!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - status = gensec_start(mem_ctx, ev, settings, NULL, gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - (*gensec_security)->gensec_role = GENSEC_CLIENT; - - return status; -} - - - -/** - Start the GENSEC system, in server mode, returning a context pointer. - @param mem_ctx The parent TALLOC memory context. - @param gensec_security Returned GENSEC context pointer. - @note The mem_ctx is only a parent and may be NULL. -*/ -_PUBLIC_ NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct gensec_settings *settings, - struct auth4_context *auth_context, - struct gensec_security **gensec_security) -{ - NTSTATUS status; - - if (!ev) { - DEBUG(0,("gensec_server_start: no event context given!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - if (!settings) { - DEBUG(0,("gensec_server_start: no settings given!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - status = gensec_start(mem_ctx, ev, settings, auth_context, gensec_security); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - (*gensec_security)->gensec_role = GENSEC_SERVER; - - return status; -} - -NTSTATUS gensec_start_mech(struct gensec_security *gensec_security) -{ - NTSTATUS status; - DEBUG(5, ("Starting GENSEC %smechanism %s\n", - gensec_security->subcontext ? "sub" : "", - gensec_security->ops->name)); - switch (gensec_security->gensec_role) { - case GENSEC_CLIENT: - if (gensec_security->ops->client_start) { - status = gensec_security->ops->client_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(gensec_security->subcontext?4:2, ("Failed to start GENSEC client mech %s: %s\n", - gensec_security->ops->name, nt_errstr(status))); - } - return status; - } - break; - case GENSEC_SERVER: - if (gensec_security->ops->server_start) { - status = gensec_security->ops->server_start(gensec_security); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n", - gensec_security->ops->name, nt_errstr(status))); - } - return status; - } - break; - } - return NT_STATUS_INVALID_PARAMETER; -} - -/** - * Start a GENSEC sub-mechanism with a specified mechansim structure, used in SPNEGO - * - */ - -NTSTATUS gensec_start_mech_by_ops(struct gensec_security *gensec_security, - const struct gensec_security_ops *ops) -{ - gensec_security->ops = ops; - return gensec_start_mech(gensec_security); -} - - -/** - * Start a GENSEC sub-mechanism by DCERPC allocated 'auth type' number - * @param gensec_security GENSEC context pointer. - * @param auth_type DCERPC auth type - * @param auth_level DCERPC auth level - */ - -_PUBLIC_ NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security, - uint8_t auth_type, uint8_t auth_level) -{ - gensec_security->ops = gensec_security_by_authtype(gensec_security, auth_type); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for auth_type=%d\n", (int)auth_type)); - return NT_STATUS_INVALID_PARAMETER; - } - gensec_want_feature(gensec_security, GENSEC_FEATURE_DCE_STYLE); - gensec_want_feature(gensec_security, GENSEC_FEATURE_ASYNC_REPLIES); - if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) { - gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); - } else if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { - gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN); - gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL); - } else if (auth_level == DCERPC_AUTH_LEVEL_CONNECT) { - /* Default features */ - } else { - DEBUG(2,("auth_level %d not supported in DCE/RPC authentication\n", - auth_level)); - return NT_STATUS_INVALID_PARAMETER; - } - - return gensec_start_mech(gensec_security); -} - -_PUBLIC_ const char *gensec_get_name_by_authtype(struct gensec_security *gensec_security, uint8_t authtype) -{ - const struct gensec_security_ops *ops; - ops = gensec_security_by_authtype(gensec_security, authtype); - if (ops) { - return ops->name; - } - return NULL; -} - - -_PUBLIC_ const char *gensec_get_name_by_oid(struct gensec_security *gensec_security, - const char *oid_string) -{ - const struct gensec_security_ops *ops; - ops = gensec_security_by_oid(gensec_security, oid_string); - if (ops) { - return ops->name; - } - return oid_string; -} - -/** - * Start a GENSEC sub-mechanism by OID, used in SPNEGO - * - * @note This should also be used when you wish to just start NLTMSSP (for example), as it uses a - * well-known #define to hook it in. - */ - -_PUBLIC_ NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security, - const char *mech_oid) -{ - SMB_ASSERT(gensec_security != NULL); - - gensec_security->ops = gensec_security_by_oid(gensec_security, mech_oid); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for oid=%s\n", mech_oid)); - return NT_STATUS_INVALID_PARAMETER; - } - return gensec_start_mech(gensec_security); -} - -/** - * Start a GENSEC sub-mechanism by a well know SASL name - * - */ - -_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security, - const char *sasl_name) -{ - gensec_security->ops = gensec_security_by_sasl_name(gensec_security, sasl_name); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name)); - return NT_STATUS_INVALID_PARAMETER; - } - return gensec_start_mech(gensec_security); -} - -/** - * Start a GENSEC sub-mechanism with the preferred option from a SASL name list - * - */ - -_PUBLIC_ NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security *gensec_security, - const char **sasl_names) -{ - NTSTATUS nt_status = NT_STATUS_INVALID_PARAMETER; - TALLOC_CTX *mem_ctx = talloc_new(gensec_security); - const struct gensec_security_ops **ops; - int i; - if (!mem_ctx) { - return NT_STATUS_NO_MEMORY; - } - ops = gensec_security_by_sasl_list(gensec_security, mem_ctx, sasl_names); - if (!ops || !*ops) { - DEBUG(3, ("Could not find GENSEC backend for any of sasl_name = %s\n", - str_list_join(mem_ctx, - sasl_names, ' '))); - talloc_free(mem_ctx); - return NT_STATUS_INVALID_PARAMETER; - } - for (i=0; ops[i]; i++) { - nt_status = gensec_start_mech_by_ops(gensec_security, ops[i]); - if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_PARAMETER)) { - break; - } - } - talloc_free(mem_ctx); - return nt_status; -} - -/** - * Start a GENSEC sub-mechanism by an internal name - * - */ - -_PUBLIC_ NTSTATUS gensec_start_mech_by_name(struct gensec_security *gensec_security, - const char *name) -{ - gensec_security->ops = gensec_security_by_name(gensec_security, name); - if (!gensec_security->ops) { - DEBUG(3, ("Could not find GENSEC backend for name=%s\n", name)); - return NT_STATUS_INVALID_PARAMETER; - } - return gensec_start_mech(gensec_security); -} - -/** - * Associate a credentials structure with a GENSEC context - talloc_reference()s it to the context - * - */ - -_PUBLIC_ NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials) -{ - gensec_security->credentials = talloc_reference(gensec_security, credentials); - NT_STATUS_HAVE_NO_MEMORY(gensec_security->credentials); - gensec_want_feature(gensec_security, cli_credentials_get_gensec_features(gensec_security->credentials)); - return NT_STATUS_OK; -} - -NTSTATUS gensec_generate_session_info(TALLOC_CTX *mem_ctx, - struct gensec_security *gensec_security, - struct auth_user_info_dc *user_info_dc, - struct auth_session_info **session_info) -{ - NTSTATUS nt_status; - uint32_t session_info_flags = 0; - - if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { - session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; - } - - session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; - if (user_info_dc->info->authenticated) { - session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED; - } - - if (gensec_security->auth_context) { - nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context, - user_info_dc, - session_info_flags, - session_info); - } else { - session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES; - nt_status = auth_generate_session_info(mem_ctx, - NULL, - NULL, - user_info_dc, session_info_flags, - session_info); - } - return nt_status; -} - -/* - register a GENSEC backend. - - The 'name' can be later used by other backends to find the operations - structure for this backend. -*/ -NTSTATUS gensec_register(const struct gensec_security_ops *ops) -{ - if (gensec_security_by_name(NULL, ops->name) != NULL) { - /* its already registered! */ - DEBUG(0,("GENSEC backend '%s' already registered\n", - ops->name)); - return NT_STATUS_OBJECT_NAME_COLLISION; - } - - generic_security_ops = talloc_realloc(talloc_autofree_context(), - generic_security_ops, - struct gensec_security_ops *, - gensec_num_backends+2); - if (!generic_security_ops) { - return NT_STATUS_NO_MEMORY; - } - - generic_security_ops[gensec_num_backends] = discard_const_p(struct gensec_security_ops, ops); - gensec_num_backends++; - generic_security_ops[gensec_num_backends] = NULL; - - DEBUG(3,("GENSEC backend '%s' registered\n", - ops->name)); - - return NT_STATUS_OK; -} - -/* - return the GENSEC interface version, and the size of some critical types - This can be used by backends to either detect compilation errors, or provide - multiple implementations for different smbd compilation options in one module -*/ -const struct gensec_critical_sizes *gensec_interface_version(void) -{ - static const struct gensec_critical_sizes critical_sizes = { - GENSEC_INTERFACE_VERSION, - sizeof(struct gensec_security_ops), - sizeof(struct gensec_security), - }; - - return &critical_sizes; -} - -static int sort_gensec(struct gensec_security_ops **gs1, struct gensec_security_ops **gs2) { - return (*gs2)->priority - (*gs1)->priority; -} - -int gensec_setting_int(struct gensec_settings *settings, const char *mechanism, const char *name, int default_value) -{ - return lpcfg_parm_int(settings->lp_ctx, NULL, mechanism, name, default_value); -} - -bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism, const char *name, bool default_value) -{ - return lpcfg_parm_bool(settings->lp_ctx, NULL, mechanism, name, default_value); -} - -/* - initialise the GENSEC subsystem -*/ -_PUBLIC_ NTSTATUS gensec_init(void) -{ - static bool initialized = false; -#define _MODULE_PROTO(init) extern NTSTATUS init(void); -#if _SAMBA_BUILD_ == 4 - STATIC_gensec_MODULES_PROTO; - init_module_fn static_init[] = { STATIC_gensec_MODULES }; -#else - init_module_fn *static_init = NULL; -#endif - init_module_fn *shared_init; - - if (initialized) return NT_STATUS_OK; - initialized = true; - - shared_init = load_samba_modules(NULL, "gensec"); - - run_init_functions(static_init); - run_init_functions(shared_init); - - talloc_free(shared_init); - - TYPESAFE_QSORT(generic_security_ops, gensec_num_backends, sort_gensec); - - return NT_STATUS_OK; -} diff --git a/source4/auth/gensec/gensec_util.c b/source4/auth/gensec/gensec_util.c new file mode 100644 index 0000000000..267366af61 --- /dev/null +++ b/source4/auth/gensec/gensec_util.c @@ -0,0 +1,59 @@ +/* + Unix SMB/CIFS implementation. + + Generic Authentication Interface + + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Bartlett 2004-2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "auth/gensec/gensec.h" +#include "auth/auth.h" +#include "auth/system_session_proto.h" + +NTSTATUS gensec_generate_session_info(TALLOC_CTX *mem_ctx, + struct gensec_security *gensec_security, + struct auth_user_info_dc *user_info_dc, + struct auth_session_info **session_info) +{ + NTSTATUS nt_status; + uint32_t session_info_flags = 0; + + if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) { + session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN; + } + + session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS; + if (user_info_dc->info->authenticated) { + session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED; + } + + if (gensec_security->auth_context) { + nt_status = gensec_security->auth_context->generate_session_info(mem_ctx, gensec_security->auth_context, + user_info_dc, + session_info_flags, + session_info); + } else { + session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES; + nt_status = auth_generate_session_info(mem_ctx, + NULL, + NULL, + user_info_dc, session_info_flags, + session_info); + } + return nt_status; +} diff --git a/source4/auth/gensec/schannel.c b/source4/auth/gensec/schannel.c index b70d65a093..35713ce068 100644 --- a/source4/auth/gensec/schannel.c +++ b/source4/auth/gensec/schannel.c @@ -30,6 +30,7 @@ #include "librpc/rpc/dcerpc.h" #include "param/param.h" #include "auth/gensec/schannel.h" +#include "auth/gensec/gensec_toplevel_proto.h" _PUBLIC_ NTSTATUS gensec_schannel_init(void); diff --git a/source4/auth/gensec/wscript_build b/source4/auth/gensec/wscript_build index a7fa12f56a..86d958950f 100644 --- a/source4/auth/gensec/wscript_build +++ b/source4/auth/gensec/wscript_build @@ -1,14 +1,9 @@ #!/usr/bin/env python -bld.SAMBA_LIBRARY('gensec', - source='gensec_start.c socket.c gensec_tstream.c', - pc_files='gensec.pc', - autoproto='gensec_proto.h', - public_deps='tevent-util samba-util errors LIBPACKET auth_system_session gensec_runtime samba-modules', - public_headers='', - deps='com_err', - vnum='0.0.1' - ) +bld.SAMBA_SUBSYSTEM('gensec_util', + source='socket.c gensec_tstream.c gensec_util.c', + deps='tevent-util tevent samba-util LIBTSOCKET', + autoproto='gensec_proto.h') bld.SAMBA_MODULE('gensec_krb5', source='gensec_krb5.c', diff --git a/source4/auth/ntlmssp/ntlmssp.c b/source4/auth/ntlmssp/ntlmssp.c index d90c908d8d..9b3aef0c65 100644 --- a/source4/auth/ntlmssp/ntlmssp.c +++ b/source4/auth/ntlmssp/ntlmssp.c @@ -27,6 +27,7 @@ #include "librpc/gen_ndr/ndr_dcerpc.h" #include "auth/gensec/gensec.h" #include "auth/gensec/gensec_proto.h" +#include "auth/gensec/gensec_toplevel_proto.h" /** * Callbacks for NTLMSSP - for both client and server operating modes -- cgit