smbclient: Handle ENUM_DIR in "notify" command
[metze/samba/wip.git] / source3 / client / client.c
index 8cc511983cb385e000ae364d0e7b20a4e4714159..1429b44e9cf1a75f5212749ecf123baf83133b02 100644 (file)
@@ -186,16 +186,20 @@ static bool yesno(const char *p)
  number taken from the buffer. This may not equal the number written.
 ****************************************************************************/
 
-static int writefile(int f, char *b, int n)
+static ssize_t writefile(int f, char *b, size_t n)
 {
-       int i;
+       size_t i = 0;
+
+       if (n == 0) {
+               errno = EINVAL;
+               return -1;
+       }
 
        if (!translation) {
                return write(f,b,n);
        }
 
-       i = 0;
-       while (i < n) {
+       do {
                if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
                        b++;i++;
                }
@@ -204,9 +208,9 @@ static int writefile(int f, char *b, int n)
                }
                b++;
                i++;
-       }
+       } while (i < n);
 
-       return(i);
+       return (ssize_t)i;
 }
 
 /****************************************************************************
@@ -430,7 +434,7 @@ static int do_cd(const char *new_dir)
        }
        client_set_cur_dir(new_cd);
 
-       new_cd = clean_name(ctx, new_cd);
+       new_cd = client_clean_name(ctx, new_cd);
        client_set_cur_dir(new_cd);
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
@@ -474,7 +478,7 @@ static int do_cd(const char *new_dir)
                        client_set_cur_dir(saved_dir);
                        goto out;
                }
-               targetpath = clean_name(ctx, targetpath);
+               targetpath = client_clean_name(ctx, targetpath);
                if (!targetpath) {
                        client_set_cur_dir(saved_dir);
                        goto out;
@@ -984,6 +988,11 @@ static int cmd_dir(void)
                return 1;
        }
 
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
+
        if (showacls) {
                /* cwd is only used if showacls is on */
                client_set_cwd(client_get_cur_dir());
@@ -1036,6 +1045,14 @@ static int cmd_du(void)
        } else {
                mask = talloc_strdup(ctx, "*");
        }
+       if (!mask) {
+               return 1;
+       }
+
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = do_list(mask, attribute, do_du, recurse, true);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1079,7 +1096,10 @@ static int cmd_echo(void)
 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
 {
        int *pfd = (int *)priv;
-       if (writefile(*pfd, buf, n) == -1) {
+       ssize_t rc;
+
+       rc = writefile(*pfd, buf, n);
+       if (rc == -1) {
                return map_nt_error_from_unix(errno);
        }
        return NT_STATUS_OK;
@@ -1232,7 +1252,7 @@ static int cmd_get(void)
        if (!rname) {
                return 1;
        }
-       rname = clean_name(ctx, rname);
+       rname = client_clean_name(ctx, rname);
        if (!rname) {
                return 1;
        }
@@ -1298,6 +1318,10 @@ static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
                if (!rname) {
                        return NT_STATUS_NO_MEMORY;
                }
+               rname = client_clean_name(ctx, rname);
+               if (rname == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
                do_get(rname, finfo->name, false);
                TALLOC_FREE(rname);
                return NT_STATUS_OK;
@@ -1317,6 +1341,10 @@ static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
        if (!new_cd) {
                return NT_STATUS_NO_MEMORY;
        }
+       new_cd = client_clean_name(ctx, new_cd);
+       if (new_cd == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
        client_set_cur_dir(new_cd);
 
        string_replace(finfo->name,'\\','/');
@@ -1347,6 +1375,10 @@ static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
                return NT_STATUS_NO_MEMORY;
        }
 
+       mget_mask = client_clean_name(ctx, mget_mask);
+       if (mget_mask == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
        status = do_list(mget_mask,
                         (FILE_ATTRIBUTE_SYSTEM
                          | FILE_ATTRIBUTE_HIDDEN
@@ -1416,7 +1448,7 @@ static int cmd_more(void)
        if (!rname) {
                return 1;
        }
-       rname = clean_name(ctx,rname);
+       rname = client_clean_name(ctx,rname);
        if (!rname) {
                return 1;
        }
@@ -1474,6 +1506,10 @@ static int cmd_mget(void)
                if (!mget_mask) {
                        return 1;
                }
+               mget_mask = client_clean_name(ctx, mget_mask);
+               if (mget_mask == NULL) {
+                       return 1;
+               }
                status = do_list(mget_mask, attribute, do_mget, false, true);
                if (!NT_STATUS_IS_OK(status)) {
                        return 1;
@@ -1492,6 +1528,10 @@ static int cmd_mget(void)
                if (!mget_mask) {
                        return 1;
                }
+               mget_mask = client_clean_name(ctx, mget_mask);
+               if (mget_mask == NULL) {
+                       return 1;
+               }
                status = do_list(mget_mask, attribute, do_mget, false, true);
                if (!NT_STATUS_IS_OK(status)) {
                        return 1;
@@ -1588,6 +1628,10 @@ static int cmd_mkdir(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        if (recurse) {
                char *ddir = NULL;
@@ -1659,6 +1703,10 @@ static int cmd_altname(void)
        if (!name) {
                return 1;
        }
+       name = client_clean_name(ctx, name);
+       if (name == NULL) {
+               return 1;
+       }
        do_altname(name);
        return 0;
 }
@@ -1889,7 +1937,10 @@ static int cmd_allinfo(void)
        if (!name) {
                return 1;
        }
-
+       name = client_clean_name(ctx, name);
+       if (name == NULL) {
+               return 1;
+       }
        do_allinfo(name);
 
        return 0;
@@ -2052,7 +2103,7 @@ static int cmd_put(void)
                return 1;
        }
 
-       rname = clean_name(ctx, rname);
+       rname = client_clean_name(ctx, rname);
        if (!rname) {
                return 1;
        }
@@ -2261,6 +2312,19 @@ static int cmd_mput(void)
                                                break;
                                        }
                                        normalize_name(rname);
+                                       {
+                                               char *tmp_rname =
+                                                       client_clean_name(ctx, rname);
+                                               if (tmp_rname == NULL) {
+                                                       break;
+                                               }
+                                               SAFE_FREE(rname);
+                                               rname = smb_xstrdup(tmp_rname);
+                                               TALLOC_FREE(tmp_rname);
+                                               if (rname == NULL) {
+                                                       break;
+                                               }
+                                       }
                                        if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
                                            !do_mkdir(rname)) {
                                                DEBUG (0, ("Unable to make dir, skipping..."));
@@ -2291,6 +2355,18 @@ static int cmd_mput(void)
 
                        normalize_name(rname);
 
+                       {
+                               char *tmp_rname = client_clean_name(ctx, rname);
+                               if (tmp_rname == NULL) {
+                                       break;
+                               }
+                               SAFE_FREE(rname);
+                               rname = smb_xstrdup(tmp_rname);
+                               TALLOC_FREE(tmp_rname);
+                               if (rname == NULL) {
+                                       break;
+                               }
+                       }
                        do_put(rname, lname, false);
                }
                free_file_list(file_list);
@@ -2461,6 +2537,10 @@ static int cmd_del(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = do_list(mask,attribute,do_del,false,false);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2577,6 +2657,10 @@ static int cmd_deltree(void)
        if (mask == NULL) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        deltree_list_head = NULL;
 
@@ -2678,6 +2762,10 @@ static int cmd_wdel(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                                cli, mask, &targetcli, &targetname);
@@ -2719,6 +2807,11 @@ static int cmd_open(void)
                return 1;
        }
 
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
+
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, mask, &targetcli, &targetname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -2834,6 +2927,10 @@ static int cmd_posix_open(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("posix_open <filename> 0<mode>\n");
@@ -2889,6 +2986,10 @@ static int cmd_posix_mkdir(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("posix_mkdir <filename> 0<mode>\n");
@@ -2933,6 +3034,10 @@ static int cmd_posix_unlink(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                                cli, mask, &targetcli, &targetname);
@@ -2972,6 +3077,10 @@ static int cmd_posix_rmdir(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, mask, &targetcli, &targetname);
@@ -3274,6 +3383,10 @@ static int cmd_rmdir(void)
        if (!mask) {
                return 1;
        }
+       mask = client_clean_name(ctx, mask);
+       if (mask == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, mask, &targetcli, &targetname);
@@ -3318,6 +3431,10 @@ static int cmd_link(void)
        if (!oldname) {
                return 1;
        }
+       oldname = client_clean_name(ctx, oldname);
+       if (oldname == NULL) {
+               return 1;
+       }
        newname = talloc_asprintf(ctx,
                        "%s%s",
                        client_get_cur_dir(),
@@ -3325,6 +3442,10 @@ static int cmd_link(void)
        if (!newname) {
                return 1;
        }
+       newname = client_clean_name(ctx, newname);
+       if (newname == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, oldname, &targetcli, &targetname);
@@ -3372,6 +3493,10 @@ static int cmd_readlink(void)
        if (!name) {
                return 1;
        }
+       name = client_clean_name(ctx, name);
+       if (name == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, name, &targetcli, &targetname);
@@ -3405,7 +3530,7 @@ static int cmd_readlink(void)
 static int cmd_symlink(void)
 {
        TALLOC_CTX *ctx = talloc_tos();
-       char *oldname = NULL;
+       char *link_target = NULL;
        char *newname = NULL;
        char *buf = NULL;
        char *buf2 = NULL;
@@ -3414,11 +3539,11 @@ static int cmd_symlink(void)
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
            !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
-               d_printf("symlink <oldname> <newname>\n");
+               d_printf("symlink <link_target> <newname>\n");
                return 1;
        }
        /* Oldname (link target) must be an untouched blob. */
-       oldname = buf;
+       link_target = buf;
 
        if (SERVER_HAS_UNIX_CIFS(cli)) {
                newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
@@ -3426,24 +3551,29 @@ static int cmd_symlink(void)
                if (!newname) {
                        return 1;
                }
+               newname = client_clean_name(ctx, newname);
+               if (newname == NULL) {
+                       return 1;
+               }
                /* New name must be present in share namespace. */
                status = cli_resolve_path(ctx, "",
                                popt_get_cmdline_auth_info(), cli, newname,
                                &newcli, &newname);
                if (!NT_STATUS_IS_OK(status)) {
-                       d_printf("link %s: %s\n", oldname, nt_errstr(status));
+                       d_printf("link %s: %s\n", newname,
+                               nt_errstr(status));
                        return 1;
                }
-               status = cli_posix_symlink(newcli, oldname, newname);
+               status = cli_posix_symlink(newcli, link_target, newname);
        } else {
                status = cli_symlink(
-                       cli, oldname, buf2,
+                       cli, link_target, buf2,
                        buf2[0] == '\\' ? 0 : SYMLINK_FLAG_RELATIVE);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s symlinking files (%s -> %s)\n",
-                        nt_errstr(status), oldname, newname);
+                        nt_errstr(status), newname, link_target);
                return 1;
        }
 
@@ -3477,6 +3607,10 @@ static int cmd_chmod(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        mode = (mode_t)strtol(buf, NULL, 8);
 
@@ -3636,6 +3770,10 @@ static int cmd_getfacl(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetname);
@@ -3804,6 +3942,10 @@ static int cmd_geteas(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetname);
@@ -3861,6 +4003,10 @@ static int cmd_setea(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetname);
@@ -3907,6 +4053,10 @@ static int cmd_stat(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetname);
@@ -4016,6 +4166,10 @@ static int cmd_chown(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -4066,6 +4220,10 @@ static int cmd_rename(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        dest = talloc_asprintf(ctx,
                        "%s%s",
@@ -4074,6 +4232,10 @@ static int cmd_rename(void)
        if (!dest) {
                return 1;
        }
+       dest = client_clean_name(ctx, dest);
+       if (dest == NULL) {
+               return 1;
+       }
 
        if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
            strcsequal(buf, "-f")) {
@@ -4159,6 +4321,10 @@ static int cmd_scopy(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        dest = talloc_asprintf(ctx,
                        "%s%s",
@@ -4167,6 +4333,10 @@ static int cmd_scopy(void)
        if (!dest) {
                return 1;
        }
+       dest = client_clean_name(ctx, dest);
+       if (dest == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                        cli, src, &targetcli, &targetsrc);
@@ -4289,6 +4459,10 @@ static int cmd_hardlink(void)
        if (!src) {
                return 1;
        }
+       src = client_clean_name(ctx, src);
+       if (src == NULL) {
+               return 1;
+       }
 
        dest = talloc_asprintf(ctx,
                        "%s%s",
@@ -4297,6 +4471,10 @@ static int cmd_hardlink(void)
        if (!dest) {
                return 1;
        }
+       dest = client_clean_name(ctx, dest);
+       if (dest == NULL) {
+               return 1;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                                cli, src, &targetcli, &targetname);
@@ -4376,6 +4554,10 @@ static int cmd_notify(void)
        if (name == NULL) {
                goto fail;
        }
+       name = client_clean_name(talloc_tos(), name);
+       if (name == NULL) {
+               return 1;
+       }
        status = cli_ntcreate(
                cli, name, 0, FILE_READ_DATA, 0,
                FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
@@ -4386,12 +4568,17 @@ static int cmd_notify(void)
        }
 
        while (1) {
-               uint32_t i, num_changes;
-               struct notify_change *changes;
+               uint32_t i;
+               uint32_t num_changes = 0;
+               struct notify_change *changes = NULL;
 
                status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
                                    true,
                                    talloc_tos(), &num_changes, &changes);
+               if (NT_STATUS_EQUAL(status, STATUS_NOTIFY_ENUM_DIR)) {
+                       printf("NOTIFY_ENUM_DIR\n");
+                       status = NT_STATUS_OK;
+               }
                if (!NT_STATUS_IS_OK(status)) {
                        d_printf("notify returned %s\n",
                                 nt_errstr(status));
@@ -4550,7 +4737,7 @@ static int cmd_reget(void)
        if (!remote_name) {
                return 1;
        }
-       remote_name = clean_name(ctx,remote_name);
+       remote_name = client_clean_name(ctx,remote_name);
        if (!remote_name) {
                return 1;
        }
@@ -4602,7 +4789,7 @@ static int cmd_reput(void)
                return 1;
        }
 
-       remote_name = clean_name(ctx, remote_name);
+       remote_name = client_clean_name(ctx, remote_name);
        if (!remote_name) {
                return 1;
        }
@@ -5038,6 +5225,11 @@ static int cmd_utimes(void)
                err = 1;
                goto out;
        }
+       fname = client_clean_name(ctx, fname);
+       if (fname == NULL) {
+               err = 1;
+               goto out;
+       }
 
        while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
                time_count < 4) {
@@ -5161,6 +5353,11 @@ int cmd_setmode(void)
                err = 1;
                goto out;
        }
+       fname = client_clean_name(ctx, fname);
+       if (fname == NULL) {
+               err = 1;
+               goto out;
+       }
 
        while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
                const char *s = buf;
@@ -5422,9 +5619,9 @@ static struct {
 
 static int process_tok(char *tok)
 {
-       int i = 0, matches = 0;
-       int cmd=0;
-       int tok_len = strlen(tok);
+       size_t i = 0, matches = 0;
+       size_t cmd=0;
+       size_t tok_len = strlen(tok);
 
        while (commands[i].fn != NULL) {
                if (strequal(commands[i].name,tok)) {
@@ -5671,6 +5868,10 @@ static char **remote_completion(const char *text, int len)
        if (!dirmask) {
                goto cleanup;
        }
+       dirmask = client_clean_name(ctx, dirmask);
+       if (dirmask == NULL) {
+               goto cleanup;
+       }
 
        status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
                                cli, dirmask, &targetcli, &targetpath);
@@ -5765,7 +5966,7 @@ static char **completion_fn(const char *text, int start, int end)
                        return NULL;
        } else {
                char **matches;
-               int i, len, samelen = 0, count=1;
+               size_t i, len, samelen = 0, count=1;
 
                matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
                if (!matches) {
@@ -5839,7 +6040,13 @@ static void readline_callback(void)
        /* Ping the server to keep the connection alive using SMBecho. */
        memset(garbage, 0xf0, sizeof(garbage));
        status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
-       if (NT_STATUS_IS_OK(status)) {
+       if (NT_STATUS_IS_OK(status) ||
+                       NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
+               /*
+                * Even if server returns NT_STATUS_INVALID_PARAMETER
+                * it still responded.
+                * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
+                */
                return;
        }