CVE-2023-3347: CI: add a test for server-side mandatory signing
[Samba.git] / source3 / client / client.c
blob68011679d7e9275e002532c362eb530315a39418
1 /*
2 Unix SMB/CIFS implementation.
3 SMB client
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/>.
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "client/client_proto.h"
28 #include "client/clitar_proto.h"
29 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
30 #include "../lib/util/select.h"
31 #include "system/readline.h"
32 #include "../libcli/smbreadline/smbreadline.h"
33 #include "../libcli/security/security.h"
34 #include "system/select.h"
35 #include "libsmb/libsmb.h"
36 #include "libsmb/clirap.h"
37 #include "trans2.h"
38 #include "libsmb/nmblib.h"
39 #include "include/ntioctl.h"
40 #include "../libcli/smb/smbXcli_base.h"
41 #include "lib/util/time_basic.h"
42 #include "lib/util/string_wrappers.h"
43 #include "lib/cmdline/cmdline.h"
45 #ifndef REGISTER
46 #define REGISTER 0
47 #endif
49 extern int do_smb_browse(void); /* mDNS browsing */
51 static int port = 0;
52 static char *service;
53 static char *desthost;
54 static bool grepable = false;
55 static bool quiet = false;
56 static char *cmdstr = NULL;
57 const char *cmd_ptr = NULL;
59 static int io_bufsize = 0; /* we use the default size */
60 static int io_timeout = (CLIENT_TIMEOUT/1000); /* Per operation timeout (in seconds). */
62 static int name_type = 0x20;
64 static int process_tok(char *tok);
65 static int cmd_help(void);
67 /* value for unused fid field in trans2 secondary request */
68 #define FID_UNUSED (0xFFFF)
70 time_t newer_than = 0;
71 static int archive_level = 0;
73 static bool translation = false;
74 static bool have_ip;
76 static bool prompt = true;
78 static bool recurse = false;
79 static bool showacls = false;
80 bool lowercase = false;
81 static bool backup_intent = false;
83 static struct sockaddr_storage dest_ss;
84 static char dest_ss_str[INET6_ADDRSTRLEN];
86 #define SEPARATORS " \t\n\r"
88 /* timing globals */
89 uint64_t get_total_size = 0;
90 unsigned int get_total_time_ms = 0;
91 static uint64_t put_total_size = 0;
92 static unsigned int put_total_time_ms = 0;
94 /* totals globals */
95 static double dir_total;
97 /* root cli_state connection */
99 struct cli_state *cli;
101 static char CLI_DIRSEP_CHAR = '\\';
102 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
104 /* Accessor functions for directory paths. */
105 static char *fileselection;
106 static const char *client_get_fileselection(void)
108 if (fileselection) {
109 return fileselection;
111 return "";
114 static const char *client_set_fileselection(const char *new_fs)
116 SAFE_FREE(fileselection);
117 if (new_fs) {
118 fileselection = SMB_STRDUP(new_fs);
120 return client_get_fileselection();
123 static char *cwd;
124 static const char *client_get_cwd(void)
126 if (cwd) {
127 return cwd;
129 return CLI_DIRSEP_STR;
132 static const char *client_set_cwd(const char *new_cwd)
134 SAFE_FREE(cwd);
135 if (new_cwd) {
136 cwd = SMB_STRDUP(new_cwd);
138 return client_get_cwd();
141 static char *cur_dir;
142 const char *client_get_cur_dir(void)
144 if (cur_dir) {
145 return cur_dir;
147 return CLI_DIRSEP_STR;
150 const char *client_set_cur_dir(const char *newdir)
152 SAFE_FREE(cur_dir);
153 if (newdir) {
154 cur_dir = SMB_STRDUP(newdir);
156 return client_get_cur_dir();
159 /****************************************************************************
160 Put up a yes/no prompt.
161 ****************************************************************************/
163 static bool yesno(const char *p)
165 char ans[20];
166 printf("%s",p);
168 if (!fgets(ans,sizeof(ans)-1,stdin))
169 return(False);
171 if (*ans == 'y' || *ans == 'Y')
172 return(True);
174 return(False);
177 /****************************************************************************
178 Write to a local file with CR/LF->LF translation if appropriate. Return the
179 number taken from the buffer. This may not equal the number written.
180 ****************************************************************************/
182 static ssize_t writefile(int f, char *b, size_t n)
184 size_t i = 0;
186 if (n == 0) {
187 errno = EINVAL;
188 return -1;
191 if (!translation) {
192 return write(f,b,n);
195 do {
196 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
197 b++;i++;
199 if (write(f, b, 1) != 1) {
200 break;
202 b++;
203 i++;
204 } while (i < n);
206 return (ssize_t)i;
209 /****************************************************************************
210 Read from a file with LF->CR/LF translation if appropriate. Return the
211 number read. read approx n bytes.
212 ****************************************************************************/
214 static int readfile(uint8_t *b, int n, FILE *f)
216 int i;
217 int c;
219 if (!translation)
220 return fread(b,1,n,f);
222 i = 0;
223 while (i < (n - 1)) {
224 if ((c = getc(f)) == EOF) {
225 break;
228 if (c == '\n') { /* change all LFs to CR/LF */
229 b[i++] = '\r';
232 b[i++] = c;
235 return(i);
238 struct push_state {
239 FILE *f;
240 off_t nread;
243 static size_t push_source(uint8_t *buf, size_t n, void *priv)
245 struct push_state *state = (struct push_state *)priv;
246 int result;
248 if (feof(state->f)) {
249 return 0;
252 result = readfile(buf, n, state->f);
253 state->nread += result;
254 return result;
257 /****************************************************************************
258 Send a message.
259 ****************************************************************************/
261 static void send_message(const char *username)
263 char buf[1600];
264 NTSTATUS status;
265 size_t i;
267 d_printf("Type your message, ending it with a Control-D\n");
269 i = 0;
270 while (i<sizeof(buf)-2) {
271 int c = fgetc(stdin);
272 if (c == EOF) {
273 break;
275 if (c == '\n') {
276 buf[i++] = '\r';
278 buf[i++] = c;
280 buf[i] = '\0';
282 status = cli_message(cli, desthost, username, buf);
283 if (!NT_STATUS_IS_OK(status)) {
284 d_fprintf(stderr, "cli_message returned %s\n",
285 nt_errstr(status));
289 /****************************************************************************
290 Check the space on a device.
291 ****************************************************************************/
293 static int do_dskattr(void)
295 uint64_t total, bsize, avail;
296 struct cli_state *targetcli = NULL;
297 char *targetpath = NULL;
298 TALLOC_CTX *ctx = talloc_tos();
299 struct cli_credentials *creds = samba_cmdline_get_creds();
300 NTSTATUS status;
302 status = cli_resolve_path(ctx,
304 creds,
305 cli,
306 client_get_cur_dir(), &targetcli,
307 &targetpath);
308 if (!NT_STATUS_IS_OK(status)) {
309 d_printf("Error in dskattr: %s\n", nt_errstr(status));
310 return 1;
313 status = cli_disk_size(targetcli, targetpath, &bsize, &total, &avail);
314 if (!NT_STATUS_IS_OK(status)) {
315 d_printf("Error in dskattr: %s\n", nt_errstr(status));
316 return 1;
319 d_printf("\n\t\t%" PRIu64
320 " blocks of size %" PRIu64
321 ". %" PRIu64 " blocks available\n",
322 total, bsize, avail);
324 return 0;
327 /****************************************************************************
328 Show cd/pwd.
329 ****************************************************************************/
331 static int cmd_pwd(void)
333 d_printf("Current directory is %s",service);
334 d_printf("%s\n",client_get_cur_dir());
335 return 0;
338 /****************************************************************************
339 Ensure name has correct directory separators.
340 ****************************************************************************/
342 static void normalize_name(char *newdir)
344 if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
345 string_replace(newdir,'/','\\');
349 /****************************************************************************
350 Local name cleanup before sending to server. SMB1 allows relative pathnames,
351 but SMB2 does not, so we need to resolve them locally.
352 ****************************************************************************/
354 char *client_clean_name(TALLOC_CTX *ctx, const char *name)
356 char *newname = NULL;
357 if (name == NULL) {
358 return NULL;
361 /* First ensure any path separators are correct. */
362 newname = talloc_strdup(ctx, name);
363 if (newname == NULL) {
364 return NULL;
366 normalize_name(newname);
368 /* Now remove any relative (..) path components. */
369 if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
370 newname = unix_clean_name(ctx, newname);
371 } else {
372 newname = clean_name(ctx, newname);
374 if (newname == NULL) {
375 return NULL;
377 return newname;
380 /****************************************************************************
381 Change directory - inner section.
382 ****************************************************************************/
384 static int do_cd(const char *new_dir)
386 char *newdir = NULL;
387 char *saved_dir = NULL;
388 char *new_cd = NULL;
389 char *targetpath = NULL;
390 struct cli_state *targetcli = NULL;
391 int ret = 1;
392 TALLOC_CTX *ctx = talloc_stackframe();
393 struct cli_credentials *creds = samba_cmdline_get_creds();
394 NTSTATUS status;
396 newdir = talloc_strdup(ctx, new_dir);
397 if (!newdir) {
398 TALLOC_FREE(ctx);
399 return 1;
402 normalize_name(newdir);
404 /* Save the current directory in case the new directory is invalid */
406 saved_dir = talloc_strdup(ctx, client_get_cur_dir());
407 if (!saved_dir) {
408 TALLOC_FREE(ctx);
409 return 1;
412 if (*newdir == CLI_DIRSEP_CHAR) {
413 client_set_cur_dir(newdir);
414 new_cd = newdir;
415 } else {
416 new_cd = talloc_asprintf(ctx, "%s%s",
417 client_get_cur_dir(),
418 newdir);
419 if (!new_cd) {
420 goto out;
424 /* Ensure cur_dir ends in a DIRSEP */
425 if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
426 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
427 if (!new_cd) {
428 goto out;
431 client_set_cur_dir(new_cd);
433 new_cd = client_clean_name(ctx, new_cd);
434 client_set_cur_dir(new_cd);
436 status = cli_resolve_path(ctx, "",
437 creds,
438 cli, new_cd, &targetcli, &targetpath);
439 if (!NT_STATUS_IS_OK(status)) {
440 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
441 client_set_cur_dir(saved_dir);
442 goto out;
445 if (strequal(targetpath,CLI_DIRSEP_STR )) {
446 TALLOC_FREE(ctx);
447 return 0;
451 targetpath = talloc_asprintf(
452 ctx, "%s%s", targetpath, CLI_DIRSEP_STR);
453 if (!targetpath) {
454 client_set_cur_dir(saved_dir);
455 goto out;
457 targetpath = client_clean_name(ctx, targetpath);
458 if (!targetpath) {
459 client_set_cur_dir(saved_dir);
460 goto out;
463 status = cli_chkpath(targetcli, targetpath);
464 if (!NT_STATUS_IS_OK(status)) {
465 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
466 client_set_cur_dir(saved_dir);
467 goto out;
470 ret = 0;
472 out:
474 TALLOC_FREE(ctx);
475 return ret;
478 /****************************************************************************
479 Change directory.
480 ****************************************************************************/
482 static int cmd_cd(void)
484 char *buf = NULL;
485 int rc = 0;
487 if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
488 rc = do_cd(buf);
489 } else {
490 d_printf("Current directory is %s\n",client_get_cur_dir());
493 return rc;
496 /****************************************************************************
497 Change directory.
498 ****************************************************************************/
500 static int cmd_cd_oneup(void)
502 return do_cd("..");
505 /*******************************************************************
506 Decide if a file should be operated on.
507 ********************************************************************/
509 static bool do_this_one(struct file_info *finfo)
511 if (!finfo->name) {
512 return false;
515 if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
516 return true;
519 if (*client_get_fileselection() &&
520 !mask_match(finfo->name,client_get_fileselection(),false)) {
521 DEBUG(3,("mask_match %s failed\n", finfo->name));
522 return false;
525 if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
526 DEBUG(3,("newer_than %s failed\n", finfo->name));
527 return false;
530 if ((archive_level==1 || archive_level==2) && !(finfo->attr & FILE_ATTRIBUTE_ARCHIVE)) {
531 DEBUG(3,("archive %s failed\n", finfo->name));
532 return false;
535 return true;
538 /****************************************************************************
539 Display info about a file.
540 ****************************************************************************/
542 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
543 const char *dir)
545 time_t t;
546 TALLOC_CTX *ctx = talloc_tos();
547 NTSTATUS status = NT_STATUS_OK;
549 if (!do_this_one(finfo)) {
550 return NT_STATUS_OK;
553 t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
554 if (!showacls) {
555 d_printf(" %-30s%7.7s %8.0f %s",
556 finfo->name,
557 attrib_string(talloc_tos(), finfo->attr),
558 (double)finfo->size,
559 time_to_asc(t));
560 dir_total += finfo->size;
561 } else {
562 struct cli_state *targetcli = NULL;
563 char *targetpath = NULL;
564 char *afname = NULL;
565 uint16_t fnum;
566 struct cli_credentials *creds = samba_cmdline_get_creds();
568 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
569 return NT_STATUS_OK;
571 /* create absolute filename for cli_ntcreate() FIXME */
572 afname = talloc_asprintf(ctx,
573 "%s%s%s",
574 dir,
575 CLI_DIRSEP_STR,
576 finfo->name);
577 if (!afname) {
578 return NT_STATUS_NO_MEMORY;
580 /* print file meta date header */
581 d_printf( "FILENAME:%s\n", finfo->name);
582 d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->attr));
583 d_printf( "SIZE:%.0f\n", (double)finfo->size);
584 d_printf( "MTIME:%s", time_to_asc(t));
586 status = cli_resolve_path(
587 ctx,
589 creds,
590 cli_state,
591 afname,
592 &targetcli,
593 &targetpath);
594 if (!NT_STATUS_IS_OK(status)) {
595 DBG_WARNING("display_finfo() Failed to resolve "
596 "%s: %s\n",
597 afname, nt_errstr(status));
598 return status;
601 status = cli_ntcreate(
602 targetcli, /* cli */
603 targetpath, /* fname */
604 0, /* CreatFlags */
605 READ_CONTROL_ACCESS, /* DesiredAccess */
606 0, /* FileAttributes */
607 FILE_SHARE_READ|
608 FILE_SHARE_WRITE, /* ShareAccess */
609 FILE_OPEN, /* CreateDisposition */
610 0x0, /* CreateOptions */
611 0x0, /* SecurityFlags */
612 &fnum, /* pfid */
613 NULL); /* cr */
614 if (!NT_STATUS_IS_OK(status)) {
615 DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
616 afname, nt_errstr(status)));
617 } else {
618 struct security_descriptor *sd = NULL;
619 status = cli_query_secdesc(targetcli, fnum,
620 ctx, &sd);
621 if (!NT_STATUS_IS_OK(status)) {
622 DEBUG( 0, ("display_finfo() failed to "
623 "get security descriptor: %s",
624 nt_errstr(status)));
625 } else {
626 display_sec_desc(sd);
628 TALLOC_FREE(sd);
629 cli_close(targetcli, fnum);
631 TALLOC_FREE(afname);
633 return status;
636 /****************************************************************************
637 Accumulate size of a file.
638 ****************************************************************************/
640 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
641 const char *dir)
643 if (do_this_one(finfo)) {
644 dir_total += finfo->size;
646 return NT_STATUS_OK;
649 struct do_list_queue_entry {
650 struct do_list_queue_entry *prev, *next;
651 char name[];
654 struct do_list_queue {
655 struct do_list_queue_entry *list;
658 static bool do_list_recurse;
659 static bool do_list_dirs;
660 static struct do_list_queue *queue = NULL;
661 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
662 const char *dir);
664 /****************************************************************************
665 Functions for do_list_queue.
666 ****************************************************************************/
668 static void reset_do_list_queue(void)
670 TALLOC_FREE(queue);
673 static void init_do_list_queue(void)
675 TALLOC_FREE(queue);
676 queue = talloc_zero(NULL, struct do_list_queue);
679 static void add_to_do_list_queue(const char *entry)
681 struct do_list_queue_entry *e = NULL;
682 size_t entry_str_len = strlen(entry)+1;
683 size_t entry_len = offsetof(struct do_list_queue_entry, name);
685 entry_len += entry_str_len;
686 SMB_ASSERT(entry_len >= entry_str_len);
688 e = talloc_size(queue, entry_len);
689 if (e == NULL) {
690 d_printf("talloc failed for entry %s\n", entry);
691 return;
693 talloc_set_name_const(e, "struct do_list_queue_entry");
695 memcpy(e->name, entry, entry_str_len);
696 DLIST_ADD_END(queue->list, e);
699 static char *do_list_queue_head(void)
701 return queue->list->name;
704 static void remove_do_list_queue_head(void)
706 struct do_list_queue_entry *e = queue->list;
707 DLIST_REMOVE(queue->list, e);
708 TALLOC_FREE(e);
711 static int do_list_queue_empty(void)
713 return (queue == NULL) || (queue->list == NULL);
716 /****************************************************************************
717 A helper for do_list.
718 ****************************************************************************/
720 struct do_list_helper_state {
721 const char *mask;
722 struct cli_state *cli;
725 static NTSTATUS do_list_helper(
726 struct file_info *f,
727 const char *_mask,
728 void *private_data)
730 struct do_list_helper_state *state = private_data;
731 TALLOC_CTX *ctx = talloc_tos();
732 char *dir = NULL;
733 char *dir_end = NULL;
734 NTSTATUS status = NT_STATUS_OK;
735 char *mask2 = NULL;
737 /* Work out the directory. */
738 dir = talloc_strdup(ctx, state->mask);
739 if (!dir) {
740 return NT_STATUS_NO_MEMORY;
742 if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
743 *dir_end = '\0';
746 if (!(f->attr & FILE_ATTRIBUTE_DIRECTORY)) {
747 if (do_this_one(f)) {
748 status = do_list_fn(state->cli, f, dir);
750 TALLOC_FREE(dir);
751 return status;
754 if (do_list_dirs && do_this_one(f)) {
755 status = do_list_fn(state->cli, f, dir);
756 if (!NT_STATUS_IS_OK(status)) {
757 return status;
761 if (!do_list_recurse ||
762 (f->name == NULL) ||
763 ISDOT(f->name) ||
764 ISDOTDOT(f->name)) {
765 return NT_STATUS_OK;
768 if (!f->name[0]) {
769 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
770 TALLOC_FREE(dir);
771 return NT_STATUS_UNSUCCESSFUL;
774 mask2 = talloc_asprintf(ctx,
775 "%s%c%s%c*",
776 dir,
777 CLI_DIRSEP_CHAR,
778 f->name,
779 CLI_DIRSEP_CHAR);
780 if (!mask2) {
781 TALLOC_FREE(dir);
782 return NT_STATUS_NO_MEMORY;
784 add_to_do_list_queue(mask2);
785 TALLOC_FREE(mask2);
787 TALLOC_FREE(dir);
788 return NT_STATUS_OK;
791 /****************************************************************************
792 A wrapper around cli_list that adds recursion.
793 ****************************************************************************/
795 NTSTATUS do_list(const char *mask,
796 uint32_t attribute,
797 NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
798 const char *dir),
799 bool rec,
800 bool dirs)
802 struct do_list_helper_state state = { .cli = cli, };
803 static int in_do_list = 0;
804 TALLOC_CTX *ctx = talloc_tos();
805 struct cli_credentials *creds = samba_cmdline_get_creds();
806 NTSTATUS ret_status = NT_STATUS_OK;
807 NTSTATUS status = NT_STATUS_OK;
809 if (in_do_list && rec) {
810 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
811 exit(1);
814 in_do_list = 1;
816 do_list_recurse = rec;
817 do_list_dirs = dirs;
818 do_list_fn = fn;
820 init_do_list_queue();
821 add_to_do_list_queue(mask);
823 while (!do_list_queue_empty()) {
824 struct cli_state *targetcli = NULL;
825 char *targetpath = NULL;
827 state.mask = do_list_queue_head();
829 /* check for dfs */
831 status = cli_resolve_path(
832 ctx,
834 creds,
835 cli,
836 state.mask,
837 &targetcli,
838 &targetpath);
839 if (!NT_STATUS_IS_OK(status)) {
840 d_printf("do_list: [%s] %s\n", state.mask,
841 nt_errstr(status));
842 remove_do_list_queue_head();
843 continue;
846 status = cli_list(
847 targetcli,
848 targetpath,
849 attribute,
850 do_list_helper,
851 &state);
852 if (!NT_STATUS_IS_OK(status)) {
853 d_printf("%s listing %s\n",
854 nt_errstr(status), targetpath);
855 ret_status = status;
857 remove_do_list_queue_head();
858 if ((! do_list_queue_empty()) && (fn == display_finfo)) {
859 char *next_file = do_list_queue_head();
860 char *save_ch = 0;
861 if ((strlen(next_file) >= 2) &&
862 (next_file[strlen(next_file) - 1] == '*') &&
863 (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
864 save_ch = next_file +
865 strlen(next_file) - 2;
866 *save_ch = '\0';
867 if (showacls) {
868 /* cwd is only used if showacls is on */
869 client_set_cwd(next_file);
872 if (!showacls) /* don't disturbe the showacls output */
873 d_printf("\n%s\n",next_file);
874 if (save_ch) {
875 *save_ch = CLI_DIRSEP_CHAR;
878 TALLOC_FREE(targetpath);
881 in_do_list = 0;
882 reset_do_list_queue();
883 return ret_status;
886 /****************************************************************************
887 Get a directory listing.
888 ****************************************************************************/
890 static int cmd_dir(void)
892 TALLOC_CTX *ctx = talloc_tos();
893 uint32_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
894 char *mask = NULL;
895 char *buf = NULL;
896 int rc = 1;
897 NTSTATUS status;
899 dir_total = 0;
900 mask = talloc_strdup(ctx, client_get_cur_dir());
901 if (!mask) {
902 return 1;
905 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
906 normalize_name(buf);
907 if (*buf == CLI_DIRSEP_CHAR) {
908 mask = talloc_strdup(ctx, buf);
909 } else {
910 mask = talloc_asprintf_append(mask, "%s", buf);
912 } else {
913 mask = talloc_asprintf_append(mask, "*");
915 if (!mask) {
916 return 1;
919 mask = client_clean_name(ctx, mask);
920 if (mask == NULL) {
921 return 1;
924 if (showacls) {
925 /* cwd is only used if showacls is on */
926 client_set_cwd(client_get_cur_dir());
929 status = do_list(mask, attribute, display_finfo, recurse, true);
930 if (!NT_STATUS_IS_OK(status)) {
931 return 1;
934 rc = do_dskattr();
936 DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
938 return rc;
941 /****************************************************************************
942 Get a directory listing.
943 ****************************************************************************/
945 static int cmd_du(void)
947 TALLOC_CTX *ctx = talloc_tos();
948 uint32_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
949 char *mask = NULL;
950 char *buf = NULL;
951 NTSTATUS status;
952 int rc = 1;
954 dir_total = 0;
955 mask = talloc_strdup(ctx, client_get_cur_dir());
956 if (!mask) {
957 return 1;
959 if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
960 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
961 if (!mask) {
962 return 1;
966 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
967 normalize_name(buf);
968 if (*buf == CLI_DIRSEP_CHAR) {
969 mask = talloc_strdup(ctx, buf);
970 } else {
971 mask = talloc_asprintf_append(mask, "%s", buf);
973 } else {
974 mask = talloc_strdup(ctx, "*");
976 if (!mask) {
977 return 1;
980 mask = client_clean_name(ctx, mask);
981 if (mask == NULL) {
982 return 1;
985 status = do_list(mask, attribute, do_du, recurse, true);
986 if (!NT_STATUS_IS_OK(status)) {
987 return 1;
990 rc = do_dskattr();
992 d_printf("Total number of bytes: %.0f\n", dir_total);
994 return rc;
997 static int cmd_echo(void)
999 TALLOC_CTX *ctx = talloc_tos();
1000 char *num;
1001 char *data;
1002 NTSTATUS status;
1004 if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1005 || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1006 d_printf("echo <num> <data>\n");
1007 return 1;
1010 status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1012 if (!NT_STATUS_IS_OK(status)) {
1013 d_printf("echo failed: %s\n", nt_errstr(status));
1014 return 1;
1017 return 0;
1020 /****************************************************************************
1021 Get a file from rname to lname
1022 ****************************************************************************/
1024 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1026 int *pfd = (int *)priv;
1027 ssize_t rc;
1029 rc = writefile(*pfd, buf, n);
1030 if (rc == -1) {
1031 return map_nt_error_from_unix(errno);
1033 return NT_STATUS_OK;
1036 static int do_get(const char *rname, const char *lname_in, bool reget)
1038 TALLOC_CTX *ctx = talloc_tos();
1039 int handle = 0;
1040 uint16_t fnum;
1041 bool newhandle = false;
1042 struct timespec tp_start;
1043 uint32_t attr;
1044 off_t size;
1045 off_t start = 0;
1046 off_t nread = 0;
1047 int rc = 0;
1048 struct cli_state *targetcli = NULL;
1049 char *targetname = NULL;
1050 char *lname = NULL;
1051 struct cli_credentials *creds = samba_cmdline_get_creds();
1052 NTSTATUS status;
1054 lname = talloc_strdup(ctx, lname_in);
1055 if (!lname) {
1056 return 1;
1059 if (lowercase) {
1060 if (!strlower_m(lname)) {
1061 d_printf("strlower_m %s failed\n", lname);
1062 return 1;
1066 status = cli_resolve_path(ctx, "",
1067 creds,
1068 cli, rname, &targetcli, &targetname);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1071 return 1;
1074 clock_gettime_mono(&tp_start);
1076 status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 d_printf("%s opening remote file %s\n", nt_errstr(status),
1079 rname);
1080 return 1;
1083 if(!strcmp(lname,"-")) {
1084 handle = fileno(stdout);
1085 } else {
1086 if (reget) {
1087 handle = open(lname, O_WRONLY|O_CREAT, 0644);
1088 if (handle >= 0) {
1089 start = lseek(handle, 0, SEEK_END);
1090 if (start == -1) {
1091 d_printf("Error seeking local file\n");
1092 close(handle);
1093 return 1;
1096 } else {
1097 handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1099 newhandle = true;
1101 if (handle < 0) {
1102 d_printf("Error opening local file %s\n",lname);
1103 return 1;
1107 status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1108 NULL, NULL, NULL);
1109 if (!NT_STATUS_IS_OK(status)) {
1110 d_printf("getattrib: %s\n", nt_errstr(status));
1111 if (newhandle) {
1112 close(handle);
1114 return 1;
1117 DEBUG(1,("getting file %s of size %.0f as %s ",
1118 rname, (double)size, lname));
1120 status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1121 writefile_sink, (void *)&handle, &nread);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 d_fprintf(stderr, "parallel_read returned %s\n",
1124 nt_errstr(status));
1125 if (newhandle) {
1126 close(handle);
1128 cli_close(targetcli, fnum);
1129 return 1;
1132 status = cli_close(targetcli, fnum);
1133 if (!NT_STATUS_IS_OK(status)) {
1134 d_printf("Error %s closing remote file\n", nt_errstr(status));
1135 rc = 1;
1138 if (newhandle) {
1139 close(handle);
1142 if (archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
1143 cli_setatr(cli, rname, attr & ~(uint32_t)FILE_ATTRIBUTE_ARCHIVE, 0);
1147 struct timespec tp_end;
1148 int this_time;
1150 clock_gettime_mono(&tp_end);
1151 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1152 get_total_time_ms += this_time;
1153 get_total_size += nread;
1155 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1156 nread / (1.024*this_time + 1.0e-4),
1157 get_total_size / (1.024*get_total_time_ms)));
1160 TALLOC_FREE(targetname);
1161 return rc;
1164 /****************************************************************************
1165 Get a file.
1166 ****************************************************************************/
1168 static int cmd_get(void)
1170 TALLOC_CTX *ctx = talloc_tos();
1171 char *lname = NULL;
1172 char *rname = NULL;
1173 char *fname = NULL;
1175 rname = talloc_strdup(ctx, client_get_cur_dir());
1176 if (!rname) {
1177 return 1;
1180 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1181 d_printf("get <filename> [localname]\n");
1182 return 1;
1184 rname = talloc_asprintf_append(rname, "%s", fname);
1185 if (!rname) {
1186 return 1;
1188 rname = client_clean_name(ctx, rname);
1189 if (!rname) {
1190 return 1;
1193 next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1194 if (!lname) {
1195 lname = fname;
1198 return do_get(rname, lname, false);
1201 /****************************************************************************
1202 Do an mget operation on one file.
1203 ****************************************************************************/
1205 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1206 const char *dir)
1208 TALLOC_CTX *ctx = talloc_tos();
1209 const char *client_cwd = NULL;
1210 size_t client_cwd_len;
1211 char *path = NULL;
1212 char *local_path = NULL;
1214 if (!finfo->name) {
1215 return NT_STATUS_OK;
1218 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1219 return NT_STATUS_OK;
1222 if ((finfo->attr & FILE_ATTRIBUTE_DIRECTORY) && !recurse) {
1223 return NT_STATUS_OK;
1226 if (prompt) {
1227 const char *object = (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) ?
1228 "directory" : "file";
1229 char *quest = NULL;
1230 bool ok;
1232 quest = talloc_asprintf(
1233 ctx, "Get %s %s? ", object, finfo->name);
1234 if (quest == NULL) {
1235 return NT_STATUS_NO_MEMORY;
1238 ok = yesno(quest);
1239 TALLOC_FREE(quest);
1240 if (!ok) {
1241 return NT_STATUS_OK;
1245 path = talloc_asprintf(
1246 ctx, "%s%c%s", dir, CLI_DIRSEP_CHAR, finfo->name);
1247 if (path == NULL) {
1248 return NT_STATUS_NO_MEMORY;
1250 path = client_clean_name(ctx, path);
1251 if (path == NULL) {
1252 return NT_STATUS_NO_MEMORY;
1256 * Skip the path prefix if we've done a remote "cd" when
1257 * creating the local path
1259 client_cwd = client_get_cur_dir();
1260 client_cwd_len = strlen(client_cwd);
1262 local_path = talloc_strdup(ctx, path + client_cwd_len);
1263 if (local_path == NULL) {
1264 TALLOC_FREE(path);
1265 return NT_STATUS_NO_MEMORY;
1267 string_replace(local_path, CLI_DIRSEP_CHAR, '/');
1269 if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
1270 int ret = mkdir(local_path, 0777);
1272 if ((ret == -1) && (errno != EEXIST)) {
1273 return map_nt_error_from_unix(errno);
1275 } else {
1276 do_get(path, local_path, false);
1279 return NT_STATUS_OK;
1282 /****************************************************************************
1283 View the file using the pager.
1284 ****************************************************************************/
1286 static int cmd_more(void)
1288 TALLOC_CTX *ctx = talloc_tos();
1289 char *rname = NULL;
1290 char *fname = NULL;
1291 char *lname = NULL;
1292 char *pager_cmd = NULL;
1293 const char *pager;
1294 int fd;
1295 int rc = 0;
1296 mode_t mask;
1298 rname = talloc_strdup(ctx, client_get_cur_dir());
1299 if (!rname) {
1300 return 1;
1303 lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1304 if (!lname) {
1305 return 1;
1307 mask = umask(S_IRWXO | S_IRWXG);
1308 fd = mkstemp(lname);
1309 umask(mask);
1310 if (fd == -1) {
1311 d_printf("failed to create temporary file for more\n");
1312 return 1;
1314 close(fd);
1316 if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1317 d_printf("more <filename>\n");
1318 unlink(lname);
1319 return 1;
1321 rname = talloc_asprintf_append(rname, "%s", fname);
1322 if (!rname) {
1323 return 1;
1325 rname = client_clean_name(ctx,rname);
1326 if (!rname) {
1327 return 1;
1330 rc = do_get(rname, lname, false);
1332 pager=getenv("PAGER");
1334 pager_cmd = talloc_asprintf(ctx,
1335 "%s %s",
1336 (pager? pager:PAGER),
1337 lname);
1338 if (!pager_cmd) {
1339 return 1;
1341 if (system(pager_cmd) == -1) {
1342 d_printf("system command '%s' returned -1\n",
1343 pager_cmd);
1345 unlink(lname);
1347 return rc;
1350 /****************************************************************************
1351 Do a mget command.
1352 ****************************************************************************/
1354 static int cmd_mget(void)
1356 TALLOC_CTX *ctx = talloc_tos();
1357 uint32_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1358 char *mget_mask = NULL;
1359 char *buf = NULL;
1360 NTSTATUS status = NT_STATUS_OK;
1362 if (recurse) {
1363 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1366 while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1368 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1369 if (!mget_mask) {
1370 return 1;
1372 if (*buf == CLI_DIRSEP_CHAR) {
1373 mget_mask = talloc_strdup(ctx, buf);
1374 } else {
1375 mget_mask = talloc_asprintf_append(mget_mask,
1376 "%s", buf);
1378 if (!mget_mask) {
1379 return 1;
1381 mget_mask = client_clean_name(ctx, mget_mask);
1382 if (mget_mask == NULL) {
1383 return 1;
1385 status = do_list(mget_mask, attribute, do_mget, recurse, true);
1386 if (!NT_STATUS_IS_OK(status)) {
1387 return 1;
1391 if (mget_mask == NULL) {
1392 d_printf("nothing to mget\n");
1393 return 0;
1396 if (!*mget_mask) {
1397 mget_mask = talloc_asprintf(ctx,
1398 "%s*",
1399 client_get_cur_dir());
1400 if (!mget_mask) {
1401 return 1;
1403 mget_mask = client_clean_name(ctx, mget_mask);
1404 if (mget_mask == NULL) {
1405 return 1;
1407 status = do_list(mget_mask, attribute, do_mget, recurse, true);
1408 if (!NT_STATUS_IS_OK(status)) {
1409 return 1;
1413 return 0;
1416 /****************************************************************************
1417 Make a directory of name "name".
1418 ****************************************************************************/
1420 static bool do_mkdir(const char *name)
1422 TALLOC_CTX *ctx = talloc_tos();
1423 struct cli_state *targetcli;
1424 char *targetname = NULL;
1425 struct cli_credentials *creds = samba_cmdline_get_creds();
1426 NTSTATUS status;
1428 status = cli_resolve_path(ctx, "",
1429 creds,
1430 cli, name, &targetcli, &targetname);
1431 if (!NT_STATUS_IS_OK(status)) {
1432 d_printf("mkdir %s: %s\n", name, nt_errstr(status));
1433 return false;
1436 status = cli_mkdir(targetcli, targetname);
1437 if (!NT_STATUS_IS_OK(status)) {
1438 d_printf("%s making remote directory %s\n",
1439 nt_errstr(status),name);
1440 return false;
1443 return true;
1446 /****************************************************************************
1447 Show 8.3 name of a file.
1448 ****************************************************************************/
1450 static bool do_altname(const char *name)
1452 fstring altname;
1453 NTSTATUS status;
1455 status = cli_qpathinfo_alt_name(cli, name, altname);
1456 if (!NT_STATUS_IS_OK(status)) {
1457 d_printf("%s getting alt name for %s\n",
1458 nt_errstr(status),name);
1459 return false;
1461 d_printf("%s\n", altname);
1463 return true;
1466 /****************************************************************************
1467 Exit client.
1468 ****************************************************************************/
1470 static int cmd_quit(void)
1472 cli_shutdown(cli);
1473 exit(0);
1474 /* NOTREACHED */
1475 return 0;
1478 /****************************************************************************
1479 Make a directory.
1480 ****************************************************************************/
1482 static int cmd_mkdir(void)
1484 TALLOC_CTX *ctx = talloc_tos();
1485 char *mask = NULL;
1486 char *buf = NULL;
1487 struct cli_credentials *creds = samba_cmdline_get_creds();
1488 NTSTATUS status;
1490 mask = talloc_strdup(ctx, client_get_cur_dir());
1491 if (!mask) {
1492 return 1;
1495 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1496 if (!recurse) {
1497 d_printf("mkdir <dirname>\n");
1499 return 1;
1501 mask = talloc_asprintf_append(mask, "%s", buf);
1502 if (!mask) {
1503 return 1;
1505 mask = client_clean_name(ctx, mask);
1506 if (mask == NULL) {
1507 return 1;
1510 if (recurse) {
1511 char *ddir = NULL;
1512 char *ddir2 = NULL;
1513 struct cli_state *targetcli;
1514 char *targetname = NULL;
1515 char *p = NULL;
1516 char *saveptr;
1518 ddir2 = talloc_strdup(ctx, "");
1519 if (!ddir2) {
1520 return 1;
1523 status = cli_resolve_path(ctx, "",
1524 creds,
1525 cli, mask,
1526 &targetcli, &targetname);
1527 if (!NT_STATUS_IS_OK(status)) {
1528 return 1;
1531 ddir = talloc_strdup(ctx, targetname);
1532 if (!ddir) {
1533 return 1;
1535 trim_char(ddir,'.','\0');
1536 p = strtok_r(ddir, "/\\", &saveptr);
1537 while (p) {
1538 ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1539 if (!ddir2) {
1540 return 1;
1542 if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1543 do_mkdir(ddir2);
1545 ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1546 if (!ddir2) {
1547 return 1;
1549 p = strtok_r(NULL, "/\\", &saveptr);
1551 } else {
1552 do_mkdir(mask);
1555 return 0;
1558 /****************************************************************************
1559 Show alt name.
1560 ****************************************************************************/
1562 static int cmd_altname(void)
1564 TALLOC_CTX *ctx = talloc_tos();
1565 char *name;
1566 char *buf;
1568 name = talloc_strdup(ctx, client_get_cur_dir());
1569 if (!name) {
1570 return 1;
1573 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1574 d_printf("altname <file>\n");
1575 return 1;
1577 name = talloc_asprintf_append(name, "%s", buf);
1578 if (!name) {
1579 return 1;
1581 name = client_clean_name(ctx, name);
1582 if (name == NULL) {
1583 return 1;
1585 do_altname(name);
1586 return 0;
1589 static char *attr_str(TALLOC_CTX *mem_ctx, uint32_t attr)
1591 char *attrs = talloc_zero_array(mem_ctx, char, 17);
1592 int i = 0;
1594 if (!(attr & FILE_ATTRIBUTE_NORMAL)) {
1595 if (attr & FILE_ATTRIBUTE_ENCRYPTED) {
1596 attrs[i++] = 'E';
1598 if (attr & FILE_ATTRIBUTE_NONINDEXED) {
1599 attrs[i++] = 'N';
1601 if (attr & FILE_ATTRIBUTE_OFFLINE) {
1602 attrs[i++] = 'O';
1604 if (attr & FILE_ATTRIBUTE_COMPRESSED) {
1605 attrs[i++] = 'C';
1607 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
1608 attrs[i++] = 'r';
1610 if (attr & FILE_ATTRIBUTE_SPARSE) {
1611 attrs[i++] = 's';
1613 if (attr & FILE_ATTRIBUTE_TEMPORARY) {
1614 attrs[i++] = 'T';
1616 if (attr & FILE_ATTRIBUTE_NORMAL) {
1617 attrs[i++] = 'N';
1619 if (attr & FILE_ATTRIBUTE_READONLY) {
1620 attrs[i++] = 'R';
1622 if (attr & FILE_ATTRIBUTE_HIDDEN) {
1623 attrs[i++] = 'H';
1625 if (attr & FILE_ATTRIBUTE_SYSTEM) {
1626 attrs[i++] = 'S';
1628 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
1629 attrs[i++] = 'D';
1631 if (attr & FILE_ATTRIBUTE_ARCHIVE) {
1632 attrs[i++] = 'A';
1635 return attrs;
1638 /****************************************************************************
1639 Show all info we can get
1640 ****************************************************************************/
1642 static int do_allinfo(const char *name)
1644 fstring altname;
1645 struct timespec b_time, a_time, m_time, c_time;
1646 off_t size;
1647 uint32_t attr;
1648 NTTIME tmp;
1649 uint16_t fnum;
1650 unsigned int num_streams;
1651 struct stream_struct *streams;
1652 int j, num_snapshots;
1653 char **snapshots = NULL;
1654 unsigned int i;
1655 NTSTATUS status;
1657 status = cli_qpathinfo_alt_name(cli, name, altname);
1658 if (!NT_STATUS_IS_OK(status)) {
1659 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1660 name);
1662 * Ignore not supported or not implemented, it does not
1663 * hurt if we can't list alternate names.
1665 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
1666 NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1667 altname[0] = '\0';
1668 } else {
1669 return false;
1672 d_printf("altname: %s\n", altname);
1674 status = cli_qpathinfo3(cli, name, &b_time, &a_time, &m_time, &c_time,
1675 &size, &attr, NULL);
1676 if (!NT_STATUS_IS_OK(status)) {
1677 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1678 name);
1679 return false;
1682 tmp = full_timespec_to_nt_time(&b_time);
1683 d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
1685 tmp = full_timespec_to_nt_time(&a_time);
1686 d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
1688 tmp = full_timespec_to_nt_time(&m_time);
1689 d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
1691 tmp = full_timespec_to_nt_time(&c_time);
1692 d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
1694 d_printf("attributes: %s (%x)\n", attr_str(talloc_tos(), attr), attr);
1696 status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1697 &streams);
1698 if (!NT_STATUS_IS_OK(status)) {
1699 d_printf("%s getting streams for %s\n", nt_errstr(status),
1700 name);
1701 return false;
1704 for (i=0; i<num_streams; i++) {
1705 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1706 (unsigned long long)streams[i].size);
1709 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
1710 char *subst, *print;
1711 uint32_t flags;
1713 status = cli_readlink(cli, name, talloc_tos(), &subst, &print,
1714 &flags);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 d_fprintf(stderr, "cli_readlink returned %s\n",
1717 nt_errstr(status));
1718 } else {
1719 d_printf("symlink: subst=[%s], print=[%s], flags=%x\n",
1720 subst, print, flags);
1721 TALLOC_FREE(subst);
1722 TALLOC_FREE(print);
1726 status = cli_ntcreate(cli, name, 0,
1727 SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE |
1728 SEC_STD_SYNCHRONIZE, 0,
1729 FILE_SHARE_READ|FILE_SHARE_WRITE
1730 |FILE_SHARE_DELETE,
1731 FILE_OPEN, 0x0, 0x0, &fnum, NULL);
1732 if (!NT_STATUS_IS_OK(status)) {
1734 * Ignore failure, it does not hurt if we can't list
1735 * snapshots
1737 return 0;
1740 * In order to get shadow copy data over SMB1 we
1741 * must call twice, once with 'get_names = false'
1742 * to get the size, then again with 'get_names = true'
1743 * to get the data or a Windows server fails to return
1744 * valid info. Samba doesn't have this bug. JRA.
1747 status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1748 false, &snapshots, &num_snapshots);
1749 if (!NT_STATUS_IS_OK(status)) {
1750 cli_close(cli, fnum);
1751 return 0;
1753 status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1754 true, &snapshots, &num_snapshots);
1755 if (!NT_STATUS_IS_OK(status)) {
1756 cli_close(cli, fnum);
1757 return 0;
1760 for (j=0; j<num_snapshots; j++) {
1761 char *snap_name;
1763 d_printf("%s\n", snapshots[j]);
1764 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1765 snapshots[j], name);
1766 status = cli_qpathinfo3(cli, snap_name, &b_time, &a_time,
1767 &m_time, &c_time, &size,
1768 NULL, NULL);
1769 if (!NT_STATUS_IS_OK(status)) {
1770 d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1771 snap_name, nt_errstr(status));
1772 TALLOC_FREE(snap_name);
1773 continue;
1775 tmp = unix_timespec_to_nt_time(b_time);
1776 d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
1777 tmp = unix_timespec_to_nt_time(a_time);
1778 d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
1779 tmp =unix_timespec_to_nt_time(m_time);
1780 d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
1781 tmp = unix_timespec_to_nt_time(c_time);
1782 d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
1783 d_printf("size: %d\n", (int)size);
1786 TALLOC_FREE(snapshots);
1787 cli_close(cli, fnum);
1789 return 0;
1792 /****************************************************************************
1793 Show all info we can get
1794 ****************************************************************************/
1796 static int cmd_allinfo(void)
1798 TALLOC_CTX *ctx = talloc_tos();
1799 char *name;
1800 char *buf;
1802 name = talloc_strdup(ctx, client_get_cur_dir());
1803 if (!name) {
1804 return 1;
1807 if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1808 d_printf("allinfo <file>\n");
1809 return 1;
1811 name = talloc_asprintf_append(name, "%s", buf);
1812 if (!name) {
1813 return 1;
1815 name = client_clean_name(ctx, name);
1816 if (name == NULL) {
1817 return 1;
1819 do_allinfo(name);
1821 return 0;
1824 /****************************************************************************
1825 Put a single file.
1826 ****************************************************************************/
1828 static int do_put(const char *rname, const char *lname, bool reput)
1830 TALLOC_CTX *ctx = talloc_tos();
1831 uint16_t fnum;
1832 FILE *f;
1833 off_t start = 0;
1834 int rc = 0;
1835 struct timespec tp_start;
1836 struct cli_state *targetcli;
1837 char *targetname = NULL;
1838 struct push_state state;
1839 struct cli_credentials *creds = samba_cmdline_get_creds();
1840 NTSTATUS status;
1842 status = cli_resolve_path(ctx, "",
1843 creds,
1844 cli, rname, &targetcli, &targetname);
1845 if (!NT_STATUS_IS_OK(status)) {
1846 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1847 return 1;
1850 clock_gettime_mono(&tp_start);
1852 if (reput) {
1853 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1854 if (NT_STATUS_IS_OK(status)) {
1855 if (!NT_STATUS_IS_OK(status = cli_qfileinfo_basic(
1856 targetcli, fnum, NULL,
1857 &start, NULL, NULL,
1858 NULL, NULL, NULL))) {
1859 d_printf("getattrib: %s\n", nt_errstr(status));
1860 return 1;
1863 } else {
1864 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1867 if (!NT_STATUS_IS_OK(status)) {
1868 d_printf("%s opening remote file %s\n", nt_errstr(status),
1869 rname);
1870 return 1;
1873 /* allow files to be piped into smbclient
1874 jdblair 24.jun.98
1876 Note that in this case this function will exit(0) rather
1877 than returning. */
1878 if (!strcmp(lname, "-")) {
1879 f = stdin;
1880 /* size of file is not known */
1881 } else {
1882 f = fopen(lname, "r");
1883 if (f && reput) {
1884 if (fseek(f, start, SEEK_SET) == -1) {
1885 d_printf("Error seeking local file\n");
1886 fclose(f);
1887 return 1;
1892 if (!f) {
1893 d_printf("Error opening local file %s\n",lname);
1894 return 1;
1897 DEBUG(1,("putting file %s as %s ",lname,
1898 rname));
1900 setvbuf(f, NULL, _IOFBF, io_bufsize);
1902 state.f = f;
1903 state.nread = 0;
1905 status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
1906 &state);
1907 if (!NT_STATUS_IS_OK(status)) {
1908 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1909 rc = 1;
1912 status = cli_close(targetcli, fnum);
1913 if (!NT_STATUS_IS_OK(status)) {
1914 d_printf("%s closing remote file %s\n", nt_errstr(status),
1915 rname);
1916 if (f != stdin) {
1917 fclose(f);
1919 return 1;
1922 if (f != stdin) {
1923 fclose(f);
1927 struct timespec tp_end;
1928 int this_time;
1930 clock_gettime_mono(&tp_end);
1931 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1932 put_total_time_ms += this_time;
1933 put_total_size += state.nread;
1935 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1936 state.nread / (1.024*this_time + 1.0e-4),
1937 put_total_size / (1.024*put_total_time_ms)));
1940 if (f == stdin) {
1941 cli_shutdown(cli);
1942 exit(rc);
1945 return rc;
1948 /****************************************************************************
1949 Put a file.
1950 ****************************************************************************/
1952 static int cmd_put(void)
1954 TALLOC_CTX *ctx = talloc_tos();
1955 char *lname;
1956 char *rname;
1957 char *buf;
1959 rname = talloc_strdup(ctx, client_get_cur_dir());
1960 if (!rname) {
1961 return 1;
1964 if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1965 d_printf("put <filename>\n");
1966 return 1;
1969 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1970 rname = talloc_asprintf_append(rname, "%s", buf);
1971 } else {
1972 rname = talloc_asprintf_append(rname, "%s", lname);
1974 if (!rname) {
1975 return 1;
1978 rname = client_clean_name(ctx, rname);
1979 if (!rname) {
1980 return 1;
1984 SMB_STRUCT_STAT st;
1985 /* allow '-' to represent stdin
1986 jdblair, 24.jun.98 */
1987 if (!file_exist_stat(lname, &st, false) &&
1988 (strcmp(lname,"-"))) {
1989 d_printf("%s does not exist\n",lname);
1990 return 1;
1994 return do_put(rname, lname, false);
1997 /*************************************
1998 File list structure.
1999 *************************************/
2001 static struct file_list {
2002 struct file_list *prev, *next;
2003 char *file_path;
2004 bool isdir;
2005 } *file_list;
2007 /****************************************************************************
2008 Free a file_list structure.
2009 ****************************************************************************/
2011 static void free_file_list (struct file_list *l_head)
2013 struct file_list *list, *next;
2015 for (list = l_head; list; list = next) {
2016 next = list->next;
2017 DLIST_REMOVE(l_head, list);
2018 TALLOC_FREE(list);
2022 /****************************************************************************
2023 Seek in a directory/file list until you get something that doesn't start with
2024 the specified name.
2025 ****************************************************************************/
2027 static bool seek_list(struct file_list *list, char *name)
2029 while (list) {
2030 trim_string(list->file_path,"./","\n");
2031 if (strncmp(list->file_path, name, strlen(name)) != 0) {
2032 return true;
2034 list = list->next;
2037 return false;
2040 /****************************************************************************
2041 Set the file selection mask.
2042 ****************************************************************************/
2044 static int cmd_select(void)
2046 TALLOC_CTX *ctx = talloc_tos();
2047 char *new_fs = NULL;
2048 next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
2050 if (new_fs) {
2051 client_set_fileselection(new_fs);
2052 } else {
2053 client_set_fileselection("");
2055 return 0;
2058 /****************************************************************************
2059 Recursive file matching function act as find
2060 match must be always set to true when calling this function
2061 ****************************************************************************/
2063 static int file_find(TALLOC_CTX *ctx,
2064 struct file_list **list,
2065 const char *directory,
2066 const char *expression,
2067 bool match)
2069 DIR *dir;
2070 struct file_list *entry;
2071 struct stat statbuf;
2072 int ret;
2073 char *path;
2074 bool isdir;
2075 const char *dname;
2077 dir = opendir(directory);
2078 if (!dir)
2079 return -1;
2081 while ((dname = readdirname(dir))) {
2082 if (ISDOT(dname) || ISDOTDOT(dname)) {
2083 continue;
2086 path = talloc_asprintf(ctx, "%s/%s", directory, dname);
2087 if (path == NULL) {
2088 continue;
2091 isdir = false;
2092 if (!match || !gen_fnmatch(expression, dname)) {
2093 if (recurse) {
2094 ret = stat(path, &statbuf);
2095 if (ret == 0) {
2096 if (S_ISDIR(statbuf.st_mode)) {
2097 isdir = true;
2098 ret = file_find(ctx,
2099 list,
2100 path,
2101 expression,
2102 false);
2104 } else {
2105 d_printf("file_find: cannot stat file %s\n", path);
2108 if (ret == -1) {
2109 TALLOC_FREE(path);
2110 closedir(dir);
2111 return -1;
2114 entry = talloc_zero(ctx, struct file_list);
2115 if (!entry) {
2116 d_printf("Out of memory in file_find\n");
2117 closedir(dir);
2118 return -1;
2120 entry->file_path = talloc_move(entry, &path);
2121 entry->isdir = isdir;
2122 DLIST_ADD(*list, entry);
2123 } else {
2124 TALLOC_FREE(path);
2128 closedir(dir);
2129 return 0;
2132 /****************************************************************************
2133 mput some files.
2134 ****************************************************************************/
2136 static int cmd_mput(void)
2138 TALLOC_CTX *ctx = talloc_tos();
2139 char *p = NULL;
2141 while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2142 int ret;
2143 struct file_list *temp_list;
2144 char *quest, *lname, *rname;
2146 file_list = NULL;
2148 ret = file_find(ctx, &file_list, ".", p, true);
2149 if (ret) {
2150 free_file_list(file_list);
2151 continue;
2154 quest = NULL;
2155 lname = NULL;
2156 rname = NULL;
2158 for (temp_list = file_list; temp_list;
2159 temp_list = temp_list->next) {
2161 SAFE_FREE(lname);
2162 if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2163 continue;
2165 trim_string(lname, "./", "/");
2167 /* check if it's a directory */
2168 if (temp_list->isdir) {
2169 /* if (!recurse) continue; */
2171 SAFE_FREE(quest);
2172 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2173 break;
2175 if (prompt && !yesno(quest)) { /* No */
2176 /* Skip the directory */
2177 lname[strlen(lname)-1] = '/';
2178 if (!seek_list(temp_list, lname))
2179 break;
2180 } else { /* Yes */
2181 SAFE_FREE(rname);
2182 if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2183 break;
2185 normalize_name(rname);
2187 char *tmp_rname =
2188 client_clean_name(ctx, rname);
2189 if (tmp_rname == NULL) {
2190 break;
2192 SAFE_FREE(rname);
2193 rname = smb_xstrdup(tmp_rname);
2194 TALLOC_FREE(tmp_rname);
2195 if (rname == NULL) {
2196 break;
2199 if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2200 !do_mkdir(rname)) {
2201 DEBUG (0, ("Unable to make dir, skipping..."));
2202 /* Skip the directory */
2203 lname[strlen(lname)-1] = '/';
2204 if (!seek_list(temp_list, lname)) {
2205 break;
2209 continue;
2210 } else {
2211 SAFE_FREE(quest);
2212 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2213 break;
2215 if (prompt && !yesno(quest)) {
2216 /* No */
2217 continue;
2220 /* Yes */
2221 SAFE_FREE(rname);
2222 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2223 break;
2227 normalize_name(rname);
2230 char *tmp_rname = client_clean_name(ctx, rname);
2231 if (tmp_rname == NULL) {
2232 break;
2234 SAFE_FREE(rname);
2235 rname = smb_xstrdup(tmp_rname);
2236 TALLOC_FREE(tmp_rname);
2237 if (rname == NULL) {
2238 break;
2241 do_put(rname, lname, false);
2243 free_file_list(file_list);
2244 SAFE_FREE(quest);
2245 SAFE_FREE(lname);
2246 SAFE_FREE(rname);
2249 return 0;
2252 /****************************************************************************
2253 Cancel a print job.
2254 ****************************************************************************/
2256 static int do_cancel(int job)
2258 if (cli_printjob_del(cli, job)) {
2259 d_printf("Job %d cancelled\n",job);
2260 return 0;
2261 } else {
2262 NTSTATUS status = cli_nt_error(cli);
2263 d_printf("Error cancelling job %d : %s\n",
2264 job, nt_errstr(status));
2265 return 1;
2269 /****************************************************************************
2270 Cancel a print job.
2271 ****************************************************************************/
2273 static int cmd_cancel(void)
2275 TALLOC_CTX *ctx = talloc_tos();
2276 char *buf = NULL;
2277 int job;
2279 if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2280 d_printf("cancel <jobid> ...\n");
2281 return 1;
2283 do {
2284 job = atoi(buf);
2285 do_cancel(job);
2286 } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2288 return 0;
2291 /****************************************************************************
2292 Print a file.
2293 ****************************************************************************/
2295 static int cmd_print(void)
2297 TALLOC_CTX *ctx = talloc_tos();
2298 char *lname = NULL;
2299 char *rname = NULL;
2300 char *p = NULL;
2302 if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2303 d_printf("print <filename>\n");
2304 return 1;
2307 rname = talloc_strdup(ctx, lname);
2308 if (!rname) {
2309 return 1;
2311 p = strrchr_m(rname,'/');
2312 if (p) {
2313 rname = talloc_asprintf(ctx,
2314 "%s-%d",
2315 p+1,
2316 (int)getpid());
2318 if (strequal(lname,"-")) {
2319 rname = talloc_asprintf(ctx,
2320 "stdin-%d",
2321 (int)getpid());
2323 if (!rname) {
2324 return 1;
2327 return do_put(rname, lname, false);
2330 /****************************************************************************
2331 Show a print queue entry.
2332 ****************************************************************************/
2334 static void queue_fn(struct print_job_info *p)
2336 d_printf("%-6d %-9d %s\n", (int)p->id, (int)p->size, p->name);
2339 /****************************************************************************
2340 Show a print queue.
2341 ****************************************************************************/
2343 static int cmd_queue(void)
2345 cli_print_queue(cli, queue_fn);
2346 return 0;
2349 /****************************************************************************
2350 Delete some files.
2351 ****************************************************************************/
2353 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2354 const char *dir)
2356 TALLOC_CTX *ctx = talloc_tos();
2357 char *mask = NULL;
2358 struct cli_state *targetcli = NULL;
2359 char *targetname = NULL;
2360 struct cli_credentials *creds = samba_cmdline_get_creds();
2361 NTSTATUS status;
2363 mask = talloc_asprintf(ctx,
2364 "%s%c%s",
2365 dir,
2366 CLI_DIRSEP_CHAR,
2367 finfo->name);
2368 if (!mask) {
2369 return NT_STATUS_NO_MEMORY;
2372 if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
2373 TALLOC_FREE(mask);
2374 return NT_STATUS_OK;
2377 status = cli_resolve_path(ctx, "",
2378 creds,
2379 cli, mask, &targetcli, &targetname);
2380 if (!NT_STATUS_IS_OK(status)) {
2381 goto out;
2384 status = cli_unlink(targetcli, targetname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2385 out:
2386 if (!NT_STATUS_IS_OK(status)) {
2387 d_printf("%s deleting remote file %s\n",
2388 nt_errstr(status), mask);
2390 TALLOC_FREE(mask);
2391 return status;
2394 /****************************************************************************
2395 Delete some files.
2396 ****************************************************************************/
2398 static int cmd_del(void)
2400 TALLOC_CTX *ctx = talloc_tos();
2401 char *mask = NULL;
2402 char *buf = NULL;
2403 NTSTATUS status = NT_STATUS_OK;
2404 uint32_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
2406 if (recurse) {
2407 attribute |= FILE_ATTRIBUTE_DIRECTORY;
2410 mask = talloc_strdup(ctx, client_get_cur_dir());
2411 if (!mask) {
2412 return 1;
2414 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2415 d_printf("del <filename>\n");
2416 return 1;
2418 mask = talloc_asprintf_append(mask, "%s", buf);
2419 if (!mask) {
2420 return 1;
2422 mask = client_clean_name(ctx, mask);
2423 if (mask == NULL) {
2424 return 1;
2427 status = do_list(mask,attribute,do_del,false,false);
2428 if (!NT_STATUS_IS_OK(status)) {
2429 return 1;
2431 return 0;
2434 /****************************************************************************
2435 Delete some files.
2436 ****************************************************************************/
2438 static NTSTATUS delete_remote_files_list(struct cli_state *cli_state,
2439 struct file_list *flist)
2441 NTSTATUS status = NT_STATUS_OK;
2442 struct file_list *deltree_list_iter = NULL;
2443 char *targetname = NULL;
2444 struct cli_state *targetcli = NULL;
2445 struct cli_credentials *creds = samba_cmdline_get_creds();
2446 TALLOC_CTX *ctx = talloc_tos();
2448 for (deltree_list_iter = flist;
2449 deltree_list_iter != NULL;
2450 deltree_list_iter = deltree_list_iter->next) {
2451 status = cli_resolve_path(ctx,
2453 creds,
2454 cli_state,
2455 deltree_list_iter->file_path,
2456 &targetcli,
2457 &targetname);
2458 if (!NT_STATUS_IS_OK(status)) {
2459 d_printf("delete_remote_files %s: %s\n",
2460 deltree_list_iter->file_path,
2461 nt_errstr(status));
2462 return status;
2464 if (CLI_DIRSEP_CHAR == '/') {
2465 /* POSIX. */
2466 status = cli_posix_unlink(targetcli,
2467 targetname);
2468 } else if (deltree_list_iter->isdir) {
2469 status = cli_rmdir(targetcli,
2470 targetname);
2471 } else {
2472 status = cli_unlink(targetcli,
2473 targetname,
2474 FILE_ATTRIBUTE_SYSTEM |
2475 FILE_ATTRIBUTE_HIDDEN);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 d_printf("%s deleting remote %s %s\n",
2479 nt_errstr(status),
2480 deltree_list_iter->isdir ?
2481 "directory" : "file",
2482 deltree_list_iter->file_path);
2483 return status;
2486 return NT_STATUS_OK;
2489 /****************************************************************************
2490 Save a list of files to delete.
2491 ****************************************************************************/
2493 static struct file_list *deltree_list_head;
2495 static NTSTATUS do_deltree_list(struct cli_state *cli_state,
2496 struct file_info *finfo,
2497 const char *dir)
2499 struct file_list **file_list_head_pp = &deltree_list_head;
2500 struct file_list *dt = NULL;
2502 if (!do_this_one(finfo)) {
2503 return NT_STATUS_OK;
2506 /* skip if this is . or .. */
2507 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2508 return NT_STATUS_OK;
2511 dt = talloc_zero(NULL, struct file_list);
2512 if (dt == NULL) {
2513 return NT_STATUS_NO_MEMORY;
2516 /* create absolute filename for cli_ntcreate() */
2517 dt->file_path = talloc_asprintf(dt,
2518 "%s%s%s",
2519 dir,
2520 CLI_DIRSEP_STR,
2521 finfo->name);
2522 if (dt->file_path == NULL) {
2523 TALLOC_FREE(dt);
2524 return NT_STATUS_NO_MEMORY;
2527 if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
2528 dt->isdir = true;
2531 DLIST_ADD(*file_list_head_pp, dt);
2532 return NT_STATUS_OK;
2535 static int cmd_deltree(void)
2537 TALLOC_CTX *ctx = talloc_tos();
2538 char *buf = NULL;
2539 NTSTATUS status = NT_STATUS_OK;
2540 struct file_list *deltree_list_norecurse = NULL;
2541 struct file_list *deltree_list_iter = NULL;
2542 uint32_t attribute = FILE_ATTRIBUTE_SYSTEM |
2543 FILE_ATTRIBUTE_HIDDEN |
2544 FILE_ATTRIBUTE_DIRECTORY;
2545 bool ok;
2546 char *mask = talloc_strdup(ctx, client_get_cur_dir());
2547 if (mask == NULL) {
2548 return 1;
2550 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
2551 if (!ok) {
2552 d_printf("deltree <filename>\n");
2553 return 1;
2555 mask = talloc_asprintf_append(mask, "%s", buf);
2556 if (mask == NULL) {
2557 return 1;
2559 mask = client_clean_name(ctx, mask);
2560 if (mask == NULL) {
2561 return 1;
2564 deltree_list_head = NULL;
2567 * Get the list of directories to
2568 * delete (in case mask has a wildcard).
2570 status = do_list(mask, attribute, do_deltree_list, false, true);
2571 if (!NT_STATUS_IS_OK(status)) {
2572 goto err;
2574 deltree_list_norecurse = deltree_list_head;
2575 deltree_list_head = NULL;
2577 for (deltree_list_iter = deltree_list_norecurse;
2578 deltree_list_iter != NULL;
2579 deltree_list_iter = deltree_list_iter->next) {
2581 if (deltree_list_iter->isdir == false) {
2582 char *targetname = NULL;
2583 struct cli_state *targetcli = NULL;
2584 struct cli_credentials *creds = samba_cmdline_get_creds();
2585 status = cli_resolve_path(ctx,
2587 creds,
2588 cli,
2589 deltree_list_iter->file_path,
2590 &targetcli,
2591 &targetname);
2592 if (!NT_STATUS_IS_OK(status)) {
2593 goto err;
2595 /* Just a regular file. */
2596 if (CLI_DIRSEP_CHAR == '/') {
2597 /* POSIX. */
2598 status = cli_posix_unlink(targetcli,
2599 targetname);
2600 } else {
2601 status = cli_unlink(targetcli,
2602 targetname,
2603 FILE_ATTRIBUTE_SYSTEM |
2604 FILE_ATTRIBUTE_HIDDEN);
2606 if (!NT_STATUS_IS_OK(status)) {
2607 goto err;
2609 continue;
2613 * Get the list of files or directories to
2614 * delete in depth order.
2616 status = do_list(deltree_list_iter->file_path,
2617 attribute,
2618 do_deltree_list,
2619 true,
2620 true);
2621 if (!NT_STATUS_IS_OK(status)) {
2622 goto err;
2624 status = delete_remote_files_list(cli, deltree_list_head);
2625 free_file_list(deltree_list_head);
2626 deltree_list_head = NULL;
2627 if (!NT_STATUS_IS_OK(status)) {
2628 goto err;
2632 free_file_list(deltree_list_norecurse);
2633 free_file_list(deltree_list_head);
2634 return 0;
2636 err:
2638 free_file_list(deltree_list_norecurse);
2639 free_file_list(deltree_list_head);
2640 deltree_list_head = NULL;
2641 return 1;
2645 /****************************************************************************
2646 Wildcard delete some files.
2647 ****************************************************************************/
2649 static int cmd_wdel(void)
2651 TALLOC_CTX *ctx = talloc_tos();
2652 char *mask = NULL;
2653 char *buf = NULL;
2654 uint32_t attribute;
2655 struct cli_state *targetcli;
2656 char *targetname = NULL;
2657 struct cli_credentials *creds = samba_cmdline_get_creds();
2658 NTSTATUS status;
2660 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2661 d_printf("wdel 0x<attrib> <wcard>\n");
2662 return 1;
2665 attribute = (uint32_t)strtol(buf, (char **)NULL, 16);
2667 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2668 d_printf("wdel 0x<attrib> <wcard>\n");
2669 return 1;
2672 mask = talloc_asprintf(ctx, "%s%s",
2673 client_get_cur_dir(),
2674 buf);
2675 if (!mask) {
2676 return 1;
2678 mask = client_clean_name(ctx, mask);
2679 if (mask == NULL) {
2680 return 1;
2683 status = cli_resolve_path(ctx, "",
2684 creds,
2685 cli, mask, &targetcli, &targetname);
2686 if (!NT_STATUS_IS_OK(status)) {
2687 d_printf("cmd_wdel %s: %s\n", mask, nt_errstr(status));
2688 return 1;
2691 status = cli_unlink(targetcli, targetname, attribute);
2692 if (!NT_STATUS_IS_OK(status)) {
2693 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2694 targetname);
2696 return 0;
2699 /****************************************************************************
2700 ****************************************************************************/
2702 static int cmd_open(void)
2704 TALLOC_CTX *ctx = talloc_tos();
2705 char *mask = NULL;
2706 char *buf = NULL;
2707 char *targetname = NULL;
2708 struct cli_state *targetcli;
2709 uint16_t fnum = (uint16_t)-1;
2710 struct cli_credentials *creds = samba_cmdline_get_creds();
2711 NTSTATUS status;
2713 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2714 d_printf("open <filename>\n");
2715 return 1;
2717 mask = talloc_asprintf(ctx,
2718 "%s%s",
2719 client_get_cur_dir(),
2720 buf);
2721 if (!mask) {
2722 return 1;
2725 mask = client_clean_name(ctx, mask);
2726 if (mask == NULL) {
2727 return 1;
2730 status = cli_resolve_path(ctx, "",
2731 creds,
2732 cli, mask, &targetcli, &targetname);
2733 if (!NT_STATUS_IS_OK(status)) {
2734 d_printf("open %s: %s\n", mask, nt_errstr(status));
2735 return 1;
2738 status = cli_ntcreate(targetcli, targetname, 0,
2739 FILE_READ_DATA|FILE_WRITE_DATA, 0,
2740 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2741 0x0, 0x0, &fnum, NULL);
2742 if (!NT_STATUS_IS_OK(status)) {
2743 status = cli_ntcreate(targetcli, targetname, 0,
2744 FILE_READ_DATA, 0,
2745 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2746 0x0, 0x0, &fnum, NULL);
2747 if (NT_STATUS_IS_OK(status)) {
2748 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2749 } else {
2750 d_printf("Failed to open file %s. %s\n",
2751 targetname, nt_errstr(status));
2753 } else {
2754 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2756 return 0;
2759 static int cmd_posix_encrypt(void)
2761 TALLOC_CTX *ctx = talloc_tos();
2762 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2763 char *domain = NULL;
2764 char *user = NULL;
2765 char *password = NULL;
2766 struct cli_credentials *creds = NULL;
2767 struct cli_credentials *lcreds = NULL;
2769 if (next_token_talloc(ctx, &cmd_ptr, &domain, NULL)) {
2771 if (!next_token_talloc(ctx, &cmd_ptr, &user, NULL)) {
2772 d_printf("posix_encrypt domain user password\n");
2773 return 1;
2776 if (!next_token_talloc(ctx, &cmd_ptr, &password, NULL)) {
2777 d_printf("posix_encrypt domain user password\n");
2778 return 1;
2781 lcreds = cli_session_creds_init(ctx,
2782 user,
2783 domain,
2784 NULL, /* realm */
2785 password,
2786 false, /* use_kerberos */
2787 false, /* fallback_after_kerberos */
2788 false, /* use_ccache */
2789 false); /* password_is_nt_hash */
2790 if (lcreds == NULL) {
2791 d_printf("cli_session_creds_init() failed.\n");
2792 return -1;
2794 creds = lcreds;
2795 } else {
2796 bool auth_requested = false;
2798 creds = samba_cmdline_get_creds();
2800 auth_requested = cli_credentials_authentication_requested(creds);
2801 if (!auth_requested) {
2802 d_printf("posix_encrypt domain user password\n");
2803 return 1;
2807 status = cli_smb1_setup_encryption(cli, creds);
2808 /* gensec currently references the creds so we can't free them here */
2809 talloc_unlink(ctx, lcreds);
2810 if (!NT_STATUS_IS_OK(status)) {
2811 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2812 } else {
2813 bool ok;
2815 d_printf("encryption on\n");
2816 ok = cli_credentials_set_smb_encryption(creds,
2817 SMB_ENCRYPTION_REQUIRED,
2818 CRED_SPECIFIED);
2819 SMB_ASSERT(ok);
2822 return 0;
2825 /****************************************************************************
2826 ****************************************************************************/
2828 static int cmd_posix_open(void)
2830 TALLOC_CTX *ctx = talloc_tos();
2831 char *mask = NULL;
2832 char *buf = NULL;
2833 char *targetname = NULL;
2834 struct cli_state *targetcli;
2835 mode_t mode;
2836 uint16_t fnum;
2837 struct cli_credentials *creds = samba_cmdline_get_creds();
2838 NTSTATUS status;
2840 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2841 d_printf("posix_open <filename> 0<mode>\n");
2842 return 1;
2844 mask = talloc_asprintf(ctx,
2845 "%s%s",
2846 client_get_cur_dir(),
2847 buf);
2848 if (!mask) {
2849 return 1;
2851 mask = client_clean_name(ctx, mask);
2852 if (mask == NULL) {
2853 return 1;
2856 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2857 d_printf("posix_open <filename> 0<mode>\n");
2858 return 1;
2860 if (CLI_DIRSEP_CHAR != '/') {
2861 d_printf("Command \"posix\" must be issued before "
2862 "the \"posix_open\" command can be used.\n");
2863 return 1;
2865 mode = (mode_t)strtol(buf, (char **)NULL, 8);
2867 status = cli_resolve_path(ctx, "",
2868 creds,
2869 cli, mask, &targetcli, &targetname);
2870 if (!NT_STATUS_IS_OK(status)) {
2871 d_printf("posix_open %s: %s\n", mask, nt_errstr(status));
2872 return 1;
2875 status = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode,
2876 &fnum);
2877 if (!NT_STATUS_IS_OK(status)) {
2878 status = cli_posix_open(targetcli, targetname,
2879 O_CREAT|O_RDONLY, mode, &fnum);
2880 if (!NT_STATUS_IS_OK(status)) {
2881 d_printf("Failed to open file %s. %s\n", targetname,
2882 nt_errstr(status));
2883 } else {
2884 d_printf("posix_open file %s: for readonly fnum %d\n",
2885 targetname, fnum);
2887 } else {
2888 d_printf("posix_open file %s: for read/write fnum %d\n",
2889 targetname, fnum);
2892 return 0;
2895 static int cmd_posix_mkdir(void)
2897 TALLOC_CTX *ctx = talloc_tos();
2898 char *mask = NULL;
2899 char *buf = NULL;
2900 char *targetname = NULL;
2901 struct cli_state *targetcli;
2902 mode_t mode;
2903 struct cli_credentials *creds = samba_cmdline_get_creds();
2904 NTSTATUS status;
2906 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2907 d_printf("posix_mkdir <filename> 0<mode>\n");
2908 return 1;
2910 mask = talloc_asprintf(ctx,
2911 "%s%s",
2912 client_get_cur_dir(),
2913 buf);
2914 if (!mask) {
2915 return 1;
2917 mask = client_clean_name(ctx, mask);
2918 if (mask == NULL) {
2919 return 1;
2922 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2923 d_printf("posix_mkdir <filename> 0<mode>\n");
2924 return 1;
2926 if (CLI_DIRSEP_CHAR != '/') {
2927 d_printf("Command \"posix\" must be issued before "
2928 "the \"posix_mkdir\" command can be used.\n");
2929 return 1;
2931 mode = (mode_t)strtol(buf, (char **)NULL, 8);
2933 status = cli_resolve_path(ctx, "",
2934 creds,
2935 cli, mask, &targetcli, &targetname);
2936 if (!NT_STATUS_IS_OK(status)) {
2937 d_printf("posix_mkdir %s: %s\n", mask, nt_errstr(status));
2938 return 1;
2941 status = cli_posix_mkdir(targetcli, targetname, mode);
2942 if (!NT_STATUS_IS_OK(status)) {
2943 d_printf("Failed to open file %s. %s\n",
2944 targetname, nt_errstr(status));
2945 } else {
2946 d_printf("posix_mkdir created directory %s\n", targetname);
2948 return 0;
2951 static int cmd_posix_unlink(void)
2953 TALLOC_CTX *ctx = talloc_tos();
2954 char *mask = NULL;
2955 char *buf = NULL;
2956 char *targetname = NULL;
2957 struct cli_state *targetcli;
2958 struct cli_credentials *creds = samba_cmdline_get_creds();
2959 NTSTATUS status;
2961 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2962 d_printf("posix_unlink <filename>\n");
2963 return 1;
2965 if (CLI_DIRSEP_CHAR != '/') {
2966 d_printf("Command \"posix\" must be issued before "
2967 "the \"posix_unlink\" command can be used.\n");
2968 return 1;
2970 mask = talloc_asprintf(ctx,
2971 "%s%s",
2972 client_get_cur_dir(),
2973 buf);
2974 if (!mask) {
2975 return 1;
2977 mask = client_clean_name(ctx, mask);
2978 if (mask == NULL) {
2979 return 1;
2982 status = cli_resolve_path(ctx, "",
2983 creds,
2984 cli, mask, &targetcli, &targetname);
2985 if (!NT_STATUS_IS_OK(status)) {
2986 d_printf("posix_unlink %s: %s\n", mask, nt_errstr(status));
2987 return 1;
2990 status = cli_posix_unlink(targetcli, targetname);
2991 if (!NT_STATUS_IS_OK(status)) {
2992 d_printf("Failed to unlink file %s. %s\n",
2993 targetname, nt_errstr(status));
2994 } else {
2995 d_printf("posix_unlink deleted file %s\n", targetname);
2998 return 0;
3001 static int cmd_posix_rmdir(void)
3003 TALLOC_CTX *ctx = talloc_tos();
3004 char *mask = NULL;
3005 char *buf = NULL;
3006 char *targetname = NULL;
3007 struct cli_state *targetcli;
3008 struct cli_credentials *creds = samba_cmdline_get_creds();
3009 NTSTATUS status;
3011 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3012 d_printf("posix_rmdir <filename>\n");
3013 return 1;
3015 if (CLI_DIRSEP_CHAR != '/') {
3016 d_printf("Command \"posix\" must be issued before "
3017 "the \"posix_rmdir\" command can be used.\n");
3018 return 1;
3020 mask = talloc_asprintf(ctx,
3021 "%s%s",
3022 client_get_cur_dir(),
3023 buf);
3024 if (!mask) {
3025 return 1;
3027 mask = client_clean_name(ctx, mask);
3028 if (mask == NULL) {
3029 return 1;
3032 status = cli_resolve_path(ctx, "",
3033 creds,
3034 cli, mask, &targetcli, &targetname);
3035 if (!NT_STATUS_IS_OK(status)) {
3036 d_printf("posix_rmdir %s: %s\n", mask, nt_errstr(status));
3037 return 1;
3040 status = cli_posix_rmdir(targetcli, targetname);
3041 if (!NT_STATUS_IS_OK(status)) {
3042 d_printf("Failed to unlink directory %s. %s\n",
3043 targetname, nt_errstr(status));
3044 } else {
3045 d_printf("posix_rmdir deleted directory %s\n", targetname);
3048 return 0;
3051 static int cmd_close(void)
3053 TALLOC_CTX *ctx = talloc_tos();
3054 char *buf = NULL;
3055 int fnum;
3056 NTSTATUS status;
3058 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3059 d_printf("close <fnum>\n");
3060 return 1;
3063 fnum = atoi(buf);
3064 /* We really should use the targetcli here.... */
3065 status = cli_close(cli, fnum);
3066 if (!NT_STATUS_IS_OK(status)) {
3067 d_printf("close %d: %s\n", fnum, nt_errstr(status));
3068 return 1;
3070 return 0;
3073 static int cmd_posix(void)
3075 TALLOC_CTX *ctx = talloc_tos();
3076 uint16_t major, minor;
3077 uint32_t caplow, caphigh;
3078 char *caps;
3079 NTSTATUS status;
3081 if (!SERVER_HAS_UNIX_CIFS(cli)) {
3082 d_printf("Server doesn't support UNIX CIFS extensions.\n");
3083 return 1;
3086 status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
3087 &caphigh);
3088 if (!NT_STATUS_IS_OK(status)) {
3089 d_printf("Can't get UNIX CIFS extensions version from "
3090 "server: %s\n", nt_errstr(status));
3091 return 1;
3094 d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
3096 caps = talloc_strdup(ctx, "");
3097 if (!caps) {
3098 return 1;
3100 if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
3101 caps = talloc_asprintf_append(caps, "locks ");
3102 if (!caps) {
3103 return 1;
3106 if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
3107 caps = talloc_asprintf_append(caps, "acls ");
3108 if (!caps) {
3109 return 1;
3112 if (caplow & CIFS_UNIX_XATTTR_CAP) {
3113 caps = talloc_asprintf_append(caps, "eas ");
3114 if (!caps) {
3115 return 1;
3118 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3119 caps = talloc_asprintf_append(caps, "pathnames ");
3120 if (!caps) {
3121 return 1;
3124 if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
3125 caps = talloc_asprintf_append(caps, "posix_path_operations ");
3126 if (!caps) {
3127 return 1;
3130 if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
3131 caps = talloc_asprintf_append(caps, "large_read ");
3132 if (!caps) {
3133 return 1;
3136 if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
3137 caps = talloc_asprintf_append(caps, "large_write ");
3138 if (!caps) {
3139 return 1;
3142 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
3143 caps = talloc_asprintf_append(caps, "posix_encrypt ");
3144 if (!caps) {
3145 return 1;
3148 if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
3149 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
3150 if (!caps) {
3151 return 1;
3155 if (*caps && caps[strlen(caps)-1] == ' ') {
3156 caps[strlen(caps)-1] = '\0';
3159 d_printf("Server supports CIFS capabilities %s\n", caps);
3161 status = cli_set_unix_extensions_capabilities(cli, major, minor,
3162 caplow, caphigh);
3163 if (!NT_STATUS_IS_OK(status)) {
3164 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
3165 nt_errstr(status));
3166 return 1;
3169 if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3170 CLI_DIRSEP_CHAR = '/';
3171 *CLI_DIRSEP_STR = '/';
3172 client_set_cur_dir(CLI_DIRSEP_STR);
3175 return 0;
3178 static int cmd_lock(void)
3180 TALLOC_CTX *ctx = talloc_tos();
3181 char *buf = NULL;
3182 uint64_t start, len;
3183 enum brl_type lock_type;
3184 int fnum;
3185 NTSTATUS status;
3187 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3188 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3189 return 1;
3191 fnum = atoi(buf);
3193 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3194 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3195 return 1;
3198 if (*buf == 'r' || *buf == 'R') {
3199 lock_type = READ_LOCK;
3200 } else if (*buf == 'w' || *buf == 'W') {
3201 lock_type = WRITE_LOCK;
3202 } else {
3203 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3204 return 1;
3207 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3208 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3209 return 1;
3212 start = (uint64_t)strtol(buf, (char **)NULL, 16);
3214 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3215 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3216 return 1;
3219 if (CLI_DIRSEP_CHAR != '/') {
3220 d_printf("Command \"posix\" must be issued before "
3221 "the \"lock\" command can be used.\n");
3222 return 1;
3225 len = (uint64_t)strtol(buf, (char **)NULL, 16);
3227 status = cli_posix_lock(cli, fnum, start, len, true, lock_type);
3228 if (!NT_STATUS_IS_OK(status)) {
3229 d_printf("lock failed %d: %s\n", fnum, nt_errstr(status));
3232 return 0;
3235 static int cmd_unlock(void)
3237 TALLOC_CTX *ctx = talloc_tos();
3238 char *buf = NULL;
3239 uint64_t start, len;
3240 int fnum;
3241 NTSTATUS status;
3243 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3244 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3245 return 1;
3247 fnum = atoi(buf);
3249 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3250 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3251 return 1;
3254 start = (uint64_t)strtol(buf, (char **)NULL, 16);
3256 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3257 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3258 return 1;
3261 if (CLI_DIRSEP_CHAR != '/') {
3262 d_printf("Command \"posix\" must be issued before "
3263 "the \"unlock\" command can be used.\n");
3264 return 1;
3267 len = (uint64_t)strtol(buf, (char **)NULL, 16);
3269 status = cli_posix_unlock(cli, fnum, start, len);
3270 if (!NT_STATUS_IS_OK(status)) {
3271 d_printf("unlock failed %d: %s\n", fnum, nt_errstr(status));
3274 return 0;
3277 static int cmd_posix_whoami(void)
3279 TALLOC_CTX *ctx = talloc_tos();
3280 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3281 uint64_t uid = 0;
3282 uint64_t gid = 0;
3283 uint32_t num_gids = 0;
3284 uint32_t num_sids = 0;
3285 uint64_t *gids = NULL;
3286 struct dom_sid *sids = NULL;
3287 bool guest = false;
3288 uint32_t i;
3290 if (CLI_DIRSEP_CHAR != '/') {
3291 d_printf("Command \"posix\" must be issued before "
3292 "the \"posix_whoami\" command can be used.\n");
3293 return 1;
3296 status = cli_posix_whoami(cli,
3297 ctx,
3298 &uid,
3299 &gid,
3300 &num_gids,
3301 &gids,
3302 &num_sids,
3303 &sids,
3304 &guest);
3306 if (!NT_STATUS_IS_OK(status)) {
3307 d_printf("posix_whoami failed with error %s\n", nt_errstr(status));
3308 return 1;
3311 d_printf("GUEST:%s\n", guest ? "True" : "False");
3312 d_printf("UID:%" PRIu64 "\n", uid);
3313 d_printf("GID:%" PRIu64 "\n", gid);
3314 d_printf("NUM_GIDS:%" PRIu32 "\n", num_gids);
3315 for (i = 0; i < num_gids; i++) {
3316 d_printf("GIDS[%" PRIu32 "]:%" PRIu64 "\n", i, gids[i]);
3318 d_printf("NUM_SIDS:%" PRIu32 "\n", num_sids);
3319 for (i = 0; i < num_sids; i++) {
3320 struct dom_sid_buf buf;
3321 d_printf("SIDS[%" PRIu32 "]:%s\n",
3323 dom_sid_str_buf(&sids[i], &buf));
3325 return 0;
3329 /****************************************************************************
3330 Remove a directory.
3331 ****************************************************************************/
3333 static int cmd_rmdir(void)
3335 TALLOC_CTX *ctx = talloc_tos();
3336 char *mask = NULL;
3337 char *buf = NULL;
3338 char *targetname = NULL;
3339 struct cli_state *targetcli;
3340 struct cli_credentials *creds = samba_cmdline_get_creds();
3341 NTSTATUS status;
3343 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3344 d_printf("rmdir <dirname>\n");
3345 return 1;
3347 mask = talloc_asprintf(ctx,
3348 "%s%s",
3349 client_get_cur_dir(),
3350 buf);
3351 if (!mask) {
3352 return 1;
3354 mask = client_clean_name(ctx, mask);
3355 if (mask == NULL) {
3356 return 1;
3359 status = cli_resolve_path(ctx, "",
3360 creds,
3361 cli, mask, &targetcli, &targetname);
3362 if (!NT_STATUS_IS_OK(status)) {
3363 d_printf("rmdir %s: %s\n", mask, nt_errstr(status));
3364 return 1;
3367 status = cli_rmdir(targetcli, targetname);
3368 if (!NT_STATUS_IS_OK(status)) {
3369 d_printf("%s removing remote directory file %s\n",
3370 nt_errstr(status), mask);
3373 return 0;
3376 /****************************************************************************
3377 UNIX hardlink.
3378 ****************************************************************************/
3380 static int cmd_link(void)
3382 TALLOC_CTX *ctx = talloc_tos();
3383 char *oldname = NULL;
3384 char *newname = NULL;
3385 char *buf = NULL;
3386 char *buf2 = NULL;
3387 char *targetname = NULL;
3388 struct cli_state *targetcli;
3389 struct cli_credentials *creds = samba_cmdline_get_creds();
3390 NTSTATUS status;
3392 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3393 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3394 d_printf("link <oldname> <newname>\n");
3395 return 1;
3397 oldname = talloc_asprintf(ctx,
3398 "%s%s",
3399 client_get_cur_dir(),
3400 buf);
3401 if (!oldname) {
3402 return 1;
3404 oldname = client_clean_name(ctx, oldname);
3405 if (oldname == NULL) {
3406 return 1;
3408 newname = talloc_asprintf(ctx,
3409 "%s%s",
3410 client_get_cur_dir(),
3411 buf2);
3412 if (!newname) {
3413 return 1;
3415 newname = client_clean_name(ctx, newname);
3416 if (newname == NULL) {
3417 return 1;
3420 status = cli_resolve_path(ctx, "",
3421 creds,
3422 cli, oldname, &targetcli, &targetname);
3423 if (!NT_STATUS_IS_OK(status)) {
3424 d_printf("link %s: %s\n", oldname, nt_errstr(status));
3425 return 1;
3428 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3429 d_printf("Server doesn't support UNIX CIFS calls.\n");
3430 return 1;
3433 if (CLI_DIRSEP_CHAR != '/') {
3434 d_printf("Command \"posix\" must be issued before "
3435 "the \"link\" command can be used.\n");
3436 return 1;
3439 status = cli_posix_hardlink(targetcli, targetname, newname);
3440 if (!NT_STATUS_IS_OK(status)) {
3441 d_printf("%s linking files (%s -> %s)\n",
3442 nt_errstr(status), newname, oldname);
3443 return 1;
3445 return 0;
3448 /****************************************************************************
3449 UNIX readlink.
3450 ****************************************************************************/
3452 static int cmd_readlink(void)
3454 TALLOC_CTX *ctx = talloc_tos();
3455 char *name= NULL;
3456 char *buf = NULL;
3457 char *targetname = NULL;
3458 char *linkname = NULL;
3459 char *printname = NULL;
3460 uint32_t flags;
3461 struct cli_state *targetcli;
3462 struct cli_credentials *creds = samba_cmdline_get_creds();
3463 NTSTATUS status;
3465 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3466 d_printf("readlink <name>\n");
3467 return 1;
3469 name = talloc_asprintf(ctx,
3470 "%s%s",
3471 client_get_cur_dir(),
3472 buf);
3473 if (!name) {
3474 return 1;
3476 name = client_clean_name(ctx, name);
3477 if (name == NULL) {
3478 return 1;
3481 status = cli_resolve_path(ctx, "",
3482 creds,
3483 cli, name, &targetcli, &targetname);
3484 if (!NT_STATUS_IS_OK(status)) {
3485 d_printf("readlink %s: %s\n", name, nt_errstr(status));
3486 return 1;
3489 status = cli_readlink(
3490 cli, name, talloc_tos(), &linkname, &printname, &flags);
3491 if (!NT_STATUS_IS_OK(status)) {
3492 d_printf("%s readlink on file %s\n",
3493 nt_errstr(status), name);
3494 return 1;
3497 d_printf("%s -> %s\n", name, linkname);
3499 TALLOC_FREE(linkname);
3501 return 0;
3505 /****************************************************************************
3506 UNIX symlink.
3507 ****************************************************************************/
3509 static int cmd_symlink(void)
3511 TALLOC_CTX *ctx = talloc_tos();
3512 char *link_target = NULL;
3513 char *newname = NULL;
3514 char *buf = NULL;
3515 char *buf2 = NULL;
3516 struct cli_state *newcli;
3517 struct cli_credentials *creds = samba_cmdline_get_creds();
3518 NTSTATUS status;
3520 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3521 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3522 d_printf("symlink <link_target> <newname>\n");
3523 return 1;
3525 /* Oldname (link target) must be an untouched blob. */
3526 link_target = buf;
3528 if (SERVER_HAS_UNIX_CIFS(cli)) {
3529 if (CLI_DIRSEP_CHAR != '/') {
3530 d_printf("Command \"posix\" must be issued before "
3531 "the \"symlink\" command can be used.\n");
3532 return 1;
3534 newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
3535 buf2);
3536 if (!newname) {
3537 return 1;
3539 newname = client_clean_name(ctx, newname);
3540 if (newname == NULL) {
3541 return 1;
3543 /* New name must be present in share namespace. */
3544 status = cli_resolve_path(ctx, "",
3545 creds,
3546 cli, newname,
3547 &newcli, &newname);
3548 if (!NT_STATUS_IS_OK(status)) {
3549 d_printf("link %s: %s\n", newname,
3550 nt_errstr(status));
3551 return 1;
3553 status = cli_posix_symlink(newcli, link_target, newname);
3554 } else {
3555 status = cli_symlink(
3556 cli, link_target, buf2,
3557 buf2[0] == '\\' ? 0 : SYMLINK_FLAG_RELATIVE);
3560 if (!NT_STATUS_IS_OK(status)) {
3561 d_printf("%s symlinking files (%s -> %s)\n",
3562 nt_errstr(status), newname, link_target);
3563 return 1;
3566 return 0;
3569 /****************************************************************************
3570 UNIX chmod.
3571 ****************************************************************************/
3573 static int cmd_chmod(void)
3575 TALLOC_CTX *ctx = talloc_tos();
3576 char *src = NULL;
3577 char *buf = NULL;
3578 char *buf2 = NULL;
3579 char *targetname = NULL;
3580 struct cli_state *targetcli;
3581 mode_t mode;
3582 struct cli_credentials *creds = samba_cmdline_get_creds();
3583 NTSTATUS status;
3585 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3586 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3587 d_printf("chmod mode file\n");
3588 return 1;
3590 src = talloc_asprintf(ctx,
3591 "%s%s",
3592 client_get_cur_dir(),
3593 buf2);
3594 if (!src) {
3595 return 1;
3597 src = client_clean_name(ctx, src);
3598 if (src == NULL) {
3599 return 1;
3602 mode = (mode_t)strtol(buf, NULL, 8);
3604 status = cli_resolve_path(ctx, "",
3605 creds,
3606 cli, src, &targetcli, &targetname);
3607 if (!NT_STATUS_IS_OK(status)) {
3608 d_printf("chmod %s: %s\n", src, nt_errstr(status));
3609 return 1;
3612 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3613 d_printf("Server doesn't support UNIX CIFS calls.\n");
3614 return 1;
3617 if (CLI_DIRSEP_CHAR != '/') {
3618 d_printf("Command \"posix\" must be issued before "
3619 "the \"chmod\" command can be used.\n");
3620 return 1;
3623 status = cli_posix_chmod(targetcli, targetname, mode);
3624 if (!NT_STATUS_IS_OK(status)) {
3625 d_printf("%s chmod file %s 0%o\n",
3626 nt_errstr(status), src, (unsigned int)mode);
3627 return 1;
3630 return 0;
3633 static const char *filetype_to_str(mode_t mode)
3635 if (S_ISREG(mode)) {
3636 return "regular file";
3637 } else if (S_ISDIR(mode)) {
3638 return "directory";
3639 } else
3640 #ifdef S_ISCHR
3641 if (S_ISCHR(mode)) {
3642 return "character device";
3643 } else
3644 #endif
3645 #ifdef S_ISBLK
3646 if (S_ISBLK(mode)) {
3647 return "block device";
3648 } else
3649 #endif
3650 #ifdef S_ISFIFO
3651 if (S_ISFIFO(mode)) {
3652 return "fifo";
3653 } else
3654 #endif
3655 #ifdef S_ISLNK
3656 if (S_ISLNK(mode)) {
3657 return "symbolic link";
3658 } else
3659 #endif
3660 #ifdef S_ISSOCK
3661 if (S_ISSOCK(mode)) {
3662 return "socket";
3663 } else
3664 #endif
3665 return "";
3668 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3670 if (m & bt) {
3671 return ret;
3672 } else {
3673 return '-';
3677 static char *unix_mode_to_str(char *s, mode_t m)
3679 char *p = s;
3680 const char *str = filetype_to_str(m);
3682 switch(str[0]) {
3683 case 'd':
3684 *p++ = 'd';
3685 break;
3686 case 'c':
3687 *p++ = 'c';
3688 break;
3689 case 'b':
3690 *p++ = 'b';
3691 break;
3692 case 'f':
3693 *p++ = 'p';
3694 break;
3695 case 's':
3696 *p++ = str[1] == 'y' ? 'l' : 's';
3697 break;
3698 case 'r':
3699 default:
3700 *p++ = '-';
3701 break;
3703 *p++ = rwx_to_str(m, S_IRUSR, 'r');
3704 *p++ = rwx_to_str(m, S_IWUSR, 'w');
3705 *p++ = rwx_to_str(m, S_IXUSR, 'x');
3706 *p++ = rwx_to_str(m, S_IRGRP, 'r');
3707 *p++ = rwx_to_str(m, S_IWGRP, 'w');
3708 *p++ = rwx_to_str(m, S_IXGRP, 'x');
3709 *p++ = rwx_to_str(m, S_IROTH, 'r');
3710 *p++ = rwx_to_str(m, S_IWOTH, 'w');
3711 *p++ = rwx_to_str(m, S_IXOTH, 'x');
3712 *p++ = '\0';
3713 return s;
3716 /****************************************************************************
3717 Utility function for UNIX getfacl.
3718 ****************************************************************************/
3720 static char *perms_to_string(fstring permstr, unsigned char perms)
3722 fstrcpy(permstr, "---");
3723 if (perms & SMB_POSIX_ACL_READ) {
3724 permstr[0] = 'r';
3726 if (perms & SMB_POSIX_ACL_WRITE) {
3727 permstr[1] = 'w';
3729 if (perms & SMB_POSIX_ACL_EXECUTE) {
3730 permstr[2] = 'x';
3732 return permstr;
3735 /****************************************************************************
3736 UNIX getfacl.
3737 ****************************************************************************/
3739 static int cmd_getfacl(void)
3741 TALLOC_CTX *ctx = talloc_tos();
3742 char *src = NULL;
3743 char *name = NULL;
3744 char *targetname = NULL;
3745 struct cli_state *targetcli;
3746 uint16_t major, minor;
3747 uint32_t caplow, caphigh;
3748 char *retbuf = NULL;
3749 size_t rb_size = 0;
3750 SMB_STRUCT_STAT sbuf;
3751 size_t num_file_acls = 0;
3752 size_t num_dir_acls = 0;
3753 size_t expected_buflen;
3754 uint16_t i;
3755 struct cli_credentials *creds = samba_cmdline_get_creds();
3756 NTSTATUS status;
3758 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3759 d_printf("getfacl filename\n");
3760 return 1;
3762 src = talloc_asprintf(ctx,
3763 "%s%s",
3764 client_get_cur_dir(),
3765 name);
3766 if (!src) {
3767 return 1;
3769 src = client_clean_name(ctx, src);
3770 if (src == NULL) {
3771 return 1;
3774 status = cli_resolve_path(ctx, "",
3775 creds,
3776 cli, src, &targetcli, &targetname);
3777 if (!NT_STATUS_IS_OK(status)) {
3778 d_printf("stat %s: %s\n", src, nt_errstr(status));
3779 return 1;
3782 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3783 d_printf("Server doesn't support UNIX CIFS calls.\n");
3784 return 1;
3787 if (CLI_DIRSEP_CHAR != '/') {
3788 d_printf("Command \"posix\" must be issued before "
3789 "the \"getfacl\" command can be used.\n");
3790 return 1;
3793 status = cli_unix_extensions_version(targetcli, &major, &minor,
3794 &caplow, &caphigh);
3795 if (!NT_STATUS_IS_OK(status)) {
3796 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3797 nt_errstr(status));
3798 return 1;
3801 if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3802 d_printf("This server supports UNIX extensions "
3803 "but doesn't support POSIX ACLs.\n");
3804 return 1;
3807 status = cli_posix_stat(targetcli, targetname, &sbuf);
3808 if (!NT_STATUS_IS_OK(status)) {
3809 d_printf("%s getfacl doing a stat on file %s\n",
3810 nt_errstr(status), src);
3811 return 1;
3814 status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf);
3815 if (!NT_STATUS_IS_OK(status)) {
3816 d_printf("%s getfacl file %s\n",
3817 nt_errstr(status), src);
3818 return 1;
3821 /* ToDo : Print out the ACL values. */
3822 if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3823 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3824 src, (unsigned int)CVAL(retbuf,0) );
3825 return 1;
3828 num_file_acls = SVAL(retbuf,2);
3829 num_dir_acls = SVAL(retbuf,4);
3832 * No overflow check, num_*_acls comes from a 16-bit value,
3833 * and we expect expected_buflen (size_t) to be of at least 32
3834 * bit.
3836 expected_buflen = SMB_POSIX_ACL_HEADER_SIZE +
3837 SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls);
3839 if (rb_size != expected_buflen) {
3840 d_printf("getfacl file %s, incorrect POSIX acl buffer size "
3841 "(should be %zu, was %zu).\n",
3842 src,
3843 expected_buflen,
3844 rb_size);
3845 return 1;
3848 d_printf("# file: %s\n", src);
3849 d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3851 if (num_file_acls == 0 && num_dir_acls == 0) {
3852 d_printf("No acls found.\n");
3855 for (i = 0; i < num_file_acls; i++) {
3856 uint32_t uorg;
3857 fstring permstring;
3858 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3859 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3861 switch(tagtype) {
3862 case SMB_POSIX_ACL_USER_OBJ:
3863 d_printf("user::");
3864 break;
3865 case SMB_POSIX_ACL_USER:
3866 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3867 d_printf("user:%u:", uorg);
3868 break;
3869 case SMB_POSIX_ACL_GROUP_OBJ:
3870 d_printf("group::");
3871 break;
3872 case SMB_POSIX_ACL_GROUP:
3873 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3874 d_printf("group:%u:", uorg);
3875 break;
3876 case SMB_POSIX_ACL_MASK:
3877 d_printf("mask::");
3878 break;
3879 case SMB_POSIX_ACL_OTHER:
3880 d_printf("other::");
3881 break;
3882 default:
3883 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3884 src, (unsigned int)tagtype );
3885 SAFE_FREE(retbuf);
3886 return 1;
3889 d_printf("%s\n", perms_to_string(permstring, perms));
3892 for (i = 0; i < num_dir_acls; i++) {
3893 uint32_t uorg;
3894 fstring permstring;
3895 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3896 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3898 switch(tagtype) {
3899 case SMB_POSIX_ACL_USER_OBJ:
3900 d_printf("default:user::");
3901 break;
3902 case SMB_POSIX_ACL_USER:
3903 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3904 d_printf("default:user:%u:", uorg);
3905 break;
3906 case SMB_POSIX_ACL_GROUP_OBJ:
3907 d_printf("default:group::");
3908 break;
3909 case SMB_POSIX_ACL_GROUP:
3910 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3911 d_printf("default:group:%u:", uorg);
3912 break;
3913 case SMB_POSIX_ACL_MASK:
3914 d_printf("default:mask::");
3915 break;
3916 case SMB_POSIX_ACL_OTHER:
3917 d_printf("default:other::");
3918 break;
3919 default:
3920 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3921 src, (unsigned int)tagtype );
3922 SAFE_FREE(retbuf);
3923 return 1;
3926 d_printf("%s\n", perms_to_string(permstring, perms));
3929 return 0;
3932 /****************************************************************************
3933 Get the EA list of a file
3934 ****************************************************************************/
3936 static int cmd_geteas(void)
3938 TALLOC_CTX *ctx = talloc_tos();
3939 char *src = NULL;
3940 char *name = NULL;
3941 char *targetname = NULL;
3942 struct cli_state *targetcli;
3943 NTSTATUS status;
3944 size_t i, num_eas;
3945 struct ea_struct *eas;
3946 struct cli_credentials *creds = samba_cmdline_get_creds();
3948 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3949 d_printf("geteas filename\n");
3950 return 1;
3952 src = talloc_asprintf(ctx,
3953 "%s%s",
3954 client_get_cur_dir(),
3955 name);
3956 if (!src) {
3957 return 1;
3959 src = client_clean_name(ctx, src);
3960 if (src == NULL) {
3961 return 1;
3964 status = cli_resolve_path(ctx, "",
3965 creds,
3966 cli, src, &targetcli, &targetname);
3967 if (!NT_STATUS_IS_OK(status)) {
3968 d_printf("stat %s: %s\n", src, nt_errstr(status));
3969 return 1;
3972 status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
3973 &num_eas, &eas);
3974 if (!NT_STATUS_IS_OK(status)) {
3975 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
3976 return 1;
3979 for (i=0; i<num_eas; i++) {
3980 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
3981 dump_data_file(eas[i].value.data, eas[i].value.length, false,
3982 stdout);
3983 d_printf("\n");
3986 TALLOC_FREE(eas);
3988 return 0;
3991 /****************************************************************************
3992 Set an EA of a file
3993 ****************************************************************************/
3995 static int cmd_setea(void)
3997 TALLOC_CTX *ctx = talloc_tos();
3998 char *src = NULL;
3999 char *name = NULL;
4000 char *eaname = NULL;
4001 char *eavalue = NULL;
4002 char *targetname = NULL;
4003 struct cli_state *targetcli;
4004 struct cli_credentials *creds = samba_cmdline_get_creds();
4005 NTSTATUS status;
4007 if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
4008 || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
4009 d_printf("setea filename eaname value\n");
4010 return 1;
4012 if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
4013 eavalue = talloc_strdup(ctx, "");
4015 src = talloc_asprintf(ctx,
4016 "%s%s",
4017 client_get_cur_dir(),
4018 name);
4019 if (!src) {
4020 return 1;
4022 src = client_clean_name(ctx, src);
4023 if (src == NULL) {
4024 return 1;
4027 status = cli_resolve_path(ctx, "",
4028 creds,
4029 cli, src, &targetcli, &targetname);
4030 if (!NT_STATUS_IS_OK(status)) {
4031 d_printf("stat %s: %s\n", src, nt_errstr(status));
4032 return 1;
4035 status = cli_set_ea_path(targetcli, targetname, eaname, eavalue,
4036 strlen(eavalue));
4037 if (!NT_STATUS_IS_OK(status)) {
4038 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
4039 return 1;
4042 return 0;
4045 /****************************************************************************
4046 UNIX stat.
4047 ****************************************************************************/
4049 static int cmd_stat(void)
4051 TALLOC_CTX *ctx = talloc_tos();
4052 char *src = NULL;
4053 char *name = NULL;
4054 char *targetname = NULL;
4055 struct cli_state *targetcli;
4056 fstring mode_str;
4057 SMB_STRUCT_STAT sbuf;
4058 struct tm *lt;
4059 time_t tmp_time;
4060 struct cli_credentials *creds = samba_cmdline_get_creds();
4061 NTSTATUS status;
4063 if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4064 d_printf("stat file\n");
4065 return 1;
4067 src = talloc_asprintf(ctx,
4068 "%s%s",
4069 client_get_cur_dir(),
4070 name);
4071 if (!src) {
4072 return 1;
4074 src = client_clean_name(ctx, src);
4075 if (src == NULL) {
4076 return 1;
4079 status = cli_resolve_path(ctx, "",
4080 creds,
4081 cli, src, &targetcli, &targetname);
4082 if (!NT_STATUS_IS_OK(status)) {
4083 d_printf("stat %s: %s\n", src, nt_errstr(status));
4084 return 1;
4087 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4088 d_printf("Server doesn't support UNIX CIFS calls.\n");
4089 return 1;
4092 if (CLI_DIRSEP_CHAR != '/') {
4093 d_printf("Command \"posix\" must be issued before "
4094 "the \"stat\" command can be used.\n");
4095 return 1;
4098 status = cli_posix_stat(targetcli, targetname, &sbuf);
4099 if (!NT_STATUS_IS_OK(status)) {
4100 d_printf("%s stat file %s\n",
4101 nt_errstr(status), src);
4102 return 1;
4105 /* Print out the stat values. */
4106 d_printf("File: %s\n", src);
4107 d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
4108 (double)sbuf.st_ex_size,
4109 (unsigned int)sbuf.st_ex_blocks,
4110 filetype_to_str(sbuf.st_ex_mode));
4112 #if defined(S_ISCHR) && defined(S_ISBLK)
4113 if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
4114 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
4115 (double)sbuf.st_ex_ino,
4116 (unsigned int)sbuf.st_ex_nlink,
4117 unix_dev_major(sbuf.st_ex_rdev),
4118 unix_dev_minor(sbuf.st_ex_rdev));
4119 } else
4120 #endif
4121 d_printf("Inode: %.0f\tLinks: %u\n",
4122 (double)sbuf.st_ex_ino,
4123 (unsigned int)sbuf.st_ex_nlink);
4125 d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
4126 ((int)sbuf.st_ex_mode & 0777),
4127 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
4128 (unsigned int)sbuf.st_ex_uid,
4129 (unsigned int)sbuf.st_ex_gid);
4131 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
4132 lt = localtime(&tmp_time);
4133 if (lt) {
4134 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4135 } else {
4136 fstrcpy(mode_str, "unknown");
4138 d_printf("Access: %s\n", mode_str);
4140 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4141 lt = localtime(&tmp_time);
4142 if (lt) {
4143 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4144 } else {
4145 fstrcpy(mode_str, "unknown");
4147 d_printf("Modify: %s\n", mode_str);
4149 tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
4150 lt = localtime(&tmp_time);
4151 if (lt) {
4152 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4153 } else {
4154 fstrcpy(mode_str, "unknown");
4156 d_printf("Change: %s\n", mode_str);
4158 return 0;
4162 /****************************************************************************
4163 UNIX chown.
4164 ****************************************************************************/
4166 static int cmd_chown(void)
4168 TALLOC_CTX *ctx = talloc_tos();
4169 char *src = NULL;
4170 uid_t uid;
4171 gid_t gid;
4172 char *buf, *buf2, *buf3;
4173 struct cli_state *targetcli;
4174 char *targetname = NULL;
4175 struct cli_credentials *creds = samba_cmdline_get_creds();
4176 NTSTATUS status;
4178 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4179 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
4180 !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
4181 d_printf("chown uid gid file\n");
4182 return 1;
4185 uid = (uid_t)atoi(buf);
4186 gid = (gid_t)atoi(buf2);
4188 src = talloc_asprintf(ctx,
4189 "%s%s",
4190 client_get_cur_dir(),
4191 buf3);
4192 if (!src) {
4193 return 1;
4195 src = client_clean_name(ctx, src);
4196 if (src == NULL) {
4197 return 1;
4199 status = cli_resolve_path(ctx, "",
4200 creds,
4201 cli, src, &targetcli, &targetname);
4202 if (!NT_STATUS_IS_OK(status)) {
4203 d_printf("chown %s: %s\n", src, nt_errstr(status));
4204 return 1;
4207 if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4208 d_printf("Server doesn't support UNIX CIFS calls.\n");
4209 return 1;
4212 if (CLI_DIRSEP_CHAR != '/') {
4213 d_printf("Command \"posix\" must be issued before "
4214 "the \"chown\" command can be used.\n");
4215 return 1;
4218 status = cli_posix_chown(targetcli, targetname, uid, gid);
4219 if (!NT_STATUS_IS_OK(status)) {
4220 d_printf("%s chown file %s uid=%d, gid=%d\n",
4221 nt_errstr(status), src, (int)uid, (int)gid);
4222 return 1;
4225 return 0;
4228 /****************************************************************************
4229 Rename some file.
4230 ****************************************************************************/
4232 static int cmd_rename(void)
4234 TALLOC_CTX *ctx = talloc_tos();
4235 char *src, *dest;
4236 char *buf, *buf2;
4237 struct cli_state *targetcli;
4238 char *targetsrc;
4239 char *targetdest;
4240 struct cli_credentials *creds = samba_cmdline_get_creds();
4241 NTSTATUS status;
4242 bool replace = false;
4244 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4245 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4246 d_printf("rename <src> <dest> [-f]\n");
4247 return 1;
4250 src = talloc_asprintf(ctx,
4251 "%s%s",
4252 client_get_cur_dir(),
4253 buf);
4254 if (!src) {
4255 return 1;
4257 src = client_clean_name(ctx, src);
4258 if (src == NULL) {
4259 return 1;
4262 dest = talloc_asprintf(ctx,
4263 "%s%s",
4264 client_get_cur_dir(),
4265 buf2);
4266 if (!dest) {
4267 return 1;
4269 dest = client_clean_name(ctx, dest);
4270 if (dest == NULL) {
4271 return 1;
4274 if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
4275 strcsequal(buf, "-f")) {
4276 replace = true;
4279 status = cli_resolve_path(ctx, "",
4280 creds,
4281 cli, src, &targetcli, &targetsrc);
4282 if (!NT_STATUS_IS_OK(status)) {
4283 d_printf("rename %s: %s\n", src, nt_errstr(status));
4284 return 1;
4287 status = cli_resolve_path(ctx, "",
4288 creds,
4289 cli, dest, &targetcli, &targetdest);
4290 if (!NT_STATUS_IS_OK(status)) {
4291 d_printf("rename %s: %s\n", dest, nt_errstr(status));
4292 return 1;
4295 status = cli_rename(targetcli, targetsrc, targetdest, replace);
4296 if (!NT_STATUS_IS_OK(status)) {
4297 d_printf("%s renaming files %s -> %s \n",
4298 nt_errstr(status),
4299 targetsrc,
4300 targetdest);
4301 return 1;
4304 return 0;
4307 struct scopy_timing {
4308 struct timespec tp_start;
4311 static int scopy_status(off_t written, void *priv)
4313 struct timespec tp_end;
4314 unsigned int scopy_total_time_ms;
4315 struct scopy_timing *st = priv;
4317 clock_gettime_mono(&tp_end);
4318 scopy_total_time_ms = nsec_time_diff(&tp_end,&st->tp_start)/1000000;
4320 DEBUG(5,("Copied %jd bytes at an average %3.1f kb/s\n",
4321 (intmax_t)written, written / (1.024*scopy_total_time_ms)));
4323 return true;
4326 /****************************************************************************
4327 Server-Side copy some file.
4328 ****************************************************************************/
4330 static int cmd_scopy(void)
4332 TALLOC_CTX *ctx = talloc_tos();
4333 char *src, *dest;
4334 char *buf, *buf2;
4335 struct cli_state *targetcli;
4336 char *targetsrc;
4337 char *targetdest;
4338 uint32_t DesiredAccess, ShareAccess, CreateDisposition, CreateOptions;
4339 struct smb_create_returns cr;
4340 uint16_t destfnum = (uint16_t)-1;
4341 uint16_t srcfnum = (uint16_t)-1;
4342 off_t written = 0;
4343 struct scopy_timing st;
4344 int rc = 0;
4345 struct cli_credentials *creds = samba_cmdline_get_creds();
4346 NTSTATUS status;
4348 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4349 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4350 d_printf("scopy <src> <dest>\n");
4351 return 1;
4354 src = talloc_asprintf(ctx,
4355 "%s%s",
4356 client_get_cur_dir(),
4357 buf);
4358 if (!src) {
4359 return 1;
4361 src = client_clean_name(ctx, src);
4362 if (src == NULL) {
4363 return 1;
4366 dest = talloc_asprintf(ctx,
4367 "%s%s",
4368 client_get_cur_dir(),
4369 buf2);
4370 if (!dest) {
4371 return 1;
4373 dest = client_clean_name(ctx, dest);
4374 if (dest == NULL) {
4375 return 1;
4378 status = cli_resolve_path(ctx, "",
4379 creds,
4380 cli, src, &targetcli, &targetsrc);
4381 if (!NT_STATUS_IS_OK(status)) {
4382 d_printf("scopy %s: %s\n", src, nt_errstr(status));
4383 return 1;
4386 status = cli_resolve_path(ctx, "",
4387 creds,
4388 cli, dest, &targetcli, &targetdest);
4389 if (!NT_STATUS_IS_OK(status)) {
4390 d_printf("scopy %s: %s\n", dest, nt_errstr(status));
4391 return 1;
4395 DesiredAccess = (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|
4396 READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS);
4397 ShareAccess = FILE_SHARE_READ|FILE_SHARE_DELETE;
4398 CreateDisposition = FILE_OPEN;
4399 CreateOptions = (FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE|
4400 FILE_OPEN_REPARSE_POINT);
4401 status = cli_ntcreate(targetcli, targetsrc, 0, DesiredAccess, 0,
4402 ShareAccess, CreateDisposition, CreateOptions, 0x0,
4403 &srcfnum, &cr);
4404 if (!NT_STATUS_IS_OK(status)) {
4405 d_printf("Failed to open file %s. %s\n",
4406 targetsrc, nt_errstr(status));
4407 return 1;
4410 DesiredAccess = (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|
4411 FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|
4412 DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|SYNCHRONIZE_ACCESS);
4413 ShareAccess = FILE_SHARE_NONE;
4414 CreateDisposition = FILE_CREATE;
4415 CreateOptions = FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE;
4416 status = cli_ntcreate(targetcli, targetdest, 0, DesiredAccess,
4417 FILE_ATTRIBUTE_ARCHIVE, ShareAccess, CreateDisposition,
4418 CreateOptions, 0x0, &destfnum, NULL);
4419 if (!NT_STATUS_IS_OK(status)) {
4420 d_printf("Failed to create file %s. %s\n",
4421 targetdest, nt_errstr(status));
4422 cli_close(targetcli, srcfnum);
4423 return 1;
4426 clock_gettime_mono(&st.tp_start);
4427 status = cli_splice(targetcli, targetcli, srcfnum, destfnum,
4428 cr.end_of_file, 0, 0, &written, scopy_status, &st);
4429 if (!NT_STATUS_IS_OK(status)) {
4430 d_printf("%s copying file %s -> %s \n",
4431 nt_errstr(status),
4432 targetsrc,
4433 targetdest);
4434 rc = 1;
4437 status = cli_close(targetcli, srcfnum);
4438 if (!NT_STATUS_IS_OK(status)) {
4439 d_printf("Error %s closing remote source file\n", nt_errstr(status));
4440 rc = 1;
4442 status = cli_close(targetcli, destfnum);
4443 if (!NT_STATUS_IS_OK(status)) {
4444 d_printf("Error %s closing remote dest file\n", nt_errstr(status));
4445 rc = 1;
4448 return rc;
4451 /****************************************************************************
4452 Print the volume name.
4453 ****************************************************************************/
4455 static int cmd_volume(void)
4457 char *volname;
4458 uint32_t serial_num;
4459 time_t create_date;
4460 NTSTATUS status;
4462 status = cli_get_fs_volume_info(cli, talloc_tos(),
4463 &volname, &serial_num,
4464 &create_date);
4465 if (!NT_STATUS_IS_OK(status)) {
4466 d_printf("Error %s getting volume info\n", nt_errstr(status));
4467 return 1;
4470 d_printf("Volume: |%s| serial number 0x%x\n",
4471 volname, (unsigned int)serial_num);
4472 return 0;
4475 /****************************************************************************
4476 Hard link files using the NT call.
4477 ****************************************************************************/
4479 static int cmd_hardlink(void)
4481 TALLOC_CTX *ctx = talloc_tos();
4482 char *src, *dest;
4483 char *buf, *buf2;
4484 struct cli_state *targetcli;
4485 char *targetname;
4486 struct cli_credentials *creds = samba_cmdline_get_creds();
4487 NTSTATUS status;
4489 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4490 !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4491 d_printf("hardlink <src> <dest>\n");
4492 return 1;
4495 src = talloc_asprintf(ctx,
4496 "%s%s",
4497 client_get_cur_dir(),
4498 buf);
4499 if (!src) {
4500 return 1;
4502 src = client_clean_name(ctx, src);
4503 if (src == NULL) {
4504 return 1;
4507 dest = talloc_asprintf(ctx,
4508 "%s%s",
4509 client_get_cur_dir(),
4510 buf2);
4511 if (!dest) {
4512 return 1;
4514 dest = client_clean_name(ctx, dest);
4515 if (dest == NULL) {
4516 return 1;
4519 status = cli_resolve_path(ctx, "",
4520 creds,
4521 cli, src, &targetcli, &targetname);
4522 if (!NT_STATUS_IS_OK(status)) {
4523 d_printf("hardlink %s: %s\n", src, nt_errstr(status));
4524 return 1;
4527 status = cli_hardlink(targetcli, targetname, dest);
4528 if (!NT_STATUS_IS_OK(status)) {
4529 d_printf("%s doing an NT hard link of files\n",
4530 nt_errstr(status));
4531 return 1;
4534 return 0;
4537 /****************************************************************************
4538 Toggle the prompt flag.
4539 ****************************************************************************/
4541 static int cmd_prompt(void)
4543 prompt = !prompt;
4544 DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
4545 return 1;
4548 /****************************************************************************
4549 Set the newer than time.
4550 ****************************************************************************/
4552 static int cmd_newer(void)
4554 TALLOC_CTX *ctx = talloc_tos();
4555 char *buf;
4556 bool ok;
4557 SMB_STRUCT_STAT sbuf;
4559 ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
4560 if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
4561 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4562 DEBUG(1,("Getting files newer than %s",
4563 time_to_asc(newer_than)));
4564 } else {
4565 newer_than = 0;
4568 if (ok && newer_than == 0) {
4569 d_printf("Error setting newer-than time\n");
4570 return 1;
4573 return 0;
4576 /****************************************************************************
4577 Watch directory changes
4578 ****************************************************************************/
4580 static int cmd_notify(void)
4582 TALLOC_CTX *frame = talloc_stackframe();
4583 char *name, *buf;
4584 NTSTATUS status;
4585 uint16_t fnum;
4587 name = talloc_strdup(talloc_tos(), client_get_cur_dir());
4588 if (name == NULL) {
4589 goto fail;
4591 if (!next_token_talloc(talloc_tos(), &cmd_ptr, &buf, NULL)) {
4592 goto usage;
4594 name = talloc_asprintf_append(name, "%s", buf);
4595 if (name == NULL) {
4596 goto fail;
4598 name = client_clean_name(talloc_tos(), name);
4599 if (name == NULL) {
4600 return 1;
4602 status = cli_ntcreate(
4603 cli, name, 0, FILE_READ_DATA, 0,
4604 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
4605 FILE_OPEN, 0, 0, &fnum, NULL);
4606 if (!NT_STATUS_IS_OK(status)) {
4607 d_printf("Could not open file: %s\n", nt_errstr(status));
4608 goto fail;
4611 while (1) {
4612 uint32_t i;
4613 uint32_t num_changes = 0;
4614 struct notify_change *changes = NULL;
4616 status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
4617 true,
4618 talloc_tos(), &num_changes, &changes);
4619 if (NT_STATUS_EQUAL(status, NT_STATUS_NOTIFY_ENUM_DIR)) {
4620 printf("NOTIFY_ENUM_DIR\n");
4621 status = NT_STATUS_OK;
4623 if (!NT_STATUS_IS_OK(status)) {
4624 d_printf("notify returned %s\n",
4625 nt_errstr(status));
4626 goto fail;
4628 for (i=0; i<num_changes; i++) {
4629 printf("%4.4x %s\n", changes[i].action,
4630 changes[i].name);
4632 TALLOC_FREE(changes);
4634 usage:
4635 d_printf("notify <dir name>\n");
4636 fail:
4637 TALLOC_FREE(frame);
4638 return 1;
4641 /****************************************************************************
4642 Set the archive level.
4643 ****************************************************************************/
4645 static int cmd_archive(void)
4647 TALLOC_CTX *ctx = talloc_tos();
4648 char *buf;
4650 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4651 archive_level = atoi(buf);
4652 } else {
4653 d_printf("Archive level is %d\n",archive_level);
4656 return 0;
4659 /****************************************************************************
4660 Toggle the backup_intent state.
4661 ****************************************************************************/
4663 static int cmd_backup(void)
4665 backup_intent = !backup_intent;
4666 cli_set_backup_intent(cli, backup_intent);
4667 DEBUG(2,("backup intent is now %s\n",backup_intent?"on":"off"));
4668 return 1;
4671 /****************************************************************************
4672 Toggle the lowercaseflag.
4673 ****************************************************************************/
4675 static int cmd_lowercase(void)
4677 lowercase = !lowercase;
4678 DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
4679 return 0;
4682 /****************************************************************************
4683 Toggle the case sensitive flag.
4684 ****************************************************************************/
4686 static int cmd_setcase(void)
4688 bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
4690 cli_set_case_sensitive(cli, !orig_case_sensitive);
4691 DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
4692 "on":"off"));
4693 return 0;
4696 /****************************************************************************
4697 Toggle the showacls flag.
4698 ****************************************************************************/
4700 static int cmd_showacls(void)
4702 showacls = !showacls;
4703 DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
4704 return 0;
4708 /****************************************************************************
4709 Toggle the recurse flag.
4710 ****************************************************************************/
4712 static int cmd_recurse(void)
4714 recurse = !recurse;
4715 DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
4716 return 0;
4719 /****************************************************************************
4720 Toggle the translate flag.
4721 ****************************************************************************/
4723 static int cmd_translate(void)
4725 translation = !translation;
4726 DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
4727 translation?"on":"off"));
4728 return 0;
4731 /****************************************************************************
4732 Do the lcd command.
4733 ****************************************************************************/
4735 static int cmd_lcd(void)
4737 TALLOC_CTX *ctx = talloc_tos();
4738 char *buf;
4739 char *d;
4741 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4742 if (chdir(buf) == -1) {
4743 d_printf("chdir to %s failed (%s)\n",
4744 buf, strerror(errno));
4747 d = sys_getwd();
4748 if (!d) {
4749 return 1;
4751 DEBUG(2,("the local directory is now %s\n",d));
4752 SAFE_FREE(d);
4753 return 0;
4756 /****************************************************************************
4757 Get a file restarting at end of local file.
4758 ****************************************************************************/
4760 static int cmd_reget(void)
4762 TALLOC_CTX *ctx = talloc_tos();
4763 char *local_name = NULL;
4764 char *remote_name = NULL;
4765 char *fname = NULL;
4766 char *p = NULL;
4768 remote_name = talloc_strdup(ctx, client_get_cur_dir());
4769 if (!remote_name) {
4770 return 1;
4773 if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
4774 d_printf("reget <filename>\n");
4775 return 1;
4777 remote_name = talloc_asprintf_append(remote_name, "%s", fname);
4778 if (!remote_name) {
4779 return 1;
4781 remote_name = client_clean_name(ctx,remote_name);
4782 if (!remote_name) {
4783 return 1;
4786 local_name = fname;
4787 next_token_talloc(ctx, &cmd_ptr, &p, NULL);
4788 if (p) {
4789 local_name = p;
4792 return do_get(remote_name, local_name, true);
4795 /****************************************************************************
4796 Put a file restarting at end of local file.
4797 ****************************************************************************/
4799 static int cmd_reput(void)
4801 TALLOC_CTX *ctx = talloc_tos();
4802 char *local_name = NULL;
4803 char *remote_name = NULL;
4804 char *buf;
4805 SMB_STRUCT_STAT st;
4807 remote_name = talloc_strdup(ctx, client_get_cur_dir());
4808 if (!remote_name) {
4809 return 1;
4812 if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
4813 d_printf("reput <filename>\n");
4814 return 1;
4817 if (!file_exist_stat(local_name, &st, false)) {
4818 d_printf("%s does not exist\n", local_name);
4819 return 1;
4822 if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
4823 remote_name = talloc_asprintf_append(remote_name,
4824 "%s", buf);
4825 } else {
4826 remote_name = talloc_asprintf_append(remote_name,
4827 "%s", local_name);
4829 if (!remote_name) {
4830 return 1;
4833 remote_name = client_clean_name(ctx, remote_name);
4834 if (!remote_name) {
4835 return 1;
4838 return do_put(remote_name, local_name, true);
4841 /****************************************************************************
4842 List a share name.
4843 ****************************************************************************/
4845 static void browse_fn(const char *name, uint32_t m,
4846 const char *comment, void *state)
4848 const char *typestr = "";
4850 switch (m & 7) {
4851 case STYPE_DISKTREE:
4852 typestr = "Disk";
4853 break;
4854 case STYPE_PRINTQ:
4855 typestr = "Printer";
4856 break;
4857 case STYPE_DEVICE:
4858 typestr = "Device";
4859 break;
4860 case STYPE_IPC:
4861 typestr = "IPC";
4862 break;
4864 /* FIXME: If the remote machine returns non-ascii characters
4865 in any of these fields, they can corrupt the output. We
4866 should remove them. */
4867 if (!grepable) {
4868 d_printf("\t%-15s %-10.10s%s\n",
4869 name,typestr,comment);
4870 } else {
4871 d_printf ("%s|%s|%s\n",typestr,name,comment);
4875 static bool browse_host_rpc(bool sort)
4877 NTSTATUS status;
4878 struct rpc_pipe_client *pipe_hnd = NULL;
4879 TALLOC_CTX *frame = talloc_stackframe();
4880 WERROR werr;
4881 struct srvsvc_NetShareInfoCtr info_ctr;
4882 struct srvsvc_NetShareCtr1 ctr1;
4883 uint32_t resume_handle = 0;
4884 uint32_t total_entries = 0;
4885 uint32_t i;
4886 struct dcerpc_binding_handle *b;
4888 status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
4889 &pipe_hnd);
4891 if (!NT_STATUS_IS_OK(status)) {
4892 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
4893 nt_errstr(status)));
4894 TALLOC_FREE(frame);
4895 return false;
4898 b = pipe_hnd->binding_handle;
4900 ZERO_STRUCT(info_ctr);
4901 ZERO_STRUCT(ctr1);
4903 info_ctr.level = 1;
4904 info_ctr.ctr.ctr1 = &ctr1;
4906 status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
4907 pipe_hnd->desthost,
4908 &info_ctr,
4909 0xffffffff,
4910 &total_entries,
4911 &resume_handle,
4912 &werr);
4914 if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4915 TALLOC_FREE(pipe_hnd);
4916 TALLOC_FREE(frame);
4917 return false;
4920 for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4921 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4922 browse_fn(info.name, info.type, info.comment, NULL);
4925 TALLOC_FREE(pipe_hnd);
4926 TALLOC_FREE(frame);
4927 return true;
4930 /****************************************************************************
4931 Try and browse available connections on a host.
4932 ****************************************************************************/
4934 static bool browse_host(bool sort)
4936 int ret;
4938 if (!grepable) {
4939 d_printf("\n\tSharename Type Comment\n");
4940 d_printf("\t--------- ---- -------\n");
4943 if (browse_host_rpc(sort)) {
4944 return true;
4947 if (smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1) {
4948 return false;
4951 ret = cli_RNetShareEnum(cli, browse_fn, NULL);
4952 if (ret == -1) {
4953 NTSTATUS status = cli_nt_error(cli);
4954 d_printf("Error returning browse list: %s\n",
4955 nt_errstr(status));
4958 return (ret != -1);
4961 /****************************************************************************
4962 List a server name.
4963 ****************************************************************************/
4965 static void server_fn(const char *name, uint32_t m,
4966 const char *comment, void *state)
4969 if (!grepable){
4970 d_printf("\t%-16s %s\n", name, comment);
4971 } else {
4972 d_printf("%s|%s|%s\n",(char *)state, name, comment);
4976 /****************************************************************************
4977 Try and browse available connections on a host.
4978 ****************************************************************************/
4980 static bool list_servers(const char *wk_grp)
4982 fstring state;
4984 if (!cli->server_domain)
4985 return false;
4987 if (!grepable) {
4988 d_printf("\n\tServer Comment\n");
4989 d_printf("\t--------- -------\n");
4991 fstrcpy( state, "Server" );
4992 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
4993 state);
4995 if (!grepable) {
4996 d_printf("\n\tWorkgroup Master\n");
4997 d_printf("\t--------- -------\n");
5000 fstrcpy( state, "Workgroup" );
5001 cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
5002 server_fn, state);
5003 return true;
5006 /****************************************************************************
5007 Print or set current VUID
5008 ****************************************************************************/
5010 static int cmd_vuid(void)
5012 TALLOC_CTX *ctx = talloc_tos();
5013 char *buf;
5015 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5016 d_printf("Current VUID is %d\n",
5017 cli_state_get_uid(cli));
5018 return 0;
5021 cli_state_set_uid(cli, atoi(buf));
5022 return 0;
5025 /****************************************************************************
5026 Setup a new VUID, by issuing a session setup
5027 ****************************************************************************/
5029 static int cmd_logon(void)
5031 TALLOC_CTX *ctx = talloc_tos();
5032 char *l_username, *l_password;
5033 struct cli_credentials *creds = NULL;
5034 NTSTATUS nt_status;
5036 if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
5037 d_printf("logon <username> [<password>]\n");
5038 return 0;
5041 if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
5042 char pwd[256] = {0};
5043 int rc;
5045 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
5046 if (rc == 0) {
5047 l_password = talloc_strdup(ctx, pwd);
5050 if (!l_password) {
5051 return 1;
5054 creds = cli_session_creds_init(ctx,
5055 l_username,
5056 lp_workgroup(),
5057 NULL, /* realm */
5058 l_password,
5059 false, /* use_kerberos */
5060 false, /* fallback_after_kerberos */
5061 false, /* use_ccache */
5062 false); /* password_is_nt_hash */
5063 if (creds == NULL) {
5064 d_printf("cli_session_creds_init() failed.\n");
5065 return -1;
5067 nt_status = cli_session_setup_creds(cli, creds);
5068 TALLOC_FREE(creds);
5069 if (!NT_STATUS_IS_OK(nt_status)) {
5070 d_printf("session setup failed: %s\n", nt_errstr(nt_status));
5071 return -1;
5074 d_printf("Current VUID is %d\n", cli_state_get_uid(cli));
5075 return 0;
5079 * close the session
5082 static int cmd_logoff(void)
5084 NTSTATUS status;
5086 status = cli_ulogoff(cli);
5087 if (!NT_STATUS_IS_OK(status)) {
5088 d_printf("logoff failed: %s\n", nt_errstr(status));
5089 return -1;
5092 d_printf("logoff successful\n");
5093 return 0;
5098 * tree connect (connect to a share)
5101 static int cmd_tcon(void)
5103 TALLOC_CTX *ctx = talloc_tos();
5104 char *sharename;
5105 NTSTATUS status;
5107 if (!next_token_talloc(ctx, &cmd_ptr, &sharename, NULL)) {
5108 d_printf("tcon <sharename>\n");
5109 return 0;
5112 if (!sharename) {
5113 return 1;
5116 status = cli_tree_connect(cli, sharename, "?????", NULL);
5117 if (!NT_STATUS_IS_OK(status)) {
5118 d_printf("tcon failed: %s\n", nt_errstr(status));
5119 return -1;
5122 d_printf("tcon to %s successful, tid: %u\n", sharename,
5123 cli_state_get_tid(cli));
5125 talloc_free(sharename);
5127 return 0;
5131 * tree disconnect (disconnect from a share)
5134 static int cmd_tdis(void)
5136 NTSTATUS status;
5138 status = cli_tdis(cli);
5139 if (!NT_STATUS_IS_OK(status)) {
5140 d_printf("tdis failed: %s\n", nt_errstr(status));
5141 return -1;
5144 d_printf("tdis successful\n");
5145 return 0;
5150 * get or set tid
5153 static int cmd_tid(void)
5155 TALLOC_CTX *ctx = talloc_tos();
5156 char *tid_str;
5158 if (!next_token_talloc(ctx, &cmd_ptr, &tid_str, NULL)) {
5159 if (cli_state_has_tcon(cli)) {
5160 d_printf("current tid is %d\n", cli_state_get_tid(cli));
5161 } else {
5162 d_printf("no tcon currently\n");
5164 } else {
5165 uint32_t tid = atoi(tid_str);
5166 if (!cli_state_has_tcon(cli)) {
5167 d_printf("no tcon currently\n");
5169 cli_state_set_tid(cli, tid);
5172 return 0;
5176 /****************************************************************************
5177 list active connections
5178 ****************************************************************************/
5180 static int cmd_list_connect(void)
5182 cli_cm_display(cli);
5183 return 0;
5186 /****************************************************************************
5187 display the current active client connection
5188 ****************************************************************************/
5190 static int cmd_show_connect( void )
5192 TALLOC_CTX *ctx = talloc_tos();
5193 struct cli_state *targetcli;
5194 char *targetpath;
5195 struct cli_credentials *creds = samba_cmdline_get_creds();
5196 NTSTATUS status;
5198 status = cli_resolve_path(ctx, "",
5199 creds,
5200 cli,
5201 client_get_cur_dir(), &targetcli,
5202 &targetpath);
5203 if (!NT_STATUS_IS_OK(status)) {
5204 d_printf("showconnect %s: %s\n", cur_dir, nt_errstr(status));
5205 return 1;
5208 d_printf("//%s/%s\n", smbXcli_conn_remote_name(targetcli->conn), targetcli->share);
5209 return 0;
5213 * cmd_utimes - interactive command to set the four times
5215 * Read a filename and four times from the client command line and update
5216 * the file times. A value of -1 for a time means don't change.
5218 static int cmd_utimes(void)
5220 char *buf;
5221 char *fname = NULL;
5222 struct timespec times[4] = {{0}};
5223 struct timeval_buf tbuf[4];
5224 int time_count = 0;
5225 int err = 0;
5226 bool ok;
5227 TALLOC_CTX *ctx = talloc_new(NULL);
5228 NTSTATUS status;
5230 if (ctx == NULL) {
5231 return 1;
5234 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5235 if (!ok) {
5236 d_printf("utimes <filename> <create-time> <access-time> "
5237 "<write-time> <change-time>\n");
5238 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5239 "or -1 for no change\n");
5240 err = 1;
5241 goto out;
5244 fname = talloc_asprintf(ctx,
5245 "%s%s",
5246 client_get_cur_dir(),
5247 buf);
5248 if (fname == NULL) {
5249 err = 1;
5250 goto out;
5252 fname = client_clean_name(ctx, fname);
5253 if (fname == NULL) {
5254 err = 1;
5255 goto out;
5258 while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
5259 time_count < 4) {
5260 const char *s = buf;
5261 struct tm tm = {0,};
5262 time_t t;
5263 char *ret;
5265 if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
5266 times[time_count] = make_omit_timespec();
5267 time_count++;
5268 continue;
5271 ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
5273 if (ret == NULL) {
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]YY:MM:DD-HH:MM:SS "
5283 "format or -1 for no change\n");
5284 err = 1;
5285 goto out;
5288 /* Convert tm to a time_t */
5289 t = mktime(&tm);
5290 times[time_count] = (struct timespec){.tv_sec = t};
5291 time_count++;
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");
5300 err = 1;
5301 goto out;
5304 DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
5305 timespec_string_buf(&times[0], false, &tbuf[0]),
5306 timespec_string_buf(&times[1], false, &tbuf[1]),
5307 timespec_string_buf(&times[2], false, &tbuf[2]),
5308 timespec_string_buf(&times[3], false, &tbuf[3])));
5310 status = cli_setpathinfo_ext(
5311 cli, fname, times[0], times[1], times[2], times[3],
5312 (uint32_t)-1);
5313 if (!NT_STATUS_IS_OK(status)) {
5314 d_printf("cli_setpathinfo_ext failed: %s\n",
5315 nt_errstr(status));
5316 err = 1;
5317 goto out;
5319 out:
5320 talloc_free(ctx);
5321 return err;
5325 * set_remote_attr - set DOS attributes of a remote file
5326 * @filename: path to the file name
5327 * @new_attr: attribute bit mask to use
5328 * @mode: one of ATTR_SET or ATTR_UNSET
5330 * Update the file attributes with the one provided.
5332 int set_remote_attr(const char *filename, uint32_t new_attr, int mode)
5334 extern struct cli_state *cli;
5335 uint32_t old_attr;
5336 NTSTATUS status;
5338 status = cli_getatr(cli, filename, &old_attr, NULL, NULL);
5339 if (!NT_STATUS_IS_OK(status)) {
5340 d_printf("cli_getatr failed: %s\n", nt_errstr(status));
5341 return 1;
5344 if (mode == ATTR_SET) {
5345 new_attr |= old_attr;
5346 } else {
5347 new_attr = old_attr & ~new_attr;
5350 status = cli_setatr(cli, filename, new_attr, 0);
5351 if (!NT_STATUS_IS_OK(status)) {
5352 d_printf("cli_setatr failed: %s\n", nt_errstr(status));
5353 return 1;
5356 return 0;
5360 * cmd_setmode - interactive command to set DOS attributes
5362 * Read a filename and mode from the client command line and update
5363 * the file DOS attributes.
5365 int cmd_setmode(void)
5367 char *buf;
5368 char *fname = NULL;
5369 uint32_t attr[2] = {0};
5370 int mode = ATTR_SET;
5371 int err = 0;
5372 bool ok;
5373 TALLOC_CTX *ctx = talloc_new(NULL);
5374 if (ctx == NULL) {
5375 return 1;
5378 ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5379 if (!ok) {
5380 d_printf("setmode <filename> <[+|-]rsha>\n");
5381 err = 1;
5382 goto out;
5385 fname = talloc_asprintf(ctx,
5386 "%s%s",
5387 client_get_cur_dir(),
5388 buf);
5389 if (fname == NULL) {
5390 err = 1;
5391 goto out;
5393 fname = client_clean_name(ctx, fname);
5394 if (fname == NULL) {
5395 err = 1;
5396 goto out;
5399 while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
5400 const char *s = buf;
5402 while (*s) {
5403 switch (*s++) {
5404 case '+':
5405 mode = ATTR_SET;
5406 break;
5407 case '-':
5408 mode = ATTR_UNSET;
5409 break;
5410 case 'r':
5411 attr[mode] |= FILE_ATTRIBUTE_READONLY;
5412 break;
5413 case 'h':
5414 attr[mode] |= FILE_ATTRIBUTE_HIDDEN;
5415 break;
5416 case 's':
5417 attr[mode] |= FILE_ATTRIBUTE_SYSTEM;
5418 break;
5419 case 'a':
5420 attr[mode] |= FILE_ATTRIBUTE_ARCHIVE;
5421 break;
5422 default:
5423 d_printf("setmode <filename> <perm=[+|-]rsha>\n");
5424 err = 1;
5425 goto out;
5430 if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) {
5431 d_printf("setmode <filename> <[+|-]rsha>\n");
5432 err = 1;
5433 goto out;
5436 DEBUG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET]));
5438 /* ignore return value: server might not store DOS attributes */
5439 set_remote_attr(fname, attr[ATTR_SET], ATTR_SET);
5440 set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET);
5441 out:
5442 talloc_free(ctx);
5443 return err;
5446 /****************************************************************************
5447 iosize command
5448 ***************************************************************************/
5450 int cmd_iosize(void)
5452 TALLOC_CTX *ctx = talloc_tos();
5453 char *buf;
5454 int iosize;
5455 struct cli_credentials *creds = samba_cmdline_get_creds();
5456 bool smb_encrypt =
5457 (cli_credentials_get_smb_encryption(creds) ==
5458 SMB_ENCRYPTION_REQUIRED);
5460 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5461 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5462 if (!smb_encrypt) {
5463 d_printf("iosize <n> or iosize 0x<n>. "
5464 "Minimum is 0 (default), "
5465 "max is 16776960 (0xFFFF00)\n");
5466 } else {
5467 d_printf("iosize <n> or iosize 0x<n>. "
5468 "(Encrypted connection) ,"
5469 "Minimum is 0 (default), "
5470 "max is 130048 (0x1FC00)\n");
5472 } else {
5473 d_printf("iosize <n> or iosize 0x<n>.\n");
5475 return 1;
5478 iosize = strtol(buf,NULL,0);
5479 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5480 if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) {
5481 d_printf("iosize out of range for encrypted "
5482 "connection (min = 0 (default), "
5483 "max = 130048 (0x1FC00)\n");
5484 return 1;
5485 } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) {
5486 d_printf("iosize out of range (min = 0 (default), "
5487 "max = 16776960 (0xFFFF00)\n");
5488 return 1;
5492 io_bufsize = iosize;
5493 d_printf("iosize is now %d\n", io_bufsize);
5494 return 0;
5497 /****************************************************************************
5498 timeout command
5499 ***************************************************************************/
5501 static int cmd_timeout(void)
5503 TALLOC_CTX *ctx = talloc_tos();
5504 char *buf;
5506 if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5507 unsigned int old_timeout = cli_set_timeout(cli, 0);
5508 cli_set_timeout(cli, old_timeout);
5509 d_printf("timeout <n> (per-operation timeout "
5510 "in seconds - currently %u).\n",
5511 old_timeout/1000);
5512 return 1;
5515 io_timeout = strtol(buf,NULL,0);
5516 cli_set_timeout(cli, io_timeout*1000);
5517 d_printf("io_timeout per operation is now %d\n", io_timeout);
5518 return 0;
5522 /****************************************************************************
5523 history
5524 ****************************************************************************/
5525 static int cmd_history(void)
5527 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
5528 HIST_ENTRY **hlist;
5529 int i;
5531 hlist = history_list();
5533 for (i = 0; hlist && hlist[i]; i++) {
5534 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
5536 #else
5537 DEBUG(0,("no history without readline support\n"));
5538 #endif
5540 return 0;
5543 /* Some constants for completing filename arguments */
5545 #define COMPL_NONE 0 /* No completions */
5546 #define COMPL_REMOTE 1 /* Complete remote filename */
5547 #define COMPL_LOCAL 2 /* Complete local filename */
5549 /* This defines the commands supported by this client.
5550 * NOTE: The "!" must be the last one in the list because it's fn pointer
5551 * field is NULL, and NULL in that field is used in process_tok()
5552 * (below) to indicate the end of the list. crh
5554 static struct {
5555 const char *name;
5556 int (*fn)(void);
5557 const char *description;
5558 char compl_args[2]; /* Completion argument info */
5559 } commands[] = {
5560 {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5561 {"allinfo",cmd_allinfo,"<file> show all available info",
5562 {COMPL_REMOTE,COMPL_NONE}},
5563 {"altname",cmd_altname,"<file> show alt name",{COMPL_REMOTE,COMPL_NONE}},
5564 {"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}},
5565 {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}},
5566 {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
5567 {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
5568 {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
5569 {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
5570 {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_NONE}},
5571 {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_NONE}},
5572 {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_NONE}},
5573 {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5574 {"deltree",cmd_deltree,"<mask> recursively delete all matching files and directories",{COMPL_REMOTE,COMPL_NONE}},
5575 {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5576 {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5577 {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
5578 {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5579 {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
5580 {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_NONE}},
5581 {"geteas", cmd_geteas, "<file name> get the EA list of a file",
5582 {COMPL_REMOTE, COMPL_NONE}},
5583 {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5584 {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5585 {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
5586 {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
5587 {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
5588 {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5589 {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5590 {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
5591 {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5592 {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5593 {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
5594 {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5595 {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
5596 {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5597 {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
5598 {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
5599 {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
5600 {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}},
5601 {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
5602 {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
5603 {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
5604 {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5605 {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5606 {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5607 {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5608 {"posix_whoami",cmd_posix_whoami,"return logged on user information "
5609 "using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5610 {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
5611 {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
5612 {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
5613 {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
5614 {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5615 {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
5616 {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5617 {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5618 {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
5619 {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
5620 {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
5621 {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
5622 {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
5623 {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5624 {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_REMOTE,COMPL_NONE}},
5625 {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},
5626 {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
5627 {COMPL_REMOTE, COMPL_LOCAL}},
5628 {"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
5629 {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
5630 {"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
5631 {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5632 {"tar",cmd_tar,"tar <c|x>[IXFvbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
5633 {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
5634 {"timeout",cmd_timeout,"timeout <number> - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}},
5635 {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
5636 {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5637 {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
5638 {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
5639 {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5640 {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
5641 {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
5642 {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
5643 {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
5644 {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
5645 {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
5646 {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
5647 "<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
5648 {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
5649 {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
5651 /* Yes, this must be here, see crh's comment above. */
5652 {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
5653 {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
5656 /*******************************************************************
5657 Lookup a command string in the list of commands, including
5658 abbreviations.
5659 ******************************************************************/
5661 static int process_tok(char *tok)
5663 size_t i = 0, matches = 0;
5664 size_t cmd=0;
5665 size_t tok_len = strlen(tok);
5667 while (commands[i].fn != NULL) {
5668 if (strequal(commands[i].name,tok)) {
5669 matches = 1;
5670 cmd = i;
5671 break;
5672 } else if (strnequal(commands[i].name, tok, tok_len)) {
5673 matches++;
5674 cmd = i;
5676 i++;
5679 if (matches == 0)
5680 return(-1);
5681 else if (matches == 1)
5682 return(cmd);
5683 else
5684 return(-2);
5687 /****************************************************************************
5688 Help.
5689 ****************************************************************************/
5691 static int cmd_help(void)
5693 TALLOC_CTX *ctx = talloc_tos();
5694 int i=0,j;
5695 char *buf;
5697 if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5698 if ((i = process_tok(buf)) >= 0)
5699 d_printf("HELP %s:\n\t%s\n\n",
5700 commands[i].name,commands[i].description);
5701 } else {
5702 while (commands[i].description) {
5703 for (j=0; commands[i].description && (j<5); j++) {
5704 d_printf("%-15s",commands[i].name);
5705 i++;
5707 d_printf("\n");
5710 return 0;
5713 /****************************************************************************
5714 Process a -c command string.
5715 ****************************************************************************/
5717 static int process_command_string(const char *cmd_in)
5719 TALLOC_CTX *ctx = talloc_tos();
5720 char *cmd = talloc_strdup(ctx, cmd_in);
5721 int rc = 0;
5722 struct cli_credentials *creds = samba_cmdline_get_creds();
5724 if (!cmd) {
5725 return 1;
5727 /* establish the connection if not already */
5729 if (!cli) {
5730 NTSTATUS status;
5732 status = cli_cm_open(talloc_tos(), NULL,
5733 desthost,
5734 service,
5735 creds,
5736 have_ip ? &dest_ss : NULL, port,
5737 name_type,
5738 &cli);
5739 if (!NT_STATUS_IS_OK(status)) {
5740 return 1;
5742 cli_set_timeout(cli, io_timeout*1000);
5745 while (cmd[0] != '\0') {
5746 char *line;
5747 char *p;
5748 char *tok;
5749 int i;
5751 if ((p = strchr_m(cmd, ';')) == 0) {
5752 line = cmd;
5753 cmd += strlen(cmd);
5754 } else {
5755 *p = '\0';
5756 line = cmd;
5757 cmd = p + 1;
5760 /* and get the first part of the command */
5761 cmd_ptr = line;
5762 if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
5763 continue;
5766 if ((i = process_tok(tok)) >= 0) {
5767 rc = commands[i].fn();
5768 } else if (i == -2) {
5769 d_printf("%s: command abbreviation ambiguous\n",tok);
5770 } else {
5771 d_printf("%s: command not found\n",tok);
5775 return rc;
5778 #define MAX_COMPLETIONS 100
5780 struct completion_remote {
5781 char *dirmask;
5782 char **matches;
5783 int count, samelen;
5784 const char *text;
5785 int len;
5788 static NTSTATUS completion_remote_filter(struct file_info *f,
5789 const char *mask,
5790 void *state)
5792 struct completion_remote *info = (struct completion_remote *)state;
5794 if (info->count >= MAX_COMPLETIONS - 1) {
5795 return NT_STATUS_OK;
5797 if (strncmp(info->text, f->name, info->len) != 0) {
5798 return NT_STATUS_OK;
5800 if (ISDOT(f->name) || ISDOTDOT(f->name)) {
5801 return NT_STATUS_OK;
5804 if ((info->dirmask[0] == 0) && !(f->attr & FILE_ATTRIBUTE_DIRECTORY))
5805 info->matches[info->count] = SMB_STRDUP(f->name);
5806 else {
5807 TALLOC_CTX *ctx = talloc_stackframe();
5808 char *tmp;
5810 tmp = talloc_strdup(ctx,info->dirmask);
5811 if (!tmp) {
5812 TALLOC_FREE(ctx);
5813 return NT_STATUS_NO_MEMORY;
5815 tmp = talloc_asprintf_append(tmp, "%s", f->name);
5816 if (!tmp) {
5817 TALLOC_FREE(ctx);
5818 return NT_STATUS_NO_MEMORY;
5820 if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
5821 tmp = talloc_asprintf_append(tmp, "%s",
5822 CLI_DIRSEP_STR);
5824 if (!tmp) {
5825 TALLOC_FREE(ctx);
5826 return NT_STATUS_NO_MEMORY;
5828 info->matches[info->count] = SMB_STRDUP(tmp);
5829 TALLOC_FREE(ctx);
5831 if (info->matches[info->count] == NULL) {
5832 return NT_STATUS_OK;
5834 if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
5835 smb_readline_ca_char(0);
5837 if (info->count == 1) {
5838 info->samelen = strlen(info->matches[info->count]);
5839 } else {
5840 while (strncmp(info->matches[info->count],
5841 info->matches[info->count-1],
5842 info->samelen) != 0) {
5843 info->samelen--;
5846 info->count++;
5847 return NT_STATUS_OK;
5850 static char **remote_completion(const char *text, int len)
5852 TALLOC_CTX *ctx = talloc_stackframe();
5853 char *dirmask = NULL;
5854 char *targetpath = NULL;
5855 struct cli_state *targetcli = NULL;
5856 int i;
5857 struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
5858 struct cli_credentials *creds = samba_cmdline_get_creds();
5859 NTSTATUS status;
5861 /* can't have non-static initialisation on Sun CC, so do it
5862 at run time here */
5863 info.samelen = len;
5864 info.text = text;
5865 info.len = len;
5867 info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
5868 if (!info.matches) {
5869 TALLOC_FREE(ctx);
5870 return NULL;
5874 * We're leaving matches[0] free to fill it later with the text to
5875 * display: Either the one single match or the longest common subset
5876 * of the matches.
5878 info.matches[0] = NULL;
5879 info.count = 1;
5881 for (i = len-1; i >= 0; i--) {
5882 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
5883 break;
5887 info.text = text+i+1;
5888 info.samelen = info.len = len-i-1;
5890 if (i > 0) {
5891 info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
5892 if (!info.dirmask) {
5893 goto cleanup;
5895 strncpy(info.dirmask, text, i+1);
5896 info.dirmask[i+1] = 0;
5897 dirmask = talloc_asprintf(ctx,
5898 "%s%*s*",
5899 client_get_cur_dir(),
5900 i-1,
5901 text);
5902 } else {
5903 info.dirmask = SMB_STRDUP("");
5904 if (!info.dirmask) {
5905 goto cleanup;
5907 dirmask = talloc_asprintf(ctx,
5908 "%s*",
5909 client_get_cur_dir());
5911 if (!dirmask) {
5912 goto cleanup;
5914 dirmask = client_clean_name(ctx, dirmask);
5915 if (dirmask == NULL) {
5916 goto cleanup;
5919 status = cli_resolve_path(ctx, "",
5920 creds,
5921 cli, dirmask, &targetcli, &targetpath);
5922 if (!NT_STATUS_IS_OK(status)) {
5923 goto cleanup;
5925 status = cli_list(targetcli, targetpath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5926 completion_remote_filter, (void *)&info);
5927 if (!NT_STATUS_IS_OK(status)) {
5928 goto cleanup;
5931 if (info.count == 1) {
5933 * No matches at all, NULL indicates there is nothing
5935 SAFE_FREE(info.matches[0]);
5936 SAFE_FREE(info.matches);
5937 TALLOC_FREE(ctx);
5938 return NULL;
5941 if (info.count == 2) {
5943 * Exactly one match in matches[1], indicate this is the one
5944 * in matches[0].
5946 info.matches[0] = info.matches[1];
5947 info.matches[1] = NULL;
5948 info.count -= 1;
5949 TALLOC_FREE(ctx);
5950 return info.matches;
5954 * We got more than one possible match, set the result to the maximum
5955 * common subset
5958 info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
5959 info.matches[info.count] = NULL;
5960 TALLOC_FREE(ctx);
5961 return info.matches;
5963 cleanup:
5964 for (i = 0; i < info.count; i++) {
5965 SAFE_FREE(info.matches[i]);
5967 SAFE_FREE(info.matches);
5968 SAFE_FREE(info.dirmask);
5969 TALLOC_FREE(ctx);
5970 return NULL;
5973 static char **completion_fn(const char *text, int start, int end)
5975 smb_readline_ca_char(' ');
5977 if (start) {
5978 const char *buf, *sp;
5979 int i;
5980 char compl_type;
5982 buf = smb_readline_get_line_buffer();
5983 if (buf == NULL)
5984 return NULL;
5986 sp = strchr(buf, ' ');
5987 if (sp == NULL)
5988 return NULL;
5990 for (i = 0; commands[i].name; i++) {
5991 if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
5992 (commands[i].name[sp - buf] == 0)) {
5993 break;
5996 if (commands[i].name == NULL)
5997 return NULL;
5999 while (*sp == ' ')
6000 sp++;
6002 if (sp == (buf + start))
6003 compl_type = commands[i].compl_args[0];
6004 else
6005 compl_type = commands[i].compl_args[1];
6007 if (compl_type == COMPL_REMOTE)
6008 return remote_completion(text, end - start);
6009 else /* fall back to local filename completion */
6010 return NULL;
6011 } else {
6012 char **matches;
6013 size_t i, len, samelen = 0, count=1;
6015 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
6016 if (!matches) {
6017 return NULL;
6019 matches[0] = NULL;
6021 len = strlen(text);
6022 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
6023 if (strncmp(text, commands[i].name, len) == 0) {
6024 matches[count] = SMB_STRDUP(commands[i].name);
6025 if (!matches[count])
6026 goto cleanup;
6027 if (count == 1)
6028 samelen = strlen(matches[count]);
6029 else
6030 while (strncmp(matches[count], matches[count-1], samelen) != 0)
6031 samelen--;
6032 count++;
6036 switch (count) {
6037 case 0: /* should never happen */
6038 case 1:
6039 goto cleanup;
6040 case 2:
6041 matches[0] = SMB_STRDUP(matches[1]);
6042 break;
6043 default:
6044 matches[0] = (char *)SMB_MALLOC(samelen+1);
6045 if (!matches[0])
6046 goto cleanup;
6047 strncpy(matches[0], matches[1], samelen);
6048 matches[0][samelen] = 0;
6050 matches[count] = NULL;
6051 return matches;
6053 cleanup:
6054 for (i = 0; i < count; i++)
6055 free(matches[i]);
6057 free(matches);
6058 return NULL;
6062 static bool finished;
6064 /****************************************************************************
6065 Make sure we swallow keepalives during idle time.
6066 ****************************************************************************/
6068 static void readline_callback(void)
6070 static time_t last_t;
6071 struct timespec now;
6072 time_t t;
6073 NTSTATUS status;
6074 unsigned char garbage[16];
6076 clock_gettime_mono(&now);
6077 t = now.tv_sec;
6079 if (t - last_t < 5)
6080 return;
6082 last_t = t;
6084 /* Ping the server to keep the connection alive using SMBecho. */
6085 memset(garbage, 0xf0, sizeof(garbage));
6086 status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
6087 if (NT_STATUS_IS_OK(status) ||
6088 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
6090 * Even if server returns NT_STATUS_INVALID_PARAMETER
6091 * it still responded.
6092 * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
6094 return;
6097 if (!cli_state_is_connected(cli)) {
6098 DEBUG(0,("SMBecho failed (%s). The connection is "
6099 "disconnected now\n", nt_errstr(status)));
6100 finished = true;
6101 smb_readline_done();
6105 /****************************************************************************
6106 Process commands on stdin.
6107 ****************************************************************************/
6109 static int process_stdin(void)
6111 int rc = 0;
6113 if (!quiet) {
6114 d_printf("Try \"help\" to get a list of possible commands.\n");
6117 while (!finished) {
6118 TALLOC_CTX *frame = talloc_stackframe();
6119 char *tok = NULL;
6120 char *the_prompt = NULL;
6121 char *line = NULL;
6122 int i;
6124 /* display a prompt */
6125 the_prompt = talloc_asprintf(frame,
6126 "smb: %s> ",
6127 client_get_cur_dir());
6128 if (the_prompt == NULL) {
6129 TALLOC_FREE(frame);
6130 break;
6132 line = smb_readline(the_prompt, readline_callback, completion_fn);
6133 if (!line) {
6134 TALLOC_FREE(frame);
6135 break;
6138 /* special case - first char is ! */
6139 if (*line == '!') {
6140 if (system(line + 1) == -1) {
6141 d_printf("system() command %s failed.\n",
6142 line+1);
6144 SAFE_FREE(line);
6145 TALLOC_FREE(frame);
6146 continue;
6149 /* and get the first part of the command */
6150 cmd_ptr = line;
6151 if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
6152 TALLOC_FREE(frame);
6153 SAFE_FREE(line);
6154 continue;
6157 if ((i = process_tok(tok)) >= 0) {
6158 rc = commands[i].fn();
6159 } else if (i == -2) {
6160 d_printf("%s: command abbreviation ambiguous\n",tok);
6161 } else {
6162 d_printf("%s: command not found\n",tok);
6164 SAFE_FREE(line);
6165 TALLOC_FREE(frame);
6167 return rc;
6170 /****************************************************************************
6171 Process commands from the client.
6172 ****************************************************************************/
6174 static int process(const char *base_directory)
6176 int rc = 0;
6177 NTSTATUS status;
6178 struct cli_credentials *creds = samba_cmdline_get_creds();
6180 status = cli_cm_open(talloc_tos(), NULL,
6181 desthost,
6182 service,
6183 creds,
6184 have_ip ? &dest_ss : NULL, port,
6185 name_type, &cli);
6186 if (!NT_STATUS_IS_OK(status)) {
6187 return 1;
6190 cli_set_timeout(cli, io_timeout*1000);
6192 if (base_directory && *base_directory) {
6193 rc = do_cd(base_directory);
6194 if (rc) {
6195 cli_shutdown(cli);
6196 return rc;
6200 if (cmdstr) {
6201 rc = process_command_string(cmdstr);
6202 } else {
6203 process_stdin();
6206 cli_shutdown(cli);
6207 return rc;
6210 /****************************************************************************
6211 Handle a -L query.
6212 ****************************************************************************/
6214 static int do_host_query(const char *query_host)
6216 NTSTATUS status;
6217 struct cli_credentials *creds = samba_cmdline_get_creds();
6219 status = cli_cm_open(talloc_tos(), NULL,
6220 query_host,
6221 "IPC$",
6222 creds,
6223 have_ip ? &dest_ss : NULL, port,
6224 name_type, &cli);
6225 if (!NT_STATUS_IS_OK(status)) {
6226 return 1;
6229 cli_set_timeout(cli, io_timeout*1000);
6230 browse_host(true);
6232 /* Ensure that the host can do IPv4 */
6234 if (!interpret_addr(query_host)) {
6235 struct sockaddr_storage ss;
6236 if (interpret_string_addr(&ss, query_host, 0) &&
6237 (ss.ss_family != AF_INET)) {
6238 d_printf("%s is an IPv6 address -- no workgroup available\n",
6239 query_host);
6240 return 1;
6244 if (lp_client_min_protocol() > PROTOCOL_NT1) {
6245 d_printf("SMB1 disabled -- no workgroup available\n");
6246 goto out;
6249 if (lp_disable_netbios()) {
6250 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
6251 goto out;
6254 if (port != NBT_SMB_PORT ||
6255 smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1)
6258 * Workgroups simply don't make sense over anything
6259 * else but port 139 and SMB1.
6262 cli_shutdown(cli);
6263 d_printf("Reconnecting with SMB1 for workgroup listing.\n");
6264 lp_set_cmdline("client max protocol", "NT1");
6265 status = cli_cm_open(talloc_tos(), NULL,
6266 query_host,
6267 "IPC$",
6268 creds,
6269 have_ip ? &dest_ss : NULL, NBT_SMB_PORT,
6270 name_type, &cli);
6271 if (!NT_STATUS_IS_OK(status)) {
6272 d_printf("Unable to connect with SMB1 "
6273 "-- no workgroup available\n");
6274 return 0;
6278 cli_set_timeout(cli, io_timeout*1000);
6279 list_servers(lp_workgroup());
6280 out:
6281 cli_shutdown(cli);
6283 return(0);
6286 /****************************************************************************
6287 Handle a tar operation.
6288 ****************************************************************************/
6290 static int do_tar_op(const char *base_directory)
6292 struct tar *tar_ctx = tar_get_ctx();
6293 int ret = 0;
6294 struct cli_credentials *creds = samba_cmdline_get_creds();
6296 /* do we already have a connection? */
6297 if (!cli) {
6298 NTSTATUS status;
6300 status = cli_cm_open(talloc_tos(), NULL,
6301 desthost,
6302 service,
6303 creds,
6304 have_ip ? &dest_ss : NULL, port,
6305 name_type, &cli);
6306 if (!NT_STATUS_IS_OK(status)) {
6307 ret = 1;
6308 goto out;
6310 cli_set_timeout(cli, io_timeout*1000);
6313 recurse = true;
6315 if (base_directory && *base_directory) {
6316 ret = do_cd(base_directory);
6317 if (ret) {
6318 goto out_cli;
6322 ret = tar_process(tar_ctx);
6324 out_cli:
6325 cli_shutdown(cli);
6326 out:
6327 return ret;
6330 /****************************************************************************
6331 Handle a message operation.
6332 ****************************************************************************/
6334 static int do_message_op(struct cli_credentials *creds)
6336 NTSTATUS status;
6338 if (lp_disable_netbios()) {
6339 d_printf("NetBIOS over TCP disabled.\n");
6340 return 1;
6343 status = cli_connect_nb(desthost, have_ip ? &dest_ss : NULL,
6344 port ? port : NBT_SMB_PORT, name_type,
6345 lp_netbios_name(),
6346 SMB_SIGNING_OFF,
6348 &cli);
6349 if (!NT_STATUS_IS_OK(status)) {
6350 d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
6351 return 1;
6354 cli_set_timeout(cli, io_timeout*1000);
6355 send_message(cli_credentials_get_username(creds));
6356 cli_shutdown(cli);
6358 return 0;
6361 /****************************************************************************
6362 main program
6363 ****************************************************************************/
6365 int main(int argc,char *argv[])
6367 const char **const_argv = discard_const_p(const char *, argv);
6368 char *base_directory = NULL;
6369 int opt;
6370 char *query_host = NULL;
6371 bool message = false;
6372 static const char *new_name_resolve_order = NULL;
6373 poptContext pc;
6374 char *p;
6375 int rc = 0;
6376 bool tar_opt = false;
6377 bool service_opt = false;
6378 struct tar *tar_ctx = tar_get_ctx();
6379 bool ok;
6381 struct poptOption long_options[] = {
6382 POPT_AUTOHELP
6385 .longName = "message",
6386 .shortName = 'M',
6387 .argInfo = POPT_ARG_STRING,
6388 .arg = NULL,
6389 .val = 'M',
6390 .descrip = "Send message",
6391 .argDescrip = "HOST",
6394 .longName = "ip-address",
6395 .shortName = 'I',
6396 .argInfo = POPT_ARG_STRING,
6397 .arg = NULL,
6398 .val = 'I',
6399 .descrip = "Use this IP to connect to",
6400 .argDescrip = "IP",
6403 .longName = "stderr",
6404 .shortName = 'E',
6405 .argInfo = POPT_ARG_NONE,
6406 .arg = NULL,
6407 .val = 'E',
6408 .descrip = "Write messages to stderr instead of stdout",
6411 .longName = "list",
6412 .shortName = 'L',
6413 .argInfo = POPT_ARG_STRING,
6414 .arg = NULL,
6415 .val = 'L',
6416 .descrip = "Get a list of shares available on a host",
6417 .argDescrip = "HOST",
6420 .longName = "tar",
6421 .shortName = 'T',
6422 .argInfo = POPT_ARG_STRING,
6423 .arg = NULL,
6424 .val = 'T',
6425 .descrip = "Command line tar",
6426 .argDescrip = "<c|x>IXFvgbNan",
6429 .longName = "directory",
6430 .shortName = 'D',
6431 .argInfo = POPT_ARG_STRING,
6432 .arg = NULL,
6433 .val = 'D',
6434 .descrip = "Start from directory",
6435 .argDescrip = "DIR",
6438 .longName = "command",
6439 .shortName = 'c',
6440 .argInfo = POPT_ARG_STRING,
6441 .arg = &cmdstr,
6442 .val = 'c',
6443 .descrip = "Execute semicolon separated commands",
6446 .longName = "send-buffer",
6447 .shortName = 'b',
6448 .argInfo = POPT_ARG_INT,
6449 .arg = &io_bufsize,
6450 .val = 'b',
6451 .descrip = "Changes the transmit/send buffer",
6452 .argDescrip = "BYTES",
6455 .longName = "timeout",
6456 .shortName = 't',
6457 .argInfo = POPT_ARG_INT,
6458 .arg = &io_timeout,
6459 .val = 'b',
6460 .descrip = "Changes the per-operation timeout",
6461 .argDescrip = "SECONDS",
6464 .longName = "port",
6465 .shortName = 'p',
6466 .argInfo = POPT_ARG_INT,
6467 .arg = &port,
6468 .val = 'p',
6469 .descrip = "Port to connect to",
6470 .argDescrip = "PORT",
6473 .longName = "grepable",
6474 .shortName = 'g',
6475 .argInfo = POPT_ARG_NONE,
6476 .arg = NULL,
6477 .val = 'g',
6478 .descrip = "Produce grepable output",
6481 .longName = "quiet",
6482 .shortName = 'q',
6483 .argInfo = POPT_ARG_NONE,
6484 .arg = NULL,
6485 .val = 'q',
6486 .descrip = "Suppress help message",
6489 .longName = "browse",
6490 .shortName = 'B',
6491 .argInfo = POPT_ARG_NONE,
6492 .arg = NULL,
6493 .val = 'B',
6494 .descrip = "Browse SMB servers using DNS",
6496 POPT_COMMON_SAMBA
6497 POPT_COMMON_CONNECTION
6498 POPT_COMMON_CREDENTIALS
6499 POPT_LEGACY_S3
6500 POPT_COMMON_VERSION
6501 POPT_TABLEEND
6503 TALLOC_CTX *frame = talloc_stackframe();
6504 struct cli_credentials *creds = NULL;
6506 if (!client_set_cur_dir("\\")) {
6507 exit(ENOMEM);
6510 smb_init_locale();
6512 ok = samba_cmdline_init(frame,
6513 SAMBA_CMDLINE_CONFIG_CLIENT,
6514 false /* require_smbconf */);
6515 if (!ok) {
6516 DBG_ERR("Failed to init cmdline parser!\n");
6517 exit(ENOMEM);
6519 lp_set_cmdline("log level", "1");
6521 /* skip argv(0) */
6522 pc = samba_popt_get_context(getprogname(),
6523 argc,
6524 const_argv,
6525 long_options,
6527 if (pc == NULL) {
6528 DBG_ERR("Failed to setup popt context!\n");
6529 exit(1);
6532 poptSetOtherOptionHelp(pc, "[OPTIONS] service <password>");
6534 creds = samba_cmdline_get_creds();
6535 while ((opt = poptGetNextOpt(pc)) != -1) {
6538 * if the tar option has been called previously, now
6539 * we need to eat out the leftovers
6541 /* I see no other way to keep things sane --SSS */
6542 if (tar_opt == true) {
6543 while (poptPeekArg(pc)) {
6544 poptGetArg(pc);
6546 tar_opt = false;
6549 /* if the service has not yet been specified lets see if it is available in the popt stack */
6550 if (!service_opt && poptPeekArg(pc)) {
6551 service = talloc_strdup(frame, poptGetArg(pc));
6552 if (!service) {
6553 exit(ENOMEM);
6555 service_opt = true;
6558 /* if the service has already been retrieved then check if we have also a password */
6559 if (service_opt &&
6560 cli_credentials_get_password(creds) == NULL &&
6561 poptPeekArg(pc)) {
6562 cli_credentials_set_password(creds,
6563 poptGetArg(pc),
6564 CRED_SPECIFIED);
6568 switch (opt) {
6569 case 'M':
6570 /* Messages are sent to NetBIOS name type 0x3
6571 * (Messenger Service). Make sure we default
6572 * to port 139 instead of port 445. srl,crh
6574 name_type = 0x03;
6575 desthost = talloc_strdup(frame,poptGetOptArg(pc));
6576 if (!desthost) {
6577 exit(ENOMEM);
6579 if( !port )
6580 port = NBT_SMB_PORT;
6581 message = true;
6582 break;
6583 case 'I':
6585 if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
6586 exit(1);
6588 have_ip = true;
6589 print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
6591 break;
6592 case 'E':
6593 setup_logging("smbclient", DEBUG_STDERR );
6594 display_set_stderr();
6595 break;
6597 case 'L':
6598 query_host = talloc_strdup(frame, poptGetOptArg(pc));
6599 if (!query_host) {
6600 exit(ENOMEM);
6602 break;
6603 case 'T':
6604 /* We must use old option processing for this. Find the
6605 * position of the -T option in the raw argv[]. */
6607 int i;
6609 for (i = 1; i < argc; i++) {
6610 if (strncmp("-T", argv[i],2)==0)
6611 break;
6613 i++;
6614 if (tar_parse_args(tar_ctx, poptGetOptArg(pc),
6615 const_argv + i, argc - i)) {
6616 poptPrintUsage(pc, stderr, 0);
6617 exit(1);
6620 /* this must be the last option, mark we have parsed it so that we know we have */
6621 tar_opt = true;
6622 break;
6623 case 'D':
6624 base_directory = talloc_strdup(frame, poptGetOptArg(pc));
6625 if (!base_directory) {
6626 exit(ENOMEM);
6628 break;
6629 case 'g':
6630 grepable=true;
6631 break;
6632 case 'q':
6633 quiet=true;
6634 break;
6635 case 'B':
6636 return(do_smb_browse());
6637 case POPT_ERROR_BADOPT:
6638 fprintf(stderr, "\nInvalid option %s: %s\n\n",
6639 poptBadOption(pc, 0), poptStrerror(opt));
6640 poptPrintUsage(pc, stderr, 0);
6641 exit(1);
6645 /* We may still have some leftovers after the last popt option has been called */
6646 if (tar_opt == true) {
6647 while (poptPeekArg(pc)) {
6648 poptGetArg(pc);
6650 tar_opt = false;
6653 /* if the service has not yet been specified lets see if it is available in the popt stack */
6654 if (!service_opt && poptPeekArg(pc)) {
6655 service = talloc_strdup(frame,poptGetArg(pc));
6656 if (!service) {
6657 exit(ENOMEM);
6659 service_opt = true;
6662 /* if the service has already been retrieved then check if we have also a password */
6663 if (service_opt &&
6664 cli_credentials_get_password(creds) == NULL &&
6665 poptPeekArg(pc)) {
6666 cli_credentials_set_password(creds,
6667 poptGetArg(pc),
6668 CRED_SPECIFIED);
6671 if (service_opt && service) {
6672 size_t len;
6674 /* Convert any '/' characters in the service name to '\' characters */
6675 string_replace(service, '/','\\');
6676 if (count_chars(service,'\\') < 3) {
6677 d_printf("\n%s: Not enough '\\' characters in service\n",service);
6678 poptPrintUsage(pc, stderr, 0);
6679 exit(1);
6681 /* Remove trailing slashes */
6682 len = strlen(service);
6683 while(len > 0 && service[len - 1] == '\\') {
6684 --len;
6685 service[len] = '\0';
6689 if(new_name_resolve_order)
6690 lp_set_cmdline("name resolve order", new_name_resolve_order);
6692 if (!tar_to_process(tar_ctx) && !query_host && !service && !message) {
6693 poptPrintUsage(pc, stderr, 0);
6694 exit(1);
6697 poptFreeContext(pc);
6698 samba_cmdline_burn(argc, argv);
6700 DEBUG(3,("Client started (version %s).\n", samba_version_string()));
6702 if (tar_to_process(tar_ctx)) {
6703 if (cmdstr)
6704 process_command_string(cmdstr);
6705 rc = do_tar_op(base_directory);
6706 } else if (query_host && *query_host) {
6707 char *qhost = query_host;
6708 char *slash;
6710 while (*qhost == '\\' || *qhost == '/')
6711 qhost++;
6713 if ((slash = strchr_m(qhost, '/'))
6714 || (slash = strchr_m(qhost, '\\'))) {
6715 *slash = 0;
6718 if ((p=strchr_m(qhost, '#'))) {
6719 *p = 0;
6720 p++;
6721 sscanf(p, "%x", &name_type);
6724 rc = do_host_query(qhost);
6725 } else if (message) {
6726 rc = do_message_op(creds);
6727 } else if (process(base_directory)) {
6728 rc = 1;
6731 TALLOC_FREE(frame);
6732 return rc;