summaryrefslogtreecommitdiff
path: root/source4/libcli/auth
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/auth')
-rw-r--r--source4/libcli/auth/config.mk3
-rw-r--r--source4/libcli/auth/credentials.c6
-rw-r--r--source4/libcli/auth/gensec.c210
-rw-r--r--source4/libcli/auth/gensec.h12
-rw-r--r--source4/libcli/auth/gensec.mk12
-rw-r--r--source4/libcli/auth/gensec_krb5.c57
-rw-r--r--source4/libcli/auth/gensec_ntlmssp.c21
-rw-r--r--source4/libcli/auth/kerberos.h1
-rw-r--r--source4/libcli/auth/ntlmssp_sign.c2
-rw-r--r--source4/libcli/auth/schannel.c268
-rw-r--r--source4/libcli/auth/schannel_sign.c67
-rw-r--r--source4/libcli/auth/spnego.c10
12 files changed, 361 insertions, 308 deletions
diff --git a/source4/libcli/auth/config.mk b/source4/libcli/auth/config.mk
index b37e214360..0c013ce0ef 100644
--- a/source4/libcli/auth/config.mk
+++ b/source4/libcli/auth/config.mk
@@ -1,8 +1,7 @@
#################################
# Start SUBSYSTEM GENSEC
[SUBSYSTEM::LIBCLI_AUTH]
-ADD_OBJ_FILES = libcli/auth/schannel_sign.o \
- libcli/auth/credentials.o \
+ADD_OBJ_FILES = libcli/auth/credentials.o \
libcli/auth/session.o \
libcli/auth/smbencrypt.o
REQUIRED_SUBSYSTEMS = \
diff --git a/source4/libcli/auth/credentials.c b/source4/libcli/auth/credentials.c
index 90b8313c9d..bcb462ae9d 100644
--- a/source4/libcli/auth/credentials.c
+++ b/source4/libcli/auth/credentials.c
@@ -192,18 +192,12 @@ next comes the client specific functions
void creds_client_init(struct creds_CredentialState *creds,
const struct netr_Credential *client_challenge,
const struct netr_Credential *server_challenge,
- const char *computer_name,
- const char *domain,
- const char *account_name,
const struct samr_Password *machine_password,
struct netr_Credential *initial_credential,
uint32_t negotiate_flags)
{
creds->sequence = time(NULL);
creds->negotiate_flags = negotiate_flags;
- creds->computer_name = talloc_strdup(creds, computer_name);
- creds->domain = talloc_strdup(creds, domain);
- creds->account_name = talloc_strdup(creds, account_name);
dump_data_pw("Client chall", client_challenge->data, sizeof(client_challenge->data));
dump_data_pw("Server chall", server_challenge->data, sizeof(server_challenge->data));
diff --git a/source4/libcli/auth/gensec.c b/source4/libcli/auth/gensec.c
index 69de016156..cc7327187c 100644
--- a/source4/libcli/auth/gensec.c
+++ b/source4/libcli/auth/gensec.c
@@ -4,7 +4,7 @@
Generic Authentication Interface
Copyright (C) Andrew Tridgell 2003
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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
@@ -130,13 +130,7 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx, struct gensec_security **gense
(*gensec_security)->ops = NULL;
- ZERO_STRUCT((*gensec_security)->user);
ZERO_STRUCT((*gensec_security)->target);
- ZERO_STRUCT((*gensec_security)->default_user);
-
- (*gensec_security)->default_user.name = "";
- (*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;
@@ -185,8 +179,6 @@ NTSTATUS gensec_client_start(TALLOC_CTX *mem_ctx, struct gensec_security **gense
(*gensec_security)->gensec_role = GENSEC_CLIENT;
(*gensec_security)->password_callback = NULL;
- ZERO_STRUCT((*gensec_security)->user);
-
return status;
}
@@ -507,163 +499,24 @@ BOOL gensec_have_feature(struct gensec_security *gensec_security,
}
/**
- * Set a username on a GENSEC context - ensures it is talloc()ed
- *
- */
-
-NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
-{
- gensec_security->user.name = talloc_strdup(gensec_security, user);
- if (user && !gensec_security->user.name) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Set a username on a GENSEC context - ensures it is talloc()ed
- *
- */
-
-const char *gensec_get_username(struct gensec_security *gensec_security)
-{
- if (gensec_security->user.name) {
- return gensec_security->user.name;
- }
- return gensec_security->default_user.name;
-}
-
-/**
- * Set a domain on a GENSEC context - ensures it is talloc()ed
+ * Associate a credentails structure with a GENSEC context - talloc_reference()s it to the context
*
*/
-NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
+NTSTATUS gensec_set_credentials(struct gensec_security *gensec_security, struct cli_credentials *credentials)
{
- gensec_security->user.domain = talloc_strdup(gensec_security, domain);
- if (domain && !gensec_security->user.domain) {
- return NT_STATUS_NO_MEMORY;
- }
+ gensec_security->credentials = talloc_reference(gensec_security, credentials);
return NT_STATUS_OK;
}
/**
- * Return the NT domain for this GENSEC context
+ * Return the credentails structure associated with a GENSEC context
*
*/
-const char *gensec_get_domain(struct gensec_security *gensec_security)
+struct cli_credentials *gensec_get_credentials(struct gensec_security *gensec_security)
{
- if (gensec_security->user.domain) {
- return gensec_security->user.domain;
- } else if (gensec_security->user.realm) {
- return gensec_security->user.realm;
- }
- 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, realm);
- if (realm && !gensec_security->user.realm) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
-}
-
-/**
- * Return the Krb5 realm for this context
- *
- */
-
-const char *gensec_get_realm(struct gensec_security *gensec_security)
-{
- if (gensec_security->user.realm) {
- return gensec_security->user.realm;
- } else if (gensec_security->user.domain) {
- return gensec_security->user.domain;
- }
- return gensec_security->default_user.realm;
-}
-
-/**
- * Return a kerberos principal for this context, if one has been set
- *
- */
-
-char *gensec_get_client_principal(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx)
-{
- const char *realm = gensec_get_realm(gensec_security);
- if (realm) {
- return talloc_asprintf(mem_ctx, "%s@%s",
- gensec_get_username(gensec_security),
- gensec_get_realm(gensec_security));
- } else {
- return talloc_strdup(mem_ctx, gensec_get_username(gensec_security));
- }
-}
-
-/**
- * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
- * not do a callback
- *
- */
-
-NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
- const char *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;
-}
-
-/**
- * Set the target principal name (if already known) on a GENSEC context - ensures it is talloc()ed
- *
- */
-
-NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal)
-{
- gensec_security->target.principal = talloc_strdup(gensec_security, principal);
- if (!gensec_security->target.principal) {
- return NT_STATUS_NO_MEMORY;
- }
- return NT_STATUS_OK;
+ return gensec_security->credentials;
}
/**
@@ -713,54 +566,6 @@ const char *gensec_get_target_service(struct gensec_security *gensec_security)
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
- */
-
-void gensec_set_password_callback(struct gensec_security *gensec_security,
- gensec_password_callback callback, void *callback_private_data)
-{
- gensec_security->password_callback = callback;
- gensec_security->password_callback_private = callback_private_data;
-}
-
-/**
- * Get (or call back for) a password.
- */
-
-NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- char **password)
-{
- if (gensec_security->user.password) {
- *password = talloc_strdup(mem_ctx, gensec_security->user.password);
- if (!*password) {
- return NT_STATUS_NO_MEMORY;
- } else {
- return NT_STATUS_OK;
- }
- }
- if (!gensec_security->password_callback) {
- *password = NULL;
- return NT_STATUS_OK;
- }
- return gensec_security->password_callback(gensec_security, mem_ctx, password);
-}
-
/*
register a GENSEC backend.
@@ -821,6 +626,5 @@ const struct gensec_critical_sizes *gensec_interface_version(void)
*/
NTSTATUS gensec_init(void)
{
- gensec_dcerpc_schannel_init();
return NT_STATUS_OK;
}
diff --git a/source4/libcli/auth/gensec.h b/source4/libcli/auth/gensec.h
index a4383d852c..91c817d48a 100644
--- a/source4/libcli/auth/gensec.h
+++ b/source4/libcli/auth/gensec.h
@@ -4,7 +4,7 @@
Generic Authentication Interface
Copyright (C) Andrew Tridgell 2003
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
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
@@ -28,13 +28,6 @@
#define GENSEC_OID_KERBEROS5_USER2USER "1 2 840 113554 1 2 2 3"
struct gensec_security;
-struct gensec_user {
- const char *workstation;
- const char *domain;
- const char *realm;
- const char *name;
- const char *password;
-};
struct gensec_target {
const char *principal;
const char *hostname;
@@ -105,8 +98,7 @@ struct gensec_security {
void *password_callback_private;
const struct gensec_security_ops *ops;
void *private_data;
- struct gensec_user user;
- struct gensec_user default_user;
+ struct cli_credentials *credentials;
struct gensec_target target;
enum gensec_role gensec_role;
BOOL subcontext;
diff --git a/source4/libcli/auth/gensec.mk b/source4/libcli/auth/gensec.mk
index 7e2e34081d..b4c612da14 100644
--- a/source4/libcli/auth/gensec.mk
+++ b/source4/libcli/auth/gensec.mk
@@ -69,6 +69,18 @@ REQUIRED_SUBSYSTEMS = AUTH
################################################
################################################
+# Start MODULE gensec_schannel
+[MODULE::gensec_schannel]
+SUBSYSTEM = GENSEC
+INIT_FUNCTION = gensec_schannel_init
+INIT_OBJ_FILES = libcli/auth/schannel.o
+ADD_OBJ_FILES = \
+ libcli/auth/schannel_sign.o
+REQUIRED_SUBSYSTEMS = AUTH SCHANNELDB
+# End MODULE gensec_ntlmssp
+################################################
+
+################################################
# Start SUBSYSTEM SCHANNELDB
[SUBSYSTEM::SCHANNELDB]
INIT_OBJ_FILES = \
diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c
index 71670632b9..453485d816 100644
--- a/source4/libcli/auth/gensec_krb5.c
+++ b/source4/libcli/auth/gensec_krb5.c
@@ -320,7 +320,12 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
struct gensec_krb5_state *gensec_krb5_state;
krb5_error_code ret;
NTSTATUS nt_status;
-
+ const char *hostname = gensec_get_target_hostname(gensec_security);
+ if (!hostname) {
+ DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
nt_status = gensec_krb5_start(gensec_security);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
@@ -341,22 +346,8 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
}
while (1) {
- if (gensec_security->target.principal) {
- DEBUG(5, ("Finding ticket for target [%s]\n", gensec_security->target.principal));
- ret = ads_krb5_mk_req(gensec_krb5_state->context,
- &gensec_krb5_state->auth_context,
- AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED,
- gensec_security->target.principal,
- gensec_krb5_state->ccache,
- &gensec_krb5_state->ticket);
- } else {
+ {
krb5_data in_data;
- const char *hostname = gensec_get_target_hostname(gensec_security);
- if (!hostname) {
- DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
- return NT_STATUS_ACCESS_DENIED;
- }
-
in_data.length = 0;
ret = krb5_mk_req(gensec_krb5_state->context,
@@ -372,36 +363,40 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
case 0:
return NT_STATUS_OK;
case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
- DEBUG(3, ("Server is not registered with our KDC: %s\n",
- error_message(ret)));
+ DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n",
+ hostname, error_message(ret)));
return NT_STATUS_ACCESS_DENIED;
case KRB5KDC_ERR_PREAUTH_FAILED:
case KRB5KRB_AP_ERR_TKT_EXPIRED:
case KRB5_CC_END:
+ /* Too much clock skew - we will need to kinit to re-skew the clock */
+ case KRB5KRB_AP_ERR_SKEW:
+ case KRB5_KDCREP_SKEW:
{
DEBUG(3, ("kerberos (mk_req) failed: %s\n",
error_message(ret)));
/* fall down to remaining code */
}
+
+
/* just don't print a message for these really ordinary messages */
case KRB5_FCC_NOFILE:
case KRB5_CC_NOTFOUND:
case ENOENT:
+
{
- char *password;
+ const char *password;
char *ccache_string;
time_t kdc_time = 0;
- nt_status = gensec_get_password(gensec_security,
- gensec_security,
- &password);
+ password = cli_credentials_get_password(gensec_security->credentials);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
/* this string should be unique */
ccache_string = talloc_asprintf(gensec_krb5_state, "MEMORY:%s:%s:%s",
- gensec_get_client_principal(gensec_security, gensec_krb5_state),
- gensec_get_target_principal(gensec_security),
+ cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state),
+ gensec_get_target_hostname(gensec_security),
generate_random_str(gensec_krb5_state, 16));
ret = krb5_cc_resolve(gensec_krb5_state->context, ccache_string, &gensec_krb5_state->ccache);
@@ -413,8 +408,8 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
}
ret = kerberos_kinit_password_cc(gensec_krb5_state->context, gensec_krb5_state->ccache,
- gensec_get_client_principal(gensec_security, gensec_krb5_state),
- password, NULL, &kdc_time);
+ cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state),
+ password, NULL, &kdc_time);
/* cope with ticket being in the future due to clock skew */
if ((unsigned)kdc_time > time(NULL)) {
@@ -422,10 +417,18 @@ static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security
int time_offset =(unsigned)kdc_time-t;
DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
krb5_set_real_time(gensec_krb5_state->context, t + time_offset + 1, 0);
+ break;
}
+ if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) {
+ DEBUG(1,("kinit for %s failed (%s)\n",
+ cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state),
+ error_message(ret)));
+ return NT_STATUS_TIME_DIFFERENCE_AT_DC;
+ }
if (ret) {
- DEBUG(1,("kinit failed (%s)\n",
+ DEBUG(1,("kinit for %s failed (%s)\n",
+ cli_credentials_get_principal(gensec_security->credentials, gensec_krb5_state),
error_message(ret)));
return NT_STATUS_WRONG_PASSWORD;
}
diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c
index 51456d9107..5955904886 100644
--- a/source4/libcli/auth/gensec_ntlmssp.c
+++ b/source4/libcli/auth/gensec_ntlmssp.c
@@ -109,7 +109,7 @@ static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state,
NT_STATUS_NOT_OK_RETURN(nt_status);
nt_status = auth_check_password(gensec_ntlmssp_state->auth_context, gensec_ntlmssp_state,
- user_info, &gensec_ntlmssp_state->server_info);
+ user_info, &gensec_ntlmssp_state->server_info);
talloc_free(user_info);
NT_STATUS_NOT_OK_RETURN(nt_status);
@@ -197,7 +197,7 @@ static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_secur
static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
{
struct gensec_ntlmssp_state *gensec_ntlmssp_state;
- char *password = NULL;
+ const char *password = NULL;
NTSTATUS nt_status;
nt_status = gensec_ntlmssp_start(gensec_security);
@@ -228,25 +228,20 @@ static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_secur
}
nt_status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state,
- gensec_security->user.domain);
+ cli_credentials_get_domain(gensec_security->credentials));
NT_STATUS_NOT_OK_RETURN(nt_status);
nt_status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state,
- gensec_security->user.name);
+ cli_credentials_get_username(gensec_security->credentials));
NT_STATUS_NOT_OK_RETURN(nt_status);
- if (gensec_security->user.name) {
- nt_status = gensec_get_password(gensec_security, gensec_ntlmssp_state, &password);
- NT_STATUS_NOT_OK_RETURN(nt_status);
- }
+ password = cli_credentials_get_password(gensec_security->credentials);
- if (password) {
- nt_status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, password);
- NT_STATUS_NOT_OK_RETURN(nt_status);
- }
+ nt_status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state, password);
+ NT_STATUS_NOT_OK_RETURN(nt_status);
nt_status = ntlmssp_set_workstation(gensec_ntlmssp_state->ntlmssp_state,
- gensec_get_workstation(gensec_security));
+ cli_credentials_get_workstation(gensec_security->credentials));
gensec_security->private_data = gensec_ntlmssp_state;
diff --git a/source4/libcli/auth/kerberos.h b/source4/libcli/auth/kerberos.h
index 9bb6d22eb6..c9b2eae55c 100644
--- a/source4/libcli/auth/kerberos.h
+++ b/source4/libcli/auth/kerberos.h
@@ -93,5 +93,6 @@ krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype);
BOOL kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, krb5_enctype enctype2);
void kerberos_free_data_contents(krb5_context context, krb5_data *pdata);
+krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry);
#endif /* HAVE_KRB5 */
diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c
index 1b391306bc..347a85da77 100644
--- a/source4/libcli/auth/ntlmssp_sign.c
+++ b/source4/libcli/auth/ntlmssp_sign.c
@@ -3,7 +3,7 @@
* Version 3.0
* NTLMSSP Signing routines
* Copyright (C) Luke Kenneth Casson Leighton 1996-2001
- * Copyright (C) Andrew Bartlett 2003
+ * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
*
* 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
diff --git a/source4/libcli/auth/schannel.c b/source4/libcli/auth/schannel.c
new file mode 100644
index 0000000000..3dbf10580b
--- /dev/null
+++ b/source4/libcli/auth/schannel.c
@@ -0,0 +1,268 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ dcerpc schannel operations
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_schannel.h"
+#include "auth/auth.h"
+#include "libcli/auth/schannel.h"
+
+static size_t schannel_sig_size(struct gensec_security *gensec_security)
+{
+ return 32;
+}
+
+static NTSTATUS schannel_session_key(struct gensec_security *gensec_security,
+ DATA_BLOB *session_key)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
+ const DATA_BLOB in, DATA_BLOB *out)
+{
+ struct schannel_state *state = gensec_security->private_data;
+ NTSTATUS status;
+ struct schannel_bind bind_schannel;
+ struct schannel_bind_ack bind_schannel_ack;
+ struct creds_CredentialState *creds;
+
+ const char *workstation;
+ const char *domain;
+ *out = data_blob(NULL, 0);
+
+ switch (gensec_security->gensec_role) {
+ case GENSEC_CLIENT:
+ if (state->state != SCHANNEL_STATE_START) {
+ /* we could parse the bind ack, but we don't know what it is yet */
+ return NT_STATUS_OK;
+ }
+
+ state->creds = talloc_reference(state, cli_credentials_get_netlogon_creds(gensec_security->credentials));
+
+ bind_schannel.unknown1 = 0;
+#if 0
+ /* to support this we'd need to have access to the full domain name */
+ bind_schannel.bind_type = 23;
+ bind_schannel.u.info23.domain = cli_credentials_get_domain(gensec_security->credentials);
+ bind_schannel.u.info23.account_name = cli_credentials_get_username(gensec_security->credentials);
+ bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(out_mem_ctx, fulldomainname);
+ bind_schannel.u.info23.workstation = str_format_nbt_domain(out_mem_ctx, cli_credentials_get_workstation(gensec_security->credentials));
+#else
+ bind_schannel.bind_type = 3;
+ bind_schannel.u.info3.domain = cli_credentials_get_domain(gensec_security->credentials);
+ bind_schannel.u.info3.workstation = cli_credentials_get_workstation(gensec_security->credentials);
+#endif
+
+ status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not create schannel bind: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ state->state = SCHANNEL_STATE_UPDATE_1;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ case GENSEC_SERVER:
+
+ if (state->state != SCHANNEL_STATE_START) {
+ /* no third leg on this protocol */
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* parse the schannel startup blob */
+ status = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
+ (ndr_pull_flags_fn_t)ndr_pull_schannel_bind);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (bind_schannel.bind_type == 23) {
+ workstation = bind_schannel.u.info23.workstation;
+ domain = bind_schannel.u.info23.domain;
+ } else {
+ workstation = bind_schannel.u.info3.workstation;
+ domain = bind_schannel.u.info3.domain;
+ }
+
+ /* pull the session key for this client */
+ status = schannel_fetch_session_key(out_mem_ctx, workstation,
+ domain, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
+ workstation, nt_errstr(status)));
+ return status;
+ }
+
+ state->creds = talloc_reference(state, creds);
+
+ bind_schannel_ack.unknown1 = 1;
+ bind_schannel_ack.unknown2 = 0;
+ bind_schannel_ack.unknown3 = 0x6c0000;
+
+ status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
+ workstation, nt_errstr(status)));
+ return status;
+ }
+
+ state->state = SCHANNEL_STATE_UPDATE_1;
+
+ return NT_STATUS_OK;
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ * Return the struct creds_CredentialState.
+ *
+ * Make sure not to call this unless gensec is using schannel...
+ */
+
+NTSTATUS dcerpc_schannel_creds(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ struct creds_CredentialState **creds)
+{
+ struct schannel_state *state = gensec_security->private_data;
+
+ *creds = talloc_reference(mem_ctx, state->creds);
+ if (!*creds) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * 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 schannel_session_info(struct gensec_security *gensec_security,
+ struct auth_session_info **session_info)
+{
+ (*session_info) = talloc(gensec_security, struct auth_session_info);
+ NT_STATUS_HAVE_NO_MEMORY(*session_info);
+
+ ZERO_STRUCTP(*session_info);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS schannel_start(struct gensec_security *gensec_security)
+{
+ struct schannel_state *state;
+
+ state = talloc(gensec_security, struct schannel_state);
+ if (!state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ state->state = SCHANNEL_STATE_START;
+ state->seq_num = 0;
+ gensec_security->private_data = state;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS schannel_server_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS status;
+ struct schannel_state *state;
+
+ status = schannel_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ state = gensec_security->private_data;
+ state->initiator = False;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS status;
+ struct schannel_state *state;
+
+ status = schannel_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ state = gensec_security->private_data;
+ state->initiator = True;
+
+ return NT_STATUS_OK;
+}
+
+
+static BOOL schannel_have_feature(struct gensec_security *gensec_security,
+ uint32_t feature)
+{
+ if (feature & (GENSEC_FEATURE_SIGN |
+ GENSEC_FEATURE_SEAL)) {
+ return True;
+ }
+ return False;
+}
+
+
+static const struct gensec_security_ops gensec_schannel_security_ops = {
+ .name = "schannel",
+ .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
+ .client_start = schannel_client_start,
+ .server_start = schannel_server_start,
+ .update = schannel_update,
+ .seal_packet = schannel_seal_packet,
+ .sign_packet = schannel_sign_packet,
+ .check_packet = schannel_check_packet,
+ .unseal_packet = schannel_unseal_packet,
+ .session_key = schannel_session_key,
+ .session_info = schannel_session_info,
+ .sig_size = schannel_sig_size,
+ .have_feature = schannel_have_feature,
+ .enabled = True
+};
+
+NTSTATUS gensec_schannel_init(void)
+{
+ NTSTATUS ret;
+ ret = gensec_register(&gensec_schannel_security_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_schannel_security_ops.name));
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/source4/libcli/auth/schannel_sign.c b/source4/libcli/auth/schannel_sign.c
index d582ff2dd0..3b493bd0d3 100644
--- a/source4/libcli/auth/schannel_sign.c
+++ b/source4/libcli/auth/schannel_sign.c
@@ -4,6 +4,7 @@
schannel library code
Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
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
@@ -22,12 +23,9 @@
#include "includes.h"
#include "lib/crypto/crypto.h"
-
-struct schannel_state {
- uint8_t session_key[16];
- uint32_t seq_num;
- BOOL initiator;
-};
+#include "libcli/auth/schannel.h"
+#include "libcli/auth/gensec.h"
+#include "libcli/auth/credentials.h"
#define NETSEC_SIGN_SIGNATURE { 0x77, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
#define NETSEC_SEAL_SIGNATURE { 0x77, 0x00, 0x7a, 0x00, 0xff, 0xff, 0x00, 0x00 }
@@ -43,7 +41,7 @@ static void netsec_deal_with_seq_num(struct schannel_state *state,
uint8_t sequence_key[16];
uint8_t digest1[16];
- hmac_md5(state->session_key, zeros, sizeof(zeros), digest1);
+ hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
hmac_md5(digest1, packet_digest, 8, sequence_key);
arcfour_crypt(seq_num, sequence_key, 8);
@@ -102,11 +100,14 @@ static void schannel_digest(const uint8_t sess_key[16],
/*
unseal a packet
*/
-NTSTATUS schannel_unseal_packet(struct schannel_state *state,
+NTSTATUS schannel_unseal_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)
{
+ struct schannel_state *state = gensec_security->private_data;
+
uint8_t digest_final[16];
uint8_t confounder[8];
uint8_t seq_num[8];
@@ -122,11 +123,11 @@ NTSTATUS schannel_unseal_packet(struct schannel_state *state,
RSIVAL(seq_num, 0, state->seq_num);
SIVAL(seq_num, 4, state->initiator?0:0x80);
- netsec_get_sealing_key(state->session_key, seq_num, sealing_key);
+ netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
arcfour_crypt(confounder, sealing_key, 8);
arcfour_crypt(data, sealing_key, length);
- schannel_digest(state->session_key,
+ schannel_digest(state->creds->session_key,
netsec_sig, confounder,
data, length, digest_final);
@@ -150,10 +151,14 @@ NTSTATUS schannel_unseal_packet(struct schannel_state *state,
/*
check the signature on a packet
*/
-NTSTATUS schannel_check_packet(struct schannel_state *state,
+NTSTATUS schannel_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)
{
+ struct schannel_state *state = gensec_security->private_data;
+
uint8_t digest_final[16];
uint8_t seq_num[8];
static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
@@ -167,9 +172,9 @@ NTSTATUS schannel_check_packet(struct schannel_state *state,
SIVAL(seq_num, 4, state->initiator?0:0x80);
dump_data_pw("seq_num:\n", seq_num, 8);
- dump_data_pw("sess_key:\n", state->session_key, 16);
+ dump_data_pw("sess_key:\n", state->creds->session_key, 16);
- schannel_digest(state->session_key,
+ schannel_digest(state->creds->session_key,
netsec_sig, NULL,
data, length, digest_final);
@@ -194,11 +199,14 @@ NTSTATUS schannel_check_packet(struct schannel_state *state,
/*
seal a packet
*/
-NTSTATUS schannel_seal_packet(struct schannel_state *state,
+NTSTATUS schannel_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)
{
+ struct schannel_state *state = gensec_security->private_data;
+
uint8_t digest_final[16];
uint8_t confounder[8];
uint8_t seq_num[8];
@@ -210,11 +218,11 @@ NTSTATUS schannel_seal_packet(struct schannel_state *state,
RSIVAL(seq_num, 0, state->seq_num);
SIVAL(seq_num, 4, state->initiator?0x80:0);
- schannel_digest(state->session_key,
+ schannel_digest(state->creds->session_key,
netsec_sig, confounder,
data, length, digest_final);
- netsec_get_sealing_key(state->session_key, seq_num, sealing_key);
+ netsec_get_sealing_key(state->creds->session_key, seq_num, sealing_key);
arcfour_crypt(confounder, sealing_key, 8);
arcfour_crypt(data, sealing_key, length);
@@ -239,11 +247,14 @@ NTSTATUS schannel_seal_packet(struct schannel_state *state,
/*
sign a packet
*/
-NTSTATUS schannel_sign_packet(struct schannel_state *state,
+NTSTATUS schannel_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)
{
+ struct schannel_state *state = gensec_security->private_data;
+
uint8_t digest_final[16];
uint8_t seq_num[8];
static const uint8_t netsec_sig[8] = NETSEC_SIGN_SIGNATURE;
@@ -251,7 +262,7 @@ NTSTATUS schannel_sign_packet(struct schannel_state *state,
RSIVAL(seq_num, 0, state->seq_num);
SIVAL(seq_num, 4, state->initiator?0x80:0);
- schannel_digest(state->session_key,
+ schannel_digest(state->creds->session_key,
netsec_sig, NULL,
data, length, digest_final);
@@ -271,23 +282,3 @@ NTSTATUS schannel_sign_packet(struct schannel_state *state,
return NT_STATUS_OK;
}
-
-/*
- create an schannel context state
-*/
-NTSTATUS schannel_start(TALLOC_CTX *mem_ctx,
- struct schannel_state **state,
- const uint8_t session_key[16],
- BOOL initiator)
-{
- (*state) = talloc(mem_ctx, struct schannel_state);
- if (!(*state)) {
- return NT_STATUS_NO_MEMORY;
- }
-
- memcpy((*state)->session_key, session_key, 16);
- (*state)->initiator = initiator;
- (*state)->seq_num = 0;
-
- return NT_STATUS_OK;
-}
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c
index 3980767165..f5a091cd78 100644
--- a/source4/libcli/auth/spnego.c
+++ b/source4/libcli/auth/spnego.c
@@ -610,7 +610,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
spnego_out.negTokenInit.mechTypes = mechlist;
spnego_out.negTokenInit.reqFlags = 0;
spnego_out.negTokenInit.mechListMIC
- = data_blob_string_const(gensec_get_target_principal(gensec_security));
+ = data_blob_string_const(talloc_asprintf(out_mem_ctx, "%s$@%s", lp_netbios_name(), lp_realm()));
spnego_out.negTokenInit.mechToken = unwrapped_out;
if (spnego_write_data(out_mem_ctx, out, &spnego_out) == -1) {
@@ -657,13 +657,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
}
if (spnego.negTokenInit.targetPrincipal) {
- DEBUG(5, ("Server claims it's principal name is %s\n", spnego.negTokenInit.targetPrincipal));
- nt_status = gensec_set_target_principal(gensec_security,
- spnego.negTokenInit.targetPrincipal);
- if (!NT_STATUS_IS_OK(nt_status)) {
- spnego_free_data(&spnego);
- return nt_status;
- }
+ DEBUG(5, ("Server claims it's principal name is %s (ignored)\n", spnego.negTokenInit.targetPrincipal));
}
nt_status = gensec_spnego_client_parse_negTokenInit(gensec_security,