1ede29a0e6c92d79e7d939fa7ea736508c2ada44
[samba.git] / source3 / client / client.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB client
4    Copyright (C) Andrew Tridgell          1994-1998
5    Copyright (C) Simo Sorce               2001-2002
6    Copyright (C) Jelmer Vernooij          2003
7    Copyright (C) Gerald (Jerry) Carter    2004
8    Copyright (C) Jeremy Allison           1994-2007
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "popt_common.h"
26 #include "client/client_proto.h"
27 #include "../librpc/gen_ndr/ndr_srvsvc_c.h"
28 #include "../lib/util/select.h"
29 #include "system/readline.h"
30 #include "../libcli/smbreadline/smbreadline.h"
31 #include "../libcli/security/security.h"
32 #include "system/select.h"
33
34 #ifndef REGISTER
35 #define REGISTER 0
36 #endif
37
38 extern int do_smb_browse(void); /* mDNS browsing */
39
40 extern bool override_logfile;
41 extern char tar_type;
42
43 static int port = 0;
44 static char *service;
45 static char *desthost;
46 static char *calling_name;
47 static bool grepable = false;
48 static char *cmdstr = NULL;
49 const char *cmd_ptr = NULL;
50
51 static int io_bufsize = 524288;
52
53 static int name_type = 0x20;
54 static int max_protocol = PROTOCOL_NT1;
55
56 static int process_tok(char *tok);
57 static int cmd_help(void);
58
59 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
60
61 /* 30 second timeout on most commands */
62 #define CLIENT_TIMEOUT (30*1000)
63 #define SHORT_TIMEOUT (5*1000)
64
65 /* value for unused fid field in trans2 secondary request */
66 #define FID_UNUSED (0xFFFF)
67
68 time_t newer_than = 0;
69 static int archive_level = 0;
70
71 static bool translation = false;
72 static bool have_ip;
73
74 /* clitar bits insert */
75 extern int blocksize;
76 extern bool tar_inc;
77 extern bool tar_reset;
78 /* clitar bits end */
79
80 static bool prompt = true;
81
82 static bool recurse = false;
83 static bool showacls = false;
84 bool lowercase = false;
85
86 static struct sockaddr_storage dest_ss;
87 static char dest_ss_str[INET6_ADDRSTRLEN];
88
89 #define SEPARATORS " \t\n\r"
90
91 static bool abort_mget = true;
92
93 /* timing globals */
94 uint64_t get_total_size = 0;
95 unsigned int get_total_time_ms = 0;
96 static uint64_t put_total_size = 0;
97 static unsigned int put_total_time_ms = 0;
98
99 /* totals globals */
100 static double dir_total;
101
102 /* encrypted state. */
103 static bool smb_encrypt;
104
105 /* root cli_state connection */
106
107 struct cli_state *cli;
108
109 static char CLI_DIRSEP_CHAR = '\\';
110 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
111
112 /* Authentication for client connections. */
113 struct user_auth_info *auth_info;
114
115 /* Accessor functions for directory paths. */
116 static char *fileselection;
117 static const char *client_get_fileselection(void)
118 {
119         if (fileselection) {
120                 return fileselection;
121         }
122         return "";
123 }
124
125 static const char *client_set_fileselection(const char *new_fs)
126 {
127         SAFE_FREE(fileselection);
128         if (new_fs) {
129                 fileselection = SMB_STRDUP(new_fs);
130         }
131         return client_get_fileselection();
132 }
133
134 static char *cwd;
135 static const char *client_get_cwd(void)
136 {
137         if (cwd) {
138                 return cwd;
139         }
140         return CLI_DIRSEP_STR;
141 }
142
143 static const char *client_set_cwd(const char *new_cwd)
144 {
145         SAFE_FREE(cwd);
146         if (new_cwd) {
147                 cwd = SMB_STRDUP(new_cwd);
148         }
149         return client_get_cwd();
150 }
151
152 static char *cur_dir;
153 const char *client_get_cur_dir(void)
154 {
155         if (cur_dir) {
156                 return cur_dir;
157         }
158         return CLI_DIRSEP_STR;
159 }
160
161 const char *client_set_cur_dir(const char *newdir)
162 {
163         SAFE_FREE(cur_dir);
164         if (newdir) {
165                 cur_dir = SMB_STRDUP(newdir);
166         }
167         return client_get_cur_dir();
168 }
169
170 /****************************************************************************
171  Put up a yes/no prompt.
172 ****************************************************************************/
173
174 static bool yesno(const char *p)
175 {
176         char ans[20];
177         printf("%s",p);
178
179         if (!fgets(ans,sizeof(ans)-1,stdin))
180                 return(False);
181
182         if (*ans == 'y' || *ans == 'Y')
183                 return(True);
184
185         return(False);
186 }
187
188 /****************************************************************************
189  Write to a local file with CR/LF->LF translation if appropriate. Return the
190  number taken from the buffer. This may not equal the number written.
191 ****************************************************************************/
192
193 static int writefile(int f, char *b, int n)
194 {
195         int i;
196
197         if (!translation) {
198                 return write(f,b,n);
199         }
200
201         i = 0;
202         while (i < n) {
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         }
212
213         return(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, XFILE *f)
222 {
223         int i;
224         int c;
225
226         if (!translation)
227                 return x_fread(b,1,n,f);
228
229         i = 0;
230         while (i < (n - 1) && (i < BUFFER_SIZE)) {
231                 if ((c = x_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         XFILE *f;
247         SMB_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 (x_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         int total, bsize, avail;
303         struct cli_state *targetcli = NULL;
304         char *targetpath = NULL;
305         TALLOC_CTX *ctx = talloc_tos();
306         NTSTATUS status;
307
308         if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
309                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
310                 return 1;
311         }
312
313         status = cli_dskattr(targetcli, &bsize, &total, &avail);
314         if (!NT_STATUS_IS_OK(status)) {
315                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
316                 return 1;
317         }
318
319         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
320                  total, bsize, avail);
321
322         return 0;
323 }
324
325 /****************************************************************************
326  Show cd/pwd.
327 ****************************************************************************/
328
329 static int cmd_pwd(void)
330 {
331         d_printf("Current directory is %s",service);
332         d_printf("%s\n",client_get_cur_dir());
333         return 0;
334 }
335
336 /****************************************************************************
337  Ensure name has correct directory separators.
338 ****************************************************************************/
339
340 static void normalize_name(char *newdir)
341 {
342         if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
343                 string_replace(newdir,'/','\\');
344         }
345 }
346
347 /****************************************************************************
348  Change directory - inner section.
349 ****************************************************************************/
350
351 static int do_cd(const char *new_dir)
352 {
353         char *newdir = NULL;
354         char *saved_dir = NULL;
355         char *new_cd = NULL;
356         char *targetpath = NULL;
357         struct cli_state *targetcli = NULL;
358         SMB_STRUCT_STAT sbuf;
359         uint32 attributes;
360         int ret = 1;
361         TALLOC_CTX *ctx = talloc_stackframe();
362
363         newdir = talloc_strdup(ctx, new_dir);
364         if (!newdir) {
365                 TALLOC_FREE(ctx);
366                 return 1;
367         }
368
369         normalize_name(newdir);
370
371         /* Save the current directory in case the new directory is invalid */
372
373         saved_dir = talloc_strdup(ctx, client_get_cur_dir());
374         if (!saved_dir) {
375                 TALLOC_FREE(ctx);
376                 return 1;
377         }
378
379         if (*newdir == CLI_DIRSEP_CHAR) {
380                 client_set_cur_dir(newdir);
381                 new_cd = newdir;
382         } else {
383                 new_cd = talloc_asprintf(ctx, "%s%s",
384                                 client_get_cur_dir(),
385                                 newdir);
386                 if (!new_cd) {
387                         goto out;
388                 }
389         }
390
391         /* Ensure cur_dir ends in a DIRSEP */
392         if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
393                 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
394                 if (!new_cd) {
395                         goto out;
396                 }
397         }
398         client_set_cur_dir(new_cd);
399
400         new_cd = clean_name(ctx, new_cd);
401         client_set_cur_dir(new_cd);
402
403         if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
404                 d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
405                 client_set_cur_dir(saved_dir);
406                 goto out;
407         }
408
409         if (strequal(targetpath,CLI_DIRSEP_STR )) {
410                 TALLOC_FREE(ctx);
411                 return 0;
412         }
413
414         /* Use a trans2_qpathinfo to test directories for modern servers.
415            Except Win9x doesn't support the qpathinfo_basic() call..... */
416
417         if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
418                 NTSTATUS status;
419
420                 status = cli_qpathinfo_basic(targetcli, targetpath, &sbuf,
421                                              &attributes);
422                 if (!NT_STATUS_IS_OK(status)) {
423                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
424                         client_set_cur_dir(saved_dir);
425                         goto out;
426                 }
427
428                 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
429                         d_printf("cd %s: not a directory\n", new_cd);
430                         client_set_cur_dir(saved_dir);
431                         goto out;
432                 }
433         } else {
434                 NTSTATUS status;
435
436                 targetpath = talloc_asprintf(ctx,
437                                 "%s%s",
438                                 targetpath,
439                                 CLI_DIRSEP_STR );
440                 if (!targetpath) {
441                         client_set_cur_dir(saved_dir);
442                         goto out;
443                 }
444                 targetpath = clean_name(ctx, targetpath);
445                 if (!targetpath) {
446                         client_set_cur_dir(saved_dir);
447                         goto out;
448                 }
449
450                 status = cli_chkpath(targetcli, targetpath);
451                 if (!NT_STATUS_IS_OK(status)) {
452                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
453                         client_set_cur_dir(saved_dir);
454                         goto out;
455                 }
456         }
457
458         ret = 0;
459
460 out:
461
462         TALLOC_FREE(ctx);
463         return ret;
464 }
465
466 /****************************************************************************
467  Change directory.
468 ****************************************************************************/
469
470 static int cmd_cd(void)
471 {
472         char *buf = NULL;
473         int rc = 0;
474
475         if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
476                 rc = do_cd(buf);
477         } else {
478                 d_printf("Current directory is %s\n",client_get_cur_dir());
479         }
480
481         return rc;
482 }
483
484 /****************************************************************************
485  Change directory.
486 ****************************************************************************/
487
488 static int cmd_cd_oneup(void)
489 {
490         return do_cd("..");
491 }
492
493 /*******************************************************************
494  Decide if a file should be operated on.
495 ********************************************************************/
496
497 static bool do_this_one(struct file_info *finfo)
498 {
499         if (!finfo->name) {
500                 return false;
501         }
502
503         if (finfo->mode & aDIR) {
504                 return true;
505         }
506
507         if (*client_get_fileselection() &&
508             !mask_match(finfo->name,client_get_fileselection(),false)) {
509                 DEBUG(3,("mask_match %s failed\n", finfo->name));
510                 return false;
511         }
512
513         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
514                 DEBUG(3,("newer_than %s failed\n", finfo->name));
515                 return false;
516         }
517
518         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
519                 DEBUG(3,("archive %s failed\n", finfo->name));
520                 return false;
521         }
522
523         return true;
524 }
525
526 /****************************************************************************
527  Display info about a file.
528 ****************************************************************************/
529
530 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
531                           const char *dir)
532 {
533         time_t t;
534         TALLOC_CTX *ctx = talloc_tos();
535         NTSTATUS status = NT_STATUS_OK;
536
537         if (!do_this_one(finfo)) {
538                 return NT_STATUS_OK;
539         }
540
541         t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
542         if (!showacls) {
543                 d_printf("  %-30s%7.7s %8.0f  %s",
544                          finfo->name,
545                          attrib_string(finfo->mode),
546                         (double)finfo->size,
547                         time_to_asc(t));
548                 dir_total += finfo->size;
549         } else {
550                 char *afname = NULL;
551                 uint16_t fnum;
552
553                 /* skip if this is . or .. */
554                 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
555                         return NT_STATUS_OK;
556                 /* create absolute filename for cli_ntcreate() FIXME */
557                 afname = talloc_asprintf(ctx,
558                                         "%s%s%s",
559                                         dir,
560                                         CLI_DIRSEP_STR,
561                                         finfo->name);
562                 if (!afname) {
563                         return NT_STATUS_NO_MEMORY;
564                 }
565                 /* print file meta date header */
566                 d_printf( "FILENAME:%s\n", finfo->name);
567                 d_printf( "MODE:%s\n", attrib_string(finfo->mode));
568                 d_printf( "SIZE:%.0f\n", (double)finfo->size);
569                 d_printf( "MTIME:%s", time_to_asc(t));
570                 status = cli_ntcreate(cli_state, afname, 0,
571                                       CREATE_ACCESS_READ, 0,
572                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
573                                       FILE_OPEN, 0x0, 0x0, &fnum);
574                 if (!NT_STATUS_IS_OK(status)) {
575                         DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
576                                    afname, nt_errstr(status)));
577                 } else {
578                         struct security_descriptor *sd = NULL;
579                         sd = cli_query_secdesc(cli_state, fnum, ctx);
580                         if (!sd) {
581                                 DEBUG( 0, ("display_finfo() failed to "
582                                         "get security descriptor: %s",
583                                         cli_errstr(cli_state)));
584                                 status = cli_nt_error(cli_state);
585                         } else {
586                                 display_sec_desc(sd);
587                         }
588                         TALLOC_FREE(sd);
589                 }
590                 TALLOC_FREE(afname);
591         }
592         return status;
593 }
594
595 /****************************************************************************
596  Accumulate size of a file.
597 ****************************************************************************/
598
599 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
600                   const char *dir)
601 {
602         if (do_this_one(finfo)) {
603                 dir_total += finfo->size;
604         }
605         return NT_STATUS_OK;
606 }
607
608 static bool do_list_recurse;
609 static bool do_list_dirs;
610 static char *do_list_queue = 0;
611 static long do_list_queue_size = 0;
612 static long do_list_queue_start = 0;
613 static long do_list_queue_end = 0;
614 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
615                           const char *dir);
616
617 /****************************************************************************
618  Functions for do_list_queue.
619 ****************************************************************************/
620
621 /*
622  * The do_list_queue is a NUL-separated list of strings stored in a
623  * char*.  Since this is a FIFO, we keep track of the beginning and
624  * ending locations of the data in the queue.  When we overflow, we
625  * double the size of the char*.  When the start of the data passes
626  * the midpoint, we move everything back.  This is logically more
627  * complex than a linked list, but easier from a memory management
628  * angle.  In any memory error condition, do_list_queue is reset.
629  * Functions check to ensure that do_list_queue is non-NULL before
630  * accessing it.
631  */
632
633 static void reset_do_list_queue(void)
634 {
635         SAFE_FREE(do_list_queue);
636         do_list_queue_size = 0;
637         do_list_queue_start = 0;
638         do_list_queue_end = 0;
639 }
640
641 static void init_do_list_queue(void)
642 {
643         reset_do_list_queue();
644         do_list_queue_size = 1024;
645         do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
646         if (do_list_queue == 0) {
647                 d_printf("malloc fail for size %d\n",
648                          (int)do_list_queue_size);
649                 reset_do_list_queue();
650         } else {
651                 memset(do_list_queue, 0, do_list_queue_size);
652         }
653 }
654
655 static void adjust_do_list_queue(void)
656 {
657         /*
658          * If the starting point of the queue is more than half way through,
659          * move everything toward the beginning.
660          */
661
662         if (do_list_queue == NULL) {
663                 DEBUG(4,("do_list_queue is empty\n"));
664                 do_list_queue_start = do_list_queue_end = 0;
665                 return;
666         }
667
668         if (do_list_queue_start == do_list_queue_end) {
669                 DEBUG(4,("do_list_queue is empty\n"));
670                 do_list_queue_start = do_list_queue_end = 0;
671                 *do_list_queue = '\0';
672         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
673                 DEBUG(4,("sliding do_list_queue backward\n"));
674                 memmove(do_list_queue,
675                         do_list_queue + do_list_queue_start,
676                         do_list_queue_end - do_list_queue_start);
677                 do_list_queue_end -= do_list_queue_start;
678                 do_list_queue_start = 0;
679         }
680 }
681
682 static void add_to_do_list_queue(const char *entry)
683 {
684         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
685         while (new_end > do_list_queue_size) {
686                 do_list_queue_size *= 2;
687                 DEBUG(4,("enlarging do_list_queue to %d\n",
688                          (int)do_list_queue_size));
689                 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
690                 if (! do_list_queue) {
691                         d_printf("failure enlarging do_list_queue to %d bytes\n",
692                                  (int)do_list_queue_size);
693                         reset_do_list_queue();
694                 } else {
695                         memset(do_list_queue + do_list_queue_size / 2,
696                                0, do_list_queue_size / 2);
697                 }
698         }
699         if (do_list_queue) {
700                 safe_strcpy_base(do_list_queue + do_list_queue_end,
701                                  entry, do_list_queue, do_list_queue_size);
702                 do_list_queue_end = new_end;
703                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
704                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
705         }
706 }
707
708 static char *do_list_queue_head(void)
709 {
710         return do_list_queue + do_list_queue_start;
711 }
712
713 static void remove_do_list_queue_head(void)
714 {
715         if (do_list_queue_end > do_list_queue_start) {
716                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
717                 adjust_do_list_queue();
718                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
719                          (int)do_list_queue_start, (int)do_list_queue_end));
720         }
721 }
722
723 static int do_list_queue_empty(void)
724 {
725         return (! (do_list_queue && *do_list_queue));
726 }
727
728 /****************************************************************************
729  A helper for do_list.
730 ****************************************************************************/
731
732 static NTSTATUS do_list_helper(const char *mntpoint, struct file_info *f,
733                            const char *mask, void *state)
734 {
735         struct cli_state *cli_state = (struct cli_state *)state;
736         TALLOC_CTX *ctx = talloc_tos();
737         char *dir = NULL;
738         char *dir_end = NULL;
739         NTSTATUS status = NT_STATUS_OK;
740
741         /* Work out the directory. */
742         dir = talloc_strdup(ctx, mask);
743         if (!dir) {
744                 return NT_STATUS_NO_MEMORY;
745         }
746         if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
747                 *dir_end = '\0';
748         }
749
750         if (f->mode & aDIR) {
751                 if (do_list_dirs && do_this_one(f)) {
752                         status = do_list_fn(cli_state, f, dir);
753                         if (!NT_STATUS_IS_OK(status)) {
754                                 return status;
755                         }
756                 }
757                 if (do_list_recurse &&
758                     f->name &&
759                     !strequal(f->name,".") &&
760                     !strequal(f->name,"..")) {
761                         char *mask2 = NULL;
762                         char *p = NULL;
763
764                         if (!f->name[0]) {
765                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
766                                 TALLOC_FREE(dir);
767                                 return NT_STATUS_UNSUCCESSFUL;
768                         }
769
770                         mask2 = talloc_asprintf(ctx,
771                                         "%s%s",
772                                         mntpoint,
773                                         mask);
774                         if (!mask2) {
775                                 TALLOC_FREE(dir);
776                                 return NT_STATUS_NO_MEMORY;
777                         }
778                         p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
779                         if (p) {
780                                 p[1] = 0;
781                         } else {
782                                 mask2[0] = '\0';
783                         }
784                         mask2 = talloc_asprintf_append(mask2,
785                                         "%s%s*",
786                                         f->name,
787                                         CLI_DIRSEP_STR);
788                         if (!mask2) {
789                                 TALLOC_FREE(dir);
790                                 return NT_STATUS_NO_MEMORY;
791                         }
792                         add_to_do_list_queue(mask2);
793                         TALLOC_FREE(mask2);
794                 }
795                 TALLOC_FREE(dir);
796                 return NT_STATUS_OK;
797         }
798
799         if (do_this_one(f)) {
800                 status = do_list_fn(cli_state, f, dir);
801         }
802         TALLOC_FREE(dir);
803         return status;
804 }
805
806 /****************************************************************************
807  A wrapper around cli_list that adds recursion.
808 ****************************************************************************/
809
810 NTSTATUS do_list(const char *mask,
811                         uint16 attribute,
812                         NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
813                                    const char *dir),
814                         bool rec,
815                         bool dirs)
816 {
817         static int in_do_list = 0;
818         TALLOC_CTX *ctx = talloc_tos();
819         struct cli_state *targetcli = NULL;
820         char *targetpath = NULL;
821         NTSTATUS ret_status = NT_STATUS_OK;
822         NTSTATUS status = NT_STATUS_OK;
823
824         if (in_do_list && rec) {
825                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
826                 exit(1);
827         }
828
829         in_do_list = 1;
830
831         do_list_recurse = rec;
832         do_list_dirs = dirs;
833         do_list_fn = fn;
834
835         if (rec) {
836                 init_do_list_queue();
837                 add_to_do_list_queue(mask);
838
839                 while (!do_list_queue_empty()) {
840                         /*
841                          * Need to copy head so that it doesn't become
842                          * invalid inside the call to cli_list.  This
843                          * would happen if the list were expanded
844                          * during the call.
845                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
846                          */
847                         char *head = talloc_strdup(ctx, do_list_queue_head());
848
849                         if (!head) {
850                                 return NT_STATUS_NO_MEMORY;
851                         }
852
853                         /* check for dfs */
854
855                         if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
856                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
857                                 remove_do_list_queue_head();
858                                 continue;
859                         }
860
861                         status = cli_list(targetcli, targetpath, attribute,
862                                  do_list_helper, targetcli);
863                         if (!NT_STATUS_IS_OK(status)) {
864                                 d_printf("%s listing %s\n",
865                                          nt_errstr(status), targetpath);
866                                 ret_status = status;
867                         }
868                         remove_do_list_queue_head();
869                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
870                                 char *next_file = do_list_queue_head();
871                                 char *save_ch = 0;
872                                 if ((strlen(next_file) >= 2) &&
873                                     (next_file[strlen(next_file) - 1] == '*') &&
874                                     (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
875                                         save_ch = next_file +
876                                                 strlen(next_file) - 2;
877                                         *save_ch = '\0';
878                                         if (showacls) {
879                                                 /* cwd is only used if showacls is on */
880                                                 client_set_cwd(next_file);
881                                         }
882                                 }
883                                 if (!showacls) /* don't disturbe the showacls output */
884                                         d_printf("\n%s\n",next_file);
885                                 if (save_ch) {
886                                         *save_ch = CLI_DIRSEP_CHAR;
887                                 }
888                         }
889                         TALLOC_FREE(head);
890                         TALLOC_FREE(targetpath);
891                 }
892         } else {
893                 /* check for dfs */
894                 if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
895
896                         status = cli_list(targetcli, targetpath, attribute,
897                                           do_list_helper, targetcli);
898                         if (!NT_STATUS_IS_OK(status)) {
899                                 d_printf("%s listing %s\n",
900                                          nt_errstr(status), targetpath);
901                                 ret_status = status;
902                         }
903                         TALLOC_FREE(targetpath);
904                 } else {
905                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
906                         ret_status = cli_nt_error(cli);
907                 }
908         }
909
910         in_do_list = 0;
911         reset_do_list_queue();
912         return ret_status;
913 }
914
915 /****************************************************************************
916  Get a directory listing.
917 ****************************************************************************/
918
919 static int cmd_dir(void)
920 {
921         TALLOC_CTX *ctx = talloc_tos();
922         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
923         char *mask = NULL;
924         char *buf = NULL;
925         int rc = 1;
926         NTSTATUS status;
927
928         dir_total = 0;
929         mask = talloc_strdup(ctx, client_get_cur_dir());
930         if (!mask) {
931                 return 1;
932         }
933
934         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
935                 normalize_name(buf);
936                 if (*buf == CLI_DIRSEP_CHAR) {
937                         mask = talloc_strdup(ctx, buf);
938                 } else {
939                         mask = talloc_asprintf_append(mask, "%s", buf);
940                 }
941         } else {
942                 mask = talloc_asprintf_append(mask, "*");
943         }
944         if (!mask) {
945                 return 1;
946         }
947
948         if (showacls) {
949                 /* cwd is only used if showacls is on */
950                 client_set_cwd(client_get_cur_dir());
951         }
952
953         status = do_list(mask, attribute, display_finfo, recurse, true);
954         if (!NT_STATUS_IS_OK(status)) {
955                 return 1;
956         }
957
958         rc = do_dskattr();
959
960         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
961
962         return rc;
963 }
964
965 /****************************************************************************
966  Get a directory listing.
967 ****************************************************************************/
968
969 static int cmd_du(void)
970 {
971         TALLOC_CTX *ctx = talloc_tos();
972         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
973         char *mask = NULL;
974         char *buf = NULL;
975         NTSTATUS status;
976         int rc = 1;
977
978         dir_total = 0;
979         mask = talloc_strdup(ctx, client_get_cur_dir());
980         if (!mask) {
981                 return 1;
982         }
983         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
984                 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
985                 if (!mask) {
986                         return 1;
987                 }
988         }
989
990         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
991                 normalize_name(buf);
992                 if (*buf == CLI_DIRSEP_CHAR) {
993                         mask = talloc_strdup(ctx, buf);
994                 } else {
995                         mask = talloc_asprintf_append(mask, "%s", buf);
996                 }
997         } else {
998                 mask = talloc_strdup(ctx, "*");
999         }
1000
1001         status = do_list(mask, attribute, do_du, recurse, true);
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 return 1;
1004         }
1005
1006         rc = do_dskattr();
1007
1008         d_printf("Total number of bytes: %.0f\n", dir_total);
1009
1010         return rc;
1011 }
1012
1013 static int cmd_echo(void)
1014 {
1015         TALLOC_CTX *ctx = talloc_tos();
1016         char *num;
1017         char *data;
1018         NTSTATUS status;
1019
1020         if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1021             || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1022                 d_printf("echo <num> <data>\n");
1023                 return 1;
1024         }
1025
1026         status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1027
1028         if (!NT_STATUS_IS_OK(status)) {
1029                 d_printf("echo failed: %s\n", nt_errstr(status));
1030                 return 1;
1031         }
1032
1033         return 0;
1034 }
1035
1036 /****************************************************************************
1037  Get a file from rname to lname
1038 ****************************************************************************/
1039
1040 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1041 {
1042         int *pfd = (int *)priv;
1043         if (writefile(*pfd, buf, n) == -1) {
1044                 return map_nt_error_from_unix(errno);
1045         }
1046         return NT_STATUS_OK;
1047 }
1048
1049 static int do_get(const char *rname, const char *lname_in, bool reget)
1050 {
1051         TALLOC_CTX *ctx = talloc_tos();
1052         int handle = 0;
1053         uint16_t fnum;
1054         bool newhandle = false;
1055         struct timespec tp_start;
1056         uint16 attr;
1057         SMB_OFF_T size;
1058         off_t start = 0;
1059         SMB_OFF_T nread = 0;
1060         int rc = 0;
1061         struct cli_state *targetcli = NULL;
1062         char *targetname = NULL;
1063         char *lname = NULL;
1064         NTSTATUS status;
1065
1066         lname = talloc_strdup(ctx, lname_in);
1067         if (!lname) {
1068                 return 1;
1069         }
1070
1071         if (lowercase) {
1072                 strlower_m(lname);
1073         }
1074
1075         if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
1076                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1077                 return 1;
1078         }
1079
1080         clock_gettime_mono(&tp_start);
1081
1082         status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1083         if (!NT_STATUS_IS_OK(status)) {
1084                 d_printf("%s opening remote file %s\n", nt_errstr(status),
1085                          rname);
1086                 return 1;
1087         }
1088
1089         if(!strcmp(lname,"-")) {
1090                 handle = fileno(stdout);
1091         } else {
1092                 if (reget) {
1093                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
1094                         if (handle >= 0) {
1095                                 start = sys_lseek(handle, 0, SEEK_END);
1096                                 if (start == -1) {
1097                                         d_printf("Error seeking local file\n");
1098                                         return 1;
1099                                 }
1100                         }
1101                 } else {
1102                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1103                 }
1104                 newhandle = true;
1105         }
1106         if (handle < 0) {
1107                 d_printf("Error opening local file %s\n",lname);
1108                 return 1;
1109         }
1110
1111
1112         status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1113                                      NULL, NULL, NULL);
1114         if (!NT_STATUS_IS_OK(status)) {
1115                 status = cli_getattrE(targetcli, fnum, &attr, &size, NULL, NULL,
1116                                       NULL);
1117                 if(!NT_STATUS_IS_OK(status)) {
1118                         d_printf("getattrib: %s\n", nt_errstr(status));
1119                         return 1;
1120                 }
1121         }
1122
1123         DEBUG(1,("getting file %s of size %.0f as %s ",
1124                  rname, (double)size, lname));
1125
1126         status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1127                           writefile_sink, (void *)&handle, &nread);
1128         if (!NT_STATUS_IS_OK(status)) {
1129                 d_fprintf(stderr, "parallel_read returned %s\n",
1130                           nt_errstr(status));
1131                 cli_close(targetcli, fnum);
1132                 return 1;
1133         }
1134
1135         status = cli_close(targetcli, fnum);
1136         if (!NT_STATUS_IS_OK(status)) {
1137                 d_printf("Error %s closing remote file\n", nt_errstr(status));
1138                 rc = 1;
1139         }
1140
1141         if (newhandle) {
1142                 close(handle);
1143         }
1144
1145         if (archive_level >= 2 && (attr & aARCH)) {
1146                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
1147         }
1148
1149         {
1150                 struct timespec tp_end;
1151                 int this_time;
1152
1153                 clock_gettime_mono(&tp_end);
1154                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1155                 get_total_time_ms += this_time;
1156                 get_total_size += nread;
1157
1158                 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1159                          nread / (1.024*this_time + 1.0e-4),
1160                          get_total_size / (1.024*get_total_time_ms)));
1161         }
1162
1163         TALLOC_FREE(targetname);
1164         return rc;
1165 }
1166
1167 /****************************************************************************
1168  Get a file.
1169 ****************************************************************************/
1170
1171 static int cmd_get(void)
1172 {
1173         TALLOC_CTX *ctx = talloc_tos();
1174         char *lname = NULL;
1175         char *rname = NULL;
1176         char *fname = NULL;
1177
1178         rname = talloc_strdup(ctx, client_get_cur_dir());
1179         if (!rname) {
1180                 return 1;
1181         }
1182
1183         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1184                 d_printf("get <filename> [localname]\n");
1185                 return 1;
1186         }
1187         rname = talloc_asprintf_append(rname, "%s", fname);
1188         if (!rname) {
1189                 return 1;
1190         }
1191         rname = clean_name(ctx, rname);
1192         if (!rname) {
1193                 return 1;
1194         }
1195
1196         next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1197         if (!lname) {
1198                 lname = fname;
1199         }
1200
1201         return do_get(rname, lname, false);
1202 }
1203
1204 /****************************************************************************
1205  Do an mget operation on one file.
1206 ****************************************************************************/
1207
1208 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1209                     const char *dir)
1210 {
1211         TALLOC_CTX *ctx = talloc_tos();
1212         NTSTATUS status = NT_STATUS_OK;
1213         char *rname = NULL;
1214         char *quest = NULL;
1215         char *saved_curdir = NULL;
1216         char *mget_mask = NULL;
1217         char *new_cd = NULL;
1218
1219         if (!finfo->name) {
1220                 return NT_STATUS_OK;
1221         }
1222
1223         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1224                 return NT_STATUS_OK;
1225
1226         if (abort_mget) {
1227                 d_printf("mget aborted\n");
1228                 return NT_STATUS_UNSUCCESSFUL;
1229         }
1230
1231         if (finfo->mode & aDIR) {
1232                 if (asprintf(&quest,
1233                          "Get directory %s? ",finfo->name) < 0) {
1234                         return NT_STATUS_NO_MEMORY;
1235                 }
1236         } else {
1237                 if (asprintf(&quest,
1238                          "Get file %s? ",finfo->name) < 0) {
1239                         return NT_STATUS_NO_MEMORY;
1240                 }
1241         }
1242
1243         if (prompt && !yesno(quest)) {
1244                 SAFE_FREE(quest);
1245                 return NT_STATUS_OK;
1246         }
1247         SAFE_FREE(quest);
1248
1249         if (!(finfo->mode & aDIR)) {
1250                 rname = talloc_asprintf(ctx,
1251                                 "%s%s",
1252                                 client_get_cur_dir(),
1253                                 finfo->name);
1254                 if (!rname) {
1255                         return NT_STATUS_NO_MEMORY;
1256                 }
1257                 do_get(rname, finfo->name, false);
1258                 TALLOC_FREE(rname);
1259                 return NT_STATUS_OK;
1260         }
1261
1262         /* handle directories */
1263         saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1264         if (!saved_curdir) {
1265                 return NT_STATUS_NO_MEMORY;
1266         }
1267
1268         new_cd = talloc_asprintf(ctx,
1269                                 "%s%s%s",
1270                                 client_get_cur_dir(),
1271                                 finfo->name,
1272                                 CLI_DIRSEP_STR);
1273         if (!new_cd) {
1274                 return NT_STATUS_NO_MEMORY;
1275         }
1276         client_set_cur_dir(new_cd);
1277
1278         string_replace(finfo->name,'\\','/');
1279         if (lowercase) {
1280                 strlower_m(finfo->name);
1281         }
1282
1283         if (!directory_exist(finfo->name) &&
1284             mkdir(finfo->name,0777) != 0) {
1285                 d_printf("failed to create directory %s\n",finfo->name);
1286                 client_set_cur_dir(saved_curdir);
1287                 return map_nt_error_from_unix(errno);
1288         }
1289
1290         if (chdir(finfo->name) != 0) {
1291                 d_printf("failed to chdir to directory %s\n",finfo->name);
1292                 client_set_cur_dir(saved_curdir);
1293                 return map_nt_error_from_unix(errno);
1294         }
1295
1296         mget_mask = talloc_asprintf(ctx,
1297                         "%s*",
1298                         client_get_cur_dir());
1299
1300         if (!mget_mask) {
1301                 return NT_STATUS_NO_MEMORY;
1302         }
1303
1304         status = do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
1305         if (!NT_STATUS_IS_OK(status)) {
1306                 return status;
1307         }
1308
1309         if (chdir("..") == -1) {
1310                 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1311                         strerror(errno) );
1312                 return map_nt_error_from_unix(errno);
1313         }
1314         client_set_cur_dir(saved_curdir);
1315         TALLOC_FREE(mget_mask);
1316         TALLOC_FREE(saved_curdir);
1317         TALLOC_FREE(new_cd);
1318         return NT_STATUS_OK;
1319 }
1320
1321 /****************************************************************************
1322  View the file using the pager.
1323 ****************************************************************************/
1324
1325 static int cmd_more(void)
1326 {
1327         TALLOC_CTX *ctx = talloc_tos();
1328         char *rname = NULL;
1329         char *fname = NULL;
1330         char *lname = NULL;
1331         char *pager_cmd = NULL;
1332         const char *pager;
1333         int fd;
1334         int rc = 0;
1335
1336         rname = talloc_strdup(ctx, client_get_cur_dir());
1337         if (!rname) {
1338                 return 1;
1339         }
1340
1341         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1342         if (!lname) {
1343                 return 1;
1344         }
1345         fd = mkstemp(lname);
1346         if (fd == -1) {
1347                 d_printf("failed to create temporary file for more\n");
1348                 return 1;
1349         }
1350         close(fd);
1351
1352         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1353                 d_printf("more <filename>\n");
1354                 unlink(lname);
1355                 return 1;
1356         }
1357         rname = talloc_asprintf_append(rname, "%s", fname);
1358         if (!rname) {
1359                 return 1;
1360         }
1361         rname = clean_name(ctx,rname);
1362         if (!rname) {
1363                 return 1;
1364         }
1365
1366         rc = do_get(rname, lname, false);
1367
1368         pager=getenv("PAGER");
1369
1370         pager_cmd = talloc_asprintf(ctx,
1371                                 "%s %s",
1372                                 (pager? pager:PAGER),
1373                                 lname);
1374         if (!pager_cmd) {
1375                 return 1;
1376         }
1377         if (system(pager_cmd) == -1) {
1378                 d_printf("system command '%s' returned -1\n",
1379                         pager_cmd);
1380         }
1381         unlink(lname);
1382
1383         return rc;
1384 }
1385
1386 /****************************************************************************
1387  Do a mget command.
1388 ****************************************************************************/
1389
1390 static int cmd_mget(void)
1391 {
1392         TALLOC_CTX *ctx = talloc_tos();
1393         uint16 attribute = aSYSTEM | aHIDDEN;
1394         char *mget_mask = NULL;
1395         char *buf = NULL;
1396         NTSTATUS status = NT_STATUS_OK;
1397
1398         if (recurse) {
1399                 attribute |= aDIR;
1400         }
1401
1402         abort_mget = false;
1403
1404         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1405
1406                 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1407                 if (!mget_mask) {
1408                         return 1;
1409                 }
1410                 if (*buf == CLI_DIRSEP_CHAR) {
1411                         mget_mask = talloc_strdup(ctx, buf);
1412                 } else {
1413                         mget_mask = talloc_asprintf_append(mget_mask,
1414                                                         "%s", buf);
1415                 }
1416                 if (!mget_mask) {
1417                         return 1;
1418                 }
1419                 status = do_list(mget_mask, attribute, do_mget, false, true);
1420                 if (!NT_STATUS_IS_OK(status)) {
1421                         return 1;
1422                 }
1423         }
1424
1425         if (mget_mask == NULL) {
1426                 d_printf("nothing to mget\n");
1427                 return 0;
1428         }
1429
1430         if (!*mget_mask) {
1431                 mget_mask = talloc_asprintf(ctx,
1432                                         "%s*",
1433                                         client_get_cur_dir());
1434                 if (!mget_mask) {
1435                         return 1;
1436                 }
1437                 status = do_list(mget_mask, attribute, do_mget, false, true);
1438                 if (!NT_STATUS_IS_OK(status)) {
1439                         return 1;
1440                 }
1441         }
1442
1443         return 0;
1444 }
1445
1446 /****************************************************************************
1447  Make a directory of name "name".
1448 ****************************************************************************/
1449
1450 static bool do_mkdir(const char *name)
1451 {
1452         TALLOC_CTX *ctx = talloc_tos();
1453         struct cli_state *targetcli;
1454         char *targetname = NULL;
1455         NTSTATUS status;
1456
1457         if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
1458                 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1459                 return false;
1460         }
1461
1462         status = cli_mkdir(targetcli, targetname);
1463         if (!NT_STATUS_IS_OK(status)) {
1464                 d_printf("%s making remote directory %s\n",
1465                          nt_errstr(status),name);
1466                 return false;
1467         }
1468
1469         return true;
1470 }
1471
1472 /****************************************************************************
1473  Show 8.3 name of a file.
1474 ****************************************************************************/
1475
1476 static bool do_altname(const char *name)
1477 {
1478         fstring altname;
1479         NTSTATUS status;
1480
1481         status = cli_qpathinfo_alt_name(cli, name, altname);
1482         if (!NT_STATUS_IS_OK(status)) {
1483                 d_printf("%s getting alt name for %s\n",
1484                          nt_errstr(status),name);
1485                 return false;
1486         }
1487         d_printf("%s\n", altname);
1488
1489         return true;
1490 }
1491
1492 /****************************************************************************
1493  Exit client.
1494 ****************************************************************************/
1495
1496 static int cmd_quit(void)
1497 {
1498         cli_shutdown(cli);
1499         exit(0);
1500         /* NOTREACHED */
1501         return 0;
1502 }
1503
1504 /****************************************************************************
1505  Make a directory.
1506 ****************************************************************************/
1507
1508 static int cmd_mkdir(void)
1509 {
1510         TALLOC_CTX *ctx = talloc_tos();
1511         char *mask = NULL;
1512         char *buf = NULL;
1513
1514         mask = talloc_strdup(ctx, client_get_cur_dir());
1515         if (!mask) {
1516                 return 1;
1517         }
1518
1519         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1520                 if (!recurse) {
1521                         d_printf("mkdir <dirname>\n");
1522                 }
1523                 return 1;
1524         }
1525         mask = talloc_asprintf_append(mask, "%s", buf);
1526         if (!mask) {
1527                 return 1;
1528         }
1529
1530         if (recurse) {
1531                 char *ddir = NULL;
1532                 char *ddir2 = NULL;
1533                 struct cli_state *targetcli;
1534                 char *targetname = NULL;
1535                 char *p = NULL;
1536                 char *saveptr;
1537
1538                 ddir2 = talloc_strdup(ctx, "");
1539                 if (!ddir2) {
1540                         return 1;
1541                 }
1542
1543                 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
1544                         return 1;
1545                 }
1546
1547                 ddir = talloc_strdup(ctx, targetname);
1548                 if (!ddir) {
1549                         return 1;
1550                 }
1551                 trim_char(ddir,'.','\0');
1552                 p = strtok_r(ddir, "/\\", &saveptr);
1553                 while (p) {
1554                         ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1555                         if (!ddir2) {
1556                                 return 1;
1557                         }
1558                         if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1559                                 do_mkdir(ddir2);
1560                         }
1561                         ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1562                         if (!ddir2) {
1563                                 return 1;
1564                         }
1565                         p = strtok_r(NULL, "/\\", &saveptr);
1566                 }
1567         } else {
1568                 do_mkdir(mask);
1569         }
1570
1571         return 0;
1572 }
1573
1574 /****************************************************************************
1575  Show alt name.
1576 ****************************************************************************/
1577
1578 static int cmd_altname(void)
1579 {
1580         TALLOC_CTX *ctx = talloc_tos();
1581         char *name;
1582         char *buf;
1583
1584         name = talloc_strdup(ctx, client_get_cur_dir());
1585         if (!name) {
1586                 return 1;
1587         }
1588
1589         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1590                 d_printf("altname <file>\n");
1591                 return 1;
1592         }
1593         name = talloc_asprintf_append(name, "%s", buf);
1594         if (!name) {
1595                 return 1;
1596         }
1597         do_altname(name);
1598         return 0;
1599 }
1600
1601 static char *attr_str(TALLOC_CTX *mem_ctx, uint16_t mode)
1602 {
1603         char *attrs = TALLOC_ZERO_ARRAY(mem_ctx, char, 17);
1604         int i = 0;
1605
1606         if (!(mode & FILE_ATTRIBUTE_NORMAL)) {
1607                 if (mode & FILE_ATTRIBUTE_READONLY) {
1608                         attrs[i++] = 'R';
1609                 }
1610                 if (mode & FILE_ATTRIBUTE_HIDDEN) {
1611                         attrs[i++] = 'H';
1612                 }
1613                 if (mode & FILE_ATTRIBUTE_SYSTEM) {
1614                         attrs[i++] = 'S';
1615                 }
1616                 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1617                         attrs[i++] = 'D';
1618                 }
1619                 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
1620                         attrs[i++] = 'A';
1621                 }
1622         }
1623         return attrs;
1624 }
1625
1626 /****************************************************************************
1627  Show all info we can get
1628 ****************************************************************************/
1629
1630 static int do_allinfo(const char *name)
1631 {
1632         fstring altname;
1633         struct timespec b_time, a_time, m_time, c_time;
1634         SMB_OFF_T size;
1635         uint16_t mode;
1636         SMB_INO_T ino;
1637         NTTIME tmp;
1638         uint16_t fnum;
1639         unsigned int num_streams;
1640         struct stream_struct *streams;
1641         int num_snapshots;
1642         char **snapshots;
1643         unsigned int i;
1644         NTSTATUS status;
1645
1646         status = cli_qpathinfo_alt_name(cli, name, altname);
1647         if (!NT_STATUS_IS_OK(status)) {
1648                 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1649                          name);
1650                 return false;
1651         }
1652         d_printf("altname: %s\n", altname);
1653
1654         status = cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
1655                                 &size, &mode, &ino);
1656         if (!NT_STATUS_IS_OK(status)) {
1657                 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1658                          name);
1659                 return false;
1660         }
1661
1662         unix_timespec_to_nt_time(&tmp, b_time);
1663         d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1664
1665         unix_timespec_to_nt_time(&tmp, a_time);
1666         d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1667
1668         unix_timespec_to_nt_time(&tmp, m_time);
1669         d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1670
1671         unix_timespec_to_nt_time(&tmp, c_time);
1672         d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1673
1674         d_printf("attributes: %s\n", attr_str(talloc_tos(), mode));
1675
1676         status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1677                                        &streams);
1678         if (!NT_STATUS_IS_OK(status)) {
1679                 d_printf("%s getting streams for %s\n", nt_errstr(status),
1680                          name);
1681                 return false;
1682         }
1683
1684         for (i=0; i<num_streams; i++) {
1685                 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1686                          (unsigned long long)streams[i].size);
1687         }
1688
1689         status = cli_open(cli, name, O_RDONLY, DENY_NONE, &fnum);
1690         if (!NT_STATUS_IS_OK(status)) {
1691                 /*
1692                  * Ignore failure, it does not hurt if we can't list
1693                  * snapshots
1694                  */
1695                 return 0;
1696         }
1697         status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1698                                       true, &snapshots, &num_snapshots);
1699         if (!NT_STATUS_IS_OK(status)) {
1700                 cli_close(cli, fnum);
1701                 return 0;
1702         }
1703
1704         for (i=0; i<num_snapshots; i++) {
1705                 char *snap_name;
1706
1707                 d_printf("%s\n", snapshots[i]);
1708                 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1709                                             snapshots[i], name);
1710                 status = cli_qpathinfo2(cli, snap_name, &b_time, &a_time,
1711                                         &m_time, &c_time, &size,
1712                                         NULL, NULL);
1713                 if (!NT_STATUS_IS_OK(status)) {
1714                         d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1715                                   snap_name, nt_errstr(status));
1716                         TALLOC_FREE(snap_name);
1717                         continue;
1718                 }
1719                 unix_timespec_to_nt_time(&tmp, b_time);
1720                 d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1721                 unix_timespec_to_nt_time(&tmp, a_time);
1722                 d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1723                 unix_timespec_to_nt_time(&tmp, m_time);
1724                 d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1725                 unix_timespec_to_nt_time(&tmp, c_time);
1726                 d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1727                 d_printf("size: %d\n", (int)size);
1728         }
1729
1730         TALLOC_FREE(snapshots);
1731
1732         return 0;
1733 }
1734
1735 /****************************************************************************
1736  Show all info we can get
1737 ****************************************************************************/
1738
1739 static int cmd_allinfo(void)
1740 {
1741         TALLOC_CTX *ctx = talloc_tos();
1742         char *name;
1743         char *buf;
1744
1745         name = talloc_strdup(ctx, client_get_cur_dir());
1746         if (!name) {
1747                 return 1;
1748         }
1749
1750         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1751                 d_printf("allinfo <file>\n");
1752                 return 1;
1753         }
1754         name = talloc_asprintf_append(name, "%s", buf);
1755         if (!name) {
1756                 return 1;
1757         }
1758
1759         do_allinfo(name);
1760
1761         return 0;
1762 }
1763
1764 /****************************************************************************
1765  Put a single file.
1766 ****************************************************************************/
1767
1768 static int do_put(const char *rname, const char *lname, bool reput)
1769 {
1770         TALLOC_CTX *ctx = talloc_tos();
1771         uint16_t fnum;
1772         XFILE *f;
1773         SMB_OFF_T start = 0;
1774         int rc = 0;
1775         struct timespec tp_start;
1776         struct cli_state *targetcli;
1777         char *targetname = NULL;
1778         struct push_state state;
1779         NTSTATUS status;
1780
1781         if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
1782                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1783                 return 1;
1784         }
1785
1786         clock_gettime_mono(&tp_start);
1787
1788         if (reput) {
1789                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1790                 if (NT_STATUS_IS_OK(status)) {
1791                         if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
1792                                                      targetcli, fnum, NULL,
1793                                                      &start, NULL, NULL,
1794                                                      NULL, NULL, NULL)) &&
1795                             !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL))) {
1796                                 d_printf("getattrib: %s\n",cli_errstr(cli));
1797                                 return 1;
1798                         }
1799                 }
1800         } else {
1801                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1802         }
1803
1804         if (!NT_STATUS_IS_OK(status)) {
1805                 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1806                 return 1;
1807         }
1808
1809         /* allow files to be piped into smbclient
1810            jdblair 24.jun.98
1811
1812            Note that in this case this function will exit(0) rather
1813            than returning. */
1814         if (!strcmp(lname, "-")) {
1815                 f = x_stdin;
1816                 /* size of file is not known */
1817         } else {
1818                 f = x_fopen(lname,O_RDONLY, 0);
1819                 if (f && reput) {
1820                         if (x_tseek(f, start, SEEK_SET) == -1) {
1821                                 d_printf("Error seeking local file\n");
1822                                 x_fclose(f);
1823                                 return 1;
1824                         }
1825                 }
1826         }
1827
1828         if (!f) {
1829                 d_printf("Error opening local file %s\n",lname);
1830                 return 1;
1831         }
1832
1833         DEBUG(1,("putting file %s as %s ",lname,
1834                  rname));
1835
1836         x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
1837
1838         state.f = f;
1839         state.nread = 0;
1840
1841         status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
1842                           &state);
1843         if (!NT_STATUS_IS_OK(status)) {
1844                 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1845                 rc = 1;
1846         }
1847
1848         status = cli_close(targetcli, fnum);
1849         if (!NT_STATUS_IS_OK(status)) {
1850                 d_printf("%s closing remote file %s\n", nt_errstr(status),
1851                          rname);
1852                 if (f != x_stdin) {
1853                         x_fclose(f);
1854                 }
1855                 return 1;
1856         }
1857
1858         if (f != x_stdin) {
1859                 x_fclose(f);
1860         }
1861
1862         {
1863                 struct timespec tp_end;
1864                 int this_time;
1865
1866                 clock_gettime_mono(&tp_end);
1867                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1868                 put_total_time_ms += this_time;
1869                 put_total_size += state.nread;
1870
1871                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1872                          state.nread / (1.024*this_time + 1.0e-4),
1873                          put_total_size / (1.024*put_total_time_ms)));
1874         }
1875
1876         if (f == x_stdin) {
1877                 cli_shutdown(cli);
1878                 exit(0);
1879         }
1880
1881         return rc;
1882 }
1883
1884 /****************************************************************************
1885  Put a file.
1886 ****************************************************************************/
1887
1888 static int cmd_put(void)
1889 {
1890         TALLOC_CTX *ctx = talloc_tos();
1891         char *lname;
1892         char *rname;
1893         char *buf;
1894
1895         rname = talloc_strdup(ctx, client_get_cur_dir());
1896         if (!rname) {
1897                 return 1;
1898         }
1899
1900         if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1901                 d_printf("put <filename>\n");
1902                 return 1;
1903         }
1904
1905         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1906                 rname = talloc_asprintf_append(rname, "%s", buf);
1907         } else {
1908                 rname = talloc_asprintf_append(rname, "%s", lname);
1909         }
1910         if (!rname) {
1911                 return 1;
1912         }
1913
1914         rname = clean_name(ctx, rname);
1915         if (!rname) {
1916                 return 1;
1917         }
1918
1919         {
1920                 SMB_STRUCT_STAT st;
1921                 /* allow '-' to represent stdin
1922                    jdblair, 24.jun.98 */
1923                 if (!file_exist_stat(lname, &st, false) &&
1924                     (strcmp(lname,"-"))) {
1925                         d_printf("%s does not exist\n",lname);
1926                         return 1;
1927                 }
1928         }
1929
1930         return do_put(rname, lname, false);
1931 }
1932
1933 /*************************************
1934  File list structure.
1935 *************************************/
1936
1937 static struct file_list {
1938         struct file_list *prev, *next;
1939         char *file_path;
1940         bool isdir;
1941 } *file_list;
1942
1943 /****************************************************************************
1944  Free a file_list structure.
1945 ****************************************************************************/
1946
1947 static void free_file_list (struct file_list *l_head)
1948 {
1949         struct file_list *list, *next;
1950
1951         for (list = l_head; list; list = next) {
1952                 next = list->next;
1953                 DLIST_REMOVE(l_head, list);
1954                 SAFE_FREE(list->file_path);
1955                 SAFE_FREE(list);
1956         }
1957 }
1958
1959 /****************************************************************************
1960  Seek in a directory/file list until you get something that doesn't start with
1961  the specified name.
1962 ****************************************************************************/
1963
1964 static bool seek_list(struct file_list *list, char *name)
1965 {
1966         while (list) {
1967                 trim_string(list->file_path,"./","\n");
1968                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1969                         return true;
1970                 }
1971                 list = list->next;
1972         }
1973
1974         return false;
1975 }
1976
1977 /****************************************************************************
1978  Set the file selection mask.
1979 ****************************************************************************/
1980
1981 static int cmd_select(void)
1982 {
1983         TALLOC_CTX *ctx = talloc_tos();
1984         char *new_fs = NULL;
1985         next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
1986                 ;
1987         if (new_fs) {
1988                 client_set_fileselection(new_fs);
1989         } else {
1990                 client_set_fileselection("");
1991         }
1992         return 0;
1993 }
1994
1995 /****************************************************************************
1996   Recursive file matching function act as find
1997   match must be always set to true when calling this function
1998 ****************************************************************************/
1999
2000 static int file_find(struct file_list **list, const char *directory,
2001                       const char *expression, bool match)
2002 {
2003         SMB_STRUCT_DIR *dir;
2004         struct file_list *entry;
2005         struct stat statbuf;
2006         int ret;
2007         char *path;
2008         bool isdir;
2009         const char *dname;
2010
2011         dir = sys_opendir(directory);
2012         if (!dir)
2013                 return -1;
2014
2015         while ((dname = readdirname(dir))) {
2016                 if (!strcmp("..", dname))
2017                         continue;
2018                 if (!strcmp(".", dname))
2019                         continue;
2020
2021                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
2022                         continue;
2023                 }
2024
2025                 isdir = false;
2026                 if (!match || !gen_fnmatch(expression, dname)) {
2027                         if (recurse) {
2028                                 ret = stat(path, &statbuf);
2029                                 if (ret == 0) {
2030                                         if (S_ISDIR(statbuf.st_mode)) {
2031                                                 isdir = true;
2032                                                 ret = file_find(list, path, expression, false);
2033                                         }
2034                                 } else {
2035                                         d_printf("file_find: cannot stat file %s\n", path);
2036                                 }
2037
2038                                 if (ret == -1) {
2039                                         SAFE_FREE(path);
2040                                         sys_closedir(dir);
2041                                         return -1;
2042                                 }
2043                         }
2044                         entry = SMB_MALLOC_P(struct file_list);
2045                         if (!entry) {
2046                                 d_printf("Out of memory in file_find\n");
2047                                 sys_closedir(dir);
2048                                 return -1;
2049                         }
2050                         entry->file_path = path;
2051                         entry->isdir = isdir;
2052                         DLIST_ADD(*list, entry);
2053                 } else {
2054                         SAFE_FREE(path);
2055                 }
2056         }
2057
2058         sys_closedir(dir);
2059         return 0;
2060 }
2061
2062 /****************************************************************************
2063  mput some files.
2064 ****************************************************************************/
2065
2066 static int cmd_mput(void)
2067 {
2068         TALLOC_CTX *ctx = talloc_tos();
2069         char *p = NULL;
2070
2071         while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2072                 int ret;
2073                 struct file_list *temp_list;
2074                 char *quest, *lname, *rname;
2075
2076                 file_list = NULL;
2077
2078                 ret = file_find(&file_list, ".", p, true);
2079                 if (ret) {
2080                         free_file_list(file_list);
2081                         continue;
2082                 }
2083
2084                 quest = NULL;
2085                 lname = NULL;
2086                 rname = NULL;
2087
2088                 for (temp_list = file_list; temp_list;
2089                      temp_list = temp_list->next) {
2090
2091                         SAFE_FREE(lname);
2092                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2093                                 continue;
2094                         }
2095                         trim_string(lname, "./", "/");
2096
2097                         /* check if it's a directory */
2098                         if (temp_list->isdir) {
2099                                 /* if (!recurse) continue; */
2100
2101                                 SAFE_FREE(quest);
2102                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2103                                         break;
2104                                 }
2105                                 if (prompt && !yesno(quest)) { /* No */
2106                                         /* Skip the directory */
2107                                         lname[strlen(lname)-1] = '/';
2108                                         if (!seek_list(temp_list, lname))
2109                                                 break;
2110                                 } else { /* Yes */
2111                                         SAFE_FREE(rname);
2112                                         if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2113                                                 break;
2114                                         }
2115                                         normalize_name(rname);
2116                                         if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2117                                             !do_mkdir(rname)) {
2118                                                 DEBUG (0, ("Unable to make dir, skipping..."));
2119                                                 /* Skip the directory */
2120                                                 lname[strlen(lname)-1] = '/';
2121                                                 if (!seek_list(temp_list, lname)) {
2122                                                         break;
2123                                                 }
2124                                         }
2125                                 }
2126                                 continue;
2127                         } else {
2128                                 SAFE_FREE(quest);
2129                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2130                                         break;
2131                                 }
2132                                 if (prompt && !yesno(quest)) {
2133                                         /* No */
2134                                         continue;
2135                                 }
2136
2137                                 /* Yes */
2138                                 SAFE_FREE(rname);
2139                                 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2140                                         break;
2141                                 }
2142                         }
2143
2144                         normalize_name(rname);
2145
2146                         do_put(rname, lname, false);
2147                 }
2148                 free_file_list(file_list);
2149                 SAFE_FREE(quest);
2150                 SAFE_FREE(lname);
2151                 SAFE_FREE(rname);
2152         }
2153
2154         return 0;
2155 }
2156
2157 /****************************************************************************
2158  Cancel a print job.
2159 ****************************************************************************/
2160
2161 static int do_cancel(int job)
2162 {
2163         if (cli_printjob_del(cli, job)) {
2164                 d_printf("Job %d cancelled\n",job);
2165                 return 0;
2166         } else {
2167                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
2168                 return 1;
2169         }
2170 }
2171
2172 /****************************************************************************
2173  Cancel a print job.
2174 ****************************************************************************/
2175
2176 static int cmd_cancel(void)
2177 {
2178         TALLOC_CTX *ctx = talloc_tos();
2179         char *buf = NULL;
2180         int job;
2181
2182         if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2183                 d_printf("cancel <jobid> ...\n");
2184                 return 1;
2185         }
2186         do {
2187                 job = atoi(buf);
2188                 do_cancel(job);
2189         } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2190
2191         return 0;
2192 }
2193
2194 /****************************************************************************
2195  Print a file.
2196 ****************************************************************************/
2197
2198 static int cmd_print(void)
2199 {
2200         TALLOC_CTX *ctx = talloc_tos();
2201         char *lname = NULL;
2202         char *rname = NULL;
2203         char *p = NULL;
2204
2205         if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2206                 d_printf("print <filename>\n");
2207                 return 1;
2208         }
2209
2210         rname = talloc_strdup(ctx, lname);
2211         if (!rname) {
2212                 return 1;
2213         }
2214         p = strrchr_m(rname,'/');
2215         if (p) {
2216                 rname = talloc_asprintf(ctx,
2217                                         "%s-%d",
2218                                         p+1,
2219                                         (int)sys_getpid());
2220         }
2221         if (strequal(lname,"-")) {
2222                 rname = talloc_asprintf(ctx,
2223                                 "stdin-%d",
2224                                 (int)sys_getpid());
2225         }
2226         if (!rname) {
2227                 return 1;
2228         }
2229
2230         return do_put(rname, lname, false);
2231 }
2232
2233 /****************************************************************************
2234  Show a print queue entry.
2235 ****************************************************************************/
2236
2237 static void queue_fn(struct print_job_info *p)
2238 {
2239         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
2240 }
2241
2242 /****************************************************************************
2243  Show a print queue.
2244 ****************************************************************************/
2245
2246 static int cmd_queue(void)
2247 {
2248         cli_print_queue(cli, queue_fn);
2249         return 0;
2250 }
2251
2252 /****************************************************************************
2253  Delete some files.
2254 ****************************************************************************/
2255
2256 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2257                    const char *dir)
2258 {
2259         TALLOC_CTX *ctx = talloc_tos();
2260         char *mask = NULL;
2261         NTSTATUS status;
2262
2263         mask = talloc_asprintf(ctx,
2264                                 "%s%c%s",
2265                                 dir,
2266                                 CLI_DIRSEP_CHAR,
2267                                 finfo->name);
2268         if (!mask) {
2269                 return NT_STATUS_NO_MEMORY;
2270         }
2271
2272         if (finfo->mode & aDIR) {
2273                 TALLOC_FREE(mask);
2274                 return NT_STATUS_OK;
2275         }
2276
2277         status = cli_unlink(cli_state, mask, aSYSTEM | aHIDDEN);
2278         if (!NT_STATUS_IS_OK(status)) {
2279                 d_printf("%s deleting remote file %s\n",
2280                          nt_errstr(status), mask);
2281         }
2282         TALLOC_FREE(mask);
2283         return status;
2284 }
2285
2286 /****************************************************************************
2287  Delete some files.
2288 ****************************************************************************/
2289
2290 static int cmd_del(void)
2291 {
2292         TALLOC_CTX *ctx = talloc_tos();
2293         char *mask = NULL;
2294         char *buf = NULL;
2295         NTSTATUS status = NT_STATUS_OK;
2296         uint16 attribute = aSYSTEM | aHIDDEN;
2297
2298         if (recurse) {
2299                 attribute |= aDIR;
2300         }
2301
2302         mask = talloc_strdup(ctx, client_get_cur_dir());
2303         if (!mask) {
2304                 return 1;
2305         }
2306         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2307                 d_printf("del <filename>\n");
2308                 return 1;
2309         }
2310         mask = talloc_asprintf_append(mask, "%s", buf);
2311         if (!mask) {
2312                 return 1;
2313         }
2314
2315         status = do_list(mask,attribute,do_del,false,false);
2316         if (!NT_STATUS_IS_OK(status)) {
2317                 return 1;
2318         }
2319         return 0;
2320 }
2321
2322 /****************************************************************************
2323  Wildcard delete some files.
2324 ****************************************************************************/
2325
2326 static int cmd_wdel(void)
2327 {
2328         TALLOC_CTX *ctx = talloc_tos();
2329         char *mask = NULL;
2330         char *buf = NULL;
2331         uint16 attribute;
2332         struct cli_state *targetcli;
2333         char *targetname = NULL;
2334         NTSTATUS status;
2335
2336         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2337                 d_printf("wdel 0x<attrib> <wcard>\n");
2338                 return 1;
2339         }
2340
2341         attribute = (uint16)strtol(buf, (char **)NULL, 16);
2342
2343         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2344                 d_printf("wdel 0x<attrib> <wcard>\n");
2345                 return 1;
2346         }
2347
2348         mask = talloc_asprintf(ctx, "%s%s",
2349                         client_get_cur_dir(),
2350                         buf);
2351         if (!mask) {
2352                 return 1;
2353         }
2354
2355         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2356                 d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
2357                 return 1;
2358         }
2359
2360         status = cli_unlink(targetcli, targetname, attribute);
2361         if (!NT_STATUS_IS_OK(status)) {
2362                 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2363                          targetname);
2364         }
2365         return 0;
2366 }
2367
2368 /****************************************************************************
2369 ****************************************************************************/
2370
2371 static int cmd_open(void)
2372 {
2373         TALLOC_CTX *ctx = talloc_tos();
2374         char *mask = NULL;
2375         char *buf = NULL;
2376         char *targetname = NULL;
2377         struct cli_state *targetcli;
2378         uint16_t fnum = (uint16_t)-1;
2379
2380         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2381                 d_printf("open <filename>\n");
2382                 return 1;
2383         }
2384         mask = talloc_asprintf(ctx,
2385                         "%s%s",
2386                         client_get_cur_dir(),
2387                         buf);
2388         if (!mask) {
2389                 return 1;
2390         }
2391
2392         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2393                 d_printf("open %s: %s\n", mask, cli_errstr(cli));
2394                 return 1;
2395         }
2396
2397         if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
2398                         FILE_READ_DATA|FILE_WRITE_DATA, 0,
2399                         FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
2400                 if (NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
2401                                 FILE_READ_DATA, 0,
2402                                 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
2403                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2404                 } else {
2405                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2406                 }
2407         } else {
2408                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2409         }
2410         return 0;
2411 }
2412
2413 static int cmd_posix_encrypt(void)
2414 {
2415         TALLOC_CTX *ctx = talloc_tos();
2416         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2417
2418         if (cli->use_kerberos) {
2419                 status = cli_gss_smb_encryption_start(cli);
2420         } else {
2421                 char *domain = NULL;
2422                 char *user = NULL;
2423                 char *password = NULL;
2424
2425                 if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
2426                         d_printf("posix_encrypt domain user password\n");
2427                         return 1;
2428                 }
2429
2430                 if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
2431                         d_printf("posix_encrypt domain user password\n");
2432                         return 1;
2433                 }
2434
2435                 if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
2436                         d_printf("posix_encrypt domain user password\n");
2437                         return 1;
2438                 }
2439
2440                 status = cli_raw_ntlm_smb_encryption_start(cli,
2441                                                         user,
2442                                                         password,
2443                                                         domain);
2444         }
2445
2446         if (!NT_STATUS_IS_OK(status)) {
2447                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2448         } else {
2449                 d_printf("encryption on\n");
2450                 smb_encrypt = true;
2451         }
2452
2453         return 0;
2454 }
2455
2456 /****************************************************************************
2457 ****************************************************************************/
2458
2459 static int cmd_posix_open(void)
2460 {
2461         TALLOC_CTX *ctx = talloc_tos();
2462         char *mask = NULL;
2463         char *buf = NULL;
2464         char *targetname = NULL;
2465         struct cli_state *targetcli;
2466         mode_t mode;
2467         uint16_t fnum;
2468
2469         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2470                 d_printf("posix_open <filename> 0<mode>\n");
2471                 return 1;
2472         }
2473         mask = talloc_asprintf(ctx,
2474                         "%s%s",
2475                         client_get_cur_dir(),
2476                         buf);
2477         if (!mask) {
2478                 return 1;
2479         }
2480
2481         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2482                 d_printf("posix_open <filename> 0<mode>\n");
2483                 return 1;
2484         }
2485         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2486
2487         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2488                 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
2489                 return 1;
2490         }
2491
2492         if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode, &fnum))) {
2493                 if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode, &fnum))) {
2494                         d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2495                 } else {
2496                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2497                 }
2498         } else {
2499                 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2500         }
2501
2502         return 0;
2503 }
2504
2505 static int cmd_posix_mkdir(void)
2506 {
2507         TALLOC_CTX *ctx = talloc_tos();
2508         char *mask = NULL;
2509         char *buf = NULL;
2510         char *targetname = NULL;
2511         struct cli_state *targetcli;
2512         mode_t mode;
2513
2514         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2515                 d_printf("posix_mkdir <filename> 0<mode>\n");
2516                 return 1;
2517         }
2518         mask = talloc_asprintf(ctx,
2519                         "%s%s",
2520                         client_get_cur_dir(),
2521                         buf);
2522         if (!mask) {
2523                 return 1;
2524         }
2525
2526         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2527                 d_printf("posix_mkdir <filename> 0<mode>\n");
2528                 return 1;
2529         }
2530         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2531
2532         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2533                 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
2534                 return 1;
2535         }
2536
2537         if (!NT_STATUS_IS_OK(cli_posix_mkdir(targetcli, targetname, mode))) {
2538                 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2539         } else {
2540                 d_printf("posix_mkdir created directory %s\n", targetname);
2541         }
2542         return 0;
2543 }
2544
2545 static int cmd_posix_unlink(void)
2546 {
2547         TALLOC_CTX *ctx = talloc_tos();
2548         char *mask = NULL;
2549         char *buf = NULL;
2550         char *targetname = NULL;
2551         struct cli_state *targetcli;
2552
2553         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2554                 d_printf("posix_unlink <filename>\n");
2555                 return 1;
2556         }
2557         mask = talloc_asprintf(ctx,
2558                         "%s%s",
2559                         client_get_cur_dir(),
2560                         buf);
2561         if (!mask) {
2562                 return 1;
2563         }
2564
2565         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2566                 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
2567                 return 1;
2568         }
2569
2570         if (!NT_STATUS_IS_OK(cli_posix_unlink(targetcli, targetname))) {
2571                 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
2572         } else {
2573                 d_printf("posix_unlink deleted file %s\n", targetname);
2574         }
2575
2576         return 0;
2577 }
2578
2579 static int cmd_posix_rmdir(void)
2580 {
2581         TALLOC_CTX *ctx = talloc_tos();
2582         char *mask = NULL;
2583         char *buf = NULL;
2584         char *targetname = NULL;
2585         struct cli_state *targetcli;
2586
2587         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2588                 d_printf("posix_rmdir <filename>\n");
2589                 return 1;
2590         }
2591         mask = talloc_asprintf(ctx,
2592                         "%s%s",
2593                         client_get_cur_dir(),
2594                         buf);
2595         if (!mask) {
2596                 return 1;
2597         }
2598
2599         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2600                 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
2601                 return 1;
2602         }
2603
2604         if (!NT_STATUS_IS_OK(cli_posix_rmdir(targetcli, targetname))) {
2605                 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
2606         } else {
2607                 d_printf("posix_rmdir deleted directory %s\n", targetname);
2608         }
2609
2610         return 0;
2611 }
2612
2613 static int cmd_close(void)
2614 {
2615         TALLOC_CTX *ctx = talloc_tos();
2616         char *buf = NULL;
2617         int fnum;
2618
2619         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2620                 d_printf("close <fnum>\n");
2621                 return 1;
2622         }
2623
2624         fnum = atoi(buf);
2625         /* We really should use the targetcli here.... */
2626         if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
2627                 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
2628                 return 1;
2629         }
2630         return 0;
2631 }
2632
2633 static int cmd_posix(void)
2634 {
2635         TALLOC_CTX *ctx = talloc_tos();
2636         uint16 major, minor;
2637         uint32 caplow, caphigh;
2638         char *caps;
2639         NTSTATUS status;
2640
2641         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2642                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
2643                 return 1;
2644         }
2645
2646         status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
2647                                              &caphigh);
2648         if (!NT_STATUS_IS_OK(status)) {
2649                 d_printf("Can't get UNIX CIFS extensions version from "
2650                          "server: %s\n", nt_errstr(status));
2651                 return 1;
2652         }
2653
2654         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2655
2656         caps = talloc_strdup(ctx, "");
2657         if (!caps) {
2658                 return 1;
2659         }
2660         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2661                 caps = talloc_asprintf_append(caps, "locks ");
2662                 if (!caps) {
2663                         return 1;
2664                 }
2665         }
2666         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2667                 caps = talloc_asprintf_append(caps, "acls ");
2668                 if (!caps) {
2669                         return 1;
2670                 }
2671         }
2672         if (caplow & CIFS_UNIX_XATTTR_CAP) {
2673                 caps = talloc_asprintf_append(caps, "eas ");
2674                 if (!caps) {
2675                         return 1;
2676                 }
2677         }
2678         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2679                 caps = talloc_asprintf_append(caps, "pathnames ");
2680                 if (!caps) {
2681                         return 1;
2682                 }
2683         }
2684         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2685                 caps = talloc_asprintf_append(caps, "posix_path_operations ");
2686                 if (!caps) {
2687                         return 1;
2688                 }
2689         }
2690         if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
2691                 caps = talloc_asprintf_append(caps, "large_read ");
2692                 if (!caps) {
2693                         return 1;
2694                 }
2695         }
2696         if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
2697                 caps = talloc_asprintf_append(caps, "large_write ");
2698                 if (!caps) {
2699                         return 1;
2700                 }
2701         }
2702         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
2703                 caps = talloc_asprintf_append(caps, "posix_encrypt ");
2704                 if (!caps) {
2705                         return 1;
2706                 }
2707         }
2708         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
2709                 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
2710                 if (!caps) {
2711                         return 1;
2712                 }
2713         }
2714
2715         if (*caps && caps[strlen(caps)-1] == ' ') {
2716                 caps[strlen(caps)-1] = '\0';
2717         }
2718
2719         d_printf("Server supports CIFS capabilities %s\n", caps);
2720
2721         status = cli_set_unix_extensions_capabilities(cli, major, minor,
2722                                                       caplow, caphigh);
2723         if (!NT_STATUS_IS_OK(status)) {
2724                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
2725                          nt_errstr(status));
2726                 return 1;
2727         }
2728
2729         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2730                 CLI_DIRSEP_CHAR = '/';
2731                 *CLI_DIRSEP_STR = '/';
2732                 client_set_cur_dir(CLI_DIRSEP_STR);
2733         }
2734
2735         return 0;
2736 }
2737
2738 static int cmd_lock(void)
2739 {
2740         TALLOC_CTX *ctx = talloc_tos();
2741         char *buf = NULL;
2742         uint64_t start, len;
2743         enum brl_type lock_type;
2744         int fnum;
2745
2746         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2747                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2748                 return 1;
2749         }
2750         fnum = atoi(buf);
2751
2752         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2753                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2754                 return 1;
2755         }
2756
2757         if (*buf == 'r' || *buf == 'R') {
2758                 lock_type = READ_LOCK;
2759         } else if (*buf == 'w' || *buf == 'W') {
2760                 lock_type = WRITE_LOCK;
2761         } else {
2762                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2763                 return 1;
2764         }
2765
2766         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2767                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2768                 return 1;
2769         }
2770
2771         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2772
2773         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2774                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2775                 return 1;
2776         }
2777
2778         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2779
2780         if (!NT_STATUS_IS_OK(cli_posix_lock(cli, fnum, start, len, true, lock_type))) {
2781                 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2782         }
2783
2784         return 0;
2785 }
2786
2787 static int cmd_unlock(void)
2788 {
2789         TALLOC_CTX *ctx = talloc_tos();
2790         char *buf = NULL;
2791         uint64_t start, len;
2792         int fnum;
2793
2794         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2795                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2796                 return 1;
2797         }
2798         fnum = atoi(buf);
2799
2800         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2801                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2802                 return 1;
2803         }
2804
2805         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2806
2807         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2808                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2809                 return 1;
2810         }
2811
2812         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2813
2814         if (!NT_STATUS_IS_OK(cli_posix_unlock(cli, fnum, start, len))) {
2815                 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2816         }
2817
2818         return 0;
2819 }
2820
2821
2822 /****************************************************************************
2823  Remove a directory.
2824 ****************************************************************************/
2825
2826 static int cmd_rmdir(void)
2827 {
2828         TALLOC_CTX *ctx = talloc_tos();
2829         char *mask = NULL;
2830         char *buf = NULL;
2831         char *targetname = NULL;
2832         struct cli_state *targetcli;
2833
2834         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2835                 d_printf("rmdir <dirname>\n");
2836                 return 1;
2837         }
2838         mask = talloc_asprintf(ctx,
2839                         "%s%s",
2840                         client_get_cur_dir(),
2841                         buf);
2842         if (!mask) {
2843                 return 1;
2844         }
2845
2846         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2847                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2848                 return 1;
2849         }
2850
2851         if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetname))) {
2852                 d_printf("%s removing remote directory file %s\n",
2853                          cli_errstr(targetcli),mask);
2854         }
2855
2856         return 0;
2857 }
2858
2859 /****************************************************************************
2860  UNIX hardlink.
2861 ****************************************************************************/
2862
2863 static int cmd_link(void)
2864 {
2865         TALLOC_CTX *ctx = talloc_tos();
2866         char *oldname = NULL;
2867         char *newname = NULL;
2868         char *buf = NULL;
2869         char *buf2 = NULL;
2870         char *targetname = NULL;
2871         struct cli_state *targetcli;
2872
2873         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2874             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2875                 d_printf("link <oldname> <newname>\n");
2876                 return 1;
2877         }
2878         oldname = talloc_asprintf(ctx,
2879                         "%s%s",
2880                         client_get_cur_dir(),
2881                         buf);
2882         if (!oldname) {
2883                 return 1;
2884         }
2885         newname = talloc_asprintf(ctx,
2886                         "%s%s",
2887                         client_get_cur_dir(),
2888                         buf2);
2889         if (!newname) {
2890                 return 1;
2891         }
2892
2893         if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
2894                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2895                 return 1;
2896         }
2897
2898         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2899                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2900                 return 1;
2901         }
2902
2903         if (!NT_STATUS_IS_OK(cli_posix_hardlink(targetcli, targetname, newname))) {
2904                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2905                 return 1;
2906         }
2907         return 0;
2908 }
2909
2910 /****************************************************************************
2911  UNIX readlink.
2912 ****************************************************************************/
2913
2914 static int cmd_readlink(void)
2915 {
2916         TALLOC_CTX *ctx = talloc_tos();
2917         char *name= NULL;
2918         char *buf = NULL;
2919         char *targetname = NULL;
2920         char linkname[PATH_MAX+1];
2921         struct cli_state *targetcli;
2922
2923         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2924                 d_printf("readlink <name>\n");
2925                 return 1;
2926         }
2927         name = talloc_asprintf(ctx,
2928                         "%s%s",
2929                         client_get_cur_dir(),
2930                         buf);
2931         if (!name) {
2932                 return 1;
2933         }
2934
2935         if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
2936                 d_printf("readlink %s: %s\n", name, cli_errstr(cli));
2937                 return 1;
2938         }
2939
2940         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2941                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2942                 return 1;
2943         }
2944
2945         if (!NT_STATUS_IS_OK(cli_posix_readlink(targetcli, name,
2946                         linkname, PATH_MAX+1))) {
2947                 d_printf("%s readlink on file %s\n",
2948                         cli_errstr(targetcli), name);
2949                 return 1;
2950         }
2951
2952         d_printf("%s -> %s\n", name, linkname);
2953
2954         return 0;
2955 }
2956
2957
2958 /****************************************************************************
2959  UNIX symlink.
2960 ****************************************************************************/
2961
2962 static int cmd_symlink(void)
2963 {
2964         TALLOC_CTX *ctx = talloc_tos();
2965         char *oldname = NULL;
2966         char *newname = NULL;
2967         char *buf = NULL;
2968         char *buf2 = NULL;
2969         struct cli_state *newcli;
2970
2971         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2972             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2973                 d_printf("symlink <oldname> <newname>\n");
2974                 return 1;
2975         }
2976         /* Oldname (link target) must be an untouched blob. */
2977         oldname = buf;
2978
2979         newname = talloc_asprintf(ctx,
2980                         "%s%s",
2981                         client_get_cur_dir(),
2982                         buf2);
2983         if (!newname) {
2984                 return 1;
2985         }
2986
2987         /* New name must be present in share namespace. */
2988         if (!cli_resolve_path(ctx, "", auth_info, cli, newname, &newcli, &newname)) {
2989                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2990                 return 1;
2991         }
2992
2993         if (!SERVER_HAS_UNIX_CIFS(newcli)) {
2994                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2995                 return 1;
2996         }
2997
2998         if (!NT_STATUS_IS_OK(cli_posix_symlink(newcli, oldname, newname))) {
2999                 d_printf("%s symlinking files (%s -> %s)\n",
3000                         cli_errstr(newcli), newname, newname);
3001                 return 1;
3002         }
3003
3004         return 0;
3005 }
3006
3007 /****************************************************************************
3008  UNIX chmod.
3009 ****************************************************************************/
3010
3011 static int cmd_chmod(void)
3012 {
3013         TALLOC_CTX *ctx = talloc_tos();
3014         char *src = NULL;
3015         char *buf = NULL;
3016         char *buf2 = NULL;
3017         char *targetname = NULL;
3018         struct cli_state *targetcli;
3019         mode_t mode;
3020
3021         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3022             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3023                 d_printf("chmod mode file\n");
3024                 return 1;
3025         }
3026         src = talloc_asprintf(ctx,
3027                         "%s%s",
3028                         client_get_cur_dir(),
3029                         buf2);
3030         if (!src) {
3031                 return 1;
3032         }
3033
3034         mode = (mode_t)strtol(buf, NULL, 8);
3035
3036         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3037                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
3038                 return 1;
3039         }
3040
3041         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3042                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3043                 return 1;
3044         }
3045
3046         if (!NT_STATUS_IS_OK(cli_posix_chmod(targetcli, targetname, mode))) {
3047                 d_printf("%s chmod file %s 0%o\n",
3048                         cli_errstr(targetcli), src, (unsigned int)mode);
3049                 return 1;
3050         }
3051
3052         return 0;
3053 }
3054
3055 static const char *filetype_to_str(mode_t mode)
3056 {
3057         if (S_ISREG(mode)) {
3058                 return "regular file";
3059         } else if (S_ISDIR(mode)) {
3060                 return "directory";
3061         } else
3062 #ifdef S_ISCHR
3063         if (S_ISCHR(mode)) {
3064                 return "character device";
3065         } else
3066 #endif
3067 #ifdef S_ISBLK
3068         if (S_ISBLK(mode)) {
3069                 return "block device";
3070         } else
3071 #endif
3072 #ifdef S_ISFIFO
3073         if (S_ISFIFO(mode)) {
3074                 return "fifo";
3075         } else
3076 #endif
3077 #ifdef S_ISLNK
3078         if (S_ISLNK(mode)) {
3079                 return "symbolic link";
3080         } else
3081 #endif
3082 #ifdef S_ISSOCK
3083         if (S_ISSOCK(mode)) {
3084                 return "socket";
3085         } else
3086 #endif
3087         return "";
3088 }
3089
3090 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3091 {
3092         if (m & bt) {
3093                 return ret;
3094         } else {
3095                 return '-';
3096         }
3097 }
3098
3099 static char *unix_mode_to_str(char *s, mode_t m)
3100 {
3101         char *p = s;
3102         const char *str = filetype_to_str(m);
3103
3104         switch(str[0]) {
3105                 case 'd':
3106                         *p++ = 'd';
3107                         break;
3108                 case 'c':
3109                         *p++ = 'c';
3110                         break;
3111                 case 'b':
3112                         *p++ = 'b';
3113                         break;
3114                 case 'f':
3115                         *p++ = 'p';
3116                         break;
3117                 case 's':
3118                         *p++ = str[1] == 'y' ? 'l' : 's';
3119                         break;
3120                 case 'r':
3121                 default:
3122                         *p++ = '-';
3123                         break;
3124         }
3125         *p++ = rwx_to_str(m, S_IRUSR, 'r');
3126         *p++ = rwx_to_str(m, S_IWUSR, 'w');
3127         *p++ = rwx_to_str(m, S_IXUSR, 'x');
3128         *p++ = rwx_to_str(m, S_IRGRP, 'r');
3129         *p++ = rwx_to_str(m, S_IWGRP, 'w');
3130         *p++ = rwx_to_str(m, S_IXGRP, 'x');
3131         *p++ = rwx_to_str(m, S_IROTH, 'r');
3132         *p++ = rwx_to_str(m, S_IWOTH, 'w');
3133         *p++ = rwx_to_str(m, S_IXOTH, 'x');
3134         *p++ = '\0';
3135         return s;
3136 }
3137
3138 /****************************************************************************
3139  Utility function for UNIX getfacl.
3140 ****************************************************************************/
3141
3142 static char *perms_to_string(fstring permstr, unsigned char perms)
3143 {
3144         fstrcpy(permstr, "---");
3145         if (perms & SMB_POSIX_ACL_READ) {
3146                 permstr[0] = 'r';
3147         }
3148         if (perms & SMB_POSIX_ACL_WRITE) {
3149                 permstr[1] = 'w';
3150         }
3151         if (perms & SMB_POSIX_ACL_EXECUTE) {
3152                 permstr[2] = 'x';
3153         }
3154         return permstr;
3155 }
3156
3157 /****************************************************************************
3158  UNIX getfacl.
3159 ****************************************************************************/
3160
3161 static int cmd_getfacl(void)
3162 {
3163         TALLOC_CTX *ctx = talloc_tos();
3164         char *src = NULL;
3165         char *name = NULL;
3166         char *targetname = NULL;
3167         struct cli_state *targetcli;
3168         uint16 major, minor;
3169         uint32 caplow, caphigh;
3170         char *retbuf = NULL;
3171         size_t rb_size = 0;
3172         SMB_STRUCT_STAT sbuf;
3173         uint16 num_file_acls = 0;
3174         uint16 num_dir_acls = 0;
3175         uint16 i;
3176         NTSTATUS status;
3177
3178         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3179                 d_printf("getfacl filename\n");
3180                 return 1;
3181         }
3182         src = talloc_asprintf(ctx,
3183                         "%s%s",
3184                         client_get_cur_dir(),
3185                         name);
3186         if (!src) {
3187                 return 1;
3188         }
3189
3190         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3191                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3192                 return 1;
3193         }
3194
3195         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3196                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3197                 return 1;
3198         }
3199
3200         status = cli_unix_extensions_version(targetcli, &major, &minor,
3201                                              &caplow, &caphigh);
3202         if (!NT_STATUS_IS_OK(status)) {
3203                 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3204                          nt_errstr(status));
3205                 return 1;
3206         }
3207
3208         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3209                 d_printf("This server supports UNIX extensions "
3210                         "but doesn't support POSIX ACLs.\n");
3211                 return 1;
3212         }
3213
3214         if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
3215                 d_printf("%s getfacl doing a stat on file %s\n",
3216                         cli_errstr(targetcli), src);
3217                 return 1;
3218         }
3219
3220         if (!NT_STATUS_IS_OK(cli_posix_getfacl(targetcli, targetname, ctx, &rb_size, &retbuf))) {
3221                 d_printf("%s getfacl file %s\n",
3222                         cli_errstr(targetcli), src);
3223                 return 1;
3224         }
3225
3226         /* ToDo : Print out the ACL values. */
3227         if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3228                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3229                         src, (unsigned int)CVAL(retbuf,0) );
3230                 return 1;
3231         }
3232
3233         num_file_acls = SVAL(retbuf,2);
3234         num_dir_acls = SVAL(retbuf,4);
3235         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3236                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3237                         src,
3238                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3239                         (unsigned int)rb_size);
3240                 return 1;
3241         }
3242
3243         d_printf("# file: %s\n", src);
3244         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3245
3246         if (num_file_acls == 0 && num_dir_acls == 0) {
3247                 d_printf("No acls found.\n");
3248         }
3249
3250         for (i = 0; i < num_file_acls; i++) {
3251                 uint32 uorg;
3252                 fstring permstring;
3253                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3254                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3255
3256                 switch(tagtype) {
3257                         case SMB_POSIX_ACL_USER_OBJ:
3258                                 d_printf("user::");
3259                                 break;
3260                         case SMB_POSIX_ACL_USER:
3261                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3262                                 d_printf("user:%u:", uorg);
3263                                 break;
3264                         case SMB_POSIX_ACL_GROUP_OBJ:
3265                                 d_printf("group::");
3266                                 break;
3267                         case SMB_POSIX_ACL_GROUP:
3268                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3269                                 d_printf("group:%u:", uorg);
3270                                 break;
3271                         case SMB_POSIX_ACL_MASK:
3272                                 d_printf("mask::");
3273                                 break;
3274                         case SMB_POSIX_ACL_OTHER:
3275                                 d_printf("other::");
3276                                 break;
3277                         default:
3278                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3279                                         src, (unsigned int)tagtype );
3280                                 SAFE_FREE(retbuf);
3281                                 return 1;
3282                 }
3283
3284                 d_printf("%s\n", perms_to_string(permstring, perms));
3285         }
3286
3287         for (i = 0; i < num_dir_acls; i++) {
3288                 uint32 uorg;
3289                 fstring permstring;
3290                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3291                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3292
3293                 switch(tagtype) {
3294                         case SMB_POSIX_ACL_USER_OBJ:
3295                                 d_printf("default:user::");
3296                                 break;
3297                         case SMB_POSIX_ACL_USER:
3298                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3299                                 d_printf("default:user:%u:", uorg);
3300                                 break;
3301                         case SMB_POSIX_ACL_GROUP_OBJ:
3302                                 d_printf("default:group::");
3303                                 break;
3304                         case SMB_POSIX_ACL_GROUP:
3305                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3306                                 d_printf("default:group:%u:", uorg);
3307                                 break;
3308                         case SMB_POSIX_ACL_MASK:
3309                                 d_printf("default:mask::");
3310                                 break;
3311                         case SMB_POSIX_ACL_OTHER:
3312                                 d_printf("default:other::");
3313                                 break;
3314                         default:
3315                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3316                                         src, (unsigned int)tagtype );
3317                                 SAFE_FREE(retbuf);
3318                                 return 1;
3319                 }
3320
3321                 d_printf("%s\n", perms_to_string(permstring, perms));
3322         }
3323
3324         return 0;
3325 }
3326
3327 static void printf_cb(const char *buf, void *private_data)
3328 {
3329         printf("%s", buf);
3330 }
3331
3332 /****************************************************************************
3333  Get the EA list of a file
3334 ****************************************************************************/
3335
3336 static int cmd_geteas(void)
3337 {
3338         TALLOC_CTX *ctx = talloc_tos();
3339         char *src = NULL;
3340         char *name = NULL;
3341         char *targetname = NULL;
3342         struct cli_state *targetcli;
3343         NTSTATUS status;
3344         size_t i, num_eas;
3345         struct ea_struct *eas;
3346
3347         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3348                 d_printf("geteas filename\n");
3349                 return 1;
3350         }
3351         src = talloc_asprintf(ctx,
3352                         "%s%s",
3353                         client_get_cur_dir(),
3354                         name);
3355         if (!src) {
3356                 return 1;
3357         }
3358
3359         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
3360                               &targetname)) {
3361                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3362                 return 1;
3363         }
3364
3365         status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
3366                                       &num_eas, &eas);
3367         if (!NT_STATUS_IS_OK(status)) {
3368                 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
3369                 return 1;
3370         }
3371
3372         for (i=0; i<num_eas; i++) {
3373                 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
3374                 dump_data_cb(eas[i].value.data, eas[i].value.length, false,
3375                              printf_cb, NULL);
3376                 d_printf("\n");
3377         }
3378
3379         TALLOC_FREE(eas);
3380
3381         return 0;
3382 }
3383
3384 /****************************************************************************
3385  Set an EA of a file
3386 ****************************************************************************/
3387
3388 static int cmd_setea(void)
3389 {
3390         TALLOC_CTX *ctx = talloc_tos();
3391         char *src = NULL;
3392         char *name = NULL;
3393         char *eaname = NULL;
3394         char *eavalue = NULL;
3395         char *targetname = NULL;
3396         struct cli_state *targetcli;
3397         NTSTATUS status;
3398
3399         if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
3400             || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
3401                 d_printf("setea filename eaname value\n");
3402                 return 1;
3403         }
3404         if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
3405                 eavalue = talloc_strdup(ctx, "");
3406         }
3407         src = talloc_asprintf(ctx,
3408                         "%s%s",
3409                         client_get_cur_dir(),
3410                         name);
3411         if (!src) {
3412                 return 1;
3413         }
3414
3415         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
3416                               &targetname)) {
3417                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3418                 return 1;
3419         }
3420
3421         status =  cli_set_ea_path(targetcli, targetname, eaname, eavalue,
3422                                   strlen(eavalue));
3423         if (!NT_STATUS_IS_OK(status)) {
3424                 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
3425                 return 1;
3426         }
3427
3428         return 0;
3429 }
3430
3431 /****************************************************************************
3432  UNIX stat.
3433 ****************************************************************************/
3434
3435 static int cmd_stat(void)
3436 {
3437         TALLOC_CTX *ctx = talloc_tos();
3438         char *src = NULL;
3439         char *name = NULL;
3440         char *targetname = NULL;
3441         struct cli_state *targetcli;
3442         fstring mode_str;
3443         SMB_STRUCT_STAT sbuf;
3444         struct tm *lt;
3445         time_t tmp_time;
3446
3447         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3448                 d_printf("stat file\n");
3449                 return 1;
3450         }
3451         src = talloc_asprintf(ctx,
3452                         "%s%s",
3453                         client_get_cur_dir(),
3454                         name);
3455         if (!src) {
3456                 return 1;
3457         }
3458
3459         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3460                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3461                 return 1;
3462         }
3463
3464         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3465                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3466                 return 1;
3467         }
3468
3469         if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
3470                 d_printf("%s stat file %s\n",
3471                         cli_errstr(targetcli), src);
3472                 return 1;
3473         }
3474
3475         /* Print out the stat values. */
3476         d_printf("File: %s\n", src);
3477         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
3478                 (double)sbuf.st_ex_size,
3479                 (unsigned int)sbuf.st_ex_blocks,
3480                 filetype_to_str(sbuf.st_ex_mode));
3481
3482 #if defined(S_ISCHR) && defined(S_ISBLK)
3483         if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
3484                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
3485                         (double)sbuf.st_ex_ino,
3486                         (unsigned int)sbuf.st_ex_nlink,
3487                         unix_dev_major(sbuf.st_ex_rdev),
3488                         unix_dev_minor(sbuf.st_ex_rdev));
3489         } else
3490 #endif
3491                 d_printf("Inode: %.0f\tLinks: %u\n",
3492                         (double)sbuf.st_ex_ino,
3493                         (unsigned int)sbuf.st_ex_nlink);
3494
3495         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
3496                 ((int)sbuf.st_ex_mode & 0777),
3497                 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
3498                 (unsigned int)sbuf.st_ex_uid,
3499                 (unsigned int)sbuf.st_ex_gid);
3500
3501         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
3502         lt = localtime(&tmp_time);
3503         if (lt) {
3504                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3505         } else {
3506                 fstrcpy(mode_str, "unknown");
3507         }
3508         d_printf("Access: %s\n", mode_str);
3509
3510         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
3511         lt = localtime(&tmp_time);
3512         if (lt) {
3513                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3514         } else {
3515                 fstrcpy(mode_str, "unknown");
3516         }
3517         d_printf("Modify: %s\n", mode_str);
3518
3519         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
3520         lt = localtime(&tmp_time);
3521         if (lt) {
3522                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3523         } else {
3524                 fstrcpy(mode_str, "unknown");
3525         }
3526         d_printf("Change: %s\n", mode_str);
3527
3528         return 0;
3529 }
3530
3531
3532 /****************************************************************************
3533  UNIX chown.
3534 ****************************************************************************/
3535
3536 static int cmd_chown(void)
3537 {
3538         TALLOC_CTX *ctx = talloc_tos();
3539         char *src = NULL;
3540         uid_t uid;
3541         gid_t gid;
3542         char *buf, *buf2, *buf3;
3543         struct cli_state *targetcli;
3544         char *targetname = NULL;
3545
3546         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3547             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
3548             !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
3549                 d_printf("chown uid gid file\n");
3550                 return 1;
3551         }
3552
3553         uid = (uid_t)atoi(buf);
3554         gid = (gid_t)atoi(buf2);
3555
3556         src = talloc_asprintf(ctx,
3557                         "%s%s",
3558                         client_get_cur_dir(),
3559                         buf3);
3560         if (!src) {
3561                 return 1;
3562         }
3563         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname) ) {
3564                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
3565                 return 1;
3566         }
3567
3568         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3569                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3570                 return 1;
3571         }
3572
3573         if (!NT_STATUS_IS_OK(cli_posix_chown(targetcli, targetname, uid, gid))) {
3574                 d_printf("%s chown file %s uid=%d, gid=%d\n",
3575                         cli_errstr(targetcli), src, (int)uid, (int)gid);
3576                 return 1;
3577         }
3578
3579         return 0;
3580 }
3581
3582 /****************************************************************************
3583  Rename some file.
3584 ****************************************************************************/
3585
3586 static int cmd_rename(void)
3587 {
3588         TALLOC_CTX *ctx = talloc_tos();
3589         char *src, *dest;
3590         char *buf, *buf2;
3591         struct cli_state *targetcli;
3592         char *targetsrc;
3593         char *targetdest;
3594
3595         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3596             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3597                 d_printf("rename <src> <dest>\n");
3598                 return 1;
3599         }
3600
3601         src = talloc_asprintf(ctx,
3602                         "%s%s",
3603                         client_get_cur_dir(),
3604                         buf);
3605         if (!src) {
3606                 return 1;
3607         }
3608
3609         dest = talloc_asprintf(ctx,
3610                         "%s%s",
3611                         client_get_cur_dir(),
3612                         buf2);
3613         if (!dest) {
3614                 return 1;
3615         }
3616
3617         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetsrc)) {
3618                 d_printf("rename %s: %s\n", src, cli_errstr(cli));
3619                 return 1;
3620         }
3621
3622         if (!cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli, &targetdest)) {
3623                 d_printf("rename %s: %s\n", dest, cli_errstr(cli));
3624                 return 1;
3625         }
3626
3627         if (!NT_STATUS_IS_OK(cli_rename(targetcli, targetsrc, targetdest))) {
3628                 d_printf("%s renaming files %s -> %s \n",
3629                         cli_errstr(targetcli),
3630                         targetsrc,
3631                         targetdest);
3632                 return 1;
3633         }
3634
3635         return 0;
3636 }
3637
3638 /****************************************************************************
3639  Print the volume name.
3640 ****************************************************************************/
3641
3642 static int cmd_volume(void)
3643 {
3644         fstring volname;
3645         uint32 serial_num;
3646         time_t create_date;
3647         NTSTATUS status;
3648
3649         status = cli_get_fs_volume_info(cli, volname, &serial_num,
3650                                         &create_date);
3651         if (!NT_STATUS_IS_OK(status)) {
3652                 d_printf("Error %s getting volume info\n", nt_errstr(status));
3653                 return 1;
3654         }
3655
3656         d_printf("Volume: |%s| serial number 0x%x\n",
3657                         volname, (unsigned int)serial_num);
3658         return 0;
3659 }
3660
3661 /****************************************************************************
3662  Hard link files using the NT call.
3663 ****************************************************************************/
3664
3665 static int cmd_hardlink(void)
3666 {
3667         TALLOC_CTX *ctx = talloc_tos();
3668         char *src, *dest;
3669         char *buf, *buf2;
3670         struct cli_state *targetcli;
3671         char *targetname;
3672
3673         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3674             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3675                 d_printf("hardlink <src> <dest>\n");
3676                 return 1;
3677         }
3678
3679         src = talloc_asprintf(ctx,
3680                         "%s%s",
3681                         client_get_cur_dir(),
3682                         buf);
3683         if (!src) {
3684                 return 1;
3685         }
3686
3687         dest = talloc_asprintf(ctx,
3688                         "%s%s",
3689                         client_get_cur_dir(),
3690                         buf2);
3691         if (!dest) {
3692                 return 1;
3693         }
3694
3695         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3696                 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
3697                 return 1;
3698         }
3699
3700         if (!NT_STATUS_IS_OK(cli_nt_hardlink(targetcli, targetname, dest))) {
3701                 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
3702                 return 1;
3703         }
3704
3705         return 0;
3706 }
3707
3708 /****************************************************************************
3709  Toggle the prompt flag.
3710 ****************************************************************************/
3711
3712 static int cmd_prompt(void)
3713 {
3714         prompt = !prompt;
3715         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
3716         return 1;
3717 }
3718
3719 /****************************************************************************
3720  Set the newer than time.
3721 ****************************************************************************/
3722
3723 static int cmd_newer(void)
3724 {
3725         TALLOC_CTX *ctx = talloc_tos();
3726         char *buf;
3727         bool ok;
3728         SMB_STRUCT_STAT sbuf;
3729
3730         ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
3731         if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
3732                 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
3733                 DEBUG(1,("Getting files newer than %s",
3734                          time_to_asc(newer_than)));
3735         } else {
3736                 newer_than = 0;
3737         }
3738
3739         if (ok && newer_than == 0) {
3740                 d_printf("Error setting newer-than time\n");
3741                 return 1;
3742         }
3743
3744         return 0;
3745 }
3746
3747 /****************************************************************************
3748  Set the archive level.
3749 ****************************************************************************/
3750
3751 static int cmd_archive(void)
3752 {
3753         TALLOC_CTX *ctx = talloc_tos();
3754         char *buf;
3755
3756         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3757                 archive_level = atoi(buf);
3758         } else {
3759                 d_printf("Archive level is %d\n",archive_level);
3760         }
3761
3762         return 0;
3763 }
3764
3765 /****************************************************************************
3766  Toggle the lowercaseflag.
3767 ****************************************************************************/
3768
3769 static int cmd_lowercase(void)
3770 {
3771         lowercase = !lowercase;
3772         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
3773         return 0;
3774 }
3775
3776 /****************************************************************************
3777  Toggle the case sensitive flag.
3778 ****************************************************************************/
3779
3780 static int cmd_setcase(void)
3781 {
3782         bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
3783
3784         cli_set_case_sensitive(cli, !orig_case_sensitive);
3785         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
3786                 "on":"off"));
3787         return 0;
3788 }
3789
3790 /****************************************************************************
3791  Toggle the showacls flag.
3792 ****************************************************************************/
3793
3794 static int cmd_showacls(void)
3795 {
3796         showacls = !showacls;
3797         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
3798         return 0;
3799 }
3800
3801
3802 /****************************************************************************
3803  Toggle the recurse flag.
3804 ****************************************************************************/
3805
3806 static int cmd_recurse(void)
3807 {
3808         recurse = !recurse;
3809         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
3810         return 0;
3811 }
3812
3813 /****************************************************************************
3814  Toggle the translate flag.
3815 ****************************************************************************/
3816
3817 static int cmd_translate(void)
3818 {
3819         translation = !translation;
3820         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
3821                  translation?"on":"off"));
3822         return 0;
3823 }
3824
3825 /****************************************************************************
3826  Do the lcd command.
3827  ****************************************************************************/
3828
3829 static int cmd_lcd(void)
3830 {
3831         TALLOC_CTX *ctx = talloc_tos();
3832         char *buf;
3833         char *d;
3834
3835         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3836                 if (chdir(buf) == -1) {
3837                         d_printf("chdir to %s failed (%s)\n",
3838                                 buf, strerror(errno));
3839                 }
3840         }
3841         d = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
3842         if (!d) {
3843                 return 1;
3844         }
3845         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
3846         return 0;
3847 }
3848
3849 /****************************************************************************
3850  Get a file restarting at end of local file.
3851  ****************************************************************************/
3852
3853 static int cmd_reget(void)
3854 {
3855         TALLOC_CTX *ctx = talloc_tos();
3856         char *local_name = NULL;
3857         char *remote_name = NULL;
3858         char *fname = NULL;
3859         char *p = NULL;
3860
3861         remote_name = talloc_strdup(ctx, client_get_cur_dir());
3862         if (!remote_name) {
3863                 return 1;
3864         }
3865
3866         if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
3867                 d_printf("reget <filename>\n");
3868                 return 1;
3869         }
3870         remote_name = talloc_asprintf_append(remote_name, "%s", fname);
3871         if (!remote_name) {
3872                 return 1;
3873         }
3874         remote_name = clean_name(ctx,remote_name);
3875         if (!remote_name) {
3876                 return 1;
3877         }
3878
3879         local_name = fname;
3880         next_token_talloc(ctx, &cmd_ptr, &p, NULL);
3881         if (p) {
3882                 local_name = p;
3883         }
3884
3885         return do_get(remote_name, local_name, true);
3886 }
3887
3888 /****************************************************************************
3889  Put a file restarting at end of local file.
3890  ****************************************************************************/
3891
3892 static int cmd_reput(void)
3893 {
3894         TALLOC_CTX *ctx = talloc_tos();
3895         char *local_name = NULL;
3896         char *remote_name = NULL;
3897         char *buf;
3898         SMB_STRUCT_STAT st;
3899
3900         remote_name = talloc_strdup(ctx, client_get_cur_dir());
3901         if (!remote_name) {
3902                 return 1;
3903         }
3904
3905         if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
3906                 d_printf("reput <filename>\n");
3907                 return 1;
3908         }
3909
3910         if (!file_exist_stat(local_name, &st, false)) {
3911                 d_printf("%s does not exist\n", local_name);
3912                 return 1;
3913         }
3914
3915         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3916                 remote_name = talloc_asprintf_append(remote_name,
3917                                                 "%s", buf);
3918         } else {
3919                 remote_name = talloc_asprintf_append(remote_name,
3920                                                 "%s", local_name);
3921         }
3922         if (!remote_name) {
3923                 return 1;
3924         }
3925
3926         remote_name = clean_name(ctx, remote_name);
3927         if (!remote_name) {
3928                 return 1;
3929         }
3930
3931         return do_put(remote_name, local_name, true);
3932 }
3933
3934 /****************************************************************************
3935  List a share name.
3936  ****************************************************************************/
3937
3938 static void browse_fn(const char *name, uint32 m,
3939                       const char *comment, void *state)
3940 {
3941         const char *typestr = "";
3942
3943         switch (m & 7) {
3944         case STYPE_DISKTREE:
3945                 typestr = "Disk";
3946                 break;
3947         case STYPE_PRINTQ:
3948                 typestr = "Printer";
3949                 break;
3950         case STYPE_DEVICE:
3951                 typestr = "Device";
3952                 break;
3953         case STYPE_IPC:
3954                 typestr = "IPC";
3955                 break;
3956         }
3957         /* FIXME: If the remote machine returns non-ascii characters
3958            in any of these fields, they can corrupt the output.  We
3959            should remove them. */
3960         if (!grepable) {
3961                 d_printf("\t%-15s %-10.10s%s\n",
3962                         name,typestr,comment);
3963         } else {
3964                 d_printf ("%s|%s|%s\n",typestr,name,comment);
3965         }
3966 }
3967
3968 static bool browse_host_rpc(bool sort)
3969 {
3970         NTSTATUS status;
3971         struct rpc_pipe_client *pipe_hnd = NULL;
3972         TALLOC_CTX *frame = talloc_stackframe();
3973         WERROR werr;
3974         struct srvsvc_NetShareInfoCtr info_ctr;
3975         struct srvsvc_NetShareCtr1 ctr1;
3976         uint32_t resume_handle = 0;
3977         uint32_t total_entries = 0;
3978         int i;
3979         struct dcerpc_binding_handle *b;
3980
3981         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
3982                                           &pipe_hnd);
3983
3984         if (!NT_STATUS_IS_OK(status)) {
3985                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
3986                            nt_errstr(status)));
3987                 TALLOC_FREE(frame);
3988                 return false;
3989         }
3990
3991         b = pipe_hnd->binding_handle;
3992
3993         ZERO_STRUCT(info_ctr);
3994         ZERO_STRUCT(ctr1);
3995
3996         info_ctr.level = 1;
3997         info_ctr.ctr.ctr1 = &ctr1;
3998
3999         status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
4000                                               pipe_hnd->desthost,
4001                                               &info_ctr,
4002                                               0xffffffff,
4003                                               &total_entries,
4004                                               &resume_handle,
4005                                               &werr);
4006
4007         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4008                 TALLOC_FREE(pipe_hnd);
4009                 TALLOC_FREE(frame);
4010                 return false;
4011         }
4012
4013         for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4014                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4015                 browse_fn(info.name, info.type, info.comment, NULL);
4016         }
4017
4018         TALLOC_FREE(pipe_hnd);
4019         TALLOC_FREE(frame);
4020         return true;
4021 }
4022
4023 /****************************************************************************
4024  Try and browse available connections on a host.
4025 ****************************************************************************/
4026
4027 static bool browse_host(bool sort)
4028 {
4029         int ret;
4030         if (!grepable) {
4031                 d_printf("\n\tSharename       Type      Comment\n");
4032                 d_printf("\t---------       ----      -------\n");
4033         }
4034
4035         if (browse_host_rpc(sort)) {
4036                 return true;
4037         }
4038
4039         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
4040                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
4041
4042         return (ret != -1);
4043 }
4044
4045 /****************************************************************************
4046  List a server name.
4047 ****************************************************************************/
4048
4049 static void server_fn(const char *name, uint32 m,
4050                       const char *comment, void *state)
4051 {
4052
4053         if (!grepable){
4054                 d_printf("\t%-16s     %s\n", name, comment);
4055         } else {
4056                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
4057         }
4058 }
4059
4060 /****************************************************************************
4061  Try and browse available connections on a host.
4062 ****************************************************************************/
4063
4064 static bool list_servers(const char *wk_grp)
4065 {
4066         fstring state;
4067
4068         if (!cli->server_domain)
4069                 return false;
4070
4071         if (!grepable) {
4072                 d_printf("\n\tServer               Comment\n");
4073                 d_printf("\t---------            -------\n");
4074         };
4075         fstrcpy( state, "Server" );
4076         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
4077                           state);
4078
4079         if (!grepable) {
4080             &nb