#include "trans2.h"
#include "libsmb/nmblib.h"
#include "../libcli/smb/smbXcli_base.h"
+#include "auth/credentials/credentials.h"
/********************************************************************
Important point.
Ensure a connection is encrypted.
********************************************************************/
-NTSTATUS cli_cm_force_encryption(struct cli_state *c,
- const char *username,
- const char *password,
- const char *domain,
- const char *sharename)
+NTSTATUS cli_cm_force_encryption_creds(struct cli_state *c,
+ struct cli_credentials *creds,
+ const char *sharename)
{
+ uint16_t major, minor;
+ uint32_t caplow, caphigh;
NTSTATUS status;
if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
return status;
}
- status = cli_force_encryption(c,
- username,
- password,
- domain);
-
- if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
+ if (!SERVER_HAS_UNIX_CIFS(c)) {
d_printf("Encryption required and "
"server that doesn't support "
"UNIX extensions - failing connect\n");
- } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNKNOWN_REVISION)) {
+ return NT_STATUS_NOT_SUPPORTED;
+ }
+
+ status = cli_unix_extensions_version(c, &major, &minor, &caplow,
+ &caphigh);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf("Encryption required and "
"can't get UNIX CIFS extensions "
"version from server.\n");
- } else if (NT_STATUS_EQUAL(status,NT_STATUS_UNSUPPORTED_COMPRESSION)) {
+ return NT_STATUS_UNKNOWN_REVISION;
+ }
+
+ if (!(caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP)) {
d_printf("Encryption required and "
"share %s doesn't support "
"encryption.\n", sharename);
- } else if (!NT_STATUS_IS_OK(status)) {
+ return NT_STATUS_UNSUPPORTED_COMPRESSION;
+ }
+
+ status = cli_smb1_setup_encryption(c, creds);
+ if (!NT_STATUS_IS_OK(status)) {
d_printf("Encryption required and "
"setup failed with error %s.\n",
nt_errstr(status));
+ return status;
}
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_cm_force_encryption(struct cli_state *c,
+ const char *username,
+ const char *password,
+ const char *domain,
+ const char *sharename)
+{
+ struct cli_credentials *creds = NULL;
+ NTSTATUS status;
+
+ creds = cli_session_creds_init(c,
+ username,
+ domain,
+ NULL, /* default realm */
+ password,
+ c->use_kerberos,
+ c->fallback_after_kerberos,
+ c->use_ccache,
+ c->pw_nt_hash);
+ if (creds == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = cli_cm_force_encryption_creds(c, creds, sharename);
+ /* gensec currently references the creds so we can't free them here */
+ talloc_unlink(c, creds);
return status;
}
char *servicename;
char *sharename;
char *newserver, *newshare;
- const char *username;
- const char *password;
NTSTATUS status;
int flags = 0;
+ enum protocol_types protocol = PROTOCOL_NONE;
+ int signing_state = get_cmdline_auth_info_signing_state(auth_info);
+ struct cli_credentials *creds = NULL;
+
+ if (force_encrypt) {
+ signing_state = SMB_SIGNING_REQUIRED;
+ }
/* make a copy so we don't modify the global string 'service' */
servicename = talloc_strdup(ctx,share);
status = cli_connect_nb(
server, NULL, port, name_type, NULL,
- get_cmdline_auth_info_signing_state(auth_info),
+ signing_state,
flags, &c);
if (!NT_STATUS_IS_OK(status)) {
- d_printf("Connection to %s failed (Error %s)\n",
- server,
- nt_errstr(status));
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
+ DBG_ERR("NetBIOS support disabled, unable to connect");
+ }
+
+ DBG_WARNING("Connection to %s failed (Error %s)\n",
+ server,
+ nt_errstr(status));
return status;
}
if (max_protocol == 0) {
- max_protocol = PROTOCOL_NT1;
+ max_protocol = PROTOCOL_LATEST;
}
DEBUG(4,(" session request ok\n"));
cli_shutdown(c);
return status;
}
+ protocol = smbXcli_conn_protocol(c->conn);
+ DEBUG(4,(" negotiated dialect[%s] against server[%s]\n",
+ smb_protocol_types_string(protocol),
+ smbXcli_conn_remote_name(c->conn)));
- if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
+ if (protocol >= PROTOCOL_SMB2_02) {
/* Ensure we ask for some initial credits. */
smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS);
}
- username = get_cmdline_auth_info_username(auth_info);
- password = get_cmdline_auth_info_password(auth_info);
+ creds = get_cmdline_auth_info_creds(auth_info);
- status = cli_session_setup(c, username,
- password, strlen(password),
- password, strlen(password),
- lp_workgroup());
+ status = cli_session_setup_creds(c, creds);
if (!NT_STATUS_IS_OK(status)) {
/* If a password was not supplied then
* try again with a null username. */
- if (password[0] || !username[0] ||
- get_cmdline_auth_info_use_kerberos(auth_info) ||
- !NT_STATUS_IS_OK(status = cli_session_setup(c, "",
- "", 0,
- "", 0,
- lp_workgroup()))) {
+ if (force_encrypt || smbXcli_conn_signing_mandatory(c->conn) ||
+ cli_credentials_authentication_requested(creds) ||
+ cli_credentials_is_anonymous(creds) ||
+ !NT_STATUS_IS_OK(status = cli_session_setup_anon(c)))
+ {
d_printf("session setup failed: %s\n",
nt_errstr(status));
if (NT_STATUS_EQUAL(status,
if (smbXcli_conn_dfs_supported(c->conn) &&
cli_check_msdfs_proxy(ctx, c, sharename,
&newserver, &newshare,
- force_encrypt,
- username,
- password,
- lp_workgroup())) {
+ force_encrypt, creds)) {
cli_shutdown(c);
return do_connect(ctx, newserver,
newshare, auth_info, false,
/* must be a normal share */
- status = cli_tree_connect(c, sharename, "?????",
- password, strlen(password)+1);
+ status = cli_tree_connect_creds(c, sharename, "?????", creds);
if (!NT_STATUS_IS_OK(status)) {
d_printf("tree connect failed: %s\n", nt_errstr(status));
cli_shutdown(c);
}
if (force_encrypt) {
- status = cli_cm_force_encryption(c,
- username,
- password,
- lp_workgroup(),
- sharename);
+ status = cli_cm_force_encryption_creds(c,
+ creds,
+ sharename);
if (!NT_STATUS_IS_OK(status)) {
cli_shutdown(c);
return status;
const char *server,
const char *share,
const struct user_auth_info *auth_info,
- bool show_hdr,
bool force_encrypt,
int max_protocol,
int port,
/* Enter into the list. */
if (referring_cli) {
- DLIST_ADD_END(referring_cli, cli, struct cli_state *);
+ DLIST_ADD_END(referring_cli, cli);
}
if (referring_cli && referring_cli->requested_posix_capabilities) {
- uint16 major, minor;
- uint32 caplow, caphigh;
+ uint16_t major, minor;
+ uint32_t caplow, caphigh;
status = cli_unix_extensions_version(cli, &major, &minor,
&caplow, &caphigh);
if (NT_STATUS_IS_OK(status)) {
const char *server,
const char *share,
const struct user_auth_info *auth_info,
- bool show_hdr,
bool force_encrypt,
int max_protocol,
int port,
server,
share,
auth_info,
- show_hdr,
force_encrypt,
max_protocol,
port,
Get the dfs referral link.
********************************************************************/
-NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx,
+NTSTATUS cli_dfs_get_referral_ex(TALLOC_CTX *ctx,
struct cli_state *cli,
const char *path,
+ uint16_t max_referral_level,
struct client_dfs_referral **refs,
size_t *num_refs,
size_t *consumed)
smb_ucs2_t *path_ucs;
char *consumed_path = NULL;
uint16_t consumed_ucs;
- uint16 num_referrals;
+ uint16_t num_referrals;
struct client_dfs_referral *referrals = NULL;
NTSTATUS status;
TALLOC_CTX *frame = talloc_stackframe();
status = NT_STATUS_NO_MEMORY;
goto out;
}
- SSVAL(param, 0, 0x03); /* max referral level */
+ SSVAL(param, 0, max_referral_level);
param = trans2_bytes_push_str(param, smbXcli_conn_use_unicode(cli->conn),
path, strlen(path)+1,
*consumed = strlen(consumed_path);
if (num_referrals != 0) {
- uint16 ref_version;
- uint16 ref_size;
+ uint16_t ref_version;
+ uint16_t ref_size;
int i;
- uint16 node_offset;
+ uint16_t node_offset;
referrals = talloc_array(ctx, struct client_dfs_referral,
num_referrals);
return status;
}
+NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *path,
+ struct client_dfs_referral **refs,
+ size_t *num_refs,
+ size_t *consumed)
+{
+ return cli_dfs_get_referral_ex(ctx,
+ cli,
+ path,
+ 3,
+ refs, /* Max referral level we want */
+ num_refs,
+ consumed);
+}
+
/********************************************************************
********************************************************************/
+struct cli_dfs_path_split {
+ char *server;
+ char *share;
+ char *extrapath;
+};
NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
const char *mountpt,
char *cleanpath = NULL;
char *extrapath = NULL;
int pathlen;
- char *server = NULL;
- char *share = NULL;
struct cli_state *newcli = NULL;
+ struct cli_state *ccli = NULL;
+ int count = 0;
char *newpath = NULL;
char *newmount = NULL;
char *ppath = NULL;
SMB_STRUCT_STAT sbuf;
- uint32 attributes;
+ uint32_t attributes;
NTSTATUS status;
struct smbXcli_tcon *root_tcon = NULL;
struct smbXcli_tcon *target_tcon = NULL;
+ struct cli_dfs_path_split *dfs_refs = NULL;
if ( !rootcli || !path || !targetcli ) {
return NT_STATUS_INVALID_PARAMETER;
root_tcon = rootcli->smb1.tcon;
}
+ /*
+ * Avoid more than one leading directory separator
+ */
+ while (IS_DIRECTORY_SEP(path[0]) && IS_DIRECTORY_SEP(path[1])) {
+ path++;
+ }
+
if (!smbXcli_tcon_is_dfs_share(root_tcon)) {
*targetcli = rootcli;
*pp_targetpath = talloc_strdup(ctx, path);
smbXcli_conn_remote_name(rootcli->conn),
"IPC$",
dfs_auth_info,
- false,
- smb1cli_conn_encryption_on(rootcli->conn),
+ cli_state_is_encryption_on(rootcli),
smbXcli_conn_protocol(rootcli->conn),
0,
0x20,
status = cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
&num_refs, &consumed);
- if (!NT_STATUS_IS_OK(status) || !num_refs) {
+ if (!NT_STATUS_IS_OK(status)) {
return status;
}
- /* Just store the first referral for now. */
-
- if (!refs[0].dfspath) {
+ if (!num_refs || !refs[0].dfspath) {
return NT_STATUS_NOT_FOUND;
}
- if (!split_dfs_path(ctx, refs[0].dfspath, &server, &share,
- &extrapath)) {
- return NT_STATUS_NOT_FOUND;
+
+ /*
+ * Bug#10123 - DFS referal entries can be provided in a random order,
+ * so check the connection cache for each item to avoid unnecessary
+ * reconnections.
+ */
+ dfs_refs = talloc_array(ctx, struct cli_dfs_path_split, num_refs);
+ if (dfs_refs == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ for (count = 0; count < num_refs; count++) {
+ if (!split_dfs_path(dfs_refs, refs[count].dfspath,
+ &dfs_refs[count].server,
+ &dfs_refs[count].share,
+ &dfs_refs[count].extrapath)) {
+ TALLOC_FREE(dfs_refs);
+ return NT_STATUS_NOT_FOUND;
+ }
+
+ ccli = cli_cm_find(rootcli, dfs_refs[count].server,
+ dfs_refs[count].share);
+ if (ccli != NULL) {
+ extrapath = dfs_refs[count].extrapath;
+ *targetcli = ccli;
+ break;
+ }
+ }
+
+ /*
+ * If no cached connection was found, then connect to the first live
+ * referral server in the list.
+ */
+ for (count = 0; (ccli == NULL) && (count < num_refs); count++) {
+ /* Connect to the target server & share */
+ status = cli_cm_connect(ctx, rootcli,
+ dfs_refs[count].server,
+ dfs_refs[count].share,
+ dfs_auth_info,
+ cli_state_is_encryption_on(rootcli),
+ smbXcli_conn_protocol(rootcli->conn),
+ 0,
+ 0x20,
+ targetcli);
+ if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
+ dfs_refs[count].server,
+ dfs_refs[count].share);
+ continue;
+ } else {
+ extrapath = dfs_refs[count].extrapath;
+ break;
+ }
+ }
+
+ /* No available referral server for the connection */
+ if (*targetcli == NULL) {
+ TALLOC_FREE(dfs_refs);
+ return status;
}
/* Make sure to recreate the original string including any wildcards. */
dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
if (!dfs_path) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
pathlen = strlen(dfs_path);
consumed = MIN(pathlen, consumed);
*pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]);
if (!*pp_targetpath) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
dfs_path[consumed] = '\0';
* (in \server\share\path format).
*/
- /* Open the connection to the target server & share */
- status = cli_cm_open(ctx, rootcli,
- server,
- share,
- dfs_auth_info,
- false,
- smb1cli_conn_encryption_on(rootcli->conn),
- smbXcli_conn_protocol(rootcli->conn),
- 0,
- 0x20,
- targetcli);
- if (!NT_STATUS_IS_OK(status)) {
- d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
- server, share );
- return status;
- }
-
if (extrapath && strlen(extrapath) > 0) {
/* EMC Celerra NAS version 5.6.50 (at least) doesn't appear to */
/* put the trailing \ on the path, so to be save we put one in if needed */
*pp_targetpath);
}
if (!*pp_targetpath) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
}
d_printf("cli_resolve_path: "
"dfs_path (%s) not in correct format.\n",
dfs_path );
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
ppath++; /* Now pointing at start of server name. */
if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
ppath++; /* Now pointing at start of share name. */
if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
if (!newmount) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NOT_FOUND;
}
*/
*targetcli = newcli;
*pp_targetpath = newpath;
+ TALLOC_FREE(dfs_refs);
return status;
}
}
if (smbXcli_tcon_is_dfs_share(target_tcon)) {
dfs_path = talloc_strdup(ctx, *pp_targetpath);
if (!dfs_path) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
*pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
if (*pp_targetpath == NULL) {
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_NO_MEMORY;
}
}
+ TALLOC_FREE(dfs_refs);
return NT_STATUS_OK;
}
char **pp_newserver,
char **pp_newshare,
bool force_encrypt,
- const char *username,
- const char *password,
- const char *domain)
+ struct cli_credentials *creds)
{
struct client_dfs_referral *refs = NULL;
size_t num_refs = 0;
size_t consumed = 0;
char *fullpath = NULL;
bool res;
- uint16 cnum;
+ struct smbXcli_tcon *orig_tcon = NULL;
char *newextrapath = NULL;
NTSTATUS status;
const char *remote_name;
}
remote_name = smbXcli_conn_remote_name(cli->conn);
- cnum = cli_state_get_tid(cli);
/* special case. never check for a referral on the IPC$ share */
return false;
}
+ /* Store tcon state. */
+ if (cli_state_has_tcon(cli)) {
+ orig_tcon = cli_state_save_tcon(cli);
+ if (orig_tcon == NULL) {
+ return false;
+ }
+ }
+
/* check for the referral */
- if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", NULL, 0))) {
+ if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", NULL))) {
+ cli_state_restore_tcon(cli, orig_tcon);
return false;
}
if (force_encrypt) {
- status = cli_cm_force_encryption(cli,
- username,
- password,
- lp_workgroup(),
- "IPC$");
+ status = cli_cm_force_encryption_creds(cli, creds, "IPC$");
if (!NT_STATUS_IS_OK(status)) {
+ cli_state_restore_tcon(cli, orig_tcon);
return false;
}
}
res = NT_STATUS_IS_OK(status);
status = cli_tdis(cli);
+
+ cli_state_restore_tcon(cli, orig_tcon);
+
if (!NT_STATUS_IS_OK(status)) {
return false;
}
- cli_state_set_tid(cli, cnum);
-
if (!res || !num_refs) {
return false;
}