From d7955dd6c3a791ea696e4962101eecabb01fd1bc Mon Sep 17 00:00:00 2001 From: SATOH Fumiyasu Date: Thu, 23 Jul 2009 14:37:18 +0900 Subject: [PATCH] Bug#6572: libsmbclient: unable to access 'msdfs proxy' share Because libsmb/libsmb_server.c:SMBC_server() does not check if the \\server\share is a 'msdfs proxy' share or not, libsmbclient cannot access a 'msdfs proxy' share. --- source/include/proto.h | 9 +++ source/libsmb/clidfs.c | 14 +---- source/libsmb/libsmb_server.c | 140 +++++++++++++++++++++++++++++++---------- 3 files changed, 118 insertions(+), 45 deletions(-) diff --git a/source/include/proto.h b/source/include/proto.h index ec8637b..0bc573e 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -4189,6 +4189,15 @@ bool cli_resolve_path(TALLOC_CTX *ctx, const char *path, struct cli_state **targetcli, char **pp_targetpath); +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); /* The following definitions come from libsmb/clidgram.c */ diff --git a/source/libsmb/clidfs.c b/source/libsmb/clidfs.c index 5379ff9..0cc3370 100644 --- a/source/libsmb/clidfs.c +++ b/source/libsmb/clidfs.c @@ -59,16 +59,6 @@ static struct sockaddr_storage dest_ss; 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. ********************************************************************/ @@ -251,7 +241,7 @@ static struct cli_state *do_connect(TALLOC_CTX *ctx, /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. - check_dfs_proxy() will fail if it is a normal share. */ + cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, sharename, @@ -1048,7 +1038,7 @@ bool cli_resolve_path(TALLOC_CTX *ctx, /******************************************************************** ********************************************************************/ -static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, +bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, struct cli_state *cli, const char *sharename, char **pp_newserver, diff --git a/source/libsmb/libsmb_server.c b/source/libsmb/libsmb_server.c index 6880f5c..fd4d739 100644 --- a/source/libsmb/libsmb_server.c +++ b/source/libsmb/libsmb_server.c @@ -227,15 +227,17 @@ check_server_cache: * info we need, unless the username and password were passed in. */ +static SMBCSRV * -SMBC_server(TALLOC_CTX *ctx, +SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, char **pp_workgroup, char **pp_username, - char **pp_password) + char **pp_password, + bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; @@ -250,6 +252,7 @@ SMBC_server(TALLOC_CTX *ctx, uint32 fs_attrs = 0; const char *username_used; NTSTATUS status; + char *newserver, *newshare; zero_sockaddr(&ss); ZERO_STRUCT(c); @@ -279,9 +282,17 @@ SMBC_server(TALLOC_CTX *ctx, * disconnect if the requested share is not the same as the * one that was already connected. */ + /* + * Use srv->cli->desthost and srv->cli->share instead of + * server and share below to connect to the actual share, + * i.e., a normal share or a referred share from + * 'msdfs proxy' share. + */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ - SMBC_call_auth_fn(ctx, context, server, share, + SMBC_call_auth_fn(ctx, context, + srv->cli->desthost, + srv->cli->share, pp_workgroup, pp_username, pp_password); @@ -301,7 +312,7 @@ SMBC_server(TALLOC_CTX *ctx, * tid. */ - if (!cli_send_tconX(srv->cli, share, "?????", + if (!cli_send_tconX(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1)) { @@ -350,8 +361,8 @@ SMBC_server(TALLOC_CTX *ctx, * server and share */ if (srv) { - srv->dev = (dev_t)(str_checksum(server) ^ - str_checksum(share)); + srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^ + str_checksum(srv->cli->share)); } } } @@ -360,8 +371,10 @@ SMBC_server(TALLOC_CTX *ctx, if (srv) { /* ... then we're done here. Give 'em what they came for. */ + *in_cache = true; goto done; } + *in_cache = false; /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { @@ -500,6 +513,32 @@ again: DEBUG(4,(" session setup ok\n")); + /* here's the fun part....to support 'msdfs proxy' shares + (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL + here before trying to connect to the original share. + cli_check_msdfs_proxy() will fail if it is a normal share. */ + + if ((c->capabilities & CAP_DFS) && + cli_check_msdfs_proxy(ctx, c, share, + &newserver, &newshare, + /* FIXME: cli_check_msdfs_proxy() does + not support smbc_smb_encrypt_level type */ + context->internal->smb_encryption_level ? + true : false, + *pp_username, + *pp_password, + *pp_workgroup)) { + cli_shutdown(c); + srv = SMBC_server_internal(ctx, context, connect_if_not_found, + newserver, newshare, pp_workgroup, + pp_username, pp_password, in_cache); + TALLOC_FREE(newserver); + TALLOC_FREE(newshare); + return srv; + } + + /* must be a normal share */ + if (!cli_send_tconX(c, share, "?????", *pp_password, strlen(*pp_password)+1)) { errno = SMBC_errno(context, c); @@ -568,8 +607,9 @@ again: srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { + cli_shutdown(c); errno = ENOMEM; - goto failed; + return NULL; } ZERO_STRUCTP(srv); @@ -579,26 +619,6 @@ again: srv->no_pathinfo2 = False; srv->no_nt_session = False; - /* now add it to the cache (internal or external) */ - /* Let the cache function set errno if it wants to */ - errno = 0; - if (smbc_getFunctionAddCachedServer(context)(context, srv, - server, share, - *pp_workgroup, - *pp_username)) { - int saved_errno = errno; - DEBUG(3, (" Failed to add server to cache\n")); - errno = saved_errno; - if (errno == 0) { - errno = ENOMEM; - } - goto failed; - } - - DEBUG(2, ("Server connect ok: //%s/%s: %p\n", - server, share, srv)); - - DLIST_ADD(context->internal->servers, srv); done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); @@ -615,16 +635,55 @@ done: *pp_username, *pp_password); - return srv; - -failed: - cli_shutdown(c); + return srv; +} + +SMBCSRV * +SMBC_server(TALLOC_CTX *ctx, + SMBCCTX *context, + bool connect_if_not_found, + const char *server, + const char *share, + char **pp_workgroup, + char **pp_username, + char **pp_password) +{ + SMBCSRV *srv=NULL; + bool in_cache; + + srv = SMBC_server_internal(ctx, context, connect_if_not_found, + server, share, pp_workgroup, + pp_username, pp_password, &in_cache); + if (!srv) { return NULL; } + if (in_cache) { + return srv; + } + + /* now add it to the cache (internal or external) */ + /* Let the cache function set errno if it wants to */ + errno = 0; + if (smbc_getFunctionAddCachedServer(context)(context, srv, + server, share, + *pp_workgroup, + *pp_username)) { + int saved_errno = errno; + DEBUG(3, (" Failed to add server to cache\n")); + errno = saved_errno; + if (errno == 0) { + errno = ENOMEM; + } + SAFE_FREE(srv); + return NULL; + } + + DEBUG(2, ("Server connect ok: //%s/%s: %p\n", + server, share, srv)); - SAFE_FREE(srv); - return NULL; + DLIST_ADD(context->internal->servers, srv); + return srv; } /* @@ -645,8 +704,23 @@ SMBC_attr_server(TALLOC_CTX *ctx, struct cli_state *ipc_cli; struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; + SMBCSRV *srv=NULL; SMBCSRV *ipc_srv=NULL; + /* + * Use srv->cli->desthost and srv->cli->share instead of + * server and share below to connect to the actual share, + * i.e., a normal share or a referred share from + * 'msdfs proxy' share. + */ + srv = SMBC_server(ctx, context, true, server, share, + pp_workgroup, pp_username, pp_password); + if (!srv) { + return NULL; + } + server = srv->cli->desthost; + share = srv->cli->share; + /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share -- 1.6.3.3