s3: libsmb: In struct file_info rename mode -> attr.
[samba.git] / source3 / client / client.c
index 5897cecbdf3143a3fbf1595d3d23ebe99d3a3b71..362fd2cc08ba6ea8403cccd185256f5cf2e4c8e3 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "includes.h"
 #include "system/filesys.h"
-#include "popt_common.h"
+#include "popt_common_cmdline.h"
 #include "rpc_client/cli_pipe.h"
 #include "client/client_proto.h"
 #include "client/clitar_proto.h"
@@ -39,6 +39,7 @@
 #include "libsmb/nmblib.h"
 #include "include/ntioctl.h"
 #include "../libcli/smb/smbXcli_base.h"
+#include "lib/util/time_basic.h"
 
 #ifndef REGISTER
 #define REGISTER 0
@@ -52,6 +53,7 @@ static int port = 0;
 static char *service;
 static char *desthost;
 static bool grepable = false;
+static bool quiet = false;
 static char *cmdstr = NULL;
 const char *cmd_ptr = NULL;
 
@@ -64,8 +66,6 @@ static int max_protocol = -1;
 static int process_tok(char *tok);
 static int cmd_help(void);
 
-#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
-
 /* value for unused fid field in trans2 secondary request */
 #define FID_UNUSED (0xFFFF)
 
@@ -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;
 }
 
 /****************************************************************************
@@ -345,6 +349,37 @@ static void normalize_name(char *newdir)
        }
 }
 
+/****************************************************************************
+ Local name cleanup before sending to server. SMB1 allows relative pathnames,
+ but SMB2 does not, so we need to resolve them locally.
+****************************************************************************/
+
+char *client_clean_name(TALLOC_CTX *ctx, const char *name)
+{
+       char *newname = NULL;
+       if (name == NULL) {
+               return NULL;
+       }
+
+       /* First ensure any path separators are correct. */
+       newname = talloc_strdup(ctx, name);
+       if (newname == NULL) {
+               return NULL;
+       }
+       normalize_name(newname);
+
+       /* Now remove any relative (..) path components. */
+       if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+               newname = unix_clean_name(ctx, newname);
+       } else {
+               newname = clean_name(ctx, newname);
+       }
+       if (newname == NULL) {
+               return NULL;
+       }
+       return newname;
+}
+
 /****************************************************************************
  Change directory - inner section.
 ****************************************************************************/
@@ -399,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(),
@@ -443,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;
@@ -502,7 +537,7 @@ static bool do_this_one(struct file_info *finfo)
                return false;
        }
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                return true;
        }
 
@@ -517,7 +552,7 @@ static bool do_this_one(struct file_info *finfo)
                return false;
        }
 
-       if ((archive_level==1 || archive_level==2) && !(finfo->mode & FILE_ATTRIBUTE_ARCHIVE)) {
+       if ((archive_level==1 || archive_level==2) && !(finfo->attr & FILE_ATTRIBUTE_ARCHIVE)) {
                DEBUG(3,("archive %s failed\n", finfo->name));
                return false;
        }
@@ -544,7 +579,7 @@ static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *fin
        if (!showacls) {
                d_printf("  %-30s%7.7s %8.0f  %s",
                         finfo->name,
-                        attrib_string(talloc_tos(), finfo->mode),
+                        attrib_string(talloc_tos(), finfo->attr),
                        (double)finfo->size,
                        time_to_asc(t));
                dir_total += finfo->size;
@@ -566,13 +601,22 @@ static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *fin
                }
                /* print file meta date header */
                d_printf( "FILENAME:%s\n", finfo->name);
-               d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->mode));
+               d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->attr));
                d_printf( "SIZE:%.0f\n", (double)finfo->size);
                d_printf( "MTIME:%s", time_to_asc(t));
-               status = cli_ntcreate(cli_state, afname, 0,
-                                     CREATE_ACCESS_READ, 0,
-                                     FILE_SHARE_READ|FILE_SHARE_WRITE,
-                                     FILE_OPEN, 0x0, 0x0, &fnum, NULL);
+               status = cli_ntcreate(
+                       cli_state,            /* cli */
+                       afname,               /* fname */
+                       0,                    /* CreatFlags */
+                       READ_CONTROL_ACCESS,  /* DesiredAccess */
+                       0,                    /* FileAttributes */
+                       FILE_SHARE_READ|
+                       FILE_SHARE_WRITE,     /* ShareAccess */
+                       FILE_OPEN,            /* CreateDisposition */
+                       0x0,                  /* CreateOptions */
+                       0x0,                  /* SecurityFlags */
+                       &fnum,                /* pfid */
+                       NULL);                /* cr */
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
                                   afname, nt_errstr(status)));
@@ -749,7 +793,7 @@ static NTSTATUS do_list_helper(const char *mntpoint, struct file_info *f,
                *dir_end = '\0';
        }
 
-       if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
                if (do_list_dirs && do_this_one(f)) {
                        status = do_list_fn(cli_state, f, dir);
                        if (!NT_STATUS_IS_OK(status)) {
@@ -953,6 +997,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());
@@ -1005,6 +1054,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)) {
@@ -1048,7 +1105,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;
@@ -1108,6 +1168,7 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
                                start = lseek(handle, 0, SEEK_END);
                                if (start == -1) {
                                        d_printf("Error seeking local file\n");
+                                       close(handle);
                                        return 1;
                                }
                        }
@@ -1129,6 +1190,9 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
                                      NULL);
                if(!NT_STATUS_IS_OK(status)) {
                        d_printf("getattrib: %s\n", nt_errstr(status));
+                       if (newhandle) {
+                               close(handle);
+                       }
                        return 1;
                }
        }
@@ -1141,6 +1205,9 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
        if (!NT_STATUS_IS_OK(status)) {
                d_fprintf(stderr, "parallel_read returned %s\n",
                          nt_errstr(status));
+               if (newhandle) {
+                       close(handle);
+               }
                cli_close(targetcli, fnum);
                return 1;
        }
@@ -1201,7 +1268,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;
        }
@@ -1241,7 +1308,7 @@ static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                if (asprintf(&quest,
                         "Get directory %s? ",finfo->name) < 0) {
                        return NT_STATUS_NO_MEMORY;
@@ -1259,7 +1326,7 @@ static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
        }
        SAFE_FREE(quest);
 
-       if (!(finfo->mode & FILE_ATTRIBUTE_DIRECTORY)) {
+       if (!(finfo->attr & FILE_ATTRIBUTE_DIRECTORY)) {
                rname = talloc_asprintf(ctx,
                                "%s%s",
                                client_get_cur_dir(),
@@ -1267,6 +1334,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;
@@ -1286,6 +1357,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,'\\','/');
@@ -1316,6 +1391,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
@@ -1385,7 +1464,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;
        }
@@ -1443,6 +1522,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;
@@ -1461,6 +1544,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;
@@ -1557,6 +1644,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;
@@ -1628,6 +1719,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;
 }
@@ -1725,16 +1820,16 @@ static int do_allinfo(const char *name)
                return false;
        }
 
-       tmp = unix_timespec_to_nt_time(b_time);
+       tmp = full_timespec_to_nt_time(&b_time);
        d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
 
-       tmp = unix_timespec_to_nt_time(a_time);
+       tmp = full_timespec_to_nt_time(&a_time);
        d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
 
-       tmp = unix_timespec_to_nt_time(m_time);
+       tmp = full_timespec_to_nt_time(&m_time);
        d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
 
-       tmp = unix_timespec_to_nt_time(c_time);
+       tmp = full_timespec_to_nt_time(&c_time);
        d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
 
        d_printf("attributes: %s (%x)\n", attr_str(talloc_tos(), mode), mode);
@@ -1858,7 +1953,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;
@@ -2021,7 +2119,7 @@ static int cmd_put(void)
                return 1;
        }
 
-       rname = clean_name(ctx, rname);
+       rname = client_clean_name(ctx, rname);
        if (!rname) {
                return 1;
        }
@@ -2230,6 +2328,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..."));
@@ -2260,6 +2371,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);
@@ -2388,7 +2511,7 @@ static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                TALLOC_FREE(mask);
                return NT_STATUS_OK;
        }
@@ -2430,6 +2553,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)) {
@@ -2514,7 +2641,7 @@ static NTSTATUS do_deltree_list(struct cli_state *cli_state,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
                dt->isdir = true;
        }
 
@@ -2546,6 +2673,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;
 
@@ -2647,6 +2778,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);
@@ -2688,6 +2823,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)) {
@@ -2803,6 +2943,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");
@@ -2858,6 +3002,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");
@@ -2902,6 +3050,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);
@@ -2941,6 +3093,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);
@@ -3211,9 +3367,10 @@ static int cmd_posix_whoami(void)
        }
        d_printf("NUM_SIDS:%" PRIu32 "\n", num_sids);
        for (i = 0; i < num_sids; i++) {
-               char *sid_str = dom_sid_string(ctx, &sids[i]);
-               d_printf("SIDS[%" PRIu32 "]:%s\n", i, sid_str);
-               TALLOC_FREE(sid_str);
+               struct dom_sid_buf buf;
+               d_printf("SIDS[%" PRIu32 "]:%s\n",
+                        i,
+                        dom_sid_str_buf(&sids[i], &buf));
        }
        return 0;
 }
@@ -3243,6 +3400,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);
@@ -3287,6 +3448,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(),
@@ -3294,6 +3459,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);
@@ -3326,7 +3495,7 @@ static int cmd_readlink(void)
        char *name= NULL;
        char *buf = NULL;
        char *targetname = NULL;
-       char linkname[PATH_MAX+1];
+       char *linkname = NULL;
        struct cli_state *targetcli;
         NTSTATUS status;
 
@@ -3341,6 +3510,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);
@@ -3354,7 +3527,7 @@ static int cmd_readlink(void)
                return 1;
        }
 
-       status = cli_posix_readlink(targetcli, name, linkname, PATH_MAX+1);
+       status = cli_posix_readlink(targetcli, name, talloc_tos(), &linkname);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s readlink on file %s\n",
                         nt_errstr(status), name);
@@ -3363,6 +3536,8 @@ static int cmd_readlink(void)
 
        d_printf("%s -> %s\n", name, linkname);
 
+       TALLOC_FREE(linkname);
+
        return 0;
 }
 
@@ -3374,7 +3549,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;
@@ -3383,11 +3558,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(),
@@ -3395,24 +3570,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;
        }
 
@@ -3446,6 +3626,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);
 
@@ -3605,6 +3789,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);
@@ -3633,7 +3821,7 @@ static int cmd_getfacl(void)
        }
 
        status = cli_posix_stat(targetcli, targetname, &sbuf);
-       if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s getfacl doing a stat on file %s\n",
                         nt_errstr(status), src);
                return 1;
@@ -3773,6 +3961,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);
@@ -3830,6 +4022,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);
@@ -3876,6 +4072,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);
@@ -3985,6 +4185,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)) {
@@ -4035,6 +4239,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",
@@ -4043,6 +4251,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")) {
@@ -4128,6 +4340,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",
@@ -4136,6 +4352,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);
@@ -4258,6 +4478,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",
@@ -4266,6 +4490,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);
@@ -4274,7 +4502,7 @@ static int cmd_hardlink(void)
                return 1;
        }
 
-       status = cli_nt_hardlink(targetcli, targetname, dest);
+       status = cli_hardlink(targetcli, targetname, dest);
        if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s doing an NT hard link of files\n",
                         nt_errstr(status));
@@ -4345,6 +4573,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,
@@ -4355,12 +4587,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));
@@ -4519,7 +4756,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;
        }
@@ -4571,7 +4808,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;
        }
@@ -4675,6 +4912,7 @@ static bool browse_host_rpc(bool sort)
 static bool browse_host(bool sort)
 {
        int ret;
+
        if (!grepable) {
                d_printf("\n\tSharename       Type      Comment\n");
                d_printf("\t---------       ----      -------\n");
@@ -4684,7 +4922,12 @@ static bool browse_host(bool sort)
                return true;
        }
 
-       if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1) {
+       if (smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1) {
+               return false;
+       }
+
+       ret = cli_RNetShareEnum(cli, browse_fn, NULL);
+       if (ret == -1) {
                NTSTATUS status = cli_nt_error(cli);
                d_printf("Error returning browse list: %s\n",
                         nt_errstr(status));
@@ -4940,6 +5183,117 @@ static int cmd_show_connect( void )
        return 0;
 }
 
+/**
+ * cmd_utimes - interactive command to set the four times
+ *
+ * Read a filename and four times from the client command line and update
+ * the file times. A value of -1 for a time means don't change.
+ */
+static int cmd_utimes(void)
+{
+       char *buf;
+       char *fname = NULL;
+       struct timespec times[4] = {{0}};
+       struct timeval_buf tbuf[4];
+       int time_count = 0;
+       int err = 0;
+       bool ok;
+       TALLOC_CTX *ctx = talloc_new(NULL);
+       NTSTATUS status;
+
+       if (ctx == NULL) {
+               return 1;
+       }
+
+       ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
+       if (!ok) {
+               d_printf("utimes <filename> <create-time> <access-time> "
+                        "<write-time> <change-time>\n");
+               d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
+                       "or -1 for no change\n");
+               err = 1;
+               goto out;
+       }
+
+       fname = talloc_asprintf(ctx,
+                               "%s%s",
+                               client_get_cur_dir(),
+                               buf);
+       if (fname == NULL) {
+               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) {
+               const char *s = buf;
+               struct tm tm = {0,};
+               time_t t;
+               char *ret;
+
+               if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
+                       times[time_count] = make_omit_timespec();
+                       time_count++;
+                       continue;
+               }
+
+               ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
+
+               if (ret == NULL) {
+                       ret = strptime(s, "%Y:%m:%d-%H:%M:%S", &tm);
+               }
+
+               /* We could not match all the chars, so print error */
+               if (ret == NULL || *ret != 0) {
+                       d_printf("Invalid date format: %s\n", s);
+                       d_printf("utimes <filename> <create-time> "
+                               "<access-time> <write-time> <change-time>\n");
+                       d_printf("Dates should be in [YY]YY:MM:DD-HH:MM:SS "
+                                "format or -1 for no change\n");
+                       err = 1;
+                       goto out;
+               }
+
+               /* Convert tm to a time_t */
+               t = mktime(&tm);
+               times[time_count] = (struct timespec){.tv_sec = t};
+               time_count++;
+       }
+
+       if (time_count < 4) {
+               d_printf("Insufficient dates: %d\n", time_count);
+               d_printf("utimes <filename> <create-time> <access-time> "
+                       "<write-time> <change-time>\n");
+               d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
+                       "or -1 for no change\n");
+               err = 1;
+               goto out;
+       }
+
+       DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
+                  timespec_string_buf(&times[0], false, &tbuf[0]),
+                  timespec_string_buf(&times[1], false, &tbuf[1]),
+                  timespec_string_buf(&times[2], false, &tbuf[2]),
+                  timespec_string_buf(&times[3], false, &tbuf[3])));
+
+       status = cli_setpathinfo_ext(
+               cli, fname, times[0], times[1], times[2], times[3], -1);
+       if (!NT_STATUS_IS_OK(status)) {
+               d_printf("cli_setpathinfo_ext failed: %s\n",
+                        nt_errstr(status));
+               err = 1;
+               goto out;
+       }
+out:
+       talloc_free(ctx);
+       return err;
+}
+
 /**
  * set_remote_attr - set DOS attributes of a remote file
  * @filename: path to the file name
@@ -4983,7 +5337,6 @@ int set_remote_attr(const char *filename, uint16_t new_attr, int mode)
  */
 int cmd_setmode(void)
 {
-       const extern char *cmd_ptr;
        char *buf;
        char *fname = NULL;
        uint16_t attr[2] = {0};
@@ -5010,6 +5363,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;
@@ -5170,8 +5528,8 @@ static struct {
 } commands[] = {
   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
   {"allinfo",cmd_allinfo,"<file> show all available info",
-   {COMPL_NONE,COMPL_NONE}},
-  {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
+   {COMPL_REMOTE,COMPL_NONE}},
+  {"altname",cmd_altname,"<file> show alt name",{COMPL_REMOTE,COMPL_NONE}},
   {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
   {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}},
   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
@@ -5216,7 +5574,7 @@ static struct {
   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
-  {"posix_whoami",cmd_posix_whoami,"retun logged on user information "
+  {"posix_whoami",cmd_posix_whoami,"return logged on user information "
                        "using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
@@ -5240,7 +5598,7 @@ static struct {
   {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
   {"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
-  {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
+  {"tar",cmd_tar,"tar <c|x>[IXFvbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
   {"timeout",cmd_timeout,"timeout <number> - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}},
   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
@@ -5254,6 +5612,8 @@ static struct {
   {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
   {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
   {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
+  {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
+       "<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
   {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
   {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
 
@@ -5269,9 +5629,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)) {
@@ -5338,10 +5698,12 @@ static int process_command_string(const char *cmd_in)
                NTSTATUS status;
 
                status = cli_cm_open(talloc_tos(), NULL,
-                                    have_ip ? dest_ss_str : desthost,
+                                    desthost,
                                     service, popt_get_cmdline_auth_info(),
                                     smb_encrypt,
-                                    max_protocol, port, name_type,
+                                    max_protocol,
+                                    have_ip ? &dest_ss : NULL, port,
+                                    name_type,
                                     &cli);
                if (!NT_STATUS_IS_OK(status)) {
                        return 1;
@@ -5409,7 +5771,7 @@ static NTSTATUS completion_remote_filter(const char *mnt,
                return NT_STATUS_OK;
        }
 
-       if ((info->dirmask[0] == 0) && !(f->mode & FILE_ATTRIBUTE_DIRECTORY))
+       if ((info->dirmask[0] == 0) && !(f->attr & FILE_ATTRIBUTE_DIRECTORY))
                info->matches[info->count] = SMB_STRDUP(f->name);
        else {
                TALLOC_CTX *ctx = talloc_stackframe();
@@ -5425,7 +5787,7 @@ static NTSTATUS completion_remote_filter(const char *mnt,
                        TALLOC_FREE(ctx);
                        return NT_STATUS_NO_MEMORY;
                }
-               if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
+               if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
                        tmp = talloc_asprintf_append(tmp, "%s",
                                                     CLI_DIRSEP_STR);
                }
@@ -5439,7 +5801,7 @@ static NTSTATUS completion_remote_filter(const char *mnt,
        if (info->matches[info->count] == NULL) {
                return NT_STATUS_OK;
        }
-       if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
+       if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
                smb_readline_ca_char(0);
        }
        if (info->count == 1) {
@@ -5518,6 +5880,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);
@@ -5612,7 +5978,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) {
@@ -5686,7 +6052,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;
        }
 
@@ -5706,7 +6078,9 @@ static int process_stdin(void)
 {
        int rc = 0;
 
-       d_printf("Try \"help\" to get a list of possible commands.\n");
+       if (!quiet) {
+               d_printf("Try \"help\" to get a list of possible commands.\n");
+       }
 
        while (!finished) {
                TALLOC_CTX *frame = talloc_stackframe();
@@ -5769,9 +6143,10 @@ static int process(const char *base_directory)
        NTSTATUS status;
 
        status = cli_cm_open(talloc_tos(), NULL,
-                            have_ip ? dest_ss_str : desthost,
+                            desthost,
                             service, popt_get_cmdline_auth_info(),
-                            smb_encrypt, max_protocol, port,
+                            smb_encrypt, max_protocol,
+                            have_ip ? &dest_ss : NULL, port,
                             name_type, &cli);
        if (!NT_STATUS_IS_OK(status)) {
                return 1;
@@ -5806,9 +6181,10 @@ static int do_host_query(const char *query_host)
        NTSTATUS status;
 
        status = cli_cm_open(talloc_tos(), NULL,
-                            have_ip ? dest_ss_str : query_host,
+                            query_host,
                             "IPC$", popt_get_cmdline_auth_info(),
-                            smb_encrypt, max_protocol, port,
+                            smb_encrypt, max_protocol,
+                            have_ip ? &dest_ss : NULL, port,
                             name_type, &cli);
        if (!NT_STATUS_IS_OK(status)) {
                return 1;
@@ -5829,6 +6205,11 @@ static int do_host_query(const char *query_host)
                }
        }
 
+       if (lp_client_min_protocol() > PROTOCOL_NT1) {
+               d_printf("SMB1 disabled -- no workgroup available\n");
+               goto out;
+       }
+
        if (lp_disable_netbios()) {
                d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
                goto out;
@@ -5847,12 +6228,13 @@ static int do_host_query(const char *query_host)
                cli_shutdown(cli);
                d_printf("Reconnecting with SMB1 for workgroup listing.\n");
                status = cli_cm_open(talloc_tos(), NULL,
-                                    have_ip ? dest_ss_str : query_host,
+                                    query_host,
                                     "IPC$", popt_get_cmdline_auth_info(),
                                     smb_encrypt, max_proto,
-                                    NBT_SMB_PORT, name_type, &cli);
+                                    have_ip ? &dest_ss : NULL, NBT_SMB_PORT,
+                                    name_type, &cli);
                if (!NT_STATUS_IS_OK(status)) {
-                       d_printf("Failed to connect with SMB1 "
+                       d_printf("Unable to connect with SMB1 "
                                 "-- no workgroup available\n");
                        return 0;
                }
@@ -5880,10 +6262,11 @@ static int do_tar_op(const char *base_directory)
                NTSTATUS status;
 
                status = cli_cm_open(talloc_tos(), NULL,
-                                    have_ip ? dest_ss_str : desthost,
+                                    desthost,
                                     service, popt_get_cmdline_auth_info(),
                                     smb_encrypt, max_protocol,
-                                    port, name_type, &cli);
+                                    have_ip ? &dest_ss : NULL, port,
+                                    name_type, &cli);
                if (!NT_STATUS_IS_OK(status)) {
             ret = 1;
             goto out;
@@ -5958,20 +6341,136 @@ int main(int argc,char *argv[])
        struct poptOption long_options[] = {
                POPT_AUTOHELP
 
-               { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
-               { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
-               { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
-               { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
-               { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
-               { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
-               { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
-               { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
-               { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" },
-               { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
-               { "timeout", 't', POPT_ARG_INT, &io_timeout, 'b', "Changes the per-operation timeout", "SECONDS" },
-               { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
-               { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
-                { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" },
+               {
+                       .longName   = "name-resolve",
+                       .shortName  = 'R',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = &new_name_resolve_order,
+                       .val        = 'R',
+                       .descrip    = "Use these name resolution services only",
+                       .argDescrip = "NAME-RESOLVE-ORDER",
+               },
+               {
+                       .longName   = "message",
+                       .shortName  = 'M',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'M',
+                       .descrip    = "Send message",
+                       .argDescrip = "HOST",
+               },
+               {
+                       .longName   = "ip-address",
+                       .shortName  = 'I',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'I',
+                       .descrip    = "Use this IP to connect to",
+                       .argDescrip = "IP",
+               },
+               {
+                       .longName   = "stderr",
+                       .shortName  = 'E',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'E',
+                       .descrip    = "Write messages to stderr instead of stdout",
+               },
+               {
+                       .longName   = "list",
+                       .shortName  = 'L',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'L',
+                       .descrip    = "Get a list of shares available on a host",
+                       .argDescrip = "HOST",
+               },
+               {
+                       .longName   = "max-protocol",
+                       .shortName  = 'm',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'm',
+                       .descrip    = "Set the max protocol level",
+                       .argDescrip = "LEVEL",
+               },
+               {
+                       .longName   = "tar",
+                       .shortName  = 'T',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'T',
+                       .descrip    = "Command line tar",
+                       .argDescrip = "<c|x>IXFvgbNan",
+               },
+               {
+                       .longName   = "directory",
+                       .shortName  = 'D',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = NULL,
+                       .val        = 'D',
+                       .descrip    = "Start from directory",
+                       .argDescrip = "DIR",
+               },
+               {
+                       .longName   = "command",
+                       .shortName  = 'c',
+                       .argInfo    = POPT_ARG_STRING,
+                       .arg        = &cmdstr,
+                       .val        = 'c',
+                       .descrip    = "Execute semicolon separated commands",
+               },
+               {
+                       .longName   = "send-buffer",
+                       .shortName  = 'b',
+                       .argInfo    = POPT_ARG_INT,
+                       .arg        = &io_bufsize,
+                       .val        = 'b',
+                       .descrip    = "Changes the transmit/send buffer",
+                       .argDescrip = "BYTES",
+               },
+               {
+                       .longName   = "timeout",
+                       .shortName  = 't',
+                       .argInfo    = POPT_ARG_INT,
+                       .arg        = &io_timeout,
+                       .val        = 'b',
+                       .descrip    = "Changes the per-operation timeout",
+                       .argDescrip = "SECONDS",
+               },
+               {
+                       .longName   = "port",
+                       .shortName  = 'p',
+                       .argInfo    = POPT_ARG_INT,
+                       .arg        = &port,
+                       .val        = 'p',
+                       .descrip    = "Port to connect to",
+                       .argDescrip = "PORT",
+               },
+               {
+                       .longName   = "grepable",
+                       .shortName  = 'g',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'g',
+                       .descrip    = "Produce grepable output",
+               },
+               {
+                       .longName   = "quiet",
+                       .shortName  = 'q',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'q',
+                       .descrip    = "Suppress help message",
+               },
+               {
+                       .longName   = "browse",
+                       .shortName  = 'B',
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = NULL,
+                       .val        = 'B',
+                       .descrip    = "Browse SMB servers using DNS",
+               },
                POPT_COMMON_SAMBA
                POPT_COMMON_CONNECTION
                POPT_COMMON_CREDENTIALS
@@ -5998,7 +6497,10 @@ int main(int argc,char *argv[])
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
 
-               /* if the tar option has been called previouslt, now we need to eat out the leftovers */
+               /*
+                * if the tar option has been called previously, now
+                * we need to eat out the leftovers
+                */
                /* I see no other way to keep things sane --SSS */
                if (tar_opt == true) {
                        while (poptPeekArg(pc)) {
@@ -6093,6 +6595,9 @@ int main(int argc,char *argv[])
                case 'g':
                        grepable=true;
                        break;
+               case 'q':
+                       quiet=true;
+                       break;
                case 'e':
                        smb_encrypt=true;
                        break;