char *password;
bool got_pass;
bool use_kerberos;
+ bool fallback_after_kerberos;
int signing_state;
} cm_creds;
static struct client_connection *connections;
+static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
+ struct cli_state *cli,
+ const char *sharename,
+ char **pp_newserver,
+ char **pp_newshare,
+ bool force_encrypt,
+ const char *username,
+ const char *password,
+ const char *domain);
+
+/********************************************************************
+ 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 status = cli_force_encryption(c,
+ username,
+ password,
+ domain);
+
+ if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) {
+ 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)) {
+ 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)) {
+ d_printf("Encryption required and "
+ "share %s doesn't support "
+ "encryption.\n", sharename);
+ } else if (!NT_STATUS_IS_OK(status)) {
+ d_printf("Encryption required and "
+ "setup failed with error %s.\n",
+ nt_errstr(status));
+ }
+
+ return status;
+}
+
/********************************************************************
Return a connection to a server.
********************************************************************/
static struct cli_state *do_connect(TALLOC_CTX *ctx,
const char *server,
const char *share,
- bool show_sessetup)
+ bool show_sessetup,
+ bool force_encrypt)
{
struct cli_state *c = NULL;
struct nmb_name called, calling;
server_n = server;
- zero_addr(&ss);
+ zero_sockaddr(&ss);
make_nmb_name(&calling, global_myname(), 0x0);
make_nmb_name(&called , server, name_type);
again:
- zero_addr(&ss);
+ zero_sockaddr(&ss);
if (have_ip)
ss = dest_ss;
/* have to open a new connection */
if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
d_printf("Connection to %s failed\n", server_n);
+ if (c) {
+ cli_shutdown(c);
+ }
return NULL;
}
status = cli_connect(c, server_n, &ss);
d_printf("Connection to %s failed (Error %s)\n",
server_n,
nt_errstr(status));
+ cli_shutdown(c);
return NULL;
}
c->protocol = max_protocol;
c->use_kerberos = cm_creds.use_kerberos;
+ c->fallback_after_kerberos = cm_creds.fallback_after_kerberos;
cli_setup_signing_state(c, cm_creds.signing_state);
if (!cli_session_request(c, &calling, &called)) {
return NULL;
}
- if (!cm_creds.got_pass) {
- char *pass = getpass("Password: ");
+ if (!cm_creds.got_pass && !cm_creds.use_kerberos) {
+ char *label = NULL;
+ char *pass;
+ label = talloc_asprintf(ctx, "Enter %s's password: ",
+ cm_creds.username);
+ pass = getpass(label);
if (pass) {
cm_set_password(pass);
}
+ TALLOC_FREE(label);
}
username = cm_creds.username ? cm_creds.username : "";
if ((c->capabilities & CAP_DFS) &&
cli_check_msdfs_proxy(ctx, c, sharename,
- &newserver, &newshare)) {
+ &newserver, &newshare,
+ force_encrypt,
+ username,
+ password,
+ lp_workgroup())) {
cli_shutdown(c);
- return do_connect(ctx, newserver, newshare, false);
+ return do_connect(ctx, newserver,
+ newshare, false, force_encrypt);
}
/* must be a normal share */
return NULL;
}
+ if (force_encrypt) {
+ status = cli_cm_force_encryption(c,
+ username,
+ password,
+ lp_workgroup(),
+ sharename);
+ if (!NT_STATUS_IS_OK(status)) {
+ cli_shutdown(c);
+ return NULL;
+ }
+ }
+
DEBUG(4,(" tconx ok\n"));
return c;
}
struct cli_state *referring_cli,
const char *server,
const char *share,
- bool show_hdr)
+ bool show_hdr,
+ bool force_encrypt)
{
struct client_connection *node;
return NULL;
}
- node->cli = do_connect(ctx, server, share, show_hdr);
+ node->cli = do_connect(ctx, server, share, show_hdr, force_encrypt);
if ( !node->cli ) {
TALLOC_FREE( node );
if (referring_cli && referring_cli->posix_capabilities) {
uint16 major, minor;
uint32 caplow, caphigh;
- if (cli_unix_extensions_version(cli, &major,
+ if (cli_unix_extensions_version(node->cli, &major,
&minor, &caplow, &caphigh)) {
- cli_set_unix_extensions_capabilities(cli, major, minor,
+ cli_set_unix_extensions_capabilities(node->cli,
+ major, minor,
caplow, caphigh);
}
}
struct cli_state *referring_cli,
const char *server,
const char *share,
- bool show_hdr)
+ bool show_hdr,
+ bool force_encrypt)
{
struct cli_state *c;
c = cli_cm_find(server, share);
if (!c) {
- c = cli_cm_connect(ctx, referring_cli, server, share, show_hdr);
+ c = cli_cm_connect(ctx, referring_cli,
+ server, share, show_hdr, force_encrypt);
}
return c;
}
}
+/****************************************************************************
+****************************************************************************/
+
void cli_cm_set_credentials(void)
{
SAFE_FREE(cm_creds.username);
}
cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos();
+ cm_creds.fallback_after_kerberos = false;
cm_creds.signing_state = get_cmdline_auth_info_signing_state();
}
/****************************************************************************
****************************************************************************/
+void cli_cm_set_signing_state(int state)
+{
+ cm_creds.signing_state = state;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_username(const char *username)
+{
+ SAFE_FREE(cm_creds.username);
+ cm_creds.username = SMB_STRDUP(username);
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_password(const char *newpass)
+{
+ SAFE_FREE(cm_creds.password);
+ cm_creds.password = SMB_STRDUP(newpass);
+ if (cm_creds.password) {
+ cm_creds.got_pass = true;
+ }
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_use_kerberos(void)
+{
+ cm_creds.use_kerberos = true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
+void cli_cm_set_fallback_after_kerberos(void)
+{
+ cm_creds.fallback_after_kerberos = true;
+}
+
+/****************************************************************************
+****************************************************************************/
+
void cli_cm_set_dest_ss(struct sockaddr_storage *pss)
{
dest_ss = *pss;
Get the dfs referral link.
********************************************************************/
-bool cli_dfs_get_referral(struct cli_state *cli,
+bool cli_dfs_get_referral(TALLOC_CTX *ctx,
+ struct cli_state *cli,
const char *path,
CLIENT_DFS_REFERRAL**refs,
size_t *num_refs,
unsigned int data_len = 0;
unsigned int param_len = 0;
uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
- char param[1024+2];
+ char *param;
char *rparam=NULL, *rdata=NULL;
char *p;
+ char *endp;
size_t pathlen = 2*(strlen(path)+1);
uint16 num_referrals;
CLIENT_DFS_REFERRAL *referrals = NULL;
+ bool ret = false;
+
+ *num_refs = 0;
+ *refs = NULL;
- memset(param, 0, sizeof(param));
+ param = SMB_MALLOC_ARRAY(char, 2+pathlen+2);
+ if (!param) {
+ return false;
+ }
SSVAL(param, 0, 0x03); /* max referral level */
p = ¶m[2];
- p += clistr_push(cli, p, path, MIN(pathlen, sizeof(param)-2),
- STR_TERMINATE);
+ p += clistr_push(cli, p, path, pathlen, STR_TERMINATE);
param_len = PTR_DIFF(p, param);
if (!cli_send_trans(cli, SMBtrans2,
- NULL, /* name */
- -1, 0, /* fid, flags */
- &setup, 1, 0, /* setup, length, max */
- param, param_len, 2, /* param, length, max */
- NULL, 0, cli->max_xmit /* data, length, max */
- )) {
- return false;
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 2, /* param, length, max */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ SAFE_FREE(param);
+ return false;
}
+ SAFE_FREE(param);
+
if (!cli_receive_trans(cli, SMBtrans2,
&rparam, ¶m_len,
&rdata, &data_len)) {
return false;
}
- *consumed = SVAL( rdata, 0 );
- num_referrals = SVAL( rdata, 2 );
+ if (data_len < 4) {
+ goto out;
+ }
+
+ endp = rdata + data_len;
- if ( num_referrals != 0 ) {
+ *consumed = SVAL(rdata, 0);
+ num_referrals = SVAL(rdata, 2);
+
+ if (num_referrals != 0) {
uint16 ref_version;
uint16 ref_size;
int i;
uint16 node_offset;
- referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL,
+ referrals = TALLOC_ARRAY(ctx, CLIENT_DFS_REFERRAL,
num_referrals);
+ if (!referrals) {
+ goto out;
+ }
/* start at the referrals array */
p = rdata+8;
- for ( i=0; i<num_referrals; i++ ) {
- ref_version = SVAL( p, 0 );
- ref_size = SVAL( p, 2 );
- node_offset = SVAL( p, 16 );
+ for (i=0; i<num_referrals && p < endp; i++) {
+ if (p + 18 > endp) {
+ goto out;
+ }
+ ref_version = SVAL(p, 0);
+ ref_size = SVAL(p, 2);
+ node_offset = SVAL(p, 16);
- if ( ref_version != 3 ) {
+ if (ref_version != 3) {
p += ref_size;
continue;
}
- referrals[i].proximity = SVAL( p, 8 );
- referrals[i].ttl = SVAL( p, 10 );
+ referrals[i].proximity = SVAL(p, 8);
+ referrals[i].ttl = SVAL(p, 10);
- clistr_pull( cli, referrals[i].dfspath, p+node_offset,
- sizeof(referrals[i].dfspath), -1,
+ if (p + node_offset > endp) {
+ goto out;
+ }
+ clistr_pull_talloc(ctx, cli, &referrals[i].dfspath,
+ p+node_offset, -1,
STR_TERMINATE|STR_UNICODE );
+ if (!referrals[i].dfspath) {
+ goto out;
+ }
p += ref_size;
}
+ if (i < num_referrals) {
+ goto out;
+ }
}
+ ret = true;
+
*num_refs = num_referrals;
*refs = referrals;
+ out:
+
SAFE_FREE(rdata);
SAFE_FREE(rparam);
-
- return true;
+ return ret;
}
-
/********************************************************************
********************************************************************/
char **pp_targetpath)
{
CLIENT_DFS_REFERRAL *refs = NULL;
- size_t num_refs;
+ size_t num_refs = 0;
uint16 consumed;
struct cli_state *cli_ipc = NULL;
char *dfs_path = NULL;
/* Check for the referral. */
if (!(cli_ipc = cli_cm_open(ctx, rootcli,
- rootcli->desthost, "IPC$", false))) {
+ rootcli->desthost,
+ "IPC$", false,
+ (rootcli->trans_enc_state != NULL)))) {
return false;
}
- if (!cli_dfs_get_referral(cli_ipc, dfs_path, &refs,
+ if (!cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
&num_refs, &consumed) || !num_refs) {
return false;
}
/* Just store the first referral for now. */
+ if (!refs[0].dfspath) {
+ return false;
+ }
split_dfs_path(ctx, refs[0].dfspath, &server, &share, &extrapath );
- SAFE_FREE(refs);
if (!server || !share) {
return false;
/* Open the connection to the target server & share */
if ((*targetcli = cli_cm_open(ctx, rootcli,
- server, share, false)) == NULL) {
+ server,
+ share,
+ false,
+ (rootcli->trans_enc_state != NULL))) == NULL) {
d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
server, share );
return false;
/********************************************************************
********************************************************************/
-bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
+static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
struct cli_state *cli,
const char *sharename,
char **pp_newserver,
- char **pp_newshare )
+ char **pp_newshare,
+ bool force_encrypt,
+ const char *username,
+ const char *password,
+ const char *domain)
{
CLIENT_DFS_REFERRAL *refs = NULL;
- size_t num_refs;
+ size_t num_refs = 0;
uint16 consumed;
char *fullpath = NULL;
bool res;
return false;
}
- res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed);
+ if (force_encrypt) {
+ NTSTATUS status = cli_cm_force_encryption(cli,
+ username,
+ password,
+ lp_workgroup(),
+ "IPC$");
+ if (!NT_STATUS_IS_OK(status)) {
+ return false;
+ }
+ }
+
+ res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
if (!cli_tdis(cli)) {
- SAFE_FREE(refs);
return false;
}
cli->cnum = cnum;
if (!res || !num_refs) {
- SAFE_FREE(refs);
+ return false;
+ }
+
+ if (!refs[0].dfspath) {
return false;
}
split_dfs_path(ctx, refs[0].dfspath, pp_newserver,
pp_newshare, &newextrapath );
- SAFE_FREE(refs);
-
- if (!pp_newserver || !pp_newshare) {
+ if ((*pp_newserver == NULL) || (*pp_newshare == NULL)) {
return false;
}