s3:libsmb: Pass memory context to cli_connect_nb()
[samba.git] / source3 / client / client.c
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
9
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.
14
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.
19
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/>.
22 */
23
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"
44 #include "libcli/smb/reparse.h"
45 #include "lib/param/param.h"
46
47 #ifndef REGISTER
48 #define REGISTER 0
49 #endif
50
51 extern int do_smb_browse(void); /* mDNS browsing */
52
53 static int port = 0;
54 static char *service;
55 static char *desthost;
56 static bool grepable = false;
57 static bool quiet = false;
58 static char *cmdstr = NULL;
59 const char *cmd_ptr = NULL;
60
61 static int io_bufsize = 0; /* we use the default size */
62 static int io_timeout = (CLIENT_TIMEOUT/1000); /* Per operation timeout (in seconds). */
63
64 static int name_type = 0x20;
65
66 static int process_tok(char *tok);
67 static int cmd_help(void);
68
69 /* value for unused fid field in trans2 secondary request */
70 #define FID_UNUSED (0xFFFF)
71
72 time_t newer_than = 0;
73 static int archive_level = 0;
74
75 static bool translation = false;
76 static bool have_ip;
77
78 static bool prompt = true;
79
80 static bool recurse = false;
81 static bool showacls = false;
82 bool lowercase = false;
83 static bool backup_intent = false;
84
85 static struct sockaddr_storage dest_ss;
86 static char dest_ss_str[INET6_ADDRSTRLEN];
87
88 #define SEPARATORS " \t\n\r"
89
90 /* timing globals */
91 uint64_t get_total_size = 0;
92 unsigned int get_total_time_ms = 0;
93 static uint64_t put_total_size = 0;
94 static unsigned int put_total_time_ms = 0;
95
96 /* totals globals */
97 static double dir_total;
98
99 /* root cli_state connection */
100
101 struct cli_state *cli;
102
103 static char CLI_DIRSEP_CHAR = '\\';
104 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
105
106 /* Accessor functions for directory paths. */
107 static char *fileselection;
108 static const char *client_get_fileselection(void)
109 {
110         if (fileselection) {
111                 return fileselection;
112         }
113         return "";
114 }
115
116 static const char *client_set_fileselection(const char *new_fs)
117 {
118         SAFE_FREE(fileselection);
119         if (new_fs) {
120                 fileselection = SMB_STRDUP(new_fs);
121         }
122         return client_get_fileselection();
123 }
124
125 static char *cwd;
126 static const char *client_get_cwd(void)
127 {
128         if (cwd) {
129                 return cwd;
130         }
131         return CLI_DIRSEP_STR;
132 }
133
134 static const char *client_set_cwd(const char *new_cwd)
135 {
136         SAFE_FREE(cwd);
137         if (new_cwd) {
138                 cwd = SMB_STRDUP(new_cwd);
139         }
140         return client_get_cwd();
141 }
142
143 static char *cur_dir;
144 const char *client_get_cur_dir(void)
145 {
146         if (cur_dir) {
147                 return cur_dir;
148         }
149         return CLI_DIRSEP_STR;
150 }
151
152 const char *client_set_cur_dir(const char *newdir)
153 {
154         SAFE_FREE(cur_dir);
155         if (newdir) {
156                 cur_dir = SMB_STRDUP(newdir);
157         }
158         return client_get_cur_dir();
159 }
160
161 /****************************************************************************
162  Put up a yes/no prompt.
163 ****************************************************************************/
164
165 static bool yesno(const char *p)
166 {
167         char ans[20];
168         printf("%s",p);
169
170         if (!fgets(ans,sizeof(ans)-1,stdin))
171                 return(False);
172
173         if (*ans == 'y' || *ans == 'Y')
174                 return(True);
175
176         return(False);
177 }
178
179 /****************************************************************************
180  Write to a local file with CR/LF->LF translation if appropriate. Return the
181  number taken from the buffer. This may not equal the number written.
182 ****************************************************************************/
183
184 static ssize_t writefile(int f, char *b, size_t n)
185 {
186         size_t i = 0;
187
188         if (n == 0) {
189                 errno = EINVAL;
190                 return -1;
191         }
192
193         if (!translation) {
194                 return write(f,b,n);
195         }
196
197         do {
198                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
199                         b++;i++;
200                 }
201                 if (write(f, b, 1) != 1) {
202                         break;
203                 }
204                 b++;
205                 i++;
206         } while (i < n);
207
208         return (ssize_t)i;
209 }
210
211 /****************************************************************************
212  Read from a file with LF->CR/LF translation if appropriate. Return the
213  number read. read approx n bytes.
214 ****************************************************************************/
215
216 static int readfile(uint8_t *b, int n, FILE *f)
217 {
218         int i;
219         int c;
220
221         if (!translation)
222                 return fread(b,1,n,f);
223
224         i = 0;
225         while (i < (n - 1)) {
226                 if ((c = getc(f)) == EOF) {
227                         break;
228                 }
229
230                 if (c == '\n') { /* change all LFs to CR/LF */
231                         b[i++] = '\r';
232                 }
233
234                 b[i++] = c;
235         }
236
237         return(i);
238 }
239
240 struct push_state {
241         FILE *f;
242         off_t nread;
243 };
244
245 static size_t push_source(uint8_t *buf, size_t n, void *priv)
246 {
247         struct push_state *state = (struct push_state *)priv;
248         int result;
249
250         if (feof(state->f)) {
251                 return 0;
252         }
253
254         result = readfile(buf, n, state->f);
255         state->nread += result;
256         return result;
257 }
258
259 /****************************************************************************
260  Send a message.
261 ****************************************************************************/
262
263 static void send_message(const char *username)
264 {
265         char buf[1600];
266         NTSTATUS status;
267         size_t i;
268
269         d_printf("Type your message, ending it with a Control-D\n");
270
271         i = 0;
272         while (i<sizeof(buf)-2) {
273                 int c = fgetc(stdin);
274                 if (c == EOF) {
275                         break;
276                 }
277                 if (c == '\n') {
278                         buf[i++] = '\r';
279                 }
280                 buf[i++] = c;
281         }
282         buf[i] = '\0';
283
284         status = cli_message(cli, desthost, username, buf);
285         if (!NT_STATUS_IS_OK(status)) {
286                 d_fprintf(stderr, "cli_message returned %s\n",
287                           nt_errstr(status));
288         }
289 }
290
291 /****************************************************************************
292  Check the space on a device.
293 ****************************************************************************/
294
295 static int do_dskattr(void)
296 {
297         uint64_t total, bsize, avail;
298         struct cli_state *targetcli = NULL;
299         char *targetpath = NULL;
300         TALLOC_CTX *ctx = talloc_tos();
301         struct cli_credentials *creds = samba_cmdline_get_creds();
302         NTSTATUS status;
303
304         status = cli_resolve_path(ctx,
305                                   "",
306                                   creds,
307                                   cli,
308                                   client_get_cur_dir(), &targetcli,
309                                   &targetpath);
310         if (!NT_STATUS_IS_OK(status)) {
311                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
312                 return 1;
313         }
314
315         status = cli_disk_size(targetcli, targetpath, &bsize, &total, &avail);
316         if (!NT_STATUS_IS_OK(status)) {
317                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
318                 return 1;
319         }
320
321         d_printf("\n\t\t%" PRIu64
322                 " blocks of size %" PRIu64
323                 ". %" PRIu64 " blocks available\n",
324                 total, bsize, avail);
325
326         return 0;
327 }
328
329 /****************************************************************************
330  Show cd/pwd.
331 ****************************************************************************/
332
333 static int cmd_pwd(void)
334 {
335         d_printf("Current directory is %s",service);
336         d_printf("%s\n",client_get_cur_dir());
337         return 0;
338 }
339
340 /****************************************************************************
341  Ensure name has correct directory separators.
342 ****************************************************************************/
343
344 static void normalize_name(char *newdir)
345 {
346         if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
347                 string_replace(newdir,'/','\\');
348         }
349 }
350
351 /****************************************************************************
352  Local name cleanup before sending to server. SMB1 allows relative pathnames,
353  but SMB2 does not, so we need to resolve them locally.
354 ****************************************************************************/
355
356 char *client_clean_name(TALLOC_CTX *ctx, const char *name)
357 {
358         char *newname = NULL;
359         if (name == NULL) {
360                 return NULL;
361         }
362
363         /* First ensure any path separators are correct. */
364         newname = talloc_strdup(ctx, name);
365         if (newname == NULL) {
366                 return NULL;
367         }
368         normalize_name(newname);
369
370         /* Now remove any relative (..) path components. */
371         if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
372                 newname = unix_clean_name(ctx, newname);
373         } else {
374                 newname = clean_name(ctx, newname);
375         }
376         if (newname == NULL) {
377                 return NULL;
378         }
379         return newname;
380 }
381
382 /****************************************************************************
383  Change directory - inner section.
384 ****************************************************************************/
385
386 static int do_cd(const char *new_dir)
387 {
388         char *newdir = NULL;
389         char *saved_dir = NULL;
390         char *new_cd = NULL;
391         char *targetpath = NULL;
392         struct cli_state *targetcli = NULL;
393         int ret = 1;
394         TALLOC_CTX *ctx = talloc_stackframe();
395         struct cli_credentials *creds = samba_cmdline_get_creds();
396         NTSTATUS status;
397
398         newdir = talloc_strdup(ctx, new_dir);
399         if (!newdir) {
400                 TALLOC_FREE(ctx);
401                 return 1;
402         }
403
404         normalize_name(newdir);
405
406         /* Save the current directory in case the new directory is invalid */
407
408         saved_dir = talloc_strdup(ctx, client_get_cur_dir());
409         if (!saved_dir) {
410                 TALLOC_FREE(ctx);
411                 return 1;
412         }
413
414         if (*newdir == CLI_DIRSEP_CHAR) {
415                 client_set_cur_dir(newdir);
416                 new_cd = newdir;
417         } else {
418                 new_cd = talloc_asprintf(ctx, "%s%s",
419                                 client_get_cur_dir(),
420                                 newdir);
421                 if (!new_cd) {
422                         goto out;
423                 }
424         }
425
426         /* Ensure cur_dir ends in a DIRSEP */
427         if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
428                 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
429                 if (!new_cd) {
430                         goto out;
431                 }
432         }
433         client_set_cur_dir(new_cd);
434
435         new_cd = client_clean_name(ctx, new_cd);
436         client_set_cur_dir(new_cd);
437
438         status = cli_resolve_path(ctx, "",
439                                   creds,
440                                 cli, new_cd, &targetcli, &targetpath);
441         if (!NT_STATUS_IS_OK(status)) {
442                 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
443                 client_set_cur_dir(saved_dir);
444                 goto out;
445         }
446
447         if (strequal(targetpath,CLI_DIRSEP_STR )) {
448                 TALLOC_FREE(ctx);
449                 return 0;
450         }
451
452
453         targetpath = talloc_asprintf(
454                 ctx, "%s%s", targetpath, CLI_DIRSEP_STR);
455         if (!targetpath) {
456                 client_set_cur_dir(saved_dir);
457                 goto out;
458         }
459         targetpath = client_clean_name(ctx, targetpath);
460         if (!targetpath) {
461                 client_set_cur_dir(saved_dir);
462                 goto out;
463         }
464
465         status = cli_chkpath(targetcli, targetpath);
466         if (!NT_STATUS_IS_OK(status)) {
467                 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
468                 client_set_cur_dir(saved_dir);
469                 goto out;
470         }
471
472         ret = 0;
473
474 out:
475
476         TALLOC_FREE(ctx);
477         return ret;
478 }
479
480 /****************************************************************************
481  Change directory.
482 ****************************************************************************/
483
484 static int cmd_cd(void)
485 {
486         char *buf = NULL;
487         int rc = 0;
488
489         if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
490                 rc = do_cd(buf);
491         } else {
492                 d_printf("Current directory is %s\n",client_get_cur_dir());
493         }
494
495         return rc;
496 }
497
498 /****************************************************************************
499  Change directory.
500 ****************************************************************************/
501
502 static int cmd_cd_oneup(void)
503 {
504         return do_cd("..");
505 }
506
507 /*******************************************************************
508  Decide if a file should be operated on.
509 ********************************************************************/
510
511 static bool do_this_one(struct file_info *finfo)
512 {
513         if (!finfo->name) {
514                 return false;
515         }
516
517         if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
518                 return true;
519         }
520
521         if (*client_get_fileselection() &&
522             !mask_match(finfo->name,client_get_fileselection(),false)) {
523                 DEBUG(3,("mask_match %s failed\n", finfo->name));
524                 return false;
525         }
526
527         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
528                 DEBUG(3,("newer_than %s failed\n", finfo->name));
529                 return false;
530         }
531
532         if ((archive_level==1 || archive_level==2) && !(finfo->attr & FILE_ATTRIBUTE_ARCHIVE)) {
533                 DEBUG(3,("archive %s failed\n", finfo->name));
534                 return false;
535         }
536
537         return true;
538 }
539
540 /****************************************************************************
541  Display info about a file.
542 ****************************************************************************/
543
544 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
545                           const char *dir)
546 {
547         time_t t;
548         TALLOC_CTX *ctx = talloc_tos();
549         NTSTATUS status = NT_STATUS_OK;
550
551         if (!do_this_one(finfo)) {
552                 return NT_STATUS_OK;
553         }
554
555         t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
556         if (!showacls) {
557                 d_printf("  %-30s%7.7s %8.0f  %s",
558                          finfo->name,
559                          attrib_string(talloc_tos(), finfo->attr),
560                         (double)finfo->size,
561                         time_to_asc(t));
562                 dir_total += finfo->size;
563         } else {
564                 struct cli_state *targetcli = NULL;
565                 char *targetpath = NULL;
566                 char *afname = NULL;
567                 uint16_t fnum;
568                 struct cli_credentials *creds = samba_cmdline_get_creds();
569
570                 if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
571                         return NT_STATUS_OK;
572                 }
573                 /* create absolute filename for cli_ntcreate() FIXME */
574                 afname = talloc_asprintf(ctx,
575                                         "%s%s%s",
576                                         dir,
577                                         CLI_DIRSEP_STR,
578                                         finfo->name);
579                 if (!afname) {
580                         return NT_STATUS_NO_MEMORY;
581                 }
582                 /* print file meta date header */
583                 d_printf( "FILENAME:%s\n", finfo->name);
584                 d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->attr));
585                 d_printf( "SIZE:%.0f\n", (double)finfo->size);
586                 d_printf( "MTIME:%s", time_to_asc(t));
587
588                 status = cli_resolve_path(
589                         ctx,
590                         "",
591                         creds,
592                         cli_state,
593                         afname,
594                         &targetcli,
595                         &targetpath);
596                 if (!NT_STATUS_IS_OK(status)) {
597                         DBG_WARNING("display_finfo() Failed to resolve "
598                                     "%s: %s\n",
599                                     afname, nt_errstr(status));
600                         return status;
601                 }
602
603                 status = cli_ntcreate(
604                         targetcli,            /* cli */
605                         targetpath,           /* fname */
606                         0,                    /* CreatFlags */
607                         READ_CONTROL_ACCESS,  /* DesiredAccess */
608                         0,                    /* FileAttributes */
609                         FILE_SHARE_READ|
610                         FILE_SHARE_WRITE,     /* ShareAccess */
611                         FILE_OPEN,            /* CreateDisposition */
612                         0x0,                  /* CreateOptions */
613                         0x0,                  /* SecurityFlags */
614                         &fnum,                /* pfid */
615                         NULL);                /* cr */
616                 if (!NT_STATUS_IS_OK(status)) {
617                         DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
618                                    afname, nt_errstr(status)));
619                 } else {
620                         struct security_descriptor *sd = NULL;
621                         status = cli_query_secdesc(targetcli, fnum,
622                                                    ctx, &sd);
623                         if (!NT_STATUS_IS_OK(status)) {
624                                 DEBUG( 0, ("display_finfo() failed to "
625                                            "get security descriptor: %s\n",
626                                            nt_errstr(status)));
627                         } else {
628                                 display_sec_desc(sd);
629                         }
630                         TALLOC_FREE(sd);
631                         cli_close(targetcli, fnum);
632                 }
633                 TALLOC_FREE(afname);
634         }
635         return status;
636 }
637
638 /****************************************************************************
639  Accumulate size of a file.
640 ****************************************************************************/
641
642 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
643                   const char *dir)
644 {
645         if (do_this_one(finfo)) {
646                 dir_total += finfo->size;
647         }
648         return NT_STATUS_OK;
649 }
650
651 struct do_list_queue_entry {
652         struct do_list_queue_entry *prev, *next;
653         char name[];
654 };
655
656 struct do_list_queue {
657         struct do_list_queue_entry *list;
658 };
659
660 static bool do_list_recurse;
661 static bool do_list_dirs;
662 static struct do_list_queue *queue = NULL;
663 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
664                           const char *dir);
665
666 /****************************************************************************
667  Functions for do_list_queue.
668 ****************************************************************************/
669
670 static void reset_do_list_queue(void)
671 {
672         TALLOC_FREE(queue);
673 }
674
675 static void init_do_list_queue(void)
676 {
677         TALLOC_FREE(queue);
678         queue = talloc_zero(NULL, struct do_list_queue);
679 }
680
681 static void add_to_do_list_queue(const char *entry)
682 {
683         struct do_list_queue_entry *e = NULL;
684         size_t entry_str_len = strlen(entry)+1;
685         size_t entry_len = offsetof(struct do_list_queue_entry, name);
686
687         entry_len += entry_str_len;
688         SMB_ASSERT(entry_len >= entry_str_len);
689
690         e = talloc_size(queue, entry_len);
691         if (e == NULL) {
692                 d_printf("talloc failed for entry %s\n", entry);
693                 return;
694         }
695         talloc_set_name_const(e, "struct do_list_queue_entry");
696
697         memcpy(e->name, entry, entry_str_len);
698         DLIST_ADD_END(queue->list, e);
699 }
700
701 static char *do_list_queue_head(void)
702 {
703         return queue->list->name;
704 }
705
706 static void remove_do_list_queue_head(void)
707 {
708         struct do_list_queue_entry *e = queue->list;
709         DLIST_REMOVE(queue->list, e);
710         TALLOC_FREE(e);
711 }
712
713 static int do_list_queue_empty(void)
714 {
715         return (queue == NULL) || (queue->list == NULL);
716 }
717
718 /****************************************************************************
719  A helper for do_list.
720 ****************************************************************************/
721
722 struct do_list_helper_state {
723         const char *mask;
724         struct cli_state *cli;
725 };
726
727 static NTSTATUS do_list_helper(
728         struct file_info *f,
729         const char *_mask,
730         void *private_data)
731 {
732         struct do_list_helper_state *state = private_data;
733         TALLOC_CTX *ctx = talloc_tos();
734         char *dir = NULL;
735         char *dir_end = NULL;
736         NTSTATUS status = NT_STATUS_OK;
737         char *mask2 = NULL;
738
739         /* Work out the directory. */
740         dir = talloc_strdup(ctx, state->mask);
741         if (!dir) {
742                 return NT_STATUS_NO_MEMORY;
743         }
744         if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
745                 *dir_end = '\0';
746         }
747
748         if (!(f->attr & FILE_ATTRIBUTE_DIRECTORY)) {
749                 if (do_this_one(f)) {
750                         status = do_list_fn(state->cli, f, dir);
751                 }
752                 TALLOC_FREE(dir);
753                 return status;
754         }
755
756         if (do_list_dirs && do_this_one(f)) {
757                 status = do_list_fn(state->cli, f, dir);
758                 if (!NT_STATUS_IS_OK(status)) {
759                         return status;
760                 }
761         }
762
763         if (!do_list_recurse ||
764             (f->name == NULL) ||
765             ISDOT(f->name) ||
766             ISDOTDOT(f->name)) {
767                 return NT_STATUS_OK;
768         }
769
770         if (!f->name[0]) {
771                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
772                 TALLOC_FREE(dir);
773                 return NT_STATUS_UNSUCCESSFUL;
774         }
775
776         mask2 = talloc_asprintf(ctx,
777                                 "%s%c%s%c*",
778                                 dir,
779                                 CLI_DIRSEP_CHAR,
780                                 f->name,
781                                 CLI_DIRSEP_CHAR);
782         if (!mask2) {
783                 TALLOC_FREE(dir);
784                 return NT_STATUS_NO_MEMORY;
785         }
786         add_to_do_list_queue(mask2);
787         TALLOC_FREE(mask2);
788
789         TALLOC_FREE(dir);
790         return NT_STATUS_OK;
791 }
792
793 /****************************************************************************
794  A wrapper around cli_list that adds recursion.
795 ****************************************************************************/
796
797 NTSTATUS do_list(const char *mask,
798                         uint32_t attribute,
799                         NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
800                                    const char *dir),
801                         bool rec,
802                         bool dirs)
803 {
804         struct do_list_helper_state state = { .cli = cli, };
805         static int in_do_list = 0;
806         TALLOC_CTX *ctx = talloc_tos();
807         struct cli_credentials *creds = samba_cmdline_get_creds();
808         NTSTATUS ret_status = NT_STATUS_OK;
809         NTSTATUS status = NT_STATUS_OK;
810
811         if (in_do_list && rec) {
812                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
813                 exit(1);
814         }
815
816         in_do_list = 1;
817
818         do_list_recurse = rec;
819         do_list_dirs = dirs;
820         do_list_fn = fn;
821
822         init_do_list_queue();
823         add_to_do_list_queue(mask);
824
825         while (!do_list_queue_empty()) {
826                 struct cli_state *targetcli = NULL;
827                 char *targetpath = NULL;
828
829                 state.mask = do_list_queue_head();
830
831                 /* check for dfs */
832
833                 status = cli_resolve_path(
834                         ctx,
835                         "",
836                         creds,
837                         cli,
838                         state.mask,
839                         &targetcli,
840                         &targetpath);
841                 if (!NT_STATUS_IS_OK(status)) {
842                         d_printf("do_list: [%s] %s\n", state.mask,
843                                  nt_errstr(status));
844                         remove_do_list_queue_head();
845                         continue;
846                 }
847
848                 status = cli_list(
849                         targetcli,
850                         targetpath,
851                         attribute,
852                         do_list_helper,
853                         &state);
854                 if (!NT_STATUS_IS_OK(status)) {
855                         d_printf("%s listing %s\n",
856                                  nt_errstr(status), targetpath);
857                         ret_status = status;
858                 }
859                 remove_do_list_queue_head();
860                 if ((! do_list_queue_empty()) && (fn == display_finfo)) {
861                         char *next_file = do_list_queue_head();
862                         char *save_ch = 0;
863                         if ((strlen(next_file) >= 2) &&
864                             (next_file[strlen(next_file) - 1] == '*') &&
865                             (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
866                                 save_ch = next_file +
867                                         strlen(next_file) - 2;
868                                 *save_ch = '\0';
869                                 if (showacls) {
870                                         /* cwd is only used if showacls is on */
871                                         client_set_cwd(next_file);
872                                 }
873                         }
874                         if (!showacls) /* don't disturbe the showacls output */
875                                 d_printf("\n%s\n",next_file);
876                         if (save_ch) {
877                                 *save_ch = CLI_DIRSEP_CHAR;
878                         }
879                 }
880                 TALLOC_FREE(targetpath);
881         }
882
883         in_do_list = 0;
884         reset_do_list_queue();
885         return ret_status;
886 }
887
888 /****************************************************************************
889  Get a directory listing.
890 ****************************************************************************/
891
892 static int cmd_dir(void)
893 {
894         TALLOC_CTX *ctx = talloc_tos();
895         uint32_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
896         char *mask = NULL;
897         char *buf = NULL;
898         int rc = 1;
899         NTSTATUS status;
900
901         dir_total = 0;
902         mask = talloc_strdup(ctx, client_get_cur_dir());
903         if (!mask) {
904                 return 1;
905         }
906
907         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
908                 normalize_name(buf);
909                 if (*buf == CLI_DIRSEP_CHAR) {
910                         mask = talloc_strdup(ctx, buf);
911                 } else {
912                         mask = talloc_asprintf_append(mask, "%s", buf);
913                 }
914         } else {
915                 mask = talloc_asprintf_append(mask, "*");
916         }
917         if (!mask) {
918                 return 1;
919         }
920
921         mask = client_clean_name(ctx, mask);
922         if (mask == NULL) {
923                 return 1;
924         }
925
926         if (showacls) {
927                 /* cwd is only used if showacls is on */
928                 client_set_cwd(client_get_cur_dir());
929         }
930
931         status = do_list(mask, attribute, display_finfo, recurse, true);
932         if (!NT_STATUS_IS_OK(status)) {
933                 return 1;
934         }
935
936         rc = do_dskattr();
937
938         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
939
940         return rc;
941 }
942
943 /****************************************************************************
944  Get a directory listing.
945 ****************************************************************************/
946
947 static int cmd_du(void)
948 {
949         TALLOC_CTX *ctx = talloc_tos();
950         uint32_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
951         char *mask = NULL;
952         char *buf = NULL;
953         NTSTATUS status;
954         int rc = 1;
955
956         dir_total = 0;
957         mask = talloc_strdup(ctx, client_get_cur_dir());
958         if (!mask) {
959                 return 1;
960         }
961         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
962                 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
963                 if (!mask) {
964                         return 1;
965                 }
966         }
967
968         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
969                 normalize_name(buf);
970                 if (*buf == CLI_DIRSEP_CHAR) {
971                         mask = talloc_strdup(ctx, buf);
972                 } else {
973                         mask = talloc_asprintf_append(mask, "%s", buf);
974                 }
975         } else {
976                 mask = talloc_strdup(ctx, "*");
977         }
978         if (!mask) {
979                 return 1;
980         }
981
982         mask = client_clean_name(ctx, mask);
983         if (mask == NULL) {
984                 return 1;
985         }
986
987         status = do_list(mask, attribute, do_du, recurse, true);
988         if (!NT_STATUS_IS_OK(status)) {
989                 return 1;
990         }
991
992         rc = do_dskattr();
993
994         d_printf("Total number of bytes: %.0f\n", dir_total);
995
996         return rc;
997 }
998
999 static int cmd_echo(void)
1000 {
1001         TALLOC_CTX *ctx = talloc_tos();
1002         char *num;
1003         char *data;
1004         NTSTATUS status;
1005
1006         if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1007             || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1008                 d_printf("echo <num> <data>\n");
1009                 return 1;
1010         }
1011
1012         status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1013
1014         if (!NT_STATUS_IS_OK(status)) {
1015                 d_printf("echo failed: %s\n", nt_errstr(status));
1016                 return 1;
1017         }
1018
1019         return 0;
1020 }
1021
1022 /****************************************************************************
1023  Get a file from rname to lname
1024 ****************************************************************************/
1025
1026 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1027 {
1028         int *pfd = (int *)priv;
1029         ssize_t rc;
1030
1031         rc = writefile(*pfd, buf, n);
1032         if (rc == -1) {
1033                 return map_nt_error_from_unix(errno);
1034         }
1035         return NT_STATUS_OK;
1036 }
1037
1038 static int do_get(const char *rname, const char *lname_in, bool reget)
1039 {
1040         TALLOC_CTX *ctx = talloc_tos();
1041         int handle = 0;
1042         uint16_t fnum;
1043         bool newhandle = false;
1044         struct timespec tp_start;
1045         uint32_t attr;
1046         off_t size;
1047         off_t start = 0;
1048         off_t nread = 0;
1049         int rc = 0;
1050         struct cli_state *targetcli = NULL;
1051         char *targetname = NULL;
1052         char *lname = NULL;
1053         struct cli_credentials *creds = samba_cmdline_get_creds();
1054         NTSTATUS status;
1055
1056         lname = talloc_strdup(ctx, lname_in);
1057         if (!lname) {
1058                 return 1;
1059         }
1060
1061         if (lowercase) {
1062                 if (!strlower_m(lname)) {
1063                         d_printf("strlower_m %s failed\n", lname);
1064                         return 1;
1065                 }
1066         }
1067
1068         status = cli_resolve_path(ctx, "",
1069                                   creds,
1070                                 cli, rname, &targetcli, &targetname);
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1073                 return 1;
1074         }
1075
1076         clock_gettime_mono(&tp_start);
1077
1078         status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1079         if (!NT_STATUS_IS_OK(status)) {
1080                 d_printf("%s opening remote file %s\n", nt_errstr(status),
1081                          rname);
1082                 return 1;
1083         }
1084
1085         if(!strcmp(lname,"-")) {
1086                 handle = fileno(stdout);
1087         } else {
1088                 if (reget) {
1089                         handle = open(lname, O_WRONLY|O_CREAT, 0644);
1090                         if (handle >= 0) {
1091                                 start = lseek(handle, 0, SEEK_END);
1092                                 if (start == -1) {
1093                                         d_printf("Error seeking local file\n");
1094                                         close(handle);
1095                                         return 1;
1096                                 }
1097                         }
1098                 } else {
1099                         handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1100                 }
1101                 newhandle = true;
1102         }
1103         if (handle < 0) {
1104                 d_printf("Error opening local file %s\n",lname);
1105                 return 1;
1106         }
1107
1108
1109         status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1110                                      NULL, NULL, NULL);
1111         if (!NT_STATUS_IS_OK(status)) {
1112                 d_printf("getattrib: %s\n", nt_errstr(status));
1113                 if (newhandle) {
1114                         close(handle);
1115                 }
1116                 return 1;
1117         }
1118
1119         DEBUG(1,("getting file %s of size %.0f as %s ",
1120                  rname, (double)size, lname));
1121
1122         status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1123                           writefile_sink, (void *)&handle, &nread);
1124         if (!NT_STATUS_IS_OK(status)) {
1125                 d_fprintf(stderr, "parallel_read returned %s\n",
1126                           nt_errstr(status));
1127                 if (newhandle) {
1128                         close(handle);
1129                 }
1130                 cli_close(targetcli, fnum);
1131                 return 1;
1132         }
1133
1134         status = cli_close(targetcli, fnum);
1135         if (!NT_STATUS_IS_OK(status)) {
1136                 d_printf("Error %s closing remote file\n", nt_errstr(status));
1137                 rc = 1;
1138         }
1139
1140         if (newhandle) {
1141                 close(handle);
1142         }
1143
1144         if (archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
1145                 cli_setatr(cli, rname, attr & ~(uint32_t)FILE_ATTRIBUTE_ARCHIVE, 0);
1146         }
1147
1148         {
1149                 struct timespec tp_end;
1150                 int this_time;
1151
1152                 clock_gettime_mono(&tp_end);
1153                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1154                 get_total_time_ms += this_time;
1155                 get_total_size += nread;
1156
1157                 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1158                          nread / (1.024*this_time + 1.0e-4),
1159                          get_total_size / (1.024*get_total_time_ms)));
1160         }
1161
1162         TALLOC_FREE(targetname);
1163         return rc;
1164 }
1165
1166 /****************************************************************************
1167  Get a file.
1168 ****************************************************************************/
1169
1170 static int cmd_get(void)
1171 {
1172         TALLOC_CTX *ctx = talloc_tos();
1173         char *lname = NULL;
1174         char *rname = NULL;
1175         char *fname = NULL;
1176
1177         rname = talloc_strdup(ctx, client_get_cur_dir());
1178         if (!rname) {
1179                 return 1;
1180         }
1181
1182         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1183                 d_printf("get <filename> [localname]\n");
1184                 return 1;
1185         }
1186         rname = talloc_asprintf_append(rname, "%s", fname);
1187         if (!rname) {
1188                 return 1;
1189         }
1190         rname = client_clean_name(ctx, rname);
1191         if (!rname) {
1192                 return 1;
1193         }
1194
1195         next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1196         if (!lname) {
1197                 lname = fname;
1198         }
1199
1200         return do_get(rname, lname, false);
1201 }
1202
1203 /****************************************************************************
1204  Do an mget operation on one file.
1205 ****************************************************************************/
1206
1207 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1208                     const char *dir)
1209 {
1210         TALLOC_CTX *ctx = talloc_tos();
1211         const char *client_cwd = NULL;
1212         size_t client_cwd_len;
1213         char *path = NULL;
1214         char *local_path = NULL;
1215
1216         if (!finfo->name) {
1217                 return NT_STATUS_OK;
1218         }
1219
1220         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
1221                 return NT_STATUS_OK;
1222         }
1223
1224         if ((finfo->attr & FILE_ATTRIBUTE_DIRECTORY) && !recurse) {
1225                 return NT_STATUS_OK;
1226         }
1227
1228         if (prompt) {
1229                 const char *object = (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) ?
1230                         "directory" : "file";
1231                 char *quest = NULL;
1232                 bool ok;
1233
1234                 quest = talloc_asprintf(
1235                         ctx, "Get %s %s? ", object, finfo->name);
1236                 if (quest == NULL) {
1237                         return NT_STATUS_NO_MEMORY;
1238                 }
1239
1240                 ok = yesno(quest);
1241                 TALLOC_FREE(quest);
1242                 if (!ok) {
1243                         return NT_STATUS_OK;
1244                 }
1245         }
1246
1247         path = talloc_asprintf(
1248                 ctx, "%s%c%s", dir, CLI_DIRSEP_CHAR, finfo->name);
1249         if (path == NULL) {
1250                 return NT_STATUS_NO_MEMORY;
1251         }
1252         path = client_clean_name(ctx, path);
1253         if (path == NULL) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256
1257         /*
1258          * Skip the path prefix if we've done a remote "cd" when
1259          * creating the local path
1260          */
1261         client_cwd = client_get_cur_dir();
1262         client_cwd_len = strlen(client_cwd);
1263
1264         local_path = talloc_strdup(ctx, path + client_cwd_len);
1265         if (local_path == NULL) {
1266                 TALLOC_FREE(path);
1267                 return NT_STATUS_NO_MEMORY;
1268         }
1269         string_replace(local_path, CLI_DIRSEP_CHAR, '/');
1270
1271         if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
1272                 int ret = mkdir(local_path, 0777);
1273
1274                 if ((ret == -1) && (errno != EEXIST)) {
1275                         return map_nt_error_from_unix(errno);
1276                 }
1277         } else {
1278                 do_get(path, local_path, false);
1279         }
1280
1281         return NT_STATUS_OK;
1282 }
1283
1284 /****************************************************************************
1285  View the file using the pager.
1286 ****************************************************************************/
1287
1288 static int cmd_more(void)
1289 {
1290         TALLOC_CTX *ctx = talloc_tos();
1291         char *rname = NULL;
1292         char *fname = NULL;
1293         char *lname = NULL;
1294         char *pager_cmd = NULL;
1295         const char *pager;
1296         int fd;
1297         int rc = 0;
1298         mode_t mask;
1299
1300         rname = talloc_strdup(ctx, client_get_cur_dir());
1301         if (!rname) {
1302                 return 1;
1303         }
1304
1305         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1306         if (!lname) {
1307                 return 1;
1308         }
1309         mask = umask(S_IRWXO | S_IRWXG);
1310         fd = mkstemp(lname);
1311         umask(mask);
1312         if (fd == -1) {
1313                 d_printf("failed to create temporary file for more\n");
1314                 return 1;
1315         }
1316         close(fd);
1317
1318         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1319                 d_printf("more <filename>\n");
1320                 unlink(lname);
1321                 return 1;
1322         }
1323         rname = talloc_asprintf_append(rname, "%s", fname);
1324         if (!rname) {
1325                 return 1;
1326         }
1327         rname = client_clean_name(ctx,rname);
1328         if (!rname) {
1329                 return 1;
1330         }
1331
1332         rc = do_get(rname, lname, false);
1333
1334         pager=getenv("PAGER");
1335
1336         pager_cmd = talloc_asprintf(ctx,
1337                                 "%s %s",
1338                                 (pager? pager:PAGER),
1339                                 lname);
1340         if (!pager_cmd) {
1341                 return 1;
1342         }
1343         if (system(pager_cmd) == -1) {
1344                 d_printf("system command '%s' returned -1\n",
1345                         pager_cmd);
1346         }
1347         unlink(lname);
1348
1349         return rc;
1350 }
1351
1352 /****************************************************************************
1353  Do a mget command.
1354 ****************************************************************************/
1355
1356 static int cmd_mget(void)
1357 {
1358         TALLOC_CTX *ctx = talloc_tos();
1359         uint32_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1360         char *mget_mask = NULL;
1361         char *buf = NULL;
1362         NTSTATUS status = NT_STATUS_OK;
1363
1364         if (recurse) {
1365                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1366         }
1367
1368         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1369
1370                 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1371                 if (!mget_mask) {
1372                         return 1;
1373                 }
1374                 if (*buf == CLI_DIRSEP_CHAR) {
1375                         mget_mask = talloc_strdup(ctx, buf);
1376                 } else {
1377                         mget_mask = talloc_asprintf_append(mget_mask,
1378                                                         "%s", buf);
1379                 }
1380                 if (!mget_mask) {
1381                         return 1;
1382                 }
1383                 mget_mask = client_clean_name(ctx, mget_mask);
1384                 if (mget_mask == NULL) {
1385                         return 1;
1386                 }
1387                 status = do_list(mget_mask, attribute, do_mget, recurse, true);
1388                 if (!NT_STATUS_IS_OK(status)) {
1389                         return 1;
1390                 }
1391         }
1392
1393         if (mget_mask == NULL) {
1394                 d_printf("nothing to mget\n");
1395                 return 0;
1396         }
1397
1398         if (!*mget_mask) {
1399                 mget_mask = talloc_asprintf(ctx,
1400                                         "%s*",
1401                                         client_get_cur_dir());
1402                 if (!mget_mask) {
1403                         return 1;
1404                 }
1405                 mget_mask = client_clean_name(ctx, mget_mask);
1406                 if (mget_mask == NULL) {
1407                         return 1;
1408                 }
1409                 status = do_list(mget_mask, attribute, do_mget, recurse, true);
1410                 if (!NT_STATUS_IS_OK(status)) {
1411                         return 1;
1412                 }
1413         }
1414
1415         return 0;
1416 }
1417
1418 /****************************************************************************
1419  Make a directory of name "name".
1420 ****************************************************************************/
1421
1422 static bool do_mkdir(const char *name)
1423 {
1424         TALLOC_CTX *ctx = talloc_tos();
1425         struct cli_state *targetcli;
1426         char *targetname = NULL;
1427         struct cli_credentials *creds = samba_cmdline_get_creds();
1428         NTSTATUS status;
1429
1430         status = cli_resolve_path(ctx, "",
1431                                   creds,
1432                                 cli, name, &targetcli, &targetname);
1433         if (!NT_STATUS_IS_OK(status)) {
1434                 d_printf("mkdir %s: %s\n", name, nt_errstr(status));
1435                 return false;
1436         }
1437
1438         status = cli_mkdir(targetcli, targetname);
1439         if (!NT_STATUS_IS_OK(status)) {
1440                 d_printf("%s making remote directory %s\n",
1441                          nt_errstr(status),name);
1442                 return false;
1443         }
1444
1445         return true;
1446 }
1447
1448 /****************************************************************************
1449  Show 8.3 name of a file.
1450 ****************************************************************************/
1451
1452 static bool do_altname(const char *name)
1453 {
1454         fstring altname;
1455         NTSTATUS status;
1456
1457         status = cli_qpathinfo_alt_name(cli, name, altname);
1458         if (!NT_STATUS_IS_OK(status)) {
1459                 d_printf("%s getting alt name for %s\n",
1460                          nt_errstr(status),name);
1461                 return false;
1462         }
1463         d_printf("%s\n", altname);
1464
1465         return true;
1466 }
1467
1468 /****************************************************************************
1469  Exit client.
1470 ****************************************************************************/
1471
1472 static int cmd_quit(void)
1473 {
1474         cli_shutdown(cli);
1475         exit(0);
1476         /* NOTREACHED */
1477         return 0;
1478 }
1479
1480 /****************************************************************************
1481  Make a directory.
1482 ****************************************************************************/
1483
1484 static int cmd_mkdir(void)
1485 {
1486         TALLOC_CTX *ctx = talloc_tos();
1487         char *mask = NULL;
1488         char *buf = NULL;
1489         struct cli_credentials *creds = samba_cmdline_get_creds();
1490         NTSTATUS status;
1491
1492         mask = talloc_strdup(ctx, client_get_cur_dir());
1493         if (!mask) {
1494                 return 1;
1495         }
1496
1497         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1498                 if (!recurse) {
1499                         d_printf("mkdir <dirname>\n");
1500                 }
1501                 return 1;
1502         }
1503         mask = talloc_asprintf_append(mask, "%s", buf);
1504         if (!mask) {
1505                 return 1;
1506         }
1507         mask = client_clean_name(ctx, mask);
1508         if (mask == NULL) {
1509                 return 1;
1510         }
1511
1512         if (recurse) {
1513                 char *ddir = NULL;
1514                 char *ddir2 = NULL;
1515                 struct cli_state *targetcli;
1516                 char *targetname = NULL;
1517                 char *p = NULL;
1518                 char *saveptr;
1519
1520                 ddir2 = talloc_strdup(ctx, "");
1521                 if (!ddir2) {
1522                         return 1;
1523                 }
1524
1525                 status = cli_resolve_path(ctx, "",
1526                                           creds,
1527                                           cli, mask,
1528                                 &targetcli, &targetname);
1529                 if (!NT_STATUS_IS_OK(status)) {
1530                         return 1;
1531                 }
1532
1533                 ddir = talloc_strdup(ctx, targetname);
1534                 if (!ddir) {
1535                         return 1;
1536                 }
1537                 trim_char(ddir,'.','\0');
1538                 p = strtok_r(ddir, "/\\", &saveptr);
1539                 while (p) {
1540                         ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1541                         if (!ddir2) {
1542                                 return 1;
1543                         }
1544                         if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1545                                 do_mkdir(ddir2);
1546                         }
1547                         ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1548                         if (!ddir2) {
1549                                 return 1;
1550                         }
1551                         p = strtok_r(NULL, "/\\", &saveptr);
1552                 }
1553         } else {
1554                 do_mkdir(mask);
1555         }
1556
1557         return 0;
1558 }
1559
1560 /****************************************************************************
1561  Show alt name.
1562 ****************************************************************************/
1563
1564 static int cmd_altname(void)
1565 {
1566         TALLOC_CTX *ctx = talloc_tos();
1567         char *name;
1568         char *buf;
1569
1570         name = talloc_strdup(ctx, client_get_cur_dir());
1571         if (!name) {
1572                 return 1;
1573         }
1574
1575         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1576                 d_printf("altname <file>\n");
1577                 return 1;
1578         }
1579         name = talloc_asprintf_append(name, "%s", buf);
1580         if (!name) {
1581                 return 1;
1582         }
1583         name = client_clean_name(ctx, name);
1584         if (name == NULL) {
1585                 return 1;
1586         }
1587         do_altname(name);
1588         return 0;
1589 }
1590
1591 static char *attr_str(TALLOC_CTX *mem_ctx, uint32_t attr)
1592 {
1593         char *attrs = talloc_zero_array(mem_ctx, char, 17);
1594         int i = 0;
1595
1596         if (!(attr & FILE_ATTRIBUTE_NORMAL)) {
1597                 if (attr & FILE_ATTRIBUTE_ENCRYPTED) {
1598                         attrs[i++] = 'E';
1599                 }
1600                 if (attr & FILE_ATTRIBUTE_NONINDEXED) {
1601                         attrs[i++] = 'N';
1602                 }
1603                 if (attr & FILE_ATTRIBUTE_OFFLINE) {
1604                         attrs[i++] = 'O';
1605                 }
1606                 if (attr & FILE_ATTRIBUTE_COMPRESSED) {
1607                         attrs[i++] = 'C';
1608                 }
1609                 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
1610                         attrs[i++] = 'r';
1611                 }
1612                 if (attr & FILE_ATTRIBUTE_SPARSE) {
1613                         attrs[i++] = 's';
1614                 }
1615                 if (attr & FILE_ATTRIBUTE_TEMPORARY) {
1616                         attrs[i++] = 'T';
1617                 }
1618                 if (attr & FILE_ATTRIBUTE_NORMAL) {
1619                         attrs[i++] = 'N';
1620                 }
1621                 if (attr & FILE_ATTRIBUTE_READONLY) {
1622                         attrs[i++] = 'R';
1623                 }
1624                 if (attr & FILE_ATTRIBUTE_HIDDEN) {
1625                         attrs[i++] = 'H';
1626                 }
1627                 if (attr & FILE_ATTRIBUTE_SYSTEM) {
1628                         attrs[i++] = 'S';
1629                 }
1630                 if (attr & FILE_ATTRIBUTE_DIRECTORY) {
1631                         attrs[i++] = 'D';
1632                 }
1633                 if (attr & FILE_ATTRIBUTE_ARCHIVE) {
1634                         attrs[i++] = 'A';
1635                 }
1636         }
1637         return attrs;
1638 }
1639
1640 /****************************************************************************
1641  Show all info we can get
1642 ****************************************************************************/
1643
1644 static int do_allinfo(const char *name)
1645 {
1646         fstring altname;
1647         struct timespec b_time, a_time, m_time, c_time;
1648         off_t size;
1649         uint32_t attr;
1650         NTTIME tmp;
1651         uint16_t fnum;
1652         unsigned int num_streams;
1653         struct stream_struct *streams;
1654         int j, num_snapshots;
1655         char **snapshots = NULL;
1656         unsigned int i;
1657         NTSTATUS status;
1658
1659         status = cli_qpathinfo_alt_name(cli, name, altname);
1660         if (!NT_STATUS_IS_OK(status)) {
1661                 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1662                          name);
1663                 /*
1664                  * Ignore not supported or not implemented, it does not
1665                  * hurt if we can't list alternate names.
1666                  */
1667                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
1668                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1669                         altname[0] = '\0';
1670                 } else {
1671                         return false;
1672                 }
1673         }
1674         d_printf("altname: %s\n", altname);
1675
1676         status = cli_qpathinfo3(cli, name, &b_time, &a_time, &m_time, &c_time,
1677                                 &size, &attr, NULL);
1678         if (!NT_STATUS_IS_OK(status)) {
1679                 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1680                          name);
1681                 return false;
1682         }
1683
1684         tmp = full_timespec_to_nt_time(&b_time);
1685         d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1686
1687         tmp = full_timespec_to_nt_time(&a_time);
1688         d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1689
1690         tmp = full_timespec_to_nt_time(&m_time);
1691         d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1692
1693         tmp = full_timespec_to_nt_time(&c_time);
1694         d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1695
1696         d_printf("attributes: %s (%x)\n", attr_str(talloc_tos(), attr), attr);
1697
1698         status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1699                                        &streams);
1700         if (!NT_STATUS_IS_OK(status)) {
1701                 d_fprintf(stderr,
1702                           "%s getting streams for %s\n",
1703                           nt_errstr(status),
1704                           name);
1705                 num_streams = 0;
1706         }
1707
1708         for (i=0; i<num_streams; i++) {
1709                 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1710                          (unsigned long long)streams[i].size);
1711         }
1712
1713         if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
1714                 struct reparse_data_buffer *rep = NULL;
1715                 uint8_t *data = NULL;
1716                 uint32_t datalen;
1717                 char *s = NULL;
1718
1719                 rep = talloc_zero(talloc_tos(), struct reparse_data_buffer);
1720                 if (rep == NULL) {
1721                         d_printf("talloc_zero() failed\n");
1722                         return false;
1723                 }
1724
1725                 status = cli_get_reparse_data(cli, name, rep, &data, &datalen);
1726                 if (!NT_STATUS_IS_OK(status)) {
1727                         d_fprintf(stderr,
1728                                   "cli_get_reparse_data() failed: %s\n",
1729                                   nt_errstr(status));
1730                         TALLOC_FREE(rep);
1731                         return false;
1732                 }
1733
1734                 status = reparse_data_buffer_parse(rep, rep, data, datalen);
1735                 if (!NT_STATUS_IS_OK(status)) {
1736                         d_fprintf(stderr,
1737                                   "reparse_data_buffer_parse() failed: %s\n",
1738                                   nt_errstr(status));
1739                         TALLOC_FREE(rep);
1740                         return false;
1741                 }
1742
1743                 s = reparse_data_buffer_str(rep, rep);
1744                 d_printf("%s", s);
1745                 TALLOC_FREE(rep);
1746         }
1747
1748         status = cli_ntcreate(cli, name, 0,
1749                               SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE |
1750                               SEC_STD_SYNCHRONIZE, 0,
1751                               FILE_SHARE_READ|FILE_SHARE_WRITE
1752                               |FILE_SHARE_DELETE,
1753                               FILE_OPEN, 0x0, 0x0, &fnum, NULL);
1754         if (!NT_STATUS_IS_OK(status)) {
1755                 /*
1756                  * Ignore failure, it does not hurt if we can't list
1757                  * snapshots
1758                  */
1759                 return 0;
1760         }
1761         /*
1762          * In order to get shadow copy data over SMB1 we
1763          * must call twice, once with 'get_names = false'
1764          * to get the size, then again with 'get_names = true'
1765          * to get the data or a Windows server fails to return
1766          * valid info. Samba doesn't have this bug. JRA.
1767          */
1768
1769         status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1770                                       false, &snapshots, &num_snapshots);
1771         if (NT_STATUS_IS_OK(status)) {
1772                 status = cli_shadow_copy_data(talloc_tos(),
1773                                               cli,
1774                                               fnum,
1775                                               true,
1776                                               &snapshots,
1777                                               &num_snapshots);
1778         }
1779         if (!NT_STATUS_IS_OK(status)) {
1780                 d_fprintf(stderr,
1781                           "%s getting shadow copy data for %s\n",
1782                           nt_errstr(status),
1783                           name);
1784                 num_snapshots = 0;
1785         }
1786
1787         for (j=0; j<num_snapshots; j++) {
1788                 char *snap_name;
1789
1790                 d_printf("%s\n", snapshots[j]);
1791                 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1792                                             snapshots[j], name);
1793                 status = cli_qpathinfo3(cli, snap_name, &b_time, &a_time,
1794                                         &m_time, &c_time, &size,
1795                                         NULL, NULL);
1796                 if (!NT_STATUS_IS_OK(status)) {
1797                         d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1798                                   snap_name, nt_errstr(status));
1799                         TALLOC_FREE(snap_name);
1800                         continue;
1801                 }
1802                 tmp = unix_timespec_to_nt_time(b_time);
1803                 d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1804                 tmp = unix_timespec_to_nt_time(a_time);
1805                 d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1806                 tmp =unix_timespec_to_nt_time(m_time);
1807                 d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1808                 tmp = unix_timespec_to_nt_time(c_time);
1809                 d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1810                 d_printf("size: %d\n", (int)size);
1811         }
1812
1813         TALLOC_FREE(snapshots);
1814         cli_close(cli, fnum);
1815
1816         return 0;
1817 }
1818
1819 /****************************************************************************
1820  Show all info we can get
1821 ****************************************************************************/
1822
1823 static int cmd_allinfo(void)
1824 {
1825         TALLOC_CTX *ctx = talloc_tos();
1826         char *name;
1827         char *buf;
1828
1829         name = talloc_strdup(ctx, client_get_cur_dir());
1830         if (!name) {
1831                 return 1;
1832         }
1833
1834         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1835                 d_printf("allinfo <file>\n");
1836                 return 1;
1837         }
1838         name = talloc_asprintf_append(name, "%s", buf);
1839         if (!name) {
1840                 return 1;
1841         }
1842         name = client_clean_name(ctx, name);
1843         if (name == NULL) {
1844                 return 1;
1845         }
1846         do_allinfo(name);
1847
1848         return 0;
1849 }
1850
1851 /****************************************************************************
1852  Put a single file.
1853 ****************************************************************************/
1854
1855 static int do_put(const char *rname, const char *lname, bool reput)
1856 {
1857         TALLOC_CTX *ctx = talloc_tos();
1858         uint16_t fnum;
1859         FILE *f;
1860         off_t start = 0;
1861         int rc = 0;
1862         struct timespec tp_start;
1863         struct cli_state *targetcli;
1864         char *targetname = NULL;
1865         struct push_state state;
1866         struct cli_credentials *creds = samba_cmdline_get_creds();
1867         NTSTATUS status;
1868
1869         status = cli_resolve_path(ctx, "",
1870                                   creds,
1871                                 cli, rname, &targetcli, &targetname);
1872         if (!NT_STATUS_IS_OK(status)) {
1873                 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1874                 return 1;
1875         }
1876
1877         clock_gettime_mono(&tp_start);
1878
1879         if (reput) {
1880                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1881                 if (NT_STATUS_IS_OK(status)) {
1882                         if (!NT_STATUS_IS_OK(status = cli_qfileinfo_basic(
1883                                                      targetcli, fnum, NULL,
1884                                                      &start, NULL, NULL,
1885                                                      NULL, NULL, NULL))) {
1886                                 d_printf("getattrib: %s\n", nt_errstr(status));
1887                                 return 1;
1888                         }
1889                 }
1890         } else {
1891                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1892         }
1893
1894         if (!NT_STATUS_IS_OK(status)) {
1895                 d_printf("%s opening remote file %s\n", nt_errstr(status),
1896                          rname);
1897                 return 1;
1898         }
1899
1900         /* allow files to be piped into smbclient
1901            jdblair 24.jun.98
1902
1903            Note that in this case this function will exit(0) rather
1904            than returning. */
1905         if (!strcmp(lname, "-")) {
1906                 f = stdin;
1907                 /* size of file is not known */
1908         } else {
1909                 f = fopen(lname, "r");
1910                 if (f && reput) {
1911                         if (fseek(f, start, SEEK_SET) == -1) {
1912                                 d_printf("Error seeking local file\n");
1913                                 fclose(f);
1914                                 return 1;
1915                         }
1916                 }
1917         }
1918
1919         if (!f) {
1920                 d_printf("Error opening local file %s\n",lname);
1921                 return 1;
1922         }
1923
1924         DEBUG(1,("putting file %s as %s ",lname,
1925                  rname));
1926
1927         setvbuf(f, NULL, _IOFBF, io_bufsize);
1928
1929         state.f = f;
1930         state.nread = 0;
1931
1932         status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
1933                           &state);
1934         if (!NT_STATUS_IS_OK(status)) {
1935                 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1936                 rc = 1;
1937         }
1938
1939         status = cli_close(targetcli, fnum);
1940         if (!NT_STATUS_IS_OK(status)) {
1941                 d_printf("%s closing remote file %s\n", nt_errstr(status),
1942                          rname);
1943                 if (f != stdin) {
1944                         fclose(f);
1945                 }
1946                 return 1;
1947         }
1948
1949         if (f != stdin) {
1950                 fclose(f);
1951         }
1952
1953         {
1954                 struct timespec tp_end;
1955                 int this_time;
1956
1957                 clock_gettime_mono(&tp_end);
1958                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1959                 put_total_time_ms += this_time;
1960                 put_total_size += state.nread;
1961
1962                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1963                          state.nread / (1.024*this_time + 1.0e-4),
1964                          put_total_size / (1.024*put_total_time_ms)));
1965         }
1966
1967         if (f == stdin) {
1968                 cli_shutdown(cli);
1969                 exit(rc);
1970         }
1971
1972         return rc;
1973 }
1974
1975 /****************************************************************************
1976  Put a file.
1977 ****************************************************************************/
1978
1979 static int cmd_put(void)
1980 {
1981         TALLOC_CTX *ctx = talloc_tos();
1982         char *lname;
1983         char *rname;
1984         char *buf;
1985
1986         rname = talloc_strdup(ctx, client_get_cur_dir());
1987         if (!rname) {
1988                 return 1;
1989         }
1990
1991         if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1992                 d_printf("put <filename>\n");
1993                 return 1;
1994         }
1995
1996         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1997                 rname = talloc_asprintf_append(rname, "%s", buf);
1998         } else {
1999                 rname = talloc_asprintf_append(rname, "%s", lname);
2000         }
2001         if (!rname) {
2002                 return 1;
2003         }
2004
2005         rname = client_clean_name(ctx, rname);
2006         if (!rname) {
2007                 return 1;
2008         }
2009
2010         {
2011                 SMB_STRUCT_STAT st;
2012                 /* allow '-' to represent stdin
2013                    jdblair, 24.jun.98 */
2014                 if (!file_exist_stat(lname, &st, false) &&
2015                     (strcmp(lname,"-"))) {
2016                         d_printf("%s does not exist\n",lname);
2017                         return 1;
2018                 }
2019         }
2020
2021         return do_put(rname, lname, false);
2022 }
2023
2024 /*************************************
2025  File list structure.
2026 *************************************/
2027
2028 static struct file_list {
2029         struct file_list *prev, *next;
2030         char *file_path;
2031         bool isdir;
2032 } *file_list;
2033
2034 /****************************************************************************
2035  Free a file_list structure.
2036 ****************************************************************************/
2037
2038 static void free_file_list (struct file_list *l_head)
2039 {
2040         struct file_list *list, *next;
2041
2042         for (list = l_head; list; list = next) {
2043                 next = list->next;
2044                 DLIST_REMOVE(l_head, list);
2045                 TALLOC_FREE(list);
2046         }
2047 }
2048
2049 /****************************************************************************
2050  Seek in a directory/file list until you get something that doesn't start with
2051  the specified name.
2052 ****************************************************************************/
2053
2054 static bool seek_list(struct file_list *list, char *name)
2055 {
2056         while (list) {
2057                 trim_string(list->file_path,"./","\n");
2058                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
2059                         return true;
2060                 }
2061                 list = list->next;
2062         }
2063
2064         return false;
2065 }
2066
2067 /****************************************************************************
2068  Set the file selection mask.
2069 ****************************************************************************/
2070
2071 static int cmd_select(void)
2072 {
2073         TALLOC_CTX *ctx = talloc_tos();
2074         char *new_fs = NULL;
2075         next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
2076                 ;
2077         if (new_fs) {
2078                 client_set_fileselection(new_fs);
2079         } else {
2080                 client_set_fileselection("");
2081         }
2082         return 0;
2083 }
2084
2085 /****************************************************************************
2086   Recursive file matching function act as find
2087   match must be always set to true when calling this function
2088 ****************************************************************************/
2089
2090 static int file_find(TALLOC_CTX *ctx,
2091                         struct file_list **list,
2092                         const char *directory,
2093                         const char *expression,
2094                         bool match)
2095 {
2096         DIR *dir;
2097         struct file_list *entry;
2098         struct stat statbuf;
2099         int ret;
2100         char *path;
2101         bool isdir;
2102         const char *dname;
2103
2104         dir = opendir(directory);
2105         if (!dir)
2106                 return -1;
2107
2108         while ((dname = readdirname(dir))) {
2109                 if (ISDOT(dname) || ISDOTDOT(dname)) {
2110                         continue;
2111                 }
2112
2113                 path = talloc_asprintf(ctx, "%s/%s", directory, dname);
2114                 if (path == NULL) {
2115                         continue;
2116                 }
2117
2118                 isdir = false;
2119                 if (!match || !gen_fnmatch(expression, dname)) {
2120                         if (recurse) {
2121                                 ret = stat(path, &statbuf);
2122                                 if (ret == 0) {
2123                                         if (S_ISDIR(statbuf.st_mode)) {
2124                                                 isdir = true;
2125                                                 ret = file_find(ctx,
2126                                                                 list,
2127                                                                 path,
2128                                                                 expression,
2129                                                                 false);
2130                                         }
2131                                 } else {
2132                                         d_printf("file_find: cannot stat file %s\n", path);
2133                                 }
2134
2135                                 if (ret == -1) {
2136                                         TALLOC_FREE(path);
2137                                         closedir(dir);
2138                                         return -1;
2139                                 }
2140                         }
2141                         entry = talloc_zero(ctx, struct file_list);
2142                         if (!entry) {
2143                                 d_printf("Out of memory in file_find\n");
2144                                 closedir(dir);
2145                                 return -1;
2146                         }
2147                         entry->file_path = talloc_move(entry, &path);
2148                         entry->isdir = isdir;
2149                         DLIST_ADD(*list, entry);
2150                 } else {
2151                         TALLOC_FREE(path);
2152                 }
2153         }
2154
2155         closedir(dir);
2156         return 0;
2157 }
2158
2159 /****************************************************************************
2160  mput some files.
2161 ****************************************************************************/
2162
2163 static int cmd_mput(void)
2164 {
2165         TALLOC_CTX *ctx = talloc_tos();
2166         char *p = NULL;
2167
2168         while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2169                 int ret;
2170                 struct file_list *temp_list;
2171                 char *quest, *lname, *rname;
2172
2173                 file_list = NULL;
2174
2175                 ret = file_find(ctx, &file_list, ".", p, true);
2176                 if (ret) {
2177                         free_file_list(file_list);
2178                         continue;
2179                 }
2180
2181                 quest = NULL;
2182                 lname = NULL;
2183                 rname = NULL;
2184
2185                 for (temp_list = file_list; temp_list;
2186                      temp_list = temp_list->next) {
2187
2188                         SAFE_FREE(lname);
2189                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2190                                 continue;
2191                         }
2192                         trim_string(lname, "./", "/");
2193
2194                         /* check if it's a directory */
2195                         if (temp_list->isdir) {
2196                                 /* if (!recurse) continue; */
2197
2198                                 SAFE_FREE(quest);
2199                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2200                                         break;
2201                                 }
2202                                 if (prompt && !yesno(quest)) { /* No */
2203                                         /* Skip the directory */
2204                                         lname[strlen(lname)-1] = '/';
2205                                         if (!seek_list(temp_list, lname))
2206                                                 break;
2207                                 } else { /* Yes */
2208                                         SAFE_FREE(rname);
2209                                         if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2210                                                 break;
2211                                         }
2212                                         normalize_name(rname);
2213                                         {
2214                                                 char *tmp_rname =
2215                                                         client_clean_name(ctx, rname);
2216                                                 if (tmp_rname == NULL) {
2217                                                         break;
2218                                                 }
2219                                                 SAFE_FREE(rname);
2220                                                 rname = smb_xstrdup(tmp_rname);
2221                                                 TALLOC_FREE(tmp_rname);
2222                                                 if (rname == NULL) {
2223                                                         break;
2224                                                 }
2225                                         }
2226                                         if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2227                                             !do_mkdir(rname)) {
2228                                                 DEBUG (0, ("Unable to make dir, skipping...\n"));
2229                                                 /* Skip the directory */
2230                                                 lname[strlen(lname)-1] = '/';
2231                                                 if (!seek_list(temp_list, lname)) {
2232                                                         break;
2233                                                 }
2234                                         }
2235                                 }
2236                                 continue;
2237                         } else {
2238                                 SAFE_FREE(quest);
2239                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2240                                         break;
2241                                 }
2242                                 if (prompt && !yesno(quest)) {
2243                                         /* No */
2244                                         continue;
2245                                 }
2246
2247                                 /* Yes */
2248                                 SAFE_FREE(rname);
2249                                 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2250                                         break;
2251                                 }
2252                         }
2253
2254                         normalize_name(rname);
2255
2256                         {
2257                                 char *tmp_rname = client_clean_name(ctx, rname);
2258                                 if (tmp_rname == NULL) {
2259                                         break;
2260                                 }
2261                                 SAFE_FREE(rname);
2262                                 rname = smb_xstrdup(tmp_rname);
2263                                 TALLOC_FREE(tmp_rname);
2264                                 if (rname == NULL) {
2265                                         break;
2266                                 }
2267                         }
2268                         do_put(rname, lname, false);
2269                 }
2270                 free_file_list(file_list);
2271                 SAFE_FREE(quest);
2272                 SAFE_FREE(lname);
2273                 SAFE_FREE(rname);
2274         }
2275
2276         return 0;
2277 }
2278
2279 /****************************************************************************
2280  Cancel a print job.
2281 ****************************************************************************/
2282
2283 static int do_cancel(int job)
2284 {
2285         NTSTATUS status = cli_printjob_del(cli, job);
2286
2287         if (NT_STATUS_IS_OK(status)) {
2288                 d_printf("Job %d cancelled\n",job);
2289                 return 0;
2290         } else {
2291                 d_printf("Error cancelling job %d : %s\n",
2292                          job, nt_errstr(status));
2293                 return 1;
2294         }
2295 }
2296
2297 /****************************************************************************
2298  Cancel a print job.
2299 ****************************************************************************/
2300
2301 static int cmd_cancel(void)
2302 {
2303         TALLOC_CTX *ctx = talloc_tos();
2304         char *buf = NULL;
2305         int job;
2306
2307         if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2308                 d_printf("cancel <jobid> ...\n");
2309                 return 1;
2310         }
2311         do {
2312                 job = atoi(buf);
2313                 do_cancel(job);
2314         } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2315
2316         return 0;
2317 }
2318
2319 /****************************************************************************
2320  Print a file.
2321 ****************************************************************************/
2322
2323 static int cmd_print(void)
2324 {
2325         TALLOC_CTX *ctx = talloc_tos();
2326         char *lname = NULL;
2327         char *rname = NULL;
2328         char *p = NULL;
2329
2330         if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2331                 d_printf("print <filename>\n");
2332                 return 1;
2333         }
2334
2335         rname = talloc_strdup(ctx, lname);
2336         if (!rname) {
2337                 return 1;
2338         }
2339         p = strrchr_m(rname,'/');
2340         if (p) {
2341                 rname = talloc_asprintf(ctx,
2342                                         "%s-%d",
2343                                         p+1,
2344                                         (int)getpid());
2345         }
2346         if (strequal(lname,"-")) {
2347                 rname = talloc_asprintf(ctx,
2348                                 "stdin-%d",
2349                                 (int)getpid());
2350         }
2351         if (!rname) {
2352                 return 1;
2353         }
2354
2355         return do_put(rname, lname, false);
2356 }
2357
2358 /****************************************************************************
2359  Show a print queue entry.
2360 ****************************************************************************/
2361
2362 static void queue_fn(struct print_job_info *p)
2363 {
2364         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
2365 }
2366
2367 /****************************************************************************
2368  Show a print queue.
2369 ****************************************************************************/
2370
2371 static int cmd_queue(void)
2372 {
2373         cli_print_queue(cli, queue_fn);
2374         return 0;
2375 }
2376
2377 /****************************************************************************
2378  Delete some files.
2379 ****************************************************************************/
2380
2381 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2382                    const char *dir)
2383 {
2384         TALLOC_CTX *ctx = talloc_tos();
2385         char *mask = NULL;
2386         struct cli_state *targetcli = NULL;
2387         char *targetname = NULL;
2388         struct cli_credentials *creds = samba_cmdline_get_creds();
2389         NTSTATUS status;
2390
2391         mask = talloc_asprintf(ctx,
2392                                 "%s%c%s",
2393                                 dir,
2394                                 CLI_DIRSEP_CHAR,
2395                                 finfo->name);
2396         if (!mask) {
2397                 return NT_STATUS_NO_MEMORY;
2398         }
2399
2400         if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
2401                 TALLOC_FREE(mask);
2402                 return NT_STATUS_OK;
2403         }
2404
2405         status = cli_resolve_path(ctx, "",
2406                                   creds,
2407                                 cli, mask, &targetcli, &targetname);
2408         if (!NT_STATUS_IS_OK(status)) {
2409                 goto out;
2410         }
2411
2412         status = cli_unlink(targetcli, targetname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2413 out:
2414         if (!NT_STATUS_IS_OK(status)) {
2415                 d_printf("%s deleting remote file %s\n",
2416                          nt_errstr(status), mask);
2417         }
2418         TALLOC_FREE(mask);
2419         return status;
2420 }
2421
2422 /****************************************************************************
2423  Delete some files.
2424 ****************************************************************************/
2425
2426 static int cmd_del(void)
2427 {
2428         TALLOC_CTX *ctx = talloc_tos();
2429         char *mask = NULL;
2430         char *buf = NULL;
2431         NTSTATUS status = NT_STATUS_OK;
2432         uint32_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
2433
2434         if (recurse) {
2435                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
2436         }
2437
2438         mask = talloc_strdup(ctx, client_get_cur_dir());
2439         if (!mask) {
2440                 return 1;
2441         }
2442         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2443                 d_printf("del <filename>\n");
2444                 return 1;
2445         }
2446         mask = talloc_asprintf_append(mask, "%s", buf);
2447         if (!mask) {
2448                 return 1;
2449         }
2450         mask = client_clean_name(ctx, mask);
2451         if (mask == NULL) {
2452                 return 1;
2453         }
2454
2455         status = do_list(mask,attribute,do_del,false,false);
2456         if (!NT_STATUS_IS_OK(status)) {
2457                 return 1;
2458         }
2459         return 0;
2460 }
2461
2462 /****************************************************************************
2463  Delete some files.
2464 ****************************************************************************/
2465
2466 static NTSTATUS delete_remote_files_list(struct cli_state *cli_state,
2467                                          struct file_list *flist)
2468 {
2469         NTSTATUS status = NT_STATUS_OK;
2470         struct file_list *deltree_list_iter = NULL;
2471         char *targetname = NULL;
2472         struct cli_state *targetcli = NULL;
2473         struct cli_credentials *creds = samba_cmdline_get_creds();
2474         TALLOC_CTX *ctx = talloc_tos();
2475
2476         for (deltree_list_iter = flist;
2477                         deltree_list_iter != NULL;
2478                         deltree_list_iter = deltree_list_iter->next) {
2479                 status = cli_resolve_path(ctx,
2480                                 "",
2481                                 creds,
2482                                 cli_state,
2483                                 deltree_list_iter->file_path,
2484                                 &targetcli,
2485                                 &targetname);
2486                 if (!NT_STATUS_IS_OK(status)) {
2487                         d_printf("delete_remote_files %s: %s\n",
2488                                 deltree_list_iter->file_path,
2489                                 nt_errstr(status));
2490                         return status;
2491                 }
2492                 if (CLI_DIRSEP_CHAR == '/') {
2493                         /* POSIX. */
2494                         status = cli_posix_unlink(targetcli,
2495                                         targetname);
2496                 } else if (deltree_list_iter->isdir) {
2497                         status = cli_rmdir(targetcli,
2498                                         targetname);
2499                 } else {
2500                         status = cli_unlink(targetcli,
2501                                         targetname,
2502                                         FILE_ATTRIBUTE_SYSTEM |
2503                                         FILE_ATTRIBUTE_HIDDEN);
2504                 }
2505                 if (!NT_STATUS_IS_OK(status)) {
2506                         d_printf("%s deleting remote %s %s\n",
2507                                 nt_errstr(status),
2508                                 deltree_list_iter->isdir ?
2509                                 "directory" : "file",
2510                                 deltree_list_iter->file_path);
2511                         return status;
2512                 }
2513         }
2514         return NT_STATUS_OK;
2515 }
2516
2517 /****************************************************************************
2518  Save a list of files to delete.
2519 ****************************************************************************/
2520
2521 static struct file_list *deltree_list_head;
2522
2523 static NTSTATUS do_deltree_list(struct cli_state *cli_state,
2524                                 struct file_info *finfo,
2525                                 const char *dir)
2526 {
2527         struct file_list **file_list_head_pp = &deltree_list_head;
2528         struct file_list *dt = NULL;
2529
2530         if (!do_this_one(finfo)) {
2531                 return NT_STATUS_OK;
2532         }
2533
2534         /* skip if this is . or .. */
2535         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2536                 return NT_STATUS_OK;
2537         }
2538
2539         dt = talloc_zero(NULL, struct file_list);
2540         if (dt == NULL) {
2541                 return NT_STATUS_NO_MEMORY;
2542         }
2543
2544         /* create absolute filename for cli_ntcreate() */
2545         dt->file_path = talloc_asprintf(dt,
2546                                         "%s%s%s",
2547                                         dir,
2548                                         CLI_DIRSEP_STR,
2549                                         finfo->name);
2550         if (dt->file_path == NULL) {
2551                 TALLOC_FREE(dt);
2552                 return NT_STATUS_NO_MEMORY;
2553         }
2554
2555         if (finfo->attr & FILE_ATTRIBUTE_DIRECTORY) {
2556                 dt->isdir = true;
2557         }
2558
2559         DLIST_ADD(*file_list_head_pp, dt);
2560         return NT_STATUS_OK;
2561 }
2562
2563 static int cmd_deltree(void)
2564 {
2565         TALLOC_CTX *ctx = talloc_tos();
2566         char *buf = NULL;
2567         NTSTATUS status = NT_STATUS_OK;
2568         struct file_list *deltree_list_norecurse = NULL;
2569         struct file_list *deltree_list_iter = NULL;
2570         uint32_t attribute = FILE_ATTRIBUTE_SYSTEM |
2571                              FILE_ATTRIBUTE_HIDDEN |
2572                              FILE_ATTRIBUTE_DIRECTORY;
2573         bool ok;
2574         char *mask = talloc_strdup(ctx, client_get_cur_dir());
2575         if (mask == NULL) {
2576                 return 1;
2577         }
2578         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
2579         if (!ok) {
2580                 d_printf("deltree <filename>\n");
2581                 return 1;
2582         }
2583         mask = talloc_asprintf_append(mask, "%s", buf);
2584         if (mask == NULL) {
2585                 return 1;
2586         }
2587         mask = client_clean_name(ctx, mask);
2588         if (mask == NULL) {
2589                 return 1;
2590         }
2591
2592         deltree_list_head = NULL;
2593
2594         /*
2595          * Get the list of directories to
2596          * delete (in case mask has a wildcard).
2597          */
2598         status = do_list(mask, attribute, do_deltree_list, false, true);
2599         if (!NT_STATUS_IS_OK(status)) {
2600                 goto err;
2601         }
2602         deltree_list_norecurse = deltree_list_head;
2603         deltree_list_head = NULL;
2604
2605         for (deltree_list_iter = deltree_list_norecurse;
2606              deltree_list_iter != NULL;
2607              deltree_list_iter = deltree_list_iter->next) {
2608
2609                 if (deltree_list_iter->isdir == false) {
2610                         char *targetname = NULL;
2611                         struct cli_state *targetcli = NULL;
2612                         struct cli_credentials *creds = samba_cmdline_get_creds();
2613                         status = cli_resolve_path(ctx,
2614                                                 "",
2615                                                 creds,
2616                                                 cli,
2617                                                 deltree_list_iter->file_path,
2618                                                 &targetcli,
2619                                                 &targetname);
2620                         if (!NT_STATUS_IS_OK(status)) {
2621                                 goto err;
2622                         }
2623                         /* Just a regular file. */
2624                         if (CLI_DIRSEP_CHAR == '/') {
2625                                 /* POSIX. */
2626                                 status = cli_posix_unlink(targetcli,
2627                                         targetname);
2628                         } else {
2629                                 status = cli_unlink(targetcli,
2630                                         targetname,
2631                                         FILE_ATTRIBUTE_SYSTEM |
2632                                         FILE_ATTRIBUTE_HIDDEN);
2633                         }
2634                         if (!NT_STATUS_IS_OK(status)) {
2635                                 goto err;
2636                         }
2637                         continue;
2638                 }
2639
2640                 /*
2641                  * Get the list of files or directories to
2642                  * delete in depth order.
2643                  */
2644                 status = do_list(deltree_list_iter->file_path,
2645                                  attribute,
2646                                  do_deltree_list,
2647                                  true,
2648                                  true);
2649                 if (!NT_STATUS_IS_OK(status)) {
2650                         goto err;
2651                 }
2652                 status = delete_remote_files_list(cli, deltree_list_head);
2653                 free_file_list(deltree_list_head);
2654                 deltree_list_head = NULL;
2655                 if (!NT_STATUS_IS_OK(status)) {
2656                         goto err;
2657                 }
2658         }
2659
2660         free_file_list(deltree_list_norecurse);
2661         free_file_list(deltree_list_head);
2662         return 0;
2663
2664   err:
2665
2666         free_file_list(deltree_list_norecurse);
2667         free_file_list(deltree_list_head);
2668         deltree_list_head = NULL;
2669         return 1;
2670 }
2671
2672
2673 /****************************************************************************
2674  Wildcard delete some files.
2675 ****************************************************************************/
2676
2677 static int cmd_wdel(void)
2678 {
2679         TALLOC_CTX *ctx = talloc_tos();
2680         char *mask = NULL;
2681         char *buf = NULL;
2682         uint32_t attribute;
2683         struct cli_state *targetcli;
2684         char *targetname = NULL;
2685         struct cli_credentials *creds = samba_cmdline_get_creds();
2686         NTSTATUS status;
2687
2688         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2689                 d_printf("wdel 0x<attrib> <wcard>\n");
2690                 return 1;
2691         }
2692
2693         attribute = (uint32_t)strtol(buf, (char **)NULL, 16);
2694
2695         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2696                 d_printf("wdel 0x<attrib> <wcard>\n");
2697                 return 1;
2698         }
2699
2700         mask = talloc_asprintf(ctx, "%s%s",
2701                         client_get_cur_dir(),
2702                         buf);
2703         if (!mask) {
2704                 return 1;
2705         }
2706         mask = client_clean_name(ctx, mask);
2707         if (mask == NULL) {
2708                 return 1;
2709         }
2710
2711         status = cli_resolve_path(ctx, "",
2712                                   creds,
2713                                 cli, mask, &targetcli, &targetname);
2714         if (!NT_STATUS_IS_OK(status)) {
2715                 d_printf("cmd_wdel %s: %s\n", mask, nt_errstr(status));
2716                 return 1;
2717         }
2718
2719         status = cli_unlink(targetcli, targetname, attribute);
2720         if (!NT_STATUS_IS_OK(status)) {
2721                 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2722                          targetname);
2723         }
2724         return 0;
2725 }
2726
2727 /****************************************************************************
2728 ****************************************************************************/
2729
2730 static int cmd_open(void)
2731 {
2732         TALLOC_CTX *ctx = talloc_tos();
2733         char *mask = NULL;
2734         char *buf = NULL;
2735         char *targetname = NULL;
2736         struct cli_state *targetcli;
2737         uint16_t fnum = (uint16_t)-1;
2738         struct cli_credentials *creds = samba_cmdline_get_creds();
2739         NTSTATUS status;
2740
2741         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2742                 d_printf("open <filename>\n");
2743                 return 1;
2744         }
2745         mask = talloc_asprintf(ctx,
2746                         "%s%s",
2747                         client_get_cur_dir(),
2748                         buf);
2749         if (!mask) {
2750                 return 1;
2751         }
2752
2753         mask = client_clean_name(ctx, mask);
2754         if (mask == NULL) {
2755                 return 1;
2756         }
2757
2758         status = cli_resolve_path(ctx, "",
2759                                   creds,
2760                         cli, mask, &targetcli, &targetname);
2761         if (!NT_STATUS_IS_OK(status)) {
2762                 d_printf("open %s: %s\n", mask, nt_errstr(status));
2763                 return 1;
2764         }
2765
2766         status = cli_ntcreate(targetcli, targetname, 0,
2767                         FILE_READ_DATA|FILE_WRITE_DATA, 0,
2768                         FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2769                         0x0, 0x0, &fnum, NULL);
2770         if (!NT_STATUS_IS_OK(status)) {
2771                 status = cli_ntcreate(targetcli, targetname, 0,
2772                                 FILE_READ_DATA, 0,
2773                                 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2774                                 0x0, 0x0, &fnum, NULL);
2775                 if (NT_STATUS_IS_OK(status)) {
2776                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2777                 } else {
2778                         d_printf("Failed to open file %s. %s\n",
2779                                  targetname, nt_errstr(status));
2780                 }
2781         } else {
2782                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2783         }
2784         return 0;
2785 }
2786
2787 static int cmd_posix_encrypt(void)
2788 {
2789         TALLOC_CTX *ctx = talloc_tos();
2790         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2791         char *domain = NULL;
2792         char *user = NULL;
2793         char *password = NULL;
2794         struct cli_credentials *creds = NULL;
2795         struct cli_credentials *lcreds = NULL;
2796
2797         if (next_token_talloc(ctx, &cmd_ptr, &domain, NULL)) {
2798
2799                 if (!next_token_talloc(ctx, &cmd_ptr, &user, NULL)) {
2800                         d_printf("posix_encrypt domain user password\n");
2801                         return 1;
2802                 }
2803
2804                 if (!next_token_talloc(ctx, &cmd_ptr, &password, NULL)) {
2805                         d_printf("posix_encrypt domain user password\n");
2806                         return 1;
2807                 }
2808
2809                 lcreds = cli_session_creds_init(ctx,
2810                                                 user,
2811                                                 domain,
2812                                                 NULL, /* realm */
2813                                                 password,
2814                                                 false, /* use_kerberos */
2815                                                 false, /* fallback_after_kerberos */
2816                                                 false, /* use_ccache */
2817                                                 false); /* password_is_nt_hash */
2818                 if (lcreds == NULL) {
2819                         d_printf("cli_session_creds_init() failed.\n");
2820                         return -1;
2821                 }
2822                 creds = lcreds;
2823         } else {
2824                 bool auth_requested = false;
2825
2826                 creds = samba_cmdline_get_creds();
2827
2828                 auth_requested = cli_credentials_authentication_requested(creds);
2829                 if (!auth_requested) {
2830                         d_printf("posix_encrypt domain user password\n");
2831                         return 1;
2832                 }
2833         }
2834
2835         status = cli_smb1_setup_encryption(cli, creds);
2836         /* gensec currently references the creds so we can't free them here */
2837         talloc_unlink(ctx, lcreds);
2838         if (!NT_STATUS_IS_OK(status)) {
2839                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2840         } else {
2841                 bool ok;
2842
2843                 d_printf("encryption on\n");
2844                 ok = cli_credentials_set_smb_encryption(creds,
2845                                                         SMB_ENCRYPTION_REQUIRED,
2846                                                         CRED_SPECIFIED);
2847                 SMB_ASSERT(ok);
2848         }
2849
2850         return 0;
2851 }
2852
2853 /****************************************************************************
2854 ****************************************************************************/
2855
2856 static int cmd_posix_open(void)
2857 {
2858         TALLOC_CTX *ctx = talloc_tos();
2859         char *mask = NULL;
2860         char *buf = NULL;
2861         char *targetname = NULL;
2862         struct cli_state *targetcli;
2863         mode_t mode;
2864         uint16_t fnum;
2865         struct cli_credentials *creds = samba_cmdline_get_creds();
2866         NTSTATUS status;
2867
2868         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2869                 d_printf("posix_open <filename> 0<mode>\n");
2870                 return 1;
2871         }
2872         mask = talloc_asprintf(ctx,
2873                         "%s%s",
2874                         client_get_cur_dir(),
2875                         buf);
2876         if (!mask) {
2877                 return 1;
2878         }
2879         mask = client_clean_name(ctx, mask);
2880         if (mask == NULL) {
2881                 return 1;
2882         }
2883
2884         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2885                 d_printf("posix_open <filename> 0<mode>\n");
2886                 return 1;
2887         }
2888         if (CLI_DIRSEP_CHAR != '/') {
2889                 d_printf("Command \"posix\" must be issued before "
2890                         "the \"posix_open\" command can be used.\n");
2891                 return 1;
2892         }
2893         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2894
2895         status = cli_resolve_path(ctx, "",
2896                                   creds,
2897                                 cli, mask, &targetcli, &targetname);
2898         if (!NT_STATUS_IS_OK(status)) {
2899                 d_printf("posix_open %s: %s\n", mask, nt_errstr(status));
2900                 return 1;
2901         }
2902
2903         status = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode,
2904                                 &fnum);
2905         if (!NT_STATUS_IS_OK(status)) {
2906                 status = cli_posix_open(targetcli, targetname,
2907                                         O_CREAT|O_RDONLY, mode, &fnum);
2908                 if (!NT_STATUS_IS_OK(status)) {
2909                         d_printf("Failed to open file %s. %s\n", targetname,
2910                                  nt_errstr(status));
2911                 } else {
2912                         d_printf("posix_open file %s: for readonly fnum %d\n",
2913                                  targetname, fnum);
2914                 }
2915         } else {
2916                 d_printf("posix_open file %s: for read/write fnum %d\n",
2917                          targetname, fnum);
2918         }
2919
2920         return 0;
2921 }
2922
2923 static int cmd_posix_mkdir(void)
2924 {
2925         TALLOC_CTX *ctx = talloc_tos();
2926         char *mask = NULL;
2927         char *buf = NULL;
2928         char *targetname = NULL;
2929         struct cli_state *targetcli;
2930         mode_t mode;
2931         struct cli_credentials *creds = samba_cmdline_get_creds();
2932         NTSTATUS status;
2933
2934         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2935                 d_printf("posix_mkdir <filename> 0<mode>\n");
2936                 return 1;
2937         }
2938         mask = talloc_asprintf(ctx,
2939                         "%s%s",
2940                         client_get_cur_dir(),
2941                         buf);
2942         if (!mask) {
2943                 return 1;
2944         }
2945         mask = client_clean_name(ctx, mask);
2946         if (mask == NULL) {
2947                 return 1;
2948         }
2949
2950         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2951                 d_printf("posix_mkdir <filename> 0<mode>\n");
2952                 return 1;
2953         }
2954         if (CLI_DIRSEP_CHAR != '/') {
2955                 d_printf("Command \"posix\" must be issued before "
2956                         "the \"posix_mkdir\" command can be used.\n");
2957                 return 1;
2958         }
2959         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2960
2961         status = cli_resolve_path(ctx, "",
2962                                   creds,
2963                                 cli, mask, &targetcli, &targetname);
2964         if (!NT_STATUS_IS_OK(status)) {
2965                 d_printf("posix_mkdir %s: %s\n", mask, nt_errstr(status));
2966                 return 1;
2967         }
2968
2969         status = cli_posix_mkdir(targetcli, targetname, mode);
2970         if (!NT_STATUS_IS_OK(status)) {
2971                 d_printf("Failed to open file %s. %s\n",
2972                          targetname, nt_errstr(status));
2973         } else {
2974                 d_printf("posix_mkdir created directory %s\n", targetname);
2975         }
2976         return 0;
2977 }
2978
2979 static int cmd_posix_unlink(void)
2980 {
2981         TALLOC_CTX *ctx = talloc_tos();
2982         char *mask = NULL;
2983         char *buf = NULL;
2984         char *targetname = NULL;
2985         struct cli_state *targetcli;
2986         struct cli_credentials *creds = samba_cmdline_get_creds();
2987         NTSTATUS status;
2988
2989         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2990                 d_printf("posix_unlink <filename>\n");
2991                 return 1;
2992         }
2993         if (CLI_DIRSEP_CHAR != '/') {
2994                 d_printf("Command \"posix\" must be issued before "
2995                         "the \"posix_unlink\" command can be used.\n");
2996                 return 1;
2997         }
2998         mask = talloc_asprintf(ctx,
2999                         "%s%s",
3000                         client_get_cur_dir(),
3001                         buf);
3002         if (!mask) {
3003                 return 1;
3004         }
3005         mask = client_clean_name(ctx, mask);
3006         if (mask == NULL) {
3007                 return 1;
3008         }
3009
3010         status = cli_resolve_path(ctx, "",
3011                                   creds,
3012                                 cli, mask, &targetcli, &targetname);
3013         if (!NT_STATUS_IS_OK(status)) {
3014                 d_printf("posix_unlink %s: %s\n", mask, nt_errstr(status));
3015                 return 1;
3016         }
3017
3018         status = cli_posix_unlink(targetcli, targetname);
3019         if (!NT_STATUS_IS_OK(status)) {
3020                 d_printf("Failed to unlink file %s. %s\n",
3021                          targetname, nt_errstr(status));
3022         } else {
3023                 d_printf("posix_unlink deleted file %s\n", targetname);
3024         }
3025
3026         return 0;
3027 }
3028
3029 static int cmd_posix_rmdir(void)
3030 {
3031         TALLOC_CTX *ctx = talloc_tos();
3032         char *mask = NULL;
3033         char *buf = NULL;
3034         char *targetname = NULL;
3035         struct cli_state *targetcli;
3036         struct cli_credentials *creds = samba_cmdline_get_creds();
3037         NTSTATUS status;
3038
3039         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3040                 d_printf("posix_rmdir <filename>\n");
3041                 return 1;
3042         }
3043         if (CLI_DIRSEP_CHAR != '/') {
3044                 d_printf("Command \"posix\" must be issued before "
3045                         "the \"posix_rmdir\" command can be used.\n");
3046                 return 1;
3047         }
3048         mask = talloc_asprintf(ctx,
3049                         "%s%s",
3050                         client_get_cur_dir(),
3051                         buf);
3052         if (!mask) {
3053                 return 1;
3054         }
3055         mask = client_clean_name(ctx, mask);
3056         if (mask == NULL) {
3057                 return 1;
3058         }
3059
3060         status = cli_resolve_path(ctx, "",
3061                                   creds,
3062                         cli, mask, &targetcli, &targetname);
3063         if (!NT_STATUS_IS_OK(status)) {
3064                 d_printf("posix_rmdir %s: %s\n", mask, nt_errstr(status));
3065                 return 1;
3066         }
3067
3068         status = cli_posix_rmdir(targetcli, targetname);
3069         if (!NT_STATUS_IS_OK(status)) {
3070                 d_printf("Failed to unlink directory %s. %s\n",
3071                          targetname, nt_errstr(status));
3072         } else {
3073                 d_printf("posix_rmdir deleted directory %s\n", targetname);
3074         }
3075
3076         return 0;
3077 }
3078
3079 static int cmd_mkfifo(void)
3080 {
3081         TALLOC_CTX *ctx = talloc_tos();
3082         char *mask = NULL;
3083         char *buf = NULL;
3084         char *targetname = NULL;
3085         struct cli_state *targetcli;
3086         mode_t mode;
3087         struct cli_credentials *creds = samba_cmdline_get_creds();
3088         NTSTATUS status;
3089
3090         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3091                 d_printf("mkfifo <filename> 0<mode>\n");
3092                 return 1;
3093         }
3094         mask = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(), buf);
3095         if (!mask) {
3096                 return 1;
3097         }
3098         mask = client_clean_name(ctx, mask);
3099         if (mask == NULL) {
3100                 return 1;
3101         }
3102
3103         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3104                 d_printf("mkfifo <filename> 0<mode>\n");
3105                 return 1;
3106         }
3107
3108         mode = (mode_t)strtol(buf, (char **)NULL, 8);
3109         if ((mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) != 0) {
3110                 d_printf("mode %o can only contain permission bits\n", mode);
3111                 return 1;
3112         }
3113
3114         status = cli_resolve_path(ctx,
3115                                   "",
3116                                   creds,
3117                                   cli,
3118                                   mask,
3119                                   &targetcli,
3120                                   &targetname);
3121         if (!NT_STATUS_IS_OK(status)) {
3122                 d_printf("mkfifo %s: %s\n", mask, nt_errstr(status));
3123                 return 1;
3124         }
3125
3126         status = cli_mknod(targetcli, targetname, mode | S_IFIFO, 0);
3127         if (!NT_STATUS_IS_OK(status)) {
3128                 d_printf("Failed to open file %s. %s\n",
3129                          targetname,
3130                          nt_errstr(status));
3131         } else {
3132                 d_printf("mkfifo created %s\n", targetname);
3133         }
3134         return 0;
3135 }
3136
3137 static int cmd_close(void)
3138 {
3139         TALLOC_CTX *ctx = talloc_tos();
3140         char *buf = NULL;
3141         int fnum;
3142         NTSTATUS status;
3143
3144         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3145                 d_printf("close <fnum>\n");
3146                 return 1;
3147         }
3148
3149         fnum = atoi(buf);
3150         /* We really should use the targetcli here.... */
3151         status = cli_close(cli, fnum);
3152         if (!NT_STATUS_IS_OK(status)) {
3153                 d_printf("close %d: %s\n", fnum, nt_errstr(status));
3154                 return 1;
3155         }
3156         return 0;
3157 }
3158
3159 static int cmd_posix(void)
3160 {
3161         TALLOC_CTX *ctx = talloc_tos();
3162         uint16_t major, minor;
3163         uint32_t caplow, caphigh;
3164         char *caps;
3165         NTSTATUS status;
3166
3167         if (!smbXcli_conn_have_posix(cli->conn)) {
3168                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
3169                 return 1;
3170         }
3171
3172         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB3_11) {
3173                 cli->smb2.client_smb311_posix = true;
3174                 return 0;
3175         }
3176
3177         status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
3178                                              &caphigh);
3179         if (!NT_STATUS_IS_OK(status)) {
3180                 d_printf("Can't get UNIX CIFS extensions version from "
3181                          "server: %s\n", nt_errstr(status));
3182                 return 1;
3183         }
3184
3185         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
3186
3187         caps = talloc_strdup(ctx, "");
3188         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
3189                 talloc_asprintf_addbuf(&caps, "locks ");
3190         }
3191         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
3192                 talloc_asprintf_addbuf(&caps, "acls ");
3193         }
3194         if (caplow & CIFS_UNIX_XATTTR_CAP) {
3195                 talloc_asprintf_addbuf(&caps, "eas ");
3196         }
3197         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3198                 talloc_asprintf_addbuf(&caps, "pathnames ");
3199         }
3200         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
3201                 talloc_asprintf_addbuf(&caps, "posix_path_operations ");
3202         }
3203         if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
3204                 talloc_asprintf_addbuf(&caps, "large_read ");
3205         }
3206         if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
3207                 talloc_asprintf_addbuf(&caps, "large_write ");
3208         }
3209         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
3210                 talloc_asprintf_addbuf(&caps, "posix_encrypt ");
3211         }
3212         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
3213                 talloc_asprintf_addbuf(&caps, "mandatory_posix_encrypt ");
3214         }
3215
3216         if (caps == NULL) {
3217                 return 1;
3218         }
3219
3220         if (*caps && caps[strlen(caps)-1] == ' ') {
3221                 caps[strlen(caps)-1] = '\0';
3222         }
3223
3224         d_printf("Server supports CIFS capabilities %s\n", caps);
3225
3226         status = cli_set_unix_extensions_capabilities(cli, major, minor,
3227                                                       caplow, caphigh);
3228         if (!NT_STATUS_IS_OK(status)) {
3229                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
3230                          nt_errstr(status));
3231                 return 1;
3232         }
3233
3234         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3235                 CLI_DIRSEP_CHAR = '/';
3236                 *CLI_DIRSEP_STR = '/';
3237                 client_set_cur_dir(CLI_DIRSEP_STR);
3238         }
3239
3240         return 0;
3241 }
3242
3243 static int cmd_lock(void)
3244 {
3245         TALLOC_CTX *ctx = talloc_tos();
3246         char *buf = NULL;
3247         uint64_t start, len;
3248         enum brl_type lock_type;
3249         int fnum;
3250         NTSTATUS status;
3251
3252         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3253                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3254                 return 1;
3255         }
3256         fnum = atoi(buf);
3257
3258         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3259                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3260                 return 1;
3261         }
3262
3263         if (*buf == 'r' || *buf == 'R') {
3264                 lock_type = READ_LOCK;
3265         } else if (*buf == 'w' || *buf == 'W') {
3266                 lock_type = WRITE_LOCK;
3267         } else {
3268                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3269                 return 1;
3270         }
3271
3272         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3273                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3274                 return 1;
3275         }
3276
3277         start = (uint64_t)strtol(buf, (char **)NULL, 16);
3278
3279         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3280                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3281                 return 1;
3282         }
3283
3284         if (CLI_DIRSEP_CHAR != '/') {
3285                 d_printf("Command \"posix\" must be issued before "
3286                         "the \"lock\" command can be used.\n");
3287                 return 1;
3288         }
3289
3290         len = (uint64_t)strtol(buf, (char **)NULL, 16);
3291
3292         status = cli_posix_lock(cli, fnum, start, len, true, lock_type);
3293         if (!NT_STATUS_IS_OK(status)) {
3294                 d_printf("lock failed %d: %s\n", fnum, nt_errstr(status));
3295         }
3296
3297         return 0;
3298 }
3299
3300 static int cmd_unlock(void)
3301 {
3302         TALLOC_CTX *ctx = talloc_tos();
3303         char *buf = NULL;
3304         uint64_t start, len;
3305         int fnum;
3306         NTSTATUS status;
3307
3308         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3309                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3310                 return 1;
3311         }
3312         fnum = atoi(buf);
3313
3314         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3315                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3316                 return 1;
3317         }
3318
3319         start = (uint64_t)strtol(buf, (char **)NULL, 16);
3320
3321         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3322                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3323                 return 1;
3324         }
3325
3326         if (CLI_DIRSEP_CHAR != '/') {
3327                 d_printf("Command \"posix\" must be issued before "
3328                         "the \"unlock\" command can be used.\n");
3329                 return 1;
3330         }
3331
3332         len = (uint64_t)strtol(buf, (char **)NULL, 16);
3333
3334         status = cli_posix_unlock(cli, fnum, start, len);
3335         if (!NT_STATUS_IS_OK(status)) {
3336                 d_printf("unlock failed %d: %s\n", fnum, nt_errstr(status));
3337         }
3338
3339         return 0;
3340 }
3341
3342 static int cmd_posix_whoami(void)
3343 {
3344         TALLOC_CTX *ctx = talloc_tos();
3345         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3346         uint64_t uid = 0;
3347         uint64_t gid = 0;
3348         uint32_t num_gids = 0;
3349         uint32_t num_sids = 0;
3350         uint64_t *gids = NULL;
3351         struct dom_sid *sids = NULL;
3352         bool guest = false;
3353         uint32_t i;
3354
3355         if (CLI_DIRSEP_CHAR != '/') {
3356                 d_printf("Command \"posix\" must be issued before "
3357                         "the \"posix_whoami\" command can be used.\n");
3358                 return 1;
3359         }
3360
3361         status = cli_posix_whoami(cli,
3362                         ctx,
3363                         &uid,
3364                         &gid,
3365                         &num_gids,
3366                         &gids,
3367                         &num_sids,
3368                         &sids,
3369                         &guest);
3370
3371         if (!NT_STATUS_IS_OK(status)) {
3372                 d_printf("posix_whoami failed with error %s\n", nt_errstr(status));
3373                 return 1;
3374         }
3375
3376         d_printf("GUEST:%s\n", guest ? "True" : "False");
3377         d_printf("UID:%" PRIu64 "\n", uid);
3378         d_printf("GID:%" PRIu64 "\n", gid);
3379         d_printf("NUM_GIDS:%" PRIu32 "\n", num_gids);
3380         for (i = 0; i < num_gids; i++) {
3381                 d_printf("GIDS[%" PRIu32 "]:%" PRIu64 "\n", i, gids[i]);
3382         }
3383         d_printf("NUM_SIDS:%" PRIu32 "\n", num_sids);
3384         for (i = 0; i < num_sids; i++) {
3385                 struct dom_sid_buf buf;
3386                 d_printf("SIDS[%" PRIu32 "]:%s\n",
3387                          i,
3388                          dom_sid_str_buf(&sids[i], &buf));
3389         }
3390         return 0;
3391 }
3392
3393
3394 /****************************************************************************
3395  Remove a directory.
3396 ****************************************************************************/
3397
3398 static int cmd_rmdir(void)
3399 {
3400         TALLOC_CTX *ctx = talloc_tos();
3401         char *mask = NULL;
3402         char *buf = NULL;
3403         char *targetname = NULL;
3404         struct cli_state *targetcli;
3405         struct cli_credentials *creds = samba_cmdline_get_creds();
3406         NTSTATUS status;
3407
3408         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3409                 d_printf("rmdir <dirname>\n");
3410                 return 1;
3411         }
3412         mask = talloc_asprintf(ctx,
3413                         "%s%s",
3414                         client_get_cur_dir(),
3415                         buf);
3416         if (!mask) {
3417                 return 1;
3418         }
3419         mask = client_clean_name(ctx, mask);
3420         if (mask == NULL) {
3421                 return 1;
3422         }
3423
3424         status = cli_resolve_path(ctx, "",
3425                                   creds,
3426                         cli, mask, &targetcli, &targetname);
3427         if (!NT_STATUS_IS_OK(status)) {
3428                 d_printf("rmdir %s: %s\n", mask, nt_errstr(status));
3429                 return 1;
3430         }
3431
3432         status = cli_rmdir(targetcli, targetname);
3433         if (!NT_STATUS_IS_OK(status)) {
3434                 d_printf("%s removing remote directory file %s\n",
3435                          nt_errstr(status), mask);
3436         }
3437
3438         return 0;
3439 }
3440
3441 /****************************************************************************
3442  UNIX hardlink.
3443 ****************************************************************************/
3444
3445 static int cmd_link(void)
3446 {
3447         TALLOC_CTX *ctx = talloc_tos();
3448         char *oldname = NULL;
3449         char *newname = NULL;
3450         char *buf = NULL;
3451         char *buf2 = NULL;
3452         char *targetname = NULL;
3453         struct cli_state *targetcli;
3454         struct cli_credentials *creds = samba_cmdline_get_creds();
3455         NTSTATUS status;
3456
3457         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3458             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3459                 d_printf("link <oldname> <newname>\n");
3460                 return 1;
3461         }
3462         oldname = talloc_asprintf(ctx,
3463                         "%s%s",
3464                         client_get_cur_dir(),
3465                         buf);
3466         if (!oldname) {
3467                 return 1;
3468         }
3469         oldname = client_clean_name(ctx, oldname);
3470         if (oldname == NULL) {
3471                 return 1;
3472         }
3473         newname = talloc_asprintf(ctx,
3474                         "%s%s",
3475                         client_get_cur_dir(),
3476                         buf2);
3477         if (!newname) {
3478                 return 1;
3479         }
3480         newname = client_clean_name(ctx, newname);
3481         if (newname == NULL) {
3482                 return 1;
3483         }
3484
3485         status = cli_resolve_path(ctx, "",
3486                                   creds,
3487                         cli, oldname, &targetcli, &targetname);
3488         if (!NT_STATUS_IS_OK(status)) {
3489                 d_printf("link %s: %s\n", oldname, nt_errstr(status));
3490                 return 1;
3491         }
3492
3493         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3494                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3495                 return 1;
3496         }
3497
3498         if (CLI_DIRSEP_CHAR != '/') {
3499                 d_printf("Command \"posix\" must be issued before "
3500                          "the \"link\" command can be used.\n");
3501                 return 1;
3502         }
3503
3504         status = cli_posix_hardlink(targetcli, targetname, newname);
3505         if (!NT_STATUS_IS_OK(status)) {
3506                 d_printf("%s linking files (%s -> %s)\n",
3507                          nt_errstr(status), newname, oldname);
3508                 return 1;
3509         }
3510         return 0;
3511 }
3512
3513 /****************************************************************************
3514  UNIX readlink.
3515 ****************************************************************************/
3516
3517 static int cmd_readlink(void)
3518 {
3519         TALLOC_CTX *ctx = talloc_tos();
3520         char *name= NULL;
3521         char *buf = NULL;
3522         char *targetname = NULL;
3523         char *linkname = NULL;
3524         char *printname = NULL;
3525         uint32_t flags;
3526         struct cli_state *targetcli;
3527         struct cli_credentials *creds = samba_cmdline_get_creds();
3528         NTSTATUS status;
3529
3530         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3531                 d_printf("readlink <name>\n");
3532                 return 1;
3533         }
3534         name = talloc_asprintf(ctx,
3535                         "%s%s",
3536                         client_get_cur_dir(),
3537                         buf);
3538         if (!name) {
3539                 return 1;
3540         }
3541         name = client_clean_name(ctx, name);
3542         if (name == NULL) {
3543                 return 1;
3544         }
3545
3546         status = cli_resolve_path(ctx, "",
3547                                   creds,
3548                         cli, name, &targetcli, &targetname);
3549         if (!NT_STATUS_IS_OK(status)) {
3550                 d_printf("readlink %s: %s\n", name, nt_errstr(status));
3551                 return 1;
3552         }
3553
3554         status = cli_readlink(
3555                 cli, name, talloc_tos(), &linkname, &printname, &flags);
3556         if (!NT_STATUS_IS_OK(status)) {
3557                 d_printf("%s readlink on file %s\n",
3558                          nt_errstr(status), name);
3559                 return 1;
3560         }
3561
3562         d_printf("%s -> %s\n", name, linkname);
3563
3564         TALLOC_FREE(linkname);
3565
3566         return 0;
3567 }
3568
3569
3570 /****************************************************************************
3571  UNIX symlink.
3572 ****************************************************************************/
3573
3574 static int cmd_symlink(void)
3575 {
3576         TALLOC_CTX *ctx = talloc_tos();
3577         char *link_target = NULL;
3578         char *newname = NULL;
3579         char *buf = NULL;
3580         char *buf2 = NULL;
3581         struct cli_state *newcli;
3582         struct cli_credentials *creds = samba_cmdline_get_creds();
3583         NTSTATUS status;
3584
3585         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3586             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3587                 d_printf("symlink <link_target> <newname>\n");
3588                 return 1;
3589         }
3590         /* Oldname (link target) must be an untouched blob. */
3591         link_target = buf;
3592
3593         if (SERVER_HAS_UNIX_CIFS(cli)) {
3594                 if (CLI_DIRSEP_CHAR != '/') {
3595                         d_printf("Command \"posix\" must be issued before "
3596                                 "the \"symlink\" command can be used.\n");
3597                         return 1;
3598                 }
3599                 newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
3600                                           buf2);
3601                 if (!newname) {
3602                         return 1;
3603                 }
3604                 newname = client_clean_name(ctx, newname);
3605                 if (newname == NULL) {
3606                         return 1;
3607                 }
3608                 /* New name must be present in share namespace. */
3609                 status = cli_resolve_path(ctx, "",
3610                                           creds,
3611                                           cli, newname,
3612                                 &newcli, &newname);
3613                 if (!NT_STATUS_IS_OK(status)) {
3614                         d_printf("link %s: %s\n", newname,
3615                                 nt_errstr(status));
3616                         return 1;
3617                 }
3618                 status = cli_posix_symlink(newcli, link_target, newname);
3619         } else {
3620                 status = cli_symlink(
3621                         cli, link_target, buf2,
3622                         buf2[0] == '\\' ? 0 : SYMLINK_FLAG_RELATIVE);
3623         }
3624
3625         if (!NT_STATUS_IS_OK(status)) {
3626                 d_printf("%s symlinking files (%s -> %s)\n",
3627                          nt_errstr(status), newname, link_target);
3628                 return 1;
3629         }
3630
3631         return 0;
3632 }
3633
3634 /****************************************************************************
3635  UNIX chmod.
3636 ****************************************************************************/
3637
3638 static int cmd_chmod(void)
3639 {
3640         TALLOC_CTX *ctx = talloc_tos();
3641         char *src = NULL;
3642         char *buf = NULL;
3643         char *buf2 = NULL;
3644         char *targetname = NULL;
3645         struct cli_state *targetcli;
3646         mode_t mode;
3647         struct cli_credentials *creds = samba_cmdline_get_creds();
3648         NTSTATUS status;
3649
3650         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3651             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3652                 d_printf("chmod mode file\n");
3653                 return 1;
3654         }
3655         src = talloc_asprintf(ctx,
3656                         "%s%s",
3657                         client_get_cur_dir(),
3658                         buf2);
3659         if (!src) {
3660                 return 1;
3661         }
3662         src = client_clean_name(ctx, src);
3663         if (src == NULL) {
3664                 return 1;
3665         }
3666
3667         mode = (mode_t)strtol(buf, NULL, 8);
3668
3669         status = cli_resolve_path(ctx, "",
3670                                   creds,
3671                         cli, src, &targetcli, &targetname);
3672         if (!NT_STATUS_IS_OK(status)) {
3673                 d_printf("chmod %s: %s\n", src, nt_errstr(status));
3674                 return 1;
3675         }
3676
3677         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3678                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3679                 return 1;
3680         }
3681
3682         if (CLI_DIRSEP_CHAR != '/') {
3683                 d_printf("Command \"posix\" must be issued before "
3684                          "the \"chmod\" command can be used.\n");
3685                 return 1;
3686         }
3687
3688         status = cli_posix_chmod(targetcli, targetname, mode);
3689         if (!NT_STATUS_IS_OK(status)) {
3690                 d_printf("%s chmod file %s 0%o\n",
3691                          nt_errstr(status), src, (unsigned int)mode);
3692                 return 1;
3693         }
3694
3695         return 0;
3696 }
3697
3698 static const char *filetype_to_str(mode_t mode)
3699 {
3700         if (S_ISREG(mode)) {
3701                 return "regular file";
3702         } else if (S_ISDIR(mode)) {
3703                 return "directory";
3704         } else
3705 #ifdef S_ISCHR
3706         if (S_ISCHR(mode)) {
3707                 return "character device";
3708         } else
3709 #endif
3710 #ifdef S_ISBLK
3711         if (S_ISBLK(mode)) {
3712                 return "block device";
3713         } else
3714 #endif
3715 #ifdef S_ISFIFO
3716         if (S_ISFIFO(mode)) {
3717                 return "fifo";
3718         } else
3719 #endif
3720 #ifdef S_ISLNK
3721         if (S_ISLNK(mode)) {
3722                 return "symbolic link";
3723         } else
3724 #endif
3725 #ifdef S_ISSOCK
3726         if (S_ISSOCK(mode)) {
3727                 return "socket";
3728         } else
3729 #endif
3730         return "";
3731 }
3732
3733 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3734 {
3735         if (m & bt) {
3736                 return ret;
3737         } else {
3738                 return '-';
3739         }
3740 }
3741
3742 static char *unix_mode_to_str(char *s, mode_t m)
3743 {
3744         char *p = s;
3745         const char *str = filetype_to_str(m);
3746
3747         switch(str[0]) {
3748                 case 'd':
3749                         *p++ = 'd';
3750                         break;
3751                 case 'c':
3752                         *p++ = 'c';
3753                         break;
3754                 case 'b':
3755                         *p++ = 'b';
3756                         break;
3757                 case 'f':
3758                         *p++ = 'p';
3759                         break;
3760                 case 's':
3761                         *p++ = str[1] == 'y' ? 'l' : 's';
3762                         break;
3763                 case 'r':
3764                 default:
3765                         *p++ = '-';
3766                         break;
3767         }
3768         *p++ = rwx_to_str(m, S_IRUSR, 'r');
3769         *p++ = rwx_to_str(m, S_IWUSR, 'w');
3770         *p++ = rwx_to_str(m, S_IXUSR, 'x');
3771         *p++ = rwx_to_str(m, S_IRGRP, 'r');
3772         *p++ = rwx_to_str(m, S_IWGRP, 'w');
3773         *p++ = rwx_to_str(m, S_IXGRP, 'x');
3774         *p++ = rwx_to_str(m, S_IROTH, 'r');
3775         *p++ = rwx_to_str(m, S_IWOTH, 'w');
3776         *p++ = rwx_to_str(m, S_IXOTH, 'x');
3777         *p++ = '\0';
3778         return s;
3779 }
3780
3781 /****************************************************************************
3782  Utility function for UNIX getfacl.
3783 ****************************************************************************/
3784
3785 static char *perms_to_string(fstring permstr, unsigned char perms)
3786 {
3787         fstrcpy(permstr, "---");
3788         if (perms & SMB_POSIX_ACL_READ) {
3789                 permstr[0] = 'r';
3790         }
3791         if (perms & SMB_POSIX_ACL_WRITE) {
3792                 permstr[1] = 'w';
3793         }
3794         if (perms & SMB_POSIX_ACL_EXECUTE) {
3795                 permstr[2] = 'x';
3796         }
3797         return permstr;
3798 }
3799
3800 /****************************************************************************
3801  UNIX getfacl.
3802 ****************************************************************************/
3803
3804 static int cmd_getfacl(void)
3805 {
3806         TALLOC_CTX *ctx = talloc_tos();
3807         char *src = NULL;
3808         char *name = NULL;
3809         char *targetname = NULL;
3810         struct cli_state *targetcli;
3811         uint16_t major, minor;
3812         uint32_t caplow, caphigh;
3813         char *retbuf = NULL;
3814         size_t rb_size = 0;
3815         SMB_STRUCT_STAT sbuf;
3816         size_t num_file_acls = 0;
3817         size_t num_dir_acls = 0;
3818         size_t expected_buflen;
3819         uint16_t i;
3820         struct cli_credentials *creds = samba_cmdline_get_creds();
3821         NTSTATUS status;
3822
3823         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3824                 d_printf("getfacl filename\n");
3825                 return 1;
3826         }
3827         src = talloc_asprintf(ctx,
3828                         "%s%s",
3829                         client_get_cur_dir(),
3830                         name);
3831         if (!src) {
3832                 return 1;
3833         }
3834         src = client_clean_name(ctx, src);
3835         if (src == NULL) {
3836                 return 1;
3837         }
3838
3839         status = cli_resolve_path(ctx, "",
3840                                   creds,
3841                         cli, src, &targetcli, &targetname);
3842         if (!NT_STATUS_IS_OK(status)) {
3843                 d_printf("stat %s: %s\n", src, nt_errstr(status));
3844                 return 1;
3845         }
3846
3847         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3848                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3849                 return 1;
3850         }
3851
3852         if (CLI_DIRSEP_CHAR != '/') {
3853                 d_printf("Command \"posix\" must be issued before "
3854                          "the \"getfacl\" command can be used.\n");
3855                 return 1;
3856         }
3857
3858         status = cli_unix_extensions_version(targetcli, &major, &minor,
3859                                              &caplow, &caphigh);
3860         if (!NT_STATUS_IS_OK(status)) {
3861                 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3862                          nt_errstr(status));
3863                 return 1;
3864         }
3865
3866         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3867                 d_printf("This server supports UNIX extensions "
3868                         "but doesn't support POSIX ACLs.\n");
3869                 return 1;
3870         }
3871
3872         status = cli_posix_stat(targetcli, targetname, &sbuf);
3873         if (!NT_STATUS_IS_OK(status)) {
3874                 d_printf("%s getfacl doing a stat on file %s\n",
3875                          nt_errstr(status), src);
3876                 return 1;
3877         }
3878
3879         status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf);
3880         if (!NT_STATUS_IS_OK(status)) {
3881                 d_printf("%s getfacl file %s\n",
3882                          nt_errstr(status), src);
3883                 return 1;
3884         }
3885
3886         /* ToDo : Print out the ACL values. */
3887         if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3888                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3889                         src, (unsigned int)CVAL(retbuf,0) );
3890                 return 1;
3891         }
3892
3893         num_file_acls = SVAL(retbuf,2);
3894         num_dir_acls = SVAL(retbuf,4);
3895
3896         /*
3897          * No overflow check, num_*_acls comes from a 16-bit value,
3898          * and we expect expected_buflen (size_t) to be of at least 32
3899          * bit.
3900          */
3901         expected_buflen = SMB_POSIX_ACL_HEADER_SIZE +
3902                 SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls);
3903
3904         if (rb_size != expected_buflen) {
3905                 d_printf("getfacl file %s, incorrect POSIX acl buffer size "
3906                          "(should be %zu, was %zu).\n",
3907                          src,
3908                          expected_buflen,
3909                          rb_size);
3910                 return 1;
3911         }
3912
3913         d_printf("# file: %s\n", src);
3914         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3915
3916         if (num_file_acls == 0 && num_dir_acls == 0) {
3917                 d_printf("No acls found.\n");
3918         }
3919
3920         for (i = 0; i < num_file_acls; i++) {
3921                 uint32_t uorg;
3922                 fstring permstring;
3923                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3924                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3925
3926                 switch(tagtype) {
3927                         case SMB_POSIX_ACL_USER_OBJ:
3928                                 d_printf("user::");
3929                                 break;
3930                         case SMB_POSIX_ACL_USER:
3931                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3932                                 d_printf("user:%u:", uorg);
3933                                 break;
3934                         case SMB_POSIX_ACL_GROUP_OBJ:
3935                                 d_printf("group::");
3936                                 break;
3937                         case SMB_POSIX_ACL_GROUP:
3938                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3939                                 d_printf("group:%u:", uorg);
3940                                 break;
3941                         case SMB_POSIX_ACL_MASK:
3942                                 d_printf("mask::");
3943                                 break;
3944                         case SMB_POSIX_ACL_OTHER:
3945                                 d_printf("other::");
3946                                 break;
3947                         default:
3948                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3949                                         src, (unsigned int)tagtype );
3950                                 SAFE_FREE(retbuf);
3951                                 return 1;
3952                 }
3953
3954                 d_printf("%s\n", perms_to_string(permstring, perms));
3955         }
3956
3957         for (i = 0; i < num_dir_acls; i++) {
3958                 uint32_t uorg;
3959                 fstring permstring;
3960                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3961                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3962
3963                 switch(tagtype) {
3964                         case SMB_POSIX_ACL_USER_OBJ:
3965                                 d_printf("default:user::");
3966                                 break;
3967                         case SMB_POSIX_ACL_USER:
3968                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3969                                 d_printf("default:user:%u:", uorg);
3970                                 break;
3971                         case SMB_POSIX_ACL_GROUP_OBJ:
3972                                 d_printf("default:group::");
3973                                 break;
3974                         case SMB_POSIX_ACL_GROUP:
3975                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3976                                 d_printf("default:group:%u:", uorg);
3977                                 break;
3978                         case SMB_POSIX_ACL_MASK:
3979                                 d_printf("default:mask::");
3980                                 break;
3981                         case SMB_POSIX_ACL_OTHER:
3982                                 d_printf("default:other::");
3983                                 break;
3984                         default:
3985                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3986                                         src, (unsigned int)tagtype );
3987                                 SAFE_FREE(retbuf);
3988                                 return 1;
3989                 }
3990
3991                 d_printf("%s\n", perms_to_string(permstring, perms));
3992         }
3993
3994         return 0;
3995 }
3996
3997 /****************************************************************************
3998  Get the EA list of a file
3999 ****************************************************************************/
4000
4001 static int cmd_geteas(void)
4002 {
4003         TALLOC_CTX *ctx = talloc_tos();
4004         char *src = NULL;
4005         char *name = NULL;
4006         char *targetname = NULL;
4007         struct cli_state *targetcli;
4008         NTSTATUS status;
4009         size_t i, num_eas;
4010         struct ea_struct *eas;
4011         struct cli_credentials *creds = samba_cmdline_get_creds();
4012
4013         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4014                 d_printf("geteas filename\n");
4015                 return 1;
4016         }
4017         src = talloc_asprintf(ctx,
4018                         "%s%s",
4019                         client_get_cur_dir(),
4020                         name);
4021         if (!src) {
4022                 return 1;
4023         }
4024         src = client_clean_name(ctx, src);
4025         if (src == NULL) {
4026                 return 1;
4027         }
4028
4029         status = cli_resolve_path(ctx, "",
4030                                   creds,
4031                         cli, src, &targetcli, &targetname);
4032         if (!NT_STATUS_IS_OK(status)) {
4033                 d_printf("stat %s: %s\n", src, nt_errstr(status));
4034                 return 1;
4035         }
4036
4037         status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
4038                                       &num_eas, &eas);
4039         if (!NT_STATUS_IS_OK(status)) {
4040                 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
4041                 return 1;
4042         }
4043
4044         for (i=0; i<num_eas; i++) {
4045                 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
4046                 dump_data_file(eas[i].value.data, eas[i].value.length, false,
4047                                stdout);
4048                 d_printf("\n");
4049         }
4050
4051         TALLOC_FREE(eas);
4052
4053         return 0;
4054 }
4055
4056 /****************************************************************************
4057  Set an EA of a file
4058 ****************************************************************************/
4059
4060 static int cmd_setea(void)
4061 {
4062         TALLOC_CTX *ctx = talloc_tos();
4063         char *src = NULL;
4064         char *name = NULL;
4065         char *eaname = NULL;
4066         char *eavalue = NULL;
4067         char *targetname = NULL;
4068         struct cli_state *targetcli;
4069         struct cli_credentials *creds = samba_cmdline_get_creds();
4070         NTSTATUS status;
4071
4072         if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
4073             || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
4074                 d_printf("setea filename eaname value\n");
4075                 return 1;
4076         }
4077         if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
4078                 eavalue = talloc_strdup(ctx, "");
4079         }
4080         src = talloc_asprintf(ctx,
4081                         "%s%s",
4082                         client_get_cur_dir(),
4083                         name);
4084         if (!src) {
4085                 return 1;
4086         }
4087         src = client_clean_name(ctx, src);
4088         if (src == NULL) {
4089                 return 1;
4090         }
4091
4092         status = cli_resolve_path(ctx, "",
4093                                   creds,
4094                         cli, src, &targetcli, &targetname);
4095         if (!NT_STATUS_IS_OK(status)) {
4096                 d_printf("stat %s: %s\n", src, nt_errstr(status));
4097                 return 1;
4098         }
4099
4100         status =  cli_set_ea_path(targetcli, targetname, eaname, eavalue,
4101                                   strlen(eavalue));
4102         if (!NT_STATUS_IS_OK(status)) {
4103                 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
4104                 return 1;
4105         }
4106
4107         return 0;
4108 }
4109
4110 /****************************************************************************
4111  UNIX stat.
4112 ****************************************************************************/
4113
4114 static int cmd_stat(void)
4115 {
4116         TALLOC_CTX *ctx = talloc_tos();
4117         char *src = NULL;
4118         char *name = NULL;
4119         char *targetname = NULL;
4120         struct cli_state *targetcli;
4121         fstring mode_str;
4122         SMB_STRUCT_STAT sbuf;
4123         struct tm *lt;
4124         time_t tmp_time;
4125         struct cli_credentials *creds = samba_cmdline_get_creds();
4126         NTSTATUS status;
4127
4128         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4129                 d_printf("stat file\n");
4130                 return 1;
4131         }
4132         src = talloc_asprintf(ctx,
4133                         "%s%s",
4134                         client_get_cur_dir(),
4135                         name);
4136         if (!src) {
4137                 return 1;
4138         }
4139         src = client_clean_name(ctx, src);
4140         if (src == NULL) {
4141                 return 1;
4142         }
4143
4144         status = cli_resolve_path(ctx, "",
4145                                   creds,
4146                         cli, src, &targetcli, &targetname);
4147         if (!NT_STATUS_IS_OK(status)) {
4148                 d_printf("stat %s: %s\n", src, nt_errstr(status));
4149                 return 1;
4150         }
4151
4152         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4153                 d_printf("Server doesn't support UNIX CIFS calls.\n");
4154                 return 1;
4155         }
4156
4157         if (CLI_DIRSEP_CHAR != '/') {
4158                 d_printf("Command \"posix\" must be issued before "
4159                          "the \"stat\" command can be used.\n");
4160                 return 1;
4161         }
4162
4163         status = cli_posix_stat(targetcli, targetname, &sbuf);
4164         if (!NT_STATUS_IS_OK(status)) {
4165                 d_printf("%s stat file %s\n",
4166                          nt_errstr(status), src);
4167                 return 1;
4168         }
4169
4170         /* Print out the stat values. */
4171         d_printf("File: %s\n", src);
4172         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
4173                 (double)sbuf.st_ex_size,
4174                 (unsigned int)sbuf.st_ex_blocks,
4175                 filetype_to_str(sbuf.st_ex_mode));
4176
4177 #if defined(S_ISCHR) && defined(S_ISBLK)
4178         if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
4179                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
4180                         (double)sbuf.st_ex_ino,
4181                         (unsigned int)sbuf.st_ex_nlink,
4182                         unix_dev_major(sbuf.st_ex_rdev),
4183                         unix_dev_minor(sbuf.st_ex_rdev));
4184         } else
4185 #endif
4186                 d_printf("Inode: %.0f\tLinks: %u\n",
4187                         (double)sbuf.st_ex_ino,
4188                         (unsigned int)sbuf.st_ex_nlink);
4189
4190         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
4191                 ((int)sbuf.st_ex_mode & 0777),
4192                 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
4193                 (unsigned int)sbuf.st_ex_uid,
4194                 (unsigned int)sbuf.st_ex_gid);
4195
4196         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
4197         lt = localtime(&tmp_time);
4198         if (lt) {
4199                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4200         } else {
4201                 fstrcpy(mode_str, "unknown");
4202         }
4203         d_printf("Access: %s\n", mode_str);
4204
4205         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4206         lt = localtime(&tmp_time);
4207         if (lt) {
4208                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4209         } else {
4210                 fstrcpy(mode_str, "unknown");
4211         }
4212         d_printf("Modify: %s\n", mode_str);
4213
4214         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
4215         lt = localtime(&tmp_time);
4216         if (lt) {
4217                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4218         } else {
4219                 fstrcpy(mode_str, "unknown");
4220         }
4221         d_printf("Change: %s\n", mode_str);
4222
4223         return 0;
4224 }
4225
4226
4227 /****************************************************************************
4228  UNIX chown.
4229 ****************************************************************************/
4230
4231 static int cmd_chown(void)
4232 {
4233         TALLOC_CTX *ctx = talloc_tos();
4234         char *src = NULL;
4235         uid_t uid;
4236         gid_t gid;
4237         char *buf, *buf2, *buf3;
4238         struct cli_state *targetcli;
4239         char *targetname = NULL;
4240         struct cli_credentials *creds = samba_cmdline_get_creds();
4241         NTSTATUS status;
4242
4243         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4244             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
4245             !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
4246                 d_printf("chown uid gid file\n");
4247                 return 1;
4248         }
4249
4250         uid = (uid_t)atoi(buf);
4251         gid = (gid_t)atoi(buf2);
4252
4253         src = talloc_asprintf(ctx,
4254                         "%s%s",
4255                         client_get_cur_dir(),
4256                         buf3);
4257         if (!src) {
4258                 return 1;
4259         }
4260         src = client_clean_name(ctx, src);
4261         if (src == NULL) {
4262                 return 1;
4263         }
4264         status = cli_resolve_path(ctx, "",
4265                                   creds,
4266                         cli, src, &targetcli, &targetname);
4267         if (!NT_STATUS_IS_OK(status)) {
4268                 d_printf("chown %s: %s\n", src, nt_errstr(status));
4269                 return 1;
4270         }
4271
4272         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4273                 d_printf("Server doesn't support UNIX CIFS calls.\n");
4274                 return 1;
4275         }
4276
4277         if (CLI_DIRSEP_CHAR != '/') {
4278                 d_printf("Command \"posix\" must be issued before "
4279                          "the \"chown\" command can be used.\n");
4280                 return 1;
4281         }
4282
4283         status = cli_posix_chown(targetcli, targetname, uid, gid);
4284         if (!NT_STATUS_IS_OK(status)) {
4285                 d_printf("%s chown file %s uid=%d, gid=%d\n",
4286                          nt_errstr(status), src, (int)uid, (int)gid);
4287                 return 1;
4288         }
4289
4290         return 0;
4291 }
4292
4293 /****************************************************************************
4294  Rename some file.
4295 ****************************************************************************/
4296
4297 static int cmd_rename(void)
4298 {
4299         TALLOC_CTX *ctx = talloc_tos();
4300         char *src, *dest;
4301         char *buf, *buf2;
4302         struct cli_state *targetcli;
4303         char *targetsrc;
4304         char *targetdest;
4305         struct cli_credentials *creds = samba_cmdline_get_creds();
4306         NTSTATUS status;
4307         bool replace = false;
4308
4309         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4310             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4311                 d_printf("rename <src> <dest> [-f]\n");
4312                 return 1;
4313         }
4314
4315         src = talloc_asprintf(ctx,
4316                         "%s%s",
4317                         client_get_cur_dir(),
4318                         buf);
4319         if (!src) {
4320                 return 1;
4321         }
4322         src = client_clean_name(ctx, src);
4323         if (src == NULL) {
4324                 return 1;
4325         }
4326
4327         dest = talloc_asprintf(ctx,
4328                         "%s%s",
4329                         client_get_cur_dir(),
4330                         buf2);
4331         if (!dest) {
4332                 return 1;
4333         }
4334         dest = client_clean_name(ctx, dest);
4335         if (dest == NULL) {
4336                 return 1;
4337         }
4338
4339         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
4340             strcsequal(buf, "-f")) {
4341                 replace = true;
4342         }
4343
4344         status = cli_resolve_path(ctx, "",
4345                                   creds,
4346                         cli, src, &targetcli, &targetsrc);
4347         if (!NT_STATUS_IS_OK(status)) {
4348                 d_printf("rename %s: %s\n", src, nt_errstr(status));
4349                 return 1;
4350         }
4351
4352         status = cli_resolve_path(ctx, "",
4353                                   creds,
4354                         cli, dest, &targetcli, &targetdest);
4355         if (!NT_STATUS_IS_OK(status)) {
4356                 d_printf("rename %s: %s\n", dest, nt_errstr(status));
4357                 return 1;
4358         }
4359
4360         status = cli_rename(targetcli, targetsrc, targetdest, replace);
4361         if (!NT_STATUS_IS_OK(status)) {
4362                 d_printf("%s renaming files %s -> %s \n",
4363                         nt_errstr(status),
4364                         targetsrc,
4365                         targetdest);
4366                 return 1;
4367         }
4368
4369         return 0;
4370 }
4371
4372 struct scopy_timing {
4373         struct timespec tp_start;
4374 };
4375
4376 static int scopy_status(off_t written, void *priv)
4377 {
4378         struct timespec tp_end;
4379         unsigned int scopy_total_time_ms;
4380         struct scopy_timing *st = priv;
4381
4382         clock_gettime_mono(&tp_end);
4383         scopy_total_time_ms = nsec_time_diff(&tp_end,&st->tp_start)/1000000;
4384
4385         DEBUG(5,("Copied %jd bytes at an average %3.1f kb/s\n",
4386                  (intmax_t)written, written / (1.024*scopy_total_time_ms)));
4387
4388         return true;
4389 }
4390
4391 /****************************************************************************
4392  Server-Side copy some file.
4393 ****************************************************************************/
4394
4395 static int cmd_scopy(void)
4396 {
4397         TALLOC_CTX *ctx = talloc_tos();
4398         char *src, *dest;
4399         char *buf, *buf2;
4400         struct cli_state *targetcli;
4401         char *targetsrc;
4402         char *targetdest;
4403         uint32_t DesiredAccess, ShareAccess, CreateDisposition, CreateOptions;
4404         struct smb_create_returns cr;
4405         uint16_t destfnum = (uint16_t)-1;
4406         uint16_t srcfnum = (uint16_t)-1;
4407         off_t written = 0;
4408         struct scopy_timing st;
4409         int rc = 0;
4410         struct cli_credentials *creds = samba_cmdline_get_creds();
4411         NTSTATUS status;
4412
4413         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4414                         !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4415                 d_printf("scopy <src> <dest>\n");
4416                 return 1;
4417         }
4418
4419         src = talloc_asprintf(ctx,
4420                         "%s%s",
4421                         client_get_cur_dir(),
4422                         buf);
4423         if (!src) {
4424                 return 1;
4425         }
4426         src = client_clean_name(ctx, src);
4427         if (src == NULL) {
4428                 return 1;
4429         }
4430
4431         dest = talloc_asprintf(ctx,
4432                         "%s%s",
4433                         client_get_cur_dir(),
4434                         buf2);
4435         if (!dest) {
4436                 return 1;
4437         }
4438         dest = client_clean_name(ctx, dest);
4439         if (dest == NULL) {
4440                 return 1;
4441         }
4442
4443         status = cli_resolve_path(ctx, "",
4444                                   creds,
4445                         cli, src, &targetcli, &targetsrc);
4446         if (!NT_STATUS_IS_OK(status)) {
4447                 d_printf("scopy %s: %s\n", src, nt_errstr(status));
4448                 return 1;
4449         }
4450
4451         status = cli_resolve_path(ctx, "",
4452                                   creds,
4453                         cli, dest, &targetcli, &targetdest);
4454         if (!NT_STATUS_IS_OK(status)) {
4455                 d_printf("scopy %s: %s\n", dest, nt_errstr(status));
4456                 return 1;
4457         }
4458
4459
4460         DesiredAccess = (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|
4461                         READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS);
4462         ShareAccess = FILE_SHARE_READ|FILE_SHARE_DELETE;
4463         CreateDisposition = FILE_OPEN;
4464         CreateOptions = (FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE|
4465                         FILE_OPEN_REPARSE_POINT);
4466         status = cli_ntcreate(targetcli, targetsrc, 0, DesiredAccess, 0,
4467                         ShareAccess, CreateDisposition, CreateOptions, 0x0,
4468                         &srcfnum, &cr);
4469         if (!NT_STATUS_IS_OK(status)) {
4470                 d_printf("Failed to open file %s. %s\n",
4471                                 targetsrc, nt_errstr(status));
4472                 return 1;
4473         }
4474
4475         DesiredAccess = (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|
4476                         FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|
4477                         DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|SYNCHRONIZE_ACCESS);
4478         ShareAccess = FILE_SHARE_NONE;
4479         CreateDisposition = FILE_CREATE;
4480         CreateOptions = FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE;
4481         status = cli_ntcreate(targetcli, targetdest, 0, DesiredAccess,
4482                         FILE_ATTRIBUTE_ARCHIVE, ShareAccess, CreateDisposition,
4483                         CreateOptions, 0x0, &destfnum, NULL);
4484         if (!NT_STATUS_IS_OK(status)) {
4485                 d_printf("Failed to create file %s. %s\n",
4486                                 targetdest, nt_errstr(status));
4487                 cli_close(targetcli, srcfnum);
4488                 return 1;
4489         }
4490
4491         clock_gettime_mono(&st.tp_start);
4492         status = cli_splice(targetcli, targetcli, srcfnum, destfnum,
4493                         cr.end_of_file, 0, 0, &written, scopy_status, &st);
4494         if (!NT_STATUS_IS_OK(status)) {
4495                 d_printf("%s copying file %s -> %s \n",
4496                                 nt_errstr(status),
4497                                 targetsrc,
4498                                 targetdest);
4499                 rc = 1;
4500         }
4501
4502         status = cli_close(targetcli, srcfnum);
4503         if (!NT_STATUS_IS_OK(status)) {
4504                 d_printf("Error %s closing remote source file\n", nt_errstr(status));
4505                 rc = 1;
4506         }
4507         status = cli_close(targetcli, destfnum);
4508         if (!NT_STATUS_IS_OK(status)) {
4509                 d_printf("Error %s closing remote dest file\n", nt_errstr(status));
4510                 rc = 1;
4511         }
4512
4513         return rc;
4514 }
4515
4516 /****************************************************************************
4517  Print the volume name.
4518 ****************************************************************************/
4519
4520 static int cmd_volume(void)
4521 {
4522         char *volname;
4523         uint32_t serial_num;
4524         time_t create_date;
4525         NTSTATUS status;
4526
4527         status = cli_get_fs_volume_info(cli, talloc_tos(),
4528                                         &volname, &serial_num,
4529                                         &create_date);
4530         if (!NT_STATUS_IS_OK(status)) {
4531                 d_printf("Error %s getting volume info\n", nt_errstr(status));
4532                 return 1;
4533         }
4534
4535         d_printf("Volume: |%s| serial number 0x%x\n",
4536                         volname, (unsigned int)serial_num);
4537         return 0;
4538 }
4539
4540 /****************************************************************************
4541  Hard link files using the NT call.
4542 ****************************************************************************/
4543
4544 static int cmd_hardlink(void)
4545 {
4546         TALLOC_CTX *ctx = talloc_tos();
4547         char *src, *dest;
4548         char *buf, *buf2;
4549         struct cli_state *targetcli;
4550         char *targetname;
4551         struct cli_credentials *creds = samba_cmdline_get_creds();
4552         NTSTATUS status;
4553
4554         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4555             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4556                 d_printf("hardlink <src> <dest>\n");
4557                 return 1;
4558         }
4559
4560         src = talloc_asprintf(ctx,
4561                         "%s%s",
4562                         client_get_cur_dir(),
4563                         buf);
4564         if (!src) {
4565                 return 1;
4566         }
4567         src = client_clean_name(ctx, src);
4568         if (src == NULL) {
4569                 return 1;
4570         }
4571
4572         dest = talloc_asprintf(ctx,
4573                         "%s%s",
4574                         client_get_cur_dir(),
4575                         buf2);
4576         if (!dest) {
4577                 return 1;
4578         }
4579         dest = client_clean_name(ctx, dest);
4580         if (dest == NULL) {
4581                 return 1;
4582         }
4583
4584         status = cli_resolve_path(ctx, "",
4585                                   creds,
4586                                 cli, src, &targetcli, &targetname);
4587         if (!NT_STATUS_IS_OK(status)) {
4588                 d_printf("hardlink %s: %s\n", src, nt_errstr(status));
4589                 return 1;
4590         }
4591
4592         status = cli_hardlink(targetcli, targetname, dest);
4593         if (!NT_STATUS_IS_OK(status)) {
4594                 d_printf("%s doing an NT hard link of files\n",
4595                          nt_errstr(status));
4596                 return 1;
4597         }
4598
4599         return 0;
4600 }
4601
4602 /****************************************************************************
4603  Toggle the prompt flag.
4604 ****************************************************************************/
4605
4606 static int cmd_prompt(void)
4607 {
4608         prompt = !prompt;
4609         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
4610         return 1;
4611 }
4612
4613 /****************************************************************************
4614  Set the newer than time.
4615 ****************************************************************************/
4616
4617 static int cmd_newer(void)
4618 {
4619         TALLOC_CTX *ctx = talloc_tos();
4620         char *buf;
4621         bool ok;
4622         SMB_STRUCT_STAT sbuf;
4623
4624         ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
4625         if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
4626                 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4627                 DEBUG(1,("Getting files newer than %s",
4628                          time_to_asc(newer_than)));
4629         } else {
4630                 newer_than = 0;
4631         }
4632
4633         if (ok && newer_than == 0) {
4634                 d_printf("Error setting newer-than time\n");
4635                 return 1;
4636         }
4637
4638         return 0;
4639 }
4640
4641 /****************************************************************************
4642  Watch directory changes
4643 ****************************************************************************/
4644
4645 static int cmd_notify(void)
4646 {
4647         TALLOC_CTX *frame = talloc_stackframe();
4648         char *name, *buf;
4649         NTSTATUS status;
4650         uint16_t fnum;
4651
4652         name = talloc_strdup(talloc_tos(), client_get_cur_dir());
4653         if (name == NULL) {
4654                 goto fail;
4655         }
4656         if (!next_token_talloc(talloc_tos(), &cmd_ptr, &buf, NULL)) {
4657                 goto usage;
4658         }
4659         name = talloc_asprintf_append(name, "%s", buf);
4660         if (name == NULL) {
4661                 goto fail;
4662         }
4663         name = client_clean_name(talloc_tos(), name);
4664         if (name == NULL) {
4665                 return 1;
4666         }
4667         status = cli_ntcreate(
4668                 cli, name, 0, FILE_READ_DATA, 0,
4669                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
4670                 FILE_OPEN, 0, 0, &fnum, NULL);
4671         if (!NT_STATUS_IS_OK(status)) {
4672                 d_printf("Could not open file: %s\n", nt_errstr(status));
4673                 goto fail;
4674         }
4675
4676         while (1) {
4677                 uint32_t i;
4678                 uint32_t num_changes = 0;
4679                 struct notify_change *changes = NULL;
4680
4681                 status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
4682                                     true,
4683                                     talloc_tos(), &num_changes, &changes);
4684                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOTIFY_ENUM_DIR)) {
4685                         printf("NOTIFY_ENUM_DIR\n");
4686                         status = NT_STATUS_OK;
4687                 }
4688                 if (!NT_STATUS_IS_OK(status)) {
4689                         d_printf("notify returned %s\n",
4690                                  nt_errstr(status));
4691                         goto fail;
4692                 }
4693                 for (i=0; i<num_changes; i++) {
4694                         printf("%4.4x %s\n", changes[i].action,
4695                                changes[i].name);
4696                 }
4697                 TALLOC_FREE(changes);
4698         }
4699 usage:
4700         d_printf("notify <dir name>\n");
4701 fail:
4702         TALLOC_FREE(frame);
4703         return 1;
4704 }
4705
4706 /****************************************************************************
4707  Set the archive level.
4708 ****************************************************************************/
4709
4710 static int cmd_archive(void)
4711 {
4712         TALLOC_CTX *ctx = talloc_tos();
4713         char *buf;
4714
4715         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4716                 archive_level = atoi(buf);
4717         } else {
4718                 d_printf("Archive level is %d\n",archive_level);
4719         }
4720
4721         return 0;
4722 }
4723
4724 /****************************************************************************
4725  Toggle the backup_intent state.
4726 ****************************************************************************/
4727
4728 static int cmd_backup(void)
4729 {
4730         backup_intent = !backup_intent;
4731         cli_set_backup_intent(cli, backup_intent);
4732         DEBUG(2,("backup intent is now %s\n",backup_intent?"on":"off"));
4733         return 1;
4734 }
4735
4736 /****************************************************************************
4737  Toggle the lowercaseflag.
4738 ****************************************************************************/
4739
4740 static int cmd_lowercase(void)
4741 {
4742         lowercase = !lowercase;
4743         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
4744         return 0;
4745 }
4746
4747 /****************************************************************************
4748  Toggle the case sensitive flag.
4749 ****************************************************************************/
4750
4751 static int cmd_setcase(void)
4752 {
4753         bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
4754
4755         cli_set_case_sensitive(cli, !orig_case_sensitive);
4756         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
4757                 "on":"off"));
4758         return 0;
4759 }
4760
4761 /****************************************************************************
4762  Toggle the showacls flag.
4763 ****************************************************************************/
4764
4765 static int cmd_showacls(void)
4766 {
4767         showacls = !showacls;
4768         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
4769         return 0;
4770 }
4771
4772
4773 /****************************************************************************
4774  Toggle the recurse flag.
4775 ****************************************************************************/
4776
4777 static int cmd_recurse(void)
4778 {
4779         recurse = !recurse;
4780         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
4781         return 0;
4782 }
4783
4784 /****************************************************************************
4785  Toggle the translate flag.
4786 ****************************************************************************/
4787
4788 static int cmd_translate(void)
4789 {
4790         translation = !translation;
4791         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
4792                  translation?"on":"off"));
4793         return 0;
4794 }
4795
4796 /****************************************************************************
4797  Do the lcd command.
4798  ****************************************************************************/
4799
4800 static int cmd_lcd(void)
4801 {
4802         TALLOC_CTX *ctx = talloc_tos();
4803         char *buf;
4804         char *d;
4805
4806         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4807                 if (chdir(buf) == -1) {
4808                         d_printf("chdir to %s failed (%s)\n",
4809                                 buf, strerror(errno));
4810                 }
4811         }
4812         d = sys_getwd();
4813         if (!d) {
4814                 return 1;
4815         }
4816         DEBUG(2,("the local directory is now %s\n",d));
4817         SAFE_FREE(d);
4818         return 0;
4819 }
4820
4821 /****************************************************************************
4822  Get a file restarting at end of local file.
4823  ****************************************************************************/
4824
4825 static int cmd_reget(void)
4826 {
4827         TALLOC_CTX *ctx = talloc_tos();
4828         char *local_name = NULL;
4829         char *remote_name = NULL;
4830         char *fname = NULL;
4831         char *p = NULL;
4832
4833         remote_name = talloc_strdup(ctx, client_get_cur_dir());
4834         if (!remote_name) {
4835                 return 1;
4836         }
4837
4838         if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
4839                 d_printf("reget <filename>\n");
4840                 return 1;
4841         }
4842         remote_name = talloc_asprintf_append(remote_name, "%s", fname);
4843         if (!remote_name) {
4844                 return 1;
4845         }
4846         remote_name = client_clean_name(ctx,remote_name);
4847         if (!remote_name) {
4848                 return 1;
4849         }
4850
4851         local_name = fname;
4852         next_token_talloc(ctx, &cmd_ptr, &p, NULL);
4853         if (p) {
4854                 local_name = p;
4855         }
4856
4857         return do_get(remote_name, local_name, true);
4858 }
4859
4860 /****************************************************************************
4861  Put a file restarting at end of local file.
4862  ****************************************************************************/
4863
4864 static int cmd_reput(void)
4865 {
4866         TALLOC_CTX *ctx = talloc_tos();
4867         char *local_name = NULL;
4868         char *remote_name = NULL;
4869         char *buf;
4870         SMB_STRUCT_STAT st;
4871
4872         remote_name = talloc_strdup(ctx, client_get_cur_dir());
4873         if (!remote_name) {
4874                 return 1;
4875         }
4876
4877         if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
4878                 d_printf("reput <filename>\n");
4879                 return 1;
4880         }
4881
4882         if (!file_exist_stat(local_name, &st, false)) {
4883                 d_printf("%s does not exist\n", local_name);
4884                 return 1;
4885         }
4886
4887         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
4888                 remote_name = talloc_asprintf_append(remote_name,
4889                                                 "%s", buf);
4890         } else {
4891                 remote_name = talloc_asprintf_append(remote_name,
4892                                                 "%s", local_name);
4893         }
4894         if (!remote_name) {
4895                 return 1;
4896         }
4897
4898         remote_name = client_clean_name(ctx, remote_name);
4899         if (!remote_name) {
4900                 return 1;
4901         }
4902
4903         return do_put(remote_name, local_name, true);
4904 }
4905
4906 /****************************************************************************
4907  List a share name.
4908  ****************************************************************************/
4909
4910 static void browse_fn(const char *name, uint32_t m,
4911                       const char *comment, void *state)
4912 {
4913         const char *typestr = "";
4914
4915         switch (m & 7) {
4916         case STYPE_DISKTREE:
4917                 typestr = "Disk";
4918                 break;
4919         case STYPE_PRINTQ:
4920                 typestr = "Printer";
4921                 break;
4922         case STYPE_DEVICE:
4923                 typestr = "Device";
4924                 break;
4925         case STYPE_IPC:
4926                 typestr = "IPC";
4927                 break;
4928         }
4929         /* FIXME: If the remote machine returns non-ascii characters
4930            in any of these fields, they can corrupt the output.  We
4931            should remove them. */
4932         if (!grepable) {
4933                 d_printf("\t%-15s %-10.10s%s\n",
4934                         name,typestr,comment);
4935         } else {
4936                 d_printf ("%s|%s|%s\n",typestr,name,comment);
4937         }
4938 }
4939
4940 static bool browse_host_rpc(bool sort)
4941 {
4942         NTSTATUS status;
4943         struct rpc_pipe_client *pipe_hnd = NULL;
4944         TALLOC_CTX *frame = talloc_stackframe();
4945         WERROR werr;
4946         struct srvsvc_NetShareInfoCtr info_ctr;
4947         struct srvsvc_NetShareCtr1 ctr1;
4948         uint32_t resume_handle = 0;
4949         uint32_t total_entries = 0;
4950         uint32_t i;
4951         struct dcerpc_binding_handle *b;
4952
4953         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
4954                                           &pipe_hnd);
4955
4956         if (!NT_STATUS_IS_OK(status)) {
4957                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
4958                            nt_errstr(status)));
4959                 TALLOC_FREE(frame);
4960                 return false;
4961         }
4962
4963         b = pipe_hnd->binding_handle;
4964
4965         ZERO_STRUCT(info_ctr);
4966         ZERO_STRUCT(ctr1);
4967
4968         info_ctr.level = 1;
4969         info_ctr.ctr.ctr1 = &ctr1;
4970
4971         status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
4972                                               pipe_hnd->desthost,
4973                                               &info_ctr,
4974                                               0xffffffff,
4975                                               &total_entries,
4976                                               &resume_handle,
4977                                               &werr);
4978
4979         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4980                 TALLOC_FREE(pipe_hnd);
4981                 TALLOC_FREE(frame);
4982                 return false;
4983         }
4984
4985         for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4986                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4987                 browse_fn(info.name, info.type, info.comment, NULL);
4988         }
4989
4990         TALLOC_FREE(pipe_hnd);
4991         TALLOC_FREE(frame);
4992         return true;
4993 }
4994
4995 /****************************************************************************
4996  Try and browse available connections on a host.
4997 ****************************************************************************/
4998
4999 static bool browse_host(bool sort)
5000 {
5001         int ret;
5002
5003         if (!grepable) {
5004                 d_printf("\n\tSharename       Type      Comment\n");
5005                 d_printf("\t---------       ----      -------\n");
5006         }
5007
5008         if (browse_host_rpc(sort)) {
5009                 return true;
5010         }
5011
5012         if (smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1) {
5013                 return false;
5014         }
5015
5016         ret = cli_RNetShareEnum(cli, browse_fn, NULL);
5017         if (ret == -1) {
5018                 NTSTATUS status = cli_nt_error(cli);
5019                 d_printf("Error returning browse list: %s\n",
5020                          nt_errstr(status));
5021         }
5022
5023         return (ret != -1);
5024 }
5025
5026 /****************************************************************************
5027  List a server name.
5028 ****************************************************************************/
5029
5030 static void server_fn(const char *name, uint32_t m,
5031                       const char *comment, void *state)
5032 {
5033
5034         if (!grepable){
5035                 d_printf("\t%-16s     %s\n", name, comment);
5036         } else {
5037                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
5038         }
5039 }
5040
5041 /****************************************************************************
5042  Try and browse available connections on a host.
5043 ****************************************************************************/
5044
5045 static bool list_servers(const char *wk_grp)
5046 {
5047         fstring state;
5048
5049         if (!cli->server_domain)
5050                 return false;
5051
5052         if (!grepable) {
5053                 d_printf("\n\tServer               Comment\n");
5054                 d_printf("\t---------            -------\n");
5055         };
5056         fstrcpy( state, "Server" );
5057         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
5058                           state);
5059
5060         if (!grepable) {
5061                 d_printf("\n\tWorkgroup            Master\n");
5062                 d_printf("\t---------            -------\n");
5063         };
5064
5065         fstrcpy( state, "Workgroup" );
5066         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
5067                           server_fn, state);
5068         return true;
5069 }
5070
5071 /****************************************************************************
5072  Print or set current VUID
5073 ****************************************************************************/
5074
5075 static int cmd_vuid(void)
5076 {
5077         TALLOC_CTX *ctx = talloc_tos();
5078         char *buf;
5079
5080         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5081                 d_printf("Current VUID is %d\n",
5082                          cli_state_get_uid(cli));
5083                 return 0;
5084         }
5085
5086         cli_state_set_uid(cli, atoi(buf));
5087         return 0;
5088 }
5089
5090 /****************************************************************************
5091  Setup a new VUID, by issuing a session setup
5092 ****************************************************************************/
5093
5094 static int cmd_logon(void)
5095 {
5096         TALLOC_CTX *ctx = talloc_tos();
5097         char *l_username, *l_password;
5098         struct cli_credentials *creds = NULL;
5099         NTSTATUS nt_status;
5100
5101         if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
5102                 d_printf("logon <username> [<password>]\n");
5103                 return 0;
5104         }
5105
5106         if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
5107                 char pwd[256] = {0};
5108                 int rc;
5109
5110                 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
5111                 if (rc == 0) {
5112                         l_password = talloc_strdup(ctx, pwd);
5113                 }
5114         }
5115         if (!l_password) {
5116                 return 1;
5117         }
5118
5119         creds = cli_session_creds_init(ctx,
5120                                        l_username,
5121                                        lp_workgroup(),
5122                                        NULL, /* realm */
5123                                        l_password,
5124                                        false, /* use_kerberos */
5125                                        false, /* fallback_after_kerberos */
5126                                        false, /* use_ccache */
5127                                        false); /* password_is_nt_hash */
5128         if (creds == NULL) {
5129                 d_printf("cli_session_creds_init() failed.\n");
5130                 return -1;
5131         }
5132         nt_status = cli_session_setup_creds(cli, creds);
5133         TALLOC_FREE(creds);
5134         if (!NT_STATUS_IS_OK(nt_status)) {
5135                 d_printf("session setup failed: %s\n", nt_errstr(nt_status));
5136                 return -1;
5137         }
5138
5139         d_printf("Current VUID is %d\n", cli_state_get_uid(cli));
5140         return 0;
5141 }
5142
5143 /**
5144  * close the session
5145  */
5146
5147 static int cmd_logoff(void)
5148 {
5149         NTSTATUS status;
5150
5151         status = cli_ulogoff(cli);
5152         if (!NT_STATUS_IS_OK(status)) {
5153                 d_printf("logoff failed: %s\n", nt_errstr(status));
5154                 return -1;
5155         }
5156
5157         d_printf("logoff successful\n");
5158         return 0;
5159 }
5160
5161
5162 /**
5163  * tree connect (connect to a share)
5164  */
5165
5166 static int cmd_tcon(void)
5167 {
5168         TALLOC_CTX *ctx = talloc_tos();
5169         char *sharename;
5170         NTSTATUS status;
5171
5172         if (!next_token_talloc(ctx, &cmd_ptr, &sharename, NULL)) {
5173                 d_printf("tcon <sharename>\n");
5174                 return 0;
5175         }
5176
5177         if (!sharename) {
5178                 return 1;
5179         }
5180
5181         status = cli_tree_connect(cli, sharename, "?????", NULL);
5182         if (!NT_STATUS_IS_OK(status)) {
5183                 d_printf("tcon failed: %s\n", nt_errstr(status));
5184                 return -1;
5185         }
5186
5187         d_printf("tcon to %s successful, tid: %u\n", sharename,
5188                  cli_state_get_tid(cli));
5189
5190         talloc_free(sharename);
5191
5192         return 0;
5193 }
5194
5195 /**
5196  * tree disconnect (disconnect from a share)
5197  */
5198
5199 static int cmd_tdis(void)
5200 {
5201         NTSTATUS status;
5202
5203         status = cli_tdis(cli);
5204         if (!NT_STATUS_IS_OK(status)) {
5205                 d_printf("tdis failed: %s\n", nt_errstr(status));
5206                 return -1;
5207         }
5208
5209         d_printf("tdis successful\n");
5210         return 0;
5211 }
5212
5213
5214 /**
5215  * get or set tid
5216  */
5217
5218 static int cmd_tid(void)
5219 {
5220         TALLOC_CTX *ctx = talloc_tos();
5221         char *tid_str;
5222
5223         if (!next_token_talloc(ctx, &cmd_ptr, &tid_str, NULL)) {
5224                 if (cli_state_has_tcon(cli)) {
5225                         d_printf("current tid is %d\n", cli_state_get_tid(cli));
5226                 } else {
5227                         d_printf("no tcon currently\n");
5228                 }
5229         } else {
5230                 uint32_t tid = atoi(tid_str);
5231                 if (!cli_state_has_tcon(cli)) {
5232                         d_printf("no tcon currently\n");
5233                 }
5234                 cli_state_set_tid(cli, tid);
5235         }
5236
5237         return 0;
5238 }
5239
5240
5241 /****************************************************************************
5242  list active connections
5243 ****************************************************************************/
5244
5245 static int cmd_list_connect(void)
5246 {
5247         cli_cm_display(cli);
5248         return 0;
5249 }
5250
5251 /****************************************************************************
5252  display the current active client connection
5253 ****************************************************************************/
5254
5255 static int cmd_show_connect( void )
5256 {
5257         TALLOC_CTX *ctx = talloc_tos();
5258         struct cli_state *targetcli;
5259         char *targetpath;
5260         struct cli_credentials *creds = samba_cmdline_get_creds();
5261         NTSTATUS status;
5262
5263         status = cli_resolve_path(ctx, "",
5264                                   creds,
5265                                   cli,
5266                                   client_get_cur_dir(), &targetcli,
5267                                   &targetpath);
5268         if (!NT_STATUS_IS_OK(status)) {
5269                 d_printf("showconnect %s: %s\n", cur_dir, nt_errstr(status));
5270                 return 1;
5271         }
5272
5273         d_printf("//%s/%s\n", smbXcli_conn_remote_name(targetcli->conn), targetcli->share);
5274         return 0;
5275 }
5276
5277 /**
5278  * cmd_utimes - interactive command to set the four times
5279  *
5280  * Read a filename and four times from the client command line and update
5281  * the file times. A value of -1 for a time means don't change.
5282  */
5283 static int cmd_utimes(void)
5284 {
5285         char *buf;
5286         char *fname = NULL;
5287         struct timespec times[4] = {{0}};
5288         struct timeval_buf tbuf[4];
5289         int time_count = 0;
5290         int err = 0;
5291         bool ok;
5292         TALLOC_CTX *ctx = talloc_new(NULL);
5293         NTSTATUS status;
5294
5295         if (ctx == NULL) {
5296                 return 1;
5297         }
5298
5299         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5300         if (!ok) {
5301                 d_printf("utimes <filename> <create-time> <access-time> "
5302                          "<write-time> <change-time>\n");
5303                 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5304                         "or -1 for no change\n");
5305                 err = 1;
5306                 goto out;
5307         }
5308
5309         fname = talloc_asprintf(ctx,
5310                                 "%s%s",
5311                                 client_get_cur_dir(),
5312                                 buf);
5313         if (fname == NULL) {
5314                 err = 1;
5315                 goto out;
5316         }
5317         fname = client_clean_name(ctx, fname);
5318         if (fname == NULL) {
5319                 err = 1;
5320                 goto out;
5321         }
5322
5323         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
5324                 time_count < 4) {
5325                 const char *s = buf;
5326                 struct tm tm = {0,};
5327                 time_t t;
5328                 char *ret;
5329
5330                 if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
5331                         times[time_count] = make_omit_timespec();
5332                         time_count++;
5333                         continue;
5334                 }
5335
5336                 ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
5337
5338                 if (ret == NULL) {
5339                         ret = strptime(s, "%Y:%m:%d-%H:%M:%S", &tm);
5340                 }
5341
5342                 /* We could not match all the chars, so print error */
5343                 if (ret == NULL || *ret != 0) {
5344                         d_printf("Invalid date format: %s\n", s);
5345                         d_printf("utimes <filename> <create-time> "
5346                                 "<access-time> <write-time> <change-time>\n");
5347                         d_printf("Dates should be in [YY]YY:MM:DD-HH:MM:SS "
5348                                  "format or -1 for no change\n");
5349                         err = 1;
5350                         goto out;
5351                 }
5352
5353                 /* Convert tm to a time_t */
5354                 t = mktime(&tm);
5355                 times[time_count] = (struct timespec){.tv_sec = t};
5356                 time_count++;
5357         }
5358
5359         if (time_count < 4) {
5360                 d_printf("Insufficient dates: %d\n", time_count);
5361                 d_printf("utimes <filename> <create-time> <access-time> "
5362                         "<write-time> <change-time>\n");
5363                 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5364                         "or -1 for no change\n");
5365                 err = 1;
5366                 goto out;
5367         }
5368
5369         DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
5370                    timespec_string_buf(&times[0], false, &tbuf[0]),
5371                    timespec_string_buf(&times[1], false, &tbuf[1]),
5372                    timespec_string_buf(&times[2], false, &tbuf[2]),
5373                    timespec_string_buf(&times[3], false, &tbuf[3])));
5374
5375         status = cli_setpathinfo_ext(
5376                 cli, fname, times[0], times[1], times[2], times[3],
5377                 (uint32_t)-1);
5378         if (!NT_STATUS_IS_OK(status)) {
5379                 d_printf("cli_setpathinfo_ext failed: %s\n",
5380                          nt_errstr(status));
5381                 err = 1;
5382                 goto out;
5383         }
5384 out:
5385         talloc_free(ctx);
5386         return err;
5387 }
5388
5389 /**
5390  * set_remote_attr - set DOS attributes of a remote file
5391  * @filename: path to the file name
5392  * @new_attr: attribute bit mask to use
5393  * @mode: one of ATTR_SET or ATTR_UNSET
5394  *
5395  * Update the file attributes with the one provided.
5396  */
5397 int set_remote_attr(const char *filename, uint32_t new_attr, int mode)
5398 {
5399         extern struct cli_state *cli;
5400         uint32_t old_attr;
5401         NTSTATUS status;
5402
5403         status = cli_getatr(cli, filename, &old_attr, NULL, NULL);
5404         if (!NT_STATUS_IS_OK(status)) {
5405                 d_printf("cli_getatr failed: %s\n", nt_errstr(status));
5406                 return 1;
5407         }
5408
5409         if (mode == ATTR_SET) {
5410                 new_attr |= old_attr;
5411         } else {
5412                 new_attr = old_attr & ~new_attr;
5413         }
5414
5415         status = cli_setatr(cli, filename, new_attr, 0);
5416         if (!NT_STATUS_IS_OK(status)) {
5417                 d_printf("cli_setatr failed: %s\n", nt_errstr(status));
5418                 return 1;
5419         }
5420
5421         return 0;
5422 }
5423
5424 /**
5425  * cmd_setmode - interactive command to set DOS attributes
5426  *
5427  * Read a filename and mode from the client command line and update
5428  * the file DOS attributes.
5429  */
5430 int cmd_setmode(void)
5431 {
5432         char *buf;
5433         char *fname = NULL;
5434         uint32_t attr[2] = {0};
5435         int mode = ATTR_SET;
5436         int err = 0;
5437         bool ok;
5438         TALLOC_CTX *ctx = talloc_new(NULL);
5439         if (ctx == NULL) {
5440                 return 1;
5441         }
5442
5443         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5444         if (!ok) {
5445                 d_printf("setmode <filename> <[+|-]rsha>\n");
5446                 err = 1;
5447                 goto out;
5448         }
5449
5450         fname = talloc_asprintf(ctx,
5451                                 "%s%s",
5452                                 client_get_cur_dir(),
5453                                 buf);
5454         if (fname == NULL) {
5455                 err = 1;
5456                 goto out;
5457         }
5458         fname = client_clean_name(ctx, fname);
5459         if (fname == NULL) {
5460                 err = 1;
5461                 goto out;
5462         }
5463
5464         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
5465                 const char *s = buf;
5466
5467                 while (*s) {
5468                         switch (*s++) {
5469                         case '+':
5470                                 mode = ATTR_SET;
5471                                 break;
5472                         case '-':
5473                                 mode = ATTR_UNSET;
5474                                 break;
5475                         case 'r':
5476                                 attr[mode] |= FILE_ATTRIBUTE_READONLY;
5477                                 break;
5478                         case 'h':
5479                                 attr[mode] |= FILE_ATTRIBUTE_HIDDEN;
5480                                 break;
5481                         case 's':
5482                                 attr[mode] |= FILE_ATTRIBUTE_SYSTEM;
5483                                 break;
5484                         case 'a':
5485                                 attr[mode] |= FILE_ATTRIBUTE_ARCHIVE;
5486                                 break;
5487                         default:
5488                                 d_printf("setmode <filename> <perm=[+|-]rsha>\n");
5489                                 err = 1;
5490                                 goto out;
5491                         }
5492                 }
5493         }
5494
5495         if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) {
5496                 d_printf("setmode <filename> <[+|-]rsha>\n");
5497                 err = 1;
5498                 goto out;
5499         }
5500
5501         DEBUG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET]));
5502
5503         /* ignore return value: server might not store DOS attributes */
5504         set_remote_attr(fname, attr[ATTR_SET], ATTR_SET);
5505         set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET);
5506 out:
5507         talloc_free(ctx);
5508         return err;
5509 }
5510
5511 /****************************************************************************
5512  iosize command
5513 ***************************************************************************/
5514
5515 int cmd_iosize(void)
5516 {
5517         TALLOC_CTX *ctx = talloc_tos();
5518         char *buf;
5519         int iosize;
5520         struct cli_credentials *creds = samba_cmdline_get_creds();
5521         bool smb_encrypt =
5522                 (cli_credentials_get_smb_encryption(creds) ==
5523                  SMB_ENCRYPTION_REQUIRED);
5524
5525         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5526                 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5527                         if (!smb_encrypt) {
5528                                 d_printf("iosize <n> or iosize 0x<n>. "
5529                                         "Minimum is 0 (default), "
5530                                         "max is 16776960 (0xFFFF00)\n");
5531                         } else {
5532                                 d_printf("iosize <n> or iosize 0x<n>. "
5533                                         "(Encrypted connection) ,"
5534                                         "Minimum is 0 (default), "
5535                                         "max is 130048 (0x1FC00)\n");
5536                         }
5537                 } else {
5538                         d_printf("iosize <n> or iosize 0x<n>.\n");
5539                 }
5540                 return 1;
5541         }
5542
5543         iosize = strtol(buf,NULL,0);
5544         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5545                 if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) {
5546                         d_printf("iosize out of range for encrypted "
5547                                 "connection (min = 0 (default), "
5548                                 "max = 130048 (0x1FC00)\n");
5549                         return 1;
5550                 } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) {
5551                         d_printf("iosize out of range (min = 0 (default), "
5552                                 "max = 16776960 (0xFFFF00)\n");
5553                         return 1;
5554                 }
5555         }
5556
5557         io_bufsize = iosize;
5558         d_printf("iosize is now %d\n", io_bufsize);
5559         return 0;
5560 }
5561
5562 /****************************************************************************
5563  timeout command
5564 ***************************************************************************/
5565
5566 static int cmd_timeout(void)
5567 {
5568         TALLOC_CTX *ctx = talloc_tos();
5569         char *buf;
5570
5571         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5572                 unsigned int old_timeout = cli_set_timeout(cli, 0);
5573                 cli_set_timeout(cli, old_timeout);
5574                 d_printf("timeout <n> (per-operation timeout "
5575                         "in seconds - currently %u).\n",
5576                         old_timeout/1000);
5577                 return 1;
5578         }
5579
5580         io_timeout = strtol(buf,NULL,0);
5581         cli_set_timeout(cli, io_timeout*1000);
5582         d_printf("io_timeout per operation is now %d\n", io_timeout);
5583         return 0;
5584 }
5585
5586
5587 /****************************************************************************
5588 history
5589 ****************************************************************************/
5590 static int cmd_history(void)
5591 {
5592 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
5593         HIST_ENTRY **hlist;
5594         int i;
5595
5596         hlist = history_list();
5597
5598         for (i = 0; hlist && hlist[i]; i++) {
5599                 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
5600         }
5601 #else
5602         DEBUG(0,("no history without readline support\n"));
5603 #endif
5604
5605         return 0;
5606 }
5607
5608 /* Some constants for completing filename arguments */
5609
5610 #define COMPL_NONE        0          /* No completions */
5611 #define COMPL_REMOTE      1          /* Complete remote filename */
5612 #define COMPL_LOCAL       2          /* Complete local filename */
5613
5614 /* This defines the commands supported by this client.
5615  * NOTE: The "!" must be the last one in the list because it's fn pointer
5616  *       field is NULL, and NULL in that field is used in process_tok()
5617  *       (below) to indicate the end of the list.  crh
5618  */
5619 static struct {
5620         const char *name;
5621         int (*fn)(void);
5622         const char *description;
5623         char compl_args[2];      /* Completion argument info */
5624 } commands[] = {
5625   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5626   {"allinfo",cmd_allinfo,"<file> show all available info",
5627    {COMPL_REMOTE,COMPL_NONE}},
5628   {"altname",cmd_altname,"<file> show alt name",{COMPL_REMOTE,COMPL_NONE}},
5629   {"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}},
5630   {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}},
5631   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
5632   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
5633   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
5634   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
5635   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_NONE}},
5636   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_NONE}},
5637   {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_NONE}},
5638   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5639   {"deltree",cmd_deltree,"<mask> recursively delete all matching files and directories",{COMPL_REMOTE,COMPL_NONE}},
5640   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5641   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5642   {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
5643   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5644   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
5645   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_NONE}},
5646   {"geteas", cmd_geteas, "<file name> get the EA list of a file",
5647    {COMPL_REMOTE, COMPL_NONE}},
5648   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5649   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5650   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
5651   {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
5652   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
5653   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5654   {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5655   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
5656   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5657   {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5658   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
5659   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5660   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
5661   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5662   {"mkfifo",cmd_mkfifo,"<file mode> make a fifo",{COMPL_NONE,COMPL_NONE}},
5663   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
5664   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
5665   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
5666   {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}},
5667   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
5668   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
5669   {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
5670   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5671   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5672   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5673   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5674   {"posix_whoami",cmd_posix_whoami,"return logged on user information "
5675                         "using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5676   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
5677   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
5678   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
5679   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
5680   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5681   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
5682   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5683   {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5684   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
5685   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
5686   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
5687   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
5688   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
5689   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5690   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_REMOTE,COMPL_NONE}},
5691   {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},
5692   {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
5693    {COMPL_REMOTE, COMPL_LOCAL}},
5694   {"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
5695   {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
5696   {"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
5697   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5698   {"tar",cmd_tar,"tar <c|x>[IXFvbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
5699   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
5700   {"timeout",cmd_timeout,"timeout <number> - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}},
5701   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
5702   {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5703   {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
5704   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
5705   {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5706   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
5707   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
5708   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
5709   {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
5710   {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
5711   {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
5712   {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
5713         "<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
5714   {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
5715   {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
5716
5717   /* Yes, this must be here, see crh's comment above. */
5718   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
5719   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
5720 };
5721
5722 /*******************************************************************
5723  Lookup a command string in the list of commands, including
5724  abbreviations.
5725 ******************************************************************/
5726
5727 static int process_tok(char *tok)
5728 {
5729         size_t i = 0, matches = 0;
5730         size_t cmd=0;
5731         size_t tok_len = strlen(tok);
5732
5733         while (commands[i].fn != NULL) {
5734                 if (strequal(commands[i].name,tok)) {
5735                         matches = 1;
5736                         cmd = i;
5737                         break;
5738                 } else if (strnequal(commands[i].name, tok, tok_len)) {
5739                         matches++;
5740                         cmd = i;
5741                 }
5742                 i++;
5743         }
5744
5745         if (matches == 0)
5746                 return(-1);
5747         else if (matches == 1)
5748                 return(cmd);
5749         else
5750                 return(-2);
5751 }
5752
5753 /****************************************************************************
5754  Help.
5755 ****************************************************************************/
5756
5757 static int cmd_help(void)
5758 {
5759         TALLOC_CTX *ctx = talloc_tos();
5760         int i=0,j;
5761         char *buf;
5762
5763         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5764                 if ((i = process_tok(buf)) >= 0)
5765                         d_printf("HELP %s:\n\t%s\n\n",
5766                                 commands[i].name,commands[i].description);
5767         } else {
5768                 while (commands[i].description) {
5769                         for (j=0; commands[i].description && (j<5); j++) {
5770                                 d_printf("%-15s",commands[i].name);
5771                                 i++;
5772                         }
5773                         d_printf("\n");
5774                 }
5775         }
5776         return 0;
5777 }
5778
5779 /****************************************************************************
5780  Process a -c command string.
5781 ****************************************************************************/
5782
5783 static int process_command_string(const char *cmd_in)
5784 {
5785         TALLOC_CTX *ctx = talloc_tos();
5786         char *cmd = talloc_strdup(ctx, cmd_in);
5787         int rc = 0;
5788         struct cli_credentials *creds = samba_cmdline_get_creds();
5789
5790         if (!cmd) {
5791                 return 1;
5792         }
5793         /* establish the connection if not already */
5794
5795         if (!cli) {
5796                 NTSTATUS status;
5797
5798                 status = cli_cm_open(talloc_tos(), NULL,
5799                                      desthost,
5800                                      service,
5801                                      creds,
5802                                      have_ip ? &dest_ss : NULL, port,
5803                                      name_type,
5804                                      &cli);
5805                 if (!NT_STATUS_IS_OK(status)) {
5806                         return 1;
5807                 }
5808                 cli_set_timeout(cli, io_timeout*1000);
5809         }
5810
5811         while (cmd[0] != '\0')    {
5812                 char *line;
5813                 char *p;
5814                 char *tok;
5815                 int i;
5816
5817                 if ((p = strchr_m(cmd, ';')) == 0) {
5818                         line = cmd;
5819                         cmd += strlen(cmd);
5820                 } else {
5821                         *p = '\0';
5822                         line = cmd;
5823                         cmd = p + 1;
5824                 }
5825
5826                 /* and get the first part of the command */
5827                 cmd_ptr = line;
5828                 if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
5829                         continue;
5830                 }
5831
5832                 if ((i = process_tok(tok)) >= 0) {
5833                         rc = commands[i].fn();
5834                 } else if (i == -2) {
5835                         d_printf("%s: command abbreviation ambiguous\n",tok);
5836                 } else {
5837                         d_printf("%s: command not found\n",tok);
5838                 }
5839         }
5840
5841         return rc;
5842 }
5843
5844 #define MAX_COMPLETIONS 100
5845
5846 struct completion_remote {
5847         char *dirmask;
5848         char **matches;
5849         int count, samelen;
5850         const char *text;
5851         int len;
5852 };
5853
5854 static NTSTATUS completion_remote_filter(struct file_info *f,
5855                                 const char *mask,
5856                                 void *state)
5857 {
5858         struct completion_remote *info = (struct completion_remote *)state;
5859
5860         if (info->count >= MAX_COMPLETIONS - 1) {
5861                 return NT_STATUS_OK;
5862         }
5863         if (strncmp(info->text, f->name, info->len) != 0) {
5864                 return NT_STATUS_OK;
5865         }
5866         if (ISDOT(f->name) || ISDOTDOT(f->name)) {
5867                 return NT_STATUS_OK;
5868         }
5869
5870         if ((info->dirmask[0] == 0) && !(f->attr & FILE_ATTRIBUTE_DIRECTORY))
5871                 info->matches[info->count] = SMB_STRDUP(f->name);
5872         else {
5873                 TALLOC_CTX *ctx = talloc_stackframe();
5874                 char *tmp;
5875
5876                 tmp = talloc_strdup(ctx,info->dirmask);
5877                 if (!tmp) {
5878                         TALLOC_FREE(ctx);
5879                         return NT_STATUS_NO_MEMORY;
5880                 }
5881                 tmp = talloc_asprintf_append(tmp, "%s", f->name);
5882                 if (!tmp) {
5883                         TALLOC_FREE(ctx);
5884                         return NT_STATUS_NO_MEMORY;
5885                 }
5886                 if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
5887                         tmp = talloc_asprintf_append(tmp, "%s",
5888                                                      CLI_DIRSEP_STR);
5889                 }
5890                 if (!tmp) {
5891                         TALLOC_FREE(ctx);
5892                         return NT_STATUS_NO_MEMORY;
5893                 }
5894                 info->matches[info->count] = SMB_STRDUP(tmp);
5895                 TALLOC_FREE(ctx);
5896         }
5897         if (info->matches[info->count] == NULL) {
5898                 return NT_STATUS_OK;
5899         }
5900         if (f->attr & FILE_ATTRIBUTE_DIRECTORY) {
5901                 smb_readline_ca_char(0);
5902         }
5903         if (info->count == 1) {
5904                 info->samelen = strlen(info->matches[info->count]);
5905         } else {
5906                 while (strncmp(info->matches[info->count],
5907                                info->matches[info->count-1],
5908                                info->samelen) != 0) {
5909                         info->samelen--;
5910                 }
5911         }
5912         info->count++;
5913         return NT_STATUS_OK;
5914 }
5915
5916 static char **remote_completion(const char *text, int len)
5917 {
5918         TALLOC_CTX *ctx = talloc_stackframe();
5919         char *dirmask = NULL;
5920         char *targetpath = NULL;
5921         struct cli_state *targetcli = NULL;
5922         int i;
5923         struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
5924         struct cli_credentials *creds = samba_cmdline_get_creds();
5925         NTSTATUS status;
5926
5927         /* can't have non-static initialisation on Sun CC, so do it
5928            at run time here */
5929         info.samelen = len;
5930         info.text = text;
5931         info.len = len;
5932
5933         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
5934         if (!info.matches) {
5935                 TALLOC_FREE(ctx);
5936                 return NULL;
5937         }
5938
5939         /*
5940          * We're leaving matches[0] free to fill it later with the text to
5941          * display: Either the one single match or the longest common subset
5942          * of the matches.
5943          */
5944         info.matches[0] = NULL;
5945         info.count = 1;
5946
5947         for (i = len-1; i >= 0; i--) {
5948                 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
5949                         break;
5950                 }
5951         }
5952
5953         info.text = text+i+1;
5954         info.samelen = info.len = len-i-1;
5955
5956         if (i > 0) {
5957                 info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
5958                 if (!info.dirmask) {
5959                         goto cleanup;
5960                 }
5961                 strncpy(info.dirmask, text, i+1);
5962                 info.dirmask[i+1] = 0;
5963                 dirmask = talloc_asprintf(ctx,
5964                                         "%s%*s*",
5965                                         client_get_cur_dir(),
5966                                         i-1,
5967                                         text);
5968         } else {
5969                 info.dirmask = SMB_STRDUP("");
5970                 if (!info.dirmask) {
5971                         goto cleanup;
5972                 }
5973                 dirmask = talloc_asprintf(ctx,
5974                                         "%s*",
5975                                         client_get_cur_dir());
5976         }
5977         if (!dirmask) {
5978                 goto cleanup;
5979         }
5980         dirmask = client_clean_name(ctx, dirmask);
5981         if (dirmask == NULL) {
5982                 goto cleanup;
5983         }
5984
5985         status = cli_resolve_path(ctx, "",
5986                                   creds,
5987                                 cli, dirmask, &targetcli, &targetpath);
5988         if (!NT_STATUS_IS_OK(status)) {
5989                 goto cleanup;
5990         }
5991         status = cli_list(targetcli, targetpath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5992                           completion_remote_filter, (void *)&info);
5993         if (!NT_STATUS_IS_OK(status)) {
5994                 goto cleanup;
5995         }
5996
5997         if (info.count == 1) {
5998                 /*
5999                  * No matches at all, NULL indicates there is nothing
6000                  */
6001                 SAFE_FREE(info.matches[0]);
6002                 SAFE_FREE(info.matches);
6003                 TALLOC_FREE(ctx);
6004                 return NULL;
6005         }
6006
6007         if (info.count == 2) {
6008                 /*
6009                  * Exactly one match in matches[1], indicate this is the one
6010                  * in matches[0].
6011                  */
6012                 info.matches[0] = info.matches[1];
6013                 info.matches[1] = NULL;
6014                 info.count -= 1;
6015                 TALLOC_FREE(ctx);
6016                 return info.matches;
6017         }
6018
6019         /*
6020          * We got more than one possible match, set the result to the maximum
6021          * common subset
6022          */
6023
6024         info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
6025         info.matches[info.count] = NULL;
6026         TALLOC_FREE(ctx);
6027         return info.matches;
6028
6029 cleanup:
6030         for (i = 0; i < info.count; i++) {
6031                 SAFE_FREE(info.matches[i]);
6032         }
6033         SAFE_FREE(info.matches);
6034         SAFE_FREE(info.dirmask);
6035         TALLOC_FREE(ctx);
6036         return NULL;
6037 }
6038
6039 static char **completion_fn(const char *text, int start, int end)
6040 {
6041         smb_readline_ca_char(' ');
6042
6043         if (start) {
6044                 const char *buf, *sp;
6045                 int i;
6046                 char compl_type;
6047
6048                 buf = smb_readline_get_line_buffer();
6049                 if (buf == NULL)
6050                         return NULL;
6051
6052                 sp = strchr(buf, ' ');
6053                 if (sp == NULL)
6054                         return NULL;
6055
6056                 for (i = 0; commands[i].name; i++) {
6057                         if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
6058                             (commands[i].name[sp - buf] == 0)) {
6059                                 break;
6060                         }
6061                 }
6062                 if (commands[i].name == NULL)
6063                         return NULL;
6064
6065                 while (*sp == ' ')
6066                         sp++;
6067
6068                 if (sp == (buf + start))
6069                         compl_type = commands[i].compl_args[0];
6070                 else
6071                         compl_type = commands[i].compl_args[1];
6072
6073                 if (compl_type == COMPL_REMOTE)
6074                         return remote_completion(text, end - start);
6075                 else /* fall back to local filename completion */
6076                         return NULL;
6077         } else {
6078                 char **matches;
6079                 size_t i, len, samelen = 0, count=1;
6080
6081                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
6082                 if (!matches) {
6083                         return NULL;
6084                 }
6085                 matches[0] = NULL;
6086
6087                 len = strlen(text);
6088                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
6089                         if (strncmp(text, commands[i].name, len) == 0) {
6090                                 matches[count] = SMB_STRDUP(commands[i].name);
6091                                 if (!matches[count])
6092                                         goto cleanup;
6093                                 if (count == 1)
6094                                         samelen = strlen(matches[count]);
6095                                 else
6096                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
6097                                                 samelen--;
6098                                 count++;
6099                         }
6100                 }
6101
6102                 switch (count) {
6103                 case 0: /* should never happen */
6104                 case 1:
6105                         goto cleanup;
6106                 case 2:
6107                         matches[0] = SMB_STRDUP(matches[1]);
6108                         break;
6109                 default:
6110                         matches[0] = (char *)SMB_MALLOC(samelen+1);
6111                         if (!matches[0])
6112                                 goto cleanup;
6113                         strncpy(matches[0], matches[1], samelen);
6114                         matches[0][samelen] = 0;
6115                 }
6116                 matches[count] = NULL;
6117                 return matches;
6118
6119 cleanup:
6120                 for (i = 0; i < count; i++)
6121                         free(matches[i]);
6122
6123                 free(matches);
6124                 return NULL;
6125         }
6126 }
6127
6128 static bool finished;
6129
6130 /****************************************************************************
6131  Make sure we swallow keepalives during idle time.
6132 ****************************************************************************/
6133
6134 static void readline_callback(void)
6135 {
6136         static time_t last_t;
6137         struct timespec now;
6138         time_t t;
6139         NTSTATUS status;
6140         unsigned char garbage[16];
6141
6142         clock_gettime_mono(&now);
6143         t = now.tv_sec;
6144
6145         if (t - last_t < 5)
6146                 return;
6147
6148         last_t = t;
6149
6150         /* Ping the server to keep the connection alive using SMBecho. */
6151         memset(garbage, 0xf0, sizeof(garbage));
6152         status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
6153         if (NT_STATUS_IS_OK(status) ||
6154                         NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
6155                 /*
6156                  * Even if server returns NT_STATUS_INVALID_PARAMETER
6157                  * it still responded.
6158                  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
6159                  */
6160                 return;
6161         }
6162
6163         if (!cli_state_is_connected(cli)) {
6164                 DEBUG(0,("SMBecho failed (%s). The connection is "
6165                          "disconnected now\n", nt_errstr(status)));
6166                 finished = true;
6167                 smb_readline_done();
6168         }
6169 }
6170
6171 /****************************************************************************
6172  Process commands on stdin.
6173 ****************************************************************************/
6174
6175 static int process_stdin(void)
6176 {
6177         int rc = 0;
6178
6179         if (!quiet) {
6180                 d_printf("Try \"help\" to get a list of possible commands.\n");
6181         }
6182
6183         while (!finished) {
6184                 TALLOC_CTX *frame = talloc_stackframe();
6185                 char *tok = NULL;
6186                 char *the_prompt = NULL;
6187                 char *line = NULL;
6188                 int i;
6189
6190                 /* display a prompt */
6191                 the_prompt = talloc_asprintf(frame,
6192                                              "smb: %s> ",
6193                                              client_get_cur_dir());
6194                 if (the_prompt == NULL) {
6195                         TALLOC_FREE(frame);
6196                         break;
6197                 }
6198                 line = smb_readline(the_prompt, readline_callback, completion_fn);
6199                 if (!line) {
6200                         TALLOC_FREE(frame);
6201                         break;
6202                 }
6203
6204                 /* special case - first char is ! */
6205                 if (*line == '!') {
6206                         if (system(line + 1) == -1) {
6207                                 d_printf("system() command %s failed.\n",
6208                                         line+1);
6209                         }
6210                         SAFE_FREE(line);
6211                         TALLOC_FREE(frame);
6212                         continue;
6213                 }
6214
6215                 /* and get the first part of the command */
6216                 cmd_ptr = line;
6217                 if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
6218                         TALLOC_FREE(frame);
6219                         SAFE_FREE(line);
6220                         continue;
6221                 }
6222
6223                 if ((i = process_tok(tok)) >= 0) {
6224                         rc = commands[i].fn();
6225                 } else if (i == -2) {
6226                         d_printf("%s: command abbreviation ambiguous\n",tok);
6227                 } else {
6228                         d_printf("%s: command not found\n",tok);
6229                 }
6230                 SAFE_FREE(line);
6231                 TALLOC_FREE(frame);
6232         }
6233         return rc;
6234 }
6235
6236 /****************************************************************************
6237  Process commands from the client.
6238 ****************************************************************************/
6239
6240 static int process(const char *base_directory)
6241 {
6242         int rc = 0;
6243         NTSTATUS status;
6244         struct cli_credentials *creds = samba_cmdline_get_creds();
6245
6246         status = cli_cm_open(talloc_tos(), NULL,
6247                              desthost,
6248                              service,
6249                              creds,
6250                              have_ip ? &dest_ss : NULL, port,
6251                              name_type, &cli);
6252         if (!NT_STATUS_IS_OK(status)) {
6253                 return 1;
6254         }
6255
6256         cli_set_timeout(cli, io_timeout*1000);
6257
6258         if (base_directory && *base_directory) {
6259                 rc = do_cd(base_directory);
6260                 if (rc) {
6261                         cli_shutdown(cli);
6262                         return rc;
6263                 }
6264         }
6265
6266         if (cmdstr) {
6267                 rc = process_command_string(cmdstr);
6268         } else {
6269                 process_stdin();
6270         }
6271
6272         cli_shutdown(cli);
6273         return rc;
6274 }
6275
6276 /****************************************************************************
6277  Handle a -L query.
6278 ****************************************************************************/
6279
6280 static int do_host_query(struct loadparm_context *lp_ctx,
6281                          const char *query_host)
6282 {
6283         NTSTATUS status;
6284         struct cli_credentials *creds = samba_cmdline_get_creds();
6285
6286         status = cli_cm_open(talloc_tos(), NULL,
6287                              query_host,
6288                              "IPC$",
6289                              creds,
6290                              have_ip ? &dest_ss : NULL, port,
6291                              name_type, &cli);
6292         if (!NT_STATUS_IS_OK(status)) {
6293                 return 1;
6294         }
6295
6296         cli_set_timeout(cli, io_timeout*1000);
6297         browse_host(true);
6298
6299         /* Ensure that the host can do IPv4 */
6300
6301         if (!interpret_addr(query_host)) {
6302                 struct sockaddr_storage ss;
6303                 if (interpret_string_addr(&ss, query_host, 0) &&
6304                                 (ss.ss_family != AF_INET)) {
6305                         d_printf("%s is an IPv6 address -- no workgroup available\n",
6306                                 query_host);
6307                         return 1;
6308                 }
6309         }
6310
6311         if (lp_client_min_protocol() > PROTOCOL_NT1) {
6312                 d_printf("SMB1 disabled -- no workgroup available\n");
6313                 goto out;
6314         }
6315
6316         if (lp_disable_netbios()) {
6317                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
6318                 goto out;
6319         }
6320
6321         if (port != NBT_SMB_PORT ||
6322             smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1)
6323         {
6324                 /*
6325                  * Workgroups simply don't make sense over anything
6326                  * else but port 139 and SMB1.
6327                  */
6328
6329                 cli_shutdown(cli);
6330                 d_printf("Reconnecting with SMB1 for workgroup listing.\n");
6331                 lpcfg_set_cmdline(lp_ctx, "client max protocol", "NT1");
6332                 status = cli_cm_open(talloc_tos(), NULL,
6333                                      query_host,
6334                                      "IPC$",
6335                                      creds,
6336                                      have_ip ? &dest_ss : NULL, NBT_SMB_PORT,
6337                                      name_type, &cli);
6338                 if (!NT_STATUS_IS_OK(status)) {
6339                         d_printf("Unable to connect with SMB1 "
6340                                  "-- no workgroup available\n");
6341                         return 0;
6342                 }
6343         }
6344
6345         cli_set_timeout(cli, io_timeout*1000);
6346         list_servers(lp_workgroup());
6347 out:
6348         cli_shutdown(cli);
6349
6350         return(0);
6351 }
6352
6353 /****************************************************************************
6354  Handle a tar operation.
6355 ****************************************************************************/
6356
6357 static int do_tar_op(const char *base_directory)
6358 {
6359         struct tar *tar_ctx = tar_get_ctx();
6360         int ret = 0;
6361         struct cli_credentials *creds = samba_cmdline_get_creds();
6362
6363         /* do we already have a connection? */
6364         if (!cli) {
6365                 NTSTATUS status;
6366
6367                 status = cli_cm_open(talloc_tos(), NULL,
6368                                      desthost,
6369                                      service,
6370                                      creds,
6371                                      have_ip ? &dest_ss : NULL, port,
6372                                      name_type, &cli);
6373                 if (!NT_STATUS_IS_OK(status)) {
6374             ret = 1;
6375             goto out;
6376                 }
6377                 cli_set_timeout(cli, io_timeout*1000);
6378         }
6379
6380         recurse = true;
6381
6382         if (base_directory && *base_directory)  {
6383                 ret = do_cd(base_directory);
6384                 if (ret) {
6385             goto out_cli;
6386                 }
6387         }
6388
6389         ret = tar_process(tar_ctx);
6390
6391  out_cli:
6392         cli_shutdown(cli);
6393  out:
6394         return ret;
6395 }
6396
6397 /****************************************************************************
6398  Handle a message operation.
6399 ****************************************************************************/
6400
6401 static int do_message_op(struct cli_credentials *creds)
6402 {
6403         NTSTATUS status;
6404
6405         if (lp_disable_netbios()) {
6406                 d_printf("NetBIOS over TCP disabled.\n");
6407                 return 1;
6408         }
6409
6410         status = cli_connect_nb(talloc_tos(),
6411                                 desthost, have_ip ? &dest_ss : NULL,
6412                                 port ? port : NBT_SMB_PORT, name_type,
6413                                 lp_netbios_name(),
6414                                 SMB_SIGNING_OFF,
6415                                 0,
6416                                 &cli);
6417         if (!NT_STATUS_IS_OK(status)) {
6418                 d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
6419                 return 1;
6420         }
6421
6422         cli_set_timeout(cli, io_timeout*1000);
6423         send_message(cli_credentials_get_username(creds));
6424         cli_shutdown(cli);
6425
6426         return 0;
6427 }
6428
6429 /****************************************************************************
6430   main program
6431 ****************************************************************************/
6432
6433 int main(int argc,char *argv[])
6434 {
6435         const char **const_argv = discard_const_p(const char *, argv);
6436         char *base_directory = NULL;
6437         int opt;
6438         char *query_host = NULL;
6439         bool message = false;
6440         static const char *new_name_resolve_order = NULL;
6441         poptContext pc;
6442         char *p;
6443         int rc = 0;
6444         bool tar_opt = false;
6445         bool service_opt = false;
6446         struct tar *tar_ctx = tar_get_ctx();
6447         bool ok;
6448
6449         struct poptOption long_options[] = {
6450                 POPT_AUTOHELP
6451
6452                 {
6453                         .longName   = "message",
6454                         .shortName  = 'M',
6455                         .argInfo    = POPT_ARG_STRING,
6456                         .arg        = NULL,
6457                         .val        = 'M',
6458                         .descrip    = "Send message",
6459                         .argDescrip = "HOST",
6460                 },
6461                 {
6462                         .longName   = "ip-address",
6463                         .shortName  = 'I',
6464                         .argInfo    = POPT_ARG_STRING,
6465                         .arg        = NULL,
6466                         .val        = 'I',
6467                         .descrip    = "Use this IP to connect to",
6468                         .argDescrip = "IP",
6469                 },
6470                 {
6471                         .longName   = "stderr",
6472                         .shortName  = 'E',
6473                         .argInfo    = POPT_ARG_NONE,
6474                         .arg        = NULL,
6475                         .val        = 'E',
6476                         .descrip    = "Write messages to stderr instead of stdout",
6477                 },
6478                 {
6479                         .longName   = "list",
6480                         .shortName  = 'L',
6481                         .argInfo    = POPT_ARG_STRING,
6482                         .arg        = NULL,
6483                         .val        = 'L',
6484                         .descrip    = "Get a list of shares available on a host",
6485                         .argDescrip = "HOST",
6486                 },
6487                 {
6488                         .longName   = "tar",
6489                         .shortName  = 'T',
6490                         .argInfo    = POPT_ARG_STRING,
6491                         .arg        = NULL,
6492                         .val        = 'T',
6493                         .descrip    = "Command line tar",
6494                         .argDescrip = "<c|x>IXFvgbNan",
6495                 },
6496                 {
6497                         .longName   = "directory",
6498                         .shortName  = 'D',
6499                         .argInfo    = POPT_ARG_STRING,
6500                         .arg        = NULL,
6501                         .val        = 'D',
6502                         .descrip    = "Start from directory",
6503                         .argDescrip = "DIR",
6504                 },
6505                 {
6506                         .longName   = "command",
6507                         .shortName  = 'c',
6508                         .argInfo    = POPT_ARG_STRING,
6509                         .arg        = &cmdstr,
6510                         .val        = 'c',
6511                         .descrip    = "Execute semicolon separated commands",
6512                 },
6513                 {
6514                         .longName   = "send-buffer",
6515                         .shortName  = 'b',
6516                         .argInfo    = POPT_ARG_INT,
6517                         .arg        = &io_bufsize,
6518                         .val        = 'b',
6519                         .descrip    = "Changes the transmit/send buffer",
6520                         .argDescrip = "BYTES",
6521                 },
6522                 {
6523                         .longName   = "timeout",
6524                         .shortName  = 't',
6525                         .argInfo    = POPT_ARG_INT,
6526                         .arg        = &io_timeout,
6527                         .val        = 'b',
6528                         .descrip    = "Changes the per-operation timeout",
6529                         .argDescrip = "SECONDS",
6530                 },
6531                 {
6532                         .longName   = "port",
6533                         .shortName  = 'p',
6534                         .argInfo    = POPT_ARG_INT,
6535                         .arg        = &port,
6536                         .val        = 'p',
6537                         .descrip    = "Port to connect to",
6538                         .argDescrip = "PORT",
6539                 },
6540                 {
6541                         .longName   = "grepable",
6542                         .shortName  = 'g',
6543                         .argInfo    = POPT_ARG_NONE,
6544                         .arg        = NULL,
6545                         .val        = 'g',
6546                         .descrip    = "Produce grepable output",
6547                 },
6548                 {
6549                         .longName   = "quiet",
6550                         .shortName  = 'q',
6551                         .argInfo    = POPT_ARG_NONE,
6552                         .arg        = NULL,
6553                         .val        = 'q',
6554                         .descrip    = "Suppress help message",
6555                 },
6556                 {
6557                         .longName   = "browse",
6558                         .shortName  = 'B',
6559                         .argInfo    = POPT_ARG_NONE,
6560                         .arg        = NULL,
6561                         .val        = 'B',
6562                         .descrip    = "Browse SMB servers using DNS",
6563                 },
6564                 POPT_COMMON_SAMBA
6565                 POPT_COMMON_CONNECTION
6566                 POPT_COMMON_CREDENTIALS
6567                 POPT_LEGACY_S3
6568                 POPT_COMMON_VERSION
6569                 POPT_TABLEEND
6570         };
6571         TALLOC_CTX *frame = talloc_stackframe();
6572         struct cli_credentials *creds = NULL;
6573         struct loadparm_context *lp_ctx = NULL;
6574
6575         if (!client_set_cur_dir("\\")) {
6576                 exit(ENOMEM);
6577         }
6578
6579         smb_init_locale();
6580
6581         ok = samba_cmdline_init(frame,
6582                                 SAMBA_CMDLINE_CONFIG_CLIENT,
6583                                 false /* require_smbconf */);
6584         if (!ok) {
6585                 DBG_ERR("Failed to init cmdline parser!\n");
6586                 exit(ENOMEM);
6587         }
6588         lp_ctx = samba_cmdline_get_lp_ctx();
6589         lpcfg_set_cmdline(lp_ctx, "log level", "1");
6590
6591         /* skip argv(0) */
6592         pc = samba_popt_get_context(getprogname(),
6593                                     argc,
6594                                     const_argv,
6595                                     long_options,
6596                                     0);
6597         if (pc == NULL) {
6598                 DBG_ERR("Failed to setup popt context!\n");
6599                 exit(1);
6600         }
6601
6602         poptSetOtherOptionHelp(pc, "[OPTIONS] service <password>");
6603
6604         creds = samba_cmdline_get_creds();
6605         while ((opt = poptGetNextOpt(pc)) != -1) {
6606
6607                 /*
6608                  * if the tar option has been called previously, now
6609                  * we need to eat out the leftovers
6610                  */
6611                 /* I see no other way to keep things sane --SSS */
6612                 if (tar_opt == true) {
6613                         while (poptPeekArg(pc)) {
6614                                 poptGetArg(pc);
6615                         }
6616                         tar_opt = false;
6617                 }
6618
6619                 /* if the service has not yet been specified lets see if it is available in the popt stack */
6620                 if (!service_opt && poptPeekArg(pc)) {
6621                         service = talloc_strdup(frame, poptGetArg(pc));
6622                         if (!service) {
6623                                 exit(ENOMEM);
6624                         }
6625                         service_opt = true;
6626                 }
6627
6628                 /* if the service has already been retrieved then check if we have also a password */
6629                 if (service_opt &&
6630                     cli_credentials_get_password(creds) == NULL &&
6631                     poptPeekArg(pc)) {
6632                         cli_credentials_set_password(creds,
6633                                                      poptGetArg(pc),
6634                                                      CRED_SPECIFIED);
6635                 }
6636
6637
6638                 switch (opt) {
6639                 case 'M':
6640                         /* Messages are sent to NetBIOS name type 0x3
6641                          * (Messenger Service).  Make sure we default
6642                          * to port 139 instead of port 445. srl,crh
6643                          */
6644                         name_type = 0x03;
6645                         desthost = talloc_strdup(frame,poptGetOptArg(pc));
6646                         if (!desthost) {
6647                                 exit(ENOMEM);
6648                         }
6649                         if( !port )
6650                                 port = NBT_SMB_PORT;
6651                         message = true;
6652                         break;
6653                 case 'I':
6654                         {
6655                                 if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
6656                                         exit(1);
6657                                 }
6658                                 have_ip = true;
6659                                 print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
6660                         }
6661                         break;
6662                 case 'E':
6663                         setup_logging("smbclient", DEBUG_STDERR );
6664                         display_set_stderr();
6665                         break;
6666
6667                 case 'L':
6668                         query_host = talloc_strdup(frame, poptGetOptArg(pc));
6669                         if (!query_host) {
6670                                 exit(ENOMEM);
6671                         }
6672                         break;
6673                 case 'T':
6674                         /* We must use old option processing for this. Find the
6675                          * position of the -T option in the raw argv[]. */
6676                         {
6677                                 int i;
6678
6679                                 for (i = 1; i < argc; i++) {
6680                                         if (strncmp("-T", argv[i],2)==0)
6681                                                 break;
6682                                 }
6683                                 i++;
6684                                 if (tar_parse_args(tar_ctx, poptGetOptArg(pc),
6685                                                    const_argv + i, argc - i)) {
6686                                         poptPrintUsage(pc, stderr, 0);
6687                                         exit(1);
6688                                 }
6689                         }
6690                         /* this must be the last option, mark we have parsed it so that we know we have */
6691                         tar_opt = true;
6692                         break;
6693                 case 'D':
6694                         base_directory = talloc_strdup(frame, poptGetOptArg(pc));
6695                         if (!base_directory) {
6696                                 exit(ENOMEM);
6697                         }
6698                         break;
6699                 case 'g':
6700                         grepable=true;
6701                         break;
6702                 case 'q':
6703                         quiet=true;
6704                         break;
6705                 case 'B':
6706                         return(do_smb_browse());
6707                 case POPT_ERROR_BADOPT:
6708                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
6709                                 poptBadOption(pc, 0), poptStrerror(opt));
6710                         poptPrintUsage(pc, stderr, 0);
6711                         exit(1);
6712                 }
6713         }
6714
6715         /* We may still have some leftovers after the last popt option has been called */
6716         if (tar_opt == true) {
6717                 while (poptPeekArg(pc)) {
6718                         poptGetArg(pc);
6719                 }
6720                 tar_opt = false;
6721         }
6722
6723         /* if the service has not yet been specified lets see if it is available in the popt stack */
6724         if (!service_opt && poptPeekArg(pc)) {
6725                 service = talloc_strdup(frame,poptGetArg(pc));
6726                 if (!service) {
6727                         exit(ENOMEM);
6728                 }
6729                 service_opt = true;
6730         }
6731
6732         /* if the service has already been retrieved then check if we have also a password */
6733         if (service_opt &&
6734             cli_credentials_get_password(creds) == NULL &&
6735             poptPeekArg(pc)) {
6736                 cli_credentials_set_password(creds,
6737                                              poptGetArg(pc),
6738                                              CRED_SPECIFIED);
6739         }
6740
6741         if (service_opt && service) {
6742                 size_t len;
6743
6744                 /* Convert any '/' characters in the service name to '\' characters */
6745                 string_replace(service, '/','\\');
6746                 if (count_chars(service,'\\') < 3) {
6747                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
6748                         poptPrintUsage(pc, stderr, 0);
6749                         exit(1);
6750                 }
6751                 /* Remove trailing slashes */
6752                 len = strlen(service);
6753                 while(len > 0 && service[len - 1] == '\\') {
6754                         --len;
6755                         service[len] = '\0';
6756                 }
6757         }
6758
6759         if(new_name_resolve_order)
6760                 lpcfg_set_cmdline(lp_ctx,
6761                                   "name resolve order",
6762                                   new_name_resolve_order);
6763
6764         if (!tar_to_process(tar_ctx) && !query_host && !service && !message) {
6765                 poptPrintUsage(pc, stderr, 0);
6766                 exit(1);
6767         }
6768
6769         poptFreeContext(pc);
6770         samba_cmdline_burn(argc, argv);
6771
6772         DEBUG(3,("Client started (version %s).\n", samba_version_string()));
6773
6774         if (tar_to_process(tar_ctx)) {
6775                 if (cmdstr)
6776                         process_command_string(cmdstr);
6777                 rc = do_tar_op(base_directory);
6778         } else if (query_host && *query_host) {
6779                 char *qhost = query_host;
6780                 char *slash;
6781
6782                 while (*qhost == '\\' || *qhost == '/')
6783                         qhost++;
6784
6785                 if ((slash = strchr_m(qhost, '/'))
6786                     || (slash = strchr_m(qhost, '\\'))) {
6787                         *slash = 0;
6788                 }
6789
6790                 if ((p=strchr_m(qhost, '#'))) {
6791                         *p = 0;
6792                         p++;
6793                         sscanf(p, "%x", &name_type);
6794                 }
6795
6796                 rc = do_host_query(lp_ctx, qhost);
6797         } else if (message) {
6798                 rc = do_message_op(creds);
6799         } else if (process(base_directory)) {
6800                 rc = 1;
6801         }
6802
6803         gfree_all();
6804
6805         TALLOC_FREE(frame);
6806         return rc;
6807 }