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