summaryrefslogtreecommitdiff
path: root/source4/libcli/auth/gensec_ntlmssp.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/auth/gensec_ntlmssp.c')
-rw-r--r--source4/libcli/auth/gensec_ntlmssp.c333
1 files changed, 304 insertions, 29 deletions
diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c
index f7e9dddd2f..9f7c4c6f86 100644
--- a/source4/libcli/auth/gensec_ntlmssp.c
+++ b/source4/libcli/auth/gensec_ntlmssp.c
@@ -23,33 +23,220 @@
#include "includes.h"
+struct gensec_ntlmssp_state {
+ TALLOC_CTX *mem_ctx;
+ struct auth_context *auth_context;
+ struct auth_serversupplied_info *server_info;
+ struct ntlmssp_state *ntlmssp_state;
+};
-NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
+
+/**
+ * Return the challenge as determined by the authentication subsystem
+ * @return an 8 byte random challenge
+ */
+
+static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+
+ return gensec_ntlmssp_state->auth_context->get_ntlm_challenge(gensec_ntlmssp_state->auth_context);
+}
+
+/**
+ * Some authentication methods 'fix' the challenge, so we may not be able to set it
+ *
+ * @return If the effective challenge used by the auth subsystem may be modified
+ */
+static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+
+ return gensec_ntlmssp_state->auth_context->challenge_may_be_modified;
+}
+
+/**
+ * NTLM2 authentication modifies the effective challenge,
+ * @param challenge The new challenge value
+ */
+static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+ struct auth_context *auth_context = gensec_ntlmssp_state->auth_context;
+
+ SMB_ASSERT(challenge->length == 8);
+
+ auth_context->challenge = data_blob_talloc(auth_context->mem_ctx,
+ challenge->data, challenge->length);
+
+ auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
+
+ DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Check the password on an NTLMSSP login.
+ *
+ * Return the session keys used on the connection.
+ */
+
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+ struct auth_usersupplied_info *user_info = NULL;
+ NTSTATUS nt_status;
+
+#if 0
+ /* the client has given us its machine name (which we otherwise would not get on port 445).
+ we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+
+ set_remote_machine_name(gensec_ntlmssp_state->ntlmssp_state->workstation, True);
+
+ /* setup the string used by %U */
+ /* sub_set_smb_name checks for weird internally */
+ sub_set_smb_name(gensec_ntlmssp_state->ntlmssp_state->user);
+
+ reload_services(True);
+
+#endif
+ nt_status = make_user_info_map(&user_info,
+ gensec_ntlmssp_state->ntlmssp_state->user,
+ gensec_ntlmssp_state->ntlmssp_state->domain,
+ gensec_ntlmssp_state->ntlmssp_state->workstation,
+ gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
+ gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
+ NULL, NULL, NULL,
+ True);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ nt_status = gensec_ntlmssp_state->auth_context->check_ntlm_password(gensec_ntlmssp_state->auth_context,
+ user_info, &gensec_ntlmssp_state->server_info);
+
+ free_user_info(&user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ if (gensec_ntlmssp_state->server_info->user_session_key.length) {
+ DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length));
+ *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ gensec_ntlmssp_state->server_info->user_session_key.data,
+ gensec_ntlmssp_state->server_info->user_session_key.length);
+ }
+ if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
+ DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length));
+ *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ gensec_ntlmssp_state->server_info->lm_session_key.data,
+ gensec_ntlmssp_state->server_info->lm_session_key.length);
+ }
+ return nt_status;
+}
+
+static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+
+ TALLOC_CTX *mem_ctx = talloc_init("gensec_ntlmssp");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gensec_ntlmssp_state = talloc_p(mem_ctx, struct gensec_ntlmssp_state);
+ if (!gensec_ntlmssp_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gensec_ntlmssp_state->mem_ctx = mem_ctx;
+ gensec_ntlmssp_state->ntlmssp_state = NULL;
+ gensec_ntlmssp_state->auth_context = NULL;
+ gensec_ntlmssp_state->server_info = NULL;
+
+ gensec_security->private_data = gensec_ntlmssp_state;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS nt_status;
+ NTSTATUS status;
+ struct ntlmssp_state *ntlmssp_state;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+
+ status = gensec_ntlmssp_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ gensec_ntlmssp_state = gensec_security->private_data;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&gensec_ntlmssp_state->ntlmssp_state))) {
+ return nt_status;
+ }
+
+ ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state;
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&gensec_ntlmssp_state->auth_context))) {
+ return nt_status;
+ }
+
+ ntlmssp_state->auth_context = gensec_ntlmssp_state;
+ ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
+ ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
+ ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
+ ntlmssp_state->check_password = auth_ntlmssp_check_password;
+ ntlmssp_state->server_role = lp_server_role();
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
{
- struct ntlmssp_state *ntlmssp_state = NULL;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+ char *password = NULL;
+
NTSTATUS status;
+ status = gensec_ntlmssp_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- status = ntlmssp_client_start(&ntlmssp_state);
+ gensec_ntlmssp_state = gensec_security->private_data;
+ status = ntlmssp_client_start(&gensec_ntlmssp_state->ntlmssp_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_domain(ntlmssp_state, gensec_security->user.domain);
+ status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state,
+ gensec_security->user.domain);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_username(ntlmssp_state, gensec_security->user.name);
+ status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state,
+ gensec_security->user.name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_password(ntlmssp_state, gensec_security->user.password);
+ status = gensec_get_password(gensec_security, gensec_ntlmssp_state->mem_ctx, &password);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
-
- gensec_security->private_data = ntlmssp_state;
+
+ if (password) {
+ status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state,
+ password);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ gensec_security->private_data = gensec_ntlmssp_state;
return status;
}
@@ -57,66 +244,154 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
/*
wrappers for the ntlmssp_*() functions
*/
-NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length, DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_unseal_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
const DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_check_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_seal_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_sign_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
DATA_BLOB *session_key)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_session_key(ntlmssp_state, session_key);
+ return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key);
}
-NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
+/**
+ * Next state function for the wrapped NTLMSSP state machine
+ *
+ * @param gensec_ntlmssp_state NTLMSSP State
+ * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
+ * @param in The request, as a DATA_BLOB
+ * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
+ * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
+ * or NT_STATUS_OK if the user is authenticated.
+ */
+
+static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
+
+ return ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out);
+}
+
+/**
+ * Return the credentials of a logged on user, including session keys
+ * etc.
+ *
+ * Only valid after a successful authentication
+ *
+ * May only be called once per authentication.
+ *
+ */
+
+static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS nt_status;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
+ nt_status = make_session_info(gensec_ntlmssp_state->server_info, session_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ /* the session_info owns this now */
+ gensec_ntlmssp_state->server_info = NULL;
+
+ (*session_info)->session_key = data_blob_talloc((*session_info)->mem_ctx,
+ gensec_ntlmssp_state->ntlmssp_state->session_key.data,
+ gensec_ntlmssp_state->ntlmssp_state->session_key.length);
+
+ (*session_info)->workstation = talloc_strdup((*session_info)->mem_ctx,
+ gensec_ntlmssp_state->ntlmssp_state->workstation);
- return ntlmssp_update(ntlmssp_state, out_mem_ctx, in, out);
+ return NT_STATUS_OK;
}
-void gensec_ntlmssp_end(struct gensec_security *gensec_security)
+static void gensec_ntlmssp_end(struct gensec_security *gensec_security)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- ntlmssp_end(&ntlmssp_state);
+ if (gensec_ntlmssp_state->ntlmssp_state) {
+ ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state);
+ }
+ if (gensec_ntlmssp_state->auth_context) {
+ free_auth_context(&gensec_ntlmssp_state->auth_context);
+ }
+ if (gensec_ntlmssp_state->server_info) {
+ free_server_info(&gensec_ntlmssp_state->server_info);
+ }
+ talloc_destroy(gensec_ntlmssp_state->mem_ctx);
gensec_security->private_data = NULL;
}
+
+static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
+ .name = "ntlmssp",
+ .sasl_name = "NTLM",
+ .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
+ .oid = OID_NTLMSSP,
+ .client_start = gensec_ntlmssp_client_start,
+ .server_start = gensec_ntlmssp_server_start,
+ .update = gensec_ntlmssp_update,
+ .seal_packet = gensec_ntlmssp_seal_packet,
+ .sign_packet = gensec_ntlmssp_sign_packet,
+ .check_packet = gensec_ntlmssp_check_packet,
+ .unseal_packet = gensec_ntlmssp_unseal_packet,
+ .session_key = gensec_ntlmssp_session_key,
+ .session_info = gensec_ntlmssp_session_info,
+ .end = gensec_ntlmssp_end
+};
+
+
+NTSTATUS gensec_ntlmssp_init(void)
+{
+ NTSTATUS ret;
+ ret = register_backend("gensec", &gensec_ntlmssp_security_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_ntlmssp_security_ops.name));
+ return ret;
+ }
+
+ /* ugly cludge, but we need the auth subsystem for this to work */
+ auth_init();
+
+ return ret;
+}