*/
#include "includes.h"
+#include "auth/auth.h"
/* the list of currently registered GENSEC backends */
const static struct gensec_security_ops **generic_security_ops;
if (!ops) {
return NULL;
}
- oid_list = talloc_array_p(mem_ctx, const char *, num_backends + 1);
+ oid_list = talloc_array(mem_ctx, const char *, num_backends + 1);
if (!oid_list) {
return NULL;
}
return oid_list;
}
-static NTSTATUS gensec_start(struct gensec_security **gensec_security)
+/**
+ 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.
+*/
+static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
{
- TALLOC_CTX *mem_ctx;
- /* awaiting a correct fix from metze */
- if (!gensec_init()) {
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- mem_ctx = talloc_init("gensec_security struct");
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
-
- (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
+ (*gensec_security) = talloc(mem_ctx, struct gensec_security);
if (!(*gensec_security)) {
- talloc_destroy(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
- (*gensec_security)->mem_ctx = mem_ctx;
(*gensec_security)->ops = NULL;
ZERO_STRUCT((*gensec_security)->user);
ZERO_STRUCT((*gensec_security)->default_user);
(*gensec_security)->default_user.name = "";
- (*gensec_security)->default_user.domain = talloc_strdup(mem_ctx, lp_workgroup());
- (*gensec_security)->default_user.realm = talloc_strdup(mem_ctx, lp_realm());
+ (*gensec_security)->default_user.domain = talloc_strdup(*gensec_security, lp_workgroup());
+ (*gensec_security)->default_user.realm = talloc_strdup(*gensec_security, lp_realm());
(*gensec_security)->subcontext = False;
+ (*gensec_security)->want_features = 0;
return NT_STATUS_OK;
}
/**
* Start a GENSEC subcontext, with a copy of the properties of the parent
- *
- * @note Used by SPENGO in particular, for the actual implementation mechanism
+ * @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
*/
-NTSTATUS gensec_subcontext_start(struct gensec_security *parent,
+NTSTATUS gensec_subcontext_start(TALLOC_CTX *mem_ctx,
+ struct gensec_security *parent,
struct gensec_security **gensec_security)
{
- (*gensec_security) = talloc_p(parent->mem_ctx, struct gensec_security);
+ (*gensec_security) = talloc(mem_ctx, struct gensec_security);
if (!(*gensec_security)) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
}
-NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
+/**
+ 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.
+*/
+NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
{
NTSTATUS status;
- status = gensec_start(gensec_security);
+ status = gensec_start(mem_ctx, gensec_security);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return status;
}
-NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
+/**
+ 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.
+*/
+NTSTATUS gensec_server_start(TALLOC_CTX *mem_ctx, struct gensec_security **gensec_security)
{
NTSTATUS status;
- status = gensec_start(gensec_security);
+ status = gensec_start(mem_ctx, gensec_security);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (gensec_security->ops->client_start) {
status = gensec_security->ops->client_start(gensec_security);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
+ DEBUG(1, ("Failed to start GENSEC client mech %s: %s\n",
gensec_security->ops->name, nt_errstr(status)));
}
return status;
if (gensec_security->ops->server_start) {
status = gensec_security->ops->server_start(gensec_security);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
+ DEBUG(1, ("Failed to start GENSEC server mech %s: %s\n",
gensec_security->ops->name, nt_errstr(status)));
}
return status;
/**
* 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
*/
NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
- uint8_t authtype)
+ uint8_t auth_type, uint8_t auth_level)
{
- gensec_security->ops = gensec_security_by_authtype(authtype);
+ gensec_security->ops = gensec_security_by_authtype(auth_type);
if (!gensec_security->ops) {
- DEBUG(3, ("Could not find GENSEC backend for authtype=%d\n", (int)authtype));
+ 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);
+ if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
+ }
+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SIGN);
+ gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
+ }
+
return gensec_start_mech(gensec_security);
}
}
+const char *gensec_get_name_by_oid(const char *oid_string)
+{
+ const struct gensec_security_ops *ops;
+ ops = gensec_security_by_oid(oid_string);
+ if (ops) {
+ return ops->name;
+ }
+ return NULL;
+}
+
+
/**
* Start a GENSEC sub-mechanism by OID, used in SPNEGO
*
*/
NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+ uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
if (!gensec_security->ops->unseal_packet) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+ if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return gensec_check_packet(gensec_security, mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return gensec_security->ops->unseal_packet(gensec_security, mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
}
NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
const DATA_BLOB *sig)
{
if (!gensec_security->ops->check_packet) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
if (!gensec_security->ops->seal_packet) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
+ if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return gensec_sign_packet(gensec_security, mem_ctx,
+ data, length,
+ whole_pdu, pdu_length,
+ sig);
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
+ const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
if (!gensec_security->ops->sign_packet) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
+}
+
+size_t gensec_sig_size(struct gensec_security *gensec_security)
+{
+ if (!gensec_security->ops->sig_size) {
+ return 0;
+ }
+ if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+ return 0;
+ }
+
+ return gensec_security->ops->sig_size(gensec_security);
+}
+
+NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ if (!gensec_security->ops->wrap) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out);
+}
+
+NTSTATUS gensec_unwrap(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *in,
+ DATA_BLOB *out)
+{
+ if (!gensec_security->ops->unwrap) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+ return gensec_security->ops->unwrap(gensec_security, mem_ctx, in, out);
}
NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
}
-void gensec_end(struct gensec_security **gensec_security)
-{
- if ((*gensec_security)->ops) {
- (*gensec_security)->ops->end(*gensec_security);
- }
- (*gensec_security)->private_data = NULL;
+/**
+ * Set the requirement for a certain feature on the connection
+ *
+ */
- if (!(*gensec_security)->subcontext) {
- /* don't destory this if this is a subcontext - it belongs to the parent */
- talloc_destroy((*gensec_security)->mem_ctx);
- }
- gensec_security = NULL;
+void gensec_want_feature(struct gensec_security *gensec_security,
+ uint32_t feature)
+{
+ gensec_security->want_features |= feature;
}
/**
- * Set a username on a GENSEC context - ensures it is talloc()ed
+ * Check the requirement for a certain feature on the connection
*
*/
-NTSTATUS gensec_set_unparsed_username(struct gensec_security *gensec_security, const char *user)
+BOOL gensec_have_feature(struct gensec_security *gensec_security,
+ uint32_t feature)
{
- char *p;
- char *u = talloc_strdup(gensec_security->mem_ctx, user);
- if (!u) {
- return NT_STATUS_NO_MEMORY;
- }
-
- p = strchr_m(user, '@');
-
- if (p) {
- *p = '\0';
- gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, u);
- if (!gensec_security->user.name) {
- return NT_STATUS_NO_MEMORY;
- }
-
- gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, p+1);
- if (!gensec_security->user.realm) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
- }
-
- p = strchr_m(user, '\\');
- if (!p) {
- p = strchr_m(user, '/');
- }
-
- if (p) {
- *p = '\0';
- gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, u);
- if (!gensec_security->user.domain) {
- return NT_STATUS_NO_MEMORY;
- }
- gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, p+1);
- if (!gensec_security->user.name) {
- return NT_STATUS_NO_MEMORY;
- }
-
- return NT_STATUS_OK;
- }
-
- gensec_security->user.name = u;
- if (!gensec_security->user.name) {
- return NT_STATUS_NO_MEMORY;
+ if (!gensec_security->ops->have_feature) {
+ return False;
}
- return NT_STATUS_OK;
+ return gensec_security->ops->have_feature(gensec_security, feature);
}
/**
NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
{
- gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, user);
- if (!gensec_security->user.name) {
+ gensec_security->user.name = talloc_strdup(gensec_security, user);
+ if (user && !gensec_security->user.name) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
{
- gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, domain);
- if (!gensec_security->user.domain) {
+ gensec_security->user.domain = talloc_strdup(gensec_security, domain);
+ if (domain && !gensec_security->user.domain) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
return gensec_security->default_user.domain;
}
+/**
+ * Set the client workstation on a GENSEC context - ensures it is talloc()ed
+ *
+ */
+
+NTSTATUS gensec_set_workstation(struct gensec_security *gensec_security, const char *workstation)
+{
+ gensec_security->user.workstation = talloc_strdup(gensec_security, workstation);
+ if (workstation && !gensec_security->user.workstation) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Return the client workstation on a GENSEC context - ensures it is talloc()ed
+ *
+ */
+
+const char *gensec_get_workstation(struct gensec_security *gensec_security)
+{
+ if (gensec_security->user.workstation) {
+ return gensec_security->user.workstation;
+ } else {
+ return lp_netbios_name();
+ }
+}
+
/**
* Set a kerberos realm on a GENSEC context - ensures it is talloc()ed
*
NTSTATUS gensec_set_realm(struct gensec_security *gensec_security, const char *realm)
{
- gensec_security->user.realm = talloc_strdup(gensec_security->mem_ctx, realm);
- if (!gensec_security->user.realm) {
+ gensec_security->user.realm = talloc_strdup(gensec_security, realm);
+ if (realm && !gensec_security->user.realm) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
const char *password)
{
- gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
- if (!gensec_security->user.password) {
+ gensec_security->user.password = talloc_strdup(gensec_security, password);
+ if (password && !gensec_security->user.password) {
return NT_STATUS_NO_MEMORY;
}
return NT_STATUS_OK;
NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
{
- gensec_security->target.principal = talloc_strdup(gensec_security->mem_ctx, principal);
+ gensec_security->target.principal = talloc_strdup(gensec_security, principal);
if (!gensec_security->target.principal) {
return NT_STATUS_NO_MEMORY;
}
NTSTATUS gensec_set_target_service(struct gensec_security *gensec_security, const char *service)
{
- gensec_security->target.service = talloc_strdup(gensec_security->mem_ctx, service);
+ gensec_security->target.service = talloc_strdup(gensec_security, service);
if (!gensec_security->target.service) {
return NT_STATUS_NO_MEMORY;
}
NTSTATUS gensec_set_target_hostname(struct gensec_security *gensec_security, const char *hostname)
{
- gensec_security->target.hostname = talloc_strdup(gensec_security->mem_ctx, hostname);
+ gensec_security->target.hostname = talloc_strdup(gensec_security, hostname);
if (!gensec_security->target.hostname) {
return NT_STATUS_NO_MEMORY;
}
return "host";
}
+const char *gensec_get_target_principal(struct gensec_security *gensec_security)
+{
+ const char *mechListMIC;
+
+ if (gensec_security->target.principal) {
+ return gensec_security->target.principal;
+ }
+
+ mechListMIC = talloc_asprintf(gensec_security,"%s$@%s",
+ lp_netbios_name(),
+ lp_realm());
+ return mechListMIC;
+}
+
/**
* Set a password callback, if the gensec module we use demands a password
*/
}
}
if (!gensec_security->password_callback) {
- return NT_STATUS_INVALID_PARAMETER;
+ *password = NULL;
+ return NT_STATUS_OK;
}
return gensec_security->password_callback(gensec_security, mem_ctx, password);
}
The 'name' can be later used by other backends to find the operations
structure for this backend.
*/
-static NTSTATUS gensec_register(const void *_ops)
+NTSTATUS gensec_register(const void *_ops)
{
const struct gensec_security_ops *ops = _ops;
+ if (!lp_parm_bool(-1, "gensec", ops->name, ops->enabled)) {
+ DEBUG(2,("gensec subsystem %s is disabled\n", ops->name));
+ return NT_STATUS_OK;
+ }
+
if (gensec_security_by_name(ops->name) != NULL) {
/* its already registered! */
DEBUG(0,("GENSEC backend '%s' already registered\n",
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (gensec_num_backends+1));
+ generic_security_ops = realloc_p(generic_security_ops,
+ const struct gensec_security_ops *,
+ gensec_num_backends+1);
if (!generic_security_ops) {
smb_panic("out of memory in gensec_register");
}
/*
initialise the GENSEC subsystem
*/
-BOOL gensec_init(void)
+NTSTATUS gensec_init(void)
{
- static BOOL initialised;
- NTSTATUS status;
-
- /* this is *completely* the wrong way to do this */
- if (initialised) {
- return True;
- }
-
- status = register_subsystem("gensec", gensec_register);
- if (!NT_STATUS_IS_OK(status)) {
- return False;
- }
-
- static_init_gensec;
gensec_dcerpc_schannel_init();
-
- initialised = True;
- DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));
- return True;
+ return NT_STATUS_OK;
}