summaryrefslogtreecommitdiff
path: root/source3/libsmb
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb')
-rw-r--r--source3/libsmb/clidfs.c58
-rw-r--r--source3/libsmb/clifsinfo.c33
-rw-r--r--source3/libsmb/doserr.c1
-rw-r--r--source3/libsmb/libsmbclient.c98
-rw-r--r--source3/libsmb/smb_seal.c25
-rw-r--r--source3/libsmb/smb_signing.c8
-rw-r--r--source3/libsmb/smbencrypt.c20
7 files changed, 186 insertions, 57 deletions
diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c
index 7800d10e8b..77419b4a1a 100644
--- a/source3/libsmb/clidfs.c
+++ b/source3/libsmb/clidfs.c
@@ -72,54 +72,36 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
Ensure a connection is encrypted.
********************************************************************/
-static bool force_cli_encryption(struct cli_state *c,
+NTSTATUS cli_cm_force_encryption(struct cli_state *c,
const char *username,
const char *password,
const char *domain,
const char *sharename)
{
- uint16 major, minor;
- uint32 caplow, caphigh;
- NTSTATUS status;
+ NTSTATUS status = cli_force_encryption(c,
+ username,
+ password,
+ domain);
- if (!SERVER_HAS_UNIX_CIFS(c)) {
+ if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
d_printf("Encryption required and "
"server that doesn't support "
"UNIX extensions - failing connect\n");
- return false;
- }
-
- if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
+ } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) {
d_printf("Encryption required and "
"can't get UNIX CIFS extensions "
"version from server.\n");
- return false;
- }
-
- if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
+ } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
d_printf("Encryption required and "
"share %s doesn't support "
"encryption.\n", sharename);
- return false;
- }
-
- if (c->use_kerberos) {
- status = cli_gss_smb_encryption_start(c);
- } else {
- status = cli_raw_ntlm_smb_encryption_start(c,
- username,
- password,
- domain);
- }
-
- if (!NT_STATUS_IS_OK(status)) {
+ } else if (!NT_STATUS_IS_OK(status)) {
d_printf("Encryption required and "
"setup failed with error %s.\n",
nt_errstr(status));
- return false;
}
- return true;
+ return status;
}
/********************************************************************
@@ -281,13 +263,16 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx,
return NULL;
}
- if (force_encrypt && !force_cli_encryption(c,
+ if (force_encrypt) {
+ status = cli_cm_force_encryption(c,
username,
password,
lp_workgroup(),
- sharename)) {
- cli_shutdown(c);
- return NULL;
+ sharename);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(c);
+ return NULL;
+ }
}
DEBUG(4,(" tconx ok\n"));
@@ -1035,12 +1020,15 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
return false;
}
- if (force_encrypt && !force_cli_encryption(cli,
+ if (force_encrypt) {
+ NTSTATUS status = cli_cm_force_encryption(cli,
username,
password,
lp_workgroup(),
- "IPC$")) {
- return false;
+ "IPC$");
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
}
res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c
index 107613c618..fb923378ab 100644
--- a/source3/libsmb/clifsinfo.c
+++ b/source3/libsmb/clifsinfo.c
@@ -634,3 +634,36 @@ NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli)
return NT_STATUS_NOT_SUPPORTED;
}
#endif
+
+/********************************************************************
+ Ensure a connection is encrypted.
+********************************************************************/
+
+NTSTATUS cli_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain)
+{
+ uint16 major, minor;
+ uint32 caplow, caphigh;
+
+ if (!SERVER_HAS_UNIX_CIFS(c)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ if (!cli_unix_extensions_version(c, &major, &minor, &caplow, &caphigh)) {
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
+ return NT_STATUS_UNSUPPORTED_COMPRESSION;
+ }
+
+ if (c->use_kerberos) {
+ return cli_gss_smb_encryption_start(c);
+ }
+ return cli_raw_ntlm_smb_encryption_start(c,
+ username,
+ password,
+ domain);
+}
diff --git a/source3/libsmb/doserr.c b/source3/libsmb/doserr.c
index ba68b5a1e8..79445a2410 100644
--- a/source3/libsmb/doserr.c
+++ b/source3/libsmb/doserr.c
@@ -92,6 +92,7 @@ werror_code_struct dos_errs[] =
{ "WERR_REG_CORRUPT", WERR_REG_CORRUPT },
{ "WERR_REG_IO_FAILURE", WERR_REG_IO_FAILURE },
{ "WERR_REG_FILE_INVALID", WERR_REG_FILE_INVALID },
+ { "WERR_NO_SUCH_SERVICE", WERR_NO_SUCH_SERVICE },
{ "WERR_SERVICE_DISABLED", WERR_SERVICE_DISABLED },
{ "WERR_CAN_NOT_COMPLETE", WERR_CAN_NOT_COMPLETE},
{ "WERR_INVALID_FLAGS", WERR_INVALID_FLAGS},
diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c
index 2ff2830256..da8f1e332b 100644
--- a/source3/libsmb/libsmbclient.c
+++ b/source3/libsmb/libsmbclient.c
@@ -6,6 +6,7 @@
Copyright (C) John Terpstra 2000
Copyright (C) Tom Jansen (Ninja ISD) 2002
Copyright (C) Derrell Lipman 2003, 2004
+ Copyright (C) Jeremy Allison 2007, 2008
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
@@ -739,6 +740,12 @@ smbc_server(SMBCCTX *context,
password, strlen(password)+1);
}
+ /*
+ * We don't need to renegotiate encryption
+ * here as the encryption context is not per
+ * tid.
+ */
+
if (! cli_send_tconX(srv->cli, share, "?????",
password, strlen(password)+1)) {
@@ -903,6 +910,30 @@ smbc_server(SMBCCTX *context,
DEBUG(4,(" tconx ok\n"));
+ if (context->internal->_smb_encryption_level) {
+ /* Attempt UNIX smb encryption. */
+ if (!NT_STATUS_IS_OK(cli_force_encryption(c,
+ username_used,
+ password,
+ workgroup))) {
+
+ /*
+ * context->internal->_smb_encryption_level == 1
+ * means don't fail if encryption can't be negotiated,
+ * == 2 means fail if encryption can't be negotiated.
+ */
+
+ DEBUG(4,(" SMB encrypt failed\n"));
+
+ if (context->internal->_smb_encryption_level == 2) {
+ cli_shutdown(c);
+ errno = EPERM;
+ return NULL;
+ }
+ }
+ DEBUG(4,(" SMB encrypt ok\n"));
+ }
+
/*
* Ok, we have got a nice connection
* Let's allocate a server structure.
@@ -1019,6 +1050,30 @@ smbc_attr_server(SMBCCTX *context,
return NULL;
}
+ if (context->internal->_smb_encryption_level) {
+ /* Attempt UNIX smb encryption. */
+ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli,
+ username,
+ password,
+ workgroup))) {
+
+ /*
+ * context->internal->_smb_encryption_level == 1
+ * means don't fail if encryption can't be negotiated,
+ * == 2 means fail if encryption can't be negotiated.
+ */
+
+ DEBUG(4,(" SMB encrypt failed on IPC$\n"));
+
+ if (context->internal->_smb_encryption_level == 2) {
+ cli_shutdown(ipc_cli);
+ errno = EPERM;
+ return NULL;
+ }
+ }
+ DEBUG(4,(" SMB encrypt ok on IPC$\n"));
+ }
+
ipc_srv = SMB_MALLOC_P(SMBCSRV);
if (!ipc_srv) {
errno = ENOMEM;
@@ -6724,6 +6779,7 @@ smbc_option_set(SMBCCTX *context,
bool b;
smbc_get_auth_data_with_context_fn auth_fn;
void *v;
+ const char *s;
} option_value;
va_start(ap, option_name);
@@ -6772,6 +6828,19 @@ smbc_option_set(SMBCCTX *context,
*/
option_value.v = va_arg(ap, void *);
context->internal->_user_data = option_value.v;
+ } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+ /*
+ * Save an encoded value for encryption level.
+ * 0 = off, 1 = attempt, 2 = required.
+ */
+ option_value.s = va_arg(ap, const char *);
+ if (strcmp(option_value.s, "none") == 0) {
+ context->internal->_smb_encryption_level = 0;
+ } else if (strcmp(option_value.s, "request") == 0) {
+ context->internal->_smb_encryption_level = 1;
+ } else if (strcmp(option_value.s, "require") == 0) {
+ context->internal->_smb_encryption_level = 2;
+ }
}
va_end(ap);
@@ -6821,6 +6890,35 @@ smbc_option_get(SMBCCTX *context,
* with smbc_option_get()
*/
return context->internal->_user_data;
+ } else if (strcmp(option_name, "smb_encrypt_level") == 0) {
+ /*
+ * Return the current smb encrypt negotiate option as a string.
+ */
+ switch (context->internal->_smb_encryption_level) {
+ case 0:
+ return (void *) "none";
+ case 1:
+ return (void *) "request";
+ case 2:
+ return (void *) "require";
+ }
+ } else if (strcmp(option_name, "smb_encrypt_on") == 0) {
+ /*
+ * Return the current smb encrypt status option as a bool.
+ * false = off, true = on. We don't know what server is
+ * being requested, so we only return true if all servers
+ * are using an encrypted connection.
+ */
+ SMBCSRV *s;
+ unsigned int num_servers = 0;
+
+ for (s = context->internal->_servers; s; s = s->next) {
+ num_servers++;
+ if (s->cli->trans_enc_state == NULL) {
+ return (void *)false;
+ }
+ }
+ return (void *) (bool) (num_servers > 0);
}
return NULL;
diff --git a/source3/libsmb/smb_seal.c b/source3/libsmb/smb_seal.c
index 055a27d05a..b5befbf7cd 100644
--- a/source3/libsmb/smb_seal.c
+++ b/source3/libsmb/smb_seal.c
@@ -23,13 +23,13 @@
Pull out the encryption context for this packet. 0 means global context.
******************************************************************************/
-NTSTATUS get_enc_ctx_num(const char *buf, uint16 *p_enc_ctx_num)
+NTSTATUS get_enc_ctx_num(const uint8_t *buf, uint16 *p_enc_ctx_num)
{
if (smb_len(buf) < 8) {
return NT_STATUS_INVALID_BUFFER_SIZE;
}
- if (buf[4] == (char)0xFF) {
+ if (buf[4] == 0xFF) {
if (buf[5] == 'S' && buf [6] == 'M' && buf[7] == 'B') {
/* Not an encrypted buffer. */
return NT_STATUS_NOT_FOUND;
@@ -93,8 +93,8 @@ NTSTATUS common_ntlm_decrypt_buffer(NTLMSSP_STATE *ntlmssp_state, char *buf)
memcpy(buf + 8, inbuf + 8 + NTLMSSP_SIG_SIZE, data_len);
- /* Reset the length. */
- _smb_setlen(buf,data_len + 4);
+ /* Reset the length and overwrite the header. */
+ smb_setlen(buf,data_len + 4);
SAFE_FREE(inbuf);
return NT_STATUS_OK;
@@ -203,7 +203,8 @@ static NTSTATUS common_gss_decrypt_buffer(struct smb_tran_enc_state_gss *gss_sta
}
memcpy(buf + 8, out_buf.value, out_buf.length);
- _smb_setlen(buf, out_buf.length + 4);
+ /* Reset the length and overwrite the header. */
+ smb_setlen(buf, out_buf.length + 4);
gss_release_buffer(&minor, &out_buf);
return NT_STATUS_OK;
@@ -440,9 +441,9 @@ void cli_free_enc_buffer(struct cli_state *cli, char *buf)
{
/* We know this is an smb buffer, and we
* didn't malloc, only copy, for a keepalive,
- * so ignore session keepalives. */
+ * so ignore non-session messages. */
- if(CVAL(buf,0) == SMBkeepalive) {
+ if(CVAL(buf,0)) {
return;
}
@@ -461,12 +462,12 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli)
NTSTATUS status;
uint16 enc_ctx_num;
- /* Ignore session keepalives. */
- if(CVAL(cli->inbuf,0) == SMBkeepalive) {
+ /* Ignore non-session messages. */
+ if(CVAL(cli->inbuf,0)) {
return NT_STATUS_OK;
}
- status = get_enc_ctx_num(cli->inbuf, &enc_ctx_num);
+ status = get_enc_ctx_num((const uint8_t *)cli->inbuf, &enc_ctx_num);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -484,8 +485,8 @@ NTSTATUS cli_decrypt_message(struct cli_state *cli)
NTSTATUS cli_encrypt_message(struct cli_state *cli, char **buf_out)
{
- /* Ignore session keepalives. */
- if(CVAL(cli->outbuf,0) == SMBkeepalive) {
+ /* Ignore non-session messages. */
+ if(CVAL(cli->outbuf,0)) {
return NT_STATUS_OK;
}
diff --git a/source3/libsmb/smb_signing.c b/source3/libsmb/smb_signing.c
index d5cbe3b125..f03c21bd0e 100644
--- a/source3/libsmb/smb_signing.c
+++ b/source3/libsmb/smb_signing.c
@@ -745,8 +745,8 @@ bool srv_oplock_set_signing(bool onoff)
bool srv_check_sign_mac(const char *inbuf, bool must_be_ok)
{
- /* Check if it's a session keepalive. */
- if(CVAL(inbuf,0) == SMBkeepalive) {
+ /* Check if it's a non-session message. */
+ if(CVAL(inbuf,0)) {
return True;
}
@@ -759,8 +759,8 @@ bool srv_check_sign_mac(const char *inbuf, bool must_be_ok)
void srv_calculate_sign_mac(char *outbuf)
{
- /* Check if it's a session keepalive. */
- if(CVAL(outbuf,0) == SMBkeepalive) {
+ /* Check if it's a non-session message. */
+ if(CVAL(outbuf,0)) {
return;
}
diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c
index 9e37d1d6cf..d7f6f604f7 100644
--- a/source3/libsmb/smbencrypt.c
+++ b/source3/libsmb/smbencrypt.c
@@ -704,16 +704,22 @@ char *decrypt_trustdom_secret(const char *pass, DATA_BLOB *data_in)
void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
const char *pwd,
DATA_BLOB *session_key,
- struct wkssvc_PasswordBuffer *pwd_buf)
+ struct wkssvc_PasswordBuffer **pwd_buf)
{
uint8_t buffer[516];
struct MD5Context ctx;
-
- DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
-
+ struct wkssvc_PasswordBuffer *my_pwd_buf = NULL;
+ DATA_BLOB confounded_session_key;
int confounder_len = 8;
uint8_t confounder[8];
+ my_pwd_buf = talloc_zero(mem_ctx, struct wkssvc_PasswordBuffer);
+ if (!my_pwd_buf) {
+ return;
+ }
+
+ confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
+
encode_pw_buffer(buffer, pwd, STR_UNICODE);
generate_random_buffer((uint8_t *)confounder, confounder_len);
@@ -725,10 +731,12 @@ void encode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,
SamOEMhashBlob(buffer, 516, &confounded_session_key);
- memcpy(&pwd_buf->data[0], confounder, confounder_len);
- memcpy(&pwd_buf->data[8], buffer, 516);
+ memcpy(&my_pwd_buf->data[0], confounder, confounder_len);
+ memcpy(&my_pwd_buf->data[8], buffer, 516);
data_blob_free(&confounded_session_key);
+
+ *pwd_buf = my_pwd_buf;
}
WERROR decode_wkssvc_join_password_buffer(TALLOC_CTX *mem_ctx,