diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/clidfs.c | 58 | ||||
-rw-r--r-- | source3/libsmb/clifsinfo.c | 33 | ||||
-rw-r--r-- | source3/libsmb/doserr.c | 1 | ||||
-rw-r--r-- | source3/libsmb/libsmbclient.c | 98 | ||||
-rw-r--r-- | source3/libsmb/smb_seal.c | 25 | ||||
-rw-r--r-- | source3/libsmb/smb_signing.c | 8 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 20 |
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, |