2a95911f54d68a8c1c3af9631bbeb642c094e8bc
[bbaumbach/samba-autobuild/.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 #include "lib/util/time_basic.h"
43
44 #ifndef REGISTER
45 #define REGISTER 0
46 #endif
47
48 extern int do_smb_browse(void); /* mDNS browsing */
49
50 extern bool override_logfile;
51
52 static int port = 0;
53 static char *service;
54 static char *desthost;
55 static bool grepable = false;
56 static bool quiet = false;
57 static char *cmdstr = NULL;
58 const char *cmd_ptr = NULL;
59
60 static int io_bufsize = 0; /* we use the default size */
61 static int io_timeout = (CLIENT_TIMEOUT/1000); /* Per operation timeout (in seconds). */
62
63 static int name_type = 0x20;
64 static int max_protocol = -1;
65
66 static int process_tok(char *tok);
67 static int cmd_help(void);
68
69 /* value for unused fid field in trans2 secondary request */
70 #define FID_UNUSED (0xFFFF)
71
72 time_t newer_than = 0;
73 static int archive_level = 0;
74
75 static bool translation = false;
76 static bool have_ip;
77
78 static bool prompt = true;
79
80 static bool recurse = false;
81 static bool showacls = false;
82 bool lowercase = false;
83 static bool backup_intent = false;
84
85 static struct sockaddr_storage dest_ss;
86 static char dest_ss_str[INET6_ADDRSTRLEN];
87
88 #define SEPARATORS " \t\n\r"
89
90 static bool abort_mget = true;
91
92 /* timing globals */
93 uint64_t get_total_size = 0;
94 unsigned int get_total_time_ms = 0;
95 static uint64_t put_total_size = 0;
96 static unsigned int put_total_time_ms = 0;
97
98 /* totals globals */
99 static double dir_total;
100
101 /* encrypted state. */
102 static bool smb_encrypt;
103
104 /* root cli_state connection */
105
106 struct cli_state *cli;
107
108 static char CLI_DIRSEP_CHAR = '\\';
109 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
110
111 /* Accessor functions for directory paths. */
112 static char *fileselection;
113 static const char *client_get_fileselection(void)
114 {
115         if (fileselection) {
116                 return fileselection;
117         }
118         return "";
119 }
120
121 static const char *client_set_fileselection(const char *new_fs)
122 {
123         SAFE_FREE(fileselection);
124         if (new_fs) {
125                 fileselection = SMB_STRDUP(new_fs);
126         }
127         return client_get_fileselection();
128 }
129
130 static char *cwd;
131 static const char *client_get_cwd(void)
132 {
133         if (cwd) {
134                 return cwd;
135         }
136         return CLI_DIRSEP_STR;
137 }
138
139 static const char *client_set_cwd(const char *new_cwd)
140 {
141         SAFE_FREE(cwd);
142         if (new_cwd) {
143                 cwd = SMB_STRDUP(new_cwd);
144         }
145         return client_get_cwd();
146 }
147
148 static char *cur_dir;
149 const char *client_get_cur_dir(void)
150 {
151         if (cur_dir) {
152                 return cur_dir;
153         }
154         return CLI_DIRSEP_STR;
155 }
156
157 const char *client_set_cur_dir(const char *newdir)
158 {
159         SAFE_FREE(cur_dir);
160         if (newdir) {
161                 cur_dir = SMB_STRDUP(newdir);
162         }
163         return client_get_cur_dir();
164 }
165
166 /****************************************************************************
167  Put up a yes/no prompt.
168 ****************************************************************************/
169
170 static bool yesno(const char *p)
171 {
172         char ans[20];
173         printf("%s",p);
174
175         if (!fgets(ans,sizeof(ans)-1,stdin))
176                 return(False);
177
178         if (*ans == 'y' || *ans == 'Y')
179                 return(True);
180
181         return(False);
182 }
183
184 /****************************************************************************
185  Write to a local file with CR/LF->LF translation if appropriate. Return the
186  number taken from the buffer. This may not equal the number written.
187 ****************************************************************************/
188
189 static ssize_t writefile(int f, char *b, size_t n)
190 {
191         size_t i = 0;
192
193         if (n == 0) {
194                 errno = EINVAL;
195                 return -1;
196         }
197
198         if (!translation) {
199                 return write(f,b,n);
200         }
201
202         do {
203                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
204                         b++;i++;
205                 }
206                 if (write(f, b, 1) != 1) {
207                         break;
208                 }
209                 b++;
210                 i++;
211         } while (i < n);
212
213         return (ssize_t)i;
214 }
215
216 /****************************************************************************
217  Read from a file with LF->CR/LF translation if appropriate. Return the
218  number read. read approx n bytes.
219 ****************************************************************************/
220
221 static int readfile(uint8_t *b, int n, FILE *f)
222 {
223         int i;
224         int c;
225
226         if (!translation)
227                 return fread(b,1,n,f);
228
229         i = 0;
230         while (i < (n - 1)) {
231                 if ((c = getc(f)) == EOF) {
232                         break;
233                 }
234
235                 if (c == '\n') { /* change all LFs to CR/LF */
236                         b[i++] = '\r';
237                 }
238
239                 b[i++] = c;
240         }
241
242         return(i);
243 }
244
245 struct push_state {
246         FILE *f;
247         off_t nread;
248 };
249
250 static size_t push_source(uint8_t *buf, size_t n, void *priv)
251 {
252         struct push_state *state = (struct push_state *)priv;
253         int result;
254
255         if (feof(state->f)) {
256                 return 0;
257         }
258
259         result = readfile(buf, n, state->f);
260         state->nread += result;
261         return result;
262 }
263
264 /****************************************************************************
265  Send a message.
266 ****************************************************************************/
267
268 static void send_message(const char *username)
269 {
270         char buf[1600];
271         NTSTATUS status;
272         int i;
273
274         d_printf("Type your message, ending it with a Control-D\n");
275
276         i = 0;
277         while (i<sizeof(buf)-2) {
278                 int c = fgetc(stdin);
279                 if (c == EOF) {
280                         break;
281                 }
282                 if (c == '\n') {
283                         buf[i++] = '\r';
284                 }
285                 buf[i++] = c;
286         }
287         buf[i] = '\0';
288
289         status = cli_message(cli, desthost, username, buf);
290         if (!NT_STATUS_IS_OK(status)) {
291                 d_fprintf(stderr, "cli_message returned %s\n",
292                           nt_errstr(status));
293         }
294 }
295
296 /****************************************************************************
297  Check the space on a device.
298 ****************************************************************************/
299
300 static int do_dskattr(void)
301 {
302         uint64_t total, bsize, avail;
303         struct cli_state *targetcli = NULL;
304         char *targetpath = NULL;
305         TALLOC_CTX *ctx = talloc_tos();
306         NTSTATUS status;
307
308         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), cli,
309                                   client_get_cur_dir(), &targetcli,
310                                   &targetpath);
311         if (!NT_STATUS_IS_OK(status)) {
312                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
313                 return 1;
314         }
315
316         status = cli_disk_size(targetcli, targetpath, &bsize, &total, &avail);
317         if (!NT_STATUS_IS_OK(status)) {
318                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
319                 return 1;
320         }
321
322         d_printf("\n\t\t%" PRIu64
323                 " blocks of size %" PRIu64
324                 ". %" PRIu64 " blocks available\n",
325                 total, bsize, avail);
326
327         return 0;
328 }
329
330 /****************************************************************************
331  Show cd/pwd.
332 ****************************************************************************/
333
334 static int cmd_pwd(void)
335 {
336         d_printf("Current directory is %s",service);
337         d_printf("%s\n",client_get_cur_dir());
338         return 0;
339 }
340
341 /****************************************************************************
342  Ensure name has correct directory separators.
343 ****************************************************************************/
344
345 static void normalize_name(char *newdir)
346 {
347         if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
348                 string_replace(newdir,'/','\\');
349         }
350 }
351
352 /****************************************************************************
353  Local name cleanup before sending to server. SMB1 allows relative pathnames,
354  but SMB2 does not, so we need to resolve them locally.
355 ****************************************************************************/
356
357 char *client_clean_name(TALLOC_CTX *ctx, const char *name)
358 {
359         char *newname = NULL;
360         if (name == NULL) {
361                 return NULL;
362         }
363
364         /* First ensure any path separators are correct. */
365         newname = talloc_strdup(ctx, name);
366         if (newname == NULL) {
367                 return NULL;
368         }
369         normalize_name(newname);
370
371         /* Now remove any relative (..) path components. */
372         if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
373                 newname = unix_clean_name(ctx, newname);
374         } else {
375                 newname = clean_name(ctx, newname);
376         }
377         if (newname == NULL) {
378                 return NULL;
379         }
380         return newname;
381 }
382
383 /****************************************************************************
384  Change directory - inner section.
385 ****************************************************************************/
386
387 static int do_cd(const char *new_dir)
388 {
389         char *newdir = NULL;
390         char *saved_dir = NULL;
391         char *new_cd = NULL;
392         char *targetpath = NULL;
393         struct cli_state *targetcli = NULL;
394         SMB_STRUCT_STAT sbuf;
395         uint32_t attributes;
396         int ret = 1;
397         TALLOC_CTX *ctx = talloc_stackframe();
398         NTSTATUS status;
399
400         newdir = talloc_strdup(ctx, new_dir);
401         if (!newdir) {
402                 TALLOC_FREE(ctx);
403                 return 1;
404         }
405
406         normalize_name(newdir);
407
408         /* Save the current directory in case the new directory is invalid */
409
410         saved_dir = talloc_strdup(ctx, client_get_cur_dir());
411         if (!saved_dir) {
412                 TALLOC_FREE(ctx);
413                 return 1;
414         }
415
416         if (*newdir == CLI_DIRSEP_CHAR) {
417                 client_set_cur_dir(newdir);
418                 new_cd = newdir;
419         } else {
420                 new_cd = talloc_asprintf(ctx, "%s%s",
421                                 client_get_cur_dir(),
422                                 newdir);
423                 if (!new_cd) {
424                         goto out;
425                 }
426         }
427
428         /* Ensure cur_dir ends in a DIRSEP */
429         if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
430                 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
431                 if (!new_cd) {
432                         goto out;
433                 }
434         }
435         client_set_cur_dir(new_cd);
436
437         new_cd = client_clean_name(ctx, new_cd);
438         client_set_cur_dir(new_cd);
439
440         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
441                                 cli, new_cd, &targetcli, &targetpath);
442         if (!NT_STATUS_IS_OK(status)) {
443                 d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
444                 client_set_cur_dir(saved_dir);
445                 goto out;
446         }
447
448         if (strequal(targetpath,CLI_DIRSEP_STR )) {
449                 TALLOC_FREE(ctx);
450                 return 0;
451         }
452
453         /* Use a trans2_qpathinfo to test directories for modern servers.
454            Except Win9x doesn't support the qpathinfo_basic() call..... */
455
456         if (smbXcli_conn_protocol(targetcli->conn) > PROTOCOL_LANMAN2 && !targetcli->win95) {
457
458                 status = cli_qpathinfo_basic(targetcli, targetpath, &sbuf,
459                                              &attributes);
460                 if (!NT_STATUS_IS_OK(status)) {
461                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
462                         client_set_cur_dir(saved_dir);
463                         goto out;
464                 }
465
466                 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
467                         d_printf("cd %s: not a directory\n", new_cd);
468                         client_set_cur_dir(saved_dir);
469                         goto out;
470                 }
471         } else {
472
473                 targetpath = talloc_asprintf(ctx,
474                                 "%s%s",
475                                 targetpath,
476                                 CLI_DIRSEP_STR );
477                 if (!targetpath) {
478                         client_set_cur_dir(saved_dir);
479                         goto out;
480                 }
481                 targetpath = client_clean_name(ctx, targetpath);
482                 if (!targetpath) {
483                         client_set_cur_dir(saved_dir);
484                         goto out;
485                 }
486
487                 status = cli_chkpath(targetcli, targetpath);
488                 if (!NT_STATUS_IS_OK(status)) {
489                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
490                         client_set_cur_dir(saved_dir);
491                         goto out;
492                 }
493         }
494
495         ret = 0;
496
497 out:
498
499         TALLOC_FREE(ctx);
500         return ret;
501 }
502
503 /****************************************************************************
504  Change directory.
505 ****************************************************************************/
506
507 static int cmd_cd(void)
508 {
509         char *buf = NULL;
510         int rc = 0;
511
512         if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
513                 rc = do_cd(buf);
514         } else {
515                 d_printf("Current directory is %s\n",client_get_cur_dir());
516         }
517
518         return rc;
519 }
520
521 /****************************************************************************
522  Change directory.
523 ****************************************************************************/
524
525 static int cmd_cd_oneup(void)
526 {
527         return do_cd("..");
528 }
529
530 /*******************************************************************
531  Decide if a file should be operated on.
532 ********************************************************************/
533
534 static bool do_this_one(struct file_info *finfo)
535 {
536         if (!finfo->name) {
537                 return false;
538         }
539
540         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
541                 return true;
542         }
543
544         if (*client_get_fileselection() &&
545             !mask_match(finfo->name,client_get_fileselection(),false)) {
546                 DEBUG(3,("mask_match %s failed\n", finfo->name));
547                 return false;
548         }
549
550         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
551                 DEBUG(3,("newer_than %s failed\n", finfo->name));
552                 return false;
553         }
554
555         if ((archive_level==1 || archive_level==2) && !(finfo->mode & FILE_ATTRIBUTE_ARCHIVE)) {
556                 DEBUG(3,("archive %s failed\n", finfo->name));
557                 return false;
558         }
559
560         return true;
561 }
562
563 /****************************************************************************
564  Display info about a file.
565 ****************************************************************************/
566
567 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
568                           const char *dir)
569 {
570         time_t t;
571         TALLOC_CTX *ctx = talloc_tos();
572         NTSTATUS status = NT_STATUS_OK;
573
574         if (!do_this_one(finfo)) {
575                 return NT_STATUS_OK;
576         }
577
578         t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
579         if (!showacls) {
580                 d_printf("  %-30s%7.7s %8.0f  %s",
581                          finfo->name,
582                          attrib_string(talloc_tos(), finfo->mode),
583                         (double)finfo->size,
584                         time_to_asc(t));
585                 dir_total += finfo->size;
586         } else {
587                 char *afname = NULL;
588                 uint16_t fnum;
589
590                 /* skip if this is . or .. */
591                 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
592                         return NT_STATUS_OK;
593                 /* create absolute filename for cli_ntcreate() FIXME */
594                 afname = talloc_asprintf(ctx,
595                                         "%s%s%s",
596                                         dir,
597                                         CLI_DIRSEP_STR,
598                                         finfo->name);
599                 if (!afname) {
600                         return NT_STATUS_NO_MEMORY;
601                 }
602                 /* print file meta date header */
603                 d_printf( "FILENAME:%s\n", finfo->name);
604                 d_printf( "MODE:%s\n", attrib_string(talloc_tos(), finfo->mode));
605                 d_printf( "SIZE:%.0f\n", (double)finfo->size);
606                 d_printf( "MTIME:%s", time_to_asc(t));
607                 status = cli_ntcreate(
608                         cli_state,            /* cli */
609                         afname,               /* fname */
610                         0,                    /* CreatFlags */
611                         READ_CONTROL_ACCESS,  /* DesiredAccess */
612                         0,                    /* FileAttributes */
613                         FILE_SHARE_READ|
614                         FILE_SHARE_WRITE,     /* ShareAccess */
615                         FILE_OPEN,            /* CreateDisposition */
616                         0x0,                  /* CreateOptions */
617                         0x0,                  /* SecurityFlags */
618                         &fnum,                /* pfid */
619                         NULL);                /* cr */
620                 if (!NT_STATUS_IS_OK(status)) {
621                         DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
622                                    afname, nt_errstr(status)));
623                 } else {
624                         struct security_descriptor *sd = NULL;
625                         status = cli_query_secdesc(cli_state, fnum,
626                                                    ctx, &sd);
627                         if (!NT_STATUS_IS_OK(status)) {
628                                 DEBUG( 0, ("display_finfo() failed to "
629                                            "get security descriptor: %s",
630                                            nt_errstr(status)));
631                         } else {
632                                 display_sec_desc(sd);
633                         }
634                         TALLOC_FREE(sd);
635                 }
636                 TALLOC_FREE(afname);
637         }
638         return status;
639 }
640
641 /****************************************************************************
642  Accumulate size of a file.
643 ****************************************************************************/
644
645 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
646                   const char *dir)
647 {
648         if (do_this_one(finfo)) {
649                 dir_total += finfo->size;
650         }
651         return NT_STATUS_OK;
652 }
653
654 static bool do_list_recurse;
655 static bool do_list_dirs;
656 static char *do_list_queue = 0;
657 static long do_list_queue_size = 0;
658 static long do_list_queue_start = 0;
659 static long do_list_queue_end = 0;
660 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
661                           const char *dir);
662
663 /****************************************************************************
664  Functions for do_list_queue.
665 ****************************************************************************/
666
667 /*
668  * The do_list_queue is a NUL-separated list of strings stored in a
669  * char*.  Since this is a FIFO, we keep track of the beginning and
670  * ending locations of the data in the queue.  When we overflow, we
671  * double the size of the char*.  When the start of the data passes
672  * the midpoint, we move everything back.  This is logically more
673  * complex than a linked list, but easier from a memory management
674  * angle.  In any memory error condition, do_list_queue is reset.
675  * Functions check to ensure that do_list_queue is non-NULL before
676  * accessing it.
677  */
678
679 static void reset_do_list_queue(void)
680 {
681         SAFE_FREE(do_list_queue);
682         do_list_queue_size = 0;
683         do_list_queue_start = 0;
684         do_list_queue_end = 0;
685 }
686
687 static void init_do_list_queue(void)
688 {
689         reset_do_list_queue();
690         do_list_queue_size = 1024;
691         do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
692         if (do_list_queue == 0) {
693                 d_printf("malloc fail for size %d\n",
694                          (int)do_list_queue_size);
695                 reset_do_list_queue();
696         } else {
697                 memset(do_list_queue, 0, do_list_queue_size);
698         }
699 }
700
701 static void adjust_do_list_queue(void)
702 {
703         /*
704          * If the starting point of the queue is more than half way through,
705          * move everything toward the beginning.
706          */
707
708         if (do_list_queue == NULL) {
709                 DEBUG(4,("do_list_queue is empty\n"));
710                 do_list_queue_start = do_list_queue_end = 0;
711                 return;
712         }
713
714         if (do_list_queue_start == do_list_queue_end) {
715                 DEBUG(4,("do_list_queue is empty\n"));
716                 do_list_queue_start = do_list_queue_end = 0;
717                 *do_list_queue = '\0';
718         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
719                 DEBUG(4,("sliding do_list_queue backward\n"));
720                 memmove(do_list_queue,
721                         do_list_queue + do_list_queue_start,
722                         do_list_queue_end - do_list_queue_start);
723                 do_list_queue_end -= do_list_queue_start;
724                 do_list_queue_start = 0;
725         }
726 }
727
728 static void add_to_do_list_queue(const char *entry)
729 {
730         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
731         while (new_end > do_list_queue_size) {
732                 do_list_queue_size *= 2;
733                 DEBUG(4,("enlarging do_list_queue to %d\n",
734                          (int)do_list_queue_size));
735                 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
736                 if (! do_list_queue) {
737                         d_printf("failure enlarging do_list_queue to %d bytes\n",
738                                  (int)do_list_queue_size);
739                         reset_do_list_queue();
740                 } else {
741                         memset(do_list_queue + do_list_queue_size / 2,
742                                0, do_list_queue_size / 2);
743                 }
744         }
745         if (do_list_queue) {
746                 strlcpy_base(do_list_queue + do_list_queue_end,
747                                  entry, do_list_queue, do_list_queue_size);
748                 do_list_queue_end = new_end;
749                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
750                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
751         }
752 }
753
754 static char *do_list_queue_head(void)
755 {
756         return do_list_queue + do_list_queue_start;
757 }
758
759 static void remove_do_list_queue_head(void)
760 {
761         if (do_list_queue_end > do_list_queue_start) {
762                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
763                 adjust_do_list_queue();
764                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
765                          (int)do_list_queue_start, (int)do_list_queue_end));
766         }
767 }
768
769 static int do_list_queue_empty(void)
770 {
771         return (! (do_list_queue && *do_list_queue));
772 }
773
774 /****************************************************************************
775  A helper for do_list.
776 ****************************************************************************/
777
778 static NTSTATUS do_list_helper(const char *mntpoint, struct file_info *f,
779                            const char *mask, void *state)
780 {
781         struct cli_state *cli_state = (struct cli_state *)state;
782         TALLOC_CTX *ctx = talloc_tos();
783         char *dir = NULL;
784         char *dir_end = NULL;
785         NTSTATUS status = NT_STATUS_OK;
786
787         /* Work out the directory. */
788         dir = talloc_strdup(ctx, mask);
789         if (!dir) {
790                 return NT_STATUS_NO_MEMORY;
791         }
792         if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
793                 *dir_end = '\0';
794         }
795
796         if (f->mode & FILE_ATTRIBUTE_DIRECTORY) {
797                 if (do_list_dirs && do_this_one(f)) {
798                         status = do_list_fn(cli_state, f, dir);
799                         if (!NT_STATUS_IS_OK(status)) {
800                                 return status;
801                         }
802                 }
803                 if (do_list_recurse &&
804                     f->name &&
805                     !strequal(f->name,".") &&
806                     !strequal(f->name,"..")) {
807                         char *mask2 = NULL;
808                         char *p = NULL;
809
810                         if (!f->name[0]) {
811                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
812                                 TALLOC_FREE(dir);
813                                 return NT_STATUS_UNSUCCESSFUL;
814                         }
815
816                         mask2 = talloc_asprintf(ctx,
817                                         "%s%s",
818                                         mntpoint,
819                                         mask);
820                         if (!mask2) {
821                                 TALLOC_FREE(dir);
822                                 return NT_STATUS_NO_MEMORY;
823                         }
824                         p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
825                         if (p) {
826                                 p[1] = 0;
827                         } else {
828                                 mask2[0] = '\0';
829                         }
830                         mask2 = talloc_asprintf_append(mask2,
831                                         "%s%s*",
832                                         f->name,
833                                         CLI_DIRSEP_STR);
834                         if (!mask2) {
835                                 TALLOC_FREE(dir);
836                                 return NT_STATUS_NO_MEMORY;
837                         }
838                         add_to_do_list_queue(mask2);
839                         TALLOC_FREE(mask2);
840                 }
841                 TALLOC_FREE(dir);
842                 return NT_STATUS_OK;
843         }
844
845         if (do_this_one(f)) {
846                 status = do_list_fn(cli_state, f, dir);
847         }
848         TALLOC_FREE(dir);
849         return status;
850 }
851
852 /****************************************************************************
853  A wrapper around cli_list that adds recursion.
854 ****************************************************************************/
855
856 NTSTATUS do_list(const char *mask,
857                         uint16_t attribute,
858                         NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
859                                    const char *dir),
860                         bool rec,
861                         bool dirs)
862 {
863         static int in_do_list = 0;
864         TALLOC_CTX *ctx = talloc_tos();
865         struct cli_state *targetcli = NULL;
866         char *targetpath = NULL;
867         NTSTATUS ret_status = NT_STATUS_OK;
868         NTSTATUS status = NT_STATUS_OK;
869
870         if (in_do_list && rec) {
871                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
872                 exit(1);
873         }
874
875         in_do_list = 1;
876
877         do_list_recurse = rec;
878         do_list_dirs = dirs;
879         do_list_fn = fn;
880
881         if (rec) {
882                 init_do_list_queue();
883                 add_to_do_list_queue(mask);
884
885                 while (!do_list_queue_empty()) {
886                         /*
887                          * Need to copy head so that it doesn't become
888                          * invalid inside the call to cli_list.  This
889                          * would happen if the list were expanded
890                          * during the call.
891                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
892                          */
893                         char *head = talloc_strdup(ctx, do_list_queue_head());
894
895                         if (!head) {
896                                 return NT_STATUS_NO_MEMORY;
897                         }
898
899                         /* check for dfs */
900
901                         status = cli_resolve_path(ctx, "",
902                                         popt_get_cmdline_auth_info(),
903                                         cli, head, &targetcli, &targetpath);
904                         if (!NT_STATUS_IS_OK(status)) {
905                                 d_printf("do_list: [%s] %s\n", head,
906                                          nt_errstr(status));
907                                 remove_do_list_queue_head();
908                                 continue;
909                         }
910
911                         status = cli_list(targetcli, targetpath, attribute,
912                                  do_list_helper, targetcli);
913                         if (!NT_STATUS_IS_OK(status)) {
914                                 d_printf("%s listing %s\n",
915                                          nt_errstr(status), targetpath);
916                                 ret_status = status;
917                         }
918                         remove_do_list_queue_head();
919                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
920                                 char *next_file = do_list_queue_head();
921                                 char *save_ch = 0;
922                                 if ((strlen(next_file) >= 2) &&
923                                     (next_file[strlen(next_file) - 1] == '*') &&
924                                     (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
925                                         save_ch = next_file +
926                                                 strlen(next_file) - 2;
927                                         *save_ch = '\0';
928                                         if (showacls) {
929                                                 /* cwd is only used if showacls is on */
930                                                 client_set_cwd(next_file);
931                                         }
932                                 }
933                                 if (!showacls) /* don't disturbe the showacls output */
934                                         d_printf("\n%s\n",next_file);
935                                 if (save_ch) {
936                                         *save_ch = CLI_DIRSEP_CHAR;
937                                 }
938                         }
939                         TALLOC_FREE(head);
940                         TALLOC_FREE(targetpath);
941                 }
942         } else {
943                 /* check for dfs */
944                 status = cli_resolve_path(ctx, "",
945                                 popt_get_cmdline_auth_info(), cli, mask,
946                                   &targetcli, &targetpath);
947                 if (NT_STATUS_IS_OK(status)) {
948                         status = cli_list(targetcli, targetpath, attribute,
949                                           do_list_helper, targetcli);
950                         if (!NT_STATUS_IS_OK(status)) {
951                                 d_printf("%s listing %s\n",
952                                          nt_errstr(status), targetpath);
953                                 ret_status = status;
954                         }
955                         TALLOC_FREE(targetpath);
956                 } else {
957                         d_printf("do_list: [%s] %s\n", mask, nt_errstr(status));
958                         ret_status = status;
959                 }
960         }
961
962         in_do_list = 0;
963         reset_do_list_queue();
964         return ret_status;
965 }
966
967 /****************************************************************************
968  Get a directory listing.
969 ****************************************************************************/
970
971 static int cmd_dir(void)
972 {
973         TALLOC_CTX *ctx = talloc_tos();
974         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
975         char *mask = NULL;
976         char *buf = NULL;
977         int rc = 1;
978         NTSTATUS status;
979
980         dir_total = 0;
981         mask = talloc_strdup(ctx, client_get_cur_dir());
982         if (!mask) {
983                 return 1;
984         }
985
986         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
987                 normalize_name(buf);
988                 if (*buf == CLI_DIRSEP_CHAR) {
989                         mask = talloc_strdup(ctx, buf);
990                 } else {
991                         mask = talloc_asprintf_append(mask, "%s", buf);
992                 }
993         } else {
994                 mask = talloc_asprintf_append(mask, "*");
995         }
996         if (!mask) {
997                 return 1;
998         }
999
1000         mask = client_clean_name(ctx, mask);
1001         if (mask == NULL) {
1002                 return 1;
1003         }
1004
1005         if (showacls) {
1006                 /* cwd is only used if showacls is on */
1007                 client_set_cwd(client_get_cur_dir());
1008         }
1009
1010         status = do_list(mask, attribute, display_finfo, recurse, true);
1011         if (!NT_STATUS_IS_OK(status)) {
1012                 return 1;
1013         }
1014
1015         rc = do_dskattr();
1016
1017         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
1018
1019         return rc;
1020 }
1021
1022 /****************************************************************************
1023  Get a directory listing.
1024 ****************************************************************************/
1025
1026 static int cmd_du(void)
1027 {
1028         TALLOC_CTX *ctx = talloc_tos();
1029         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1030         char *mask = NULL;
1031         char *buf = NULL;
1032         NTSTATUS status;
1033         int rc = 1;
1034
1035         dir_total = 0;
1036         mask = talloc_strdup(ctx, client_get_cur_dir());
1037         if (!mask) {
1038                 return 1;
1039         }
1040         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
1041                 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
1042                 if (!mask) {
1043                         return 1;
1044                 }
1045         }
1046
1047         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1048                 normalize_name(buf);
1049                 if (*buf == CLI_DIRSEP_CHAR) {
1050                         mask = talloc_strdup(ctx, buf);
1051                 } else {
1052                         mask = talloc_asprintf_append(mask, "%s", buf);
1053                 }
1054         } else {
1055                 mask = talloc_strdup(ctx, "*");
1056         }
1057         if (!mask) {
1058                 return 1;
1059         }
1060
1061         mask = client_clean_name(ctx, mask);
1062         if (mask == NULL) {
1063                 return 1;
1064         }
1065
1066         status = do_list(mask, attribute, do_du, recurse, true);
1067         if (!NT_STATUS_IS_OK(status)) {
1068                 return 1;
1069         }
1070
1071         rc = do_dskattr();
1072
1073         d_printf("Total number of bytes: %.0f\n", dir_total);
1074
1075         return rc;
1076 }
1077
1078 static int cmd_echo(void)
1079 {
1080         TALLOC_CTX *ctx = talloc_tos();
1081         char *num;
1082         char *data;
1083         NTSTATUS status;
1084
1085         if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1086             || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1087                 d_printf("echo <num> <data>\n");
1088                 return 1;
1089         }
1090
1091         status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1092
1093         if (!NT_STATUS_IS_OK(status)) {
1094                 d_printf("echo failed: %s\n", nt_errstr(status));
1095                 return 1;
1096         }
1097
1098         return 0;
1099 }
1100
1101 /****************************************************************************
1102  Get a file from rname to lname
1103 ****************************************************************************/
1104
1105 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1106 {
1107         int *pfd = (int *)priv;
1108         ssize_t rc;
1109
1110         rc = writefile(*pfd, buf, n);
1111         if (rc == -1) {
1112                 return map_nt_error_from_unix(errno);
1113         }
1114         return NT_STATUS_OK;
1115 }
1116
1117 static int do_get(const char *rname, const char *lname_in, bool reget)
1118 {
1119         TALLOC_CTX *ctx = talloc_tos();
1120         int handle = 0;
1121         uint16_t fnum;
1122         bool newhandle = false;
1123         struct timespec tp_start;
1124         uint16_t attr;
1125         off_t size;
1126         off_t start = 0;
1127         off_t nread = 0;
1128         int rc = 0;
1129         struct cli_state *targetcli = NULL;
1130         char *targetname = NULL;
1131         char *lname = NULL;
1132         NTSTATUS status;
1133
1134         lname = talloc_strdup(ctx, lname_in);
1135         if (!lname) {
1136                 return 1;
1137         }
1138
1139         if (lowercase) {
1140                 if (!strlower_m(lname)) {
1141                         d_printf("strlower_m %s failed\n", lname);
1142                         return 1;
1143                 }
1144         }
1145
1146         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1147                                 cli, rname, &targetcli, &targetname);
1148         if (!NT_STATUS_IS_OK(status)) {
1149                 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1150                 return 1;
1151         }
1152
1153         clock_gettime_mono(&tp_start);
1154
1155         status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1156         if (!NT_STATUS_IS_OK(status)) {
1157                 d_printf("%s opening remote file %s\n", nt_errstr(status),
1158                          rname);
1159                 return 1;
1160         }
1161
1162         if(!strcmp(lname,"-")) {
1163                 handle = fileno(stdout);
1164         } else {
1165                 if (reget) {
1166                         handle = open(lname, O_WRONLY|O_CREAT, 0644);
1167                         if (handle >= 0) {
1168                                 start = lseek(handle, 0, SEEK_END);
1169                                 if (start == -1) {
1170                                         d_printf("Error seeking local file\n");
1171                                         close(handle);
1172                                         return 1;
1173                                 }
1174                         }
1175                 } else {
1176                         handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1177                 }
1178                 newhandle = true;
1179         }
1180         if (handle < 0) {
1181                 d_printf("Error opening local file %s\n",lname);
1182                 return 1;
1183         }
1184
1185
1186         status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1187                                      NULL, NULL, NULL);
1188         if (!NT_STATUS_IS_OK(status)) {
1189                 status = cli_getattrE(targetcli, fnum, &attr, &size, NULL, NULL,
1190                                       NULL);
1191                 if(!NT_STATUS_IS_OK(status)) {
1192                         d_printf("getattrib: %s\n", nt_errstr(status));
1193                         if (newhandle) {
1194                                 close(handle);
1195                         }
1196                         return 1;
1197                 }
1198         }
1199
1200         DEBUG(1,("getting file %s of size %.0f as %s ",
1201                  rname, (double)size, lname));
1202
1203         status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1204                           writefile_sink, (void *)&handle, &nread);
1205         if (!NT_STATUS_IS_OK(status)) {
1206                 d_fprintf(stderr, "parallel_read returned %s\n",
1207                           nt_errstr(status));
1208                 if (newhandle) {
1209                         close(handle);
1210                 }
1211                 cli_close(targetcli, fnum);
1212                 return 1;
1213         }
1214
1215         status = cli_close(targetcli, fnum);
1216         if (!NT_STATUS_IS_OK(status)) {
1217                 d_printf("Error %s closing remote file\n", nt_errstr(status));
1218                 rc = 1;
1219         }
1220
1221         if (newhandle) {
1222                 close(handle);
1223         }
1224
1225         if (archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
1226                 cli_setatr(cli, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
1227         }
1228
1229         {
1230                 struct timespec tp_end;
1231                 int this_time;
1232
1233                 clock_gettime_mono(&tp_end);
1234                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1235                 get_total_time_ms += this_time;
1236                 get_total_size += nread;
1237
1238                 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1239                          nread / (1.024*this_time + 1.0e-4),
1240                          get_total_size / (1.024*get_total_time_ms)));
1241         }
1242
1243         TALLOC_FREE(targetname);
1244         return rc;
1245 }
1246
1247 /****************************************************************************
1248  Get a file.
1249 ****************************************************************************/
1250
1251 static int cmd_get(void)
1252 {
1253         TALLOC_CTX *ctx = talloc_tos();
1254         char *lname = NULL;
1255         char *rname = NULL;
1256         char *fname = NULL;
1257
1258         rname = talloc_strdup(ctx, client_get_cur_dir());
1259         if (!rname) {
1260                 return 1;
1261         }
1262
1263         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1264                 d_printf("get <filename> [localname]\n");
1265                 return 1;
1266         }
1267         rname = talloc_asprintf_append(rname, "%s", fname);
1268         if (!rname) {
1269                 return 1;
1270         }
1271         rname = client_clean_name(ctx, rname);
1272         if (!rname) {
1273                 return 1;
1274         }
1275
1276         next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1277         if (!lname) {
1278                 lname = fname;
1279         }
1280
1281         return do_get(rname, lname, false);
1282 }
1283
1284 /****************************************************************************
1285  Do an mget operation on one file.
1286 ****************************************************************************/
1287
1288 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1289                     const char *dir)
1290 {
1291         TALLOC_CTX *ctx = talloc_tos();
1292         NTSTATUS status = NT_STATUS_OK;
1293         char *rname = NULL;
1294         char *quest = NULL;
1295         char *saved_curdir = NULL;
1296         char *mget_mask = NULL;
1297         char *new_cd = NULL;
1298
1299         if (!finfo->name) {
1300                 return NT_STATUS_OK;
1301         }
1302
1303         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1304                 return NT_STATUS_OK;
1305
1306         if (abort_mget) {
1307                 d_printf("mget aborted\n");
1308                 return NT_STATUS_UNSUCCESSFUL;
1309         }
1310
1311         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
1312                 if (asprintf(&quest,
1313                          "Get directory %s? ",finfo->name) < 0) {
1314                         return NT_STATUS_NO_MEMORY;
1315                 }
1316         } else {
1317                 if (asprintf(&quest,
1318                          "Get file %s? ",finfo->name) < 0) {
1319                         return NT_STATUS_NO_MEMORY;
1320                 }
1321         }
1322
1323         if (prompt && !yesno(quest)) {
1324                 SAFE_FREE(quest);
1325                 return NT_STATUS_OK;
1326         }
1327         SAFE_FREE(quest);
1328
1329         if (!(finfo->mode & FILE_ATTRIBUTE_DIRECTORY)) {
1330                 rname = talloc_asprintf(ctx,
1331                                 "%s%s",
1332                                 client_get_cur_dir(),
1333                                 finfo->name);
1334                 if (!rname) {
1335                         return NT_STATUS_NO_MEMORY;
1336                 }
1337                 rname = client_clean_name(ctx, rname);
1338                 if (rname == NULL) {
1339                         return NT_STATUS_NO_MEMORY;
1340                 }
1341                 do_get(rname, finfo->name, false);
1342                 TALLOC_FREE(rname);
1343                 return NT_STATUS_OK;
1344         }
1345
1346         /* handle directories */
1347         saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1348         if (!saved_curdir) {
1349                 return NT_STATUS_NO_MEMORY;
1350         }
1351
1352         new_cd = talloc_asprintf(ctx,
1353                                 "%s%s%s",
1354                                 client_get_cur_dir(),
1355                                 finfo->name,
1356                                 CLI_DIRSEP_STR);
1357         if (!new_cd) {
1358                 return NT_STATUS_NO_MEMORY;
1359         }
1360         new_cd = client_clean_name(ctx, new_cd);
1361         if (new_cd == NULL) {
1362                 return NT_STATUS_NO_MEMORY;
1363         }
1364         client_set_cur_dir(new_cd);
1365
1366         string_replace(finfo->name,'\\','/');
1367         if (lowercase) {
1368                 if (!strlower_m(finfo->name)) {
1369                         return NT_STATUS_INVALID_PARAMETER;
1370                 }
1371         }
1372
1373         if (!directory_exist(finfo->name) &&
1374             mkdir(finfo->name,0777) != 0) {
1375                 d_printf("failed to create directory %s\n",finfo->name);
1376                 client_set_cur_dir(saved_curdir);
1377                 return map_nt_error_from_unix(errno);
1378         }
1379
1380         if (chdir(finfo->name) != 0) {
1381                 d_printf("failed to chdir to directory %s\n",finfo->name);
1382                 client_set_cur_dir(saved_curdir);
1383                 return map_nt_error_from_unix(errno);
1384         }
1385
1386         mget_mask = talloc_asprintf(ctx,
1387                         "%s*",
1388                         client_get_cur_dir());
1389
1390         if (!mget_mask) {
1391                 return NT_STATUS_NO_MEMORY;
1392         }
1393
1394         mget_mask = client_clean_name(ctx, mget_mask);
1395         if (mget_mask == NULL) {
1396                 return NT_STATUS_NO_MEMORY;
1397         }
1398         status = do_list(mget_mask,
1399                          (FILE_ATTRIBUTE_SYSTEM
1400                           | FILE_ATTRIBUTE_HIDDEN
1401                           | FILE_ATTRIBUTE_DIRECTORY),
1402                          do_mget, false, true);
1403         if (!NT_STATUS_IS_OK(status)
1404          && !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
1405                 /*
1406                  * Ignore access denied errors to ensure all permitted files are
1407                  * pulled down.
1408                  */
1409                 return status;
1410         }
1411
1412         if (chdir("..") == -1) {
1413                 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1414                         strerror(errno) );
1415                 return map_nt_error_from_unix(errno);
1416         }
1417         client_set_cur_dir(saved_curdir);
1418         TALLOC_FREE(mget_mask);
1419         TALLOC_FREE(saved_curdir);
1420         TALLOC_FREE(new_cd);
1421         return NT_STATUS_OK;
1422 }
1423
1424 /****************************************************************************
1425  View the file using the pager.
1426 ****************************************************************************/
1427
1428 static int cmd_more(void)
1429 {
1430         TALLOC_CTX *ctx = talloc_tos();
1431         char *rname = NULL;
1432         char *fname = NULL;
1433         char *lname = NULL;
1434         char *pager_cmd = NULL;
1435         const char *pager;
1436         int fd;
1437         int rc = 0;
1438         mode_t mask;
1439
1440         rname = talloc_strdup(ctx, client_get_cur_dir());
1441         if (!rname) {
1442                 return 1;
1443         }
1444
1445         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1446         if (!lname) {
1447                 return 1;
1448         }
1449         mask = umask(S_IRWXO | S_IRWXG);
1450         fd = mkstemp(lname);
1451         umask(mask);
1452         if (fd == -1) {
1453                 d_printf("failed to create temporary file for more\n");
1454                 return 1;
1455         }
1456         close(fd);
1457
1458         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1459                 d_printf("more <filename>\n");
1460                 unlink(lname);
1461                 return 1;
1462         }
1463         rname = talloc_asprintf_append(rname, "%s", fname);
1464         if (!rname) {
1465                 return 1;
1466         }
1467         rname = client_clean_name(ctx,rname);
1468         if (!rname) {
1469                 return 1;
1470         }
1471
1472         rc = do_get(rname, lname, false);
1473
1474         pager=getenv("PAGER");
1475
1476         pager_cmd = talloc_asprintf(ctx,
1477                                 "%s %s",
1478                                 (pager? pager:PAGER),
1479                                 lname);
1480         if (!pager_cmd) {
1481                 return 1;
1482         }
1483         if (system(pager_cmd) == -1) {
1484                 d_printf("system command '%s' returned -1\n",
1485                         pager_cmd);
1486         }
1487         unlink(lname);
1488
1489         return rc;
1490 }
1491
1492 /****************************************************************************
1493  Do a mget command.
1494 ****************************************************************************/
1495
1496 static int cmd_mget(void)
1497 {
1498         TALLOC_CTX *ctx = talloc_tos();
1499         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1500         char *mget_mask = NULL;
1501         char *buf = NULL;
1502         NTSTATUS status = NT_STATUS_OK;
1503
1504         if (recurse) {
1505                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1506         }
1507
1508         abort_mget = false;
1509
1510         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1511
1512                 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1513                 if (!mget_mask) {
1514                         return 1;
1515                 }
1516                 if (*buf == CLI_DIRSEP_CHAR) {
1517                         mget_mask = talloc_strdup(ctx, buf);
1518                 } else {
1519                         mget_mask = talloc_asprintf_append(mget_mask,
1520                                                         "%s", buf);
1521                 }
1522                 if (!mget_mask) {
1523                         return 1;
1524                 }
1525                 mget_mask = client_clean_name(ctx, mget_mask);
1526                 if (mget_mask == NULL) {
1527                         return 1;
1528                 }
1529                 status = do_list(mget_mask, attribute, do_mget, false, true);
1530                 if (!NT_STATUS_IS_OK(status)) {
1531                         return 1;
1532                 }
1533         }
1534
1535         if (mget_mask == NULL) {
1536                 d_printf("nothing to mget\n");
1537                 return 0;
1538         }
1539
1540         if (!*mget_mask) {
1541                 mget_mask = talloc_asprintf(ctx,
1542                                         "%s*",
1543                                         client_get_cur_dir());
1544                 if (!mget_mask) {
1545                         return 1;
1546                 }
1547                 mget_mask = client_clean_name(ctx, mget_mask);
1548                 if (mget_mask == NULL) {
1549                         return 1;
1550                 }
1551                 status = do_list(mget_mask, attribute, do_mget, false, true);
1552                 if (!NT_STATUS_IS_OK(status)) {
1553                         return 1;
1554                 }
1555         }
1556
1557         return 0;
1558 }
1559
1560 /****************************************************************************
1561  Make a directory of name "name".
1562 ****************************************************************************/
1563
1564 static bool do_mkdir(const char *name)
1565 {
1566         TALLOC_CTX *ctx = talloc_tos();
1567         struct cli_state *targetcli;
1568         char *targetname = NULL;
1569         NTSTATUS status;
1570
1571         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1572                                 cli, name, &targetcli, &targetname);
1573         if (!NT_STATUS_IS_OK(status)) {
1574                 d_printf("mkdir %s: %s\n", name, nt_errstr(status));
1575                 return false;
1576         }
1577
1578         status = cli_mkdir(targetcli, targetname);
1579         if (!NT_STATUS_IS_OK(status)) {
1580                 d_printf("%s making remote directory %s\n",
1581                          nt_errstr(status),name);
1582                 return false;
1583         }
1584
1585         return true;
1586 }
1587
1588 /****************************************************************************
1589  Show 8.3 name of a file.
1590 ****************************************************************************/
1591
1592 static bool do_altname(const char *name)
1593 {
1594         fstring altname;
1595         NTSTATUS status;
1596
1597         status = cli_qpathinfo_alt_name(cli, name, altname);
1598         if (!NT_STATUS_IS_OK(status)) {
1599                 d_printf("%s getting alt name for %s\n",
1600                          nt_errstr(status),name);
1601                 return false;
1602         }
1603         d_printf("%s\n", altname);
1604
1605         return true;
1606 }
1607
1608 /****************************************************************************
1609  Exit client.
1610 ****************************************************************************/
1611
1612 static int cmd_quit(void)
1613 {
1614         cli_shutdown(cli);
1615         popt_free_cmdline_auth_info();
1616         exit(0);
1617         /* NOTREACHED */
1618         return 0;
1619 }
1620
1621 /****************************************************************************
1622  Make a directory.
1623 ****************************************************************************/
1624
1625 static int cmd_mkdir(void)
1626 {
1627         TALLOC_CTX *ctx = talloc_tos();
1628         char *mask = NULL;
1629         char *buf = NULL;
1630         NTSTATUS status;
1631
1632         mask = talloc_strdup(ctx, client_get_cur_dir());
1633         if (!mask) {
1634                 return 1;
1635         }
1636
1637         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1638                 if (!recurse) {
1639                         d_printf("mkdir <dirname>\n");
1640                 }
1641                 return 1;
1642         }
1643         mask = talloc_asprintf_append(mask, "%s", buf);
1644         if (!mask) {
1645                 return 1;
1646         }
1647         mask = client_clean_name(ctx, mask);
1648         if (mask == NULL) {
1649                 return 1;
1650         }
1651
1652         if (recurse) {
1653                 char *ddir = NULL;
1654                 char *ddir2 = NULL;
1655                 struct cli_state *targetcli;
1656                 char *targetname = NULL;
1657                 char *p = NULL;
1658                 char *saveptr;
1659
1660                 ddir2 = talloc_strdup(ctx, "");
1661                 if (!ddir2) {
1662                         return 1;
1663                 }
1664
1665                 status = cli_resolve_path(ctx, "",
1666                                 popt_get_cmdline_auth_info(), cli, mask,
1667                                 &targetcli, &targetname);
1668                 if (!NT_STATUS_IS_OK(status)) {
1669                         return 1;
1670                 }
1671
1672                 ddir = talloc_strdup(ctx, targetname);
1673                 if (!ddir) {
1674                         return 1;
1675                 }
1676                 trim_char(ddir,'.','\0');
1677                 p = strtok_r(ddir, "/\\", &saveptr);
1678                 while (p) {
1679                         ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1680                         if (!ddir2) {
1681                                 return 1;
1682                         }
1683                         if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1684                                 do_mkdir(ddir2);
1685                         }
1686                         ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1687                         if (!ddir2) {
1688                                 return 1;
1689                         }
1690                         p = strtok_r(NULL, "/\\", &saveptr);
1691                 }
1692         } else {
1693                 do_mkdir(mask);
1694         }
1695
1696         return 0;
1697 }
1698
1699 /****************************************************************************
1700  Show alt name.
1701 ****************************************************************************/
1702
1703 static int cmd_altname(void)
1704 {
1705         TALLOC_CTX *ctx = talloc_tos();
1706         char *name;
1707         char *buf;
1708
1709         name = talloc_strdup(ctx, client_get_cur_dir());
1710         if (!name) {
1711                 return 1;
1712         }
1713
1714         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1715                 d_printf("altname <file>\n");
1716                 return 1;
1717         }
1718         name = talloc_asprintf_append(name, "%s", buf);
1719         if (!name) {
1720                 return 1;
1721         }
1722         name = client_clean_name(ctx, name);
1723         if (name == NULL) {
1724                 return 1;
1725         }
1726         do_altname(name);
1727         return 0;
1728 }
1729
1730 static char *attr_str(TALLOC_CTX *mem_ctx, uint16_t mode)
1731 {
1732         char *attrs = talloc_zero_array(mem_ctx, char, 17);
1733         int i = 0;
1734
1735         if (!(mode & FILE_ATTRIBUTE_NORMAL)) {
1736                 if (mode & FILE_ATTRIBUTE_ENCRYPTED) {
1737                         attrs[i++] = 'E';
1738                 }
1739                 if (mode & FILE_ATTRIBUTE_NONINDEXED) {
1740                         attrs[i++] = 'N';
1741                 }
1742                 if (mode & FILE_ATTRIBUTE_OFFLINE) {
1743                         attrs[i++] = 'O';
1744                 }
1745                 if (mode & FILE_ATTRIBUTE_COMPRESSED) {
1746                         attrs[i++] = 'C';
1747                 }
1748                 if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1749                         attrs[i++] = 'r';
1750                 }
1751                 if (mode & FILE_ATTRIBUTE_SPARSE) {
1752                         attrs[i++] = 's';
1753                 }
1754                 if (mode & FILE_ATTRIBUTE_TEMPORARY) {
1755                         attrs[i++] = 'T';
1756                 }
1757                 if (mode & FILE_ATTRIBUTE_NORMAL) {
1758                         attrs[i++] = 'N';
1759                 }
1760                 if (mode & FILE_ATTRIBUTE_READONLY) {
1761                         attrs[i++] = 'R';
1762                 }
1763                 if (mode & FILE_ATTRIBUTE_HIDDEN) {
1764                         attrs[i++] = 'H';
1765                 }
1766                 if (mode & FILE_ATTRIBUTE_SYSTEM) {
1767                         attrs[i++] = 'S';
1768                 }
1769                 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1770                         attrs[i++] = 'D';
1771                 }
1772                 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
1773                         attrs[i++] = 'A';
1774                 }
1775         }
1776         return attrs;
1777 }
1778
1779 /****************************************************************************
1780  Show all info we can get
1781 ****************************************************************************/
1782
1783 static int do_allinfo(const char *name)
1784 {
1785         fstring altname;
1786         struct timespec b_time, a_time, m_time, c_time;
1787         off_t size;
1788         uint16_t mode;
1789         NTTIME tmp;
1790         uint16_t fnum;
1791         unsigned int num_streams;
1792         struct stream_struct *streams;
1793         int num_snapshots;
1794         char **snapshots = NULL;
1795         unsigned int i;
1796         NTSTATUS status;
1797
1798         status = cli_qpathinfo_alt_name(cli, name, altname);
1799         if (!NT_STATUS_IS_OK(status)) {
1800                 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1801                          name);
1802                 /*
1803                  * Ignore not supported or not implemented, it does not
1804                  * hurt if we can't list alternate names.
1805                  */
1806                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
1807                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
1808                         altname[0] = '\0';
1809                 } else {
1810                         return false;
1811                 }
1812         }
1813         d_printf("altname: %s\n", altname);
1814
1815         status = cli_qpathinfo3(cli, name, &b_time, &a_time, &m_time, &c_time,
1816                                 &size, &mode, NULL);
1817         if (!NT_STATUS_IS_OK(status)) {
1818                 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1819                          name);
1820                 return false;
1821         }
1822
1823         tmp = full_timespec_to_nt_time(&b_time);
1824         d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1825
1826         tmp = full_timespec_to_nt_time(&a_time);
1827         d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1828
1829         tmp = full_timespec_to_nt_time(&m_time);
1830         d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1831
1832         tmp = full_timespec_to_nt_time(&c_time);
1833         d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1834
1835         d_printf("attributes: %s (%x)\n", attr_str(talloc_tos(), mode), mode);
1836
1837         status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1838                                        &streams);
1839         if (!NT_STATUS_IS_OK(status)) {
1840                 d_printf("%s getting streams for %s\n", nt_errstr(status),
1841                          name);
1842                 return false;
1843         }
1844
1845         for (i=0; i<num_streams; i++) {
1846                 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1847                          (unsigned long long)streams[i].size);
1848         }
1849
1850         if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
1851                 char *subst, *print;
1852                 uint32_t flags;
1853
1854                 status = cli_readlink(cli, name, talloc_tos(), &subst, &print,
1855                                       &flags);
1856                 if (!NT_STATUS_IS_OK(status)) {
1857                         d_fprintf(stderr, "cli_readlink returned %s\n",
1858                                   nt_errstr(status));
1859                 } else {
1860                         d_printf("symlink: subst=[%s], print=[%s], flags=%x\n",
1861                                  subst, print, flags);
1862                         TALLOC_FREE(subst);
1863                         TALLOC_FREE(print);
1864                 }
1865         }
1866
1867         status = cli_ntcreate(cli, name, 0,
1868                               SEC_FILE_READ_DATA | SEC_FILE_READ_ATTRIBUTE |
1869                               SEC_STD_SYNCHRONIZE, 0,
1870                               FILE_SHARE_READ|FILE_SHARE_WRITE
1871                               |FILE_SHARE_DELETE,
1872                               FILE_OPEN, 0x0, 0x0, &fnum, NULL);
1873         if (!NT_STATUS_IS_OK(status)) {
1874                 /*
1875                  * Ignore failure, it does not hurt if we can't list
1876                  * snapshots
1877                  */
1878                 return 0;
1879         }
1880         /*
1881          * In order to get shadow copy data over SMB1 we
1882          * must call twice, once with 'get_names = false'
1883          * to get the size, then again with 'get_names = true'
1884          * to get the data or a Windows server fails to return
1885          * valid info. Samba doesn't have this bug. JRA.
1886          */
1887
1888         status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1889                                       false, &snapshots, &num_snapshots);
1890         if (!NT_STATUS_IS_OK(status)) {
1891                 cli_close(cli, fnum);
1892                 return 0;
1893         }
1894         status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1895                                       true, &snapshots, &num_snapshots);
1896         if (!NT_STATUS_IS_OK(status)) {
1897                 cli_close(cli, fnum);
1898                 return 0;
1899         }
1900
1901         for (i=0; i<num_snapshots; i++) {
1902                 char *snap_name;
1903
1904                 d_printf("%s\n", snapshots[i]);
1905                 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1906                                             snapshots[i], name);
1907                 status = cli_qpathinfo3(cli, snap_name, &b_time, &a_time,
1908                                         &m_time, &c_time, &size,
1909                                         NULL, NULL);
1910                 if (!NT_STATUS_IS_OK(status)) {
1911                         d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1912                                   snap_name, nt_errstr(status));
1913                         TALLOC_FREE(snap_name);
1914                         continue;
1915                 }
1916                 tmp = unix_timespec_to_nt_time(b_time);
1917                 d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1918                 tmp = unix_timespec_to_nt_time(a_time);
1919                 d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1920                 tmp =unix_timespec_to_nt_time(m_time);
1921                 d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1922                 tmp = unix_timespec_to_nt_time(c_time);
1923                 d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1924                 d_printf("size: %d\n", (int)size);
1925         }
1926
1927         TALLOC_FREE(snapshots);
1928         cli_close(cli, fnum);
1929
1930         return 0;
1931 }
1932
1933 /****************************************************************************
1934  Show all info we can get
1935 ****************************************************************************/
1936
1937 static int cmd_allinfo(void)
1938 {
1939         TALLOC_CTX *ctx = talloc_tos();
1940         char *name;
1941         char *buf;
1942
1943         name = talloc_strdup(ctx, client_get_cur_dir());
1944         if (!name) {
1945                 return 1;
1946         }
1947
1948         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1949                 d_printf("allinfo <file>\n");
1950                 return 1;
1951         }
1952         name = talloc_asprintf_append(name, "%s", buf);
1953         if (!name) {
1954                 return 1;
1955         }
1956         name = client_clean_name(ctx, name);
1957         if (name == NULL) {
1958                 return 1;
1959         }
1960         do_allinfo(name);
1961
1962         return 0;
1963 }
1964
1965 /****************************************************************************
1966  Put a single file.
1967 ****************************************************************************/
1968
1969 static int do_put(const char *rname, const char *lname, bool reput)
1970 {
1971         TALLOC_CTX *ctx = talloc_tos();
1972         uint16_t fnum;
1973         FILE *f;
1974         off_t start = 0;
1975         int rc = 0;
1976         struct timespec tp_start;
1977         struct cli_state *targetcli;
1978         char *targetname = NULL;
1979         struct push_state state;
1980         NTSTATUS status;
1981
1982         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
1983                                 cli, rname, &targetcli, &targetname);
1984         if (!NT_STATUS_IS_OK(status)) {
1985                 d_printf("Failed to open %s: %s\n", rname, nt_errstr(status));
1986                 return 1;
1987         }
1988
1989         clock_gettime_mono(&tp_start);
1990
1991         if (reput) {
1992                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1993                 if (NT_STATUS_IS_OK(status)) {
1994                         if (!NT_STATUS_IS_OK(status = cli_qfileinfo_basic(
1995                                                      targetcli, fnum, NULL,
1996                                                      &start, NULL, NULL,
1997                                                      NULL, NULL, NULL)) &&
1998                             !NT_STATUS_IS_OK(status = cli_getattrE(
1999                                                      targetcli, fnum, NULL,
2000                                                      &start, NULL, NULL,
2001                                                      NULL))) {
2002                                 d_printf("getattrib: %s\n", nt_errstr(status));
2003                                 return 1;
2004                         }
2005                 }
2006         } else {
2007                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
2008         }
2009
2010         if (!NT_STATUS_IS_OK(status)) {
2011                 d_printf("%s opening remote file %s\n", nt_errstr(status),
2012                          rname);
2013                 return 1;
2014         }
2015
2016         /* allow files to be piped into smbclient
2017            jdblair 24.jun.98
2018
2019            Note that in this case this function will exit(0) rather
2020            than returning. */
2021         if (!strcmp(lname, "-")) {
2022                 f = stdin;
2023                 /* size of file is not known */
2024         } else {
2025                 f = fopen(lname, "r");
2026                 if (f && reput) {
2027                         if (fseek(f, start, SEEK_SET) == -1) {
2028                                 d_printf("Error seeking local file\n");
2029                                 fclose(f);
2030                                 return 1;
2031                         }
2032                 }
2033         }
2034
2035         if (!f) {
2036                 d_printf("Error opening local file %s\n",lname);
2037                 return 1;
2038         }
2039
2040         DEBUG(1,("putting file %s as %s ",lname,
2041                  rname));
2042
2043         setvbuf(f, NULL, _IOFBF, io_bufsize);
2044
2045         state.f = f;
2046         state.nread = 0;
2047
2048         status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
2049                           &state);
2050         if (!NT_STATUS_IS_OK(status)) {
2051                 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
2052                 rc = 1;
2053         }
2054
2055         status = cli_close(targetcli, fnum);
2056         if (!NT_STATUS_IS_OK(status)) {
2057                 d_printf("%s closing remote file %s\n", nt_errstr(status),
2058                          rname);
2059                 if (f != stdin) {
2060                         fclose(f);
2061                 }
2062                 return 1;
2063         }
2064
2065         if (f != stdin) {
2066                 fclose(f);
2067         }
2068
2069         {
2070                 struct timespec tp_end;
2071                 int this_time;
2072
2073                 clock_gettime_mono(&tp_end);
2074                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
2075                 put_total_time_ms += this_time;
2076                 put_total_size += state.nread;
2077
2078                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
2079                          state.nread / (1.024*this_time + 1.0e-4),
2080                          put_total_size / (1.024*put_total_time_ms)));
2081         }
2082
2083         if (f == stdin) {
2084                 cli_shutdown(cli);
2085                 popt_free_cmdline_auth_info();
2086                 exit(rc);
2087         }
2088
2089         return rc;
2090 }
2091
2092 /****************************************************************************
2093  Put a file.
2094 ****************************************************************************/
2095
2096 static int cmd_put(void)
2097 {
2098         TALLOC_CTX *ctx = talloc_tos();
2099         char *lname;
2100         char *rname;
2101         char *buf;
2102
2103         rname = talloc_strdup(ctx, client_get_cur_dir());
2104         if (!rname) {
2105                 return 1;
2106         }
2107
2108         if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
2109                 d_printf("put <filename>\n");
2110                 return 1;
2111         }
2112
2113         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2114                 rname = talloc_asprintf_append(rname, "%s", buf);
2115         } else {
2116                 rname = talloc_asprintf_append(rname, "%s", lname);
2117         }
2118         if (!rname) {
2119                 return 1;
2120         }
2121
2122         rname = client_clean_name(ctx, rname);
2123         if (!rname) {
2124                 return 1;
2125         }
2126
2127         {
2128                 SMB_STRUCT_STAT st;
2129                 /* allow '-' to represent stdin
2130                    jdblair, 24.jun.98 */
2131                 if (!file_exist_stat(lname, &st, false) &&
2132                     (strcmp(lname,"-"))) {
2133                         d_printf("%s does not exist\n",lname);
2134                         return 1;
2135                 }
2136         }
2137
2138         return do_put(rname, lname, false);
2139 }
2140
2141 /*************************************
2142  File list structure.
2143 *************************************/
2144
2145 static struct file_list {
2146         struct file_list *prev, *next;
2147         char *file_path;
2148         bool isdir;
2149 } *file_list;
2150
2151 /****************************************************************************
2152  Free a file_list structure.
2153 ****************************************************************************/
2154
2155 static void free_file_list (struct file_list *l_head)
2156 {
2157         struct file_list *list, *next;
2158
2159         for (list = l_head; list; list = next) {
2160                 next = list->next;
2161                 DLIST_REMOVE(l_head, list);
2162                 TALLOC_FREE(list);
2163         }
2164 }
2165
2166 /****************************************************************************
2167  Seek in a directory/file list until you get something that doesn't start with
2168  the specified name.
2169 ****************************************************************************/
2170
2171 static bool seek_list(struct file_list *list, char *name)
2172 {
2173         while (list) {
2174                 trim_string(list->file_path,"./","\n");
2175                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
2176                         return true;
2177                 }
2178                 list = list->next;
2179         }
2180
2181         return false;
2182 }
2183
2184 /****************************************************************************
2185  Set the file selection mask.
2186 ****************************************************************************/
2187
2188 static int cmd_select(void)
2189 {
2190         TALLOC_CTX *ctx = talloc_tos();
2191         char *new_fs = NULL;
2192         next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
2193                 ;
2194         if (new_fs) {
2195                 client_set_fileselection(new_fs);
2196         } else {
2197                 client_set_fileselection("");
2198         }
2199         return 0;
2200 }
2201
2202 /****************************************************************************
2203   Recursive file matching function act as find
2204   match must be always set to true when calling this function
2205 ****************************************************************************/
2206
2207 static int file_find(TALLOC_CTX *ctx,
2208                         struct file_list **list,
2209                         const char *directory,
2210                         const char *expression,
2211                         bool match)
2212 {
2213         DIR *dir;
2214         struct file_list *entry;
2215         struct stat statbuf;
2216         int ret;
2217         char *path;
2218         bool isdir;
2219         const char *dname;
2220
2221         dir = opendir(directory);
2222         if (!dir)
2223                 return -1;
2224
2225         while ((dname = readdirname(dir))) {
2226                 if (!strcmp("..", dname))
2227                         continue;
2228                 if (!strcmp(".", dname))
2229                         continue;
2230
2231                 path = talloc_asprintf(ctx, "%s/%s", directory, dname);
2232                 if (path == NULL) {
2233                         continue;
2234                 }
2235
2236                 isdir = false;
2237                 if (!match || !gen_fnmatch(expression, dname)) {
2238                         if (recurse) {
2239                                 ret = stat(path, &statbuf);
2240                                 if (ret == 0) {
2241                                         if (S_ISDIR(statbuf.st_mode)) {
2242                                                 isdir = true;
2243                                                 ret = file_find(ctx,
2244                                                                 list,
2245                                                                 path,
2246                                                                 expression,
2247                                                                 false);
2248                                         }
2249                                 } else {
2250                                         d_printf("file_find: cannot stat file %s\n", path);
2251                                 }
2252
2253                                 if (ret == -1) {
2254                                         TALLOC_FREE(path);
2255                                         closedir(dir);
2256                                         return -1;
2257                                 }
2258                         }
2259                         entry = talloc_zero(ctx, struct file_list);
2260                         if (!entry) {
2261                                 d_printf("Out of memory in file_find\n");
2262                                 closedir(dir);
2263                                 return -1;
2264                         }
2265                         entry->file_path = talloc_move(entry, &path);
2266                         entry->isdir = isdir;
2267                         DLIST_ADD(*list, entry);
2268                 } else {
2269                         TALLOC_FREE(path);
2270                 }
2271         }
2272
2273         closedir(dir);
2274         return 0;
2275 }
2276
2277 /****************************************************************************
2278  mput some files.
2279 ****************************************************************************/
2280
2281 static int cmd_mput(void)
2282 {
2283         TALLOC_CTX *ctx = talloc_tos();
2284         char *p = NULL;
2285
2286         while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2287                 int ret;
2288                 struct file_list *temp_list;
2289                 char *quest, *lname, *rname;
2290
2291                 file_list = NULL;
2292
2293                 ret = file_find(ctx, &file_list, ".", p, true);
2294                 if (ret) {
2295                         free_file_list(file_list);
2296                         continue;
2297                 }
2298
2299                 quest = NULL;
2300                 lname = NULL;
2301                 rname = NULL;
2302
2303                 for (temp_list = file_list; temp_list;
2304                      temp_list = temp_list->next) {
2305
2306                         SAFE_FREE(lname);
2307                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2308                                 continue;
2309                         }
2310                         trim_string(lname, "./", "/");
2311
2312                         /* check if it's a directory */
2313                         if (temp_list->isdir) {
2314                                 /* if (!recurse) continue; */
2315
2316                                 SAFE_FREE(quest);
2317                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2318                                         break;
2319                                 }
2320                                 if (prompt && !yesno(quest)) { /* No */
2321                                         /* Skip the directory */
2322                                         lname[strlen(lname)-1] = '/';
2323                                         if (!seek_list(temp_list, lname))
2324                                                 break;
2325                                 } else { /* Yes */
2326                                         SAFE_FREE(rname);
2327                                         if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2328                                                 break;
2329                                         }
2330                                         normalize_name(rname);
2331                                         {
2332                                                 char *tmp_rname =
2333                                                         client_clean_name(ctx, rname);
2334                                                 if (tmp_rname == NULL) {
2335                                                         break;
2336                                                 }
2337                                                 SAFE_FREE(rname);
2338                                                 rname = smb_xstrdup(tmp_rname);
2339                                                 TALLOC_FREE(tmp_rname);
2340                                                 if (rname == NULL) {
2341                                                         break;
2342                                                 }
2343                                         }
2344                                         if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2345                                             !do_mkdir(rname)) {
2346                                                 DEBUG (0, ("Unable to make dir, skipping..."));
2347                                                 /* Skip the directory */
2348                                                 lname[strlen(lname)-1] = '/';
2349                                                 if (!seek_list(temp_list, lname)) {
2350                                                         break;
2351                                                 }
2352                                         }
2353                                 }
2354                                 continue;
2355                         } else {
2356                                 SAFE_FREE(quest);
2357                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2358                                         break;
2359                                 }
2360                                 if (prompt && !yesno(quest)) {
2361                                         /* No */
2362                                         continue;
2363                                 }
2364
2365                                 /* Yes */
2366                                 SAFE_FREE(rname);
2367                                 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2368                                         break;
2369                                 }
2370                         }
2371
2372                         normalize_name(rname);
2373
2374                         {
2375                                 char *tmp_rname = client_clean_name(ctx, rname);
2376                                 if (tmp_rname == NULL) {
2377                                         break;
2378                                 }
2379                                 SAFE_FREE(rname);
2380                                 rname = smb_xstrdup(tmp_rname);
2381                                 TALLOC_FREE(tmp_rname);
2382                                 if (rname == NULL) {
2383                                         break;
2384                                 }
2385                         }
2386                         do_put(rname, lname, false);
2387                 }
2388                 free_file_list(file_list);
2389                 SAFE_FREE(quest);
2390                 SAFE_FREE(lname);
2391                 SAFE_FREE(rname);
2392         }
2393
2394         return 0;
2395 }
2396
2397 /****************************************************************************
2398  Cancel a print job.
2399 ****************************************************************************/
2400
2401 static int do_cancel(int job)
2402 {
2403         if (cli_printjob_del(cli, job)) {
2404                 d_printf("Job %d cancelled\n",job);
2405                 return 0;
2406         } else {
2407                 NTSTATUS status = cli_nt_error(cli);
2408                 d_printf("Error cancelling job %d : %s\n",
2409                          job, nt_errstr(status));
2410                 return 1;
2411         }
2412 }
2413
2414 /****************************************************************************
2415  Cancel a print job.
2416 ****************************************************************************/
2417
2418 static int cmd_cancel(void)
2419 {
2420         TALLOC_CTX *ctx = talloc_tos();
2421         char *buf = NULL;
2422         int job;
2423
2424         if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2425                 d_printf("cancel <jobid> ...\n");
2426                 return 1;
2427         }
2428         do {
2429                 job = atoi(buf);
2430                 do_cancel(job);
2431         } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2432
2433         return 0;
2434 }
2435
2436 /****************************************************************************
2437  Print a file.
2438 ****************************************************************************/
2439
2440 static int cmd_print(void)
2441 {
2442         TALLOC_CTX *ctx = talloc_tos();
2443         char *lname = NULL;
2444         char *rname = NULL;
2445         char *p = NULL;
2446
2447         if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2448                 d_printf("print <filename>\n");
2449                 return 1;
2450         }
2451
2452         rname = talloc_strdup(ctx, lname);
2453         if (!rname) {
2454                 return 1;
2455         }
2456         p = strrchr_m(rname,'/');
2457         if (p) {
2458                 rname = talloc_asprintf(ctx,
2459                                         "%s-%d",
2460                                         p+1,
2461                                         (int)getpid());
2462         }
2463         if (strequal(lname,"-")) {
2464                 rname = talloc_asprintf(ctx,
2465                                 "stdin-%d",
2466                                 (int)getpid());
2467         }
2468         if (!rname) {
2469                 return 1;
2470         }
2471
2472         return do_put(rname, lname, false);
2473 }
2474
2475 /****************************************************************************
2476  Show a print queue entry.
2477 ****************************************************************************/
2478
2479 static void queue_fn(struct print_job_info *p)
2480 {
2481         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
2482 }
2483
2484 /****************************************************************************
2485  Show a print queue.
2486 ****************************************************************************/
2487
2488 static int cmd_queue(void)
2489 {
2490         cli_print_queue(cli, queue_fn);
2491         return 0;
2492 }
2493
2494 /****************************************************************************
2495  Delete some files.
2496 ****************************************************************************/
2497
2498 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2499                    const char *dir)
2500 {
2501         TALLOC_CTX *ctx = talloc_tos();
2502         char *mask = NULL;
2503         NTSTATUS status;
2504
2505         mask = talloc_asprintf(ctx,
2506                                 "%s%c%s",
2507                                 dir,
2508                                 CLI_DIRSEP_CHAR,
2509                                 finfo->name);
2510         if (!mask) {
2511                 return NT_STATUS_NO_MEMORY;
2512         }
2513
2514         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
2515                 TALLOC_FREE(mask);
2516                 return NT_STATUS_OK;
2517         }
2518
2519         status = cli_unlink(cli_state, mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
2520         if (!NT_STATUS_IS_OK(status)) {
2521                 d_printf("%s deleting remote file %s\n",
2522                          nt_errstr(status), mask);
2523         }
2524         TALLOC_FREE(mask);
2525         return status;
2526 }
2527
2528 /****************************************************************************
2529  Delete some files.
2530 ****************************************************************************/
2531
2532 static int cmd_del(void)
2533 {
2534         TALLOC_CTX *ctx = talloc_tos();
2535         char *mask = NULL;
2536         char *buf = NULL;
2537         NTSTATUS status = NT_STATUS_OK;
2538         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
2539
2540         if (recurse) {
2541                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
2542         }
2543
2544         mask = talloc_strdup(ctx, client_get_cur_dir());
2545         if (!mask) {
2546                 return 1;
2547         }
2548         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2549                 d_printf("del <filename>\n");
2550                 return 1;
2551         }
2552         mask = talloc_asprintf_append(mask, "%s", buf);
2553         if (!mask) {
2554                 return 1;
2555         }
2556         mask = client_clean_name(ctx, mask);
2557         if (mask == NULL) {
2558                 return 1;
2559         }
2560
2561         status = do_list(mask,attribute,do_del,false,false);
2562         if (!NT_STATUS_IS_OK(status)) {
2563                 return 1;
2564         }
2565         return 0;
2566 }
2567
2568 /****************************************************************************
2569  Delete some files.
2570 ****************************************************************************/
2571
2572 static NTSTATUS delete_remote_files_list(struct cli_state *cli_state,
2573                                          struct file_list *flist)
2574 {
2575         NTSTATUS status = NT_STATUS_OK;
2576         struct file_list *deltree_list_iter = NULL;
2577
2578         for (deltree_list_iter = flist;
2579                         deltree_list_iter != NULL;
2580                         deltree_list_iter = deltree_list_iter->next) {
2581                 if (CLI_DIRSEP_CHAR == '/') {
2582                         /* POSIX. */
2583                         status = cli_posix_unlink(cli_state,
2584                                         deltree_list_iter->file_path);
2585                 } else if (deltree_list_iter->isdir) {
2586                         status = cli_rmdir(cli_state,
2587                                         deltree_list_iter->file_path);
2588                 } else {
2589                         status = cli_unlink(cli_state,
2590                                         deltree_list_iter->file_path,
2591                                         FILE_ATTRIBUTE_SYSTEM |
2592                                         FILE_ATTRIBUTE_HIDDEN);
2593                 }
2594                 if (!NT_STATUS_IS_OK(status)) {
2595                         d_printf("%s deleting remote %s %s\n",
2596                                 nt_errstr(status),
2597                                 deltree_list_iter->isdir ?
2598                                 "directory" : "file",
2599                                 deltree_list_iter->file_path);
2600                         return status;
2601                 }
2602         }
2603         return NT_STATUS_OK;
2604 }
2605
2606 /****************************************************************************
2607  Save a list of files to delete.
2608 ****************************************************************************/
2609
2610 static struct file_list *deltree_list_head;
2611
2612 static NTSTATUS do_deltree_list(struct cli_state *cli_state,
2613                                 struct file_info *finfo,
2614                                 const char *dir)
2615 {
2616         struct file_list **file_list_head_pp = &deltree_list_head;
2617         struct file_list *dt = NULL;
2618
2619         if (!do_this_one(finfo)) {
2620                 return NT_STATUS_OK;
2621         }
2622
2623         /* skip if this is . or .. */
2624         if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
2625                 return NT_STATUS_OK;
2626         }
2627
2628         dt = talloc_zero(NULL, struct file_list);
2629         if (dt == NULL) {
2630                 return NT_STATUS_NO_MEMORY;
2631         }
2632
2633         /* create absolute filename for cli_ntcreate() */
2634         dt->file_path = talloc_asprintf(dt,
2635                                         "%s%s%s",
2636                                         dir,
2637                                         CLI_DIRSEP_STR,
2638                                         finfo->name);
2639         if (dt->file_path == NULL) {
2640                 TALLOC_FREE(dt);
2641                 return NT_STATUS_NO_MEMORY;
2642         }
2643
2644         if (finfo->mode & FILE_ATTRIBUTE_DIRECTORY) {
2645                 dt->isdir = true;
2646         }
2647
2648         DLIST_ADD(*file_list_head_pp, dt);
2649         return NT_STATUS_OK;
2650 }
2651
2652 static int cmd_deltree(void)
2653 {
2654         TALLOC_CTX *ctx = talloc_tos();
2655         char *buf = NULL;
2656         NTSTATUS status = NT_STATUS_OK;
2657         struct file_list *deltree_list_norecurse = NULL;
2658         struct file_list *deltree_list_iter = NULL;
2659         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM |
2660                              FILE_ATTRIBUTE_HIDDEN |
2661                              FILE_ATTRIBUTE_DIRECTORY;
2662         bool ok;
2663         char *mask = talloc_strdup(ctx, client_get_cur_dir());
2664         if (mask == NULL) {
2665                 return 1;
2666         }
2667         ok = next_token_talloc(ctx, &cmd_ptr, &buf, NULL);
2668         if (!ok) {
2669                 d_printf("deltree <filename>\n");
2670                 return 1;
2671         }
2672         mask = talloc_asprintf_append(mask, "%s", buf);
2673         if (mask == NULL) {
2674                 return 1;
2675         }
2676         mask = client_clean_name(ctx, mask);
2677         if (mask == NULL) {
2678                 return 1;
2679         }
2680
2681         deltree_list_head = NULL;
2682
2683         /*
2684          * Get the list of directories to
2685          * delete (in case mask has a wildcard).
2686          */
2687         status = do_list(mask, attribute, do_deltree_list, false, true);
2688         if (!NT_STATUS_IS_OK(status)) {
2689                 goto err;
2690         }
2691         deltree_list_norecurse = deltree_list_head;
2692         deltree_list_head = NULL;
2693
2694         for (deltree_list_iter = deltree_list_norecurse;
2695              deltree_list_iter != NULL;
2696              deltree_list_iter = deltree_list_iter->next) {
2697
2698                 if (deltree_list_iter->isdir == false) {
2699                         /* Just a regular file. */
2700                         if (CLI_DIRSEP_CHAR == '/') {
2701                                 /* POSIX. */
2702                                 status = cli_posix_unlink(cli,
2703                                         deltree_list_iter->file_path);
2704                         } else {
2705                                 status = cli_unlink(cli,
2706                                         deltree_list_iter->file_path,
2707                                         FILE_ATTRIBUTE_SYSTEM |
2708                                         FILE_ATTRIBUTE_HIDDEN);
2709                         }
2710                         if (!NT_STATUS_IS_OK(status)) {
2711                                 goto err;
2712                         }
2713                         continue;
2714                 }
2715
2716                 /*
2717                  * Get the list of files or directories to
2718                  * delete in depth order.
2719                  */
2720                 status = do_list(deltree_list_iter->file_path,
2721                                  attribute,
2722                                  do_deltree_list,
2723                                  true,
2724                                  true);
2725                 if (!NT_STATUS_IS_OK(status)) {
2726                         goto err;
2727                 }
2728                 status = delete_remote_files_list(cli, deltree_list_head);
2729                 free_file_list(deltree_list_head);
2730                 deltree_list_head = NULL;
2731                 if (!NT_STATUS_IS_OK(status)) {
2732                         goto err;
2733                 }
2734         }
2735
2736         free_file_list(deltree_list_norecurse);
2737         free_file_list(deltree_list_head);
2738         return 0;
2739
2740   err:
2741
2742         free_file_list(deltree_list_norecurse);
2743         free_file_list(deltree_list_head);
2744         deltree_list_head = NULL;
2745         return 1;
2746 }
2747
2748
2749 /****************************************************************************
2750  Wildcard delete some files.
2751 ****************************************************************************/
2752
2753 static int cmd_wdel(void)
2754 {
2755         TALLOC_CTX *ctx = talloc_tos();
2756         char *mask = NULL;
2757         char *buf = NULL;
2758         uint16_t attribute;
2759         struct cli_state *targetcli;
2760         char *targetname = NULL;
2761         NTSTATUS status;
2762
2763         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2764                 d_printf("wdel 0x<attrib> <wcard>\n");
2765                 return 1;
2766         }
2767
2768         attribute = (uint16_t)strtol(buf, (char **)NULL, 16);
2769
2770         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2771                 d_printf("wdel 0x<attrib> <wcard>\n");
2772                 return 1;
2773         }
2774
2775         mask = talloc_asprintf(ctx, "%s%s",
2776                         client_get_cur_dir(),
2777                         buf);
2778         if (!mask) {
2779                 return 1;
2780         }
2781         mask = client_clean_name(ctx, mask);
2782         if (mask == NULL) {
2783                 return 1;
2784         }
2785
2786         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2787                                 cli, mask, &targetcli, &targetname);
2788         if (!NT_STATUS_IS_OK(status)) {
2789                 d_printf("cmd_wdel %s: %s\n", mask, nt_errstr(status));
2790                 return 1;
2791         }
2792
2793         status = cli_unlink(targetcli, targetname, attribute);
2794         if (!NT_STATUS_IS_OK(status)) {
2795                 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2796                          targetname);
2797         }
2798         return 0;
2799 }
2800
2801 /****************************************************************************
2802 ****************************************************************************/
2803
2804 static int cmd_open(void)
2805 {
2806         TALLOC_CTX *ctx = talloc_tos();
2807         char *mask = NULL;
2808         char *buf = NULL;
2809         char *targetname = NULL;
2810         struct cli_state *targetcli;
2811         uint16_t fnum = (uint16_t)-1;
2812         NTSTATUS status;
2813
2814         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2815                 d_printf("open <filename>\n");
2816                 return 1;
2817         }
2818         mask = talloc_asprintf(ctx,
2819                         "%s%s",
2820                         client_get_cur_dir(),
2821                         buf);
2822         if (!mask) {
2823                 return 1;
2824         }
2825
2826         mask = client_clean_name(ctx, mask);
2827         if (mask == NULL) {
2828                 return 1;
2829         }
2830
2831         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2832                         cli, mask, &targetcli, &targetname);
2833         if (!NT_STATUS_IS_OK(status)) {
2834                 d_printf("open %s: %s\n", mask, nt_errstr(status));
2835                 return 1;
2836         }
2837
2838         status = cli_ntcreate(targetcli, targetname, 0,
2839                         FILE_READ_DATA|FILE_WRITE_DATA, 0,
2840                         FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2841                         0x0, 0x0, &fnum, NULL);
2842         if (!NT_STATUS_IS_OK(status)) {
2843                 status = cli_ntcreate(targetcli, targetname, 0,
2844                                 FILE_READ_DATA, 0,
2845                                 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN,
2846                                 0x0, 0x0, &fnum, NULL);
2847                 if (NT_STATUS_IS_OK(status)) {
2848                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2849                 } else {
2850                         d_printf("Failed to open file %s. %s\n",
2851                                  targetname, nt_errstr(status));
2852                 }
2853         } else {
2854                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2855         }
2856         return 0;
2857 }
2858
2859 static int cmd_posix_encrypt(void)
2860 {
2861         TALLOC_CTX *ctx = talloc_tos();
2862         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2863         char *domain = NULL;
2864         char *user = NULL;
2865         char *password = NULL;
2866         struct cli_credentials *creds = NULL;
2867         struct cli_credentials *lcreds = NULL;
2868
2869         if (next_token_talloc(ctx, &cmd_ptr, &domain, NULL)) {
2870
2871                 if (!next_token_talloc(ctx, &cmd_ptr, &user, NULL)) {
2872                         d_printf("posix_encrypt domain user password\n");
2873                         return 1;
2874                 }
2875
2876                 if (!next_token_talloc(ctx, &cmd_ptr, &password, NULL)) {
2877                         d_printf("posix_encrypt domain user password\n");
2878                         return 1;
2879                 }
2880
2881                 lcreds = cli_session_creds_init(ctx,
2882                                                 user,
2883                                                 domain,
2884                                                 NULL, /* realm */
2885                                                 password,
2886                                                 false, /* use_kerberos */
2887                                                 false, /* fallback_after_kerberos */
2888                                                 false, /* use_ccache */
2889                                                 false); /* password_is_nt_hash */
2890                 if (lcreds == NULL) {
2891                         d_printf("cli_session_creds_init() failed.\n");
2892                         return -1;
2893                 }
2894                 creds = lcreds;
2895         } else {
2896                 bool auth_requested = false;
2897
2898                 creds = get_cmdline_auth_info_creds(
2899                                 popt_get_cmdline_auth_info());
2900
2901                 auth_requested = cli_credentials_authentication_requested(creds);
2902                 if (!auth_requested) {
2903                         d_printf("posix_encrypt domain user password\n");
2904                         return 1;
2905                 }
2906         }
2907
2908         status = cli_smb1_setup_encryption(cli, creds);
2909         /* gensec currently references the creds so we can't free them here */
2910         talloc_unlink(ctx, lcreds);
2911         if (!NT_STATUS_IS_OK(status)) {
2912                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2913         } else {
2914                 d_printf("encryption on\n");
2915                 smb_encrypt = true;
2916         }
2917
2918         return 0;
2919 }
2920
2921 /****************************************************************************
2922 ****************************************************************************/
2923
2924 static int cmd_posix_open(void)
2925 {
2926         TALLOC_CTX *ctx = talloc_tos();
2927         char *mask = NULL;
2928         char *buf = NULL;
2929         char *targetname = NULL;
2930         struct cli_state *targetcli;
2931         mode_t mode;
2932         uint16_t fnum;
2933         NTSTATUS status;
2934
2935         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2936                 d_printf("posix_open <filename> 0<mode>\n");
2937                 return 1;
2938         }
2939         mask = talloc_asprintf(ctx,
2940                         "%s%s",
2941                         client_get_cur_dir(),
2942                         buf);
2943         if (!mask) {
2944                 return 1;
2945         }
2946         mask = client_clean_name(ctx, mask);
2947         if (mask == NULL) {
2948                 return 1;
2949         }
2950
2951         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2952                 d_printf("posix_open <filename> 0<mode>\n");
2953                 return 1;
2954         }
2955         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2956
2957         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
2958                                 cli, mask, &targetcli, &targetname);
2959         if (!NT_STATUS_IS_OK(status)) {
2960                 d_printf("posix_open %s: %s\n", mask, nt_errstr(status));
2961                 return 1;
2962         }
2963
2964         status = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode,
2965                                 &fnum);
2966         if (!NT_STATUS_IS_OK(status)) {
2967                 status = cli_posix_open(targetcli, targetname,
2968                                         O_CREAT|O_RDONLY, mode, &fnum);
2969                 if (!NT_STATUS_IS_OK(status)) {
2970                         d_printf("Failed to open file %s. %s\n", targetname,
2971                                  nt_errstr(status));
2972                 } else {
2973                         d_printf("posix_open file %s: for readonly fnum %d\n",
2974                                  targetname, fnum);
2975                 }
2976         } else {
2977                 d_printf("posix_open file %s: for read/write fnum %d\n",
2978                          targetname, fnum);
2979         }
2980
2981         return 0;
2982 }
2983
2984 static int cmd_posix_mkdir(void)
2985 {
2986         TALLOC_CTX *ctx = talloc_tos();
2987         char *mask = NULL;
2988         char *buf = NULL;
2989         char *targetname = NULL;
2990         struct cli_state *targetcli;
2991         mode_t mode;
2992         NTSTATUS status;
2993
2994         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2995                 d_printf("posix_mkdir <filename> 0<mode>\n");
2996                 return 1;
2997         }
2998         mask = talloc_asprintf(ctx,
2999                         "%s%s",
3000                         client_get_cur_dir(),
3001                         buf);
3002         if (!mask) {
3003                 return 1;
3004         }
3005         mask = client_clean_name(ctx, mask);
3006         if (mask == NULL) {
3007                 return 1;
3008         }
3009
3010         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3011                 d_printf("posix_mkdir <filename> 0<mode>\n");
3012                 return 1;
3013         }
3014         mode = (mode_t)strtol(buf, (char **)NULL, 8);
3015
3016         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3017                                 cli, mask, &targetcli, &targetname);
3018         if (!NT_STATUS_IS_OK(status)) {
3019                 d_printf("posix_mkdir %s: %s\n", mask, nt_errstr(status));
3020                 return 1;
3021         }
3022
3023         status = cli_posix_mkdir(targetcli, targetname, mode);
3024         if (!NT_STATUS_IS_OK(status)) {
3025                 d_printf("Failed to open file %s. %s\n",
3026                          targetname, nt_errstr(status));
3027         } else {
3028                 d_printf("posix_mkdir created directory %s\n", targetname);
3029         }
3030         return 0;
3031 }
3032
3033 static int cmd_posix_unlink(void)
3034 {
3035         TALLOC_CTX *ctx = talloc_tos();
3036         char *mask = NULL;
3037         char *buf = NULL;
3038         char *targetname = NULL;
3039         struct cli_state *targetcli;
3040         NTSTATUS status;
3041
3042         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3043                 d_printf("posix_unlink <filename>\n");
3044                 return 1;
3045         }
3046         mask = talloc_asprintf(ctx,
3047                         "%s%s",
3048                         client_get_cur_dir(),
3049                         buf);
3050         if (!mask) {
3051                 return 1;
3052         }
3053         mask = client_clean_name(ctx, mask);
3054         if (mask == NULL) {
3055                 return 1;
3056         }
3057
3058         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3059                                 cli, mask, &targetcli, &targetname);
3060         if (!NT_STATUS_IS_OK(status)) {
3061                 d_printf("posix_unlink %s: %s\n", mask, nt_errstr(status));
3062                 return 1;
3063         }
3064
3065         status = cli_posix_unlink(targetcli, targetname);
3066         if (!NT_STATUS_IS_OK(status)) {
3067                 d_printf("Failed to unlink file %s. %s\n",
3068                          targetname, nt_errstr(status));
3069         } else {
3070                 d_printf("posix_unlink deleted file %s\n", targetname);
3071         }
3072
3073         return 0;
3074 }
3075
3076 static int cmd_posix_rmdir(void)
3077 {
3078         TALLOC_CTX *ctx = talloc_tos();
3079         char *mask = NULL;
3080         char *buf = NULL;
3081         char *targetname = NULL;
3082         struct cli_state *targetcli;
3083         NTSTATUS status;
3084
3085         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3086                 d_printf("posix_rmdir <filename>\n");
3087                 return 1;
3088         }
3089         mask = talloc_asprintf(ctx,
3090                         "%s%s",
3091                         client_get_cur_dir(),
3092                         buf);
3093         if (!mask) {
3094                 return 1;
3095         }
3096         mask = client_clean_name(ctx, mask);
3097         if (mask == NULL) {
3098                 return 1;
3099         }
3100
3101         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3102                         cli, mask, &targetcli, &targetname);
3103         if (!NT_STATUS_IS_OK(status)) {
3104                 d_printf("posix_rmdir %s: %s\n", mask, nt_errstr(status));
3105                 return 1;
3106         }
3107
3108         status = cli_posix_rmdir(targetcli, targetname);
3109         if (!NT_STATUS_IS_OK(status)) {
3110                 d_printf("Failed to unlink directory %s. %s\n",
3111                          targetname, nt_errstr(status));
3112         } else {
3113                 d_printf("posix_rmdir deleted directory %s\n", targetname);
3114         }
3115
3116         return 0;
3117 }
3118
3119 static int cmd_close(void)
3120 {
3121         TALLOC_CTX *ctx = talloc_tos();
3122         char *buf = NULL;
3123         int fnum;
3124         NTSTATUS status;
3125
3126         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3127                 d_printf("close <fnum>\n");
3128                 return 1;
3129         }
3130
3131         fnum = atoi(buf);
3132         /* We really should use the targetcli here.... */
3133         status = cli_close(cli, fnum);
3134         if (!NT_STATUS_IS_OK(status)) {
3135                 d_printf("close %d: %s\n", fnum, nt_errstr(status));
3136                 return 1;
3137         }
3138         return 0;
3139 }
3140
3141 static int cmd_posix(void)
3142 {
3143         TALLOC_CTX *ctx = talloc_tos();
3144         uint16_t major, minor;
3145         uint32_t caplow, caphigh;
3146         char *caps;
3147         NTSTATUS status;
3148
3149         if (!SERVER_HAS_UNIX_CIFS(cli)) {
3150                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
3151                 return 1;
3152         }
3153
3154         status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
3155                                              &caphigh);
3156         if (!NT_STATUS_IS_OK(status)) {
3157                 d_printf("Can't get UNIX CIFS extensions version from "
3158                          "server: %s\n", nt_errstr(status));
3159                 return 1;
3160         }
3161
3162         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
3163
3164         caps = talloc_strdup(ctx, "");
3165         if (!caps) {
3166                 return 1;
3167         }
3168         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
3169                 caps = talloc_asprintf_append(caps, "locks ");
3170                 if (!caps) {
3171                         return 1;
3172                 }
3173         }
3174         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
3175                 caps = talloc_asprintf_append(caps, "acls ");
3176                 if (!caps) {
3177                         return 1;
3178                 }
3179         }
3180         if (caplow & CIFS_UNIX_XATTTR_CAP) {
3181                 caps = talloc_asprintf_append(caps, "eas ");
3182                 if (!caps) {
3183                         return 1;
3184                 }
3185         }
3186         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3187                 caps = talloc_asprintf_append(caps, "pathnames ");
3188                 if (!caps) {
3189                         return 1;
3190                 }
3191         }
3192         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
3193                 caps = talloc_asprintf_append(caps, "posix_path_operations ");
3194                 if (!caps) {
3195                         return 1;
3196                 }
3197         }
3198         if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
3199                 caps = talloc_asprintf_append(caps, "large_read ");
3200                 if (!caps) {
3201                         return 1;
3202                 }
3203         }
3204         if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
3205                 caps = talloc_asprintf_append(caps, "large_write ");
3206                 if (!caps) {
3207                         return 1;
3208                 }
3209         }
3210         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
3211                 caps = talloc_asprintf_append(caps, "posix_encrypt ");
3212                 if (!caps) {
3213                         return 1;
3214                 }
3215         }
3216         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
3217                 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
3218                 if (!caps) {
3219                         return 1;
3220                 }
3221         }
3222
3223         if (*caps && caps[strlen(caps)-1] == ' ') {
3224                 caps[strlen(caps)-1] = '\0';
3225         }
3226
3227         d_printf("Server supports CIFS capabilities %s\n", caps);
3228
3229         status = cli_set_unix_extensions_capabilities(cli, major, minor,
3230                                                       caplow, caphigh);
3231         if (!NT_STATUS_IS_OK(status)) {
3232                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
3233                          nt_errstr(status));
3234                 return 1;
3235         }
3236
3237         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
3238                 CLI_DIRSEP_CHAR = '/';
3239                 *CLI_DIRSEP_STR = '/';
3240                 client_set_cur_dir(CLI_DIRSEP_STR);
3241         }
3242
3243         return 0;
3244 }
3245
3246 static int cmd_lock(void)
3247 {
3248         TALLOC_CTX *ctx = talloc_tos();
3249         char *buf = NULL;
3250         uint64_t start, len;
3251         enum brl_type lock_type;
3252         int fnum;
3253         NTSTATUS status;
3254
3255         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3256                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3257                 return 1;
3258         }
3259         fnum = atoi(buf);
3260
3261         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3262                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3263                 return 1;
3264         }
3265
3266         if (*buf == 'r' || *buf == 'R') {
3267                 lock_type = READ_LOCK;
3268         } else if (*buf == 'w' || *buf == 'W') {
3269                 lock_type = WRITE_LOCK;
3270         } else {
3271                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3272                 return 1;
3273         }
3274
3275         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3276                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3277                 return 1;
3278         }
3279
3280         start = (uint64_t)strtol(buf, (char **)NULL, 16);
3281
3282         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3283                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
3284                 return 1;
3285         }
3286
3287         len = (uint64_t)strtol(buf, (char **)NULL, 16);
3288
3289         status = cli_posix_lock(cli, fnum, start, len, true, lock_type);
3290         if (!NT_STATUS_IS_OK(status)) {
3291                 d_printf("lock failed %d: %s\n", fnum, nt_errstr(status));
3292         }
3293
3294         return 0;
3295 }
3296
3297 static int cmd_unlock(void)
3298 {
3299         TALLOC_CTX *ctx = talloc_tos();
3300         char *buf = NULL;
3301         uint64_t start, len;
3302         int fnum;
3303         NTSTATUS status;
3304
3305         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3306                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3307                 return 1;
3308         }
3309         fnum = atoi(buf);
3310
3311         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3312                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3313                 return 1;
3314         }
3315
3316         start = (uint64_t)strtol(buf, (char **)NULL, 16);
3317
3318         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3319                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
3320                 return 1;
3321         }
3322
3323         len = (uint64_t)strtol(buf, (char **)NULL, 16);
3324
3325         status = cli_posix_unlock(cli, fnum, start, len);
3326         if (!NT_STATUS_IS_OK(status)) {
3327                 d_printf("unlock failed %d: %s\n", fnum, nt_errstr(status));
3328         }
3329
3330         return 0;
3331 }
3332
3333 static int cmd_posix_whoami(void)
3334 {
3335         TALLOC_CTX *ctx = talloc_tos();
3336         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
3337         uint64_t uid = 0;
3338         uint64_t gid = 0;
3339         uint32_t num_gids = 0;
3340         uint32_t num_sids = 0;
3341         uint64_t *gids = NULL;
3342         struct dom_sid *sids = NULL;
3343         bool guest = false;
3344         uint32_t i;
3345
3346         status = cli_posix_whoami(cli,
3347                         ctx,
3348                         &uid,
3349                         &gid,
3350                         &num_gids,
3351                         &gids,
3352                         &num_sids,
3353                         &sids,
3354                         &guest);
3355
3356         if (!NT_STATUS_IS_OK(status)) {
3357                 d_printf("posix_whoami failed with error %s\n", nt_errstr(status));
3358                 return 1;
3359         }
3360
3361         d_printf("GUEST:%s\n", guest ? "True" : "False");
3362         d_printf("UID:%" PRIu64 "\n", uid);
3363         d_printf("GID:%" PRIu64 "\n", gid);
3364         d_printf("NUM_GIDS:%" PRIu32 "\n", num_gids);
3365         for (i = 0; i < num_gids; i++) {
3366                 d_printf("GIDS[%" PRIu32 "]:%" PRIu64 "\n", i, gids[i]);
3367         }
3368         d_printf("NUM_SIDS:%" PRIu32 "\n", num_sids);
3369         for (i = 0; i < num_sids; i++) {
3370                 struct dom_sid_buf buf;
3371                 d_printf("SIDS[%" PRIu32 "]:%s\n",
3372                          i,
3373                          dom_sid_str_buf(&sids[i], &buf));
3374         }
3375         return 0;
3376 }
3377
3378
3379 /****************************************************************************
3380  Remove a directory.
3381 ****************************************************************************/
3382
3383 static int cmd_rmdir(void)
3384 {
3385         TALLOC_CTX *ctx = talloc_tos();
3386         char *mask = NULL;
3387         char *buf = NULL;
3388         char *targetname = NULL;
3389         struct cli_state *targetcli;
3390         NTSTATUS status;
3391
3392         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3393                 d_printf("rmdir <dirname>\n");
3394                 return 1;
3395         }
3396         mask = talloc_asprintf(ctx,
3397                         "%s%s",
3398                         client_get_cur_dir(),
3399                         buf);
3400         if (!mask) {
3401                 return 1;
3402         }
3403         mask = client_clean_name(ctx, mask);
3404         if (mask == NULL) {
3405                 return 1;
3406         }
3407
3408         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3409                         cli, mask, &targetcli, &targetname);
3410         if (!NT_STATUS_IS_OK(status)) {
3411                 d_printf("rmdir %s: %s\n", mask, nt_errstr(status));
3412                 return 1;
3413         }
3414
3415         status = cli_rmdir(targetcli, targetname);
3416         if (!NT_STATUS_IS_OK(status)) {
3417                 d_printf("%s removing remote directory file %s\n",
3418                          nt_errstr(status), mask);
3419         }
3420
3421         return 0;
3422 }
3423
3424 /****************************************************************************
3425  UNIX hardlink.
3426 ****************************************************************************/
3427
3428 static int cmd_link(void)
3429 {
3430         TALLOC_CTX *ctx = talloc_tos();
3431         char *oldname = NULL;
3432         char *newname = NULL;
3433         char *buf = NULL;
3434         char *buf2 = NULL;
3435         char *targetname = NULL;
3436         struct cli_state *targetcli;
3437         NTSTATUS status;
3438
3439         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3440             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3441                 d_printf("link <oldname> <newname>\n");
3442                 return 1;
3443         }
3444         oldname = talloc_asprintf(ctx,
3445                         "%s%s",
3446                         client_get_cur_dir(),
3447                         buf);
3448         if (!oldname) {
3449                 return 1;
3450         }
3451         oldname = client_clean_name(ctx, oldname);
3452         if (oldname == NULL) {
3453                 return 1;
3454         }
3455         newname = talloc_asprintf(ctx,
3456                         "%s%s",
3457                         client_get_cur_dir(),
3458                         buf2);
3459         if (!newname) {
3460                 return 1;
3461         }
3462         newname = client_clean_name(ctx, newname);
3463         if (newname == NULL) {
3464                 return 1;
3465         }
3466
3467         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3468                         cli, oldname, &targetcli, &targetname);
3469         if (!NT_STATUS_IS_OK(status)) {
3470                 d_printf("link %s: %s\n", oldname, nt_errstr(status));
3471                 return 1;
3472         }
3473
3474         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3475                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3476                 return 1;
3477         }
3478
3479         status = cli_posix_hardlink(targetcli, targetname, newname);
3480         if (!NT_STATUS_IS_OK(status)) {
3481                 d_printf("%s linking files (%s -> %s)\n",
3482                          nt_errstr(status), newname, oldname);
3483                 return 1;
3484         }
3485         return 0;
3486 }
3487
3488 /****************************************************************************
3489  UNIX readlink.
3490 ****************************************************************************/
3491
3492 static int cmd_readlink(void)
3493 {
3494         TALLOC_CTX *ctx = talloc_tos();
3495         char *name= NULL;
3496         char *buf = NULL;
3497         char *targetname = NULL;
3498         char *linkname = NULL;
3499         struct cli_state *targetcli;
3500         NTSTATUS status;
3501
3502         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3503                 d_printf("readlink <name>\n");
3504                 return 1;
3505         }
3506         name = talloc_asprintf(ctx,
3507                         "%s%s",
3508                         client_get_cur_dir(),
3509                         buf);
3510         if (!name) {
3511                 return 1;
3512         }
3513         name = client_clean_name(ctx, name);
3514         if (name == NULL) {
3515                 return 1;
3516         }
3517
3518         status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(),
3519                         cli, name, &targetcli, &targetname);
3520         if (!NT_STATUS_IS_OK(status)) {
3521                 d_printf("readlink %s: %s\n", name, nt_errstr(status));
3522                 return 1;
3523         }
3524
3525         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3526                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3527                 return 1;
3528         }
3529
3530         status = cli_posix_readlink(targetcli, name, talloc_tos(), &linkname);
3531         if (!NT_STATUS_IS_OK(status)) {
3532                 d_printf("%s readlink on file %s\n",
3533                          nt_errstr(status), name);
3534                 return 1;
3535         }
3536
3537         d_printf("%s -> %s\n", name, linkname);
3538
3539         TALLOC_FREE(linkname);
3540
3541         return 0;
3542 }
3543
3544
3545 /****************************************************************************
3546  UNIX symlink.
3547 ****************************************************************************/
3548
3549 static int cmd_symlink(void)
3550 {
3551         TALLOC_CTX *ctx = talloc_tos();