summaryrefslogtreecommitdiffstats
path: root/source/libsmb
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2005-09-30 17:13:37 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:04:48 -0500
commit939c3cb5d78e3a2236209b296aa8aba8bdce32d3 (patch)
tree5f3a22ba40783ce548328a44b9262a451f33ad27 /source/libsmb
parentf049fd463b087ccf4873b03675cca5eb8576af2e (diff)
downloadsamba-939c3cb5d78e3a2236209b296aa8aba8bdce32d3.tar.gz
samba-939c3cb5d78e3a2236209b296aa8aba8bdce32d3.tar.xz
samba-939c3cb5d78e3a2236209b296aa8aba8bdce32d3.zip
r10656: BIG merge from trunk. Features not copied over
* \PIPE\unixinfo * winbindd's {group,alias}membership new functions * winbindd's lookupsids() functionality * swat (trunk changes to be reverted as per discussion with Deryck)
Diffstat (limited to 'source/libsmb')
-rw-r--r--source/libsmb/cliconnect.c27
-rw-r--r--source/libsmb/clidgram.c2
-rw-r--r--source/libsmb/clientgen.c83
-rw-r--r--source/libsmb/clierror.c17
-rw-r--r--source/libsmb/clikrb5.c451
-rw-r--r--source/libsmb/clireadwrite.c12
-rw-r--r--source/libsmb/clispnego.c5
-rw-r--r--source/libsmb/clitrans.c19
-rw-r--r--source/libsmb/credentials.c295
-rw-r--r--source/libsmb/errormap.c4
-rw-r--r--source/libsmb/libsmb_compat.c2
-rw-r--r--source/libsmb/libsmbclient.c89
-rw-r--r--source/libsmb/ntlmssp.c84
-rw-r--r--source/libsmb/ntlmssp_parse.c6
-rw-r--r--source/libsmb/ntlmssp_sign.c436
-rw-r--r--source/libsmb/passchange.c66
-rw-r--r--source/libsmb/pwd_cache.c1
-rw-r--r--source/libsmb/smb_share_modes.c93
-rw-r--r--source/libsmb/smbdes.c78
-rw-r--r--source/libsmb/smbencrypt.c30
-rw-r--r--source/libsmb/smberr.c1
-rw-r--r--source/libsmb/spnego.c4
-rw-r--r--source/libsmb/trusts_util.c47
23 files changed, 1216 insertions, 636 deletions
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index 3d8e36c493a..7ecc7695171 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -532,7 +532,7 @@ static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *
DEBUG(2,("Doing kerberos session setup\n"));
/* generate the encapsulated kerberos5 ticket */
- rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5);
+ rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0);
if (rc) {
DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc)));
@@ -600,7 +600,7 @@ static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *use
nt_status = ntlmssp_update(ntlmssp_state,
blob_in, &blob_out);
data_blob_free(&blob_in);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
if (turn == 1) {
/* and wrap it in a SPNEGO wrapper */
msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
@@ -1337,25 +1337,6 @@ BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
return True;
}
-/****************************************************************************
- Initialise client credentials for authenticated pipe access.
-****************************************************************************/
-
-void init_creds(struct ntuser_creds *creds, const char* username,
- const char* domain, const char* password)
-{
- ZERO_STRUCTP(creds);
-
- pwd_set_cleartext(&creds->pwd, password);
-
- fstrcpy(creds->user_name, username);
- fstrcpy(creds->domain, domain);
-
- if (!*username) {
- creds->pwd.null_pwd = True;
- }
-}
-
/**
establishes a connection to after the negprot.
@param output_cli A fully initialised cli structure, non-null only on success
@@ -1474,7 +1455,6 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli,
int signing_state,
BOOL *retry)
{
- struct ntuser_creds creds;
NTSTATUS nt_status;
struct cli_state *cli = NULL;
@@ -1513,8 +1493,7 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli,
}
}
- init_creds(&creds, user, domain, password);
- cli_init_creds(cli, &creds);
+ cli_init_creds(cli, user, domain, password);
*output_cli = cli;
return NT_STATUS_OK;
diff --git a/source/libsmb/clidgram.c b/source/libsmb/clidgram.c
index 819616105ed..dfb613238f6 100644
--- a/source/libsmb/clidgram.c
+++ b/source/libsmb/clidgram.c
@@ -101,7 +101,7 @@ BOOL cli_send_mailslot(BOOL unique, const char *mailslot,
DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name),
inet_ntoa(dest_ip)));
- return message_send_pid(nmbd_pid, MSG_SEND_PACKET, &p, sizeof(p),
+ return message_send_pid(pid_to_procid(nmbd_pid), MSG_SEND_PACKET, &p, sizeof(p),
False);
}
diff --git a/source/libsmb/clientgen.c b/source/libsmb/clientgen.c
index f1794ab5dc8..bc64cc919b7 100644
--- a/source/libsmb/clientgen.c
+++ b/source/libsmb/clientgen.c
@@ -221,15 +221,16 @@ void cli_setup_bcc(struct cli_state *cli, void *p)
Initialise credentials of a client structure.
****************************************************************************/
-void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
+void cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password)
{
- /* copy_nt_creds(&cli->usr, usr); */
- fstrcpy(cli->domain , usr->domain);
- fstrcpy(cli->user_name, usr->user_name);
- memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
+ fstrcpy(cli->domain, domain);
+ fstrcpy(cli->user_name, username);
+ pwd_set_cleartext(&cli->pwd, password);
+ if (!*username) {
+ cli->pwd.null_pwd = True;
+ }
- DEBUG(10,("cli_init_creds: user %s domain %s\n",
- cli->user_name, cli->domain));
+ DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain));
}
/****************************************************************************
@@ -260,7 +261,6 @@ void cli_setup_signing_state(struct cli_state *cli, int signing_state)
struct cli_state *cli_initialise(struct cli_state *cli)
{
BOOL alloced_cli = False;
- int i;
/* Check the effective uid - make sure we are not setuid */
if (is_setuid_root()) {
@@ -332,16 +332,9 @@ struct cli_state *cli_initialise(struct cli_state *cli)
/* initialise signing */
cli_null_set_signing(cli);
- for (i=0; i<PI_MAX_PIPES; i++)
- cli->pipes[i].fnum = 0;
-
- cli->netlogon_pipe.fnum = 0;
-
cli->initialised = 1;
cli->allocated = alloced_cli;
- cli->pipe_idx = -1;
-
return cli;
/* Clean up after malloc() error */
@@ -358,34 +351,42 @@ struct cli_state *cli_initialise(struct cli_state *cli)
}
/****************************************************************************
-close the session
-****************************************************************************/
+ External interface.
+ Close an open named pipe over SMB. Free any authentication data.
+ ****************************************************************************/
-void cli_nt_session_close(struct cli_state *cli)
+void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
{
- int i;
-
- for (i=0; i<PI_MAX_PIPES; i++) {
- if (cli->pipes[i].pipe_auth_flags & AUTH_PIPE_NTLMSSP) {
- ntlmssp_end(&cli->pipes[i].ntlmssp_pipe_state);
- }
+ if (!cli_close(cli->cli, cli->fnum)) {
+ DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s "
+ "to machine %s. Error was %s\n",
+ cli->pipe_name,
+ cli->cli->desthost,
+ cli_errstr(cli->cli)));
+ }
- if (cli->pipes[i].fnum != 0)
- cli_close(cli, cli->pipes[i].fnum);
- cli->pipes[i].fnum = 0;
+ if (cli->auth.cli_auth_data_free_func) {
+ (*cli->auth.cli_auth_data_free_func)(&cli->auth);
}
- cli->pipe_idx = -1;
+
+ DEBUG(10,("cli_rpc_pipe_close: closed pipe %s to machine %s\n",
+ cli->pipe_name, cli->cli->desthost ));
+
+ DLIST_REMOVE(cli->cli->pipe_list, cli);
+ talloc_destroy(cli->mem_ctx);
}
/****************************************************************************
-close the NETLOGON session holding the session key for NETSEC
+ Close all pipes open on this session.
****************************************************************************/
-void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
+void cli_nt_pipes_close(struct cli_state *cli)
{
- if (cli->netlogon_pipe.fnum != 0) {
- cli_close(cli, cli->netlogon_pipe.fnum);
- cli->netlogon_pipe.fnum = 0;
+ struct rpc_pipe_client *cp, *next;
+
+ for (cp = cli->pipe_list; cp; cp = next) {
+ next = cp->next;
+ cli_rpc_pipe_close(cp);
}
}
@@ -395,8 +396,7 @@ void cli_nt_netlogon_netsec_session_close(struct cli_state *cli)
void cli_close_connection(struct cli_state *cli)
{
- cli_nt_session_close(cli);
- cli_nt_netlogon_netsec_session_close(cli);
+ cli_nt_pipes_close(cli);
/*
* tell our peer to free his resources. Wihtout this, when an
@@ -410,8 +410,9 @@ void cli_close_connection(struct cli_state *cli)
* the only user for this so far is smbmount which passes opened connection
* down to kernel's smbfs module.
*/
- if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != DO_NOT_DO_TDIS ) )
+ if ( (cli->cnum != (uint16)-1) && (cli->smb_rw_error != DO_NOT_DO_TDIS ) ) {
cli_tdis(cli);
+ }
SAFE_FREE(cli->outbuf);
SAFE_FREE(cli->inbuf);
@@ -420,19 +421,16 @@ void cli_close_connection(struct cli_state *cli)
data_blob_free(&cli->secblob);
data_blob_free(&cli->user_session_key);
- if (cli->pipes[cli->pipe_idx].pipe_auth_flags & AUTH_PIPE_NTLMSSP)
- ntlmssp_end(&cli->pipes[cli->pipe_idx].ntlmssp_pipe_state);
-
if (cli->mem_ctx) {
talloc_destroy(cli->mem_ctx);
cli->mem_ctx = NULL;
}
- if (cli->fd != -1)
+ if (cli->fd != -1) {
close(cli->fd);
+ }
cli->fd = -1;
cli->smb_rw_error = 0;
-
}
/****************************************************************************
@@ -444,8 +442,9 @@ void cli_shutdown(struct cli_state *cli)
BOOL allocated = cli->allocated;
cli_close_connection(cli);
ZERO_STRUCTP(cli);
- if (allocated)
+ if (allocated) {
free(cli);
+ }
}
/****************************************************************************
diff --git a/source/libsmb/clierror.c b/source/libsmb/clierror.c
index 355a2adf34d..6938702e1e0 100644
--- a/source/libsmb/clierror.c
+++ b/source/libsmb/clierror.c
@@ -404,3 +404,20 @@ BOOL cli_is_dos_error(struct cli_state *cli)
return cli_is_error(cli) && !(flgs2 & FLAGS2_32_BIT_ERROR_CODES);
}
+
+/* Return the last error always as an NTSTATUS. */
+
+NTSTATUS cli_get_nt_error(struct cli_state *cli)
+{
+ if (cli_is_nt_error(cli)) {
+ return cli_nt_error(cli);
+ } else if (cli_is_dos_error(cli)) {
+ uint32 ecode;
+ uint8 eclass;
+ cli_dos_error(cli, &eclass, &ecode);
+ return dos_to_ntstatus(eclass, ecode);
+ } else {
+ /* Something went wrong, we don't know what. */
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+}
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
index 1741c1db3cd..e3ad5f17cb0 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -3,6 +3,8 @@
simple kerberos5 routines for active directory
Copyright (C) Andrew Tridgell 2001
Copyright (C) Luke Howard 2002-2003
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Guenther Deschner 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
@@ -186,17 +188,107 @@
}
#endif
- void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt)
+BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
{
+ DATA_BLOB pac_contents;
+ ASN1_DATA data;
+ int data_type;
+
+ if (!auth_data->length) {
+ return False;
+ }
+
+ asn1_load(&data, *auth_data);
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_SEQUENCE(0));
+ asn1_start_tag(&data, ASN1_CONTEXT(0));
+ asn1_read_Integer(&data, &data_type);
+
+ if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) {
+ DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type));
+ asn1_free(&data);
+ return False;
+ }
+
+ asn1_end_tag(&data);
+ asn1_start_tag(&data, ASN1_CONTEXT(1));
+ asn1_read_OctetString(&data, &pac_contents);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_end_tag(&data);
+ asn1_free(&data);
+
+ *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length);
+
+ data_blob_free(&pac_contents);
+
+ return True;
+}
+
+ BOOL get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt)
+{
+ DATA_BLOB auth_data_wrapped;
+ BOOL got_auth_data_pac = False;
+ int i;
+
#if defined(HAVE_KRB5_TKT_ENC_PART2)
- if (tkt->enc_part2 && tkt->enc_part2->authorization_data && tkt->enc_part2->authorization_data[0] && tkt->enc_part2->authorization_data[0]->length)
- *auth_data = data_blob(tkt->enc_part2->authorization_data[0]->contents,
- tkt->enc_part2->authorization_data[0]->length);
+ if (tkt->enc_part2 && tkt->enc_part2->authorization_data &&
+ tkt->enc_part2->authorization_data[0] &&
+ tkt->enc_part2->authorization_data[0]->length)
+ {
+ for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) {
+
+ if (tkt->enc_part2->authorization_data[i]->ad_type !=
+ KRB5_AUTHDATA_IF_RELEVANT) {
+ DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
+ tkt->enc_part2->authorization_data[i]->ad_type));
+ continue;
+ }
+
+ auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents,
+ tkt->enc_part2->authorization_data[i]->length);
+
+ /* check if it is a PAC */
+ got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
+ data_blob_free(&auth_data_wrapped);
+
+ if (!got_auth_data_pac) {
+ continue;
+ }
+ }
+
+ return got_auth_data_pac;
+ }
+
#else
- if (tkt->ticket.authorization_data && tkt->ticket.authorization_data->len)
- *auth_data = data_blob(tkt->ticket.authorization_data->val->ad_data.data,
- tkt->ticket.authorization_data->val->ad_data.length);
+ if (tkt->ticket.authorization_data &&
+ tkt->ticket.authorization_data->len)
+ {
+ for (i = 0; i < tkt->ticket.authorization_data->len; i++) {
+
+ if (tkt->ticket.authorization_data->val[i].ad_type !=
+ KRB5_AUTHDATA_IF_RELEVANT) {
+ DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n",
+ tkt->ticket.authorization_data->val[i].ad_type));
+ continue;
+ }
+
+ auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data,
+ tkt->ticket.authorization_data->val[i].ad_data.length);
+
+ /* check if it is a PAC */
+ got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
+ data_blob_free(&auth_data_wrapped);
+
+ if (!got_auth_data_pac) {
+ continue;
+ }
+ }
+
+ return got_auth_data_pac;
+ }
#endif
+ return False;
}
krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
@@ -435,7 +527,7 @@ cleanup_princ:
get a kerberos5 ticket for the given service
*/
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
- DATA_BLOB *ticket, DATA_BLOB *session_key_krb5)
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts)
{
krb5_error_code retval;
krb5_data packet;
@@ -475,7 +567,7 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
if ((retval = ads_krb5_mk_req(context,
&auth_context,
- AP_OPTS_USE_SUBKEY,
+ AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
principal,
ccdef, &packet))) {
goto failed;
@@ -550,10 +642,349 @@ failed:
#endif
}
+void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum,
+ PAC_SIGNATURE_DATA *sig)
+{
+#ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM
+ cksum->cksumtype = (krb5_cksumtype)sig->type;
+ cksum->checksum.length = sig->signature.buf_len;
+ cksum->checksum.data = sig->signature.buffer;
+#else
+ cksum->checksum_type = (krb5_cksumtype)sig->type;
+ cksum->length = sig->signature.buf_len;
+ cksum->contents = sig->signature.buffer;
+#endif
+}
+
+krb5_error_code smb_krb5_verify_checksum(krb5_context context,
+ krb5_keyblock *keyblock,
+ krb5_keyusage usage,
+ krb5_checksum *cksum,
+ uint8 *data,
+ size_t length)
+{
+ krb5_error_code ret;
+
+ /* verify the checksum */
+
+ /* welcome to the wonderful world of samba's kerberos abstraction layer:
+ *
+ * function heimdal 0.6.1rc3 heimdal 0.7 MIT krb 1.4.2
+ * -----------------------------------------------------------------------------
+ * krb5_c_verify_checksum - works works
+ * krb5_verify_checksum works (6 args) works (6 args) broken (7 args)
+ */
+
+#if defined(HAVE_KRB5_C_VERIFY_CHECKSUM)
+ {
+ krb5_boolean checksum_valid = False;
+ krb5_data input;
+
+ input.data = (char *)data;
+ input.length = length;
+
+ ret = krb5_c_verify_checksum(context,
+ keyblock,
+ usage,
+ &input,
+ cksum,
+ &checksum_valid);
+ if (!checksum_valid)
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+
+#elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY)
+
+ /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key
+ * without enctype and it ignores any key_usage types - Guenther */
+
+ {
+
+ krb5_crypto crypto;
+ ret = krb5_crypto_init(context,
+ keyblock,
+ 0,
+ &crypto);
+ if (ret) {
+ DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n",
+ error_message(ret)));
+ return ret;
+ }
+
+ ret = krb5_verify_checksum(context,
+ crypto,
+ usage,
+ data,
+ length,
+ cksum);
+
+ krb5_crypto_destroy(context, crypto);
+ }
+
+#else
+#error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION
+#endif
+
+ return ret;
+}
+
+time_t get_authtime_from_tkt(krb5_ticket *tkt)
+{
+#if defined(HAVE_KRB5_TKT_ENC_PART2)
+ return tkt->enc_part2->times.authtime;
+#else
+ return tkt->ticket.authtime;
+#endif
+}
+
+static int get_kvno_from_ap_req(krb5_ap_req *ap_req)
+{
+#ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */
+ if (ap_req->ticket->enc_part.kvno)
+ return ap_req->ticket->enc_part.kvno;
+#else /* Heimdal */
+ if (ap_req->ticket.enc_part.kvno)
+ return *ap_req->ticket.enc_part.kvno;
+#endif
+ return 0;
+}
+
+static krb5_enctype get_enctype_from_ap_req(krb5_ap_req *ap_req)
+{
+#ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */
+ return ap_req->ticket.enc_part.etype;
+#else /* MIT */
+ return ap_req->ticket->enc_part.enctype;
+#endif
+}
+
+static krb5_error_code
+get_key_from_keytab(krb5_context context,
+ krb5_keytab keytab,
+ krb5_const_principal server,
+ krb5_enctype enctype,
+ krb5_kvno kvno,
+ krb5_keyblock **out_key)
+{
+ krb5_keytab_entry entry;
+ krb5_error_code ret;
+ krb5_keytab real_keytab;
+ char *name = NULL;
+
+ if (keytab == NULL) {
+ krb5_kt_default(context, &real_keytab);
+ } else {
+ real_keytab = keytab;
+ }
+
+ if ( DEBUGLEVEL >= 10 ) {
+ krb5_unparse_name(context, server, &name);
+ DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n",
+ kvno, enctype, name));
+ krb5_free_unparsed_name(context, name);
+ }
+
+ ret = krb5_kt_get_entry(context,
+ real_keytab,
+ server,
+ kvno,
+ enctype,
+ &entry);
+
+ if (ret) {
+ DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret)));
+ goto out;
+ }
+
+#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
+ ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
+#elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
+ ret = krb5_copy_keyblock(context, &entry.key, out_key);
+#else
+#error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
+#endif
+
+ if (ret) {
+ DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret)));
+ goto out;
+ }
+
+ smb_krb5_kt_free_entry(context, &entry);
+
+out:
+ if (keytab == NULL) {
+ krb5_kt_close(context, real_keytab);
+ }
+
+ return ret;
+}
+
+void smb_krb5_free_ap_req(krb5_context context,
+ krb5_ap_req *ap_req)
+{
+#ifdef HAVE_KRB5_FREE_AP_REQ /* MIT */
+ krb5_free_ap_req(context, ap_req);
+#elif defined(HAVE_FREE_AP_REQ) /* Heimdal */
+ free_AP_REQ(ap_req);
+#else
+#error UNKNOWN_KRB5_AP_REQ_FREE_FUNCTION
+#endif
+}
+
+/* Prototypes */
+#if defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */
+krb5_error_code decode_krb5_ap_req(const krb5_data *code, krb5_ap_req **rep);
+#endif
+
+krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context,
+ const krb5_data *inbuf,
+ krb5_kvno *kvno,
+ krb5_enctype *enctype)
+{
+ krb5_error_code ret;
+#ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
+ {
+ krb5_ap_req ap_req;
+
+ ret = krb5_decode_ap_req(context, inbuf, &ap_req);
+ if (ret)
+ return ret;
+
+ *kvno = get_kvno_from_ap_req(&ap_req);
+ *enctype = get_enctype_from_ap_req(&ap_req);
+
+ smb_krb5_free_ap_req(context, &ap_req);
+ }
+#elif defined(HAVE_DECODE_KRB5_AP_REQ) /* MIT */
+ {
+ krb5_ap_req *ap_req = NULL;
+
+ ret = decode_krb5_ap_req(inbuf, &ap_req);
+ if (ret)
+ return ret;
+
+ *kvno = get_kvno_from_ap_req(ap_req);
+ *enctype = get_enctype_from_ap_req(ap_req);
+
+ smb_krb5_free_ap_req(context, ap_req);
+ }
+#else
+#error UNKOWN_KRB5_AP_REQ_DECODING_FUNCTION
+#endif
+ return ret;
+}
+
+krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
+ krb5_auth_context *auth_context,
+ const krb5_data *inbuf,
+ krb5_const_principal server,
+ krb5_keytab keytab,
+ krb5_flags *ap_req_options,
+ krb5_ticket **ticket,
+ krb5_keyblock **keyblock)
+{
+ krb5_error_code ret;
+ krb5_ap_req *ap_req = NULL;
+ krb5_kvno kvno;
+ krb5_enctype enctype;
+ krb5_keyblock *local_keyblock;
+
+ ret = krb5_rd_req(context,
+ auth_context,
+ inbuf,
+ server,
+ keytab,
+ ap_req_options,
+ ticket);
+ if (ret) {
+ return ret;
+ }
+
+ ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype);
+ if (ret) {
+ return ret;
+ }
+
+ ret = get_key_from_keytab(context,
+ keytab,
+ server,
+ enctype,
+ kvno,
+ &local_keyblock);
+ if (ret) {
+ DEBUG(0,("krb5_rd_req_return_keyblock_from_keytab: failed to call get_key_from_keytab\n"));
+ goto out;
+ }
+
+out:
+ if (ap_req) {
+ smb_krb5_free_ap_req(context, ap_req);
+ }
+
+ if (ret && local_keyblock != NULL) {
+ krb5_free_keyblock(context, local_keyblock);
+ } else {
+ *keyblock = local_keyblock;
+ }
+
+ return ret;
+}
+
+krb5_error_code smb_krb5_parse_name_norealm(krb5_context context,
+ const char *name,
+ krb5_principal *principal)
+{
+#ifdef HAVE_KRB5_PARSE_NAME_NOREALM
+ return krb5_parse_name_norealm(context, name, principal);
+#endif
+
+ /* we are cheating here because parse_name will in fact set the realm.
+ * We don't care as the only caller of smb_krb5_parse_name_norealm
+ * ignores the realm anyway when calling
+ * smb_krb5_principal_compare_any_realm later - Guenther */
+
+ return krb5_parse_name(context, name, principal);
+}
+
+BOOL smb_krb5_principal_compare_any_realm(krb5_context context,
+ krb5_const_principal princ1,
+ krb5_const_principal princ2)
+{
+#ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM
+
+ return krb5_principal_compare_any_realm(context, princ1, princ2);
+
+/* krb5_princ_size is a macro in MIT */
+#elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
+
+ int i, len1, len2;
+ const krb5_data *p1, *p2;
+
+ len1 = krb5_princ_size(context, princ1);
+ len2 = krb5_princ_size(context, princ2);
+
+ if (len1 != len2)
+ return False;
+
+ for (i = 0; i < len1; i++) {
+
+ p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i);
+ p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i);
+
+ if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length))
+ return False;
+ }
+
+ return True;
+#else
+#error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION
+#endif
+}
+
#else /* HAVE_KRB5 */
/* this saves a few linking headaches */
int cli_krb5_get_ticket(const char *principal, time_t time_offset,
- DATA_BLOB *ticket, DATA_BLOB *session_key_krb5)
+ DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts)
{
DEBUG(0,("NO KERBEROS SUPPORT\n"));
return 1;
diff --git a/source/libsmb/clireadwrite.c b/source/libsmb/clireadwrite.c
index 1220907629c..55e36b646b9 100644
--- a/source/libsmb/clireadwrite.c
+++ b/source/libsmb/clireadwrite.c
@@ -323,13 +323,13 @@ static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset,
0x0008 start of message mode named pipe protocol
****************************************************************************/
-size_t cli_write(struct cli_state *cli,
+ssize_t cli_write(struct cli_state *cli,
int fnum, uint16 write_mode,
const char *buf, off_t offset, size_t size)
{
- int bwritten = 0;
- int issued = 0;
- int received = 0;
+ ssize_t bwritten = 0;
+ unsigned int issued = 0;
+ unsigned int received = 0;
int mpx = 1;
int block = cli->max_xmit - (smb_size+32);
int blocks = (size + (block-1)) / block;
@@ -343,8 +343,8 @@ size_t cli_write(struct cli_state *cli,
while (received < blocks) {
while ((issued - received < mpx) && (issued < blocks)) {
- int bsent = issued * block;
- int size1 = MIN(block, size - bsent);
+ ssize_t bsent = issued * block;
+ ssize_t size1 = MIN(block, size - bsent);
if (!cli_issue_write(cli, fnum, offset + bsent,
write_mode,
diff --git a/source/libsmb/clispnego.c b/source/libsmb/clispnego.c
index 85b7bd9e1ee..33fc265f798 100644
--- a/source/libsmb/clispnego.c
+++ b/source/libsmb/clispnego.c
@@ -325,14 +325,15 @@ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])
*/
int spnego_gen_negTokenTarg(const char *principal, int time_offset,
DATA_BLOB *targ,
- DATA_BLOB *session_key_krb5)
+ DATA_BLOB *session_key_krb5, uint32 extra_ap_opts)
{
int retval;
DATA_BLOB tkt, tkt_wrapped;
const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_NTLMSSP, NULL};
/* get a kerberos ticket for the service and extract the session key */
- retval = cli_krb5_get_ticket(principal, time_offset, &tkt, session_key_krb5);
+ retval = cli_krb5_get_ticket(principal, time_offset,
+ &tkt, session_key_krb5, extra_ap_opts);
if (retval)
return retval;
diff --git a/source/libsmb/clitrans.c b/source/libsmb/clitrans.c
index c6b1d465ffe..5d3710b92e2 100644
--- a/source/libsmb/clitrans.c
+++ b/source/libsmb/clitrans.c
@@ -464,8 +464,8 @@ BOOL cli_send_nt_trans(struct cli_state *cli,
}
/****************************************************************************
- receive a SMB nttrans response allocating the necessary memory
- ****************************************************************************/
+ Receive a SMB nttrans response allocating the necessary memory.
+****************************************************************************/
BOOL cli_receive_nt_trans(struct cli_state *cli,
char **param, unsigned int *param_len,
@@ -503,7 +503,7 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
*/
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
- if (cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
+ if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
cli_signing_trans_stop(cli);
return(False);
}
@@ -637,11 +637,22 @@ BOOL cli_receive_nt_trans(struct cli_state *cli,
}
if (cli_is_dos_error(cli)) {
cli_dos_error(cli, &eclass, &ecode);
- if(cli->pipes[cli->pipe_idx].fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata)) {
+ if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
+ cli_signing_trans_stop(cli);
+ return(False);
+ }
+ }
+ /*
+ * Likewise for NT_STATUS_BUFFER_TOO_SMALL
+ */
+ if (cli_is_nt_error(cli)) {
+ if (!NT_STATUS_EQUAL(cli_nt_error(cli),
+ NT_STATUS_BUFFER_TOO_SMALL)) {
cli_signing_trans_stop(cli);
return(False);
}
}
+
/* parse out the total lengths again - they can shrink! */
if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
diff --git a/source/libsmb/credentials.c b/source/libsmb/credentials.c
index 0d521bae8ac..3f2dcd850b3 100644
--- a/source/libsmb/credentials.c
+++ b/source/libsmb/credentials.c
@@ -2,6 +2,7 @@
Unix SMB/CIFS implementation.
code to manipulate domain credentials
Copyright (C) Andrew Tridgell 1997-1998
+ Largely rewritten by Jeremy Allison 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
@@ -21,8 +22,9 @@
#include "includes.h"
/****************************************************************************
-represent a credential as a string
+ Represent a credential as a string.
****************************************************************************/
+
char *credstr(const uchar *cred)
{
static fstring buf;
@@ -34,182 +36,243 @@ char *credstr(const uchar *cred)
/****************************************************************************
- setup the session key.
-Input: 8 byte challenge block
+ Setup the session key.
+ Input: 8 byte challenge block
8 byte server challenge block
16 byte md4 encrypted password
-Output:
- 8 byte session key
+ Output:
+ 16 byte session key (last 8 bytes zero).
****************************************************************************/
-void cred_session_key(const DOM_CHAL *clnt_chal, const DOM_CHAL *srv_chal, const uchar *pass,
- uchar session_key[8])
+
+static void cred_create_session_key(const DOM_CHAL *clnt_chal_in,
+ const DOM_CHAL *srv_chal_in,
+ const uchar *pass_in,
+ uchar session_key_out[16])
{
uint32 sum[2];
unsigned char sum2[8];
- sum[0] = IVAL(clnt_chal->data, 0) + IVAL(srv_chal->data, 0);
- sum[1] = IVAL(clnt_chal->data, 4) + IVAL(srv_chal->data, 4);
+ sum[0] = IVAL(clnt_chal_in->data, 0) + IVAL(srv_chal_in->data, 0);
+ sum[1] = IVAL(clnt_chal_in->data, 4) + IVAL(srv_chal_in->data, 4);
SIVAL(sum2,0,sum[0]);
SIVAL(sum2,4,sum[1]);
- cred_hash1(session_key, sum2, pass);
+ cred_hash1(session_key_out, sum2, pass_in);
+ memset(&session_key_out[8], '\0', 8);
/* debug output */
- DEBUG(4,("cred_session_key\n"));
+ DEBUG(4,("cred_create_session_key\n"));
- DEBUG(5,(" clnt_chal: %s\n", credstr(clnt_chal->data)));
- DEBUG(5,(" srv_chal : %s\n", credstr(srv_chal->data)));
+ DEBUG(5,(" clnt_chal_in: %s\n", credstr(clnt_chal_in->data)));
+ DEBUG(5,(" srv_chal_in : %s\n", credstr(srv_chal_in->data)));
DEBUG(5,(" clnt+srv : %s\n", credstr(sum2)));
- DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
+ DEBUG(5,(" sess_key_out : %s\n", credstr(session_key_out)));
}
-
/****************************************************************************
-create a credential
-
-Input:
- 8 byte sesssion key
- 8 byte stored credential
- 4 byte timestamp
-
-Output:
- 8 byte credential
+ Utility function to step credential chain one forward.
+ Deliberately doesn't update the seed. See reseed comment below.
****************************************************************************/
-void cred_create(uchar session_key[8], DOM_CHAL *stor_cred, UTIME timestamp,
- DOM_CHAL *cred)
+
+static void creds_step(struct dcinfo *dc)
{
- DOM_CHAL time_cred;
+ DOM_CHAL time_chal;
- SIVAL(time_cred.data, 0, IVAL(stor_cred->data, 0) + timestamp.time);
- SIVAL(time_cred.data, 4, IVAL(stor_cred->data, 4));
+ DEBUG(5,("\tsequence = 0x%x\n", (unsigned int)dc->sequence ));
- cred_hash2(cred->data, time_cred.data, session_key);
+ DEBUG(5,("\tseed: %s\n", credstr(dc->seed_chal.data) ));
- /* debug output*/
- DEBUG(4,("cred_create\n"));
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq %s\n", credstr(time_chal.data) ));
- DEBUG(5,(" sess_key : %s\n", credstr(session_key)));
- DEBUG(5,(" stor_cred: %s\n", credstr(stor_cred->data)));
- DEBUG(5,(" timestamp: %x\n" , timestamp.time));
- DEBUG(5,(" timecred : %s\n", credstr(time_cred.data)));
- DEBUG(5,(" calc_cred: %s\n", credstr(cred->data)));
-}
+ cred_hash2(dc->clnt_chal.data, time_chal.data, dc->sess_key);
+ DEBUG(5,("\tCLIENT %s\n", credstr(dc->clnt_chal.data) ));
-/****************************************************************************
- check a supplied credential
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
+
+ DEBUG(5,("\tseed+seq+1 %s\n", credstr(time_chal.data) ));
-Input:
- 8 byte received credential
- 8 byte sesssion key
- 8 byte stored credential
- 4 byte timestamp
+ cred_hash2(dc->srv_chal.data, time_chal.data, dc->sess_key);
+
+ DEBUG(5,("\tSERVER %s\n", credstr(dc->srv_chal.data) ));
+}
-Output:
- returns 1 if computed credential matches received credential
- returns 0 otherwise
+
+/****************************************************************************
+ Create a server credential struct.
****************************************************************************/
-int cred_assert(DOM_CHAL *cred, uchar session_key[8], DOM_CHAL *stored_cred,
- UTIME timestamp)
+
+void creds_server_init(struct dcinfo *dc,
+ DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal,
+ const char mach_pw[16],
+ DOM_CHAL *init_chal_out)
{
- DOM_CHAL cred2;
+ DEBUG(10,("creds_server_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_server_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_server_init: machine pass", mach_pw, 16);
- cred_create(session_key, stored_cred, timestamp, &cred2);
+ /* Just in case this isn't already there */
+ memcpy(dc->mach_pw, mach_pw, 16);
- /* debug output*/
- DEBUG(4,("cred_assert\n"));
+ /* Generate the session key. */
+ cred_create_session_key(clnt_chal, /* Stored client challenge. */
+ srv_chal, /* Stored server challenge. */
+ dc->mach_pw, /* input machine password. */
+ dc->sess_key); /* output session key. */
- DEBUG(5,(" challenge : %s\n", credstr(cred->data)));
- DEBUG(5,(" calculated: %s\n", credstr(cred2.data)));
+ dump_data_pw("creds_server_init: session key", dc->sess_key, 16);
- if (memcmp(cred->data, cred2.data, 8) == 0)
- {
- DEBUG(5, ("credentials check ok\n"));
- return True;
- }
- else
- {
- DEBUG(5, ("credentials check wrong\n"));
+ /* Generate the next client and server creds. */
+ cred_hash2(dc->clnt_chal.data, /* output */
+ clnt_chal->data, /* input */
+ dc->sess_key); /* input */
+
+ cred_hash2(dc->srv_chal.data, /* output */
+ srv_chal->data, /* input */
+ dc->sess_key); /* input */
+
+ /* Seed is the client chal. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
+
+ DEBUG(10,("creds_server_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_server_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_server_init: seed : %s\n", credstr(dc->seed_chal.data) ));
+
+ memcpy(init_chal_out->data, dc->srv_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential sent by the client.
+****************************************************************************/
+
+BOOL creds_server_check(const struct dcinfo *dc, const DOM_CHAL *rcv_cli_chal_in)
+{
+ if (memcmp(dc->clnt_chal.data, rcv_cli_chal_in->data, 8)) {
+ DEBUG(5,("creds_server_check: challenge : %s\n", credstr(rcv_cli_chal_in->data)));
+ DEBUG(5,("calculated: %s\n", credstr(dc->clnt_chal.data)));
+ DEBUG(0,("creds_server_check: credentials check failed.\n"));
return False;
}
+ DEBUG(10,("creds_server_check: credentials check OK.\n"));
+ return True;
}
-
/****************************************************************************
- checks credentials; generates next step in the credential chain
+ Replace current seed chal. Internal function - due to split server step below.
****************************************************************************/
-BOOL clnt_deal_with_creds(uchar sess_key[8],
- DOM_CRED *sto_clnt_cred, DOM_CRED *rcv_srv_cred)
+
+static void creds_reseed(struct dcinfo *dc)
{
- UTIME new_clnt_time;
- uint32 new_cred;
+ DOM_CHAL time_chal;
- DEBUG(5,("clnt_deal_with_creds: %d\n", __LINE__));
+ SIVAL(time_chal.data, 0, IVAL(dc->seed_chal.data, 0) + dc->sequence + 1);
+ SIVAL(time_chal.data, 4, IVAL(dc->seed_chal.data, 4));
- /* increment client time by one second */
- new_clnt_time.time = sto_clnt_cred->timestamp.time + 1;
+ dc->seed_chal = time_chal;
- /* check that the received server credentials are valid */
- if (!cred_assert(&rcv_srv_cred->challenge, sess_key,
- &sto_clnt_cred->challenge, new_clnt_time))
- {
- return False;
- }
+ DEBUG(5,("cred_reseed: seed %s\n", credstr(dc->seed_chal.data) ));
+}
- /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
- new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
- new_cred += new_clnt_time.time;
+/****************************************************************************
+ Step the server credential chain one forward.
+****************************************************************************/
- /* store new seed in client credentials */
- SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+BOOL creds_server_step(struct dcinfo *dc, const DOM_CRED *received_cred, DOM_CRED *cred_out)
+{
+ dc->sequence = received_cred->timestamp.time;
- DEBUG(5,(" new clnt cred: %s\n", credstr(sto_clnt_cred->challenge.data)));
- return True;
-}
+ creds_step(dc);
+
+ /* Create the outgoing credentials */
+ cred_out->timestamp.time = dc->sequence + 1;
+ cred_out->challenge = dc->srv_chal;
+ creds_reseed(dc);
+
+ return creds_server_check(dc, &received_cred->challenge);
+}
/****************************************************************************
- checks credentials; generates next step in the credential chain
+ Create a client credential struct.
****************************************************************************/
-BOOL deal_with_creds(uchar sess_key[8],
- DOM_CRED *sto_clnt_cred,
- DOM_CRED *rcv_clnt_cred, DOM_CRED *rtn_srv_cred)
+
+void creds_client_init(struct dcinfo *dc,
+ DOM_CHAL *clnt_chal,
+ DOM_CHAL *srv_chal,
+ const char mach_pw[16],
+ DOM_CHAL *init_chal_out)
{
- UTIME new_clnt_time;
- uint32 new_cred;
+ dc->sequence = time(NULL);
- DEBUG(5,("deal_with_creds: %d\n", __LINE__));
+ DEBUG(10,("creds_client_init: client chal : %s\n", credstr(clnt_chal->data) ));
+ DEBUG(10,("creds_client_init: server chal : %s\n", credstr(srv_chal->data) ));
+ dump_data_pw("creds_client_init: machine pass", mach_pw, 16);
- /* check that the received client credentials are valid */
- if (!cred_assert(&rcv_clnt_cred->challenge, sess_key,
- &sto_clnt_cred->challenge, rcv_clnt_cred->timestamp))
- {
- return False;
- }
+ /* Just in case this isn't already there */
+ memcpy(dc->mach_pw, mach_pw, 16);
- /* increment client time by one second */
- new_clnt_time.time = rcv_clnt_cred->timestamp.time + 1;
+ /* Generate the session key. */
+ cred_create_session_key(clnt_chal, /* Stored client challenge. */
+ srv_chal, /* Stored server challenge. */
+ dc->mach_pw, /* input machine password. */
+ dc->sess_key); /* output session key. */
- /* first 4 bytes of the new seed is old client 4 bytes + clnt time + 1 */
- new_cred = IVAL(sto_clnt_cred->challenge.data, 0);
- new_cred += new_clnt_time.time;
+ dump_data_pw("creds_client_init: session key", dc->sess_key, 16);
- DEBUG(5,("deal_with_creds: new_cred[0]=%x\n", new_cred));
+ /* Generate the next client and server creds. */
+ cred_hash2(dc->clnt_chal.data, /* output */
+ clnt_chal->data, /* input */
+ dc->sess_key); /* input */
- /* doesn't matter that server time is 0 */
- rtn_srv_cred->timestamp.time = 0;
+ cred_hash2(dc->srv_chal.data, /* output */
+ srv_chal->data, /* input */
+ dc->sess_key); /* input */
- DEBUG(5,("deal_with_creds: new_clnt_time=%x\n", new_clnt_time.time));
+ /* Seed is the client cred. */
+ memcpy(dc->seed_chal.data, dc->clnt_chal.data, 8);
- /* create return credentials for inclusion in the reply */
- cred_create(sess_key, &sto_clnt_cred->challenge, new_clnt_time,
- &rtn_srv_cred->challenge);
-
- DEBUG(5,("deal_with_creds: clnt_cred=%s\n", credstr(sto_clnt_cred->challenge.data)));
+ DEBUG(10,("creds_client_init: clnt : %s\n", credstr(dc->clnt_chal.data) ));
+ DEBUG(10,("creds_client_init: server : %s\n", credstr(dc->srv_chal.data) ));
+ DEBUG(10,("creds_client_init: seed : %s\n", credstr(dc->seed_chal.data) ));
- /* store new seed in client credentials */
- SIVAL(sto_clnt_cred->challenge.data, 0, new_cred);
+ memcpy(init_chal_out->data, dc->clnt_chal.data, 8);
+}
+
+/****************************************************************************
+ Check a credential returned by the server.
+****************************************************************************/
+BOOL creds_client_check(const struct dcinfo *dc, const DOM_CHAL *rcv_srv_chal_in)
+{
+ if (memcmp(dc->srv_chal.data, rcv_srv_chal_in->data, 8)) {
+ DEBUG(5,("creds_client_check: challenge : %s\n", credstr(rcv_srv_chal_in->data)));
+ DEBUG(5,("calculated: %s\n", credstr(dc->srv_chal.data)));
+ DEBUG(0,("creds_client_check: credentials check failed.\n"));
+ return False;
+ }
+ DEBUG(10,("creds_client_check: credentials check OK.\n"));
return True;
}
+
+/****************************************************************************
+ Step the client credentials to the next element in the chain, updating the
+ current client and server credentials and the seed
+ produce the next authenticator in the sequence ready to send to
+ the server
+****************************************************************************/
+
+void creds_client_step(struct dcinfo *dc, DOM_CRED *next_cred_out)
+{
+ dc->sequence += 2;
+ creds_step(dc);
+ creds_reseed(dc);
+
+ next_cred_out->challenge = dc->clnt_chal;
+ next_cred_out->timestamp.time = dc->sequence;
+}
diff --git a/source/libsmb/errormap.c b/source/libsmb/errormap.c
index 8462fbee877..3c0b13ad6ff 100644
--- a/source/libsmb/errormap.c
+++ b/source/libsmb/errormap.c
@@ -62,7 +62,7 @@ static const struct {
{ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC},
{ERRDOS, 87, NT_STATUS_INVALID_CID},
{ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED},
- {ERRDOS, 87, NT_STATUS_INVALID_PARAMETER},
+ {ERRDOS, ERRinvalidparam, NT_STATUS_INVALID_PARAMETER},
{ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE},
{ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE},
{ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST},
@@ -338,7 +338,7 @@ static const struct {
{ERRDOS, 203, NT_STATUS(0xc0000100)},
{ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY},
{ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR},
- {ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY},
+ {ERRDOS, ERRbaddirectory, NT_STATUS_NOT_A_DIRECTORY},
{ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE},
{ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION},
{ERRDOS, 206, NT_STATUS_NAME_TOO_LONG},
diff --git a/source/libsmb/libsmb_compat.c b/source/libsmb/libsmb_compat.c
index f9461f93683..5699e153bbd 100644
--- a/source/libsmb/libsmb_compat.c
+++ b/source/libsmb/libsmb_compat.c
@@ -420,7 +420,7 @@ int smbc_open_print_job(const char *fname)
{
SMBCFILE * file = statcont->open_print_job(statcont, fname);
if (!file) return -1;
- return (int) file;
+ return file->cli_fd;
}
int smbc_list_print_jobs(const char *purl, smbc_list_print_job_fn fn)
diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c
index fe8f878aa57..1e729abb221 100644
--- a/source/libsmb/libsmbclient.c
+++ b/source/libsmb/libsmbclient.c
@@ -80,6 +80,23 @@ static int DLIST_CONTAINS(SMBCFILE * list, SMBCFILE *p) {
return False;
}
+/*
+ * Find an lsa pipe handle associated with a cli struct.
+ */
+
+static struct rpc_pipe_client *find_lsa_pipe_hnd(struct cli_state *ipc_cli)
+{
+ struct rpc_pipe_client *pipe_hnd;
+
+ for (pipe_hnd = ipc_cli->pipe_list; pipe_hnd; pipe_hnd = pipe_hnd->next) {
+ if (pipe_hnd->pipe_idx == PI_LSARPC) {
+ return pipe_hnd;
+ }
+ }
+
+ return NULL;
+}
+
static int smbc_close_ctx(SMBCCTX *context, SMBCFILE *file);
static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int whence);
@@ -800,6 +817,7 @@ SMBCSRV *smbc_attr_server(SMBCCTX *context,
{
struct in_addr ip;
struct cli_state *ipc_cli;
+ struct rpc_pipe_client *pipe_hnd;
NTSTATUS nt_status;
SMBCSRV *ipc_srv=NULL;
@@ -835,29 +853,27 @@ SMBCSRV *smbc_attr_server(SMBCCTX *context,
return NULL;
}
- if(pol) {
+ pipe_hnd = cli_rpc_pipe_open_noauth(ipc_cli, PI_LSARPC, &nt_status);
+ if (!pipe_hnd) {
+ DEBUG(1, ("cli_nt_session_open fail!\n"));
+ errno = ENOTSUP;
+ cli_shutdown(ipc_cli);
+ return NULL;
+ }
- if (!cli_nt_session_open(ipc_cli, PI_LSARPC)) {
- DEBUG(1, ("cli_nt_session_open fail!\n"));
- errno = ENOTSUP;
- cli_shutdown(ipc_cli);
- return NULL;
- }
-
- /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
- but NT sends 0x2000000 so we might as well do it too. */
-
- nt_status = cli_lsa_open_policy(ipc_cli,
- ipc_cli->mem_ctx,
- True,
- GENERIC_EXECUTE_ACCESS,
- pol);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- errno = smbc_errno(context, ipc_cli);
- cli_shutdown(ipc_cli);
- return NULL;
- }
+ /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
+ but NT sends 0x2000000 so we might as well do it too. */
+
+ nt_status = rpccli_lsa_open_policy(pipe_hnd,
+ ipc_cli->mem_ctx,
+ True,
+ GENERIC_EXECUTE_ACCESS,
+ pol);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ errno = smbc_errno(context, ipc_cli);
+ cli_shutdown(ipc_cli);
+ return NULL;
}
ipc_srv = SMB_MALLOC_P(SMBCSRV);
@@ -1782,7 +1798,7 @@ static off_t smbc_lseek_ctx(SMBCCTX *context, SMBCFILE *file, off_t offset, int
if (!cli_qfileinfo(targetcli, file->cli_fd, NULL, &size, NULL, NULL,
NULL, NULL, NULL))
{
- SMB_BIG_UINT b_size = size;
+ SMB_OFF_T b_size = size;
if (!cli_getattrE(targetcli, file->cli_fd, NULL, &b_size, NULL, NULL,
NULL))
{
@@ -3041,7 +3057,7 @@ static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir)
/*
* We return the pointer here as the offset
*/
- ret_val = (int)dir->dir_next;
+ ret_val = (off_t)(long)dir->dir_next;
return ret_val;
}
@@ -3347,14 +3363,20 @@ static void convert_sid_to_string(struct cli_state *ipc_cli,
char **domains = NULL;
char **names = NULL;
uint32 *types = NULL;
-
+ struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
sid_to_string(str, sid);
- if (numeric) return; /* no lookup desired */
-
+ if (numeric) {
+ return; /* no lookup desired */
+ }
+
+ if (!pipe_hnd) {
+ return;
+ }
+
/* Ask LSA to convert the sid to a name */
- if (!NT_STATUS_IS_OK(cli_lsa_lookup_sids(ipc_cli, ipc_cli->mem_ctx,
+ if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_sids(pipe_hnd, ipc_cli->mem_ctx,
pol, 1, sid, &domains,
&names, &types)) ||
!domains || !domains[0] || !names || !names[0]) {
@@ -3378,6 +3400,11 @@ static BOOL convert_string_to_sid(struct cli_state *ipc_cli,
uint32 *types = NULL;
DOM_SID *sids = NULL;
BOOL result = True;
+ struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
+
+ if (!pipe_hnd) {
+ return False;
+ }
if (numeric) {
if (strncmp(str, "S-", 2) == 0) {
@@ -3388,7 +3415,7 @@ static BOOL convert_string_to_sid(struct cli_state *ipc_cli,
goto done;
}
- if (!NT_STATUS_IS_OK(cli_lsa_lookup_names(ipc_cli, ipc_cli->mem_ctx,
+ if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx,
pol, 1, &str, &sids,
&types))) {
result = False;
@@ -5161,7 +5188,7 @@ static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_pr
/* Try to open the file for reading ... */
- if ((int)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) {
+ if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) {
DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno));
return -1; /* smbc_open sets errno */
@@ -5170,7 +5197,7 @@ static int smbc_print_file_ctx(SMBCCTX *c_file, const char *fname, SMBCCTX *c_pr
/* Now, try to open the printer file for writing */
- if ((int)(fid2 = c_print->open_print_job(c_print, printq)) < 0) {
+ if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) {
saverr = errno; /* Save errno */
c_file->close_fn(c_file, fid1);
diff --git a/source/libsmb/ntlmssp.c b/source/libsmb/ntlmssp.c
index b02c2384a8d..6b551e8774c 100644
--- a/source/libsmb/ntlmssp.c
+++ b/source/libsmb/ntlmssp.c
@@ -5,6 +5,7 @@
Copyright (C) Andrew Tridgell 2001
Copyright (C) Andrew Bartlett 2001-2003
+ Copyright (C) Andrew Bartlett 2005 (Updated from gensec).
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
@@ -217,6 +218,12 @@ NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state,
uint32 ntlmssp_command;
int i;
+ if (ntlmssp_state->expected_state == NTLMSSP_DONE) {
+ /* Called update after negotiations finished. */
+ DEBUG(1, ("Called NTLMSSP after state machine was 'done'\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
*out = data_blob(NULL, 0);
if (!in.length && ntlmssp_state->stored_response.length) {
@@ -348,6 +355,13 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+ if (neg_flags & NTLMSSP_NEGOTIATE_56) {
+ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56;
+ }
+ }
+
+ if (!(neg_flags & NTLMSSP_NEGOTIATE_56)) {
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_56;
}
if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
@@ -360,6 +374,34 @@ static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
}
+/**
+ Weaken NTLMSSP keys to cope with down-level clients and servers.
+
+ We probably should have some parameters to control this, but as
+ it only occours for LM_KEY connections, and this is controlled
+ by the client lanman auth/lanman auth parameters, it isn't too bad.
+*/
+
+void ntlmssp_weaken_keys(NTLMSSP_STATE *ntlmssp_state)
+{
+ /* Key weakening not performed on the master key for NTLM2
+ and does not occour for NTLM1. Therefore we only need
+ to do this for the LM_KEY.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+ ;
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ ntlmssp_state->session_key.data[7] = 0xa0;
+ } else { /* forty bits */
+ ntlmssp_state->session_key.data[5] = 0xe5;
+ ntlmssp_state->session_key.data[6] = 0x38;
+ ntlmssp_state->session_key.data[7] = 0xb0;
+ }
+ ntlmssp_state->session_key.length = 8;
+ }
+}
/**
* Next state function for the Negotiate packet
@@ -398,6 +440,9 @@ static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
return NT_STATUS_INVALID_PARAMETER;
}
+ DEBUG(10, ("ntlmssp_server_negotiate: client = %s, domain = %s\n",
+ cliname ? cliname : "", domname ? domname : ""));
+
SAFE_FREE(cliname);
SAFE_FREE(domname);
@@ -495,7 +540,7 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
DATA_BLOB lm_session_key = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
uint32 ntlmssp_command, auth_flags;
- NTSTATUS nt_status;
+ NTSTATUS nt_status = NT_STATUS_OK;
/* used by NTLM2 */
BOOL doing_ntlm2 = False;
@@ -639,6 +684,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
data_blob_free(&encrypted_session_key);
return nt_status;
}
+
+ /* LM Key is incompatible. */
+ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
}
}
@@ -710,11 +758,11 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
if (!encrypted_session_key.data || encrypted_session_key.length != 16) {
data_blob_free(&encrypted_session_key);
DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n",
- encrypted_session_key.length));
+ (unsigned int)encrypted_session_key.length));
return NT_STATUS_INVALID_PARAMETER;
} else if (!session_key.data || session_key.length != 16) {
DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n",
- session_key.length));
+ (unsigned int)session_key.length));
ntlmssp_state->session_key = session_key;
} else {
dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
@@ -731,6 +779,9 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
ntlmssp_state->session_key = session_key;
}
+ /* The client might need us to use a partial-strength session key */
+ ntlmssp_weaken_keys(ntlmssp_state);
+
if (!NT_STATUS_IS_OK(nt_status)) {
ntlmssp_state->session_key = data_blob(NULL, 0);
} else if (ntlmssp_state->session_key.length) {
@@ -739,8 +790,8 @@ static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
data_blob_free(&encrypted_session_key);
- /* allow arbitarily many authentications */
- ntlmssp_state->expected_state = NTLMSSP_AUTH;
+ /* Only one authentication allowed per server state. */
+ ntlmssp_state->expected_state = NTLMSSP_DONE;
return nt_status;
}
@@ -784,7 +835,8 @@ NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_NTLM2 |
NTLMSSP_NEGOTIATE_KEY_EXCH |
- NTLMSSP_NEGOTIATE_SIGN;
+ NTLMSSP_NEGOTIATE_SIGN |
+ NTLMSSP_NEGOTIATE_SEAL;
return NT_STATUS_OK;
}
@@ -851,7 +903,7 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
DATA_BLOB nt_response = data_blob(NULL, 0);
DATA_BLOB session_key = data_blob(NULL, 0);
DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
- NTSTATUS nt_status;
+ NTSTATUS nt_status = NT_STATUS_OK;
if (!msrpc_parse(&reply, "CdBd",
"NTLMSSP",
@@ -977,8 +1029,6 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data);
dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
} else {
-
-
uchar lm_hash[16];
uchar nt_hash[16];
E_deshash(ntlmssp_state->password, lm_hash);
@@ -998,8 +1048,8 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY)
&& lp_client_lanman_auth()) {
- SMBsesskeygen_lmv1(lm_hash, lm_response.data,
- session_key.data);
+ SMBsesskeygen_lm_sess_key(lm_hash, lm_response.data,
+ session_key.data);
dump_data_pw("LM session key\n", session_key.data, session_key.length);
} else {
SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
@@ -1045,19 +1095,22 @@ static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state,
data_blob_free(&ntlmssp_state->chal);
+ ntlmssp_state->session_key = session_key;
+
+ /* The client might be using 56 or 40 bit weakened keys */
+ ntlmssp_weaken_keys(ntlmssp_state);
+
ntlmssp_state->chal = challenge_blob;
ntlmssp_state->lm_resp = lm_response;
ntlmssp_state->nt_resp = nt_response;
- ntlmssp_state->session_key = session_key;
- ntlmssp_state->expected_state = NTLMSSP_UNKNOWN;
+ ntlmssp_state->expected_state = NTLMSSP_DONE;
if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
- return nt_status;
}
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ return nt_status;
}
NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
@@ -1103,4 +1156,3 @@ NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
return NT_STATUS_OK;
}
-
diff --git a/source/libsmb/ntlmssp_parse.c b/source/libsmb/ntlmssp_parse.c
index 4b3043aec80..e71504867e9 100644
--- a/source/libsmb/ntlmssp_parse.c
+++ b/source/libsmb/ntlmssp_parse.c
@@ -216,7 +216,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
/* if odd length and unicode */
return False;
}
- if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data)
return False;
if (0 < len1) {
@@ -244,7 +244,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
return False;
}
- if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data)
return False;
if (0 < len1) {
@@ -272,7 +272,7 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
return False;
}
- if (blob->data + ptr < (uint8 *)ptr || blob->data + ptr < blob->data)
+ if (blob->data + ptr < (uint8 *)(unsigned long)ptr || blob->data + ptr < blob->data)
return False;
*b = data_blob(blob->data + ptr, len1);
diff --git a/source/libsmb/ntlmssp_sign.c b/source/libsmb/ntlmssp_sign.c
index b8105970762..51023ca3565 100644
--- a/source/libsmb/ntlmssp_sign.c
+++ b/source/libsmb/ntlmssp_sign.c
@@ -2,8 +2,7 @@
* Unix SMB/CIFS implementation.
* Version 3.0
* NTLMSSP Signing routines
- * Copyright (C) Luke Kenneth Casson Leighton 1996-2001
- * Copyright (C) Andrew Bartlett 2003
+ * Copyright (C) Andrew Bartlett 2003-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
@@ -27,74 +26,25 @@
#define SRV_SIGN "session key to server-to-client signing key magic constant"
#define SRV_SEAL "session key to server-to-client sealing key magic constant"
-static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
-{
- unsigned char index_i = hash[256];
- unsigned char index_j = hash[257];
- int ind;
-
- for (ind = 0; ind < len; ind++)
- {
- unsigned char tc;
- unsigned char t;
-
- index_i++;
- index_j += hash[index_i];
-
- tc = hash[index_i];
- hash[index_i] = hash[index_j];
- hash[index_j] = tc;
-
- t = hash[index_i] + hash[index_j];
- data[ind] = data[ind] ^ hash[t];
- }
-
- hash[256] = index_i;
- hash[257] = index_j;
-}
-
-static void calc_hash(unsigned char hash[258], unsigned char *k2, int k2l)
-{
- unsigned char j = 0;
- int ind;
-
- for (ind = 0; ind < 256; ind++)
- {
- hash[ind] = (unsigned char)ind;
- }
-
- for (ind = 0; ind < 256; ind++)
- {
- unsigned char tc;
-
- j += (hash[ind] + k2[ind%k2l]);
-
- tc = hash[ind];
- hash[ind] = hash[j];
- hash[j] = tc;
- }
-
- hash[256] = 0;
- hash[257] = 0;
-}
+/**
+ * Some notes on then NTLM2 code:
+ *
+ * NTLM2 is a AEAD system. This means that the data encrypted is not
+ * all the data that is signed. In DCE-RPC case, the headers of the
+ * DCE-RPC packets are also signed. This prevents some of the
+ * fun-and-games one might have by changing them.
+ *
+ */
-static void calc_ntlmv2_hash(unsigned char hash[258], unsigned char digest[16],
- DATA_BLOB session_key,
- const char *constant)
+static void calc_ntlmv2_key(unsigned char subkey[16],
+ DATA_BLOB session_key,
+ const char *constant)
{
struct MD5Context ctx3;
-
- /* NOTE: This code is currently complate fantasy - it's
- got more in common with reality than the previous code
- (the LM session key is not the right thing to use) but
- it still needs work */
-
MD5Init(&ctx3);
MD5Update(&ctx3, session_key.data, session_key.length);
- MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant)+1);
- MD5Final(digest, &ctx3);
-
- calc_hash(hash, digest, 16);
+ MD5Update(&ctx3, constant, strlen(constant)+1);
+ MD5Final(subkey, &ctx3);
}
enum ntlmssp_direction {
@@ -103,64 +53,107 @@ enum ntlmssp_direction {
};
static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- enum ntlmssp_direction direction,
- DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ enum ntlmssp_direction direction,
+ DATA_BLOB *sig,
+ BOOL encrypt_sig)
{
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
HMACMD5Context ctx;
uchar seq_num[4];
uchar digest[16];
- SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
- hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
- hmac_md5_update(seq_num, 4, &ctx);
- hmac_md5_update(data, length, &ctx);
- hmac_md5_final(digest, &ctx);
- if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
- , ntlmssp_state->ntlmssp_seq_num)) {
+ *sig = data_blob(NULL, NTLMSSP_SIG_SIZE);
+ if (!sig->data) {
return NT_STATUS_NO_MEMORY;
}
- if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ switch (direction) {
+ case NTLMSSP_SEND:
+ DEBUG(100,("ntlmssp_make_packet_signature: SEND seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_send_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
+
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_send_seq_num);
+ ntlmssp_state->ntlm2_send_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->send_sign_key, 16, &ctx);
+ break;
+ case NTLMSSP_RECEIVE:
+
+ DEBUG(100,("ntlmssp_make_packet_signature: RECV seq = %u, len = %u, pdu_len = %u\n",
+ ntlmssp_state->ntlm2_recv_seq_num,
+ (unsigned int)length,
+ (unsigned int)pdu_length));
+
+ SIVAL(seq_num, 0, ntlmssp_state->ntlm2_recv_seq_num);
+ ntlmssp_state->ntlm2_recv_seq_num++;
+ hmac_md5_init_limK_to_64(ntlmssp_state->recv_sign_key, 16, &ctx);
+ break;
+ }
+
+ dump_data_pw("pdu data ", whole_pdu, pdu_length);
+
+ hmac_md5_update(seq_num, 4, &ctx);
+ hmac_md5_update(whole_pdu, pdu_length, &ctx);
+ hmac_md5_final(digest, &ctx);
+
+ if (encrypt_sig && (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
switch (direction) {
case NTLMSSP_SEND:
- NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4);
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, digest, 8);
break;
case NTLMSSP_RECEIVE:
- NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash, sig->data+4, sig->length-4);
+ smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, digest, 8);
break;
}
}
+
+ SIVAL(sig->data, 0, NTLMSSP_SIGN_VERSION);
+ memcpy(sig->data + 4, digest, 8);
+ memcpy(sig->data + 12, seq_num, 4);
+
+ dump_data_pw("ntlmssp v2 sig ", sig->data, sig->length);
+
} else {
uint32 crc;
crc = crc32_calc_buffer((const char *)data, length);
- if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
- dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ ntlmssp_state->ntlmv1_seq_num++;
+
+ dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
}
return NT_STATUS_OK;
}
NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
NTSTATUS nt_status;
+
+ if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN) {
+ DEBUG(3, ("NTLMSSP Signing not negotiated - cannot sign packet!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot check sign packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
}
- nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, True);
- /* increment counter on send */
- ntlmssp_state->ntlmssp_seq_num++;
return nt_status;
}
@@ -171,8 +164,9 @@ NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
- const uchar *data, size_t length,
- const DATA_BLOB *sig)
+ const uchar *data, size_t length,
+ const uchar *whole_pdu, size_t pdu_length,
+ const DATA_BLOB *sig)
{
DATA_BLOB local_sig;
NTSTATUS nt_status;
@@ -187,32 +181,51 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
(unsigned long)sig->length));
}
- nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data,
- length, NTLMSSP_RECEIVE, &local_sig);
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_RECEIVE, &local_sig, True);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+ data_blob_free(&local_sig);
return nt_status;
}
- if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
- DEBUG(5, ("BAD SIG: wanted signature of\n"));
- dump_data(5, (const char *)local_sig.data, local_sig.length);
-
- DEBUG(5, ("BAD SIG: got signature of\n"));
- dump_data(5, (const char *)(sig->data), sig->length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+ if (local_sig.length != sig->length ||
+ memcmp(local_sig.data, sig->data, sig->length) != 0) {
+ DEBUG(5, ("BAD SIG NTLM2: wanted signature of\n"));
+ dump_data(5, local_sig.data, local_sig.length);
- DEBUG(0, ("NTLMSSP packet check failed due to invalid signature!\n"));
- return NT_STATUS_ACCESS_DENIED;
- }
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
+
+ DEBUG(0, ("NTLMSSP NTLM2 packet check failed due to invalid signature!\n"));
+ data_blob_free(&local_sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ } else {
+ if (local_sig.length != sig->length ||
+ memcmp(local_sig.data + 8, sig->data + 8, sig->length - 8) != 0) {
+ DEBUG(5, ("BAD SIG NTLM1: wanted signature of\n"));
+ dump_data(5, local_sig.data, local_sig.length);
+
+ DEBUG(5, ("BAD SIG: got signature of\n"));
+ dump_data(5, sig->data, sig->length);
- /* increment counter on recieive */
- ntlmssp_state->ntlmssp_seq_num++;
+ DEBUG(0, ("NTLMSSP NTLM1 packet check failed due to invalid signature!\n"));
+ data_blob_free(&local_sig);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ }
+ dump_data_pw("checked ntlmssp signature\n", sig->data, sig->length);
+ DEBUG(10,("ntlmssp_check_packet: NTLMSSP signature OK !\n"));
+ data_blob_free(&local_sig);
return NT_STATUS_OK;
}
-
/**
* Seal data with the NTLMSSP algorithm
*
@@ -220,8 +233,16 @@ NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
DATA_BLOB *sig)
{
+ NTSTATUS nt_status;
+
+ if (!ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL) {
+ DEBUG(3, ("NTLMSSP Sealing not negotiated - cannot seal packet!\n"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot seal packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
@@ -230,53 +251,44 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
DEBUG(10,("ntlmssp_seal_data: seal\n"));
dump_data_pw("ntlmssp clear data\n", data, length);
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- HMACMD5Context ctx;
- char seq_num[4];
- uchar digest[16];
- SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
- hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
- hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
- hmac_md5_update(data, length, &ctx);
- hmac_md5_final(digest, &ctx);
-
- if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
- , ntlmssp_state->ntlmssp_seq_num)) {
- return NT_STATUS_NO_MEMORY;
+ /* The order of these two operations matters - we must first seal the packet,
+ then seal the sequence number - this is becouse the send_seal_hash is not
+ constant, but is is rather updated with each iteration */
+ nt_status = ntlmssp_make_packet_signature(ntlmssp_state,
+ data, length,
+ whole_pdu, pdu_length,
+ NTLMSSP_SEND, sig, False);
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, data, length);
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+ smb_arc4_crypt(ntlmssp_state->send_seal_arc4_state, sig->data+4, 8);
}
-
- dump_data_pw("ntlmssp client sealing hash:\n",
- ntlmssp_state->send_seal_hash,
- sizeof(ntlmssp_state->send_seal_hash));
- NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length);
- dump_data_pw("ntlmssp client signing hash:\n",
- ntlmssp_state->send_sign_hash,
- sizeof(ntlmssp_state->send_sign_hash));
- NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash, sig->data+4, sig->length-4);
} else {
uint32 crc;
crc = crc32_calc_buffer((const char *)data, length);
- if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+ if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmv1_seq_num)) {
return NT_STATUS_NO_MEMORY;
}
/* The order of these two operations matters - we must first seal the packet,
- then seal the sequence number - this is becouse the ntlmssp_hash is not
+ then seal the sequence number - this is becouse the ntlmv1_arc4_state is not
constant, but is is rather updated with each iteration */
- dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+
+ dump_data_pw("ntlmv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, sig->data+4, sig->length-4);
- dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
+ ntlmssp_state->ntlmv1_seq_num++;
+
+ nt_status = NT_STATUS_OK;
}
+ dump_data_pw("ntlmssp signature\n", sig->data, sig->length);
dump_data_pw("ntlmssp sealed data\n", data, length);
- /* increment counter on send */
- ntlmssp_state->ntlmssp_seq_num++;
-
return NT_STATUS_OK;
}
@@ -286,26 +298,27 @@ NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
*/
NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
- uchar *data, size_t length,
- DATA_BLOB *sig)
+ uchar *data, size_t length,
+ uchar *whole_pdu, size_t pdu_length,
+ DATA_BLOB *sig)
{
if (!ntlmssp_state->session_key.length) {
DEBUG(3, ("NO session key, cannot unseal packet\n"));
return NT_STATUS_NO_USER_SESSION_KEY;
}
- DEBUG(10,("ntlmssp__unseal_data: seal\n"));
+ DEBUG(10,("ntlmssp_unseal_data: seal\n"));
dump_data_pw("ntlmssp sealed data\n", data, length);
+
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
- NTLMSSPcalc_ap(ntlmssp_state->recv_seal_hash, data, length);
+ /* First unseal the data. */
+ smb_arc4_crypt(ntlmssp_state->recv_seal_arc4_state, data, length);
+ dump_data_pw("ntlmv2 clear data\n", data, length);
} else {
- dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
- NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+ smb_arc4_crypt(ntlmssp_state->ntlmv1_arc4_state, data, length);
+ dump_data_pw("ntlmv1 clear data\n", data, length);
}
- dump_data_pw("ntlmssp clear data\n", data, length);
-
- return ntlmssp_check_packet(ntlmssp_state, data, length, sig);
+ return ntlmssp_check_packet(ntlmssp_state, data, length, whole_pdu, pdu_length, sig);
}
/**
@@ -326,6 +339,7 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
{
+ DATA_BLOB weak_session_key = ntlmssp_state->session_key;
const char *send_sign_const;
const char *send_seal_const;
const char *recv_sign_const;
@@ -352,62 +366,96 @@ NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
break;
}
- calc_ntlmv2_hash(ntlmssp_state->send_sign_hash,
- ntlmssp_state->send_sign_const,
- ntlmssp_state->session_key, send_sign_const);
- dump_data_pw("NTLMSSP send sign hash:\n",
- ntlmssp_state->send_sign_hash,
- sizeof(ntlmssp_state->send_sign_hash));
-
- calc_ntlmv2_hash(ntlmssp_state->send_seal_hash,
- ntlmssp_state->send_seal_const,
- ntlmssp_state->session_key, send_seal_const);
- dump_data_pw("NTLMSSP send sesl hash:\n",
- ntlmssp_state->send_seal_hash,
- sizeof(ntlmssp_state->send_seal_hash));
-
- calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash,
- ntlmssp_state->recv_sign_const,
- ntlmssp_state->session_key, recv_sign_const);
- dump_data_pw("NTLMSSP receive sign hash:\n",
- ntlmssp_state->recv_sign_hash,
- sizeof(ntlmssp_state->recv_sign_hash));
-
- calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash,
- ntlmssp_state->recv_seal_const,
- ntlmssp_state->session_key, recv_seal_const);
- dump_data_pw("NTLMSSP receive seal hash:\n",
- ntlmssp_state->recv_sign_hash,
- sizeof(ntlmssp_state->recv_sign_hash));
-
- }
- else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
- if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
- /* can't sign or check signatures yet */
- DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));
- return NT_STATUS_UNSUCCESSFUL;
+ /**
+ Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+ We probably should have some parameters to control this, once we get NTLM2 working.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+ ;
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ weak_session_key.length = 6;
+ } else { /* forty bits */
+ weak_session_key.length = 5;
}
+
+ dump_data_pw("NTLMSSP weakend master key:\n",
+ weak_session_key.data,
+ weak_session_key.length);
+
+ /* SEND */
+ calc_ntlmv2_key(ntlmssp_state->send_sign_key,
+ ntlmssp_state->session_key, send_sign_const);
+ dump_data_pw("NTLMSSP send sign key:\n",
+ ntlmssp_state->send_sign_key, 16);
+
+ calc_ntlmv2_key(ntlmssp_state->send_seal_key,
+ weak_session_key, send_seal_const);
+ dump_data_pw("NTLMSSP send seal key:\n",
+ ntlmssp_state->send_seal_key, 16);
+
+ smb_arc4_init(ntlmssp_state->send_seal_arc4_state,
+ ntlmssp_state->send_seal_key, 16);
+
+ dump_data_pw("NTLMSSP send seal arc4 state:\n",
+ ntlmssp_state->send_seal_arc4_state,
+ sizeof(ntlmssp_state->send_seal_arc4_state));
+
+ /* RECV */
+ calc_ntlmv2_key(ntlmssp_state->recv_sign_key,
+ ntlmssp_state->session_key, recv_sign_const);
+ dump_data_pw("NTLMSSP recv send sign key:\n",
+ ntlmssp_state->recv_sign_key, 16);
+
+ calc_ntlmv2_key(ntlmssp_state->recv_seal_key,
+ weak_session_key, recv_seal_const);
- DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+ dump_data_pw("NTLMSSP recv seal key:\n",
+ ntlmssp_state->recv_seal_key, 16);
+
+ smb_arc4_init(ntlmssp_state->recv_seal_arc4_state,
+ ntlmssp_state->recv_seal_key, 16);
+
+ dump_data_pw("NTLMSSP recv seal arc4 state:\n",
+ ntlmssp_state->recv_seal_arc4_state,
+ sizeof(ntlmssp_state->recv_seal_arc4_state));
+
+ ntlmssp_state->ntlm2_send_seq_num = 0;
+ ntlmssp_state->ntlm2_recv_seq_num = 0;
+
- calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 8);
- dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
} else {
- if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
- /* can't sign or check signatures yet */
- DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
- return NT_STATUS_UNSUCCESSFUL;
+#if 0
+ /* Hmmm. Shouldn't we also weaken keys for ntlmv1 ? JRA. */
+
+ DATA_BLOB weak_session_key = ntlmssp_state->session_key;
+ /**
+ Weaken NTLMSSP keys to cope with down-level clients, servers and export restrictions.
+ We probably should have some parameters to control this, once we get NTLM2 working.
+ */
+
+ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_128) {
+ ;
+ } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_56) {
+ weak_session_key.length = 6;
+ } else { /* forty bits */
+ weak_session_key.length = 5;
}
-
- DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+ dump_data_pw("NTLMSSP weakend master key:\n",
+ weak_session_key.data,
+ weak_session_key.length);
+#endif
- calc_hash(ntlmssp_state->ntlmssp_hash, ntlmssp_state->session_key.data, 16);
- dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
- }
+ DEBUG(5, ("NTLMSSP Sign/Seal - using NTLM1\n"));
+
+ smb_arc4_init(ntlmssp_state->ntlmv1_arc4_state,
+ ntlmssp_state->session_key.data, ntlmssp_state->session_key.length);
- ntlmssp_state->ntlmssp_seq_num = 0;
+ dump_data_pw("NTLMv1 arc4 state:\n", ntlmssp_state->ntlmv1_arc4_state,
+ sizeof(ntlmssp_state->ntlmv1_arc4_state));
+
+ ntlmssp_state->ntlmv1_seq_num = 0;
+ }
return NT_STATUS_OK;
}
diff --git a/source/libsmb/passchange.c b/source/libsmb/passchange.c
index 8bce9c86a1e..b104a4678d9 100644
--- a/source/libsmb/passchange.c
+++ b/source/libsmb/passchange.c
@@ -21,16 +21,17 @@
#include "includes.h"
/*************************************************************
-change a password on a remote machine using IPC calls
+ Change a password on a remote machine using IPC calls.
*************************************************************/
+
BOOL remote_password_change(const char *remote_machine, const char *user_name,
const char *old_passwd, const char *new_passwd,
char *err_str, size_t err_str_len)
{
struct nmb_name calling, called;
struct cli_state cli;
+ struct rpc_pipe_client *pipe_hnd;
struct in_addr ip;
- struct ntuser_creds creds;
NTSTATUS result;
@@ -85,11 +86,9 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
return False;
}
- init_creds(&creds, "", "", NULL);
- cli_init_creds(&cli, &creds);
+ cli_init_creds(&cli, "", "", NULL);
} else {
- init_creds(&creds, user_name, "", old_passwd);
- cli_init_creds(&cli, &creds);
+ cli_init_creds(&cli, user_name, "", old_passwd);
}
if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
@@ -99,14 +98,19 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
return False;
}
- /* Try not to give the password away to easily */
+ /* Try not to give the password away too easily */
- cli.pipe_auth_flags = AUTH_PIPE_NTLMSSP;
- cli.pipe_auth_flags |= AUTH_PIPE_SIGN;
- cli.pipe_auth_flags |= AUTH_PIPE_SEAL;
-
- if ( !cli_nt_session_open( &cli, PI_SAMR ) ) {
+ pipe_hnd = cli_rpc_pipe_open_ntlmssp(&cli,
+ PI_SAMR,
+ PIPE_AUTH_LEVEL_PRIVACY,
+ "", /* what domain... ? */
+ user_name,
+ old_passwd,
+ &result);
+
+ if (!pipe_hnd) {
if (lp_client_lanman_auth()) {
+ /* Use the old RAP method. */
if (!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
remote_machine, cli_errstr(&cli) );
@@ -114,14 +118,16 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
return False;
}
} else {
- slprintf(err_str, err_str_len-1, "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n",
- remote_machine);
+ slprintf(err_str, err_str_len-1,
+ "SAMR connection to machine %s failed. Error was %s, "
+ "but LANMAN password changed are disabled\n",
+ nt_errstr(result), remote_machine);
cli_shutdown(&cli);
return False;
}
}
- if (NT_STATUS_IS_OK(result = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name,
+ if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, cli.mem_ctx, user_name,
new_passwd, old_passwd))) {
/* Great - it all worked! */
cli_shutdown(&cli);
@@ -138,25 +144,25 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
}
/* OK, that failed, so try again... */
- cli_nt_session_close(&cli);
+ cli_rpc_pipe_close(pipe_hnd);
/* Try anonymous NTLMSSP... */
- init_creds(&creds, "", "", NULL);
- cli_init_creds(&cli, &creds);
+ cli_init_creds(&cli, "", "", NULL);
- cli.pipe_auth_flags = 0;
-
result = NT_STATUS_UNSUCCESSFUL;
- /* OK, this is ugly, but... */
- if ( cli_nt_session_open( &cli, PI_SAMR )
- && NT_STATUS_IS_OK(result
- = cli_samr_chgpasswd_user(&cli, cli.mem_ctx, user_name,
- new_passwd, old_passwd))) {
+ /* OK, this is ugly, but... try an anonymous pipe. */
+ pipe_hnd = cli_rpc_pipe_open_noauth(&cli, PI_SAMR, &result);
+
+ if ( pipe_hnd &&
+ (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd,
+ cli.mem_ctx,
+ user_name,
+ new_passwd,
+ old_passwd)))) {
/* Great - it all worked! */
cli_shutdown(&cli);
return True;
-
} else {
if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)
|| NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
@@ -173,6 +179,7 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
just might not support SAMR password changes, so fall back */
if (lp_client_lanman_auth()) {
+ /* Use the old RAP method. */
if (cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
/* SAMR failed, but the old LanMan protocol worked! */
@@ -185,9 +192,10 @@ BOOL remote_password_change(const char *remote_machine, const char *user_name,
cli_shutdown(&cli);
return False;
} else {
- slprintf(err_str, err_str_len-1,
- "machine %s does not support SAMR connections, but LANMAN password changed are disabled\n",
- remote_machine);
+ slprintf(err_str, err_str_len-1,
+ "SAMR connection to machine %s failed. Error was %s, "
+ "but LANMAN password changed are disabled\n",
+ nt_errstr(result), remote_machine);
cli_shutdown(&cli);
return False;
}
diff --git a/source/libsmb/pwd_cache.c b/source/libsmb/pwd_cache.c
index e010f226a02..a0f3383e297 100644
--- a/source/libsmb/pwd_cache.c
+++ b/source/libsmb/pwd_cache.c
@@ -60,4 +60,3 @@ void pwd_get_cleartext(struct pwd_info *pwd, fstring clr)
clr[0] = 0;
}
-
diff --git a/source/libsmb/smb_share_modes.c b/source/libsmb/smb_share_modes.c
index 87a386307c1..7659d1cd6e8 100644
--- a/source/libsmb/smb_share_modes.c
+++ b/source/libsmb/smb_share_modes.c
@@ -55,6 +55,12 @@ struct smbdb_ctx *smb_share_mode_db_open(const char *db_path)
return smb_db;
}
+/* key and data records in the tdb locking database */
+struct locking_key {
+ SMB_DEV_T dev;
+ SMB_INO_T inode;
+};
+
int smb_share_mode_db_close(struct smbdb_ctx *db_ctx)
{
int ret = tdb_close(db_ctx->smb_tdb);
@@ -102,10 +108,10 @@ struct locking_data {
int num_share_mode_entries;
BOOL delete_on_close;
} s;
- share_mode_entry dummy; /* Needed for alignment. */
+ struct share_mode_entry dummy; /* Needed for alignment. */
} u;
/* the following two entries are implicit
- share_mode_entry modes[num_share_mode_entries];
+ struct share_mode_entry modes[num_share_mode_entries];
char file_name[];
*/
};
@@ -114,9 +120,9 @@ struct locking_data {
* Check if an external smb_share_mode_entry and an internal share_mode entry match.
*/
-static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const share_mode_entry *entry)
+static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const struct share_mode_entry *entry)
{
- return (e_entry->pid == entry->pid &&
+ return (procid_equal(&e_entry->pid, &entry->pid) &&
e_entry->file_id == (uint32_t)entry->share_file_id &&
e_entry->open_time.tv_sec == entry->time.tv_sec &&
e_entry->open_time.tv_usec == entry->time.tv_usec &&
@@ -130,9 +136,9 @@ static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, co
* Create an internal Samba share_mode entry from an external smb_share_mode_entry.
*/
-static void create_share_mode_entry(share_mode_entry *out, const struct smb_share_mode_entry *in)
+static void create_share_mode_entry(struct share_mode_entry *out, const struct smb_share_mode_entry *in)
{
- memset(out, '\0', sizeof(share_mode_entry));
+ memset(out, '\0', sizeof(struct share_mode_entry));
out->pid = in->pid;
out->share_file_id = (unsigned long)in->file_id;
@@ -159,7 +165,7 @@ int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
struct smb_share_mode_entry *list = NULL;
int num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
- share_mode_entry *shares = NULL;
+ struct share_mode_entry *shares = NULL;
size_t i;
int list_num;
@@ -187,19 +193,24 @@ int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry));
- shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry));
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
list_num = 0;
for (i = 0; i < num_share_modes; i++) {
- share_mode_entry *share = &shares[i];
+ struct share_mode_entry *share = &shares[i];
struct smb_share_mode_entry *sme = &list[list_num];
- pid_t pid = share->pid;
+ struct process_id pid = share->pid;
/* Check this process really exists. */
- if (kill(pid, 0) == -1 && (errno == ESRCH)) {
+ if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
continue; /* No longer exists. */
}
+ /* Ignore deferred open entries. */
+ if (share->op_type == DEFERRED_OPEN_ENTRY) {
+ continue;
+ }
+
/* Copy into the external list. */
sme->dev = (uint64_t)share->dev;
sme->ino = (uint64_t)share->inode;
@@ -238,27 +249,27 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
TDB_DATA locking_key = get_locking_key(dev, ino);
int orig_num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
- share_mode_entry *shares = NULL;
+ struct share_mode_entry *shares = NULL;
char *new_data_p = NULL;
size_t new_data_size = 0;
db_data = tdb_fetch(db_ctx->smb_tdb, locking_key);
if (!db_data.dptr) {
/* We must create the entry. */
- db_data.dptr = malloc((2*sizeof(share_mode_entry)) + strlen(filename) + 1);
+ db_data.dptr = malloc((2*sizeof(struct share_mode_entry)) + strlen(filename) + 1);
if (!db_data.dptr) {
return -1;
}
ld = (struct locking_data *)db_data.dptr;
ld->u.s.num_share_mode_entries = 1;
ld->u.s.delete_on_close = 0;
- shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry));
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
create_share_mode_entry(shares, new_entry);
- memcpy(db_data.dptr + 2*sizeof(share_mode_entry),
+ memcpy(db_data.dptr + 2*sizeof(struct share_mode_entry),
filename,
strlen(filename) + 1);
- db_data.dsize = 2*sizeof(share_mode_entry) + strlen(filename) + 1;
+ db_data.dsize = 2*sizeof(struct share_mode_entry) + strlen(filename) + 1;
if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) == -1) {
free(db_data.dptr);
return -1;
@@ -268,7 +279,7 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
}
/* Entry exists, we must add a new entry. */
- new_data_p = malloc(db_data.dsize + sizeof(share_mode_entry));
+ new_data_p = malloc(db_data.dsize + sizeof(struct share_mode_entry));
if (!new_data_p) {
free(db_data.dptr);
return -1;
@@ -278,11 +289,11 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
orig_num_share_modes = ld->u.s.num_share_mode_entries;
/* Copy the original data. */
- memcpy(new_data_p, db_data.dptr, (orig_num_share_modes+1)*sizeof(share_mode_entry));
+ memcpy(new_data_p, db_data.dptr, (orig_num_share_modes+1)*sizeof(struct share_mode_entry));
/* Add in the new share mode */
- shares = (share_mode_entry *)(new_data_p +
- ((orig_num_share_modes+1)*sizeof(share_mode_entry)));
+ shares = (struct share_mode_entry *)(new_data_p +
+ ((orig_num_share_modes+1)*sizeof(struct share_mode_entry)));
create_share_mode_entry(shares, new_entry);
@@ -290,11 +301,11 @@ int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
ld->u.s.num_share_mode_entries++;
/* Append the original filename */
- memcpy(new_data_p + ((ld->u.s.num_share_mode_entries+1)*sizeof(share_mode_entry)),
- db_data.dptr + ((orig_num_share_modes+1)*sizeof(share_mode_entry)),
- db_data.dsize - ((orig_num_share_modes+1) * sizeof(share_mode_entry)));
+ memcpy(new_data_p + ((ld->u.s.num_share_mode_entries+1)*sizeof(struct share_mode_entry)),
+ db_data.dptr + ((orig_num_share_modes+1)*sizeof(struct share_mode_entry)),
+ db_data.dsize - ((orig_num_share_modes+1) * sizeof(struct share_mode_entry)));
- new_data_size = db_data.dsize + sizeof(share_mode_entry);
+ new_data_size = db_data.dsize + sizeof(struct share_mode_entry);
free(db_data.dptr);
@@ -318,7 +329,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
TDB_DATA locking_key = get_locking_key(dev, ino);
int orig_num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
- share_mode_entry *shares = NULL;
+ struct share_mode_entry *shares = NULL;
char *new_data_p = NULL;
size_t filename_size = 0;
size_t i, num_share_modes;
@@ -331,7 +342,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
ld = (struct locking_data *)db_data.dptr;
orig_num_share_modes = ld->u.s.num_share_mode_entries;
- shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry));
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
if (orig_num_share_modes == 1) {
/* Only one entry - better be ours... */
@@ -346,22 +357,22 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
}
/* More than one - allocate a new record minus the one we'll delete. */
- new_data_p = malloc(db_data.dsize - sizeof(share_mode_entry));
+ new_data_p = malloc(db_data.dsize - sizeof(struct share_mode_entry));
if (!new_data_p) {
free(db_data.dptr);
return -1;
}
/* Copy the header. */
- memcpy(new_data_p, db_data.dptr, sizeof(share_mode_entry));
+ memcpy(new_data_p, db_data.dptr, sizeof(struct share_mode_entry));
num_share_modes = 0;
for (i = 0; i < orig_num_share_modes; i++) {
- share_mode_entry *share = &shares[i];
- pid_t pid = share->pid;
+ struct share_mode_entry *share = &shares[i];
+ struct process_id pid = share->pid;
/* Check this process really exists. */
- if (kill(pid, 0) == -1 && (errno == ESRCH)) {
+ if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
continue; /* No longer exists. */
}
@@ -369,8 +380,8 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
continue; /* This is our delete taget. */
}
- memcpy(new_data_p + ((num_share_modes+1)*sizeof(share_mode_entry)),
- share, sizeof(share_mode_entry) );
+ memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)),
+ share, sizeof(struct share_mode_entry) );
num_share_modes++;
}
@@ -383,10 +394,10 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
}
/* Copy the terminating filename. */
- fname_ptr = db_data.dptr + ((orig_num_share_modes+1) * sizeof(share_mode_entry));
+ fname_ptr = db_data.dptr + ((orig_num_share_modes+1) * sizeof(struct share_mode_entry));
filename_size = db_data.dsize - (fname_ptr - db_data.dptr);
- memcpy(new_data_p + ((num_share_modes+1)*sizeof(share_mode_entry)),
+ memcpy(new_data_p + ((num_share_modes+1)*sizeof(struct share_mode_entry)),
fname_ptr,
filename_size);
@@ -398,7 +409,7 @@ int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
ld = (struct locking_data *)db_data.dptr;
ld->u.s.num_share_mode_entries = num_share_modes;
- db_data.dsize = ((num_share_modes+1)*sizeof(share_mode_entry)) + filename_size;
+ db_data.dsize = ((num_share_modes+1)*sizeof(struct share_mode_entry)) + filename_size;
if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) {
free(db_data.dptr);
@@ -418,7 +429,7 @@ int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
TDB_DATA locking_key = get_locking_key(dev, ino);
int num_share_modes = 0;
struct locking_data *ld = NULL; /* internal samba db state. */
- share_mode_entry *shares = NULL;
+ struct share_mode_entry *shares = NULL;
size_t i;
int found_entry = 0;
@@ -429,14 +440,14 @@ int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
ld = (struct locking_data *)db_data.dptr;
num_share_modes = ld->u.s.num_share_mode_entries;
- shares = (share_mode_entry *)(db_data.dptr + sizeof(share_mode_entry));
+ shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct share_mode_entry));
for (i = 0; i < num_share_modes; i++) {
- share_mode_entry *share = &shares[i];
- pid_t pid = share->pid;
+ struct share_mode_entry *share = &shares[i];
+ struct process_id pid = share->pid;
/* Check this process really exists. */
- if (kill(pid, 0) == -1 && (errno == ESRCH)) {
+ if (kill(procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
continue; /* No longer exists. */
}
diff --git a/source/libsmb/smbdes.c b/source/libsmb/smbdes.c
index b7f0cd05c33..dc49396d9e1 100644
--- a/source/libsmb/smbdes.c
+++ b/source/libsmb/smbdes.c
@@ -357,78 +357,24 @@ void cred_hash3(unsigned char *out, unsigned char *in, const unsigned char *key,
des_crypt56(out + 8, in + 8, key2, forw);
}
-void SamOEMhash( unsigned char *data, const unsigned char *key, int val)
-{
- unsigned char s_box[256];
- unsigned char index_i = 0;
- unsigned char index_j = 0;
- unsigned char j = 0;
- int ind;
-
- for (ind = 0; ind < 256; ind++) {
- s_box[ind] = (unsigned char)ind;
- }
-
- for( ind = 0; ind < 256; ind++) {
- unsigned char tc;
+/*****************************************************************
+ arc4 crypt/decrypt with a 16 byte key.
+*****************************************************************/
- j += (s_box[ind] + key[ind%16]);
-
- tc = s_box[ind];
- s_box[ind] = s_box[j];
- s_box[j] = tc;
- }
- for( ind = 0; ind < val; ind++) {
- unsigned char tc;
- unsigned char t;
-
- index_i++;
- index_j += s_box[index_i];
-
- tc = s_box[index_i];
- s_box[index_i] = s_box[index_j];
- s_box[index_j] = tc;
+void SamOEMhash( unsigned char *data, const unsigned char key[16], size_t len)
+{
+ unsigned char arc4_state[258];
- t = s_box[index_i] + s_box[index_j];
- data[ind] = data[ind] ^ s_box[t];
- }
+ smb_arc4_init(arc4_state, key, 16);
+ smb_arc4_crypt(arc4_state, data, len);
}
-void SamOEMhashBlob( unsigned char *data, int len, DATA_BLOB *key)
+void SamOEMhashBlob( unsigned char *data, size_t len, DATA_BLOB *key)
{
- unsigned char s_box[256];
- unsigned char index_i = 0;
- unsigned char index_j = 0;
- unsigned char j = 0;
- int ind;
-
- for (ind = 0; ind < 256; ind++) {
- s_box[ind] = (unsigned char)ind;
- }
-
- for( ind = 0; ind < 256; ind++) {
- unsigned char tc;
-
- j += (s_box[ind] + key->data[ind%key->length]);
-
- tc = s_box[ind];
- s_box[ind] = s_box[j];
- s_box[j] = tc;
- }
- for( ind = 0; ind < len; ind++) {
- unsigned char tc;
- unsigned char t;
-
- index_i++;
- index_j += s_box[index_i];
+ unsigned char arc4_state[258];
- tc = s_box[index_i];
- s_box[index_i] = s_box[index_j];
- s_box[index_j] = tc;
-
- t = s_box[index_i] + s_box[index_j];
- data[ind] = data[ind] ^ s_box[t];
- }
+ smb_arc4_init(arc4_state, key->data, key->length);
+ smb_arc4_crypt(arc4_state, data, len);
}
/* Decode a sam password hash into a password. The password hash is the
diff --git a/source/libsmb/smbencrypt.c b/source/libsmb/smbencrypt.c
index 8361c35a8e2..0c9eacfe4c0 100644
--- a/source/libsmb/smbencrypt.c
+++ b/source/libsmb/smbencrypt.c
@@ -308,32 +308,6 @@ void SMBsesskeygen_ntv1(const uchar kr[16],
#endif
}
-void SMBsesskeygen_lmv1(const uchar lm_hash[16],
- const uchar lm_resp[24], /* only uses 8 */
- uint8 sess_key[16])
-{
- /* Calculate the LM session key (effective length 40 bits,
- but changes with each session) */
-
- uchar p24[24];
- uchar partial_lm_hash[16];
-
- memcpy(partial_lm_hash, lm_hash, 8);
- memset(partial_lm_hash + 8, 0xbd, 8);
-
- SMBOWFencrypt(lm_hash, lm_resp, p24);
-
- memcpy(sess_key, p24, 16);
- sess_key[5] = 0xe5;
- sess_key[6] = 0x38;
- sess_key[7] = 0xb0;
-
-#ifdef DEBUG_PASSWORD
- DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
- dump_data(100, sess_key, 16);
-#endif
-}
-
void SMBsesskeygen_lm_sess_key(const uchar lm_hash[16],
const uchar lm_resp[24], /* only uses 8 */
uint8 sess_key[16])
@@ -485,7 +459,7 @@ BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password
encode a password buffer with a unicode password. The buffer
is filled with random data to make it harder to attack.
************************************************************/
-BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags)
+BOOL encode_pw_buffer(uint8 buffer[516], const char *password, int string_flags)
{
uchar new_pw[512];
size_t new_pw_len;
@@ -496,7 +470,7 @@ BOOL encode_pw_buffer(char buffer[516], const char *password, int string_flags)
memcpy(&buffer[512 - new_pw_len], new_pw, new_pw_len);
- generate_random_buffer((unsigned char *)buffer, 512 - new_pw_len);
+ generate_random_buffer(buffer, 512 - new_pw_len);
/*
* The length of the new password is in the last 4 bytes of
diff --git a/source/libsmb/smberr.c b/source/libsmb/smberr.c
index a21063e52ac..82a06bde2bc 100644
--- a/source/libsmb/smberr.c
+++ b/source/libsmb/smberr.c
@@ -75,6 +75,7 @@ err_code_struct dos_msgs[] = {
{"ERRlogonfailure",ERRlogonfailure,"Logon failure"},
{"ERRdiskfull",ERRdiskfull,"Disk full"},
{"ERRgeneral",ERRgeneral, "General failure"},
+ {"ERRbaddirectory", ERRbaddirectory, "Bad directory name"},
{"ERRunknownlevel",ERRunknownlevel, "Unknown info level"},
{NULL,-1,NULL}};
diff --git a/source/libsmb/spnego.c b/source/libsmb/spnego.c
index 2eaec61ed79..2cf3480fce3 100644
--- a/source/libsmb/spnego.c
+++ b/source/libsmb/spnego.c
@@ -42,11 +42,11 @@ static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
asn1_start_tag(asn1, ASN1_CONTEXT(0));
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
- token->mechTypes = SMB_MALLOC_P(char *);
+ token->mechTypes = SMB_MALLOC_P(const char *);
for (i = 0; !asn1->has_error &&
0 < asn1_tag_remaining(asn1); i++) {
token->mechTypes =
- SMB_REALLOC_ARRAY(token->mechTypes, char *, i + 2);
+ SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2);
asn1_read_OID(asn1, &token->mechTypes[i]);
}
token->mechTypes[i] = NULL;
diff --git a/source/libsmb/trusts_util.c b/source/libsmb/trusts_util.c
index aab0d7d1517..50fa613e72c 100644
--- a/source/libsmb/trusts_util.c
+++ b/source/libsmb/trusts_util.c
@@ -29,22 +29,36 @@
Caller must have the cli connected to the netlogon pipe
already.
**********************************************************/
-static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+
+static NTSTATUS just_change_the_password(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
unsigned char orig_trust_passwd_hash[16],
unsigned char new_trust_passwd_hash[16],
uint32 sec_channel_type)
{
NTSTATUS result;
- /* ensure that schannel uses the right domain */
- fstrcpy(cli->domain, lp_workgroup());
- if (! NT_STATUS_IS_OK(result = cli_nt_establish_netlogon(cli, sec_channel_type, orig_trust_passwd_hash))) {
- DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
- nt_errstr(result)));
- return result;
+ /* Check if the netlogon pipe is open using schannel. If so we
+ already have valid creds. If not we must set them up. */
+
+ if (cli->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
+ uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS;
+
+ result = rpccli_netlogon_setup_creds(cli,
+ cli->cli->desthost,
+ lp_workgroup(),
+ global_myname(),
+ orig_trust_passwd_hash,
+ sec_channel_type,
+ &neg_flags);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3,("just_change_the_password: unable to setup creds (%s)!\n",
+ nt_errstr(result)));
+ return result;
+ }
}
-
- result = cli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash);
+
+ result = rpccli_net_srv_pwset(cli, mem_ctx, global_myname(), new_trust_passwd_hash);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(0,("just_change_the_password: unable to change password (%s)!\n",
@@ -59,7 +73,7 @@ static NTSTATUS just_change_the_password(struct cli_state *cli, TALLOC_CTX *mem_
Caller must have already setup the connection to the NETLOGON pipe
**********************************************************/
-NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+NTSTATUS trust_pw_change_and_store_it(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
const char *domain,
unsigned char orig_trust_passwd_hash[16],
uint32 sec_channel_type)
@@ -99,7 +113,7 @@ NTSTATUS trust_pw_change_and_store_it(struct cli_state *cli, TALLOC_CTX *mem_ctx
already setup the connection to the NETLOGON pipe
**********************************************************/
-NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli,
+NTSTATUS trust_pw_find_change_and_store_it(struct rpc_pipe_client *cli,
TALLOC_CTX *mem_ctx,
const char *domain)
{
@@ -116,7 +130,6 @@ NTSTATUS trust_pw_find_change_and_store_it(struct cli_state *cli,
return trust_pw_change_and_store_it(cli, mem_ctx, domain,
old_trust_passwd_hash,
sec_channel_type);
-
}
/*********************************************************************
@@ -133,6 +146,7 @@ BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
struct in_addr dc_ip;
uint32 enum_ctx = 0;
struct cli_state *cli = NULL;
+ struct rpc_pipe_client *lsa_pipe;
BOOL retry;
*domain_names = NULL;
@@ -156,21 +170,21 @@ BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain,
/* open the LSARPC_PIPE */
- if ( !cli_nt_session_open( cli, PI_LSARPC ) ) {
- result = NT_STATUS_UNSUCCESSFUL;
+ lsa_pipe = cli_rpc_pipe_open_noauth( cli, PI_LSARPC, &result );
+ if ( !lsa_pipe) {
goto done;
}
/* get a handle */
- result = cli_lsa_open_policy(cli, mem_ctx, True,
+ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True,
POLICY_VIEW_LOCAL_INFORMATION, &pol);
if ( !NT_STATUS_IS_OK(result) )
goto done;
/* Lookup list of trusted domains */
- result = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
+ result = rpccli_lsa_enum_trust_dom(lsa_pipe, mem_ctx, &pol, &enum_ctx,
num_domains, domain_names, sids);
if ( !NT_STATUS_IS_OK(result) )
goto done;
@@ -184,4 +198,3 @@ done:
return NT_STATUS_IS_OK(result);
}
-