2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Simo Sorce 2001-2002
6 Copyright (C) Jelmer Vernooij 2003
7 Copyright (C) Gerald (Jerry) Carter 2004
8 Copyright (C) Jeremy Allison 1994-2007
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "system/filesys.h"
26 #include "popt_common_cmdline.h"
27 #include "rpc_client/cli_pipe.h"
28 #include "client/client_proto.h"
29 #include "client/clitar_proto.h"
30 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
31 #include "../lib/util/select.h"
32 #include "system/readline.h"
33 #include "../libcli/smbreadline/smbreadline.h"
34 #include "../libcli/security/security.h"
35 #include "system/select.h"
36 #include "libsmb/libsmb.h"
37 #include "libsmb/clirap.h"
39 #include "libsmb/nmblib.h"
40 #include "include/ntioctl.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/util/time_basic.h"
48 extern int do_smb_browse(void); /* mDNS browsing */
50 extern bool override_logfile;
54 static char *desthost;
55 static bool grepable = false;
56 static bool quiet = false;
57 static char *cmdstr = NULL;
58 const char *cmd_ptr = NULL;
60 static int io_bufsize = 0; /* we use the default size */
61 static int io_timeout = (CLIENT_TIMEOUT/1000); /* Per operation timeout (in seconds). */
63 static int name_type = 0x20;
64 static int max_protocol = -1;
66 static int process_tok(char *tok);
67 static int cmd_help(void);
69 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
71 /* value for unused fid field in trans2 secondary request */
72 #define FID_UNUSED (0xFFFF)
74 time_t newer_than = 0;
75 static int archive_level = 0;
77 static bool translation = false;
80 static bool prompt = true;
82 static bool recurse = false;
83 static bool showacls = false;
84 bool lowercase = false;
85 static bool backup_intent = false;
87 static struct sockaddr_storage dest_ss;
88 static char dest_ss_str[INET6_ADDRSTRLEN];
90 #define SEPARATORS " \t\n\r"
92 static bool abort_mget = true;
95 uint64_t get_total_size = 0;
96 unsigned int get_total_time_ms = 0;
97 static uint64_t put_total_size = 0;
98 static unsigned int put_total_time_ms = 0;
101 static double dir_total;
103 /* encrypted state. */
104 static bool smb_encrypt;
106 /* root cli_state connection */
108 struct cli_state *cli;
110 static char CLI_DIRSEP_CHAR = '\\';
111 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
113 /* Accessor functions for directory paths. */
114 static char *fileselection;
115 static const char *client_get_fileselection(void)
118 return fileselection;
123 static const char *client_set_fileselection(const char *new_fs)
125 SAFE_FREE(fileselection);
127 fileselection = SMB_STRDUP(new_fs);
129 return client_get_fileselection();
133 static const char *client_get_cwd(void)
138 return CLI_DIRSEP_STR;
141 static const char *client_set_cwd(const char *new_cwd)
145 cwd = SMB_STRDUP(new_cwd);
147 return client_get_cwd();
150 static char *cur_dir;
151 const char *client_get_cur_dir(void)
156 return CLI_DIRSEP_STR;
159 const char *client_set_cur_dir(const char *newdir)
163 cur_dir = SMB_STRDUP(newdir);
165 return client_get_cur_dir();
168 /****************************************************************************
169 Put up a yes/no prompt.
170 ****************************************************************************/
172 static bool yesno(const char *p)
177 if (!fgets(ans,sizeof(ans)-1,stdin))
180 if (*ans == 'y' || *ans == 'Y')
186 /****************************************************************************
187 Write to a local file with CR/LF->LF translation if appropriate. Return the
188 number taken from the buffer. This may not equal the number written.
189 ****************************************************************************/
191 static ssize_t writefile(int f, char *b, size_t n)
205 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
208 if (write(f, b, 1) != 1) {
218 /****************************************************************************
219 Read from a file with LF->CR/LF translation if appropriate. Return the
220 number read. read approx n bytes.
221 ****************************************************************************/
223 static int readfile(uint8_t *b, int n, FILE *f)
229 return fread(b,1,n,f);
232 while (i < (n - 1)) {
233 if ((c = getc(f)) == EOF) {
237 if (c == '\n') { /* change all LFs to CR/LF */
252 static size_t push_source(uint8_t *buf, size_t n, void *priv)
254 struct push_state *state = (struct push_state *)priv;
257 if (feof(state->f)) {
261 result = readfile(buf, n, state->f);
262 state->nread += result;
266 /****************************************************************************
268 ****************************************************************************/
270 static void send_message(const char *username)
276 d_printf("Type your message, ending it with a Control-D\n");
279 while (i<sizeof(buf)-2) {
280 int c = fgetc(stdin);
291 status = cli_message(cli, desthost, username, buf);
292 if (!NT_STATUS_IS_OK(status)) {
293 d_fprintf(stderr, "cli_message returned %s\n",
298 /****************************************************************************
299 Check the space on a device.
300 ****************************************************************************/
302 static int do_dskattr(void)
304 uint64_t total, bsize, avail;
305 struct cli_state *targetcli = NULL;
306 char *targetpath = NULL;
307 TALLOC_CTX *ctx = talloc_tos();
310 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), cli,
311 client_get_cur_dir(), &targetcli,
313 if (!NT_STATUS_IS_OK(status)) {
314 d_printf("Error in dskattr: %s\n", nt_errstr(status));
318 status = cli_disk_size(targetcli, targetpath, &bsize, &total, &avail);
319 if (!NT_STATUS_IS_OK(status)) {
320 d_printf("Error in dskattr: %s\n", nt_errstr(status));
324 d_printf("\n\t\t%" PRIu64
325 " blocks of size %" PRIu64
326 ". %" PRIu64 " blocks available\n",
327 total, bsize, avail);
332 /****************************************************************************
334 ****************************************************************************/
336 static int cmd_pwd(void)
338 d_printf("Current directory is %s",service);
339 d_printf("%s\n",client_get_cur_dir());
343 /****************************************************************************
344 Ensure name has correct directory separators.
345 ****************************************************************************/
347 static void normalize_name(char *newdir)
349 if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
350 string_replace(newdir,'/','\\');
354 /****************************************************************************
355 Local name cleanup before sending to server. SMB1 allows relative pathnames,
356 but SMB2 does not, so we need to resolve them locally.
357 ****************************************************************************/
359 char *client_clean_name(TALLOC_CTX *ctx, const char *name)
361 char *newname = NULL;
366 /* First ensure any path separators are correct. */
367 newname = talloc_strdup(ctx, name);
368 if (newname == NULL) {
371 normalize_name(newname);
373 /* Now remove any relative (..) path components. */
374 if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
375 newname = unix_clean_name(ctx, newname);
377 newname = clean_name(ctx, newname);
379 if (newname == NULL) {
385 /****************************************************************************
386 Change directory - inner section.
387 ****************************************************************************/
389 static int do_cd(const char *new_dir)
392 char *saved_dir = NULL;
394 char *targetpath = NULL;
395 struct cli_state *targetcli = NULL;
396 SMB_STRUCT_STAT sbuf;
399 TALLOC_CTX *ctx = talloc_stackframe();
402 newdir = talloc_strdup(ctx, new_dir);
408 normalize_name(newdir);
410 /* Save the current directory in case the new directory is invalid */
412 saved_dir = talloc_strdup(ctx, client_get_cur_dir());
418 if (*newdir == CLI_DIRSEP_CHAR) {
419 client_set_cur_dir(newdir);
422 new_cd = talloc_asprintf(ctx, "%s%s",
423 client_get_cur_dir(),
430 /* Ensure cur_dir ends in a DIRSEP */
431 if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
432 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
437 client_set_cur_dir(new_cd);
439 new_cd = client_clean_name(ctx, new_cd);
440 client_set_cur_dir(new_cd);
442 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
443 cli, new_cd, &targetcli, &targetpath);
444 if (!NT_STATUS_IS_OK(status)) {
445 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
446 client_set_cur_dir(saved_dir);
450 if (strequal(targetpath,CLI_DIRSEP_STR )) {
455 /* Use a trans2_qpathinfo to test directories for modern servers.
456 Except Win9x doesn't support the qpathinfo_basic() call..... */
458 if (smbXcli_conn_protocol(targetcli->conn) > PROTOCOL_LANMAN2 && !targetcli->win95) {
460 status = cli_qpathinfo_basic(targetcli, targetpath, &sbuf,
462 if (!NT_STATUS_IS_OK(status)) {
463 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
464 client_set_cur_dir(saved_dir);
468 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
469 d_printf("cd %s: not a directory\n", new_cd);
470 client_set_cur_dir(saved_dir);
475 targetpath = talloc_asprintf(ctx,
480 client_set_cur_dir(saved_dir);
483 targetpath = client_clean_name(ctx, targetpath);
485 client_set_cur_dir(saved_dir);
489 status = cli_chkpath(targetcli, targetpath);
490 if (!NT_STATUS_IS_OK(status)) {
491 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
492 client_set_cur_dir(saved_dir);
505 /****************************************************************************
507 ****************************************************************************/
509 static int cmd_cd(void)
514 if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
517 d_printf("Current directory is %s\n",client_get_cur_dir());
523 /****************************************************************************
525 ****************************************************************************/
527 static int cmd_cd_oneup(void)
532 /*******************************************************************
533 Decide if a file should be operated on.
534 ********************************************************************/
536 static bool do_this_one(struct file_info *finfo)
542 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
546 if (*client_get_fileselection() &&
547 !mask_match(finfo->name,client_get_fileselection(),false)) {
548 DEBUG(3,("mask_match %s failed\n", finfo->name));
552 if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
553 DEBUG(3,("newer_than %s failed\n", finfo->name));
557 if ((archive_level==1 || archive_level==2) && !(finfo->mode & FILE_ATTRIBUTE_ARCHIVE)) {
558 DEBUG(3,("archive %s failed\n", finfo->name));
565 /****************************************************************************
566 Display info about a file.
567 ****************************************************************************/
569 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
573 TALLOC_CTX *ctx = talloc_tos();
574 NTSTATUS status = NT_STATUS_OK;
576 if (!do_this_one(finfo)) {
580 t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
582 d_printf(" %-30s%7.7s %8.0f %s",
584 attrib_string(talloc_tos(), finfo->mode),
587 dir_total += finfo->size;
592 /* skip if this is . or .. */
593 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
595 /* create absolute filename for cli_ntcreate() FIXME */
596 afname = talloc_asprintf(ctx,
602 return NT_STATUS_NO_MEMORY;
604 /* print file meta date header */
605 d_printf( "FILENAME:%s\n", finfo->name);
606 d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->mode));
607 d_printf( "SIZE:%.0f\n", (double)finfo->size);
608 d_printf( "MTIME:%s", time_to_asc(t));
609 status = cli_ntcreate(cli_state, afname, 0,
610 CREATE_ACCESS_READ, 0,
611 FILE_SHARE_READ|FILE_SHARE_WRITE,
612 FILE_OPEN, 0x0, 0x0, &fnum, NULL);
613 if (!NT_STATUS_IS_OK(status)) {
614 DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
615 afname, nt_errstr(status)));
617 struct security_descriptor *sd = NULL;
618 status = cli_query_secdesc(cli_state, fnum,
620 if (!NT_STATUS_IS_OK(status)) {
621 DEBUG( 0, ("display_finfo() failed to "
622 "get security descriptor: %s",
625 display_sec_desc(sd);
634 /****************************************************************************
635 Accumulate size of a file.
636 ****************************************************************************/
638 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
641 if (do_this_one(finfo)) {
642 dir_total += finfo->size;
647 static bool do_list_recurse;
648 static bool do_list_dirs;
649 static char *do_list_queue = 0;
650 static long do_list_queue_size = 0;
651 static long do_list_queue_start = 0;
652 static long do_list_queue_end = 0;
653 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
656 /****************************************************************************
657 Functions for do_list_queue.
658 ****************************************************************************/
661 * The do_list_queue is a NUL-separated list of strings stored in a
662 * char*. Since this is a FIFO, we keep track of the beginning and
663 * ending locations of the data in the queue. When we overflow, we
664 * double the size of the char*. When the start of the data passes
665 * the midpoint, we move everything back. This is logically more
666 * complex than a linked list, but easier from a memory management
667 * angle. In any memory error condition, do_list_queue is reset.
668 * Functions check to ensure that do_list_queue is non-NULL before
672 static void reset_do_list_queue(void)
674 SAFE_FREE(do_list_queue);
675 do_list_queue_size = 0;
676 do_list_queue_start = 0;
677 do_list_queue_end = 0;
680 static void init_do_list_queue(void)
682 reset_do_list_queue();
683 do_list_queue_size = 1024;
684 do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
685 if (do_list_queue == 0) {
686 d_printf("malloc fail for size %d\n",
687 (int)do_list_queue_size);
688 reset_do_list_queue();
690 memset(do_list_queue, 0, do_list_queue_size);
694 static void adjust_do_list_queue(void)
697 * If the starting point of the queue is more than half way through,
698 * move everything toward the beginning.
701 if (do_list_queue == NULL) {
702 DEBUG(4,("do_list_queue is empty\n"));
703 do_list_queue_start = do_list_queue_end = 0;
707 if (do_list_queue_start == do_list_queue_end) {
708 DEBUG(4,("do_list_queue is empty\n"));
709 do_list_queue_start = do_list_queue_end = 0;
710 *do_list_queue = '\0';
711 } else if (do_list_queue_start > (do_list_queue_size / 2)) {
712 DEBUG(4,("sliding do_list_queue backward\n"));
713 memmove(do_list_queue,
714 do_list_queue + do_list_queue_start,
715 do_list_queue_end - do_list_queue_start);
716 do_list_queue_end -= do_list_queue_start;
717 do_list_queue_start = 0;
721 static void add_to_do_list_queue(const char *entry)
723 long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
724 while (new_end > do_list_queue_size) {
725 do_list_queue_size *= 2;
726 DEBUG(4,("enlarging do_list_queue to %d\n",
727 (int)do_list_queue_size));
728 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
729 if (! do_list_queue) {
730 d_printf("failure enlarging do_list_queue to %d bytes\n",
731 (int)do_list_queue_size);
732 reset_do_list_queue();
734 memset(do_list_queue + do_list_queue_size / 2,
735 0, do_list_queue_size / 2);
739 strlcpy_base(do_list_queue + do_list_queue_end,
740 entry, do_list_queue, do_list_queue_size);
741 do_list_queue_end = new_end;
742 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
743 entry, (int)do_list_queue_start, (int)do_list_queue_end));
747 static char *do_list_queue_head(void)
749 return do_list_queue + do_list_queue_start;
752 static void remove_do_list_queue_head(void)
754 if (do_list_queue_end > do_list_queue_start) {
755 do_list_queue_start += strlen(do_list_queue_head()) + 1;
756 adjust_do_list_queue();
757 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
758 (int)do_list_queue_start, (int)do_list_queue_end));
762 static int do_list_queue_empty(void)
764 return (! (do_list_queue && *do_list_queue));
767 /****************************************************************************
768 A helper for do_list.
769 ****************************************************************************/
771 static NTSTATUS do_list_helper(const char *mntpoint, struct file_info *f,
772 const char *mask, void *state)
774 struct cli_state *cli_state = (struct cli_state *)state;
775 TALLOC_CTX *ctx = talloc_tos();
777 char *dir_end = NULL;
778 NTSTATUS status = NT_STATUS_OK;
780 /* Work out the directory. */
781 dir = talloc_strdup(ctx, mask);
783 return NT_STATUS_NO_MEMORY;
785 if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
789 if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
790 if (do_list_dirs && do_this_one(f)) {
791 status = do_list_fn(cli_state, f, dir);
792 if (!NT_STATUS_IS_OK(status)) {
796 if (do_list_recurse &&
798 !strequal(f->name,".") &&
799 !strequal(f->name,"..")) {
804 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
806 return NT_STATUS_UNSUCCESSFUL;
809 mask2 = talloc_asprintf(ctx,
815 return NT_STATUS_NO_MEMORY;
817 p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
823 mask2 = talloc_asprintf_append(mask2,
829 return NT_STATUS_NO_MEMORY;
831 add_to_do_list_queue(mask2);
838 if (do_this_one(f)) {
839 status = do_list_fn(cli_state, f, dir);
845 /****************************************************************************
846 A wrapper around cli_list that adds recursion.
847 ****************************************************************************/
849 NTSTATUS do_list(const char *mask,
851 NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
856 static int in_do_list = 0;
857 TALLOC_CTX *ctx = talloc_tos();
858 struct cli_state *targetcli = NULL;
859 char *targetpath = NULL;
860 NTSTATUS ret_status = NT_STATUS_OK;
861 NTSTATUS status = NT_STATUS_OK;
863 if (in_do_list && rec) {
864 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
870 do_list_recurse = rec;
875 init_do_list_queue();
876 add_to_do_list_queue(mask);
878 while (!do_list_queue_empty()) {
880 * Need to copy head so that it doesn't become
881 * invalid inside the call to cli_list. This
882 * would happen if the list were expanded
884 * Fix from E. Jay Berkenbilt (ejb@ql.org)
886 char *head = talloc_strdup(ctx, do_list_queue_head());
889 return NT_STATUS_NO_MEMORY;
894 status = cli_resolve_path(ctx, "",
895 popt_get_cmdline_auth_info(),
896 cli, head, &targetcli, &targetpath);
897 if (!NT_STATUS_IS_OK(status)) {
898 d_printf("do_list: [%s] %s\n", head,
900 remove_do_list_queue_head();
904 status = cli_list(targetcli, targetpath, attribute,
905 do_list_helper, targetcli);
906 if (!NT_STATUS_IS_OK(status)) {
907 d_printf("%s listing %s\n",
908 nt_errstr(status), targetpath);
911 remove_do_list_queue_head();
912 if ((! do_list_queue_empty()) && (fn == display_finfo)) {
913 char *next_file = do_list_queue_head();
915 if ((strlen(next_file) >= 2) &&
916 (next_file[strlen(next_file) - 1] == '*') &&
917 (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
918 save_ch = next_file +
919 strlen(next_file) - 2;
922 /* cwd is only used if showacls is on */
923 client_set_cwd(next_file);
926 if (!showacls) /* don't disturbe the showacls output */
927 d_printf("\n%s\n",next_file);
929 *save_ch = CLI_DIRSEP_CHAR;
933 TALLOC_FREE(targetpath);
937 status = cli_resolve_path(ctx, "",
938 popt_get_cmdline_auth_info(), cli, mask,
939 &targetcli, &targetpath);
940 if (NT_STATUS_IS_OK(status)) {
941 status = cli_list(targetcli, targetpath, attribute,
942 do_list_helper, targetcli);
943 if (!NT_STATUS_IS_OK(status)) {
944 d_printf("%s listing %s\n",
945 nt_errstr(status), targetpath);
948 TALLOC_FREE(targetpath);
950 d_printf("do_list: [%s] %s\n", mask, nt_errstr(status));
956 reset_do_list_queue();
960 /****************************************************************************
961 Get a directory listing.
962 ****************************************************************************/
964 static int cmd_dir(void)
966 TALLOC_CTX *ctx = talloc_tos();
967 uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
974 mask = talloc_strdup(ctx, client_get_cur_dir());
979 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
981 if (*buf == CLI_DIRSEP_CHAR) {
982 mask = talloc_strdup(ctx, buf);
984 mask = talloc_asprintf_append(mask, "%s", buf);
987 mask = talloc_asprintf_append(mask, "*");
993 mask = client_clean_name(ctx, mask);
999 /* cwd is only used if showacls is on */
1000 client_set_cwd(client_get_cur_dir());
1003 status = do_list(mask, attribute, display_finfo, recurse, true);
1004 if (!NT_STATUS_IS_OK(status)) {
1010 DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
1015 /****************************************************************************
1016 Get a directory listing.
1017 ****************************************************************************/
1019 static int cmd_du(void)
1021 TALLOC_CTX *ctx = talloc_tos();
1022 uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1029 mask = talloc_strdup(ctx, client_get_cur_dir());
1033 if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
1034 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
1040 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1041 normalize_name(buf);
1042 if (*buf == CLI_DIRSEP_CHAR) {
1043 mask = talloc_strdup(ctx, buf);
1045 mask = talloc_asprintf_append(mask, "%s", buf);
1048 mask = talloc_strdup(ctx, "*");
1054 mask = client_clean_name(ctx, mask);
1059 status = do_list(mask, attribute, do_du, recurse, true);
1060 if (!NT_STATUS_IS_OK(status)) {
1066 d_printf("Total number of bytes: %.0f\n", dir_total);
1071 static int cmd_echo(void)
1073 TALLOC_CTX *ctx = talloc_tos();
1078 if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1079 || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1080 d_printf("echo <num> <data>\n");
1084 status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1086 if (!NT_STATUS_IS_OK(status)) {
1087 d_printf("echo failed: %s\n", nt_errstr(status));
1094 /****************************************************************************
1095 Get a file from rname to lname
1096 ****************************************************************************/
1098 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1100 int *pfd = (int *)priv;
1103 rc = writefile(*pfd, buf, n);
1105 return map_nt_error_from_unix(errno);
1107 return NT_STATUS_OK;
1110 static int do_get(const char *rname, const char *lname_in, bool reget)
1112 TALLOC_CTX *ctx = talloc_tos();
1115 bool newhandle = false;
1116 struct timespec tp_start;
1122 struct cli_state *targetcli = NULL;
1123 char *targetname = NULL;
1127 lname = talloc_strdup(ctx, lname_in);
1133 if (!strlower_m(lname)) {
1134 d_printf("strlower_m %s failed\n", lname);
1139 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1140 cli, rname, &targetcli, &targetname);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1146 clock_gettime_mono(&tp_start);
1148 status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1149 if (!NT_STATUS_IS_OK(status)) {
1150 d_printf("%s opening remote file %s\n", nt_errstr(status),
1155 if(!strcmp(lname,"-")) {
1156 handle = fileno(stdout);
1159 handle = open(lname, O_WRONLY|O_CREAT, 0644);
1161 start = lseek(handle, 0, SEEK_END);
1163 d_printf("Error seeking local file\n");
1169 handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1174 d_printf("Error opening local file %s\n",lname);
1179 status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1181 if (!NT_STATUS_IS_OK(status)) {
1182 status = cli_getattrE(targetcli, fnum, &attr, &size, NULL, NULL,
1184 if(!NT_STATUS_IS_OK(status)) {
1185 d_printf("getattrib: %s\n", nt_errstr(status));
1193 DEBUG(1,("getting file %s of size %.0f as %s ",
1194 rname, (double)size, lname));
1196 status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1197 writefile_sink, (void *)&handle, &nread);
1198 if (!NT_STATUS_IS_OK(status)) {
1199 d_fprintf(stderr, "parallel_read returned %s\n",
1204 cli_close(targetcli, fnum);
1208 status = cli_close(targetcli, fnum);
1209 if (!NT_STATUS_IS_OK(status)) {
1210 d_printf("Error %s closing remote file\n", nt_errstr(status));
1218 if (archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
1219 cli_setatr(cli, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
1223 struct timespec tp_end;
1226 clock_gettime_mono(&tp_end);
1227 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1228 get_total_time_ms += this_time;
1229 get_total_size += nread;
1231 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1232 nread / (1.024*this_time + 1.0e-4),
1233 get_total_size / (1.024*get_total_time_ms)));
1236 TALLOC_FREE(targetname);
1240 /****************************************************************************
1242 ****************************************************************************/
1244 static int cmd_get(void)
1246 TALLOC_CTX *ctx = talloc_tos();
1251 rname = talloc_strdup(ctx, client_get_cur_dir());
1256 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1257 d_printf("get <filename> [localname]\n");
1260 rname = talloc_asprintf_append(rname, "%s", fname);
1264 rname = client_clean_name(ctx, rname);
1269 next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1274 return do_get(rname, lname, false);
1277 /****************************************************************************
1278 Do an mget operation on one file.
1279 ****************************************************************************/
1281 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1284 TALLOC_CTX *ctx = talloc_tos();
1285 NTSTATUS status = NT_STATUS_OK;
1288 char *saved_curdir = NULL;
1289 char *mget_mask = NULL;
1290 char *new_cd = NULL;
1293 return NT_STATUS_OK;
1296 if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1297 return NT_STATUS_OK;
1300 d_printf("mget aborted\n");
1301 return NT_STATUS_UNSUCCESSFUL;
1304 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
1305 if (asprintf(&quest,
1306 "Get directory %s? ",finfo->name) < 0) {
1307 return NT_STATUS_NO_MEMORY;
1310 if (asprintf(&quest,
1311 "Get file %s? ",finfo->name) < 0) {
1312 return NT_STATUS_NO_MEMORY;
1316 if (prompt && !yesno(quest)) {
1318 return NT_STATUS_OK;
1322 if (!(finfo->mode & FILE_ATTRIBUTE_DIRECTORY)) {
1323 rname = talloc_asprintf(ctx,
1325 client_get_cur_dir(),
1328 return NT_STATUS_NO_MEMORY;
1330 rname = client_clean_name(ctx, rname);
1331 if (rname == NULL) {
1332 return NT_STATUS_NO_MEMORY;
1334 do_get(rname, finfo->name, false);
1336 return NT_STATUS_OK;
1339 /* handle directories */
1340 saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1341 if (!saved_curdir) {
1342 return NT_STATUS_NO_MEMORY;
1345 new_cd = talloc_asprintf(ctx,
1347 client_get_cur_dir(),
1351 return NT_STATUS_NO_MEMORY;
1353 new_cd = client_clean_name(ctx, new_cd);
1354 if (new_cd == NULL) {
1355 return NT_STATUS_NO_MEMORY;
1357 client_set_cur_dir(new_cd);
1359 string_replace(finfo->name,'\\','/');
1361 if (!strlower_m(finfo->name)) {
1362 return NT_STATUS_INVALID_PARAMETER;
1366 if (!directory_exist(finfo->name) &&
1367 mkdir(finfo->name,0777) != 0) {
1368 d_printf("failed to create directory %s\n",finfo->name);
1369 client_set_cur_dir(saved_curdir);
1370 return map_nt_error_from_unix(errno);
1373 if (chdir(finfo->name) != 0) {
1374 d_printf("failed to chdir to directory %s\n",finfo->name);
1375 client_set_cur_dir(saved_curdir);
1376 return map_nt_error_from_unix(errno);
1379 mget_mask = talloc_asprintf(ctx,
1381 client_get_cur_dir());
1384 return NT_STATUS_NO_MEMORY;
1387 mget_mask = client_clean_name(ctx, mget_mask);
1388 if (mget_mask == NULL) {
1389 return NT_STATUS_NO_MEMORY;
1391 status = do_list(mget_mask,
1392 (FILE_ATTRIBUTE_SYSTEM
1393 | FILE_ATTRIBUTE_HIDDEN
1394 | FILE_ATTRIBUTE_DIRECTORY),
1395 do_mget, false, true);
1396 if (!NT_STATUS_IS_OK(status)
1397 && !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1399 * Ignore access denied errors to ensure all permitted files are
1405 if (chdir("..") == -1) {
1406 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1408 return map_nt_error_from_unix(errno);
1410 client_set_cur_dir(saved_curdir);
1411 TALLOC_FREE(mget_mask);
1412 TALLOC_FREE(saved_curdir);
1413 TALLOC_FREE(new_cd);
1414 return NT_STATUS_OK;
1417 /****************************************************************************
1418 View the file using the pager.
1419 ****************************************************************************/
1421 static int cmd_more(void)
1423 TALLOC_CTX *ctx = talloc_tos();
1427 char *pager_cmd = NULL;
1433 rname = talloc_strdup(ctx, client_get_cur_dir());
1438 lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1442 mask = umask(S_IRWXO | S_IRWXG);
1443 fd = mkstemp(lname);
1446 d_printf("failed to create temporary file for more\n");
1451 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1452 d_printf("more <filename>\n");
1456 rname = talloc_asprintf_append(rname, "%s", fname);
1460 rname = client_clean_name(ctx,rname);
1465 rc = do_get(rname, lname, false);
1467 pager=getenv("PAGER");
1469 pager_cmd = talloc_asprintf(ctx,
1471 (pager? pager:PAGER),
1476 if (system(pager_cmd) == -1) {
1477 d_printf("system command '%s' returned -1\n",
1485 /****************************************************************************
1487 ****************************************************************************/
1489 static int cmd_mget(void)
1491 TALLOC_CTX *ctx = talloc_tos();
1492 uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1493 char *mget_mask = NULL;
1495 NTSTATUS status = NT_STATUS_OK;
1498 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1503 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1505 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1509 if (*buf == CLI_DIRSEP_CHAR) {
1510 mget_mask = talloc_strdup(ctx, buf);
1512 mget_mask = talloc_asprintf_append(mget_mask,
1518 mget_mask = client_clean_name(ctx, mget_mask);
1519 if (mget_mask == NULL) {
1522 status = do_list(mget_mask, attribute, do_mget, false, true);
1523 if (!NT_STATUS_IS_OK(status)) {
1528 if (mget_mask == NULL) {
1529 d_printf("nothing to mget\n");
1534 mget_mask = talloc_asprintf(ctx,
1536 client_get_cur_dir());
1540 mget_mask = client_clean_name(ctx, mget_mask);
1541 if (mget_mask == NULL) {
1544 status = do_list(mget_mask, attribute, do_mget, false, true);
1545 if (!NT_STATUS_IS_OK(status)) {
1553 /****************************************************************************
1554 Make a directory of name "name".
1555 ****************************************************************************/
1557 static bool do_mkdir(const char *name)
1559 TALLOC_CTX *ctx = talloc_tos();
1560 struct cli_state *targetcli;
1561 char *targetname = NULL;
1564 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1565 cli, name, &targetcli, &targetname);
1566 if (!NT_STATUS_IS_OK(status)) {
1567 d_printf("mkdir %s: %s\n", name, nt_errstr(status));
1571 status = cli_mkdir(targetcli, targetname);
1572 if (!NT_STATUS_IS_OK(status)) {
1573 d_printf("%s making remote directory %s\n",
1574 nt_errstr(status),name);
1581 /****************************************************************************
1582 Show 8.3 name of a file.
1583 ****************************************************************************/
1585 static bool do_altname(const char *name)
1590 status = cli_qpathinfo_alt_name(cli, name, altname);
1591 if (!NT_STATUS_IS_OK(status)) {
1592 d_printf("%s getting alt name for %s\n",
1593 nt_errstr(status),name);
1596 d_printf("%s\n", altname);
1601 /****************************************************************************
1603 ****************************************************************************/
1605 static int cmd_quit(void)
1608 popt_free_cmdline_auth_info();
1614 /****************************************************************************
1616 ****************************************************************************/
1618 static int cmd_mkdir(void)
1620 TALLOC_CTX *ctx = talloc_tos();
1625 mask = talloc_strdup(ctx, client_get_cur_dir());
1630 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1632 d_printf("mkdir <dirname>\n");
1636 mask = talloc_asprintf_append(mask, "%s", buf);
1640 mask = client_clean_name(ctx, mask);
1648 struct cli_state *targetcli;
1649 char *targetname = NULL;
1653 ddir2 = talloc_strdup(ctx, "");
1658 status = cli_resolve_path(ctx, "",
1659 popt_get_cmdline_auth_info(), cli, mask,
1660 &targetcli, &targetname);
1661 if (!NT_STATUS_IS_OK(status)) {
1665 ddir = talloc_strdup(ctx, targetname);
1669 trim_char(ddir,'.','\0');
1670 p = strtok_r(ddir, "/\\", &saveptr);
1672 ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1676 if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1679 ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1683 p = strtok_r(NULL, "/\\", &saveptr);
1692 /****************************************************************************
1694 ****************************************************************************/
1696 static int cmd_altname(void)
1698 TALLOC_CTX *ctx = talloc_tos();
1702 name = talloc_strdup(ctx, client_get_cur_dir());
1707 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1708 d_printf("altname <file>\n");
1711 name = talloc_asprintf_append(name, "%s", buf);
1715 name = client_clean_name(ctx, name);
1723 static char *attr_str(TALLOC_CTX *mem_ctx, uint16_t mode)
1725 char *attrs = talloc_zero_array(mem_ctx, char, 17);
1728 if (!(mode & FILE_ATTRIBUTE_NORMAL)) {
1729 if (mode & FILE_ATTRIBUTE_ENCRYPTED) {
1732 if (mode & FILE_ATTRIBUTE_NONINDEXED) {
1735 if (mode & FILE_ATTRIBUTE_OFFLINE) {
1738 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
1741 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1744 if (mode & FILE_ATTRIBUTE_SPARSE) {
1747 if (mode & FILE_ATTRIBUTE_TEMPORARY) {
1750 if (mode & FILE_ATTRIBUTE_NORMAL) {
1753 if (mode & FILE_ATTRIBUTE_READONLY) {
1756 if (mode & FILE_ATTRIBUTE_HIDDEN) {
1759 if (mode & FILE_ATTRIBUTE_SYSTEM) {
1762 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1765 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
1772 /****************************************************************************
1773 Show all info we can get
1774 ****************************************************************************/
1776 static int do_allinfo(const char *name)
1779 struct timespec b_time, a_time, m_time, c_time;
1784 unsigned int num_streams;
1785 struct stream_struct *streams;
1787 char **snapshots = NULL;
1791 status = cli_qpathinfo_alt_name(cli, name, altname);
1792 if (!NT_STATUS_IS_OK(status)) {
1793 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1796 * Ignore not supported or not implemented, it does not
1797 * hurt if we can't list alternate names.
1799 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
1800 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1806 d_printf("altname: %s\n", altname);
1808 status = cli_qpathinfo3(cli, name, &b_time, &a_time, &m_time, &c_time,
1809 &size, &mode, NULL);
1810 if (!NT_STATUS_IS_OK(status)) {
1811 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1816 tmp = full_timespec_to_nt_time(&b_time);
1817 d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
1819 tmp = full_timespec_to_nt_time(&a_time);
1820 d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
1822 tmp = full_timespec_to_nt_time(&m_time);
1823 d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
1825 tmp = full_timespec_to_nt_time(&c_time);
1826 d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
1828 d_printf("attributes: %s (%x)\n", attr_str(talloc_tos(), mode), mode);
1830 status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1832 if (!NT_STATUS_IS_OK(status)) {
1833 d_printf("%s getting streams for %s\n", nt_errstr(status),
1838 for (i=0; i<num_streams; i++) {
1839 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1840 (unsigned long long)streams[i].size);
1843 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1844 char *subst, *print;
1847 status = cli_readlink(cli, name, talloc_tos(), &subst, &print,
1849 if (!NT_STATUS_IS_OK(status)) {
1850 d_fprintf(stderr, "cli_readlink returned %s\n",
1853 d_printf("symlink: subst=[%s], print=[%s], flags=%x\n",
1854 subst, print, flags);
1860 status = cli_ntcreate(cli, name, 0,
1861 SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE |
1862 SEC_STD_SYNCHRONIZE, 0,
1863 FILE_SHARE_READ|FILE_SHARE_WRITE
1865 FILE_OPEN, 0x0, 0x0, &fnum, NULL);
1866 if (!NT_STATUS_IS_OK(status)) {
1868 * Ignore failure, it does not hurt if we can't list
1874 * In order to get shadow copy data over SMB1 we
1875 * must call twice, once with 'get_names = false'
1876 * to get the size, then again with 'get_names = true'
1877 * to get the data or a Windows server fails to return
1878 * valid info. Samba doesn't have this bug. JRA.
1881 status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1882 false, &snapshots, &num_snapshots);
1883 if (!NT_STATUS_IS_OK(status)) {
1884 cli_close(cli, fnum);
1887 status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1888 true, &snapshots, &num_snapshots);
1889 if (!NT_STATUS_IS_OK(status)) {
1890 cli_close(cli, fnum);
1894 for (i=0; i<num_snapshots; i++) {
1897 d_printf("%s\n", snapshots[i]);
1898 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1899 snapshots[i], name);
1900 status = cli_qpathinfo3(cli, snap_name, &b_time, &a_time,
1901 &m_time, &c_time, &size,
1903 if (!NT_STATUS_IS_OK(status)) {
1904 d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1905 snap_name, nt_errstr(status));
1906 TALLOC_FREE(snap_name);
1909 tmp = unix_timespec_to_nt_time(b_time);
1910 d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
1911 tmp = unix_timespec_to_nt_time(a_time);
1912 d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
1913 tmp =unix_timespec_to_nt_time(m_time);
1914 d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
1915 tmp = unix_timespec_to_nt_time(c_time);
1916 d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
1917 d_printf("size: %d\n", (int)size);
1920 TALLOC_FREE(snapshots);
1921 cli_close(cli, fnum);
1926 /****************************************************************************
1927 Show all info we can get
1928 ****************************************************************************/
1930 static int cmd_allinfo(void)
1932 TALLOC_CTX *ctx = talloc_tos();
1936 name = talloc_strdup(ctx, client_get_cur_dir());
1941 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1942 d_printf("allinfo <file>\n");
1945 name = talloc_asprintf_append(name, "%s", buf);
1949 name = client_clean_name(ctx, name);
1958 /****************************************************************************
1960 ****************************************************************************/
1962 static int do_put(const char *rname, const char *lname, bool reput)
1964 TALLOC_CTX *ctx = talloc_tos();
1969 struct timespec tp_start;
1970 struct cli_state *targetcli;
1971 char *targetname = NULL;
1972 struct push_state state;
1975 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1976 cli, rname, &targetcli, &targetname);
1977 if (!NT_STATUS_IS_OK(status)) {
1978 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1982 clock_gettime_mono(&tp_start);
1985 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1986 if (NT_STATUS_IS_OK(status)) {
1987 if (!NT_STATUS_IS_OK(status = cli_qfileinfo_basic(
1988 targetcli, fnum, NULL,
1990 NULL, NULL, NULL)) &&
1991 !NT_STATUS_IS_OK(status = cli_getattrE(
1992 targetcli, fnum, NULL,
1995 d_printf("getattrib: %s\n", nt_errstr(status));
2000 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
2003 if (!NT_STATUS_IS_OK(status)) {
2004 d_printf("%s opening remote file %s\n", nt_errstr(status),
2009 /* allow files to be piped into smbclient
2012 Note that in this case this function will exit(0) rather
2014 if (!strcmp(lname, "-")) {
2016 /* size of file is not known */
2018 f = fopen(lname, "r");
2020 if (fseek(f, start, SEEK_SET) == -1) {
2021 d_printf("Error seeking local file\n");
2029 d_printf("Error opening local file %s\n",lname);
2033 DEBUG(1,("putting file %s as %s ",lname,
2036 setvbuf(f, NULL, _IOFBF, io_bufsize);
2041 status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
2043 if (!NT_STATUS_IS_OK(status)) {
2044 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
2048 status = cli_close(targetcli, fnum);
2049 if (!NT_STATUS_IS_OK(status)) {
2050 d_printf("%s closing remote file %s\n", nt_errstr(status),
2063 struct timespec tp_end;
2066 clock_gettime_mono(&tp_end);
2067 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
2068 put_total_time_ms += this_time;
2069 put_total_size += state.nread;
2071 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
2072 state.nread / (1.024*this_time + 1.0e-4),
2073 put_total_size / (1.024*put_total_time_ms)));
2078 popt_free_cmdline_auth_info();
2085 /****************************************************************************
2087 ****************************************************************************/
2089 static int cmd_put(void)
2091 TALLOC_CTX *ctx = talloc_tos();
2096 rname = talloc_strdup(ctx, client_get_cur_dir());
2101 if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
2102 d_printf("put <filename>\n");
2106 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2107 rname = talloc_asprintf_append(rname, "%s", buf);
2109 rname = talloc_asprintf_append(rname, "%s", lname);
2115 rname = client_clean_name(ctx, rname);
2122 /* allow '-' to represent stdin
2123 jdblair, 24.jun.98 */
2124 if (!file_exist_stat(lname, &st, false) &&
2125 (strcmp(lname,"-"))) {
2126 d_printf("%s does not exist\n",lname);
2131 return do_put(rname, lname, false);
2134 /*************************************
2135 File list structure.
2136 *************************************/
2138 static struct file_list {
2139 struct file_list *prev, *next;
2144 /****************************************************************************
2145 Free a file_list structure.
2146 ****************************************************************************/
2148 static void free_file_list (struct file_list *l_head)
2150 struct file_list *list, *next;
2152 for (list = l_head; list; list = next) {
2154 DLIST_REMOVE(l_head, list);
2159 /****************************************************************************
2160 Seek in a directory/file list until you get something that doesn't start with
2162 ****************************************************************************/
2164 static bool seek_list(struct file_list *list, char *name)
2167 trim_string(list->file_path,"./","\n");
2168 if (strncmp(list->file_path, name, strlen(name)) != 0) {
2177 /****************************************************************************
2178 Set the file selection mask.
2179 ****************************************************************************/
2181 static int cmd_select(void)
2183 TALLOC_CTX *ctx = talloc_tos();
2184 char *new_fs = NULL;
2185 next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
2188 client_set_fileselection(new_fs);
2190 client_set_fileselection("");
2195 /****************************************************************************
2196 Recursive file matching function act as find
2197 match must be always set to true when calling this function
2198 ****************************************************************************/
2200 static int file_find(TALLOC_CTX *ctx,
2201 struct file_list **list,
2202 const char *directory,
2203 const char *expression,
2207 struct file_list *entry;
2208 struct stat statbuf;
2214 dir = opendir(directory);
2218 while ((dname = readdirname(dir))) {
2219 if (!strcmp("..", dname))
2221 if (!strcmp(".", dname))
2224 path = talloc_asprintf(ctx, "%s/%s", directory, dname);
2230 if (!match || !gen_fnmatch(expression, dname)) {
2232 ret = stat(path, &statbuf);
2234 if (S_ISDIR(statbuf.st_mode)) {
2236 ret = file_find(ctx,
2243 d_printf("file_find: cannot stat file %s\n", path);
2252 entry = talloc_zero(ctx, struct file_list);
2254 d_printf("Out of memory in file_find\n");
2258 entry->file_path = talloc_move(entry, &path);
2259 entry->isdir = isdir;
2260 DLIST_ADD(*list, entry);
2270 /****************************************************************************
2272 ****************************************************************************/
2274 static int cmd_mput(void)
2276 TALLOC_CTX *ctx = talloc_tos();
2279 while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2281 struct file_list *temp_list;
2282 char *quest, *lname, *rname;
2286 ret = file_find(ctx, &file_list, ".", p, true);
2288 free_file_list(file_list);
2296 for (temp_list = file_list; temp_list;
2297 temp_list = temp_list->next) {
2300 if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2303 trim_string(lname, "./", "/");
2305 /* check if it's a directory */
2306 if (temp_list->isdir) {
2307 /* if (!recurse) continue; */
2310 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2313 if (prompt && !yesno(quest)) { /* No */
2314 /* Skip the directory */
2315 lname[strlen(lname)-1] = '/';
2316 if (!seek_list(temp_list, lname))
2320 if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2323 normalize_name(rname);
2326 client_clean_name(ctx, rname);
2327 if (tmp_rname == NULL) {
2331 rname = smb_xstrdup(tmp_rname);
2332 TALLOC_FREE(tmp_rname);
2333 if (rname == NULL) {
2337 if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2339 DEBUG (0, ("Unable to make dir, skipping..."));
2340 /* Skip the directory */
2341 lname[strlen(lname)-1] = '/';
2342 if (!seek_list(temp_list, lname)) {
2350 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2353 if (prompt && !yesno(quest)) {
2360 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2365 normalize_name(rname);
2368 char *tmp_rname = client_clean_name(ctx, rname);
2369 if (tmp_rname == NULL) {
2373 rname = smb_xstrdup(tmp_rname);
2374 TALLOC_FREE(tmp_rname);
2375 if (rname == NULL) {
2379 do_put(rname, lname, false);
2381 free_file_list(file_list);
2390 /****************************************************************************
2392 ****************************************************************************/
2394 static int do_cancel(int job)
2396 if (cli_printjob_del(cli, job)) {
2397 d_printf("Job %d cancelled\n",job);
2400 NTSTATUS status = cli_nt_error(cli);
2401 d_printf("Error cancelling job %d : %s\n",
2402 job, nt_errstr(status));
2407 /****************************************************************************
2409 ****************************************************************************/
2411 static int cmd_cancel(void)
2413 TALLOC_CTX *ctx = talloc_tos();
2417 if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2418 d_printf("cancel <jobid> ...\n");
2424 } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2429 /****************************************************************************
2431 ****************************************************************************/
2433 static int cmd_print(void)
2435 TALLOC_CTX *ctx = talloc_tos();
2440 if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2441 d_printf("print <filename>\n");
2445 rname = talloc_strdup(ctx, lname);
2449 p = strrchr_m(rname,'/');
2451 rname = talloc_asprintf(ctx,
2456 if (strequal(lname,"-")) {
2457 rname = talloc_asprintf(ctx,
2465 return do_put(rname, lname, false);
2468 /****************************************************************************
2469 Show a print queue entry.
2470 ****************************************************************************/
2472 static void queue_fn(struct print_job_info *p)
2474 d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
2477 /****************************************************************************
2479 ****************************************************************************/
2481 static int cmd_queue(void)
2483 cli_print_queue(cli, queue_fn);
2487 /****************************************************************************
2489 ****************************************************************************/
2491 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2494 TALLOC_CTX *ctx = talloc_tos();
2498 mask = talloc_asprintf(ctx,
2504 return NT_STATUS_NO_MEMORY;
2507 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
2509 return NT_STATUS_OK;
2512 status = cli_unlink(cli_state, mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 d_printf("%s deleting remote file %s\n",
2515 nt_errstr(status), mask);
2521 /****************************************************************************
2523 ****************************************************************************/
2525 static int cmd_del(void)
2527 TALLOC_CTX *ctx = talloc_tos();
2530 NTSTATUS status = NT_STATUS_OK;
2531 uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
2534 attribute |= FILE_ATTRIBUTE_DIRECTORY;
2537 mask = talloc_strdup(ctx, client_get_cur_dir());
2541 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2542 d_printf("del <filename>\n");
2545 mask = talloc_asprintf_append(mask, "%s", buf);
2549 mask = client_clean_name(ctx, mask);
2554 status = do_list(mask,attribute,do_del,false,false);
2555 if (!NT_STATUS_IS_OK(status)) {
2561 /****************************************************************************
2563 ****************************************************************************/
2565 static NTSTATUS delete_remote_files_list(struct cli_state *cli_state,
2566 struct file_list *flist)
2568 NTSTATUS status = NT_STATUS_OK;
2569 struct file_list *deltree_list_iter = NULL;
2571 for (deltree_list_iter = flist;
2572 deltree_list_iter != NULL;
2573 deltree_list_iter = deltree_list_iter->next) {
2574 if (CLI_DIRSEP_CHAR == '/') {
2576 status = cli_posix_unlink(cli_state,
2577 deltree_list_iter->file_path);
2578 } else if (deltree_list_iter->isdir) {
2579 status = cli_rmdir(cli_state,
2580 deltree_list_iter->file_path);
2582 status = cli_unlink(cli_state,
2583 deltree_list_iter->file_path,
2584 FILE_ATTRIBUTE_SYSTEM |
2585 FILE_ATTRIBUTE_HIDDEN);
2587 if (!NT_STATUS_IS_OK(status)) {
2588 d_printf("%s deleting remote %s %s\n",
2590 deltree_list_iter->isdir ?
2591 "directory" : "file",
2592 deltree_list_iter->file_path);
2596 return NT_STATUS_OK;
2599 /****************************************************************************
2600 Save a list of files to delete.
2601 ****************************************************************************/
2603 static struct file_list *deltree_list_head;
2605 static NTSTATUS do_deltree_list(struct cli_state *cli_state,
2606 struct file_info *finfo,
2609 struct file_list **file_list_head_pp = &deltree_list_head;
2610 struct file_list *dt = NULL;
2612 if (!do_this_one(finfo)) {
2613 return NT_STATUS_OK;
2616 /* skip if this is . or .. */
2617 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2618 return NT_STATUS_OK;
2621 dt = talloc_zero(NULL, struct file_list);
2623 return NT_STATUS_NO_MEMORY;
2626 /* create absolute filename for cli_ntcreate() */
2627 dt->file_path = talloc_asprintf(dt,
2632 if (dt->file_path == NULL) {
2634 return NT_STATUS_NO_MEMORY;
2637 if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
2641 DLIST_ADD(*file_list_head_pp, dt);
2642 return NT_STATUS_OK;
2645 static int cmd_deltree(void)
2647 TALLOC_CTX *ctx = talloc_tos();
2649 NTSTATUS status = NT_STATUS_OK;
2650 struct file_list *deltree_list_norecurse = NULL;
2651 struct file_list *deltree_list_iter = NULL;
2652 uint16_t attribute = FILE_ATTRIBUTE_SYSTEM |
2653 FILE_ATTRIBUTE_HIDDEN |
2654 FILE_ATTRIBUTE_DIRECTORY;
2656 char *mask = talloc_strdup(ctx, client_get_cur_dir());
2660 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
2662 d_printf("deltree <filename>\n");
2665 mask = talloc_asprintf_append(mask, "%s", buf);
2669 mask = client_clean_name(ctx, mask);
2674 deltree_list_head = NULL;
2677 * Get the list of directories to
2678 * delete (in case mask has a wildcard).
2680 status = do_list(mask, attribute, do_deltree_list, false, true);
2681 if (!NT_STATUS_IS_OK(status)) {
2684 deltree_list_norecurse = deltree_list_head;
2685 deltree_list_head = NULL;
2687 for (deltree_list_iter = deltree_list_norecurse;
2688 deltree_list_iter != NULL;
2689 deltree_list_iter = deltree_list_iter->next) {
2691 if (deltree_list_iter->isdir == false) {
2692 /* Just a regular file. */
2693 if (CLI_DIRSEP_CHAR == '/') {
2695 status = cli_posix_unlink(cli,
2696 deltree_list_iter->file_path);
2698 status = cli_unlink(cli,
2699 deltree_list_iter->file_path,
2700 FILE_ATTRIBUTE_SYSTEM |
2701 FILE_ATTRIBUTE_HIDDEN);
2703 if (!NT_STATUS_IS_OK(status)) {
2710 * Get the list of files or directories to
2711 * delete in depth order.
2713 status = do_list(deltree_list_iter->file_path,
2718 if (!NT_STATUS_IS_OK(status)) {
2721 status = delete_remote_files_list(cli, deltree_list_head);
2722 free_file_list(deltree_list_head);
2723 deltree_list_head = NULL;
2724 if (!NT_STATUS_IS_OK(status)) {
2729 free_file_list(deltree_list_norecurse);
2730 free_file_list(deltree_list_head);
2735 free_file_list(deltree_list_norecurse);
2736 free_file_list(deltree_list_head);
2737 deltree_list_head = NULL;
2742 /****************************************************************************
2743 Wildcard delete some files.
2744 ****************************************************************************/
2746 static int cmd_wdel(void)
2748 TALLOC_CTX *ctx = talloc_tos();
2752 struct cli_state *targetcli;
2753 char *targetname = NULL;
2756 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2757 d_printf("wdel 0x<attrib> <wcard>\n");
2761 attribute = (uint16_t)strtol(buf, (char **)NULL, 16);
2763 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2764 d_printf("wdel 0x<attrib> <wcard>\n");
2768 mask = talloc_asprintf(ctx, "%s%s",
2769 client_get_cur_dir(),
2774 mask = client_clean_name(ctx, mask);
2779 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2780 cli, mask, &targetcli, &targetname);
2781 if (!NT_STATUS_IS_OK(status)) {
2782 d_printf("cmd_wdel %s: %s\n", mask, nt_errstr(status));
2786 status = cli_unlink(targetcli, targetname, attribute);
2787 if (!NT_STATUS_IS_OK(status)) {
2788 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2794 /****************************************************************************
2795 ****************************************************************************/
2797 static int cmd_open(void)
2799 TALLOC_CTX *ctx = talloc_tos();
2802 char *targetname = NULL;
2803 struct cli_state *targetcli;
2804 uint16_t fnum = (uint16_t)-1;
2807 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2808 d_printf("open <filename>\n");
2811 mask = talloc_asprintf(ctx,
2813 client_get_cur_dir(),
2819 mask = client_clean_name(ctx, mask);
2824 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2825 cli, mask, &targetcli, &targetname);
2826 if (!NT_STATUS_IS_OK(status)) {
2827 d_printf("open %s: %s\n", mask, nt_errstr(status));
2831 status = cli_ntcreate(targetcli, targetname, 0,
2832 FILE_READ_DATA|FILE_WRITE_DATA, 0,
2833 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2834 0x0, 0x0, &fnum, NULL);
2835 if (!NT_STATUS_IS_OK(status)) {
2836 status = cli_ntcreate(targetcli, targetname, 0,
2838 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2839 0x0, 0x0, &fnum, NULL);
2840 if (NT_STATUS_IS_OK(status)) {
2841 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2843 d_printf("Failed to open file %s. %s\n",
2844 targetname, nt_errstr(status));
2847 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2852 static int cmd_posix_encrypt(void)
2854 TALLOC_CTX *ctx = talloc_tos();
2855 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2856 char *domain = NULL;
2858 char *password = NULL;
2859 struct cli_credentials *creds = NULL;
2860 struct cli_credentials *lcreds = NULL;
2862 if (next_token_talloc(ctx, &cmd_ptr, &domain, NULL)) {
2864 if (!next_token_talloc(ctx, &cmd_ptr, &user, NULL)) {
2865 d_printf("posix_encrypt domain user password\n");
2869 if (!next_token_talloc(ctx, &cmd_ptr, &password, NULL)) {
2870 d_printf("posix_encrypt domain user password\n");
2874 lcreds = cli_session_creds_init(ctx,
2879 false, /* use_kerberos */
2880 false, /* fallback_after_kerberos */
2881 false, /* use_ccache */
2882 false); /* password_is_nt_hash */
2883 if (lcreds == NULL) {
2884 d_printf("cli_session_creds_init() failed.\n");
2889 bool auth_requested = false;
2891 creds = get_cmdline_auth_info_creds(
2892 popt_get_cmdline_auth_info());
2894 auth_requested = cli_credentials_authentication_requested(creds);
2895 if (!auth_requested) {
2896 d_printf("posix_encrypt domain user password\n");
2901 status = cli_smb1_setup_encryption(cli, creds);
2902 /* gensec currently references the creds so we can't free them here */
2903 talloc_unlink(ctx, lcreds);
2904 if (!NT_STATUS_IS_OK(status)) {
2905 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2907 d_printf("encryption on\n");
2914 /****************************************************************************
2915 ****************************************************************************/
2917 static int cmd_posix_open(void)
2919 TALLOC_CTX *ctx = talloc_tos();
2922 char *targetname = NULL;
2923 struct cli_state *targetcli;
2928 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2929 d_printf("posix_open <filename> 0<mode>\n");
2932 mask = talloc_asprintf(ctx,
2934 client_get_cur_dir(),
2939 mask = client_clean_name(ctx, mask);
2944 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2945 d_printf("posix_open <filename> 0<mode>\n");
2948 mode = (mode_t)strtol(buf, (char **)NULL, 8);
2950 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2951 cli, mask, &targetcli, &targetname);
2952 if (!NT_STATUS_IS_OK(status)) {
2953 d_printf("posix_open %s: %s\n", mask, nt_errstr(status));
2957 status = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode,
2959 if (!NT_STATUS_IS_OK(status)) {
2960 status = cli_posix_open(targetcli, targetname,
2961 O_CREAT|O_RDONLY, mode, &fnum);
2962 if (!NT_STATUS_IS_OK(status)) {
2963 d_printf("Failed to open file %s. %s\n", targetname,
2966 d_printf("posix_open file %s: for readonly fnum %d\n",
2970 d_printf("posix_open file %s: for read/write fnum %d\n",
2977 static int cmd_posix_mkdir(void)
2979 TALLOC_CTX *ctx = talloc_tos();
2982 char *targetname = NULL;
2983 struct cli_state *targetcli;
2987 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2988 d_printf("posix_mkdir <filename> 0<mode>\n");
2991 mask = talloc_asprintf(ctx,
2993 client_get_cur_dir(),
2998 mask = client_clean_name(ctx, mask);
3003 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3004 d_printf("posix_mkdir <filename> 0<mode>\n");
3007 mode = (mode_t)strtol(buf, (char **)NULL, 8);
3009 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3010 cli, mask, &targetcli, &targetname);
3011 if (!NT_STATUS_IS_OK(status)) {
3012 d_printf("posix_mkdir %s: %s\n", mask, nt_errstr(status));
3016 status = cli_posix_mkdir(targetcli, targetname, mode);
3017 if (!NT_STATUS_IS_OK(status)) {
3018 d_printf("Failed to open file %s. %s\n",
3019 targetname, nt_errstr(status));
3021 d_printf("posix_mkdir created directory %s\n", targetname);
3026 static int cmd_posix_unlink(void)
3028 TALLOC_CTX *ctx = talloc_tos();
3031 char *targetname = NULL;
3032 struct cli_state *targetcli;
3035 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3036 d_printf("posix_unlink <filename>\n");
3039 mask = talloc_asprintf(ctx,
3041 client_get_cur_dir(),
3046 mask = client_clean_name(ctx, mask);
3051 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3052 cli, mask, &targetcli, &targetname);
3053 if (!NT_STATUS_IS_OK(status)) {
3054 d_printf("posix_unlink %s: %s\n", mask, nt_errstr(status));
3058 status = cli_posix_unlink(targetcli, targetname);
3059 if (!NT_STATUS_IS_OK(status)) {
3060 d_printf("Failed to unlink file %s. %s\n",
3061 targetname, nt_errstr(status));
3063 d_printf("posix_unlink deleted file %s\n", targetname);
3069 static int cmd_posix_rmdir(void)
3071 TALLOC_CTX *ctx = talloc_tos();
3074 char *targetname = NULL;
3075 struct cli_state *targetcli;
3078 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3079 d_printf("posix_rmdir <filename>\n");
3082 mask = talloc_asprintf(ctx,
3084 client_get_cur_dir(),
3089 mask = client_clean_name(ctx, mask);
3094 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3095 cli, mask, &targetcli, &targetname);
3096 if (!NT_STATUS_IS_OK(status)) {
3097 d_printf("posix_rmdir %s: %s\n", mask, nt_errstr(status));
3101 status = cli_posix_rmdir(targetcli, targetname);
3102 if (!NT_STATUS_IS_OK(status)) {
3103 d_printf("Failed to unlink directory %s. %s\n",
3104 targetname, nt_errstr(status));
3106 d_printf("posix_rmdir deleted directory %s\n", targetname);
3112 static int cmd_close(void)
3114 TALLOC_CTX *ctx = talloc_tos();
3119 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3120 d_printf("close <fnum>\n");
3125 /* We really should use the targetcli here.... */
3126 status = cli_close(cli, fnum);
3127 if (!NT_STATUS_IS_OK(status)) {
3128 d_printf("close %d: %s\n", fnum, nt_errstr(status));
3134 static int cmd_posix(void)
3136 TALLOC_CTX *ctx = talloc_tos();
3137 uint16_t major, minor;
3138 uint32_t caplow, caphigh;
3142 if (!SERVER_HAS_UNIX_CIFS(cli)) {
3143 d_printf("Server doesn't support UNIX CIFS extensions.\n");
3147 status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
3149 if (!NT_STATUS_IS_OK(status)) {
3150 d_printf("Can't get UNIX CIFS extensions version from "
3151 "server: %s\n", nt_errstr(status));
3155 d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
3157 caps = talloc_strdup(ctx, "");
3161 if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
3162 caps = talloc_asprintf_append(caps, "locks ");
3167 if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
3168 caps = talloc_asprintf_append(caps, "acls ");
3173 if (caplow & CIFS_UNIX_XATTTR_CAP) {
3174 caps = talloc_asprintf_append(caps, "eas ");
3179 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3180 caps = talloc_asprintf_append(caps, "pathnames ");
3185 if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
3186 caps = talloc_asprintf_append(caps, "posix_path_operations ");
3191 if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
3192 caps = talloc_asprintf_append(caps, "large_read ");
3197 if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
3198 caps = talloc_asprintf_append(caps, "large_write ");
3203 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
3204 caps = talloc_asprintf_append(caps, "posix_encrypt ");
3209 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
3210 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
3216 if (*caps && caps[strlen(caps)-1] == ' ') {
3217 caps[strlen(caps)-1] = '\0';
3220 d_printf("Server supports CIFS capabilities %s\n", caps);
3222 status = cli_set_unix_extensions_capabilities(cli, major, minor,
3224 if (!NT_STATUS_IS_OK(status)) {
3225 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
3230 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3231 CLI_DIRSEP_CHAR = '/';
3232 *CLI_DIRSEP_STR = '/';
3233 client_set_cur_dir(CLI_DIRSEP_STR);
3239 static int cmd_lock(void)
3241 TALLOC_CTX *ctx = talloc_tos();
3243 uint64_t start, len;
3244 enum brl_type lock_type;
3248 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3249 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3254 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3255 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3259 if (*buf == 'r' || *buf == 'R') {
3260 lock_type = READ_LOCK;
3261 } else if (*buf == 'w' || *buf == 'W') {
3262 lock_type = WRITE_LOCK;
3264 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3268 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3269 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3273 start = (uint64_t)strtol(buf, (char **)NULL, 16);
3275 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3276 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3280 len = (uint64_t)strtol(buf, (char **)NULL, 16);
3282 status = cli_posix_lock(cli, fnum, start, len, true, lock_type);
3283 if (!NT_STATUS_IS_OK(status)) {
3284 d_printf("lock failed %d: %s\n", fnum, nt_errstr(status));
3290 static int cmd_unlock(void)
3292 TALLOC_CTX *ctx = talloc_tos();
3294 uint64_t start, len;
3298 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3299 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3304 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3305 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3309 start = (uint64_t)strtol(buf, (char **)NULL, 16);
3311 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3312 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3316 len = (uint64_t)strtol(buf, (char **)NULL, 16);
3318 status = cli_posix_unlock(cli, fnum, start, len);
3319 if (!NT_STATUS_IS_OK(status)) {
3320 d_printf("unlock failed %d: %s\n", fnum, nt_errstr(status));
3326 static int cmd_posix_whoami(void)
3328 TALLOC_CTX *ctx = talloc_tos();
3329 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3332 uint32_t num_gids = 0;
3333 uint32_t num_sids = 0;
3334 uint64_t *gids = NULL;
3335 struct dom_sid *sids = NULL;
3339 status = cli_posix_whoami(cli,
3349 if (!NT_STATUS_IS_OK(status)) {
3350 d_printf("posix_whoami failed with error %s\n", nt_errstr(status));
3354 d_printf("GUEST:%s\n", guest ? "True" : "False");
3355 d_printf("UID:%" PRIu64 "\n", uid);
3356 d_printf("GID:%" PRIu64 "\n", gid);
3357 d_printf("NUM_GIDS:%" PRIu32 "\n", num_gids);
3358 for (i = 0; i < num_gids; i++) {
3359 d_printf("GIDS[%" PRIu32 "]:%" PRIu64 "\n", i, gids[i]);
3361 d_printf("NUM_SIDS:%" PRIu32 "\n", num_sids);
3362 for (i = 0; i < num_sids; i++) {
3363 struct dom_sid_buf buf;
3364 d_printf("SIDS[%" PRIu32 "]:%s\n",
3366 dom_sid_str_buf(&sids[i], &buf));
3372 /****************************************************************************
3374 ****************************************************************************/
3376 static int cmd_rmdir(void)
3378 TALLOC_CTX *ctx = talloc_tos();
3381 char *targetname = NULL;
3382 struct cli_state *targetcli;
3385 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3386 d_printf("rmdir <dirname>\n");
3389 mask = talloc_asprintf(ctx,
3391 client_get_cur_dir(),
3396 mask = client_clean_name(ctx, mask);
3401 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3402 cli, mask, &targetcli, &targetname);
3403 if (!NT_STATUS_IS_OK(status)) {
3404 d_printf("rmdir %s: %s\n", mask, nt_errstr(status));
3408 status = cli_rmdir(targetcli, targetname);
3409 if (!NT_STATUS_IS_OK(status)) {
3410 d_printf("%s removing remote directory file %s\n",
3411 nt_errstr(status), mask);
3417 /****************************************************************************
3419 ****************************************************************************/
3421 static int cmd_link(void)
3423 TALLOC_CTX *ctx = talloc_tos();
3424 char *oldname = NULL;
3425 char *newname = NULL;
3428 char *targetname = NULL;
3429 struct cli_state *targetcli;
3432 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3433 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3434 d_printf("link <oldname> <newname>\n");
3437 oldname = talloc_asprintf(ctx,
3439 client_get_cur_dir(),
3444 oldname = client_clean_name(ctx, oldname);
3445 if (oldname == NULL) {
3448 newname = talloc_asprintf(ctx,
3450 client_get_cur_dir(),
3455 newname = client_clean_name(ctx, newname);
3456 if (newname == NULL) {
3460 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3461 cli, oldname, &targetcli, &targetname);
3462 if (!NT_STATUS_IS_OK(status)) {
3463 d_printf("link %s: %s\n", oldname, nt_errstr(status));
3467 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3468 d_printf("Server doesn't support UNIX CIFS calls.\n");
3472 status = cli_posix_hardlink(targetcli, targetname, newname);
3473 if (!NT_STATUS_IS_OK(status)) {
3474 d_printf("%s linking files (%s -> %s)\n",
3475 nt_errstr(status), newname, oldname);
3481 /****************************************************************************
3483 ****************************************************************************/
3485 static int cmd_readlink(void)
3487 TALLOC_CTX *ctx = talloc_tos();
3490 char *targetname = NULL;
3491 char *linkname = NULL;
3492 struct cli_state *targetcli;
3495 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3496 d_printf("readlink <name>\n");
3499 name = talloc_asprintf(ctx,
3501 client_get_cur_dir(),
3506 name = client_clean_name(ctx, name);
3511 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3512 cli, name, &targetcli, &targetname);
3513 if (!NT_STATUS_IS_OK(status)) {
3514 d_printf("readlink %s: %s\n", name, nt_errstr(status));
3518 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3519 d_printf("Server doesn't support UNIX CIFS calls.\n");
3523 status = cli_posix_readlink(targetcli, name, talloc_tos(), &linkname);
3524 if (!NT_STATUS_IS_OK(status)) {
3525 d_printf("%s readlink on file %s\n",
3526 nt_errstr(status), name);
3530 d_printf("%s -> %s\n", name, linkname);
3532 TALLOC_FREE(linkname);
3538 /****************************************************************************
3540 ****************************************************************************/
3542 static int cmd_symlink(void)
3544 TALLOC_CTX *ctx = talloc_tos();
3545 char *link_target = NULL;
3546 char *newname = NULL;
3549 struct cli_state *newcli;
3552 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3553 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3554 d_printf("symlink <link_target> <newname>\n");
3557 /* Oldname (link target) must be an untouched blob. */
3560 if (SERVER_HAS_UNIX_CIFS(cli)) {
3561 newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
3566 newname = client_clean_name(ctx, newname);
3567 if (newname == NULL) {
3570 /* New name must be present in share namespace. */
3571 status = cli_resolve_path(ctx, "",
3572 popt_get_cmdline_auth_info(), cli, newname,
3574 if (!NT_STATUS_IS_OK(status)) {
3575 d_printf("link %s: %s\n", newname,
3579 status = cli_posix_symlink(newcli, link_target, newname);
3581 status = cli_symlink(
3582 cli, link_target, buf2,
3583 buf2[0] == '\\' ? 0 : SYMLINK_FLAG_RELATIVE);
3586 if (!NT_STATUS_IS_OK(status)) {
3587 d_printf("%s symlinking files (%s -> %s)\n",
3588 nt_errstr(status), newname, link_target);
3595 /****************************************************************************
3597 ****************************************************************************/
3599 static int cmd_chmod(void)
3601 TALLOC_CTX *ctx = talloc_tos();
3605 char *targetname = NULL;
3606 struct cli_state *targetcli;
3610 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3611 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3612 d_printf("chmod mode file\n");
3615 src = talloc_asprintf(ctx,
3617 client_get_cur_dir(),
3622 src = client_clean_name(ctx, src);
3627 mode = (mode_t)strtol(buf, NULL, 8);
3629 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3630 cli, src, &targetcli, &targetname);
3631 if (!NT_STATUS_IS_OK(status)) {
3632 d_printf("chmod %s: %s\n", src, nt_errstr(status));
3636 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3637 d_printf("Server doesn't support UNIX CIFS calls.\n");
3641 status = cli_posix_chmod(targetcli, targetname, mode);
3642 if (!NT_STATUS_IS_OK(status)) {
3643 d_printf("%s chmod file %s 0%o\n",
3644 nt_errstr(status), src, (unsigned int)mode);
3651 static const char *filetype_to_str(mode_t mode)
3653 if (S_ISREG(mode)) {
3654 return "regular file";
3655 } else if (S_ISDIR(mode)) {
3659 if (S_ISCHR(mode)) {
3660 return "character device";
3664 if (S_ISBLK(mode)) {
3665 return "block device";
3669 if (S_ISFIFO(mode)) {
3674 if (S_ISLNK(mode)) {
3675 return "symbolic link";
3679 if (S_ISSOCK(mode)) {
3686 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3695 static char *unix_mode_to_str(char *s, mode_t m)
3698 const char *str = filetype_to_str(m);
3714 *p++ = str[1] == 'y' ? 'l' : 's';
3721 *p++ = rwx_to_str(m, S_IRUSR, 'r');
3722 *p++ = rwx_to_str(m, S_IWUSR, 'w');
3723 *p++ = rwx_to_str(m, S_IXUSR, 'x');
3724 *p++ = rwx_to_str(m, S_IRGRP, 'r');
3725 *p++ = rwx_to_str(m, S_IWGRP, 'w');
3726 *p++ = rwx_to_str(m, S_IXGRP, 'x');
3727 *p++ = rwx_to_str(m, S_IROTH, 'r');
3728 *p++ = rwx_to_str(m, S_IWOTH, 'w');
3729 *p++ = rwx_to_str(m, S_IXOTH, 'x');
3734 /****************************************************************************
3735 Utility function for UNIX getfacl.
3736 ****************************************************************************/
3738 static char *perms_to_string(fstring permstr, unsigned char perms)
3740 fstrcpy(permstr, "---");
3741 if (perms & SMB_POSIX_ACL_READ) {
3744 if (perms & SMB_POSIX_ACL_WRITE) {
3747 if (perms & SMB_POSIX_ACL_EXECUTE) {
3753 /****************************************************************************
3755 ****************************************************************************/
3757 static int cmd_getfacl(void)
3759 TALLOC_CTX *ctx = talloc_tos();
3762 char *targetname = NULL;
3763 struct cli_state *targetcli;
3764 uint16_t major, minor;
3765 uint32_t caplow, caphigh;
3766 char *retbuf = NULL;
3768 SMB_STRUCT_STAT sbuf;
3769 uint16_t num_file_acls = 0;
3770 uint16_t num_dir_acls = 0;
3774 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3775 d_printf("getfacl filename\n");
3778 src = talloc_asprintf(ctx,
3780 client_get_cur_dir(),
3785 src = client_clean_name(ctx, src);
3790 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3791 cli, src, &targetcli, &targetname);
3792 if (!NT_STATUS_IS_OK(status)) {
3793 d_printf("stat %s: %s\n", src, nt_errstr(status));
3797 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3798 d_printf("Server doesn't support UNIX CIFS calls.\n");
3802 status = cli_unix_extensions_version(targetcli, &major, &minor,
3804 if (!NT_STATUS_IS_OK(status)) {
3805 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3810 if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3811 d_printf("This server supports UNIX extensions "
3812 "but doesn't support POSIX ACLs.\n");
3816 status = cli_posix_stat(targetcli, targetname, &sbuf);
3817 if (!NT_STATUS_IS_OK(status)) {
3818 d_printf("%s getfacl doing a stat on file %s\n",
3819 nt_errstr(status), src);
3823 status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf);
3824 if (!NT_STATUS_IS_OK(status)) {
3825 d_printf("%s getfacl file %s\n",
3826 nt_errstr(status), src);
3830 /* ToDo : Print out the ACL values. */
3831 if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3832 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3833 src, (unsigned int)CVAL(retbuf,0) );
3837 num_file_acls = SVAL(retbuf,2);
3838 num_dir_acls = SVAL(retbuf,4);
3839 if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3840 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3842 (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3843 (unsigned int)rb_size);
3847 d_printf("# file: %s\n", src);
3848 d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3850 if (num_file_acls == 0 && num_dir_acls == 0) {
3851 d_printf("No acls found.\n");
3854 for (i = 0; i < num_file_acls; i++) {
3857 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3858 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3861 case SMB_POSIX_ACL_USER_OBJ:
3864 case SMB_POSIX_ACL_USER:
3865 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3866 d_printf("user:%u:", uorg);
3868 case SMB_POSIX_ACL_GROUP_OBJ:
3869 d_printf("group::");
3871 case SMB_POSIX_ACL_GROUP:
3872 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3873 d_printf("group:%u:", uorg);
3875 case SMB_POSIX_ACL_MASK:
3878 case SMB_POSIX_ACL_OTHER:
3879 d_printf("other::");
3882 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3883 src, (unsigned int)tagtype );
3888 d_printf("%s\n", perms_to_string(permstring, perms));
3891 for (i = 0; i < num_dir_acls; i++) {
3894 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3895 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3898 case SMB_POSIX_ACL_USER_OBJ:
3899 d_printf("default:user::");
3901 case SMB_POSIX_ACL_USER:
3902 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3903 d_printf("default:user:%u:", uorg);
3905 case SMB_POSIX_ACL_GROUP_OBJ:
3906 d_printf("default:group::");
3908 case SMB_POSIX_ACL_GROUP:
3909 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3910 d_printf("default:group:%u:", uorg);
3912 case SMB_POSIX_ACL_MASK:
3913 d_printf("default:mask::");
3915 case SMB_POSIX_ACL_OTHER:
3916 d_printf("default:other::");
3919 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3920 src, (unsigned int)tagtype );
3925 d_printf("%s\n", perms_to_string(permstring, perms));
3931 /****************************************************************************
3932 Get the EA list of a file
3933 ****************************************************************************/
3935 static int cmd_geteas(void)
3937 TALLOC_CTX *ctx = talloc_tos();
3940 char *targetname = NULL;
3941 struct cli_state *targetcli;
3944 struct ea_struct *eas;
3946 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3947 d_printf("geteas filename\n");
3950 src = talloc_asprintf(ctx,
3952 client_get_cur_dir(),
3957 src = client_clean_name(ctx, src);
3962 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3963 cli, src, &targetcli, &targetname);
3964 if (!NT_STATUS_IS_OK(status)) {
3965 d_printf("stat %s: %s\n", src, nt_errstr(status));
3969 status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
3971 if (!NT_STATUS_IS_OK(status)) {
3972 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
3976 for (i=0; i<num_eas; i++) {
3977 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
3978 dump_data_file(eas[i].value.data, eas[i].value.length, false,
3988 /****************************************************************************
3990 ****************************************************************************/
3992 static int cmd_setea(void)
3994 TALLOC_CTX *ctx = talloc_tos();
3997 char *eaname = NULL;
3998 char *eavalue = NULL;
3999 char *targetname = NULL;
4000 struct cli_state *targetcli;
4003 if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
4004 || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
4005 d_printf("setea filename eaname value\n");
4008 if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
4009 eavalue = talloc_strdup(ctx, "");
4011 src = talloc_asprintf(ctx,
4013 client_get_cur_dir(),
4018 src = client_clean_name(ctx, src);
4023 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4024 cli, src, &targetcli, &targetname);
4025 if (!NT_STATUS_IS_OK(status)) {
4026 d_printf("stat %s: %s\n", src, nt_errstr(status));
4030 status = cli_set_ea_path(targetcli, targetname, eaname, eavalue,
4032 if (!NT_STATUS_IS_OK(status)) {
4033 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
4040 /****************************************************************************
4042 ****************************************************************************/
4044 static int cmd_stat(void)
4046 TALLOC_CTX *ctx = talloc_tos();
4049 char *targetname = NULL;
4050 struct cli_state *targetcli;
4052 SMB_STRUCT_STAT sbuf;
4057 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4058 d_printf("stat file\n");
4061 src = talloc_asprintf(ctx,
4063 client_get_cur_dir(),
4068 src = client_clean_name(ctx, src);
4073 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4074 cli, src, &targetcli, &targetname);
4075 if (!NT_STATUS_IS_OK(status)) {
4076 d_printf("stat %s: %s\n", src, nt_errstr(status));
4080 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4081 d_printf("Server doesn't support UNIX CIFS calls.\n");
4085 status = cli_posix_stat(targetcli, targetname, &sbuf);
4086 if (!NT_STATUS_IS_OK(status)) {
4087 d_printf("%s stat file %s\n",
4088 nt_errstr(status), src);
4092 /* Print out the stat values. */
4093 d_printf("File: %s\n", src);
4094 d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
4095 (double)sbuf.st_ex_size,
4096 (unsigned int)sbuf.st_ex_blocks,
4097 filetype_to_str(sbuf.st_ex_mode));
4099 #if defined(S_ISCHR) && defined(S_ISBLK)
4100 if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
4101 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
4102 (double)sbuf.st_ex_ino,
4103 (unsigned int)sbuf.st_ex_nlink,
4104 unix_dev_major(sbuf.st_ex_rdev),
4105 unix_dev_minor(sbuf.st_ex_rdev));
4108 d_printf("Inode: %.0f\tLinks: %u\n",
4109 (double)sbuf.st_ex_ino,
4110 (unsigned int)sbuf.st_ex_nlink);
4112 d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
4113 ((int)sbuf.st_ex_mode & 0777),
4114 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
4115 (unsigned int)sbuf.st_ex_uid,
4116 (unsigned int)sbuf.st_ex_gid);
4118 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
4119 lt = localtime(&tmp_time);
4121 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4123 fstrcpy(mode_str, "unknown");
4125 d_printf("Access: %s\n", mode_str);
4127 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4128 lt = localtime(&tmp_time);
4130 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4132 fstrcpy(mode_str, "unknown");
4134 d_printf("Modify: %s\n", mode_str);
4136 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
4137 lt = localtime(&tmp_time);
4139 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4141 fstrcpy(mode_str, "unknown");
4143 d_printf("Change: %s\n", mode_str);
4149 /****************************************************************************
4151 ****************************************************************************/
4153 static int cmd_chown(void)
4155 TALLOC_CTX *ctx = talloc_tos();
4159 char *buf, *buf2, *buf3;
4160 struct cli_state *targetcli;
4161 char *targetname = NULL;
4164 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4165 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
4166 !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
4167 d_printf("chown uid gid file\n");
4171 uid = (uid_t)atoi(buf);
4172 gid = (gid_t)atoi(buf2);
4174 src = talloc_asprintf(ctx,
4176 client_get_cur_dir(),
4181 src = client_clean_name(ctx, src);
4185 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4186 cli, src, &targetcli, &targetname);
4187 if (!NT_STATUS_IS_OK(status)) {
4188 d_printf("chown %s: %s\n", src, nt_errstr(status));
4192 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4193 d_printf("Server doesn't support UNIX CIFS calls.\n");
4197 status = cli_posix_chown(targetcli, targetname, uid, gid);
4198 if (!NT_STATUS_IS_OK(status)) {
4199 d_printf("%s chown file %s uid=%d, gid=%d\n",
4200 nt_errstr(status), src, (int)uid, (int)gid);
4207 /****************************************************************************
4209 ****************************************************************************/
4211 static int cmd_rename(void)
4213 TALLOC_CTX *ctx = talloc_tos();
4216 struct cli_state *targetcli;
4220 bool replace = false;
4222 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4223 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4224 d_printf("rename <src> <dest> [-f]\n");
4228 src = talloc_asprintf(ctx,
4230 client_get_cur_dir(),
4235 src = client_clean_name(ctx, src);
4240 dest = talloc_asprintf(ctx,
4242 client_get_cur_dir(),
4247 dest = client_clean_name(ctx, dest);
4252 if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
4253 strcsequal(buf, "-f")) {
4257 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4258 cli, src, &targetcli, &targetsrc);
4259 if (!NT_STATUS_IS_OK(status)) {
4260 d_printf("rename %s: %s\n", src, nt_errstr(status));
4264 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4265 cli, dest, &targetcli, &targetdest);
4266 if (!NT_STATUS_IS_OK(status)) {
4267 d_printf("rename %s: %s\n", dest, nt_errstr(status));
4271 status = cli_rename(targetcli, targetsrc, targetdest, replace);
4272 if (!NT_STATUS_IS_OK(status)) {
4273 d_printf("%s renaming files %s -> %s \n",
4283 struct scopy_timing {
4284 struct timespec tp_start;
4287 static int scopy_status(off_t written, void *priv)
4289 struct timespec tp_end;
4290 unsigned int scopy_total_time_ms;
4291 struct scopy_timing *st = priv;
4293 clock_gettime_mono(&tp_end);
4294 scopy_total_time_ms = nsec_time_diff(&tp_end,&st->tp_start)/1000000;
4296 DEBUG(5,("Copied %jd bytes at an average %3.1f kb/s\n",
4297 (intmax_t)written, written / (1.024*scopy_total_time_ms)));
4302 /****************************************************************************
4303 Server-Side copy some file.
4304 ****************************************************************************/
4306 static int cmd_scopy(void)
4308 TALLOC_CTX *ctx = talloc_tos();
4311 struct cli_state *targetcli;
4314 uint32_t DesiredAccess, ShareAccess, CreateDisposition, CreateOptions;
4315 struct smb_create_returns cr;
4316 uint16_t destfnum = (uint16_t)-1;
4317 uint16_t srcfnum = (uint16_t)-1;
4319 struct scopy_timing st;
4323 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4324 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4325 d_printf("scopy <src> <dest>\n");
4329 src = talloc_asprintf(ctx,
4331 client_get_cur_dir(),
4336 src = client_clean_name(ctx, src);
4341 dest = talloc_asprintf(ctx,
4343 client_get_cur_dir(),
4348 dest = client_clean_name(ctx, dest);
4353 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4354 cli, src, &targetcli, &targetsrc);
4355 if (!NT_STATUS_IS_OK(status)) {
4356 d_printf("scopy %s: %s\n", src, nt_errstr(status));
4360 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4361 cli, dest, &targetcli, &targetdest);
4362 if (!NT_STATUS_IS_OK(status)) {
4363 d_printf("scopy %s: %s\n", dest, nt_errstr(status));
4368 DesiredAccess = (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|
4369 READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS);
4370 ShareAccess = FILE_SHARE_READ|FILE_SHARE_DELETE;
4371 CreateDisposition = FILE_OPEN;
4372 CreateOptions = (FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE|
4373 FILE_OPEN_REPARSE_POINT);
4374 status = cli_ntcreate(targetcli, targetsrc, 0, DesiredAccess, 0,
4375 ShareAccess, CreateDisposition, CreateOptions, 0x0,
4377 if (!NT_STATUS_IS_OK(status)) {
4378 d_printf("Failed to open file %s. %s\n",
4379 targetsrc, nt_errstr(status));
4383 DesiredAccess = (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|
4384 FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|
4385 DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|SYNCHRONIZE_ACCESS);
4386 ShareAccess = FILE_SHARE_NONE;
4387 CreateDisposition = FILE_CREATE;
4388 CreateOptions = FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE;
4389 status = cli_ntcreate(targetcli, targetdest, 0, DesiredAccess,
4390 FILE_ATTRIBUTE_ARCHIVE, ShareAccess, CreateDisposition,
4391 CreateOptions, 0x0, &destfnum, NULL);
4392 if (!NT_STATUS_IS_OK(status)) {
4393 d_printf("Failed to create file %s. %s\n",
4394 targetdest, nt_errstr(status));
4395 cli_close(targetcli, srcfnum);
4399 clock_gettime_mono(&st.tp_start);
4400 status = cli_splice(targetcli, targetcli, srcfnum, destfnum,
4401 cr.end_of_file, 0, 0, &written, scopy_status, &st);
4402 if (!NT_STATUS_IS_OK(status)) {
4403 d_printf("%s copying file %s -> %s \n",
4410 status = cli_close(targetcli, srcfnum);
4411 if (!NT_STATUS_IS_OK(status)) {
4412 d_printf("Error %s closing remote source file\n", nt_errstr(status));
4415 status = cli_close(targetcli, destfnum);
4416 if (!NT_STATUS_IS_OK(status)) {
4417 d_printf("Error %s closing remote dest file\n", nt_errstr(status));
4424 /****************************************************************************
4425 Print the volume name.
4426 ****************************************************************************/
4428 static int cmd_volume(void)
4431 uint32_t serial_num;
4435 status = cli_get_fs_volume_info(cli, talloc_tos(),
4436 &volname, &serial_num,
4438 if (!NT_STATUS_IS_OK(status)) {
4439 d_printf("Error %s getting volume info\n", nt_errstr(status));
4443 d_printf("Volume: |%s| serial number 0x%x\n",
4444 volname, (unsigned int)serial_num);
4448 /****************************************************************************
4449 Hard link files using the NT call.
4450 ****************************************************************************/
4452 static int cmd_hardlink(void)
4454 TALLOC_CTX *ctx = talloc_tos();
4457 struct cli_state *targetcli;
4461 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4462 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4463 d_printf("hardlink <src> <dest>\n");
4467 src = talloc_asprintf(ctx,
4469 client_get_cur_dir(),
4474 src = client_clean_name(ctx, src);
4479 dest = talloc_asprintf(ctx,
4481 client_get_cur_dir(),
4486 dest = client_clean_name(ctx, dest);
4491 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4492 cli, src, &targetcli, &targetname);
4493 if (!NT_STATUS_IS_OK(status)) {
4494 d_printf("hardlink %s: %s\n", src, nt_errstr(status));
4498 status = cli_hardlink(targetcli, targetname, dest);
4499 if (!NT_STATUS_IS_OK(status)) {
4500 d_printf("%s doing an NT hard link of files\n",
4508 /****************************************************************************
4509 Toggle the prompt flag.
4510 ****************************************************************************/
4512 static int cmd_prompt(void)
4515 DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
4519 /****************************************************************************
4520 Set the newer than time.
4521 ****************************************************************************/
4523 static int cmd_newer(void)
4525 TALLOC_CTX *ctx = talloc_tos();
4528 SMB_STRUCT_STAT sbuf;
4530 ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
4531 if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
4532 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4533 DEBUG(1,("Getting files newer than %s",
4534 time_to_asc(newer_than)));
4539 if (ok && newer_than == 0) {
4540 d_printf("Error setting newer-than time\n");
4547 /****************************************************************************
4548 Watch directory changes
4549 ****************************************************************************/
4551 static int cmd_notify(void)
4553 TALLOC_CTX *frame = talloc_stackframe();
4558 name = talloc_strdup(talloc_tos(), client_get_cur_dir());
4562 if (!next_token_talloc(talloc_tos(), &cmd_ptr, &buf, NULL)) {
4565 name = talloc_asprintf_append(name, "%s", buf);
4569 name = client_clean_name(talloc_tos(), name);
4573 status = cli_ntcreate(
4574 cli, name, 0, FILE_READ_DATA, 0,
4575 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
4576 FILE_OPEN, 0, 0, &fnum, NULL);
4577 if (!NT_STATUS_IS_OK(status)) {
4578 d_printf("Could not open file: %s\n", nt_errstr(status));
4584 uint32_t num_changes = 0;
4585 struct notify_change *changes = NULL;
4587 status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
4589 talloc_tos(), &num_changes, &changes);
4590 if (NT_STATUS_EQUAL(status, STATUS_NOTIFY_ENUM_DIR)) {
4591 printf("NOTIFY_ENUM_DIR\n");
4592 status = NT_STATUS_OK;
4594 if (!NT_STATUS_IS_OK(status)) {
4595 d_printf("notify returned %s\n",
4599 for (i=0; i<num_changes; i++) {
4600 printf("%4.4x %s\n", changes[i].action,
4603 TALLOC_FREE(changes);
4606 d_printf("notify <dir name>\n");
4612 /****************************************************************************
4613 Set the archive level.
4614 ****************************************************************************/
4616 static int cmd_archive(void)
4618 TALLOC_CTX *ctx = talloc_tos();
4621 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4622 archive_level = atoi(buf);
4624 d_printf("Archive level is %d\n",archive_level);
4630 /****************************************************************************
4631 Toggle the backup_intent state.
4632 ****************************************************************************/
4634 static int cmd_backup(void)
4636 backup_intent = !backup_intent;
4637 cli_set_backup_intent(cli, backup_intent);
4638 DEBUG(2,("backup intent is now %s\n",backup_intent?"on":"off"));
4642 /****************************************************************************
4643 Toggle the lowercaseflag.
4644 ****************************************************************************/
4646 static int cmd_lowercase(void)
4648 lowercase = !lowercase;
4649 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
4653 /****************************************************************************
4654 Toggle the case sensitive flag.
4655 ****************************************************************************/
4657 static int cmd_setcase(void)
4659 bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
4661 cli_set_case_sensitive(cli, !orig_case_sensitive);
4662 DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
4667 /****************************************************************************
4668 Toggle the showacls flag.
4669 ****************************************************************************/
4671 static int cmd_showacls(void)
4673 showacls = !showacls;
4674 DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
4679 /****************************************************************************
4680 Toggle the recurse flag.
4681 ****************************************************************************/
4683 static int cmd_recurse(void)
4686 DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
4690 /****************************************************************************
4691 Toggle the translate flag.
4692 ****************************************************************************/
4694 static int cmd_translate(void)
4696 translation = !translation;
4697 DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
4698 translation?"on":"off"));
4702 /****************************************************************************
4704 ****************************************************************************/
4706 static int cmd_lcd(void)
4708 TALLOC_CTX *ctx = talloc_tos();
4712 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4713 if (chdir(buf) == -1) {
4714 d_printf("chdir to %s failed (%s)\n",
4715 buf, strerror(errno));
4722 DEBUG(2,("the local directory is now %s\n",d));
4727 /****************************************************************************
4728 Get a file restarting at end of local file.
4729 ****************************************************************************/
4731 static int cmd_reget(void)
4733 TALLOC_CTX *ctx = talloc_tos();
4734 char *local_name = NULL;
4735 char *remote_name = NULL;
4739 remote_name = talloc_strdup(ctx, client_get_cur_dir());
4744 if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
4745 d_printf("reget <filename>\n");
4748 remote_name = talloc_asprintf_append(remote_name, "%s", fname);
4752 remote_name = client_clean_name(ctx,remote_name);
4758 next_token_talloc(ctx, &cmd_ptr, &p, NULL);
4763 return do_get(remote_name, local_name, true);
4766 /****************************************************************************
4767 Put a file restarting at end of local file.
4768 ****************************************************************************/
4770 static int cmd_reput(void)
4772 TALLOC_CTX *ctx = talloc_tos();
4773 char *local_name = NULL;
4774 char *remote_name = NULL;
4778 remote_name = talloc_strdup(ctx, client_get_cur_dir());
4783 if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
4784 d_printf("reput <filename>\n");
4788 if (!file_exist_stat(local_name, &st, false)) {
4789 d_printf("%s does not exist\n", local_name);
4793 if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
4794 remote_name = talloc_asprintf_append(remote_name,
4797 remote_name = talloc_asprintf_append(remote_name,
4804 remote_name = client_clean_name(ctx, remote_name);
4809 return do_put(remote_name, local_name, true);
4812 /****************************************************************************
4814 ****************************************************************************/
4816 static void browse_fn(const char *name, uint32_t m,
4817 const char *comment, void *state)
4819 const char *typestr = "";
4822 case STYPE_DISKTREE:
4826 typestr = "Printer";
4835 /* FIXME: If the remote machine returns non-ascii characters
4836 in any of these fields, they can corrupt the output. We
4837 should remove them. */
4839 d_printf("\t%-15s %-10.10s%s\n",
4840 name,typestr,comment);
4842 d_printf ("%s|%s|%s\n",typestr,name,comment);
4846 static bool browse_host_rpc(bool sort)
4849 struct rpc_pipe_client *pipe_hnd = NULL;
4850 TALLOC_CTX *frame = talloc_stackframe();
4852 struct srvsvc_NetShareInfoCtr info_ctr;
4853 struct srvsvc_NetShareCtr1 ctr1;
4854 uint32_t resume_handle = 0;
4855 uint32_t total_entries = 0;
4857 struct dcerpc_binding_handle *b;
4859 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
4862 if (!NT_STATUS_IS_OK(status)) {
4863 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
4864 nt_errstr(status)));
4869 b = pipe_hnd->binding_handle;
4871 ZERO_STRUCT(info_ctr);
4875 info_ctr.ctr.ctr1 = &ctr1;
4877 status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
4885 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4886 TALLOC_FREE(pipe_hnd);
4891 for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4892 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4893 browse_fn(info.name, info.type, info.comment, NULL);
4896 TALLOC_FREE(pipe_hnd);
4901 /****************************************************************************
4902 Try and browse available connections on a host.
4903 ****************************************************************************/
4905 static bool browse_host(bool sort)
4910 d_printf("\n\tSharename Type Comment\n");
4911 d_printf("\t--------- ---- -------\n");
4914 if (browse_host_rpc(sort)) {
4918 if (lp_client_min_protocol() > PROTOCOL_NT1) {
4922 if (smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1) {
4926 ret = cli_RNetShareEnum(cli, browse_fn, NULL);
4928 NTSTATUS status = cli_nt_error(cli);
4929 d_printf("Error returning browse list: %s\n",
4936 /****************************************************************************
4938 ****************************************************************************/
4940 static void server_fn(const char *name, uint32_t m,
4941 const char *comment, void *state)
4945 d_printf("\t%-16s %s\n", name, comment);
4947 d_printf("%s|%s|%s\n",(char *)state, name, comment);
4951 /****************************************************************************
4952 Try and browse available connections on a host.
4953 ****************************************************************************/
4955 static bool list_servers(const char *wk_grp)
4959 if (!cli->server_domain)
4963 d_printf("\n\tServer Comment\n");
4964 d_printf("\t--------- -------\n");
4966 fstrcpy( state, "Server" );
4967 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
4971 d_printf("\n\tWorkgroup Master\n");
4972 d_printf("\t--------- -------\n");
4975 fstrcpy( state, "Workgroup" );
4976 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
4981 /****************************************************************************
4982 Print or set current VUID
4983 ****************************************************************************/
4985 static int cmd_vuid(void)
4987 TALLOC_CTX *ctx = talloc_tos();
4990 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4991 d_printf("Current VUID is %d\n",
4992 cli_state_get_uid(cli));
4996 cli_state_set_uid(cli, atoi(buf));
5000 /****************************************************************************
5001 Setup a new VUID, by issuing a session setup
5002 ****************************************************************************/
5004 static int cmd_logon(void)
5006 TALLOC_CTX *ctx = talloc_tos();
5007 char *l_username, *l_password;
5008 struct cli_credentials *creds = NULL;
5011 if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
5012 d_printf("logon <username> [<password>]\n");
5016 if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
5017 char pwd[256] = {0};
5020 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
5022 l_password = talloc_strdup(ctx, pwd);
5029 creds = cli_session_creds_init(ctx,
5034 false, /* use_kerberos */
5035 false, /* fallback_after_kerberos */
5036 false, /* use_ccache */
5037 false); /* password_is_nt_hash */
5038 if (creds == NULL) {
5039 d_printf("cli_session_creds_init() failed.\n");
5042 nt_status = cli_session_setup_creds(cli, creds);
5044 if (!NT_STATUS_IS_OK(nt_status)) {
5045 d_printf("session setup failed: %s\n", nt_errstr(nt_status));
5049 d_printf("Current VUID is %d\n", cli_state_get_uid(cli));
5057 static int cmd_logoff(void)
5061 status = cli_ulogoff(cli);
5062 if (!NT_STATUS_IS_OK(status)) {
5063 d_printf("logoff failed: %s\n", nt_errstr(status));
5067 d_printf("logoff successful\n");
5073 * tree connect (connect to a share)
5076 static int cmd_tcon(void)
5078 TALLOC_CTX *ctx = talloc_tos();
5082 if (!next_token_talloc(ctx, &cmd_ptr, &sharename, NULL)) {
5083 d_printf("tcon <sharename>\n");
5091 status = cli_tree_connect(cli, sharename, "?????", NULL);
5092 if (!NT_STATUS_IS_OK(status)) {
5093 d_printf("tcon failed: %s\n", nt_errstr(status));
5097 talloc_free(sharename);
5099 d_printf("tcon to %s successful, tid: %u\n", sharename,
5100 cli_state_get_tid(cli));
5105 * tree disconnect (disconnect from a share)
5108 static int cmd_tdis(void)
5112 status = cli_tdis(cli);
5113 if (!NT_STATUS_IS_OK(status)) {
5114 d_printf("tdis failed: %s\n", nt_errstr(status));
5118 d_printf("tdis successful\n");
5127 static int cmd_tid(void)
5129 TALLOC_CTX *ctx = talloc_tos();
5132 if (!next_token_talloc(ctx, &cmd_ptr, &tid_str, NULL)) {
5133 if (cli_state_has_tcon(cli)) {
5134 d_printf("current tid is %d\n", cli_state_get_tid(cli));
5136 d_printf("no tcon currently\n");
5139 uint32_t tid = atoi(tid_str);
5140 if (!cli_state_has_tcon(cli)) {
5141 d_printf("no tcon currently\n");
5143 cli_state_set_tid(cli, tid);
5150 /****************************************************************************
5151 list active connections
5152 ****************************************************************************/
5154 static int cmd_list_connect(void)
5156 cli_cm_display(cli);
5160 /****************************************************************************
5161 display the current active client connection
5162 ****************************************************************************/
5164 static int cmd_show_connect( void )
5166 TALLOC_CTX *ctx = talloc_tos();
5167 struct cli_state *targetcli;
5171 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), cli,
5172 client_get_cur_dir(), &targetcli,
5174 if (!NT_STATUS_IS_OK(status)) {
5175 d_printf("showconnect %s: %s\n", cur_dir, nt_errstr(status));
5179 d_printf("//%s/%s\n", smbXcli_conn_remote_name(targetcli->conn), targetcli->share);
5184 * set_remote_times - set times of a remote file
5185 * @filename: path to the file name
5186 * @create_time: New create time
5187 * @access_time: New access time
5188 * @write_time: New write time
5189 * @change_time: New metadata change time
5191 * Update the file times with the ones provided.
5193 static int set_remote_times(const char *filename,
5194 struct timespec *create_time,
5195 struct timespec *access_time,
5196 struct timespec *write_time,
5197 struct timespec *change_time)
5199 extern struct cli_state *cli;
5202 status = cli_setpathinfo_ext(cli,
5209 if (!NT_STATUS_IS_OK(status)) {
5210 d_printf("cli_setpathinfo_basic failed: %s\n",
5219 * cmd_utimes - interactive command to set the four times
5221 * Read a filename and four times from the client command line and update
5222 * the file times. A value of -1 for a time means don't change.
5224 static int cmd_utimes(void)
5228 struct timespec times[4] = {{0}};
5229 struct timeval_buf tbuf[4];
5233 TALLOC_CTX *ctx = talloc_new(NULL);
5238 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5240 d_printf("utimes <filename> <create-time> <access-time> "
5241 "<write-time> <change-time>\n");
5242 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5243 "or -1 for no change\n");
5248 fname = talloc_asprintf(ctx,
5250 client_get_cur_dir(),
5252 if (fname == NULL) {
5256 fname = client_clean_name(ctx, fname);
5257 if (fname == NULL) {
5262 while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
5264 const char *s = buf;
5265 struct tm tm = {0,};
5269 if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
5270 times[time_count] = make_omit_timespec();
5274 ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
5277 /* We could not match all the chars, so print error */
5278 if (ret == NULL || *ret != 0) {
5279 d_printf("Invalid date format: %s\n", s);
5280 d_printf("utimes <filename> <create-time> "
5281 "<access-time> <write-time> <change-time>\n");
5282 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5283 "or -1 for no change\n");
5288 /* Convert tm to a time_t */
5290 times[time_count] = (struct timespec){.tv_sec = t};
5294 if (time_count < 4) {
5295 d_printf("Insufficient dates: %d\n", time_count);
5296 d_printf("utimes <filename> <create-time> <access-time> "
5297 "<write-time> <change-time>\n");
5298 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5299 "or -1 for no change\n");
5304 DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
5305 timespec_string_buf(×[0], false, &tbuf[0]),
5306 timespec_string_buf(×[1], false, &tbuf[1]),
5307 timespec_string_buf(×[2], false, &tbuf[2]),
5308 timespec_string_buf(×[3], false, &tbuf[3])));
5310 set_remote_times(fname, ×[0], ×[1], ×[2], ×[3]);
5317 * set_remote_attr - set DOS attributes of a remote file
5318 * @filename: path to the file name
5319 * @new_attr: attribute bit mask to use
5320 * @mode: one of ATTR_SET or ATTR_UNSET
5322 * Update the file attributes with the one provided.
5324 int set_remote_attr(const char *filename, uint16_t new_attr, int mode)
5326 extern struct cli_state *cli;
5330 status = cli_getatr(cli, filename, &old_attr, NULL, NULL);
5331 if (!NT_STATUS_IS_OK(status)) {
5332 d_printf("cli_getatr failed: %s\n", nt_errstr(status));
5336 if (mode == ATTR_SET) {
5337 new_attr |= old_attr;
5339 new_attr = old_attr & ~new_attr;
5342 status = cli_setatr(cli, filename, new_attr, 0);
5343 if (!NT_STATUS_IS_OK(status)) {
5344 d_printf("cli_setatr failed: %s\n", nt_errstr(status));
5352 * cmd_setmode - interactive command to set DOS attributes
5354 * Read a filename and mode from the client command line and update
5355 * the file DOS attributes.
5357 int cmd_setmode(void)
5361 uint16_t attr[2] = {0};
5362 int mode = ATTR_SET;
5365 TALLOC_CTX *ctx = talloc_new(NULL);
5370 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5372 d_printf("setmode <filename> <[+|-]rsha>\n");
5377 fname = talloc_asprintf(ctx,
5379 client_get_cur_dir(),
5381 if (fname == NULL) {
5385 fname = client_clean_name(ctx, fname);
5386 if (fname == NULL) {
5391 while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
5392 const char *s = buf;
5403 attr[mode] |= FILE_ATTRIBUTE_READONLY;
5406 attr[mode] |= FILE_ATTRIBUTE_HIDDEN;
5409 attr[mode] |= FILE_ATTRIBUTE_SYSTEM;
5412 attr[mode] |= FILE_ATTRIBUTE_ARCHIVE;
5415 d_printf("setmode <filename> <perm=[+|-]rsha>\n");
5422 if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) {
5423 d_printf("setmode <filename> <[+|-]rsha>\n");
5428 DEBUG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET]));
5430 /* ignore return value: server might not store DOS attributes */
5431 set_remote_attr(fname, attr[ATTR_SET], ATTR_SET);
5432 set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET);
5438 /****************************************************************************
5440 ***************************************************************************/
5442 int cmd_iosize(void)
5444 TALLOC_CTX *ctx = talloc_tos();
5448 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5449 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5451 d_printf("iosize <n> or iosize 0x<n>. "
5452 "Minimum is 0 (default), "
5453 "max is 16776960 (0xFFFF00)\n");
5455 d_printf("iosize <n> or iosize 0x<n>. "
5456 "(Encrypted connection) ,"
5457 "Minimum is 0 (default), "
5458 "max is 130048 (0x1FC00)\n");
5461 d_printf("iosize <n> or iosize 0x<n>.\n");
5466 iosize = strtol(buf,NULL,0);
5467 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5468 if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) {
5469 d_printf("iosize out of range for encrypted "
5470 "connection (min = 0 (default), "
5471 "max = 130048 (0x1FC00)\n");
5473 } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) {
5474 d_printf("iosize out of range (min = 0 (default), "
5475 "max = 16776960 (0xFFFF00)\n");
5480 io_bufsize = iosize;
5481 d_printf("iosize is now %d\n", io_bufsize);
5485 /****************************************************************************
5487 ***************************************************************************/
5489 static int cmd_timeout(void)
5491 TALLOC_CTX *ctx = talloc_tos();
5494 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5495 unsigned int old_timeout = cli_set_timeout(cli, 0);
5496 cli_set_timeout(cli, old_timeout);
5497 d_printf("timeout <n> (per-operation timeout "
5498 "in seconds - currently %u).\n",
5503 io_timeout = strtol(buf,NULL,0);
5504 cli_set_timeout(cli, io_timeout*1000);
5505 d_printf("io_timeout per operation is now %d\n", io_timeout);
5510 /****************************************************************************
5512 ****************************************************************************/
5513 static int cmd_history(void)
5515 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
5519 hlist = history_list();
5521 for (i = 0; hlist && hlist[i]; i++) {
5522 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
5525 DEBUG(0,("no history without readline support\n"));
5531 /* Some constants for completing filename arguments */
5533 #define COMPL_NONE 0 /* No completions */
5534 #define COMPL_REMOTE 1 /* Complete remote filename */
5535 #define COMPL_LOCAL 2 /* Complete local filename */
5537 /* This defines the commands supported by this client.
5538 * NOTE: The "!" must be the last one in the list because it's fn pointer
5539 * field is NULL, and NULL in that field is used in process_tok()
5540 * (below) to indicate the end of the list. crh
5545 const char *description;
5546 char compl_args[2]; /* Completion argument info */
5548 {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5549 {"allinfo",cmd_allinfo,"<file> show all available info",
5550 {COMPL_REMOTE,COMPL_NONE}},
5551 {"altname",cmd_altname,"<file> show alt name",{COMPL_REMOTE,COMPL_NONE}},
5552 {"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}},
5553 {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}},
5554 {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
5555 {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
5556 {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
5557 {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
5558 {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_NONE}},
5559 {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_NONE}},
5560 {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_NONE}},
5561 {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5562 {"deltree",cmd_deltree,"<mask> recursively delete all matching files and directories",{COMPL_REMOTE,COMPL_NONE}},
5563 {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5564 {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5565 {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
5566 {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5567 {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
5568 {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_NONE}},
5569 {"geteas", cmd_geteas, "<file name> get the EA list of a file",
5570 {COMPL_REMOTE, COMPL_NONE}},
5571 {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5572 {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5573 {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
5574 {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
5575 {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
5576 {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5577 {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5578 {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
5579 {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5580 {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5581 {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
5582 {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5583 {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
5584 {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5585 {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
5586 {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
5587 {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
5588 {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}},
5589 {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
5590 {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
5591 {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
5592 {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5593 {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5594 {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5595 {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5596 {"posix_whoami",cmd_posix_whoami,"return logged on user information "
5597 "using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5598 {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
5599 {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
5600 {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
5601 {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
5602 {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5603 {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
5604 {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5605 {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5606 {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
5607 {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
5608 {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
5609 {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
5610 {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
5611 {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5612 {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_REMOTE,COMPL_NONE}},
5613 {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},
5614 {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
5615 {COMPL_REMOTE, COMPL_LOCAL}},
5616 {"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
5617 {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
5618 {"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
5619 {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5620 {"tar",cmd_tar,"tar <c|x>[IXFvbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
5621 {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
5622 {"timeout",cmd_timeout,"timeout <number> - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}},
5623 {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
5624 {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5625 {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
5626 {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
5627 {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5628 {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
5629 {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
5630 {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
5631 {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
5632 {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
5633 {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
5634 {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
5635 "<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
5636 {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
5637 {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
5639 /* Yes, this must be here, see crh's comment above. */
5640 {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
5641 {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
5644 /*******************************************************************
5645 Lookup a command string in the list of commands, including
5647 ******************************************************************/
5649 static int process_tok(char *tok)
5651 size_t i = 0, matches = 0;
5653 size_t tok_len = strlen(tok);
5655 while (commands[i].fn != NULL) {
5656 if (strequal(commands[i].name,tok)) {
5660 } else if (strnequal(commands[i].name, tok, tok_len)) {
5669 else if (matches == 1)
5675 /****************************************************************************
5677 ****************************************************************************/
5679 static int cmd_help(void)
5681 TALLOC_CTX *ctx = talloc_tos();
5685 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5686 if ((i = process_tok(buf)) >= 0)
5687 d_printf("HELP %s:\n\t%s\n\n",
5688 commands[i].name,commands[i].description);
5690 while (commands[i].description) {
5691 for (j=0; commands[i].description && (j<5); j++) {
5692 d_printf("%-15s",commands[i].name);
5701 /****************************************************************************
5702 Process a -c command string.
5703 ****************************************************************************/
5705 static int process_command_string(const char *cmd_in)
5707 TALLOC_CTX *ctx = talloc_tos();
5708 char *cmd = talloc_strdup(ctx, cmd_in);
5714 /* establish the connection if not already */
5719 status = cli_cm_open(talloc_tos(), NULL,
5721 service, popt_get_cmdline_auth_info(),
5724 have_ip ? &dest_ss : NULL, port,
5727 if (!NT_STATUS_IS_OK(status)) {
5730 cli_set_timeout(cli, io_timeout*1000);
5733 while (cmd[0] != '\0') {
5739 if ((p = strchr_m(cmd, ';')) == 0) {
5748 /* and get the first part of the command */
5750 if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
5754 if ((i = process_tok(tok)) >= 0) {
5755 rc = commands[i].fn();
5756 } else if (i == -2) {
5757 d_printf("%s: command abbreviation ambiguous\n",tok);
5759 d_printf("%s: command not found\n",tok);
5766 #define MAX_COMPLETIONS 100
5768 struct completion_remote {
5776 static NTSTATUS completion_remote_filter(const char *mnt,
5777 struct file_info *f,
5781 struct completion_remote *info = (struct completion_remote *)state;
5783 if (info->count >= MAX_COMPLETIONS - 1) {
5784 return NT_STATUS_OK;
5786 if (strncmp(info->text, f->name, info->len) != 0) {
5787 return NT_STATUS_OK;
5789 if (ISDOT(f->name) || ISDOTDOT(f->name)) {
5790 return NT_STATUS_OK;
5793 if ((info->dirmask[0] == 0) && !(f->mode & FILE_ATTRIBUTE_DIRECTORY))
5794 info->matches[info->count] = SMB_STRDUP(f->name);
5796 TALLOC_CTX *ctx = talloc_stackframe();
5799 tmp = talloc_strdup(ctx,info->dirmask);
5802 return NT_STATUS_NO_MEMORY;
5804 tmp = talloc_asprintf_append(tmp, "%s", f->name);
5807 return NT_STATUS_NO_MEMORY;
5809 if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
5810 tmp = talloc_asprintf_append(tmp, "%s",
5815 return NT_STATUS_NO_MEMORY;
5817 info->matches[info->count] = SMB_STRDUP(tmp);
5820 if (info->matches[info->count] == NULL) {
5821 return NT_STATUS_OK;
5823 if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
5824 smb_readline_ca_char(0);
5826 if (info->count == 1) {
5827 info->samelen = strlen(info->matches[info->count]);
5829 while (strncmp(info->matches[info->count],
5830 info->matches[info->count-1],
5831 info->samelen) != 0) {
5836 return NT_STATUS_OK;
5839 static char **remote_completion(const char *text, int len)
5841 TALLOC_CTX *ctx = talloc_stackframe();
5842 char *dirmask = NULL;
5843 char *targetpath = NULL;
5844 struct cli_state *targetcli = NULL;
5846 struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
5849 /* can't have non-static initialisation on Sun CC, so do it
5855 info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
5856 if (!info.matches) {
5862 * We're leaving matches[0] free to fill it later with the text to
5863 * display: Either the one single match or the longest common subset
5866 info.matches[0] = NULL;
5869 for (i = len-1; i >= 0; i--) {
5870 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
5875 info.text = text+i+1;
5876 info.samelen = info.len = len-i-1;
5879 info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
5880 if (!info.dirmask) {
5883 strncpy(info.dirmask, text, i+1);
5884 info.dirmask[i+1] = 0;
5885 dirmask = talloc_asprintf(ctx,
5887 client_get_cur_dir(),
5891 info.dirmask = SMB_STRDUP("");
5892 if (!info.dirmask) {
5895 dirmask = talloc_asprintf(ctx,
5897 client_get_cur_dir());
5902 dirmask = client_clean_name(ctx, dirmask);
5903 if (dirmask == NULL) {
5907 status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
5908 cli, dirmask, &targetcli, &targetpath);
5909 if (!NT_STATUS_IS_OK(status)) {
5912 status = cli_list(targetcli, targetpath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5913 completion_remote_filter, (void *)&info);
5914 if (!NT_STATUS_IS_OK(status)) {
5918 if (info.count == 1) {
5920 * No matches at all, NULL indicates there is nothing
5922 SAFE_FREE(info.matches[0]);
5923 SAFE_FREE(info.matches);
5928 if (info.count == 2) {
5930 * Exactly one match in matches[1], indicate this is the one
5933 info.matches[0] = info.matches[1];
5934 info.matches[1] = NULL;
5937 return info.matches;
5941 * We got more than one possible match, set the result to the maximum
5945 info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
5946 info.matches[info.count] = NULL;
5948 return info.matches;
5951 for (i = 0; i < info.count; i++) {
5952 SAFE_FREE(info.matches[i]);
5954 SAFE_FREE(info.matches);
5955 SAFE_FREE(info.dirmask);
5960 static char **completion_fn(const char *text, int start, int end)
5962 smb_readline_ca_char(' ');
5965 const char *buf, *sp;
5969 buf = smb_readline_get_line_buffer();
5973 sp = strchr(buf, ' ');
5977 for (i = 0; commands[i].name; i++) {
5978 if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
5979 (commands[i].name[sp - buf] == 0)) {
5983 if (commands[i].name == NULL)
5989 if (sp == (buf + start))
5990 compl_type = commands[i].compl_args[0];
5992 compl_type = commands[i].compl_args[1];
5994 if (compl_type == COMPL_REMOTE)
5995 return remote_completion(text, end - start);
5996 else /* fall back to local filename completion */
6000 size_t i, len, samelen = 0, count=1;
6002 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
6009 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
6010 if (strncmp(text, commands[i].name, len) == 0) {
6011 matches[count] = SMB_STRDUP(commands[i].name);
6012 if (!matches[count])
6015 samelen = strlen(matches[count]);
6017 while (strncmp(matches[count], matches[count-1], samelen) != 0)
6024 case 0: /* should never happen */
6028 matches[0] = SMB_STRDUP(matches[1]);
6031 matches[0] = (char *)SMB_MALLOC(samelen+1);
6034 strncpy(matches[0], matches[1], samelen);
6035 matches[0][samelen] = 0;
6037 matches[count] = NULL;
6041 for (i = 0; i < count; i++)
6049 static bool finished;
6051 /****************************************************************************
6052 Make sure we swallow keepalives during idle time.
6053 ****************************************************************************/
6055 static void readline_callback(void)
6057 static time_t last_t;
6058 struct timespec now;
6061 unsigned char garbage[16];
6063 clock_gettime_mono(&now);
6071 /* Ping the server to keep the connection alive using SMBecho. */
6072 memset(garbage, 0xf0, sizeof(garbage));
6073 status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
6074 if (NT_STATUS_IS_OK(status) ||
6075 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
6077 * Even if server returns NT_STATUS_INVALID_PARAMETER
6078 * it still responded.
6079 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
6084 if (!cli_state_is_connected(cli)) {
6085 DEBUG(0,("SMBecho failed (%s). The connection is "
6086 "disconnected now\n", nt_errstr(status)));
6088 smb_readline_done();
6092 /****************************************************************************
6093 Process commands on stdin.
6094 ****************************************************************************/
6096 static int process_stdin(void)
6101 d_printf("Try \"help\" to get a list of possible commands.\n");
6105 TALLOC_CTX *frame = talloc_stackframe();
6107 char *the_prompt = NULL;
6111 /* display a prompt */
6112 if (asprintf(&the_prompt, "smb: %s> ", client_get_cur_dir()) < 0) {
6116 line = smb_readline(the_prompt, readline_callback, completion_fn);
6117 SAFE_FREE(the_prompt);
6123 /* special case - first char is ! */
6125 if (system(line + 1) == -1) {
6126 d_printf("system() command %s failed.\n",
6134 /* and get the first part of the command */
6136 if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
6142 if ((i = process_tok(tok)) >= 0) {
6143 rc = commands[i].fn();
6144 } else if (i == -2) {
6145 d_printf("%s: command abbreviation ambiguous\n",tok);
6147 d_printf("%s: command not found\n",tok);
6155 /****************************************************************************
6156 Process commands from the client.
6157 ****************************************************************************/
6159 static int process(const char *base_directory)
6164 status = cli_cm_open(talloc_tos(), NULL,
6166 service, popt_get_cmdline_auth_info(),
6167 smb_encrypt, max_protocol,
6168 have_ip ? &dest_ss : NULL, port,
6170 if (!NT_STATUS_IS_OK(status)) {
6174 cli_set_timeout(cli, io_timeout*1000);
6176 if (base_directory && *base_directory) {
6177 rc = do_cd(base_directory);
6185 rc = process_command_string(cmdstr);
6194 /****************************************************************************
6196 ****************************************************************************/
6198 static int do_host_query(const char *query_host)
6202 status = cli_cm_open(talloc_tos(), NULL,
6204 "IPC$", popt_get_cmdline_auth_info(),
6205 smb_encrypt, max_protocol,
6206 have_ip ? &dest_ss : NULL, port,
6208 if (!NT_STATUS_IS_OK(status)) {
6212 cli_set_timeout(cli, io_timeout*1000);
6215 /* Ensure that the host can do IPv4 */
6217 if (!interpret_addr(query_host)) {
6218 struct sockaddr_storage ss;
6219 if (interpret_string_addr(&ss, query_host, 0) &&
6220 (ss.ss_family != AF_INET)) {
6221 d_printf("%s is an IPv6 address -- no workgroup available\n",
6227 if (lp_client_min_protocol() > PROTOCOL_NT1) {
6228 d_printf("SMB1 disabled -- no workgroup available\n");
6232 if (lp_disable_netbios()) {
6233 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
6237 if (port != NBT_SMB_PORT ||
6238 smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1)
6240 int max_proto = MIN(max_protocol, PROTOCOL_NT1);
6243 * Workgroups simply don't make sense over anything
6244 * else but port 139 and SMB1.
6248 d_printf("Reconnecting with SMB1 for workgroup listing.\n");
6249 status = cli_cm_open(talloc_tos(), NULL,
6251 "IPC$", popt_get_cmdline_auth_info(),
6252 smb_encrypt, max_proto,
6253 have_ip ? &dest_ss : NULL, NBT_SMB_PORT,
6255 if (!NT_STATUS_IS_OK(status)) {
6256 d_printf("Unable to connect with SMB1 "
6257 "-- no workgroup available\n");
6262 cli_set_timeout(cli, io_timeout*1000);
6263 list_servers(lp_workgroup());
6270 /****************************************************************************
6271 Handle a tar operation.
6272 ****************************************************************************/
6274 static int do_tar_op(const char *base_directory)
6276 struct tar *tar_ctx = tar_get_ctx();
6279 /* do we already have a connection? */
6283 status = cli_cm_open(talloc_tos(), NULL,
6285 service, popt_get_cmdline_auth_info(),
6286 smb_encrypt, max_protocol,
6287 have_ip ? &dest_ss : NULL, port,
6289 if (!NT_STATUS_IS_OK(status)) {
6293 cli_set_timeout(cli, io_timeout*1000);
6298 if (base_directory && *base_directory) {
6299 ret = do_cd(base_directory);
6305 ret = tar_process(tar_ctx);
6313 /****************************************************************************
6314 Handle a message operation.
6315 ****************************************************************************/
6317 static int do_message_op(struct user_auth_info *a_info)
6321 if (lp_disable_netbios()) {
6322 d_printf("NetBIOS over TCP disabled.\n");
6326 status = cli_connect_nb(desthost, have_ip ? &dest_ss : NULL,
6327 port ? port : NBT_SMB_PORT, name_type,
6328 lp_netbios_name(), SMB_SIGNING_DEFAULT, 0, &cli);
6329 if (!NT_STATUS_IS_OK(status)) {
6330 d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
6334 cli_set_timeout(cli, io_timeout*1000);
6335 send_message(get_cmdline_auth_info_username(a_info));
6341 /****************************************************************************
6343 ****************************************************************************/
6345 int main(int argc,char *argv[])
6347 const char **const_argv = discard_const_p(const char *, argv);
6348 char *base_directory = NULL;
6350 char *query_host = NULL;
6351 bool message = false;
6352 static const char *new_name_resolve_order = NULL;
6356 bool tar_opt = false;
6357 bool service_opt = false;
6358 struct tar *tar_ctx = tar_get_ctx();
6360 struct poptOption long_options[] = {
6364 .longName = "name-resolve",
6366 .argInfo = POPT_ARG_STRING,
6367 .arg = &new_name_resolve_order,
6369 .descrip = "Use these name resolution services only",
6370 .argDescrip = "NAME-RESOLVE-ORDER",
6373 .longName = "message",
6375 .argInfo = POPT_ARG_STRING,
6378 .descrip = "Send message",
6379 .argDescrip = "HOST",
6382 .longName = "ip-address",
6384 .argInfo = POPT_ARG_STRING,
6387 .descrip = "Use this IP to connect to",
6391 .longName = "stderr",
6393 .argInfo = POPT_ARG_NONE,
6396 .descrip = "Write messages to stderr instead of stdout",
6401 .argInfo = POPT_ARG_STRING,
6404 .descrip = "Get a list of shares available on a host",
6405 .argDescrip = "HOST",
6408 .longName = "max-protocol",
6410 .argInfo = POPT_ARG_STRING,
6413 .descrip = "Set the max protocol level",
6414 .argDescrip = "LEVEL",
6419 .argInfo = POPT_ARG_STRING,
6422 .descrip = "Command line tar",
6423 .argDescrip = "<c|x>IXFvgbNan",
6426 .longName = "directory",
6428 .argInfo = POPT_ARG_STRING,
6431 .descrip = "Start from directory",
6432 .argDescrip = "DIR",
6435 .longName = "command",
6437 .argInfo = POPT_ARG_STRING,
6440 .descrip = "Execute semicolon separated commands",
6443 .longName = "send-buffer",
6445 .argInfo = POPT_ARG_INT,
6448 .descrip = "Changes the transmit/send buffer",
6449 .argDescrip = "BYTES",
6452 .longName = "timeout",
6454 .argInfo = POPT_ARG_INT,
6457 .descrip = "Changes the per-operation timeout",
6458 .argDescrip = "SECONDS",
6463 .argInfo = POPT_ARG_INT,
6466 .descrip = "Port to connect to",
6467 .argDescrip = "PORT",
6470 .longName = "grepable",
6472 .argInfo = POPT_ARG_NONE,
6475 .descrip = "Produce grepable output",
6478 .longName = "quiet",
6480 .argInfo = POPT_ARG_NONE,
6483 .descrip = "Suppress help message",
6486 .longName = "browse",
6488 .argInfo = POPT_ARG_NONE,
6491 .descrip = "Browse SMB servers using DNS",
6494 POPT_COMMON_CONNECTION
6495 POPT_COMMON_CREDENTIALS
6498 TALLOC_CTX *frame = talloc_stackframe();
6500 if (!client_set_cur_dir("\\")) {
6504 /* set default debug level to 1 regardless of what smb.conf sets */
6505 setup_logging( "smbclient", DEBUG_DEFAULT_STDERR );
6508 lp_set_cmdline("log level", "1");
6510 popt_common_credentials_set_ignore_missing_conf();
6511 popt_common_credentials_set_delay_post();
6514 pc = poptGetContext("smbclient", argc, const_argv, long_options, 0);
6515 poptSetOtherOptionHelp(pc, "service <password>");
6517 while ((opt = poptGetNextOpt(pc)) != -1) {
6520 * if the tar option has been called previously, now
6521 * we need to eat out the leftovers
6523 /* I see no other way to keep things sane --SSS */
6524 if (tar_opt == true) {
6525 while (poptPeekArg(pc)) {
6531 /* if the service has not yet been specified lets see if it is available in the popt stack */
6532 if (!service_opt && poptPeekArg(pc)) {
6533 service = talloc_strdup(frame, poptGetArg(pc));
6540 /* if the service has already been retrieved then check if we have also a password */
6542 && (!get_cmdline_auth_info_got_pass(
6543 popt_get_cmdline_auth_info()))
6544 && poptPeekArg(pc)) {
6545 set_cmdline_auth_info_password(
6546 popt_get_cmdline_auth_info(), poptGetArg(pc));
6552 /* Messages are sent to NetBIOS name type 0x3
6553 * (Messenger Service). Make sure we default
6554 * to port 139 instead of port 445. srl,crh
6557 desthost = talloc_strdup(frame,poptGetOptArg(pc));
6562 port = NBT_SMB_PORT;
6567 if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
6571 print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
6575 setup_logging("smbclient", DEBUG_STDERR );
6576 display_set_stderr();
6580 query_host = talloc_strdup(frame, poptGetOptArg(pc));
6586 lp_set_cmdline("client max protocol", poptGetOptArg(pc));
6589 /* We must use old option processing for this. Find the
6590 * position of the -T option in the raw argv[]. */
6594 for (i = 1; i < argc; i++) {
6595 if (strncmp("-T", argv[i],2)==0)
6599 if (tar_parse_args(tar_ctx, poptGetOptArg(pc),
6600 const_argv + i, argc - i)) {
6601 poptPrintUsage(pc, stderr, 0);
6605 /* this must be the last option, mark we have parsed it so that we know we have */
6609 base_directory = talloc_strdup(frame, poptGetOptArg(pc));
6610 if (!base_directory) {
6624 return(do_smb_browse());
6629 /* We may still have some leftovers after the last popt option has been called */
6630 if (tar_opt == true) {
6631 while (poptPeekArg(pc)) {
6637 /* if the service has not yet been specified lets see if it is available in the popt stack */
6638 if (!service_opt && poptPeekArg(pc)) {
6639 service = talloc_strdup(frame,poptGetArg(pc));
6646 /* if the service has already been retrieved then check if we have also a password */
6648 && !get_cmdline_auth_info_got_pass(popt_get_cmdline_auth_info())
6649 && poptPeekArg(pc)) {
6650 set_cmdline_auth_info_password(popt_get_cmdline_auth_info(),
6654 if (service_opt && service) {
6657 /* Convert any '/' characters in the service name to '\' characters */
6658 string_replace(service, '/','\\');
6659 if (count_chars(service,'\\') < 3) {
6660 d_printf("\n%s: Not enough '\\' characters in service\n",service);
6661 poptPrintUsage(pc, stderr, 0);
6664 /* Remove trailing slashes */
6665 len = strlen(service);
6666 while(len > 0 && service[len - 1] == '\\') {
6668 service[len] = '\0';
6672 if (!init_names()) {
6673 fprintf(stderr, "init_names() failed\n");
6677 if(new_name_resolve_order)
6678 lp_set_cmdline("name resolve order", new_name_resolve_order);
6680 if (!tar_to_process(tar_ctx) && !query_host && !service && !message) {
6681 poptPrintUsage(pc, stderr, 0);
6685 poptFreeContext(pc);
6686 popt_burn_cmdline_password(argc, argv);
6688 DEBUG(3,("Client started (version %s).\n", samba_version_string()));
6690 /* Ensure we have a password (or equivalent). */
6691 popt_common_credentials_post();
6692 smb_encrypt = get_cmdline_auth_info_smb_encrypt(
6693 popt_get_cmdline_auth_info());
6695 max_protocol = lp_client_max_protocol();
6697 if (tar_to_process(tar_ctx)) {
6699 process_command_string(cmdstr);
6700 rc = do_tar_op(base_directory);
6701 } else if (query_host && *query_host) {
6702 char *qhost = query_host;
6705 while (*qhost == '\\' || *qhost == '/')
6708 if ((slash = strchr_m(qhost, '/'))
6709 || (slash = strchr_m(qhost, '\\'))) {
6713 if ((p=strchr_m(qhost, '#'))) {
6716 sscanf(p, "%x", &name_type);
6719 rc = do_host_query(qhost);
6720 } else if (message) {
6721 rc = do_message_op(popt_get_cmdline_auth_info());
6722 } else if (process(base_directory)) {
6726 popt_free_cmdline_auth_info();