9db8ff657177d969ff5cedccf76de4405e5f6917
[metze/samba/wip.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[PATH_MAX+1];
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, linkname, PATH_MAX+1);
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         return 0;
3532 }
3533
3534
3535 /****************************************************************************
3536  UNIX symlink.
3537 ****************************************************************************/
3538
3539 static int cmd_symlink(void)
3540 {
3541         TALLOC_CTX *ctx = talloc_tos();
3542         char *link_target = NULL;
3543         char *newname = NULL;
3544         char *buf = NULL;
3545         char *buf2 = NULL;
3546         struct cli_state *newcli;
3547         NTSTATUS status;
3548
3549         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3550             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3551                 d_printf("symlink <link_target> <newname>\n");
3552                 return 1;
3553         }
3554         /* Oldname (link target) must be an untouched blob. */
3555         link_target = buf;
3556
3557         if (SERVER_HAS_UNIX_CIFS(cli)) {
3558                 newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(),
3559                                           buf2);
3560                 if (!newname) {
3561                         return 1;
3562                 }
3563                 newname = client_clean_name(ctx, newname);
3564                 if (newname == NULL) {
3565                         return 1;
3566                 }
3567                 /* New name must be present in share namespace. */
3568                 status = cli_resolve_path(ctx, "",
3569                                 popt_get_cmdline_auth_info(), cli, newname,
3570                                 &newcli, &newname);
3571                 if (!NT_STATUS_IS_OK(status)) {
3572                         d_printf("link %s: %s\n", newname,
3573                                 nt_errstr(status));
3574                         return 1;
3575                 }
3576                 status = cli_posix_symlink(newcli, link_target, newname);
3577         } else {
3578                 status = cli_symlink(
3579                         cli, link_target, buf2,
3580                         buf2[0] == '\\' ? 0 : SYMLINK_FLAG_RELATIVE);
3581         }
3582
3583         if (!NT_STATUS_IS_OK(status)) {
3584                 d_printf("%s symlinking files (%s -> %s)\n",
3585                          nt_errstr(status), newname, link_target);
3586                 return 1;
3587         }
3588
3589         return 0;
3590 }
3591
3592 /****************************************************************************
3593  UNIX chmod.
3594 ****************************************************************************/
3595
3596 static int cmd_chmod(void)
3597 {
3598         TALLOC_CTX *ctx = talloc_tos();
3599         char *src = NULL;
3600         char *buf = NULL;
3601         char *buf2 = NULL;
3602         char *targetname = NULL;
3603         struct cli_state *targetcli;
3604         mode_t mode;
3605         NTSTATUS status;
3606
3607         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3608             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3609                 d_printf("chmod mode file\n");
3610                 return 1;
3611         }
3612         src = talloc_asprintf(ctx,
3613                         "%s%s",
3614                         client_get_cur_dir(),
3615                         buf2);
3616         if (!src) {
3617                 return 1;
3618         }
3619         src = client_clean_name(ctx, src);
3620         if (src == NULL) {
3621                 return 1;
3622         }
3623
3624         mode = (mode_t)strtol(buf, NULL, 8);
3625
3626         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3627                         cli, src, &targetcli, &targetname);
3628         if (!NT_STATUS_IS_OK(status)) {
3629                 d_printf("chmod %s: %s\n", src, nt_errstr(status));
3630                 return 1;
3631         }
3632
3633         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3634                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3635                 return 1;
3636         }
3637
3638         status = cli_posix_chmod(targetcli, targetname, mode);
3639         if (!NT_STATUS_IS_OK(status)) {
3640                 d_printf("%s chmod file %s 0%o\n",
3641                          nt_errstr(status), src, (unsigned int)mode);
3642                 return 1;
3643         }
3644
3645         return 0;
3646 }
3647
3648 static const char *filetype_to_str(mode_t mode)
3649 {
3650         if (S_ISREG(mode)) {
3651                 return "regular file";
3652         } else if (S_ISDIR(mode)) {
3653                 return "directory";
3654         } else
3655 #ifdef S_ISCHR
3656         if (S_ISCHR(mode)) {
3657                 return "character device";
3658         } else
3659 #endif
3660 #ifdef S_ISBLK
3661         if (S_ISBLK(mode)) {
3662                 return "block device";
3663         } else
3664 #endif
3665 #ifdef S_ISFIFO
3666         if (S_ISFIFO(mode)) {
3667                 return "fifo";
3668         } else
3669 #endif
3670 #ifdef S_ISLNK
3671         if (S_ISLNK(mode)) {
3672                 return "symbolic link";
3673         } else
3674 #endif
3675 #ifdef S_ISSOCK
3676         if (S_ISSOCK(mode)) {
3677                 return "socket";
3678         } else
3679 #endif
3680         return "";
3681 }
3682
3683 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3684 {
3685         if (m & bt) {
3686                 return ret;
3687         } else {
3688                 return '-';
3689         }
3690 }
3691
3692 static char *unix_mode_to_str(char *s, mode_t m)
3693 {
3694         char *p = s;
3695         const char *str = filetype_to_str(m);
3696
3697         switch(str[0]) {
3698                 case 'd':
3699                         *p++ = 'd';
3700                         break;
3701                 case 'c':
3702                         *p++ = 'c';
3703                         break;
3704                 case 'b':
3705                         *p++ = 'b';
3706                         break;
3707                 case 'f':
3708                         *p++ = 'p';
3709                         break;
3710                 case 's':
3711                         *p++ = str[1] == 'y' ? 'l' : 's';
3712                         break;
3713                 case 'r':
3714                 default:
3715                         *p++ = '-';
3716                         break;
3717         }
3718         *p++ = rwx_to_str(m, S_IRUSR, 'r');
3719         *p++ = rwx_to_str(m, S_IWUSR, 'w');
3720         *p++ = rwx_to_str(m, S_IXUSR, 'x');
3721         *p++ = rwx_to_str(m, S_IRGRP, 'r');
3722         *p++ = rwx_to_str(m, S_IWGRP, 'w');
3723         *p++ = rwx_to_str(m, S_IXGRP, 'x');
3724         *p++ = rwx_to_str(m, S_IROTH, 'r');
3725         *p++ = rwx_to_str(m, S_IWOTH, 'w');
3726         *p++ = rwx_to_str(m, S_IXOTH, 'x');
3727         *p++ = '\0';
3728         return s;
3729 }
3730
3731 /****************************************************************************
3732  Utility function for UNIX getfacl.
3733 ****************************************************************************/
3734
3735 static char *perms_to_string(fstring permstr, unsigned char perms)
3736 {
3737         fstrcpy(permstr, "---");
3738         if (perms & SMB_POSIX_ACL_READ) {
3739                 permstr[0] = 'r';
3740         }
3741         if (perms & SMB_POSIX_ACL_WRITE) {
3742                 permstr[1] = 'w';
3743         }
3744         if (perms & SMB_POSIX_ACL_EXECUTE) {
3745                 permstr[2] = 'x';
3746         }
3747         return permstr;
3748 }
3749
3750 /****************************************************************************
3751  UNIX getfacl.
3752 ****************************************************************************/
3753
3754 static int cmd_getfacl(void)
3755 {
3756         TALLOC_CTX *ctx = talloc_tos();
3757         char *src = NULL;
3758         char *name = NULL;
3759         char *targetname = NULL;
3760         struct cli_state *targetcli;
3761         uint16_t major, minor;
3762         uint32_t caplow, caphigh;
3763         char *retbuf = NULL;
3764         size_t rb_size = 0;
3765         SMB_STRUCT_STAT sbuf;
3766         uint16_t num_file_acls = 0;
3767         uint16_t num_dir_acls = 0;
3768         uint16_t i;
3769         NTSTATUS status;
3770
3771         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3772                 d_printf("getfacl filename\n");
3773                 return 1;
3774         }
3775         src = talloc_asprintf(ctx,
3776                         "%s%s",
3777                         client_get_cur_dir(),
3778                         name);
3779         if (!src) {
3780                 return 1;
3781         }
3782         src = client_clean_name(ctx, src);
3783         if (src == NULL) {
3784                 return 1;
3785         }
3786
3787         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3788                         cli, src, &targetcli, &targetname);
3789         if (!NT_STATUS_IS_OK(status)) {
3790                 d_printf("stat %s: %s\n", src, nt_errstr(status));
3791                 return 1;
3792         }
3793
3794         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3795                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3796                 return 1;
3797         }
3798
3799         status = cli_unix_extensions_version(targetcli, &major, &minor,
3800                                              &caplow, &caphigh);
3801         if (!NT_STATUS_IS_OK(status)) {
3802                 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3803                          nt_errstr(status));
3804                 return 1;
3805         }
3806
3807         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3808                 d_printf("This server supports UNIX extensions "
3809                         "but doesn't support POSIX ACLs.\n");
3810                 return 1;
3811         }
3812
3813         status = cli_posix_stat(targetcli, targetname, &sbuf);
3814         if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
3815                 d_printf("%s getfacl doing a stat on file %s\n",
3816                          nt_errstr(status), src);
3817                 return 1;
3818         }
3819
3820         status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf);
3821         if (!NT_STATUS_IS_OK(status)) {
3822                 d_printf("%s getfacl file %s\n",
3823                          nt_errstr(status), src);
3824                 return 1;
3825         }
3826
3827         /* ToDo : Print out the ACL values. */
3828         if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3829                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3830                         src, (unsigned int)CVAL(retbuf,0) );
3831                 return 1;
3832         }
3833
3834         num_file_acls = SVAL(retbuf,2);
3835         num_dir_acls = SVAL(retbuf,4);
3836         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3837                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3838                         src,
3839                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3840                         (unsigned int)rb_size);
3841                 return 1;
3842         }
3843
3844         d_printf("# file: %s\n", src);
3845         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3846
3847         if (num_file_acls == 0 && num_dir_acls == 0) {
3848                 d_printf("No acls found.\n");
3849         }
3850
3851         for (i = 0; i < num_file_acls; i++) {
3852                 uint32_t uorg;
3853                 fstring permstring;
3854                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3855                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3856
3857                 switch(tagtype) {
3858                         case SMB_POSIX_ACL_USER_OBJ:
3859                                 d_printf("user::");
3860                                 break;
3861                         case SMB_POSIX_ACL_USER:
3862                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3863                                 d_printf("user:%u:", uorg);
3864                                 break;
3865                         case SMB_POSIX_ACL_GROUP_OBJ:
3866                                 d_printf("group::");
3867                                 break;
3868                         case SMB_POSIX_ACL_GROUP:
3869                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3870                                 d_printf("group:%u:", uorg);
3871                                 break;
3872                         case SMB_POSIX_ACL_MASK:
3873                                 d_printf("mask::");
3874                                 break;
3875                         case SMB_POSIX_ACL_OTHER:
3876                                 d_printf("other::");
3877                                 break;
3878                         default:
3879                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3880                                         src, (unsigned int)tagtype );
3881                                 SAFE_FREE(retbuf);
3882                                 return 1;
3883                 }
3884
3885                 d_printf("%s\n", perms_to_string(permstring, perms));
3886         }
3887
3888         for (i = 0; i < num_dir_acls; i++) {
3889                 uint32_t uorg;
3890                 fstring permstring;
3891                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3892                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3893
3894                 switch(tagtype) {
3895                         case SMB_POSIX_ACL_USER_OBJ:
3896                                 d_printf("default:user::");
3897                                 break;
3898                         case SMB_POSIX_ACL_USER:
3899                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3900                                 d_printf("default:user:%u:", uorg);
3901                                 break;
3902                         case SMB_POSIX_ACL_GROUP_OBJ:
3903                                 d_printf("default:group::");
3904                                 break;
3905                         case SMB_POSIX_ACL_GROUP:
3906                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3907                                 d_printf("default:group:%u:", uorg);
3908                                 break;
3909                         case SMB_POSIX_ACL_MASK:
3910                                 d_printf("default:mask::");
3911                                 break;
3912                         case SMB_POSIX_ACL_OTHER:
3913                                 d_printf("default:other::");
3914                                 break;
3915                         default:
3916                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3917                                         src, (unsigned int)tagtype );
3918                                 SAFE_FREE(retbuf);
3919                                 return 1;
3920                 }
3921
3922                 d_printf("%s\n", perms_to_string(permstring, perms));
3923         }
3924
3925         return 0;
3926 }
3927
3928 /****************************************************************************
3929  Get the EA list of a file
3930 ****************************************************************************/
3931
3932 static int cmd_geteas(void)
3933 {
3934         TALLOC_CTX *ctx = talloc_tos();
3935         char *src = NULL;
3936         char *name = NULL;
3937         char *targetname = NULL;
3938         struct cli_state *targetcli;
3939         NTSTATUS status;
3940         size_t i, num_eas;
3941         struct ea_struct *eas;
3942
3943         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3944                 d_printf("geteas filename\n");
3945                 return 1;
3946         }
3947         src = talloc_asprintf(ctx,
3948                         "%s%s",
3949                         client_get_cur_dir(),
3950                         name);
3951         if (!src) {
3952                 return 1;
3953         }
3954         src = client_clean_name(ctx, src);
3955         if (src == NULL) {
3956                 return 1;
3957         }
3958
3959         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3960                         cli, src, &targetcli, &targetname);
3961         if (!NT_STATUS_IS_OK(status)) {
3962                 d_printf("stat %s: %s\n", src, nt_errstr(status));
3963                 return 1;
3964         }
3965
3966         status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
3967                                       &num_eas, &eas);
3968         if (!NT_STATUS_IS_OK(status)) {
3969                 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
3970                 return 1;
3971         }
3972
3973         for (i=0; i<num_eas; i++) {
3974                 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
3975                 dump_data_file(eas[i].value.data, eas[i].value.length, false,
3976                                stdout);
3977                 d_printf("\n");
3978         }
3979
3980         TALLOC_FREE(eas);
3981
3982         return 0;
3983 }
3984
3985 /****************************************************************************
3986  Set an EA of a file
3987 ****************************************************************************/
3988
3989 static int cmd_setea(void)
3990 {
3991         TALLOC_CTX *ctx = talloc_tos();
3992         char *src = NULL;
3993         char *name = NULL;
3994         char *eaname = NULL;
3995         char *eavalue = NULL;
3996         char *targetname = NULL;
3997         struct cli_state *targetcli;
3998         NTSTATUS status;
3999
4000         if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
4001             || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
4002                 d_printf("setea filename eaname value\n");
4003                 return 1;
4004         }
4005         if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
4006                 eavalue = talloc_strdup(ctx, "");
4007         }
4008         src = talloc_asprintf(ctx,
4009                         "%s%s",
4010                         client_get_cur_dir(),
4011                         name);
4012         if (!src) {
4013                 return 1;
4014         }
4015         src = client_clean_name(ctx, src);
4016         if (src == NULL) {
4017                 return 1;
4018         }
4019
4020         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4021                         cli, src, &targetcli, &targetname);
4022         if (!NT_STATUS_IS_OK(status)) {
4023                 d_printf("stat %s: %s\n", src, nt_errstr(status));
4024                 return 1;
4025         }
4026
4027         status =  cli_set_ea_path(targetcli, targetname, eaname, eavalue,
4028                                   strlen(eavalue));
4029         if (!NT_STATUS_IS_OK(status)) {
4030                 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
4031                 return 1;
4032         }
4033
4034         return 0;
4035 }
4036
4037 /****************************************************************************
4038  UNIX stat.
4039 ****************************************************************************/
4040
4041 static int cmd_stat(void)
4042 {
4043         TALLOC_CTX *ctx = talloc_tos();
4044         char *src = NULL;
4045         char *name = NULL;
4046         char *targetname = NULL;
4047         struct cli_state *targetcli;
4048         fstring mode_str;
4049         SMB_STRUCT_STAT sbuf;
4050         struct tm *lt;
4051         time_t tmp_time;
4052         NTSTATUS status;
4053
4054         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
4055                 d_printf("stat file\n");
4056                 return 1;
4057         }
4058         src = talloc_asprintf(ctx,
4059                         "%s%s",
4060                         client_get_cur_dir(),
4061                         name);
4062         if (!src) {
4063                 return 1;
4064         }
4065         src = client_clean_name(ctx, src);
4066         if (src == NULL) {
4067                 return 1;
4068         }
4069
4070         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4071                         cli, src, &targetcli, &targetname);
4072         if (!NT_STATUS_IS_OK(status)) {
4073                 d_printf("stat %s: %s\n", src, nt_errstr(status));
4074                 return 1;
4075         }
4076
4077         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4078                 d_printf("Server doesn't support UNIX CIFS calls.\n");
4079                 return 1;
4080         }
4081
4082         status = cli_posix_stat(targetcli, targetname, &sbuf);
4083         if (!NT_STATUS_IS_OK(status)) {
4084                 d_printf("%s stat file %s\n",
4085                          nt_errstr(status), src);
4086                 return 1;
4087         }
4088
4089         /* Print out the stat values. */
4090         d_printf("File: %s\n", src);
4091         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
4092                 (double)sbuf.st_ex_size,
4093                 (unsigned int)sbuf.st_ex_blocks,
4094                 filetype_to_str(sbuf.st_ex_mode));
4095
4096 #if defined(S_ISCHR) && defined(S_ISBLK)
4097         if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
4098                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
4099                         (double)sbuf.st_ex_ino,
4100                         (unsigned int)sbuf.st_ex_nlink,
4101                         unix_dev_major(sbuf.st_ex_rdev),
4102                         unix_dev_minor(sbuf.st_ex_rdev));
4103         } else
4104 #endif
4105                 d_printf("Inode: %.0f\tLinks: %u\n",
4106                         (double)sbuf.st_ex_ino,
4107                         (unsigned int)sbuf.st_ex_nlink);
4108
4109         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
4110                 ((int)sbuf.st_ex_mode & 0777),
4111                 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
4112                 (unsigned int)sbuf.st_ex_uid,
4113                 (unsigned int)sbuf.st_ex_gid);
4114
4115         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
4116         lt = localtime(&tmp_time);
4117         if (lt) {
4118                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4119         } else {
4120                 fstrcpy(mode_str, "unknown");
4121         }
4122         d_printf("Access: %s\n", mode_str);
4123
4124         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4125         lt = localtime(&tmp_time);
4126         if (lt) {
4127                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4128         } else {
4129                 fstrcpy(mode_str, "unknown");
4130         }
4131         d_printf("Modify: %s\n", mode_str);
4132
4133         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
4134         lt = localtime(&tmp_time);
4135         if (lt) {
4136                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
4137         } else {
4138                 fstrcpy(mode_str, "unknown");
4139         }
4140         d_printf("Change: %s\n", mode_str);
4141
4142         return 0;
4143 }
4144
4145
4146 /****************************************************************************
4147  UNIX chown.
4148 ****************************************************************************/
4149
4150 static int cmd_chown(void)
4151 {
4152         TALLOC_CTX *ctx = talloc_tos();
4153         char *src = NULL;
4154         uid_t uid;
4155         gid_t gid;
4156         char *buf, *buf2, *buf3;
4157         struct cli_state *targetcli;
4158         char *targetname = NULL;
4159         NTSTATUS status;
4160
4161         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4162             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
4163             !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
4164                 d_printf("chown uid gid file\n");
4165                 return 1;
4166         }
4167
4168         uid = (uid_t)atoi(buf);
4169         gid = (gid_t)atoi(buf2);
4170
4171         src = talloc_asprintf(ctx,
4172                         "%s%s",
4173                         client_get_cur_dir(),
4174                         buf3);
4175         if (!src) {
4176                 return 1;
4177         }
4178         src = client_clean_name(ctx, src);
4179         if (src == NULL) {
4180                 return 1;
4181         }
4182         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4183                         cli, src, &targetcli, &targetname);
4184         if (!NT_STATUS_IS_OK(status)) {
4185                 d_printf("chown %s: %s\n", src, nt_errstr(status));
4186                 return 1;
4187         }
4188
4189         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
4190                 d_printf("Server doesn't support UNIX CIFS calls.\n");
4191                 return 1;
4192         }
4193
4194         status = cli_posix_chown(targetcli, targetname, uid, gid);
4195         if (!NT_STATUS_IS_OK(status)) {
4196                 d_printf("%s chown file %s uid=%d, gid=%d\n",
4197                          nt_errstr(status), src, (int)uid, (int)gid);
4198                 return 1;
4199         }
4200
4201         return 0;
4202 }
4203
4204 /****************************************************************************
4205  Rename some file.
4206 ****************************************************************************/
4207
4208 static int cmd_rename(void)
4209 {
4210         TALLOC_CTX *ctx = talloc_tos();
4211         char *src, *dest;
4212         char *buf, *buf2;
4213         struct cli_state *targetcli;
4214         char *targetsrc;
4215         char *targetdest;
4216         NTSTATUS status;
4217         bool replace = false;
4218
4219         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4220             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4221                 d_printf("rename <src> <dest> [-f]\n");
4222                 return 1;
4223         }
4224
4225         src = talloc_asprintf(ctx,
4226                         "%s%s",
4227                         client_get_cur_dir(),
4228                         buf);
4229         if (!src) {
4230                 return 1;
4231         }
4232         src = client_clean_name(ctx, src);
4233         if (src == NULL) {
4234                 return 1;
4235         }
4236
4237         dest = talloc_asprintf(ctx,
4238                         "%s%s",
4239                         client_get_cur_dir(),
4240                         buf2);
4241         if (!dest) {
4242                 return 1;
4243         }
4244         dest = client_clean_name(ctx, dest);
4245         if (dest == NULL) {
4246                 return 1;
4247         }
4248
4249         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
4250             strcsequal(buf, "-f")) {
4251                 replace = true;
4252         }
4253
4254         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4255                         cli, src, &targetcli, &targetsrc);
4256         if (!NT_STATUS_IS_OK(status)) {
4257                 d_printf("rename %s: %s\n", src, nt_errstr(status));
4258                 return 1;
4259         }
4260
4261         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4262                         cli, dest, &targetcli, &targetdest);
4263         if (!NT_STATUS_IS_OK(status)) {
4264                 d_printf("rename %s: %s\n", dest, nt_errstr(status));
4265                 return 1;
4266         }
4267
4268         status = cli_rename(targetcli, targetsrc, targetdest, replace);
4269         if (!NT_STATUS_IS_OK(status)) {
4270                 d_printf("%s renaming files %s -> %s \n",
4271                         nt_errstr(status),
4272                         targetsrc,
4273                         targetdest);
4274                 return 1;
4275         }
4276
4277         return 0;
4278 }
4279
4280 struct scopy_timing {
4281         struct timespec tp_start;
4282 };
4283
4284 static int scopy_status(off_t written, void *priv)
4285 {
4286         struct timespec tp_end;
4287         unsigned int scopy_total_time_ms;
4288         struct scopy_timing *st = priv;
4289
4290         clock_gettime_mono(&tp_end);
4291         scopy_total_time_ms = nsec_time_diff(&tp_end,&st->tp_start)/1000000;
4292
4293         DEBUG(5,("Copied %jd bytes at an average %3.1f kb/s\n",
4294                  (intmax_t)written, written / (1.024*scopy_total_time_ms)));
4295
4296         return true;
4297 }
4298
4299 /****************************************************************************
4300  Server-Side copy some file.
4301 ****************************************************************************/
4302
4303 static int cmd_scopy(void)
4304 {
4305         TALLOC_CTX *ctx = talloc_tos();
4306         char *src, *dest;
4307         char *buf, *buf2;
4308         struct cli_state *targetcli;
4309         char *targetsrc;
4310         char *targetdest;
4311         uint32_t DesiredAccess, ShareAccess, CreateDisposition, CreateOptions;
4312         struct smb_create_returns cr;
4313         uint16_t destfnum = (uint16_t)-1;
4314         uint16_t srcfnum = (uint16_t)-1;
4315         off_t written = 0;
4316         struct scopy_timing st;
4317         int rc = 0;
4318         NTSTATUS status;
4319
4320         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4321                         !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4322                 d_printf("scopy <src> <dest>\n");
4323                 return 1;
4324         }
4325
4326         src = talloc_asprintf(ctx,
4327                         "%s%s",
4328                         client_get_cur_dir(),
4329                         buf);
4330         if (!src) {
4331                 return 1;
4332         }
4333         src = client_clean_name(ctx, src);
4334         if (src == NULL) {
4335                 return 1;
4336         }
4337
4338         dest = talloc_asprintf(ctx,
4339                         "%s%s",
4340                         client_get_cur_dir(),
4341                         buf2);
4342         if (!dest) {
4343                 return 1;
4344         }
4345         dest = client_clean_name(ctx, dest);
4346         if (dest == NULL) {
4347                 return 1;
4348         }
4349
4350         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4351                         cli, src, &targetcli, &targetsrc);
4352         if (!NT_STATUS_IS_OK(status)) {
4353                 d_printf("scopy %s: %s\n", src, nt_errstr(status));
4354                 return 1;
4355         }
4356
4357         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4358                         cli, dest, &targetcli, &targetdest);
4359         if (!NT_STATUS_IS_OK(status)) {
4360                 d_printf("scopy %s: %s\n", dest, nt_errstr(status));
4361                 return 1;
4362         }
4363
4364
4365         DesiredAccess = (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES|
4366                         READ_CONTROL_ACCESS|SYNCHRONIZE_ACCESS);
4367         ShareAccess = FILE_SHARE_READ|FILE_SHARE_DELETE;
4368         CreateDisposition = FILE_OPEN;
4369         CreateOptions = (FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE|
4370                         FILE_OPEN_REPARSE_POINT);
4371         status = cli_ntcreate(targetcli, targetsrc, 0, DesiredAccess, 0,
4372                         ShareAccess, CreateDisposition, CreateOptions, 0x0,
4373                         &srcfnum, &cr);
4374         if (!NT_STATUS_IS_OK(status)) {
4375                 d_printf("Failed to open file %s. %s\n",
4376                                 targetsrc, nt_errstr(status));
4377                 return 1;
4378         }
4379
4380         DesiredAccess = (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_READ_EA|
4381                         FILE_WRITE_EA|FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES|
4382                         DELETE_ACCESS|READ_CONTROL_ACCESS|WRITE_DAC_ACCESS|SYNCHRONIZE_ACCESS);
4383         ShareAccess = FILE_SHARE_NONE;
4384         CreateDisposition = FILE_CREATE;
4385         CreateOptions = FILE_SEQUENTIAL_ONLY|FILE_NON_DIRECTORY_FILE;
4386         status = cli_ntcreate(targetcli, targetdest, 0, DesiredAccess,
4387                         FILE_ATTRIBUTE_ARCHIVE, ShareAccess, CreateDisposition,
4388                         CreateOptions, 0x0, &destfnum, NULL);
4389         if (!NT_STATUS_IS_OK(status)) {
4390                 d_printf("Failed to create file %s. %s\n",
4391                                 targetdest, nt_errstr(status));
4392                 cli_close(targetcli, srcfnum);
4393                 return 1;
4394         }
4395
4396         clock_gettime_mono(&st.tp_start);
4397         status = cli_splice(targetcli, targetcli, srcfnum, destfnum,
4398                         cr.end_of_file, 0, 0, &written, scopy_status, &st);
4399         if (!NT_STATUS_IS_OK(status)) {
4400                 d_printf("%s copying file %s -> %s \n",
4401                                 nt_errstr(status),
4402                                 targetsrc,
4403                                 targetdest);
4404                 rc = 1;
4405         }
4406
4407         status = cli_close(targetcli, srcfnum);
4408         if (!NT_STATUS_IS_OK(status)) {
4409                 d_printf("Error %s closing remote source file\n", nt_errstr(status));
4410                 rc = 1;
4411         }
4412         status = cli_close(targetcli, destfnum);
4413         if (!NT_STATUS_IS_OK(status)) {
4414                 d_printf("Error %s closing remote dest file\n", nt_errstr(status));
4415                 rc = 1;
4416         }
4417
4418         return rc;
4419 }
4420
4421 /****************************************************************************
4422  Print the volume name.
4423 ****************************************************************************/
4424
4425 static int cmd_volume(void)
4426 {
4427         char *volname;
4428         uint32_t serial_num;
4429         time_t create_date;
4430         NTSTATUS status;
4431
4432         status = cli_get_fs_volume_info(cli, talloc_tos(),
4433                                         &volname, &serial_num,
4434                                         &create_date);
4435         if (!NT_STATUS_IS_OK(status)) {
4436                 d_printf("Error %s getting volume info\n", nt_errstr(status));
4437                 return 1;
4438         }
4439
4440         d_printf("Volume: |%s| serial number 0x%x\n",
4441                         volname, (unsigned int)serial_num);
4442         return 0;
4443 }
4444
4445 /****************************************************************************
4446  Hard link files using the NT call.
4447 ****************************************************************************/
4448
4449 static int cmd_hardlink(void)
4450 {
4451         TALLOC_CTX *ctx = talloc_tos();
4452         char *src, *dest;
4453         char *buf, *buf2;
4454         struct cli_state *targetcli;
4455         char *targetname;
4456         NTSTATUS status;
4457
4458         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
4459             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
4460                 d_printf("hardlink <src> <dest>\n");
4461                 return 1;
4462         }
4463
4464         src = talloc_asprintf(ctx,
4465                         "%s%s",
4466                         client_get_cur_dir(),
4467                         buf);
4468         if (!src) {
4469                 return 1;
4470         }
4471         src = client_clean_name(ctx, src);
4472         if (src == NULL) {
4473                 return 1;
4474         }
4475
4476         dest = talloc_asprintf(ctx,
4477                         "%s%s",
4478                         client_get_cur_dir(),
4479                         buf2);
4480         if (!dest) {
4481                 return 1;
4482         }
4483         dest = client_clean_name(ctx, dest);
4484         if (dest == NULL) {
4485                 return 1;
4486         }
4487
4488         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
4489                                 cli, src, &targetcli, &targetname);
4490         if (!NT_STATUS_IS_OK(status)) {
4491                 d_printf("hardlink %s: %s\n", src, nt_errstr(status));
4492                 return 1;
4493         }
4494
4495         status = cli_nt_hardlink(targetcli, targetname, dest);
4496         if (!NT_STATUS_IS_OK(status)) {
4497                 d_printf("%s doing an NT hard link of files\n",
4498                          nt_errstr(status));
4499                 return 1;
4500         }
4501
4502         return 0;
4503 }
4504
4505 /****************************************************************************
4506  Toggle the prompt flag.
4507 ****************************************************************************/
4508
4509 static int cmd_prompt(void)
4510 {
4511         prompt = !prompt;
4512         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
4513         return 1;
4514 }
4515
4516 /****************************************************************************
4517  Set the newer than time.
4518 ****************************************************************************/
4519
4520 static int cmd_newer(void)
4521 {
4522         TALLOC_CTX *ctx = talloc_tos();
4523         char *buf;
4524         bool ok;
4525         SMB_STRUCT_STAT sbuf;
4526
4527         ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
4528         if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
4529                 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
4530                 DEBUG(1,("Getting files newer than %s",
4531                          time_to_asc(newer_than)));
4532         } else {
4533                 newer_than = 0;
4534         }
4535
4536         if (ok && newer_than == 0) {
4537                 d_printf("Error setting newer-than time\n");
4538                 return 1;
4539         }
4540
4541         return 0;
4542 }
4543
4544 /****************************************************************************
4545  Watch directory changes
4546 ****************************************************************************/
4547
4548 static int cmd_notify(void)
4549 {
4550         TALLOC_CTX *frame = talloc_stackframe();
4551         char *name, *buf;
4552         NTSTATUS status;
4553         uint16_t fnum;
4554
4555         name = talloc_strdup(talloc_tos(), client_get_cur_dir());
4556         if (name == NULL) {
4557                 goto fail;
4558         }
4559         if (!next_token_talloc(talloc_tos(), &cmd_ptr, &buf, NULL)) {
4560                 goto usage;
4561         }
4562         name = talloc_asprintf_append(name, "%s", buf);
4563         if (name == NULL) {
4564                 goto fail;
4565         }
4566         name = client_clean_name(talloc_tos(), name);
4567         if (name == NULL) {
4568                 return 1;
4569         }
4570         status = cli_ntcreate(
4571                 cli, name, 0, FILE_READ_DATA, 0,
4572                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
4573                 FILE_OPEN, 0, 0, &fnum, NULL);
4574         if (!NT_STATUS_IS_OK(status)) {
4575                 d_printf("Could not open file: %s\n", nt_errstr(status));
4576                 goto fail;
4577         }
4578
4579         while (1) {
4580                 uint32_t i;
4581                 uint32_t num_changes = 0;
4582                 struct notify_change *changes = NULL;
4583
4584                 status = cli_notify(cli, fnum, 1000, FILE_NOTIFY_CHANGE_ALL,
4585                                     true,
4586                                     talloc_tos(), &num_changes, &changes);
4587                 if (NT_STATUS_EQUAL(status, STATUS_NOTIFY_ENUM_DIR)) {
4588                         printf("NOTIFY_ENUM_DIR\n");
4589                         status = NT_STATUS_OK;
4590                 }
4591                 if (!NT_STATUS_IS_OK(status)) {
4592                         d_printf("notify returned %s\n",
4593                                  nt_errstr(status));
4594                         goto fail;
4595                 }
4596                 for (i=0; i<num_changes; i++) {
4597                         printf("%4.4x %s\n", changes[i].action,
4598                                changes[i].name);
4599                 }
4600                 TALLOC_FREE(changes);
4601         }
4602 usage:
4603         d_printf("notify <dir name>\n");
4604 fail:
4605         TALLOC_FREE(frame);
4606         return 1;
4607 }
4608
4609 /****************************************************************************
4610  Set the archive level.
4611 ****************************************************************************/
4612
4613 static int cmd_archive(void)
4614 {
4615         TALLOC_CTX *ctx = talloc_tos();
4616         char *buf;
4617
4618         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4619                 archive_level = atoi(buf);
4620         } else {
4621                 d_printf("Archive level is %d\n",archive_level);
4622         }
4623
4624         return 0;
4625 }
4626
4627 /****************************************************************************
4628  Toggle the backup_intent state.
4629 ****************************************************************************/
4630
4631 static int cmd_backup(void)
4632 {
4633         backup_intent = !backup_intent;
4634         cli_set_backup_intent(cli, backup_intent);
4635         DEBUG(2,("backup intent is now %s\n",backup_intent?"on":"off"));
4636         return 1;
4637 }
4638
4639 /****************************************************************************
4640  Toggle the lowercaseflag.
4641 ****************************************************************************/
4642
4643 static int cmd_lowercase(void)
4644 {
4645         lowercase = !lowercase;
4646         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
4647         return 0;
4648 }
4649
4650 /****************************************************************************
4651  Toggle the case sensitive flag.
4652 ****************************************************************************/
4653
4654 static int cmd_setcase(void)
4655 {
4656         bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
4657
4658         cli_set_case_sensitive(cli, !orig_case_sensitive);
4659         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
4660                 "on":"off"));
4661         return 0;
4662 }
4663
4664 /****************************************************************************
4665  Toggle the showacls flag.
4666 ****************************************************************************/
4667
4668 static int cmd_showacls(void)
4669 {
4670         showacls = !showacls;
4671         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
4672         return 0;
4673 }
4674
4675
4676 /****************************************************************************
4677  Toggle the recurse flag.
4678 ****************************************************************************/
4679
4680 static int cmd_recurse(void)
4681 {
4682         recurse = !recurse;
4683         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
4684         return 0;
4685 }
4686
4687 /****************************************************************************
4688  Toggle the translate flag.
4689 ****************************************************************************/
4690
4691 static int cmd_translate(void)
4692 {
4693         translation = !translation;
4694         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
4695                  translation?"on":"off"));
4696         return 0;
4697 }
4698
4699 /****************************************************************************
4700  Do the lcd command.
4701  ****************************************************************************/
4702
4703 static int cmd_lcd(void)
4704 {
4705         TALLOC_CTX *ctx = talloc_tos();
4706         char *buf;
4707         char *d;
4708
4709         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4710                 if (chdir(buf) == -1) {
4711                         d_printf("chdir to %s failed (%s)\n",
4712                                 buf, strerror(errno));
4713                 }
4714         }
4715         d = sys_getwd();
4716         if (!d) {
4717                 return 1;
4718         }
4719         DEBUG(2,("the local directory is now %s\n",d));
4720         SAFE_FREE(d);
4721         return 0;
4722 }
4723
4724 /****************************************************************************
4725  Get a file restarting at end of local file.
4726  ****************************************************************************/
4727
4728 static int cmd_reget(void)
4729 {
4730         TALLOC_CTX *ctx = talloc_tos();
4731         char *local_name = NULL;
4732         char *remote_name = NULL;
4733         char *fname = NULL;
4734         char *p = NULL;
4735
4736         remote_name = talloc_strdup(ctx, client_get_cur_dir());
4737         if (!remote_name) {
4738                 return 1;
4739         }
4740
4741         if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
4742                 d_printf("reget <filename>\n");
4743                 return 1;
4744         }
4745         remote_name = talloc_asprintf_append(remote_name, "%s", fname);
4746         if (!remote_name) {
4747                 return 1;
4748         }
4749         remote_name = client_clean_name(ctx,remote_name);
4750         if (!remote_name) {
4751                 return 1;
4752         }
4753
4754         local_name = fname;
4755         next_token_talloc(ctx, &cmd_ptr, &p, NULL);
4756         if (p) {
4757                 local_name = p;
4758         }
4759
4760         return do_get(remote_name, local_name, true);
4761 }
4762
4763 /****************************************************************************
4764  Put a file restarting at end of local file.
4765  ****************************************************************************/
4766
4767 static int cmd_reput(void)
4768 {
4769         TALLOC_CTX *ctx = talloc_tos();
4770         char *local_name = NULL;
4771         char *remote_name = NULL;
4772         char *buf;
4773         SMB_STRUCT_STAT st;
4774
4775         remote_name = talloc_strdup(ctx, client_get_cur_dir());
4776         if (!remote_name) {
4777                 return 1;
4778         }
4779
4780         if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
4781                 d_printf("reput <filename>\n");
4782                 return 1;
4783         }
4784
4785         if (!file_exist_stat(local_name, &st, false)) {
4786                 d_printf("%s does not exist\n", local_name);
4787                 return 1;
4788         }
4789
4790         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
4791                 remote_name = talloc_asprintf_append(remote_name,
4792                                                 "%s", buf);
4793         } else {
4794                 remote_name = talloc_asprintf_append(remote_name,
4795                                                 "%s", local_name);
4796         }
4797         if (!remote_name) {
4798                 return 1;
4799         }
4800
4801         remote_name = client_clean_name(ctx, remote_name);
4802         if (!remote_name) {
4803                 return 1;
4804         }
4805
4806         return do_put(remote_name, local_name, true);
4807 }
4808
4809 /****************************************************************************
4810  List a share name.
4811  ****************************************************************************/
4812
4813 static void browse_fn(const char *name, uint32_t m,
4814                       const char *comment, void *state)
4815 {
4816         const char *typestr = "";
4817
4818         switch (m & 7) {
4819         case STYPE_DISKTREE:
4820                 typestr = "Disk";
4821                 break;
4822         case STYPE_PRINTQ:
4823                 typestr = "Printer";
4824                 break;
4825         case STYPE_DEVICE:
4826                 typestr = "Device";
4827                 break;
4828         case STYPE_IPC:
4829                 typestr = "IPC";
4830                 break;
4831         }
4832         /* FIXME: If the remote machine returns non-ascii characters
4833            in any of these fields, they can corrupt the output.  We
4834            should remove them. */
4835         if (!grepable) {
4836                 d_printf("\t%-15s %-10.10s%s\n",
4837                         name,typestr,comment);
4838         } else {
4839                 d_printf ("%s|%s|%s\n",typestr,name,comment);
4840         }
4841 }
4842
4843 static bool browse_host_rpc(bool sort)
4844 {
4845         NTSTATUS status;
4846         struct rpc_pipe_client *pipe_hnd = NULL;
4847         TALLOC_CTX *frame = talloc_stackframe();
4848         WERROR werr;
4849         struct srvsvc_NetShareInfoCtr info_ctr;
4850         struct srvsvc_NetShareCtr1 ctr1;
4851         uint32_t resume_handle = 0;
4852         uint32_t total_entries = 0;
4853         int i;
4854         struct dcerpc_binding_handle *b;
4855
4856         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc,
4857                                           &pipe_hnd);
4858
4859         if (!NT_STATUS_IS_OK(status)) {
4860                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
4861                            nt_errstr(status)));
4862                 TALLOC_FREE(frame);
4863                 return false;
4864         }
4865
4866         b = pipe_hnd->binding_handle;
4867
4868         ZERO_STRUCT(info_ctr);
4869         ZERO_STRUCT(ctr1);
4870
4871         info_ctr.level = 1;
4872         info_ctr.ctr.ctr1 = &ctr1;
4873
4874         status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
4875                                               pipe_hnd->desthost,
4876                                               &info_ctr,
4877                                               0xffffffff,
4878                                               &total_entries,
4879                                               &resume_handle,
4880                                               &werr);
4881
4882         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4883                 TALLOC_FREE(pipe_hnd);
4884                 TALLOC_FREE(frame);
4885                 return false;
4886         }
4887
4888         for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4889                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4890                 browse_fn(info.name, info.type, info.comment, NULL);
4891         }
4892
4893         TALLOC_FREE(pipe_hnd);
4894         TALLOC_FREE(frame);
4895         return true;
4896 }
4897
4898 /****************************************************************************
4899  Try and browse available connections on a host.
4900 ****************************************************************************/
4901
4902 static bool browse_host(bool sort)
4903 {
4904         int ret;
4905
4906         if (!grepable) {
4907                 d_printf("\n\tSharename       Type      Comment\n");
4908                 d_printf("\t---------       ----      -------\n");
4909         }
4910
4911         if (browse_host_rpc(sort)) {
4912                 return true;
4913         }
4914
4915         if (lp_client_min_protocol() > PROTOCOL_NT1) {
4916                 return false;
4917         }
4918
4919         ret = cli_RNetShareEnum(cli, browse_fn, NULL);
4920         if (ret == -1) {
4921                 NTSTATUS status = cli_nt_error(cli);
4922                 d_printf("Error returning browse list: %s\n",
4923                          nt_errstr(status));
4924         }
4925
4926         return (ret != -1);
4927 }
4928
4929 /****************************************************************************
4930  List a server name.
4931 ****************************************************************************/
4932
4933 static void server_fn(const char *name, uint32_t m,
4934                       const char *comment, void *state)
4935 {
4936
4937         if (!grepable){
4938                 d_printf("\t%-16s     %s\n", name, comment);
4939         } else {
4940                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
4941         }
4942 }
4943
4944 /****************************************************************************
4945  Try and browse available connections on a host.
4946 ****************************************************************************/
4947
4948 static bool list_servers(const char *wk_grp)
4949 {
4950         fstring state;
4951
4952         if (!cli->server_domain)
4953                 return false;
4954
4955         if (!grepable) {
4956                 d_printf("\n\tServer               Comment\n");
4957                 d_printf("\t---------            -------\n");
4958         };
4959         fstrcpy( state, "Server" );
4960         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
4961                           state);
4962
4963         if (!grepable) {
4964                 d_printf("\n\tWorkgroup            Master\n");
4965                 d_printf("\t---------            -------\n");
4966         };
4967
4968         fstrcpy( state, "Workgroup" );
4969         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
4970                           server_fn, state);
4971         return true;
4972 }
4973
4974 /****************************************************************************
4975  Print or set current VUID
4976 ****************************************************************************/
4977
4978 static int cmd_vuid(void)
4979 {
4980         TALLOC_CTX *ctx = talloc_tos();
4981         char *buf;
4982
4983         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4984                 d_printf("Current VUID is %d\n",
4985                          cli_state_get_uid(cli));
4986                 return 0;
4987         }
4988
4989         cli_state_set_uid(cli, atoi(buf));
4990         return 0;
4991 }
4992
4993 /****************************************************************************
4994  Setup a new VUID, by issuing a session setup
4995 ****************************************************************************/
4996
4997 static int cmd_logon(void)
4998 {
4999         TALLOC_CTX *ctx = talloc_tos();
5000         char *l_username, *l_password;
5001         struct cli_credentials *creds = NULL;
5002         NTSTATUS nt_status;
5003
5004         if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
5005                 d_printf("logon <username> [<password>]\n");
5006                 return 0;
5007         }
5008
5009         if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
5010                 char pwd[256] = {0};
5011                 int rc;
5012
5013                 rc = samba_getpass("Password: ", pwd, sizeof(pwd), false, false);
5014                 if (rc == 0) {
5015                         l_password = talloc_strdup(ctx, pwd);
5016                 }
5017         }
5018         if (!l_password) {
5019                 return 1;
5020         }
5021
5022         creds = cli_session_creds_init(ctx,
5023                                        l_username,
5024                                        lp_workgroup(),
5025                                        NULL, /* realm */
5026                                        l_password,
5027                                        false, /* use_kerberos */
5028                                        false, /* fallback_after_kerberos */
5029                                        false, /* use_ccache */
5030                                        false); /* password_is_nt_hash */
5031         if (creds == NULL) {
5032                 d_printf("cli_session_creds_init() failed.\n");
5033                 return -1;
5034         }
5035         nt_status = cli_session_setup_creds(cli, creds);
5036         TALLOC_FREE(creds);
5037         if (!NT_STATUS_IS_OK(nt_status)) {
5038                 d_printf("session setup failed: %s\n", nt_errstr(nt_status));
5039                 return -1;
5040         }
5041
5042         d_printf("Current VUID is %d\n", cli_state_get_uid(cli));
5043         return 0;
5044 }
5045
5046 /**
5047  * close the session
5048  */
5049
5050 static int cmd_logoff(void)
5051 {
5052         NTSTATUS status;
5053
5054         status = cli_ulogoff(cli);
5055         if (!NT_STATUS_IS_OK(status)) {
5056                 d_printf("logoff failed: %s\n", nt_errstr(status));
5057                 return -1;
5058         }
5059
5060         d_printf("logoff successful\n");
5061         return 0;
5062 }
5063
5064
5065 /**
5066  * tree connect (connect to a share)
5067  */
5068
5069 static int cmd_tcon(void)
5070 {
5071         TALLOC_CTX *ctx = talloc_tos();
5072         char *sharename;
5073         NTSTATUS status;
5074
5075         if (!next_token_talloc(ctx, &cmd_ptr, &sharename, NULL)) {
5076                 d_printf("tcon <sharename>\n");
5077                 return 0;
5078         }
5079
5080         if (!sharename) {
5081                 return 1;
5082         }
5083
5084         status = cli_tree_connect(cli, sharename, "?????", NULL);
5085         if (!NT_STATUS_IS_OK(status)) {
5086                 d_printf("tcon failed: %s\n", nt_errstr(status));
5087                 return -1;
5088         }
5089
5090         talloc_free(sharename);
5091
5092         d_printf("tcon to %s successful, tid: %u\n", sharename,
5093                  cli_state_get_tid(cli));
5094         return 0;
5095 }
5096
5097 /**
5098  * tree disconnect (disconnect from a share)
5099  */
5100
5101 static int cmd_tdis(void)
5102 {
5103         NTSTATUS status;
5104
5105         status = cli_tdis(cli);
5106         if (!NT_STATUS_IS_OK(status)) {
5107                 d_printf("tdis failed: %s\n", nt_errstr(status));
5108                 return -1;
5109         }
5110
5111         d_printf("tdis successful\n");
5112         return 0;
5113 }
5114
5115
5116 /**
5117  * get or set tid
5118  */
5119
5120 static int cmd_tid(void)
5121 {
5122         TALLOC_CTX *ctx = talloc_tos();
5123         char *tid_str;
5124
5125         if (!next_token_talloc(ctx, &cmd_ptr, &tid_str, NULL)) {
5126                 if (cli_state_has_tcon(cli)) {
5127                         d_printf("current tid is %d\n", cli_state_get_tid(cli));
5128                 } else {
5129                         d_printf("no tcon currently\n");
5130                 }
5131         } else {
5132                 uint32_t tid = atoi(tid_str);
5133                 if (!cli_state_has_tcon(cli)) {
5134                         d_printf("no tcon currently\n");
5135                 }
5136                 cli_state_set_tid(cli, tid);
5137         }
5138
5139         return 0;
5140 }
5141
5142
5143 /****************************************************************************
5144  list active connections
5145 ****************************************************************************/
5146
5147 static int cmd_list_connect(void)
5148 {
5149         cli_cm_display(cli);
5150         return 0;
5151 }
5152
5153 /****************************************************************************
5154  display the current active client connection
5155 ****************************************************************************/
5156
5157 static int cmd_show_connect( void )
5158 {
5159         TALLOC_CTX *ctx = talloc_tos();
5160         struct cli_state *targetcli;
5161         char *targetpath;
5162         NTSTATUS status;
5163
5164         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), cli,
5165                                   client_get_cur_dir(), &targetcli,
5166                                   &targetpath);
5167         if (!NT_STATUS_IS_OK(status)) {
5168                 d_printf("showconnect %s: %s\n", cur_dir, nt_errstr(status));
5169                 return 1;
5170         }
5171
5172         d_printf("//%s/%s\n", smbXcli_conn_remote_name(targetcli->conn), targetcli->share);
5173         return 0;
5174 }
5175
5176 /**
5177  * set_remote_times - set times of a remote file
5178  * @filename: path to the file name
5179  * @create_time: New create time
5180  * @access_time: New access time
5181  * @write_time: New write time
5182  * @change_time: New metadata change time
5183  *
5184  * Update the file times with the ones provided.
5185  */
5186 static int set_remote_times(const char *filename, time_t create_time,
5187                         time_t access_time, time_t write_time,
5188                         time_t change_time)
5189 {
5190         extern struct cli_state *cli;
5191         NTSTATUS status;
5192
5193         status = cli_setpathinfo_basic(cli, filename, create_time,
5194                                         access_time, write_time,
5195                                         change_time, -1);
5196         if (!NT_STATUS_IS_OK(status)) {
5197                 d_printf("cli_setpathinfo_basic failed: %s\n",
5198                          nt_errstr(status));
5199                 return 1;
5200         }
5201
5202         return 0;
5203 }
5204
5205 /**
5206  * cmd_utimes - interactive command to set the four times
5207  *
5208  * Read a filename and four times from the client command line and update
5209  * the file times. A value of -1 for a time means don't change.
5210  */
5211 static int cmd_utimes(void)
5212 {
5213         const extern char *cmd_ptr;
5214         char *buf;
5215         char *fname = NULL;
5216         time_t times[4] = {0, 0, 0, 0};
5217         int time_count = 0;
5218         int err = 0;
5219         bool ok;
5220         TALLOC_CTX *ctx = talloc_new(NULL);
5221         if (ctx == NULL) {
5222                 return 1;
5223         }
5224
5225         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5226         if (!ok) {
5227                 d_printf("utimes <filename> <create-time> <access-time> "
5228                          "<write-time> <change-time>\n");
5229                 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5230                         "or -1 for no change\n");
5231                 err = 1;
5232                 goto out;
5233         }
5234
5235         fname = talloc_asprintf(ctx,
5236                                 "%s%s",
5237                                 client_get_cur_dir(),
5238                                 buf);
5239         if (fname == NULL) {
5240                 err = 1;
5241                 goto out;
5242         }
5243         fname = client_clean_name(ctx, fname);
5244         if (fname == NULL) {
5245                 err = 1;
5246                 goto out;
5247         }
5248
5249         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL) &&
5250                 time_count < 4) {
5251                 const char *s = buf;
5252                 struct tm tm = {0,};
5253                 char *ret;
5254
5255                 if (strlen(s) == 2 && strcmp(s, "-1") == 0) {
5256                         times[time_count] = 0;
5257                         time_count++;
5258                         continue;
5259                 } else {
5260                         ret = strptime(s, "%y:%m:%d-%H:%M:%S", &tm);
5261                 }
5262
5263                 /* We could not match all the chars, so print error */
5264                 if (ret == NULL || *ret != 0) {
5265                         d_printf("Invalid date format: %s\n", s);
5266                         d_printf("utimes <filename> <create-time> "
5267                                 "<access-time> <write-time> <change-time>\n");
5268                         d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5269                                 "or -1 for no change\n");
5270                         err = 1;
5271                         goto out;
5272                 }
5273
5274                 /* Convert tm to a time_t */
5275                 times[time_count] = mktime(&tm);
5276                 time_count++;
5277         }
5278
5279         if (time_count < 4) {
5280                 d_printf("Insufficient dates: %d\n", time_count);
5281                 d_printf("utimes <filename> <create-time> <access-time> "
5282                         "<write-time> <change-time>\n");
5283                 d_printf("Dates should be in YY:MM:DD-HH:MM:SS format "
5284                         "or -1 for no change\n");
5285                 err = 1;
5286                 goto out;
5287         }
5288
5289         DEBUG(10, ("times\nCreate: %sAccess: %s Write: %sChange: %s\n",
5290                 talloc_strdup(ctx, ctime(&times[0])),
5291                 talloc_strdup(ctx, ctime(&times[1])),
5292                 talloc_strdup(ctx, ctime(&times[2])),
5293                 talloc_strdup(ctx, ctime(&times[3]))));
5294
5295         set_remote_times(fname, times[0], times[1], times[2], times[3]);
5296 out:
5297         talloc_free(ctx);
5298         return err;
5299 }
5300
5301 /**
5302  * set_remote_attr - set DOS attributes of a remote file
5303  * @filename: path to the file name
5304  * @new_attr: attribute bit mask to use
5305  * @mode: one of ATTR_SET or ATTR_UNSET
5306  *
5307  * Update the file attributes with the one provided.
5308  */
5309 int set_remote_attr(const char *filename, uint16_t new_attr, int mode)
5310 {
5311         extern struct cli_state *cli;
5312         uint16_t old_attr;
5313         NTSTATUS status;
5314
5315         status = cli_getatr(cli, filename, &old_attr, NULL, NULL);
5316         if (!NT_STATUS_IS_OK(status)) {
5317                 d_printf("cli_getatr failed: %s\n", nt_errstr(status));
5318                 return 1;
5319         }
5320
5321         if (mode == ATTR_SET) {
5322                 new_attr |= old_attr;
5323         } else {
5324                 new_attr = old_attr & ~new_attr;
5325         }
5326
5327         status = cli_setatr(cli, filename, new_attr, 0);
5328         if (!NT_STATUS_IS_OK(status)) {
5329                 d_printf("cli_setatr failed: %s\n", nt_errstr(status));
5330                 return 1;
5331         }
5332
5333         return 0;
5334 }
5335
5336 /**
5337  * cmd_setmode - interactive command to set DOS attributes
5338  *
5339  * Read a filename and mode from the client command line and update
5340  * the file DOS attributes.
5341  */
5342 int cmd_setmode(void)
5343 {
5344         const extern char *cmd_ptr;
5345         char *buf;
5346         char *fname = NULL;
5347         uint16_t attr[2] = {0};
5348         int mode = ATTR_SET;
5349         int err = 0;
5350         bool ok;
5351         TALLOC_CTX *ctx = talloc_new(NULL);
5352         if (ctx == NULL) {
5353                 return 1;
5354         }
5355
5356         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
5357         if (!ok) {
5358                 d_printf("setmode <filename> <[+|-]rsha>\n");
5359                 err = 1;
5360                 goto out;
5361         }
5362
5363         fname = talloc_asprintf(ctx,
5364                                 "%s%s",
5365                                 client_get_cur_dir(),
5366                                 buf);
5367         if (fname == NULL) {
5368                 err = 1;
5369                 goto out;
5370         }
5371         fname = client_clean_name(ctx, fname);
5372         if (fname == NULL) {
5373                 err = 1;
5374                 goto out;
5375         }
5376
5377         while (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
5378                 const char *s = buf;
5379
5380                 while (*s) {
5381                         switch (*s++) {
5382                         case '+':
5383                                 mode = ATTR_SET;
5384                                 break;
5385                         case '-':
5386                                 mode = ATTR_UNSET;
5387                                 break;
5388                         case 'r':
5389                                 attr[mode] |= FILE_ATTRIBUTE_READONLY;
5390                                 break;
5391                         case 'h':
5392                                 attr[mode] |= FILE_ATTRIBUTE_HIDDEN;
5393                                 break;
5394                         case 's':
5395                                 attr[mode] |= FILE_ATTRIBUTE_SYSTEM;
5396                                 break;
5397                         case 'a':
5398                                 attr[mode] |= FILE_ATTRIBUTE_ARCHIVE;
5399                                 break;
5400                         default:
5401                                 d_printf("setmode <filename> <perm=[+|-]rsha>\n");
5402                                 err = 1;
5403                                 goto out;
5404                         }
5405                 }
5406         }
5407
5408         if (attr[ATTR_SET] == 0 && attr[ATTR_UNSET] == 0) {
5409                 d_printf("setmode <filename> <[+|-]rsha>\n");
5410                 err = 1;
5411                 goto out;
5412         }
5413
5414         DEBUG(2, ("perm set %d %d\n", attr[ATTR_SET], attr[ATTR_UNSET]));
5415
5416         /* ignore return value: server might not store DOS attributes */
5417         set_remote_attr(fname, attr[ATTR_SET], ATTR_SET);
5418         set_remote_attr(fname, attr[ATTR_UNSET], ATTR_UNSET);
5419 out:
5420         talloc_free(ctx);
5421         return err;
5422 }
5423
5424 /****************************************************************************
5425  iosize command
5426 ***************************************************************************/
5427
5428 int cmd_iosize(void)
5429 {
5430         TALLOC_CTX *ctx = talloc_tos();
5431         char *buf;
5432         int iosize;
5433
5434         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5435                 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5436                         if (!smb_encrypt) {
5437                                 d_printf("iosize <n> or iosize 0x<n>. "
5438                                         "Minimum is 0 (default), "
5439                                         "max is 16776960 (0xFFFF00)\n");
5440                         } else {
5441                                 d_printf("iosize <n> or iosize 0x<n>. "
5442                                         "(Encrypted connection) ,"
5443                                         "Minimum is 0 (default), "
5444                                         "max is 130048 (0x1FC00)\n");
5445                         }
5446                 } else {
5447                         d_printf("iosize <n> or iosize 0x<n>.\n");
5448                 }
5449                 return 1;
5450         }
5451
5452         iosize = strtol(buf,NULL,0);
5453         if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
5454                 if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) {
5455                         d_printf("iosize out of range for encrypted "
5456                                 "connection (min = 0 (default), "
5457                                 "max = 130048 (0x1FC00)\n");
5458                         return 1;
5459                 } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) {
5460                         d_printf("iosize out of range (min = 0 (default), "
5461                                 "max = 16776960 (0xFFFF00)\n");
5462                         return 1;
5463                 }
5464         }
5465
5466         io_bufsize = iosize;
5467         d_printf("iosize is now %d\n", io_bufsize);
5468         return 0;
5469 }
5470
5471 /****************************************************************************
5472  timeout command
5473 ***************************************************************************/
5474
5475 static int cmd_timeout(void)
5476 {
5477         TALLOC_CTX *ctx = talloc_tos();
5478         char *buf;
5479
5480         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5481                 unsigned int old_timeout = cli_set_timeout(cli, 0);
5482                 cli_set_timeout(cli, old_timeout);
5483                 d_printf("timeout <n> (per-operation timeout "
5484                         "in seconds - currently %u).\n",
5485                         old_timeout/1000);
5486                 return 1;
5487         }
5488
5489         io_timeout = strtol(buf,NULL,0);
5490         cli_set_timeout(cli, io_timeout*1000);
5491         d_printf("io_timeout per operation is now %d\n", io_timeout);
5492         return 0;
5493 }
5494
5495
5496 /****************************************************************************
5497 history
5498 ****************************************************************************/
5499 static int cmd_history(void)
5500 {
5501 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
5502         HIST_ENTRY **hlist;
5503         int i;
5504
5505         hlist = history_list();
5506
5507         for (i = 0; hlist && hlist[i]; i++) {
5508                 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
5509         }
5510 #else
5511         DEBUG(0,("no history without readline support\n"));
5512 #endif
5513
5514         return 0;
5515 }
5516
5517 /* Some constants for completing filename arguments */
5518
5519 #define COMPL_NONE        0          /* No completions */
5520 #define COMPL_REMOTE      1          /* Complete remote filename */
5521 #define COMPL_LOCAL       2          /* Complete local filename */
5522
5523 /* This defines the commands supported by this client.
5524  * NOTE: The "!" must be the last one in the list because it's fn pointer
5525  *       field is NULL, and NULL in that field is used in process_tok()
5526  *       (below) to indicate the end of the list.  crh
5527  */
5528 static struct {
5529         const char *name;
5530         int (*fn)(void);
5531         const char *description;
5532         char compl_args[2];      /* Completion argument info */
5533 } commands[] = {
5534   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5535   {"allinfo",cmd_allinfo,"<file> show all available info",
5536    {COMPL_NONE,COMPL_NONE}},
5537   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
5538   {"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}},
5539   {"backup",cmd_backup,"toggle backup intent state",{COMPL_NONE,COMPL_NONE}},
5540   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
5541   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
5542   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
5543   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
5544   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_NONE}},
5545   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_NONE}},
5546   {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_NONE}},
5547   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5548   {"deltree",cmd_deltree,"<mask> recursively delete all matching files and directories",{COMPL_REMOTE,COMPL_NONE}},
5549   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5550   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5551   {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
5552   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5553   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
5554   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_NONE}},
5555   {"geteas", cmd_geteas, "<file name> get the EA list of a file",
5556    {COMPL_REMOTE, COMPL_NONE}},
5557   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5558   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
5559   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
5560   {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
5561   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
5562   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
5563   {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5564   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},
5565   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5566   {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
5567   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
5568   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5569   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
5570   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
5571   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},
5572   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
5573   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
5574   {"notify",cmd_notify,"<file>Get notified of dir changes",{COMPL_REMOTE,COMPL_NONE}},
5575   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
5576   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
5577   {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
5578   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5579   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5580   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5581   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5582   {"posix_whoami",cmd_posix_whoami,"return logged on user information "
5583                         "using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
5584   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
5585   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},
5586   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
5587   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
5588   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5589   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
5590   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
5591   {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5592   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
5593   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},
5594   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
5595   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
5596   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
5597   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5598   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_REMOTE,COMPL_NONE}},
5599   {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},
5600   {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
5601    {COMPL_REMOTE, COMPL_LOCAL}},
5602   {"setmode",cmd_setmode,"<file name> <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
5603   {"scopy",cmd_scopy,"<src> <dest> server-side copy file",{COMPL_REMOTE,COMPL_REMOTE}},
5604   {"stat",cmd_stat,"<file name> Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_NONE}},
5605   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
5606   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
5607   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
5608   {"timeout",cmd_timeout,"timeout <number> - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}},
5609   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
5610   {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
5611   {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
5612   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
5613   {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
5614   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
5615   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
5616   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
5617   {"tcon",cmd_tcon,"connect to a share" ,{COMPL_NONE,COMPL_NONE}},
5618   {"tdis",cmd_tdis,"disconnect from a share",{COMPL_NONE,COMPL_NONE}},
5619   {"tid",cmd_tid,"show or set the current tid (tree-id)",{COMPL_NONE,COMPL_NONE}},
5620   {"utimes", cmd_utimes,"<file name> <create_time> <access_time> <mod_time> "
5621         "<ctime> set times", {COMPL_REMOTE,COMPL_NONE}},
5622   {"logoff",cmd_logoff,"log off (close the session)",{COMPL_NONE,COMPL_NONE}},
5623   {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
5624
5625   /* Yes, this must be here, see crh's comment above. */
5626   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
5627   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
5628 };
5629
5630 /*******************************************************************
5631  Lookup a command string in the list of commands, including
5632  abbreviations.
5633 ******************************************************************/
5634
5635 static int process_tok(char *tok)
5636 {
5637         size_t i = 0, matches = 0;
5638         size_t cmd=0;
5639         size_t tok_len = strlen(tok);
5640
5641         while (commands[i].fn != NULL) {
5642                 if (strequal(commands[i].name,tok)) {
5643                         matches = 1;
5644                         cmd = i;
5645                         break;
5646                 } else if (strnequal(commands[i].name, tok, tok_len)) {
5647                         matches++;
5648                         cmd = i;
5649                 }
5650                 i++;
5651         }
5652
5653         if (matches == 0)
5654                 return(-1);
5655         else if (matches == 1)
5656                 return(cmd);
5657         else
5658                 return(-2);
5659 }
5660
5661 /****************************************************************************
5662  Help.
5663 ****************************************************************************/
5664
5665 static int cmd_help(void)
5666 {
5667         TALLOC_CTX *ctx = talloc_tos();
5668         int i=0,j;
5669         char *buf;
5670
5671         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
5672                 if ((i = process_tok(buf)) >= 0)
5673                         d_printf("HELP %s:\n\t%s\n\n",
5674                                 commands[i].name,commands[i].description);
5675         } else {
5676                 while (commands[i].description) {
5677                         for (j=0; commands[i].description && (j<5); j++) {
5678                                 d_printf("%-15s",commands[i].name);
5679                                 i++;
5680                         }
5681                         d_printf("\n");
5682                 }
5683         }
5684         return 0;
5685 }
5686
5687 /****************************************************************************
5688  Process a -c command string.
5689 ****************************************************************************/
5690
5691 static int process_command_string(const char *cmd_in)
5692 {
5693         TALLOC_CTX *ctx = talloc_tos();
5694         char *cmd = talloc_strdup(ctx, cmd_in);
5695         int rc = 0;
5696
5697         if (!cmd) {
5698                 return 1;
5699         }
5700         /* establish the connection if not already */
5701
5702         if (!cli) {
5703                 NTSTATUS status;
5704
5705                 status = cli_cm_open(talloc_tos(), NULL,
5706                                      have_ip ? dest_ss_str : desthost,
5707                                      service, popt_get_cmdline_auth_info(),
5708                                      smb_encrypt,
5709                                      max_protocol, port, name_type,
5710                                      &cli);
5711                 if (!NT_STATUS_IS_OK(status)) {
5712                         return 1;
5713                 }
5714                 cli_set_timeout(cli, io_timeout*1000);
5715         }
5716
5717         while (cmd[0] != '\0')    {
5718                 char *line;
5719                 char *p;
5720                 char *tok;
5721                 int i;
5722
5723                 if ((p = strchr_m(cmd, ';')) == 0) {
5724                         line = cmd;
5725                         cmd += strlen(cmd);
5726                 } else {
5727                         *p = '\0';
5728                         line = cmd;
5729                         cmd = p + 1;
5730                 }
5731
5732                 /* and get the first part of the command */
5733                 cmd_ptr = line;
5734                 if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
5735                         continue;
5736                 }
5737
5738                 if ((i = process_tok(tok)) >= 0) {
5739                         rc = commands[i].fn();
5740                 } else if (i == -2) {
5741                         d_printf("%s: command abbreviation ambiguous\n",tok);
5742                 } else {
5743                         d_printf("%s: command not found\n",tok);
5744                 }
5745         }
5746
5747         return rc;
5748 }
5749
5750 #define MAX_COMPLETIONS 100
5751
5752 struct completion_remote {
5753         char *dirmask;
5754         char **matches;
5755         int count, samelen;
5756         const char *text;
5757         int len;
5758 };
5759
5760 static NTSTATUS completion_remote_filter(const char *mnt,
5761                                 struct file_info *f,
5762                                 const char *mask,
5763                                 void *state)
5764 {
5765         struct completion_remote *info = (struct completion_remote *)state;
5766
5767         if (info->count >= MAX_COMPLETIONS - 1) {
5768                 return NT_STATUS_OK;
5769         }
5770         if (strncmp(info->text, f->name, info->len) != 0) {
5771                 return NT_STATUS_OK;
5772         }
5773         if (ISDOT(f->name) || ISDOTDOT(f->name)) {
5774                 return NT_STATUS_OK;
5775         }
5776
5777         if ((info->dirmask[0] == 0) && !(f->mode & FILE_ATTRIBUTE_DIRECTORY))
5778                 info->matches[info->count] = SMB_STRDUP(f->name);
5779         else {
5780                 TALLOC_CTX *ctx = talloc_stackframe();
5781                 char *tmp;
5782
5783                 tmp = talloc_strdup(ctx,info->dirmask);
5784                 if (!tmp) {
5785                         TALLOC_FREE(ctx);
5786                         return NT_STATUS_NO_MEMORY;
5787                 }
5788                 tmp = talloc_asprintf_append(tmp, "%s", f->name);
5789                 if (!tmp) {
5790                         TALLOC_FREE(ctx);
5791                         return NT_STATUS_NO_MEMORY;
5792                 }
5793                 if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
5794                         tmp = talloc_asprintf_append(tmp, "%s",
5795                                                      CLI_DIRSEP_STR);
5796                 }
5797                 if (!tmp) {
5798                         TALLOC_FREE(ctx);
5799                         return NT_STATUS_NO_MEMORY;
5800                 }
5801                 info->matches[info->count] = SMB_STRDUP(tmp);
5802                 TALLOC_FREE(ctx);
5803         }
5804         if (info->matches[info->count] == NULL) {
5805                 return NT_STATUS_OK;
5806         }
5807         if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
5808                 smb_readline_ca_char(0);
5809         }
5810         if (info->count == 1) {
5811                 info->samelen = strlen(info->matches[info->count]);
5812         } else {
5813                 while (strncmp(info->matches[info->count],
5814                                info->matches[info->count-1],
5815                                info->samelen) != 0) {
5816                         info->samelen--;
5817                 }
5818         }
5819         info->count++;
5820         return NT_STATUS_OK;
5821 }
5822
5823 static char **remote_completion(const char *text, int len)
5824 {
5825         TALLOC_CTX *ctx = talloc_stackframe();
5826         char *dirmask = NULL;
5827         char *targetpath = NULL;
5828         struct cli_state *targetcli = NULL;
5829         int i;
5830         struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
5831         NTSTATUS status;
5832
5833         /* can't have non-static initialisation on Sun CC, so do it
5834            at run time here */
5835         info.samelen = len;
5836         info.text = text;
5837         info.len = len;
5838
5839         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
5840         if (!info.matches) {
5841                 TALLOC_FREE(ctx);
5842                 return NULL;
5843         }
5844
5845         /*
5846          * We're leaving matches[0] free to fill it later with the text to
5847          * display: Either the one single match or the longest common subset
5848          * of the matches.
5849          */
5850         info.matches[0] = NULL;
5851         info.count = 1;
5852
5853         for (i = len-1; i >= 0; i--) {
5854                 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
5855                         break;
5856                 }
5857         }
5858
5859         info.text = text+i+1;
5860         info.samelen = info.len = len-i-1;
5861
5862         if (i > 0) {
5863                 info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
5864                 if (!info.dirmask) {
5865                         goto cleanup;
5866                 }
5867                 strncpy(info.dirmask, text, i+1);
5868                 info.dirmask[i+1] = 0;
5869                 dirmask = talloc_asprintf(ctx,
5870                                         "%s%*s*",
5871                                         client_get_cur_dir(),
5872                                         i-1,
5873                                         text);
5874         } else {
5875                 info.dirmask = SMB_STRDUP("");
5876                 if (!info.dirmask) {
5877                         goto cleanup;
5878                 }
5879                 dirmask = talloc_asprintf(ctx,
5880                                         "%s*",
5881                                         client_get_cur_dir());
5882         }
5883         if (!dirmask) {
5884                 goto cleanup;
5885         }
5886         dirmask = client_clean_name(ctx, dirmask);
5887         if (dirmask == NULL) {
5888                 goto cleanup;
5889         }
5890
5891         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
5892                                 cli, dirmask, &targetcli, &targetpath);
5893         if (!NT_STATUS_IS_OK(status)) {
5894                 goto cleanup;
5895         }
5896         status = cli_list(targetcli, targetpath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
5897                           completion_remote_filter, (void *)&info);
5898         if (!NT_STATUS_IS_OK(status)) {
5899                 goto cleanup;
5900         }
5901
5902         if (info.count == 1) {
5903                 /*
5904                  * No matches at all, NULL indicates there is nothing
5905                  */
5906                 SAFE_FREE(info.matches[0]);
5907                 SAFE_FREE(info.matches);
5908                 TALLOC_FREE(ctx);
5909                 return NULL;
5910         }
5911
5912         if (info.count == 2) {
5913                 /*
5914                  * Exactly one match in matches[1], indicate this is the one
5915                  * in matches[0].
5916                  */
5917                 info.matches[0] = info.matches[1];
5918                 info.matches[1] = NULL;
5919                 info.count -= 1;
5920                 TALLOC_FREE(ctx);
5921                 return info.matches;
5922         }
5923
5924         /*
5925          * We got more than one possible match, set the result to the maximum
5926          * common subset
5927          */
5928
5929         info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
5930         info.matches[info.count] = NULL;
5931         TALLOC_FREE(ctx);
5932         return info.matches;
5933
5934 cleanup:
5935         for (i = 0; i < info.count; i++) {
5936                 SAFE_FREE(info.matches[i]);
5937         }
5938         SAFE_FREE(info.matches);
5939         SAFE_FREE(info.dirmask);
5940         TALLOC_FREE(ctx);
5941         return NULL;
5942 }
5943
5944 static char **completion_fn(const char *text, int start, int end)
5945 {
5946         smb_readline_ca_char(' ');
5947
5948         if (start) {
5949                 const char *buf, *sp;
5950                 int i;
5951                 char compl_type;
5952
5953                 buf = smb_readline_get_line_buffer();
5954                 if (buf == NULL)
5955                         return NULL;
5956
5957                 sp = strchr(buf, ' ');
5958                 if (sp == NULL)
5959                         return NULL;
5960
5961                 for (i = 0; commands[i].name; i++) {
5962                         if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
5963                             (commands[i].name[sp - buf] == 0)) {
5964                                 break;
5965                         }
5966                 }
5967                 if (commands[i].name == NULL)
5968                         return NULL;
5969
5970                 while (*sp == ' ')
5971                         sp++;
5972
5973                 if (sp == (buf + start))
5974                         compl_type = commands[i].compl_args[0];
5975                 else
5976                         compl_type = commands[i].compl_args[1];
5977
5978                 if (compl_type == COMPL_REMOTE)
5979                         return remote_completion(text, end - start);
5980                 else /* fall back to local filename completion */
5981                         return NULL;
5982         } else {
5983                 char **matches;
5984                 size_t i, len, samelen = 0, count=1;
5985
5986                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
5987                 if (!matches) {
5988                         return NULL;
5989                 }
5990                 matches[0] = NULL;
5991
5992                 len = strlen(text);
5993                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
5994                         if (strncmp(text, commands[i].name, len) == 0) {
5995                                 matches[count] = SMB_STRDUP(commands[i].name);
5996                                 if (!matches[count])
5997                                         goto cleanup;
5998                                 if (count == 1)
5999                                         samelen = strlen(matches[count]);
6000                                 else
6001                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
6002                                                 samelen--;
6003                                 count++;
6004                         }
6005                 }
6006
6007                 switch (count) {
6008                 case 0: /* should never happen */
6009                 case 1:
6010                         goto cleanup;
6011                 case 2:
6012                         matches[0] = SMB_STRDUP(matches[1]);
6013                         break;
6014                 default:
6015                         matches[0] = (char *)SMB_MALLOC(samelen+1);
6016                         if (!matches[0])
6017                                 goto cleanup;
6018                         strncpy(matches[0], matches[1], samelen);
6019                         matches[0][samelen] = 0;
6020                 }
6021                 matches[count] = NULL;
6022                 return matches;
6023
6024 cleanup:
6025                 for (i = 0; i < count; i++)
6026                         free(matches[i]);
6027
6028                 free(matches);
6029                 return NULL;
6030         }
6031 }
6032
6033 static bool finished;
6034
6035 /****************************************************************************
6036  Make sure we swallow keepalives during idle time.
6037 ****************************************************************************/
6038
6039 static void readline_callback(void)
6040 {
6041         static time_t last_t;
6042         struct timespec now;
6043         time_t t;
6044         NTSTATUS status;
6045         unsigned char garbage[16];
6046
6047         clock_gettime_mono(&now);
6048         t = now.tv_sec;
6049
6050         if (t - last_t < 5)
6051                 return;
6052
6053         last_t = t;
6054
6055         /* Ping the server to keep the connection alive using SMBecho. */
6056         memset(garbage, 0xf0, sizeof(garbage));
6057         status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
6058         if (NT_STATUS_IS_OK(status) ||
6059                         NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
6060                 /*
6061                  * Even if server returns NT_STATUS_INVALID_PARAMETER
6062                  * it still responded.
6063                  * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13007
6064                  */
6065                 return;
6066         }
6067
6068         if (!cli_state_is_connected(cli)) {
6069                 DEBUG(0,("SMBecho failed (%s). The connection is "
6070                          "disconnected now\n", nt_errstr(status)));
6071                 finished = true;
6072                 smb_readline_done();
6073         }
6074 }
6075
6076 /****************************************************************************
6077  Process commands on stdin.
6078 ****************************************************************************/
6079
6080 static int process_stdin(void)
6081 {
6082         int rc = 0;
6083
6084         if (!quiet) {
6085                 d_printf("Try \"help\" to get a list of possible commands.\n");
6086         }
6087
6088         while (!finished) {
6089                 TALLOC_CTX *frame = talloc_stackframe();
6090                 char *tok = NULL;
6091                 char *the_prompt = NULL;
6092                 char *line = NULL;
6093                 int i;
6094
6095                 /* display a prompt */
6096                 if (asprintf(&the_prompt, "smb: %s> ", client_get_cur_dir()) < 0) {
6097                         TALLOC_FREE(frame);
6098                         break;
6099                 }
6100                 line = smb_readline(the_prompt, readline_callback, completion_fn);
6101                 SAFE_FREE(the_prompt);
6102                 if (!line) {
6103                         TALLOC_FREE(frame);
6104                         break;
6105                 }
6106
6107                 /* special case - first char is ! */
6108                 if (*line == '!') {
6109                         if (system(line + 1) == -1) {
6110                                 d_printf("system() command %s failed.\n",
6111                                         line+1);
6112                         }
6113                         SAFE_FREE(line);
6114                         TALLOC_FREE(frame);
6115                         continue;
6116                 }
6117
6118                 /* and get the first part of the command */
6119                 cmd_ptr = line;
6120                 if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
6121                         TALLOC_FREE(frame);
6122                         SAFE_FREE(line);
6123                         continue;
6124                 }
6125
6126                 if ((i = process_tok(tok)) >= 0) {
6127                         rc = commands[i].fn();
6128                 } else if (i == -2) {
6129                         d_printf("%s: command abbreviation ambiguous\n",tok);
6130                 } else {
6131                         d_printf("%s: command not found\n",tok);
6132                 }
6133                 SAFE_FREE(line);
6134                 TALLOC_FREE(frame);
6135         }
6136         return rc;
6137 }
6138
6139 /****************************************************************************
6140  Process commands from the client.
6141 ****************************************************************************/
6142
6143 static int process(const char *base_directory)
6144 {
6145         int rc = 0;
6146         NTSTATUS status;
6147
6148         status = cli_cm_open(talloc_tos(), NULL,
6149                              have_ip ? dest_ss_str : desthost,
6150                              service, popt_get_cmdline_auth_info(),
6151                              smb_encrypt, max_protocol, port,
6152                              name_type, &cli);
6153         if (!NT_STATUS_IS_OK(status)) {
6154                 return 1;
6155         }
6156
6157         cli_set_timeout(cli, io_timeout*1000);
6158
6159         if (base_directory && *base_directory) {
6160                 rc = do_cd(base_directory);
6161                 if (rc) {
6162                         cli_shutdown(cli);
6163                         return rc;
6164                 }
6165         }
6166
6167         if (cmdstr) {
6168                 rc = process_command_string(cmdstr);
6169         } else {
6170                 process_stdin();
6171         }
6172
6173         cli_shutdown(cli);
6174         return rc;
6175 }
6176
6177 /****************************************************************************
6178  Handle a -L query.
6179 ****************************************************************************/
6180
6181 static int do_host_query(const char *query_host)
6182 {
6183         NTSTATUS status;
6184
6185         status = cli_cm_open(talloc_tos(), NULL,
6186                              have_ip ? dest_ss_str : query_host,
6187                              "IPC$", popt_get_cmdline_auth_info(),
6188                              smb_encrypt, max_protocol, port,
6189                              name_type, &cli);
6190         if (!NT_STATUS_IS_OK(status)) {
6191                 return 1;
6192         }
6193
6194         cli_set_timeout(cli, io_timeout*1000);
6195         browse_host(true);
6196
6197         /* Ensure that the host can do IPv4 */
6198
6199         if (!interpret_addr(query_host)) {
6200                 struct sockaddr_storage ss;
6201                 if (interpret_string_addr(&ss, query_host, 0) &&
6202                                 (ss.ss_family != AF_INET)) {
6203                         d_printf("%s is an IPv6 address -- no workgroup available\n",
6204                                 query_host);
6205                         return 1;
6206                 }
6207         }
6208
6209         if (lp_client_min_protocol() > PROTOCOL_NT1) {
6210                 d_printf("SMB1 disabled -- no workgroup available\n");
6211                 goto out;
6212         }
6213
6214         if (lp_disable_netbios()) {
6215                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
6216                 goto out;
6217         }
6218
6219         if (port != NBT_SMB_PORT ||
6220             smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1)
6221         {
6222                 int max_proto = MIN(max_protocol, PROTOCOL_NT1);
6223
6224                 /*
6225                  * Workgroups simply don't make sense over anything
6226                  * else but port 139 and SMB1.
6227                  */
6228
6229                 cli_shutdown(cli);
6230                 d_printf("Reconnecting with SMB1 for workgroup listing.\n");
6231                 status = cli_cm_open(talloc_tos(), NULL,
6232                                      have_ip ? dest_ss_str : query_host,
6233                                      "IPC$", popt_get_cmdline_auth_info(),
6234                                      smb_encrypt, max_proto,
6235                                      NBT_SMB_PORT, name_type, &cli);
6236                 if (!NT_STATUS_IS_OK(status)) {
6237                         d_printf("Unable to connect with SMB1 "
6238                                  "-- no workgroup available\n");
6239                         return 0;
6240                 }
6241         }
6242
6243         cli_set_timeout(cli, io_timeout*1000);
6244         list_servers(lp_workgroup());
6245 out:
6246         cli_shutdown(cli);
6247
6248         return(0);
6249 }
6250
6251 /****************************************************************************
6252  Handle a tar operation.
6253 ****************************************************************************/
6254
6255 static int do_tar_op(const char *base_directory)
6256 {
6257         struct tar *tar_ctx = tar_get_ctx();
6258         int ret = 0;
6259
6260         /* do we already have a connection? */
6261         if (!cli) {
6262                 NTSTATUS status;
6263
6264                 status = cli_cm_open(talloc_tos(), NULL,
6265                                      have_ip ? dest_ss_str : desthost,
6266                                      service, popt_get_cmdline_auth_info(),
6267                                      smb_encrypt, max_protocol,
6268                                      port, name_type, &cli);
6269                 if (!NT_STATUS_IS_OK(status)) {
6270             ret = 1;
6271             goto out;
6272                 }
6273                 cli_set_timeout(cli, io_timeout*1000);
6274         }
6275
6276         recurse = true;
6277
6278         if (base_directory && *base_directory)  {
6279                 ret = do_cd(base_directory);
6280                 if (ret) {
6281             goto out_cli;
6282                 }
6283         }
6284
6285         ret = tar_process(tar_ctx);
6286
6287  out_cli:
6288         cli_shutdown(cli);
6289  out:
6290         return ret;
6291 }
6292
6293 /****************************************************************************
6294  Handle a message operation.
6295 ****************************************************************************/
6296
6297 static int do_message_op(struct user_auth_info *a_info)
6298 {
6299         NTSTATUS status;
6300
6301         if (lp_disable_netbios()) {
6302                 d_printf("NetBIOS over TCP disabled.\n");
6303                 return 1;
6304         }
6305
6306         status = cli_connect_nb(desthost, have_ip ? &dest_ss : NULL,
6307                                 port ? port : NBT_SMB_PORT, name_type,
6308                                 lp_netbios_name(), SMB_SIGNING_DEFAULT, 0, &cli);
6309         if (!NT_STATUS_IS_OK(status)) {
6310                 d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
6311                 return 1;
6312         }
6313
6314         cli_set_timeout(cli, io_timeout*1000);
6315         send_message(get_cmdline_auth_info_username(a_info));
6316         cli_shutdown(cli);
6317
6318         return 0;
6319 }
6320
6321 /****************************************************************************
6322   main program
6323 ****************************************************************************/
6324
6325 int main(int argc,char *argv[])
6326 {
6327         const char **const_argv = discard_const_p(const char *, argv);
6328         char *base_directory = NULL;
6329         int opt;
6330         char *query_host = NULL;
6331         bool message = false;
6332         static const char *new_name_resolve_order = NULL;
6333         poptContext pc;
6334         char *p;
6335         int rc = 0;
6336         bool tar_opt = false;
6337         bool service_opt = false;
6338         struct tar *tar_ctx = tar_get_ctx();
6339
6340         struct poptOption long_options[] = {
6341                 POPT_AUTOHELP
6342
6343                 {
6344                         .longName   = "name-resolve",
6345                         .shortName  = 'R',
6346                         .argInfo    = POPT_ARG_STRING,
6347                         .arg        = &new_name_resolve_order,
6348                         .val        = 'R',
6349                         .descrip    = "Use these name resolution services only",
6350                         .argDescrip = "NAME-RESOLVE-ORDER",
6351                 },
6352                 {
6353                         .longName   = "message",
6354                         .shortName  = 'M',
6355                         .argInfo    = POPT_ARG_STRING,
6356                         .arg        = NULL,
6357                         .val        = 'M',
6358                         .descrip    = "Send message",
6359                         .argDescrip = "HOST",
6360                 },
6361                 {
6362                         .longName   = "ip-address",
6363                         .shortName  = 'I',
6364                         .argInfo    = POPT_ARG_STRING,
6365                         .arg        = NULL,
6366                         .val        = 'I',
6367                         .descrip    = "Use this IP to connect to",
6368                         .argDescrip = "IP",
6369                 },
6370                 {
6371                         .longName   = "stderr",
6372                         .shortName  = 'E',
6373                         .argInfo    = POPT_ARG_NONE,
6374                         .arg        = NULL,
6375                         .val        = 'E',
6376                         .descrip    = "Write messages to stderr instead of stdout",
6377                 },
6378                 {
6379                         .longName   = "list",
6380                         .shortName  = 'L',
6381                         .argInfo    = POPT_ARG_STRING,
6382                         .arg        = NULL,
6383                         .val        = 'L',
6384                         .descrip    = "Get a list of shares available on a host",
6385                         .argDescrip = "HOST",
6386                 },
6387                 {
6388                         .longName   = "max-protocol",
6389                         .shortName  = 'm',
6390                         .argInfo    = POPT_ARG_STRING,
6391                         .arg        = NULL,
6392                         .val        = 'm',
6393                         .descrip    = "Set the max protocol level",
6394                         .argDescrip = "LEVEL",
6395                 },
6396                 {
6397                         .longName   = "tar",
6398                         .shortName  = 'T',
6399                         .argInfo    = POPT_ARG_STRING,
6400                         .arg        = NULL,
6401                         .val        = 'T',
6402                         .descrip    = "Command line tar",
6403                         .argDescrip = "<c|x>IXFqgbNan",
6404                 },
6405                 {
6406                         .longName   = "directory",
6407                         .shortName  = 'D',
6408                         .argInfo    = POPT_ARG_STRING,
6409                         .arg        = NULL,
6410                         .val        = 'D',
6411                         .descrip    = "Start from directory",
6412                         .argDescrip = "DIR",
6413                 },
6414                 {
6415                         .longName   = "command",
6416                         .shortName  = 'c',
6417                         .argInfo    = POPT_ARG_STRING,
6418                         .arg        = &cmdstr,
6419                         .val        = 'c',
6420                         .descrip    = "Execute semicolon separated commands",
6421                 },
6422                 {
6423                         .longName   = "send-buffer",
6424                         .shortName  = 'b',
6425                         .argInfo    = POPT_ARG_INT,
6426                         .arg        = &io_bufsize,
6427                         .val        = 'b',
6428                         .descrip    = "Changes the transmit/send buffer",
6429                         .argDescrip = "BYTES",
6430                 },
6431                 {
6432                         .longName   = "timeout",
6433                         .shortName  = 't',
6434                         .argInfo    = POPT_ARG_INT,
6435                         .arg        = &io_timeout,
6436                         .val        = 'b',
6437                         .descrip    = "Changes the per-operation timeout",
6438                         .argDescrip = "SECONDS",
6439                 },
6440                 {
6441                         .longName   = "port",
6442                         .shortName  = 'p',
6443                         .argInfo    = POPT_ARG_INT,
6444                         .arg        = &port,
6445                         .val        = 'p',
6446                         .descrip    = "Port to connect to",
6447                         .argDescrip = "PORT",
6448                 },
6449                 {
6450                         .longName   = "grepable",
6451                         .shortName  = 'g',
6452                         .argInfo    = POPT_ARG_NONE,
6453                         .arg        = NULL,
6454                         .val        = 'g',
6455                         .descrip    = "Produce grepable output",
6456                 },
6457                 {
6458                         .longName   = "quiet",
6459                         .shortName  = 'q',
6460                         .argInfo    = POPT_ARG_NONE,
6461                         .arg        = NULL,
6462                         .val        = 'q',
6463                         .descrip    = "Suppress help message",
6464                 },
6465                 {
6466                         .longName   = "browse",
6467                         .shortName  = 'B',
6468                         .argInfo    = POPT_ARG_NONE,
6469                         .arg        = NULL,
6470                         .val        = 'B',
6471                         .descrip    = "Browse SMB servers using DNS",
6472                 },
6473                 POPT_COMMON_SAMBA
6474                 POPT_COMMON_CONNECTION
6475                 POPT_COMMON_CREDENTIALS
6476                 POPT_TABLEEND
6477         };
6478         TALLOC_CTX *frame = talloc_stackframe();
6479
6480         if (!client_set_cur_dir("\\")) {
6481                 exit(ENOMEM);
6482         }
6483
6484         /* set default debug level to 1 regardless of what smb.conf sets */
6485         setup_logging( "smbclient", DEBUG_DEFAULT_STDERR );
6486         smb_init_locale();
6487
6488         lp_set_cmdline("log level", "1");
6489
6490         popt_common_credentials_set_ignore_missing_conf();
6491         popt_common_credentials_set_delay_post();
6492
6493         /* skip argv(0) */
6494         pc = poptGetContext("smbclient", argc, const_argv, long_options, 0);
6495         poptSetOtherOptionHelp(pc, "service <password>");
6496
6497         while ((opt = poptGetNextOpt(pc)) != -1) {
6498
6499                 /* if the tar option has been called previouslt, now we need to eat out the leftovers */
6500                 /* I see no other way to keep things sane --SSS */
6501                 if (tar_opt == true) {
6502                         while (poptPeekArg(pc)) {
6503                                 poptGetArg(pc);
6504                         }
6505                         tar_opt = false;
6506                 }
6507
6508                 /* if the service has not yet been specified lets see if it is available in the popt stack */
6509                 if (!service_opt && poptPeekArg(pc)) {
6510                         service = talloc_strdup(frame, poptGetArg(pc));
6511                         if (!service) {
6512                                 exit(ENOMEM);
6513                         }
6514                         service_opt = true;
6515                 }
6516
6517                 /* if the service has already been retrieved then check if we have also a password */
6518                 if (service_opt
6519                     && (!get_cmdline_auth_info_got_pass(
6520                                 popt_get_cmdline_auth_info()))
6521                     && poptPeekArg(pc)) {
6522                         set_cmdline_auth_info_password(
6523                                 popt_get_cmdline_auth_info(), poptGetArg(pc));
6524                 }
6525
6526
6527                 switch (opt) {
6528                 case 'M':
6529                         /* Messages are sent to NetBIOS name type 0x3
6530                          * (Messenger Service).  Make sure we default
6531                          * to port 139 instead of port 445. srl,crh
6532                          */
6533                         name_type = 0x03;
6534                         desthost = talloc_strdup(frame,poptGetOptArg(pc));
6535                         if (!desthost) {
6536                                 exit(ENOMEM);
6537                         }
6538                         if( !port )
6539                                 port = NBT_SMB_PORT;
6540                         message = true;
6541                         break;
6542                 case 'I':
6543                         {
6544                                 if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
6545                                         exit(1);
6546                                 }
6547                                 have_ip = true;
6548                                 print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
6549                         }
6550                         break;
6551                 case 'E':
6552                         setup_logging("smbclient", DEBUG_STDERR );
6553                         display_set_stderr();
6554                         break;
6555
6556                 case 'L':
6557                         query_host = talloc_strdup(frame, poptGetOptArg(pc));
6558                         if (!query_host) {
6559                                 exit(ENOMEM);
6560                         }
6561                         break;
6562                 case 'm':
6563                         lp_set_cmdline("client max protocol", poptGetOptArg(pc));
6564                         break;
6565                 case 'T':
6566                         /* We must use old option processing for this. Find the
6567                          * position of the -T option in the raw argv[]. */
6568                         {
6569                                 int i;
6570
6571                                 for (i = 1; i < argc; i++) {
6572                                         if (strncmp("-T", argv[i],2)==0)
6573                                                 break;
6574                                 }
6575                                 i++;
6576                                 if (tar_parse_args(tar_ctx, poptGetOptArg(pc),
6577                                                    const_argv + i, argc - i)) {
6578                                         poptPrintUsage(pc, stderr, 0);
6579                                         exit(1);
6580                                 }
6581                         }
6582                         /* this must be the last option, mark we have parsed it so that we know we have */
6583                         tar_opt = true;
6584                         break;
6585                 case 'D':
6586                         base_directory = talloc_strdup(frame, poptGetOptArg(pc));
6587                         if (!base_directory) {
6588                                 exit(ENOMEM);
6589                         }
6590                         break;
6591                 case 'g':
6592                         grepable=true;
6593                         break;
6594                 case 'q':
6595                         quiet=true;
6596                         break;
6597                 case 'e':
6598                         smb_encrypt=true;
6599                         break;
6600                 case 'B':
6601                         return(do_smb_browse());
6602
6603                 }
6604         }
6605
6606         /* We may still have some leftovers after the last popt option has been called */
6607         if (tar_opt == true) {
6608                 while (poptPeekArg(pc)) {
6609                         poptGetArg(pc);
6610                 }
6611                 tar_opt = false;
6612         }
6613
6614         /* if the service has not yet been specified lets see if it is available in the popt stack */
6615         if (!service_opt && poptPeekArg(pc)) {
6616                 service = talloc_strdup(frame,poptGetArg(pc));
6617                 if (!service) {
6618                         exit(ENOMEM);
6619                 }
6620                 service_opt = true;
6621         }
6622
6623         /* if the service has already been retrieved then check if we have also a password */
6624         if (service_opt
6625             && !get_cmdline_auth_info_got_pass(popt_get_cmdline_auth_info())
6626             && poptPeekArg(pc)) {
6627                 set_cmdline_auth_info_password(popt_get_cmdline_auth_info(),
6628                                                poptGetArg(pc));
6629         }
6630
6631         if (service_opt && service) {
6632                 size_t len;
6633
6634                 /* Convert any '/' characters in the service name to '\' characters */
6635                 string_replace(service, '/','\\');
6636                 if (count_chars(service,'\\') < 3) {
6637                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
6638                         poptPrintUsage(pc, stderr, 0);
6639                         exit(1);
6640                 }
6641                 /* Remove trailing slashes */
6642                 len = strlen(service);
6643                 while(len > 0 && service[len - 1] == '\\') {
6644                         --len;
6645                         service[len] = '\0';
6646                 }
6647         }
6648
6649         if (!init_names()) {
6650                 fprintf(stderr, "init_names() failed\n");
6651                 exit(1);
6652         }
6653
6654         if(new_name_resolve_order)
6655                 lp_set_cmdline("name resolve order", new_name_resolve_order);
6656
6657         if (!tar_to_process(tar_ctx) && !query_host && !service && !message) {
6658                 poptPrintUsage(pc, stderr, 0);
6659                 exit(1);
6660         }
6661
6662         poptFreeContext(pc);
6663         popt_burn_cmdline_password(argc, argv);
6664
6665         DEBUG(3,("Client started (version %s).\n", samba_version_string()));
6666
6667         /* Ensure we have a password (or equivalent). */
6668         popt_common_credentials_post();
6669         smb_encrypt = get_cmdline_auth_info_smb_encrypt(
6670                         popt_get_cmdline_auth_info());
6671
6672         max_protocol = lp_client_max_protocol();
6673
6674         if (tar_to_process(tar_ctx)) {
6675                 if (cmdstr)
6676                         process_command_string(cmdstr);
6677                 rc = do_tar_op(base_directory);
6678         } else if (query_host && *query_host) {
6679                 char *qhost = query_host;
6680                 char *slash;
6681
6682                 while (*qhost == '\\' || *qhost == '/')
6683                         qhost++;
6684
6685                 if ((slash = strchr_m(qhost, '/'))
6686                     || (slash = strchr_m(qhost, '\\'))) {
6687                         *slash = 0;
6688                 }
6689
6690                 if ((p=strchr_m(qhost, '#'))) {
6691                         *p = 0;
6692                         p++;
6693                         sscanf(p, "%x", &name_type);
6694                 }
6695
6696                 rc = do_host_query(qhost);
6697         } else if (message) {
6698                 rc = do_message_op(popt_get_cmdline_auth_info());
6699         } else if (process(base_directory)) {
6700                 rc = 1;
6701         }
6702
6703         popt_free_cmdline_auth_info();
6704         TALLOC_FREE(frame);
6705         return rc;
6706 }