Fix bug #6496 - MS-DFS: cannot follow multibyte char link name.
authorSATOH Fumiyasu <fumiyas@osstech.co.jp>
Tue, 30 Jun 2009 22:29:08 +0000 (15:29 -0700)
committerJeremy Allison <jra@samba.org>
Tue, 30 Jun 2009 22:29:08 +0000 (15:29 -0700)
consumed_ucs is the number of bytes
of the UCS2 path consumed not counting any
terminating null. We need to convert
back to unix charset and count again
to get the number of bytes consumed from
the incoming path.

source3/include/proto.h
source3/libsmb/clidfs.c

index 49afd8c46681f43ebc0a112d7d363c4c44562911..a3ae1ddad708e9f00d9845f7286d73fa43700134 100644 (file)
@@ -2260,7 +2260,7 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
                        const char *path,
                        CLIENT_DFS_REFERRAL**refs,
                        size_t *num_refs,
-                       uint16 *consumed);
+                       size_t *consumed);
 bool cli_resolve_path(TALLOC_CTX *ctx,
                        const char *mountpt,
                        const struct user_auth_info *dfs_auth_info,
index 98b96cfc566652f34d2ef1e3e5c0a8f546651fb1..5e944f1aaad29d6a3a98ff0780cc54275b5b7fa7 100644 (file)
@@ -603,16 +603,19 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
                        const char *path,
                        CLIENT_DFS_REFERRAL**refs,
                        size_t *num_refs,
-                       uint16 *consumed)
+                       size_t *consumed)
 {
        unsigned int data_len = 0;
        unsigned int param_len = 0;
        uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
-       char *param;
+       char *param = NULL;
        char *rparam=NULL, *rdata=NULL;
        char *p;
        char *endp;
        size_t pathlen = 2*(strlen(path)+1);
+       smb_ucs2_t *path_ucs;
+       char *consumed_path = NULL;
+       uint16_t consumed_ucs;
        uint16 num_referrals;
        CLIENT_DFS_REFERRAL *referrals = NULL;
        bool ret = false;
@@ -622,11 +625,12 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
 
        param = SMB_MALLOC_ARRAY(char, 2+pathlen+2);
        if (!param) {
-               return false;
+               goto out;
        }
        SSVAL(param, 0, 0x03);  /* max referral level */
        p = &param[2];
 
+       path_ucs = (smb_ucs2_t *)p;
        p += clistr_push(cli, p, path, pathlen, STR_TERMINATE);
        param_len = PTR_DIFF(p, param);
 
@@ -637,16 +641,13 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
                        param, param_len, 2,            /* param, length, max */
                        NULL, 0, cli->max_xmit /* data, length, max */
                        )) {
-               SAFE_FREE(param);
-               return false;
+               goto out;
        }
 
-       SAFE_FREE(param);
-
        if (!cli_receive_trans(cli, SMBtrans2,
                &rparam, &param_len,
                &rdata, &data_len)) {
-                       return false;
+               goto out;
        }
 
        if (data_len < 4) {
@@ -655,9 +656,30 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
 
        endp = rdata + data_len;
 
-       *consumed     = SVAL(rdata, 0);
+       consumed_ucs  = SVAL(rdata, 0);
        num_referrals = SVAL(rdata, 2);
 
+       /* consumed_ucs is the number of bytes
+        * of the UCS2 path consumed not counting any
+        * terminating null. We need to convert
+        * back to unix charset and count again
+        * to get the number of bytes consumed from
+        * the incoming path. */
+
+       if (pull_string_talloc(talloc_tos(),
+                       NULL,
+                       0,
+                       &consumed_path,
+                       path_ucs,
+                       consumed_ucs,
+                       STR_UNICODE) == 0) {
+               goto out;
+       }
+       if (consumed_path == NULL) {
+               goto out;
+       }
+       *consumed = strlen(consumed_path);
+
        if (num_referrals != 0) {
                uint16 ref_version;
                uint16 ref_size;
@@ -714,6 +736,8 @@ bool cli_dfs_get_referral(TALLOC_CTX *ctx,
 
   out:
 
+       TALLOC_FREE(consumed_path);
+       SAFE_FREE(param);
        SAFE_FREE(rdata);
        SAFE_FREE(rparam);
        return ret;
@@ -732,7 +756,7 @@ bool cli_resolve_path(TALLOC_CTX *ctx,
 {
        CLIENT_DFS_REFERRAL *refs = NULL;
        size_t num_refs = 0;
-       uint16 consumed;
+       size_t consumed = 0;
        struct cli_state *cli_ipc = NULL;
        char *dfs_path = NULL;
        char *cleanpath = NULL;
@@ -840,13 +864,13 @@ bool cli_resolve_path(TALLOC_CTX *ctx,
        if (!dfs_path) {
                return false;
        }
-       pathlen = strlen(dfs_path)*2;
+       pathlen = strlen(dfs_path);
        consumed = MIN(pathlen, consumed);
-       *pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed/2]);
+       *pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]);
        if (!*pp_targetpath) {
                return false;
        }
-       dfs_path[consumed/2] = '\0';
+       dfs_path[consumed] = '\0';
 
        /*
         * *pp_targetpath is now the unconsumed part of the path.
@@ -963,7 +987,7 @@ static bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
 {
        CLIENT_DFS_REFERRAL *refs = NULL;
        size_t num_refs = 0;
-       uint16 consumed;
+       size_t consumed = 0;
        char *fullpath = NULL;
        bool res;
        uint16 cnum;