mit-samba: Allow nesting on the event context
[idra/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
33 #ifndef REGISTER
34 #define REGISTER 0
35 #endif
36
37 extern int do_smb_browse(void); /* mDNS browsing */
38
39 extern bool override_logfile;
40 extern char tar_type;
41
42 static int port = 0;
43 static char *service;
44 static char *desthost;
45 static char *calling_name;
46 static bool grepable = false;
47 static char *cmdstr = NULL;
48 const char *cmd_ptr = NULL;
49
50 static int io_bufsize = 524288;
51
52 static int name_type = 0x20;
53 static int max_protocol = PROTOCOL_NT1;
54
55 static int process_tok(char *tok);
56 static int cmd_help(void);
57
58 #define CREATE_ACCESS_READ READ_CONTROL_ACCESS
59
60 /* 30 second timeout on most commands */
61 #define CLIENT_TIMEOUT (30*1000)
62 #define SHORT_TIMEOUT (5*1000)
63
64 /* value for unused fid field in trans2 secondary request */
65 #define FID_UNUSED (0xFFFF)
66
67 time_t newer_than = 0;
68 static int archive_level = 0;
69
70 static bool translation = false;
71 static bool have_ip;
72
73 /* clitar bits insert */
74 extern int blocksize;
75 extern bool tar_inc;
76 extern bool tar_reset;
77 /* clitar bits end */
78
79 static bool prompt = true;
80
81 static bool recurse = false;
82 static bool showacls = false;
83 bool lowercase = false;
84
85 static struct sockaddr_storage dest_ss;
86 static char dest_ss_str[INET6_ADDRSTRLEN];
87
88 #define SEPARATORS " \t\n\r"
89
90 static bool abort_mget = true;
91
92 /* timing globals */
93 uint64_t get_total_size = 0;
94 unsigned int get_total_time_ms = 0;
95 static uint64_t put_total_size = 0;
96 static unsigned int put_total_time_ms = 0;
97
98 /* totals globals */
99 static double dir_total;
100
101 /* encrypted state. */
102 static bool smb_encrypt;
103
104 /* root cli_state connection */
105
106 struct cli_state *cli;
107
108 static char CLI_DIRSEP_CHAR = '\\';
109 static char CLI_DIRSEP_STR[] = { '\\', '\0' };
110
111 /* Authentication for client connections. */
112 struct user_auth_info *auth_info;
113
114 /* Accessor functions for directory paths. */
115 static char *fileselection;
116 static const char *client_get_fileselection(void)
117 {
118         if (fileselection) {
119                 return fileselection;
120         }
121         return "";
122 }
123
124 static const char *client_set_fileselection(const char *new_fs)
125 {
126         SAFE_FREE(fileselection);
127         if (new_fs) {
128                 fileselection = SMB_STRDUP(new_fs);
129         }
130         return client_get_fileselection();
131 }
132
133 static char *cwd;
134 static const char *client_get_cwd(void)
135 {
136         if (cwd) {
137                 return cwd;
138         }
139         return CLI_DIRSEP_STR;
140 }
141
142 static const char *client_set_cwd(const char *new_cwd)
143 {
144         SAFE_FREE(cwd);
145         if (new_cwd) {
146                 cwd = SMB_STRDUP(new_cwd);
147         }
148         return client_get_cwd();
149 }
150
151 static char *cur_dir;
152 const char *client_get_cur_dir(void)
153 {
154         if (cur_dir) {
155                 return cur_dir;
156         }
157         return CLI_DIRSEP_STR;
158 }
159
160 const char *client_set_cur_dir(const char *newdir)
161 {
162         SAFE_FREE(cur_dir);
163         if (newdir) {
164                 cur_dir = SMB_STRDUP(newdir);
165         }
166         return client_get_cur_dir();
167 }
168
169 /****************************************************************************
170  Put up a yes/no prompt.
171 ****************************************************************************/
172
173 static bool yesno(const char *p)
174 {
175         char ans[20];
176         printf("%s",p);
177
178         if (!fgets(ans,sizeof(ans)-1,stdin))
179                 return(False);
180
181         if (*ans == 'y' || *ans == 'Y')
182                 return(True);
183
184         return(False);
185 }
186
187 /****************************************************************************
188  Write to a local file with CR/LF->LF translation if appropriate. Return the
189  number taken from the buffer. This may not equal the number written.
190 ****************************************************************************/
191
192 static int writefile(int f, char *b, int n)
193 {
194         int i;
195
196         if (!translation) {
197                 return write(f,b,n);
198         }
199
200         i = 0;
201         while (i < n) {
202                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
203                         b++;i++;
204                 }
205                 if (write(f, b, 1) != 1) {
206                         break;
207                 }
208                 b++;
209                 i++;
210         }
211
212         return(i);
213 }
214
215 /****************************************************************************
216  Read from a file with LF->CR/LF translation if appropriate. Return the
217  number read. read approx n bytes.
218 ****************************************************************************/
219
220 static int readfile(uint8_t *b, int n, XFILE *f)
221 {
222         int i;
223         int c;
224
225         if (!translation)
226                 return x_fread(b,1,n,f);
227
228         i = 0;
229         while (i < (n - 1) && (i < BUFFER_SIZE)) {
230                 if ((c = x_getc(f)) == EOF) {
231                         break;
232                 }
233
234                 if (c == '\n') { /* change all LFs to CR/LF */
235                         b[i++] = '\r';
236                 }
237
238                 b[i++] = c;
239         }
240
241         return(i);
242 }
243
244 struct push_state {
245         XFILE *f;
246         SMB_OFF_T nread;
247 };
248
249 static size_t push_source(uint8_t *buf, size_t n, void *priv)
250 {
251         struct push_state *state = (struct push_state *)priv;
252         int result;
253
254         if (x_feof(state->f)) {
255                 return 0;
256         }
257
258         result = readfile(buf, n, state->f);
259         state->nread += result;
260         return result;
261 }
262
263 /****************************************************************************
264  Send a message.
265 ****************************************************************************/
266
267 static void send_message(const char *username)
268 {
269         char buf[1600];
270         NTSTATUS status;
271         int i;
272
273         d_printf("Type your message, ending it with a Control-D\n");
274
275         i = 0;
276         while (i<sizeof(buf)-2) {
277                 int c = fgetc(stdin);
278                 if (c == EOF) {
279                         break;
280                 }
281                 if (c == '\n') {
282                         buf[i++] = '\r';
283                 }
284                 buf[i++] = c;
285         }
286         buf[i] = '\0';
287
288         status = cli_message(cli, desthost, username, buf);
289         if (!NT_STATUS_IS_OK(status)) {
290                 d_fprintf(stderr, "cli_message returned %s\n",
291                           nt_errstr(status));
292         }
293 }
294
295 /****************************************************************************
296  Check the space on a device.
297 ****************************************************************************/
298
299 static int do_dskattr(void)
300 {
301         int total, bsize, avail;
302         struct cli_state *targetcli = NULL;
303         char *targetpath = NULL;
304         TALLOC_CTX *ctx = talloc_tos();
305         NTSTATUS status;
306
307         if ( !cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(), &targetcli, &targetpath)) {
308                 d_printf("Error in dskattr: %s\n", cli_errstr(cli));
309                 return 1;
310         }
311
312         status = cli_dskattr(targetcli, &bsize, &total, &avail);
313         if (!NT_STATUS_IS_OK(status)) {
314                 d_printf("Error in dskattr: %s\n", nt_errstr(status));
315                 return 1;
316         }
317
318         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
319                  total, bsize, avail);
320
321         return 0;
322 }
323
324 /****************************************************************************
325  Show cd/pwd.
326 ****************************************************************************/
327
328 static int cmd_pwd(void)
329 {
330         d_printf("Current directory is %s",service);
331         d_printf("%s\n",client_get_cur_dir());
332         return 0;
333 }
334
335 /****************************************************************************
336  Ensure name has correct directory separators.
337 ****************************************************************************/
338
339 static void normalize_name(char *newdir)
340 {
341         if (!(cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP)) {
342                 string_replace(newdir,'/','\\');
343         }
344 }
345
346 /****************************************************************************
347  Change directory - inner section.
348 ****************************************************************************/
349
350 static int do_cd(const char *new_dir)
351 {
352         char *newdir = NULL;
353         char *saved_dir = NULL;
354         char *new_cd = NULL;
355         char *targetpath = NULL;
356         struct cli_state *targetcli = NULL;
357         SMB_STRUCT_STAT sbuf;
358         uint32 attributes;
359         int ret = 1;
360         TALLOC_CTX *ctx = talloc_stackframe();
361
362         newdir = talloc_strdup(ctx, new_dir);
363         if (!newdir) {
364                 TALLOC_FREE(ctx);
365                 return 1;
366         }
367
368         normalize_name(newdir);
369
370         /* Save the current directory in case the new directory is invalid */
371
372         saved_dir = talloc_strdup(ctx, client_get_cur_dir());
373         if (!saved_dir) {
374                 TALLOC_FREE(ctx);
375                 return 1;
376         }
377
378         if (*newdir == CLI_DIRSEP_CHAR) {
379                 client_set_cur_dir(newdir);
380                 new_cd = newdir;
381         } else {
382                 new_cd = talloc_asprintf(ctx, "%s%s",
383                                 client_get_cur_dir(),
384                                 newdir);
385                 if (!new_cd) {
386                         goto out;
387                 }
388         }
389
390         /* Ensure cur_dir ends in a DIRSEP */
391         if ((new_cd[0] != '\0') && (*(new_cd+strlen(new_cd)-1) != CLI_DIRSEP_CHAR)) {
392                 new_cd = talloc_asprintf_append(new_cd, "%s", CLI_DIRSEP_STR);
393                 if (!new_cd) {
394                         goto out;
395                 }
396         }
397         client_set_cur_dir(new_cd);
398
399         new_cd = clean_name(ctx, new_cd);
400         client_set_cur_dir(new_cd);
401
402         if ( !cli_resolve_path(ctx, "", auth_info, cli, new_cd, &targetcli, &targetpath)) {
403                 d_printf("cd %s: %s\n", new_cd, cli_errstr(cli));
404                 client_set_cur_dir(saved_dir);
405                 goto out;
406         }
407
408         if (strequal(targetpath,CLI_DIRSEP_STR )) {
409                 TALLOC_FREE(ctx);
410                 return 0;
411         }
412
413         /* Use a trans2_qpathinfo to test directories for modern servers.
414            Except Win9x doesn't support the qpathinfo_basic() call..... */
415
416         if (targetcli->protocol > PROTOCOL_LANMAN2 && !targetcli->win95) {
417                 NTSTATUS status;
418
419                 status = cli_qpathinfo_basic(targetcli, targetpath, &sbuf,
420                                              &attributes);
421                 if (!NT_STATUS_IS_OK(status)) {
422                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
423                         client_set_cur_dir(saved_dir);
424                         goto out;
425                 }
426
427                 if (!(attributes & FILE_ATTRIBUTE_DIRECTORY)) {
428                         d_printf("cd %s: not a directory\n", new_cd);
429                         client_set_cur_dir(saved_dir);
430                         goto out;
431                 }
432         } else {
433                 NTSTATUS status;
434
435                 targetpath = talloc_asprintf(ctx,
436                                 "%s%s",
437                                 targetpath,
438                                 CLI_DIRSEP_STR );
439                 if (!targetpath) {
440                         client_set_cur_dir(saved_dir);
441                         goto out;
442                 }
443                 targetpath = clean_name(ctx, targetpath);
444                 if (!targetpath) {
445                         client_set_cur_dir(saved_dir);
446                         goto out;
447                 }
448
449                 status = cli_chkpath(targetcli, targetpath);
450                 if (!NT_STATUS_IS_OK(status)) {
451                         d_printf("cd %s: %s\n", new_cd, nt_errstr(status));
452                         client_set_cur_dir(saved_dir);
453                         goto out;
454                 }
455         }
456
457         ret = 0;
458
459 out:
460
461         TALLOC_FREE(ctx);
462         return ret;
463 }
464
465 /****************************************************************************
466  Change directory.
467 ****************************************************************************/
468
469 static int cmd_cd(void)
470 {
471         char *buf = NULL;
472         int rc = 0;
473
474         if (next_token_talloc(talloc_tos(), &cmd_ptr, &buf,NULL)) {
475                 rc = do_cd(buf);
476         } else {
477                 d_printf("Current directory is %s\n",client_get_cur_dir());
478         }
479
480         return rc;
481 }
482
483 /****************************************************************************
484  Change directory.
485 ****************************************************************************/
486
487 static int cmd_cd_oneup(void)
488 {
489         return do_cd("..");
490 }
491
492 /*******************************************************************
493  Decide if a file should be operated on.
494 ********************************************************************/
495
496 static bool do_this_one(struct file_info *finfo)
497 {
498         if (!finfo->name) {
499                 return false;
500         }
501
502         if (finfo->mode & aDIR) {
503                 return true;
504         }
505
506         if (*client_get_fileselection() &&
507             !mask_match(finfo->name,client_get_fileselection(),false)) {
508                 DEBUG(3,("mask_match %s failed\n", finfo->name));
509                 return false;
510         }
511
512         if (newer_than && finfo->mtime_ts.tv_sec < newer_than) {
513                 DEBUG(3,("newer_than %s failed\n", finfo->name));
514                 return false;
515         }
516
517         if ((archive_level==1 || archive_level==2) && !(finfo->mode & aARCH)) {
518                 DEBUG(3,("archive %s failed\n", finfo->name));
519                 return false;
520         }
521
522         return true;
523 }
524
525 /****************************************************************************
526  Display info about a file.
527 ****************************************************************************/
528
529 static NTSTATUS display_finfo(struct cli_state *cli_state, struct file_info *finfo,
530                           const char *dir)
531 {
532         time_t t;
533         TALLOC_CTX *ctx = talloc_tos();
534         NTSTATUS status = NT_STATUS_OK;
535
536         if (!do_this_one(finfo)) {
537                 return NT_STATUS_OK;
538         }
539
540         t = finfo->mtime_ts.tv_sec; /* the time is assumed to be passed as GMT */
541         if (!showacls) {
542                 d_printf("  %-30s%7.7s %8.0f  %s",
543                          finfo->name,
544                          attrib_string(finfo->mode),
545                         (double)finfo->size,
546                         time_to_asc(t));
547                 dir_total += finfo->size;
548         } else {
549                 char *afname = NULL;
550                 uint16_t fnum;
551
552                 /* skip if this is . or .. */
553                 if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
554                         return NT_STATUS_OK;
555                 /* create absolute filename for cli_ntcreate() FIXME */
556                 afname = talloc_asprintf(ctx,
557                                         "%s%s%s",
558                                         dir,
559                                         CLI_DIRSEP_STR,
560                                         finfo->name);
561                 if (!afname) {
562                         return NT_STATUS_NO_MEMORY;
563                 }
564                 /* print file meta date header */
565                 d_printf( "FILENAME:%s\n", finfo->name);
566                 d_printf( "MODE:%s\n", attrib_string(finfo->mode));
567                 d_printf( "SIZE:%.0f\n", (double)finfo->size);
568                 d_printf( "MTIME:%s", time_to_asc(t));
569                 status = cli_ntcreate(cli_state, afname, 0,
570                                       CREATE_ACCESS_READ, 0,
571                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
572                                       FILE_OPEN, 0x0, 0x0, &fnum);
573                 if (!NT_STATUS_IS_OK(status)) {
574                         DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
575                                    afname, nt_errstr(status)));
576                 } else {
577                         struct security_descriptor *sd = NULL;
578                         sd = cli_query_secdesc(cli_state, fnum, ctx);
579                         if (!sd) {
580                                 DEBUG( 0, ("display_finfo() failed to "
581                                         "get security descriptor: %s",
582                                         cli_errstr(cli_state)));
583                                 status = cli_nt_error(cli_state);
584                         } else {
585                                 display_sec_desc(sd);
586                         }
587                         TALLOC_FREE(sd);
588                 }
589                 TALLOC_FREE(afname);
590         }
591         return status;
592 }
593
594 /****************************************************************************
595  Accumulate size of a file.
596 ****************************************************************************/
597
598 static NTSTATUS do_du(struct cli_state *cli_state, struct file_info *finfo,
599                   const char *dir)
600 {
601         if (do_this_one(finfo)) {
602                 dir_total += finfo->size;
603         }
604         return NT_STATUS_OK;
605 }
606
607 static bool do_list_recurse;
608 static bool do_list_dirs;
609 static char *do_list_queue = 0;
610 static long do_list_queue_size = 0;
611 static long do_list_queue_start = 0;
612 static long do_list_queue_end = 0;
613 static NTSTATUS (*do_list_fn)(struct cli_state *cli_state, struct file_info *,
614                           const char *dir);
615
616 /****************************************************************************
617  Functions for do_list_queue.
618 ****************************************************************************/
619
620 /*
621  * The do_list_queue is a NUL-separated list of strings stored in a
622  * char*.  Since this is a FIFO, we keep track of the beginning and
623  * ending locations of the data in the queue.  When we overflow, we
624  * double the size of the char*.  When the start of the data passes
625  * the midpoint, we move everything back.  This is logically more
626  * complex than a linked list, but easier from a memory management
627  * angle.  In any memory error condition, do_list_queue is reset.
628  * Functions check to ensure that do_list_queue is non-NULL before
629  * accessing it.
630  */
631
632 static void reset_do_list_queue(void)
633 {
634         SAFE_FREE(do_list_queue);
635         do_list_queue_size = 0;
636         do_list_queue_start = 0;
637         do_list_queue_end = 0;
638 }
639
640 static void init_do_list_queue(void)
641 {
642         reset_do_list_queue();
643         do_list_queue_size = 1024;
644         do_list_queue = (char *)SMB_MALLOC(do_list_queue_size);
645         if (do_list_queue == 0) {
646                 d_printf("malloc fail for size %d\n",
647                          (int)do_list_queue_size);
648                 reset_do_list_queue();
649         } else {
650                 memset(do_list_queue, 0, do_list_queue_size);
651         }
652 }
653
654 static void adjust_do_list_queue(void)
655 {
656         /*
657          * If the starting point of the queue is more than half way through,
658          * move everything toward the beginning.
659          */
660
661         if (do_list_queue == NULL) {
662                 DEBUG(4,("do_list_queue is empty\n"));
663                 do_list_queue_start = do_list_queue_end = 0;
664                 return;
665         }
666
667         if (do_list_queue_start == do_list_queue_end) {
668                 DEBUG(4,("do_list_queue is empty\n"));
669                 do_list_queue_start = do_list_queue_end = 0;
670                 *do_list_queue = '\0';
671         } else if (do_list_queue_start > (do_list_queue_size / 2)) {
672                 DEBUG(4,("sliding do_list_queue backward\n"));
673                 memmove(do_list_queue,
674                         do_list_queue + do_list_queue_start,
675                         do_list_queue_end - do_list_queue_start);
676                 do_list_queue_end -= do_list_queue_start;
677                 do_list_queue_start = 0;
678         }
679 }
680
681 static void add_to_do_list_queue(const char *entry)
682 {
683         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
684         while (new_end > do_list_queue_size) {
685                 do_list_queue_size *= 2;
686                 DEBUG(4,("enlarging do_list_queue to %d\n",
687                          (int)do_list_queue_size));
688                 do_list_queue = (char *)SMB_REALLOC(do_list_queue, do_list_queue_size);
689                 if (! do_list_queue) {
690                         d_printf("failure enlarging do_list_queue to %d bytes\n",
691                                  (int)do_list_queue_size);
692                         reset_do_list_queue();
693                 } else {
694                         memset(do_list_queue + do_list_queue_size / 2,
695                                0, do_list_queue_size / 2);
696                 }
697         }
698         if (do_list_queue) {
699                 safe_strcpy_base(do_list_queue + do_list_queue_end,
700                                  entry, do_list_queue, do_list_queue_size);
701                 do_list_queue_end = new_end;
702                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
703                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
704         }
705 }
706
707 static char *do_list_queue_head(void)
708 {
709         return do_list_queue + do_list_queue_start;
710 }
711
712 static void remove_do_list_queue_head(void)
713 {
714         if (do_list_queue_end > do_list_queue_start) {
715                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
716                 adjust_do_list_queue();
717                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
718                          (int)do_list_queue_start, (int)do_list_queue_end));
719         }
720 }
721
722 static int do_list_queue_empty(void)
723 {
724         return (! (do_list_queue && *do_list_queue));
725 }
726
727 /****************************************************************************
728  A helper for do_list.
729 ****************************************************************************/
730
731 static NTSTATUS do_list_helper(const char *mntpoint, struct file_info *f,
732                            const char *mask, void *state)
733 {
734         struct cli_state *cli_state = (struct cli_state *)state;
735         TALLOC_CTX *ctx = talloc_tos();
736         char *dir = NULL;
737         char *dir_end = NULL;
738         NTSTATUS status = NT_STATUS_OK;
739
740         /* Work out the directory. */
741         dir = talloc_strdup(ctx, mask);
742         if (!dir) {
743                 return NT_STATUS_NO_MEMORY;
744         }
745         if ((dir_end = strrchr(dir, CLI_DIRSEP_CHAR)) != NULL) {
746                 *dir_end = '\0';
747         }
748
749         if (f->mode & aDIR) {
750                 if (do_list_dirs && do_this_one(f)) {
751                         status = do_list_fn(cli_state, f, dir);
752                         if (!NT_STATUS_IS_OK(status)) {
753                                 return status;
754                         }
755                 }
756                 if (do_list_recurse &&
757                     f->name &&
758                     !strequal(f->name,".") &&
759                     !strequal(f->name,"..")) {
760                         char *mask2 = NULL;
761                         char *p = NULL;
762
763                         if (!f->name[0]) {
764                                 d_printf("Empty dir name returned. Possible server misconfiguration.\n");
765                                 TALLOC_FREE(dir);
766                                 return NT_STATUS_UNSUCCESSFUL;
767                         }
768
769                         mask2 = talloc_asprintf(ctx,
770                                         "%s%s",
771                                         mntpoint,
772                                         mask);
773                         if (!mask2) {
774                                 TALLOC_FREE(dir);
775                                 return NT_STATUS_NO_MEMORY;
776                         }
777                         p = strrchr_m(mask2,CLI_DIRSEP_CHAR);
778                         if (p) {
779                                 p[1] = 0;
780                         } else {
781                                 mask2[0] = '\0';
782                         }
783                         mask2 = talloc_asprintf_append(mask2,
784                                         "%s%s*",
785                                         f->name,
786                                         CLI_DIRSEP_STR);
787                         if (!mask2) {
788                                 TALLOC_FREE(dir);
789                                 return NT_STATUS_NO_MEMORY;
790                         }
791                         add_to_do_list_queue(mask2);
792                         TALLOC_FREE(mask2);
793                 }
794                 TALLOC_FREE(dir);
795                 return NT_STATUS_OK;
796         }
797
798         if (do_this_one(f)) {
799                 status = do_list_fn(cli_state, f, dir);
800         }
801         TALLOC_FREE(dir);
802         return status;
803 }
804
805 /****************************************************************************
806  A wrapper around cli_list that adds recursion.
807 ****************************************************************************/
808
809 NTSTATUS do_list(const char *mask,
810                         uint16 attribute,
811                         NTSTATUS (*fn)(struct cli_state *cli_state, struct file_info *,
812                                    const char *dir),
813                         bool rec,
814                         bool dirs)
815 {
816         static int in_do_list = 0;
817         TALLOC_CTX *ctx = talloc_tos();
818         struct cli_state *targetcli = NULL;
819         char *targetpath = NULL;
820         NTSTATUS ret_status = NT_STATUS_OK;
821         NTSTATUS status = NT_STATUS_OK;
822
823         if (in_do_list && rec) {
824                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
825                 exit(1);
826         }
827
828         in_do_list = 1;
829
830         do_list_recurse = rec;
831         do_list_dirs = dirs;
832         do_list_fn = fn;
833
834         if (rec) {
835                 init_do_list_queue();
836                 add_to_do_list_queue(mask);
837
838                 while (!do_list_queue_empty()) {
839                         /*
840                          * Need to copy head so that it doesn't become
841                          * invalid inside the call to cli_list.  This
842                          * would happen if the list were expanded
843                          * during the call.
844                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
845                          */
846                         char *head = talloc_strdup(ctx, do_list_queue_head());
847
848                         if (!head) {
849                                 return NT_STATUS_NO_MEMORY;
850                         }
851
852                         /* check for dfs */
853
854                         if ( !cli_resolve_path(ctx, "", auth_info, cli, head, &targetcli, &targetpath ) ) {
855                                 d_printf("do_list: [%s] %s\n", head, cli_errstr(cli));
856                                 remove_do_list_queue_head();
857                                 continue;
858                         }
859
860                         status = cli_list(targetcli, targetpath, attribute,
861                                  do_list_helper, targetcli);
862                         if (!NT_STATUS_IS_OK(status)) {
863                                 d_printf("%s listing %s\n",
864                                          nt_errstr(status), targetpath);
865                                 ret_status = status;
866                         }
867                         remove_do_list_queue_head();
868                         if ((! do_list_queue_empty()) && (fn == display_finfo)) {
869                                 char *next_file = do_list_queue_head();
870                                 char *save_ch = 0;
871                                 if ((strlen(next_file) >= 2) &&
872                                     (next_file[strlen(next_file) - 1] == '*') &&
873                                     (next_file[strlen(next_file) - 2] == CLI_DIRSEP_CHAR)) {
874                                         save_ch = next_file +
875                                                 strlen(next_file) - 2;
876                                         *save_ch = '\0';
877                                         if (showacls) {
878                                                 /* cwd is only used if showacls is on */
879                                                 client_set_cwd(next_file);
880                                         }
881                                 }
882                                 if (!showacls) /* don't disturbe the showacls output */
883                                         d_printf("\n%s\n",next_file);
884                                 if (save_ch) {
885                                         *save_ch = CLI_DIRSEP_CHAR;
886                                 }
887                         }
888                         TALLOC_FREE(head);
889                         TALLOC_FREE(targetpath);
890                 }
891         } else {
892                 /* check for dfs */
893                 if (cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetpath)) {
894
895                         status = cli_list(targetcli, targetpath, attribute,
896                                           do_list_helper, targetcli);
897                         if (!NT_STATUS_IS_OK(status)) {
898                                 d_printf("%s listing %s\n",
899                                          nt_errstr(status), targetpath);
900                                 ret_status = status;
901                         }
902                         TALLOC_FREE(targetpath);
903                 } else {
904                         d_printf("do_list: [%s] %s\n", mask, cli_errstr(cli));
905                         ret_status = cli_nt_error(cli);
906                 }
907         }
908
909         in_do_list = 0;
910         reset_do_list_queue();
911         return ret_status;
912 }
913
914 /****************************************************************************
915  Get a directory listing.
916 ****************************************************************************/
917
918 static int cmd_dir(void)
919 {
920         TALLOC_CTX *ctx = talloc_tos();
921         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
922         char *mask = NULL;
923         char *buf = NULL;
924         int rc = 1;
925         NTSTATUS status;
926
927         dir_total = 0;
928         mask = talloc_strdup(ctx, client_get_cur_dir());
929         if (!mask) {
930                 return 1;
931         }
932
933         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
934                 normalize_name(buf);
935                 if (*buf == CLI_DIRSEP_CHAR) {
936                         mask = talloc_strdup(ctx, buf);
937                 } else {
938                         mask = talloc_asprintf_append(mask, "%s", buf);
939                 }
940         } else {
941                 mask = talloc_asprintf_append(mask, "*");
942         }
943         if (!mask) {
944                 return 1;
945         }
946
947         if (showacls) {
948                 /* cwd is only used if showacls is on */
949                 client_set_cwd(client_get_cur_dir());
950         }
951
952         status = do_list(mask, attribute, display_finfo, recurse, true);
953         if (!NT_STATUS_IS_OK(status)) {
954                 return 1;
955         }
956
957         rc = do_dskattr();
958
959         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
960
961         return rc;
962 }
963
964 /****************************************************************************
965  Get a directory listing.
966 ****************************************************************************/
967
968 static int cmd_du(void)
969 {
970         TALLOC_CTX *ctx = talloc_tos();
971         uint16 attribute = aDIR | aSYSTEM | aHIDDEN;
972         char *mask = NULL;
973         char *buf = NULL;
974         NTSTATUS status;
975         int rc = 1;
976
977         dir_total = 0;
978         mask = talloc_strdup(ctx, client_get_cur_dir());
979         if (!mask) {
980                 return 1;
981         }
982         if ((mask[0] != '\0') && (mask[strlen(mask)-1]!=CLI_DIRSEP_CHAR)) {
983                 mask = talloc_asprintf_append(mask, "%s", CLI_DIRSEP_STR);
984                 if (!mask) {
985                         return 1;
986                 }
987         }
988
989         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
990                 normalize_name(buf);
991                 if (*buf == CLI_DIRSEP_CHAR) {
992                         mask = talloc_strdup(ctx, buf);
993                 } else {
994                         mask = talloc_asprintf_append(mask, "%s", buf);
995                 }
996         } else {
997                 mask = talloc_strdup(ctx, "*");
998         }
999
1000         status = do_list(mask, attribute, do_du, recurse, true);
1001         if (!NT_STATUS_IS_OK(status)) {
1002                 return 1;
1003         }
1004
1005         rc = do_dskattr();
1006
1007         d_printf("Total number of bytes: %.0f\n", dir_total);
1008
1009         return rc;
1010 }
1011
1012 static int cmd_echo(void)
1013 {
1014         TALLOC_CTX *ctx = talloc_tos();
1015         char *num;
1016         char *data;
1017         NTSTATUS status;
1018
1019         if (!next_token_talloc(ctx, &cmd_ptr, &num, NULL)
1020             || !next_token_talloc(ctx, &cmd_ptr, &data, NULL)) {
1021                 d_printf("echo <num> <data>\n");
1022                 return 1;
1023         }
1024
1025         status = cli_echo(cli, atoi(num), data_blob_const(data, strlen(data)));
1026
1027         if (!NT_STATUS_IS_OK(status)) {
1028                 d_printf("echo failed: %s\n", nt_errstr(status));
1029                 return 1;
1030         }
1031
1032         return 0;
1033 }
1034
1035 /****************************************************************************
1036  Get a file from rname to lname
1037 ****************************************************************************/
1038
1039 static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
1040 {
1041         int *pfd = (int *)priv;
1042         if (writefile(*pfd, buf, n) == -1) {
1043                 return map_nt_error_from_unix(errno);
1044         }
1045         return NT_STATUS_OK;
1046 }
1047
1048 static int do_get(const char *rname, const char *lname_in, bool reget)
1049 {
1050         TALLOC_CTX *ctx = talloc_tos();
1051         int handle = 0;
1052         uint16_t fnum;
1053         bool newhandle = false;
1054         struct timespec tp_start;
1055         uint16 attr;
1056         SMB_OFF_T size;
1057         off_t start = 0;
1058         SMB_OFF_T nread = 0;
1059         int rc = 0;
1060         struct cli_state *targetcli = NULL;
1061         char *targetname = NULL;
1062         char *lname = NULL;
1063         NTSTATUS status;
1064
1065         lname = talloc_strdup(ctx, lname_in);
1066         if (!lname) {
1067                 return 1;
1068         }
1069
1070         if (lowercase) {
1071                 strlower_m(lname);
1072         }
1073
1074         if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname ) ) {
1075                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1076                 return 1;
1077         }
1078
1079         clock_gettime_mono(&tp_start);
1080
1081         status = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum);
1082         if (!NT_STATUS_IS_OK(status)) {
1083                 d_printf("%s opening remote file %s\n", nt_errstr(status),
1084                          rname);
1085                 return 1;
1086         }
1087
1088         if(!strcmp(lname,"-")) {
1089                 handle = fileno(stdout);
1090         } else {
1091                 if (reget) {
1092                         handle = sys_open(lname, O_WRONLY|O_CREAT, 0644);
1093                         if (handle >= 0) {
1094                                 start = sys_lseek(handle, 0, SEEK_END);
1095                                 if (start == -1) {
1096                                         d_printf("Error seeking local file\n");
1097                                         return 1;
1098                                 }
1099                         }
1100                 } else {
1101                         handle = sys_open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
1102                 }
1103                 newhandle = true;
1104         }
1105         if (handle < 0) {
1106                 d_printf("Error opening local file %s\n",lname);
1107                 return 1;
1108         }
1109
1110
1111         status = cli_qfileinfo_basic(targetcli, fnum, &attr, &size, NULL, NULL,
1112                                      NULL, NULL, NULL);
1113         if (!NT_STATUS_IS_OK(status)) {
1114                 status = cli_getattrE(targetcli, fnum, &attr, &size, NULL, NULL,
1115                                       NULL);
1116                 if(!NT_STATUS_IS_OK(status)) {
1117                         d_printf("getattrib: %s\n", nt_errstr(status));
1118                         return 1;
1119                 }
1120         }
1121
1122         DEBUG(1,("getting file %s of size %.0f as %s ",
1123                  rname, (double)size, lname));
1124
1125         status = cli_pull(targetcli, fnum, start, size, io_bufsize,
1126                           writefile_sink, (void *)&handle, &nread);
1127         if (!NT_STATUS_IS_OK(status)) {
1128                 d_fprintf(stderr, "parallel_read returned %s\n",
1129                           nt_errstr(status));
1130                 cli_close(targetcli, fnum);
1131                 return 1;
1132         }
1133
1134         status = cli_close(targetcli, fnum);
1135         if (!NT_STATUS_IS_OK(status)) {
1136                 d_printf("Error %s closing remote file\n", nt_errstr(status));
1137                 rc = 1;
1138         }
1139
1140         if (newhandle) {
1141                 close(handle);
1142         }
1143
1144         if (archive_level >= 2 && (attr & aARCH)) {
1145                 cli_setatr(cli, rname, attr & ~(uint16)aARCH, 0);
1146         }
1147
1148         {
1149                 struct timespec tp_end;
1150                 int this_time;
1151
1152                 clock_gettime_mono(&tp_end);
1153                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1154                 get_total_time_ms += this_time;
1155                 get_total_size += nread;
1156
1157                 DEBUG(1,("(%3.1f KiloBytes/sec) (average %3.1f KiloBytes/sec)\n",
1158                          nread / (1.024*this_time + 1.0e-4),
1159                          get_total_size / (1.024*get_total_time_ms)));
1160         }
1161
1162         TALLOC_FREE(targetname);
1163         return rc;
1164 }
1165
1166 /****************************************************************************
1167  Get a file.
1168 ****************************************************************************/
1169
1170 static int cmd_get(void)
1171 {
1172         TALLOC_CTX *ctx = talloc_tos();
1173         char *lname = NULL;
1174         char *rname = NULL;
1175         char *fname = NULL;
1176
1177         rname = talloc_strdup(ctx, client_get_cur_dir());
1178         if (!rname) {
1179                 return 1;
1180         }
1181
1182         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1183                 d_printf("get <filename> [localname]\n");
1184                 return 1;
1185         }
1186         rname = talloc_asprintf_append(rname, "%s", fname);
1187         if (!rname) {
1188                 return 1;
1189         }
1190         rname = clean_name(ctx, rname);
1191         if (!rname) {
1192                 return 1;
1193         }
1194
1195         next_token_talloc(ctx, &cmd_ptr,&lname,NULL);
1196         if (!lname) {
1197                 lname = fname;
1198         }
1199
1200         return do_get(rname, lname, false);
1201 }
1202
1203 /****************************************************************************
1204  Do an mget operation on one file.
1205 ****************************************************************************/
1206
1207 static NTSTATUS do_mget(struct cli_state *cli_state, struct file_info *finfo,
1208                     const char *dir)
1209 {
1210         TALLOC_CTX *ctx = talloc_tos();
1211         NTSTATUS status = NT_STATUS_OK;
1212         char *rname = NULL;
1213         char *quest = NULL;
1214         char *saved_curdir = NULL;
1215         char *mget_mask = NULL;
1216         char *new_cd = NULL;
1217
1218         if (!finfo->name) {
1219                 return NT_STATUS_OK;
1220         }
1221
1222         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
1223                 return NT_STATUS_OK;
1224
1225         if (abort_mget) {
1226                 d_printf("mget aborted\n");
1227                 return NT_STATUS_UNSUCCESSFUL;
1228         }
1229
1230         if (finfo->mode & aDIR) {
1231                 if (asprintf(&quest,
1232                          "Get directory %s? ",finfo->name) < 0) {
1233                         return NT_STATUS_NO_MEMORY;
1234                 }
1235         } else {
1236                 if (asprintf(&quest,
1237                          "Get file %s? ",finfo->name) < 0) {
1238                         return NT_STATUS_NO_MEMORY;
1239                 }
1240         }
1241
1242         if (prompt && !yesno(quest)) {
1243                 SAFE_FREE(quest);
1244                 return NT_STATUS_OK;
1245         }
1246         SAFE_FREE(quest);
1247
1248         if (!(finfo->mode & aDIR)) {
1249                 rname = talloc_asprintf(ctx,
1250                                 "%s%s",
1251                                 client_get_cur_dir(),
1252                                 finfo->name);
1253                 if (!rname) {
1254                         return NT_STATUS_NO_MEMORY;
1255                 }
1256                 do_get(rname, finfo->name, false);
1257                 TALLOC_FREE(rname);
1258                 return NT_STATUS_OK;
1259         }
1260
1261         /* handle directories */
1262         saved_curdir = talloc_strdup(ctx, client_get_cur_dir());
1263         if (!saved_curdir) {
1264                 return NT_STATUS_NO_MEMORY;
1265         }
1266
1267         new_cd = talloc_asprintf(ctx,
1268                                 "%s%s%s",
1269                                 client_get_cur_dir(),
1270                                 finfo->name,
1271                                 CLI_DIRSEP_STR);
1272         if (!new_cd) {
1273                 return NT_STATUS_NO_MEMORY;
1274         }
1275         client_set_cur_dir(new_cd);
1276
1277         string_replace(finfo->name,'\\','/');
1278         if (lowercase) {
1279                 strlower_m(finfo->name);
1280         }
1281
1282         if (!directory_exist(finfo->name) &&
1283             mkdir(finfo->name,0777) != 0) {
1284                 d_printf("failed to create directory %s\n",finfo->name);
1285                 client_set_cur_dir(saved_curdir);
1286                 return map_nt_error_from_unix(errno);
1287         }
1288
1289         if (chdir(finfo->name) != 0) {
1290                 d_printf("failed to chdir to directory %s\n",finfo->name);
1291                 client_set_cur_dir(saved_curdir);
1292                 return map_nt_error_from_unix(errno);
1293         }
1294
1295         mget_mask = talloc_asprintf(ctx,
1296                         "%s*",
1297                         client_get_cur_dir());
1298
1299         if (!mget_mask) {
1300                 return NT_STATUS_NO_MEMORY;
1301         }
1302
1303         status = do_list(mget_mask, aSYSTEM | aHIDDEN | aDIR,do_mget,false, true);
1304         if (!NT_STATUS_IS_OK(status)) {
1305                 return status;
1306         }
1307
1308         if (chdir("..") == -1) {
1309                 d_printf("do_mget: failed to chdir to .. (error %s)\n",
1310                         strerror(errno) );
1311                 return map_nt_error_from_unix(errno);
1312         }
1313         client_set_cur_dir(saved_curdir);
1314         TALLOC_FREE(mget_mask);
1315         TALLOC_FREE(saved_curdir);
1316         TALLOC_FREE(new_cd);
1317         return NT_STATUS_OK;
1318 }
1319
1320 /****************************************************************************
1321  View the file using the pager.
1322 ****************************************************************************/
1323
1324 static int cmd_more(void)
1325 {
1326         TALLOC_CTX *ctx = talloc_tos();
1327         char *rname = NULL;
1328         char *fname = NULL;
1329         char *lname = NULL;
1330         char *pager_cmd = NULL;
1331         const char *pager;
1332         int fd;
1333         int rc = 0;
1334
1335         rname = talloc_strdup(ctx, client_get_cur_dir());
1336         if (!rname) {
1337                 return 1;
1338         }
1339
1340         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
1341         if (!lname) {
1342                 return 1;
1343         }
1344         fd = mkstemp(lname);
1345         if (fd == -1) {
1346                 d_printf("failed to create temporary file for more\n");
1347                 return 1;
1348         }
1349         close(fd);
1350
1351         if (!next_token_talloc(ctx, &cmd_ptr,&fname,NULL)) {
1352                 d_printf("more <filename>\n");
1353                 unlink(lname);
1354                 return 1;
1355         }
1356         rname = talloc_asprintf_append(rname, "%s", fname);
1357         if (!rname) {
1358                 return 1;
1359         }
1360         rname = clean_name(ctx,rname);
1361         if (!rname) {
1362                 return 1;
1363         }
1364
1365         rc = do_get(rname, lname, false);
1366
1367         pager=getenv("PAGER");
1368
1369         pager_cmd = talloc_asprintf(ctx,
1370                                 "%s %s",
1371                                 (pager? pager:PAGER),
1372                                 lname);
1373         if (!pager_cmd) {
1374                 return 1;
1375         }
1376         if (system(pager_cmd) == -1) {
1377                 d_printf("system command '%s' returned -1\n",
1378                         pager_cmd);
1379         }
1380         unlink(lname);
1381
1382         return rc;
1383 }
1384
1385 /****************************************************************************
1386  Do a mget command.
1387 ****************************************************************************/
1388
1389 static int cmd_mget(void)
1390 {
1391         TALLOC_CTX *ctx = talloc_tos();
1392         uint16 attribute = aSYSTEM | aHIDDEN;
1393         char *mget_mask = NULL;
1394         char *buf = NULL;
1395         NTSTATUS status = NT_STATUS_OK;
1396
1397         if (recurse) {
1398                 attribute |= aDIR;
1399         }
1400
1401         abort_mget = false;
1402
1403         while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1404
1405                 mget_mask = talloc_strdup(ctx, client_get_cur_dir());
1406                 if (!mget_mask) {
1407                         return 1;
1408                 }
1409                 if (*buf == CLI_DIRSEP_CHAR) {
1410                         mget_mask = talloc_strdup(ctx, buf);
1411                 } else {
1412                         mget_mask = talloc_asprintf_append(mget_mask,
1413                                                         "%s", buf);
1414                 }
1415                 if (!mget_mask) {
1416                         return 1;
1417                 }
1418                 status = do_list(mget_mask, attribute, do_mget, false, true);
1419                 if (!NT_STATUS_IS_OK(status)) {
1420                         return 1;
1421                 }
1422         }
1423
1424         if (mget_mask == NULL) {
1425                 d_printf("nothing to mget\n");
1426                 return 0;
1427         }
1428
1429         if (!*mget_mask) {
1430                 mget_mask = talloc_asprintf(ctx,
1431                                         "%s*",
1432                                         client_get_cur_dir());
1433                 if (!mget_mask) {
1434                         return 1;
1435                 }
1436                 status = do_list(mget_mask, attribute, do_mget, false, true);
1437                 if (!NT_STATUS_IS_OK(status)) {
1438                         return 1;
1439                 }
1440         }
1441
1442         return 0;
1443 }
1444
1445 /****************************************************************************
1446  Make a directory of name "name".
1447 ****************************************************************************/
1448
1449 static bool do_mkdir(const char *name)
1450 {
1451         TALLOC_CTX *ctx = talloc_tos();
1452         struct cli_state *targetcli;
1453         char *targetname = NULL;
1454         NTSTATUS status;
1455
1456         if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
1457                 d_printf("mkdir %s: %s\n", name, cli_errstr(cli));
1458                 return false;
1459         }
1460
1461         status = cli_mkdir(targetcli, targetname);
1462         if (!NT_STATUS_IS_OK(status)) {
1463                 d_printf("%s making remote directory %s\n",
1464                          nt_errstr(status),name);
1465                 return false;
1466         }
1467
1468         return true;
1469 }
1470
1471 /****************************************************************************
1472  Show 8.3 name of a file.
1473 ****************************************************************************/
1474
1475 static bool do_altname(const char *name)
1476 {
1477         fstring altname;
1478         NTSTATUS status;
1479
1480         status = cli_qpathinfo_alt_name(cli, name, altname);
1481         if (!NT_STATUS_IS_OK(status)) {
1482                 d_printf("%s getting alt name for %s\n",
1483                          nt_errstr(status),name);
1484                 return false;
1485         }
1486         d_printf("%s\n", altname);
1487
1488         return true;
1489 }
1490
1491 /****************************************************************************
1492  Exit client.
1493 ****************************************************************************/
1494
1495 static int cmd_quit(void)
1496 {
1497         cli_shutdown(cli);
1498         exit(0);
1499         /* NOTREACHED */
1500         return 0;
1501 }
1502
1503 /****************************************************************************
1504  Make a directory.
1505 ****************************************************************************/
1506
1507 static int cmd_mkdir(void)
1508 {
1509         TALLOC_CTX *ctx = talloc_tos();
1510         char *mask = NULL;
1511         char *buf = NULL;
1512
1513         mask = talloc_strdup(ctx, client_get_cur_dir());
1514         if (!mask) {
1515                 return 1;
1516         }
1517
1518         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1519                 if (!recurse) {
1520                         d_printf("mkdir <dirname>\n");
1521                 }
1522                 return 1;
1523         }
1524         mask = talloc_asprintf_append(mask, "%s", buf);
1525         if (!mask) {
1526                 return 1;
1527         }
1528
1529         if (recurse) {
1530                 char *ddir = NULL;
1531                 char *ddir2 = NULL;
1532                 struct cli_state *targetcli;
1533                 char *targetname = NULL;
1534                 char *p = NULL;
1535                 char *saveptr;
1536
1537                 ddir2 = talloc_strdup(ctx, "");
1538                 if (!ddir2) {
1539                         return 1;
1540                 }
1541
1542                 if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
1543                         return 1;
1544                 }
1545
1546                 ddir = talloc_strdup(ctx, targetname);
1547                 if (!ddir) {
1548                         return 1;
1549                 }
1550                 trim_char(ddir,'.','\0');
1551                 p = strtok_r(ddir, "/\\", &saveptr);
1552                 while (p) {
1553                         ddir2 = talloc_asprintf_append(ddir2, "%s", p);
1554                         if (!ddir2) {
1555                                 return 1;
1556                         }
1557                         if (!NT_STATUS_IS_OK(cli_chkpath(targetcli, ddir2))) {
1558                                 do_mkdir(ddir2);
1559                         }
1560                         ddir2 = talloc_asprintf_append(ddir2, "%s", CLI_DIRSEP_STR);
1561                         if (!ddir2) {
1562                                 return 1;
1563                         }
1564                         p = strtok_r(NULL, "/\\", &saveptr);
1565                 }
1566         } else {
1567                 do_mkdir(mask);
1568         }
1569
1570         return 0;
1571 }
1572
1573 /****************************************************************************
1574  Show alt name.
1575 ****************************************************************************/
1576
1577 static int cmd_altname(void)
1578 {
1579         TALLOC_CTX *ctx = talloc_tos();
1580         char *name;
1581         char *buf;
1582
1583         name = talloc_strdup(ctx, client_get_cur_dir());
1584         if (!name) {
1585                 return 1;
1586         }
1587
1588         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1589                 d_printf("altname <file>\n");
1590                 return 1;
1591         }
1592         name = talloc_asprintf_append(name, "%s", buf);
1593         if (!name) {
1594                 return 1;
1595         }
1596         do_altname(name);
1597         return 0;
1598 }
1599
1600 static char *attr_str(TALLOC_CTX *mem_ctx, uint16_t mode)
1601 {
1602         char *attrs = TALLOC_ZERO_ARRAY(mem_ctx, char, 17);
1603         int i = 0;
1604
1605         if (!(mode & FILE_ATTRIBUTE_NORMAL)) {
1606                 if (mode & FILE_ATTRIBUTE_READONLY) {
1607                         attrs[i++] = 'R';
1608                 }
1609                 if (mode & FILE_ATTRIBUTE_HIDDEN) {
1610                         attrs[i++] = 'H';
1611                 }
1612                 if (mode & FILE_ATTRIBUTE_SYSTEM) {
1613                         attrs[i++] = 'S';
1614                 }
1615                 if (mode & FILE_ATTRIBUTE_DIRECTORY) {
1616                         attrs[i++] = 'D';
1617                 }
1618                 if (mode & FILE_ATTRIBUTE_ARCHIVE) {
1619                         attrs[i++] = 'A';
1620                 }
1621         }
1622         return attrs;
1623 }
1624
1625 /****************************************************************************
1626  Show all info we can get
1627 ****************************************************************************/
1628
1629 static int do_allinfo(const char *name)
1630 {
1631         fstring altname;
1632         struct timespec b_time, a_time, m_time, c_time;
1633         SMB_OFF_T size;
1634         uint16_t mode;
1635         SMB_INO_T ino;
1636         NTTIME tmp;
1637         uint16_t fnum;
1638         unsigned int num_streams;
1639         struct stream_struct *streams;
1640         int num_snapshots;
1641         char **snapshots;
1642         unsigned int i;
1643         NTSTATUS status;
1644
1645         status = cli_qpathinfo_alt_name(cli, name, altname);
1646         if (!NT_STATUS_IS_OK(status)) {
1647                 d_printf("%s getting alt name for %s\n", nt_errstr(status),
1648                          name);
1649                 return false;
1650         }
1651         d_printf("altname: %s\n", altname);
1652
1653         status = cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
1654                                 &size, &mode, &ino);
1655         if (!NT_STATUS_IS_OK(status)) {
1656                 d_printf("%s getting pathinfo for %s\n", nt_errstr(status),
1657                          name);
1658                 return false;
1659         }
1660
1661         unix_timespec_to_nt_time(&tmp, b_time);
1662         d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1663
1664         unix_timespec_to_nt_time(&tmp, a_time);
1665         d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1666
1667         unix_timespec_to_nt_time(&tmp, m_time);
1668         d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1669
1670         unix_timespec_to_nt_time(&tmp, c_time);
1671         d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1672
1673         d_printf("attributes: %s\n", attr_str(talloc_tos(), mode));
1674
1675         status = cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
1676                                        &streams);
1677         if (!NT_STATUS_IS_OK(status)) {
1678                 d_printf("%s getting streams for %s\n", nt_errstr(status),
1679                          name);
1680                 return false;
1681         }
1682
1683         for (i=0; i<num_streams; i++) {
1684                 d_printf("stream: [%s], %lld bytes\n", streams[i].name,
1685                          (unsigned long long)streams[i].size);
1686         }
1687
1688         status = cli_open(cli, name, O_RDONLY, DENY_NONE, &fnum);
1689         if (!NT_STATUS_IS_OK(status)) {
1690                 /*
1691                  * Ignore failure, it does not hurt if we can't list
1692                  * snapshots
1693                  */
1694                 return 0;
1695         }
1696         status = cli_shadow_copy_data(talloc_tos(), cli, fnum,
1697                                       true, &snapshots, &num_snapshots);
1698         if (!NT_STATUS_IS_OK(status)) {
1699                 cli_close(cli, fnum);
1700                 return 0;
1701         }
1702
1703         for (i=0; i<num_snapshots; i++) {
1704                 char *snap_name;
1705
1706                 d_printf("%s\n", snapshots[i]);
1707                 snap_name = talloc_asprintf(talloc_tos(), "%s%s",
1708                                             snapshots[i], name);
1709                 status = cli_qpathinfo2(cli, snap_name, &b_time, &a_time,
1710                                         &m_time, &c_time, &size,
1711                                         NULL, NULL);
1712                 if (!NT_STATUS_IS_OK(status)) {
1713                         d_fprintf(stderr, "pathinfo(%s) failed: %s\n",
1714                                   snap_name, nt_errstr(status));
1715                         TALLOC_FREE(snap_name);
1716                         continue;
1717                 }
1718                 unix_timespec_to_nt_time(&tmp, b_time);
1719                 d_printf("create_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1720                 unix_timespec_to_nt_time(&tmp, a_time);
1721                 d_printf("access_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1722                 unix_timespec_to_nt_time(&tmp, m_time);
1723                 d_printf("write_time:     %s\n", nt_time_string(talloc_tos(), tmp));
1724                 unix_timespec_to_nt_time(&tmp, c_time);
1725                 d_printf("change_time:    %s\n", nt_time_string(talloc_tos(), tmp));
1726                 d_printf("size: %d\n", (int)size);
1727         }
1728
1729         TALLOC_FREE(snapshots);
1730
1731         return 0;
1732 }
1733
1734 /****************************************************************************
1735  Show all info we can get
1736 ****************************************************************************/
1737
1738 static int cmd_allinfo(void)
1739 {
1740         TALLOC_CTX *ctx = talloc_tos();
1741         char *name;
1742         char *buf;
1743
1744         name = talloc_strdup(ctx, client_get_cur_dir());
1745         if (!name) {
1746                 return 1;
1747         }
1748
1749         if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
1750                 d_printf("allinfo <file>\n");
1751                 return 1;
1752         }
1753         name = talloc_asprintf_append(name, "%s", buf);
1754         if (!name) {
1755                 return 1;
1756         }
1757
1758         do_allinfo(name);
1759
1760         return 0;
1761 }
1762
1763 /****************************************************************************
1764  Put a single file.
1765 ****************************************************************************/
1766
1767 static int do_put(const char *rname, const char *lname, bool reput)
1768 {
1769         TALLOC_CTX *ctx = talloc_tos();
1770         uint16_t fnum;
1771         XFILE *f;
1772         SMB_OFF_T start = 0;
1773         int rc = 0;
1774         struct timespec tp_start;
1775         struct cli_state *targetcli;
1776         char *targetname = NULL;
1777         struct push_state state;
1778         NTSTATUS status;
1779
1780         if (!cli_resolve_path(ctx, "", auth_info, cli, rname, &targetcli, &targetname)) {
1781                 d_printf("Failed to open %s: %s\n", rname, cli_errstr(cli));
1782                 return 1;
1783         }
1784
1785         clock_gettime_mono(&tp_start);
1786
1787         if (reput) {
1788                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
1789                 if (NT_STATUS_IS_OK(status)) {
1790                         if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
1791                                                      targetcli, fnum, NULL,
1792                                                      &start, NULL, NULL,
1793                                                      NULL, NULL, NULL)) &&
1794                             !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL))) {
1795                                 d_printf("getattrib: %s\n",cli_errstr(cli));
1796                                 return 1;
1797                         }
1798                 }
1799         } else {
1800                 status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
1801         }
1802
1803         if (!NT_STATUS_IS_OK(status)) {
1804                 d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
1805                 return 1;
1806         }
1807
1808         /* allow files to be piped into smbclient
1809            jdblair 24.jun.98
1810
1811            Note that in this case this function will exit(0) rather
1812            than returning. */
1813         if (!strcmp(lname, "-")) {
1814                 f = x_stdin;
1815                 /* size of file is not known */
1816         } else {
1817                 f = x_fopen(lname,O_RDONLY, 0);
1818                 if (f && reput) {
1819                         if (x_tseek(f, start, SEEK_SET) == -1) {
1820                                 d_printf("Error seeking local file\n");
1821                                 x_fclose(f);
1822                                 return 1;
1823                         }
1824                 }
1825         }
1826
1827         if (!f) {
1828                 d_printf("Error opening local file %s\n",lname);
1829                 return 1;
1830         }
1831
1832         DEBUG(1,("putting file %s as %s ",lname,
1833                  rname));
1834
1835         x_setvbuf(f, NULL, X_IOFBF, io_bufsize);
1836
1837         state.f = f;
1838         state.nread = 0;
1839
1840         status = cli_push(targetcli, fnum, 0, 0, io_bufsize, push_source,
1841                           &state);
1842         if (!NT_STATUS_IS_OK(status)) {
1843                 d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
1844                 rc = 1;
1845         }
1846
1847         status = cli_close(targetcli, fnum);
1848         if (!NT_STATUS_IS_OK(status)) {
1849                 d_printf("%s closing remote file %s\n", nt_errstr(status),
1850                          rname);
1851                 if (f != x_stdin) {
1852                         x_fclose(f);
1853                 }
1854                 return 1;
1855         }
1856
1857         if (f != x_stdin) {
1858                 x_fclose(f);
1859         }
1860
1861         {
1862                 struct timespec tp_end;
1863                 int this_time;
1864
1865                 clock_gettime_mono(&tp_end);
1866                 this_time = nsec_time_diff(&tp_end,&tp_start)/1000000;
1867                 put_total_time_ms += this_time;
1868                 put_total_size += state.nread;
1869
1870                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1871                          state.nread / (1.024*this_time + 1.0e-4),
1872                          put_total_size / (1.024*put_total_time_ms)));
1873         }
1874
1875         if (f == x_stdin) {
1876                 cli_shutdown(cli);
1877                 exit(0);
1878         }
1879
1880         return rc;
1881 }
1882
1883 /****************************************************************************
1884  Put a file.
1885 ****************************************************************************/
1886
1887 static int cmd_put(void)
1888 {
1889         TALLOC_CTX *ctx = talloc_tos();
1890         char *lname;
1891         char *rname;
1892         char *buf;
1893
1894         rname = talloc_strdup(ctx, client_get_cur_dir());
1895         if (!rname) {
1896                 return 1;
1897         }
1898
1899         if (!next_token_talloc(ctx, &cmd_ptr,&lname,NULL)) {
1900                 d_printf("put <filename>\n");
1901                 return 1;
1902         }
1903
1904         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
1905                 rname = talloc_asprintf_append(rname, "%s", buf);
1906         } else {
1907                 rname = talloc_asprintf_append(rname, "%s", lname);
1908         }
1909         if (!rname) {
1910                 return 1;
1911         }
1912
1913         rname = clean_name(ctx, rname);
1914         if (!rname) {
1915                 return 1;
1916         }
1917
1918         {
1919                 SMB_STRUCT_STAT st;
1920                 /* allow '-' to represent stdin
1921                    jdblair, 24.jun.98 */
1922                 if (!file_exist_stat(lname, &st, false) &&
1923                     (strcmp(lname,"-"))) {
1924                         d_printf("%s does not exist\n",lname);
1925                         return 1;
1926                 }
1927         }
1928
1929         return do_put(rname, lname, false);
1930 }
1931
1932 /*************************************
1933  File list structure.
1934 *************************************/
1935
1936 static struct file_list {
1937         struct file_list *prev, *next;
1938         char *file_path;
1939         bool isdir;
1940 } *file_list;
1941
1942 /****************************************************************************
1943  Free a file_list structure.
1944 ****************************************************************************/
1945
1946 static void free_file_list (struct file_list *l_head)
1947 {
1948         struct file_list *list, *next;
1949
1950         for (list = l_head; list; list = next) {
1951                 next = list->next;
1952                 DLIST_REMOVE(l_head, list);
1953                 SAFE_FREE(list->file_path);
1954                 SAFE_FREE(list);
1955         }
1956 }
1957
1958 /****************************************************************************
1959  Seek in a directory/file list until you get something that doesn't start with
1960  the specified name.
1961 ****************************************************************************/
1962
1963 static bool seek_list(struct file_list *list, char *name)
1964 {
1965         while (list) {
1966                 trim_string(list->file_path,"./","\n");
1967                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1968                         return true;
1969                 }
1970                 list = list->next;
1971         }
1972
1973         return false;
1974 }
1975
1976 /****************************************************************************
1977  Set the file selection mask.
1978 ****************************************************************************/
1979
1980 static int cmd_select(void)
1981 {
1982         TALLOC_CTX *ctx = talloc_tos();
1983         char *new_fs = NULL;
1984         next_token_talloc(ctx, &cmd_ptr,&new_fs,NULL)
1985                 ;
1986         if (new_fs) {
1987                 client_set_fileselection(new_fs);
1988         } else {
1989                 client_set_fileselection("");
1990         }
1991         return 0;
1992 }
1993
1994 /****************************************************************************
1995   Recursive file matching function act as find
1996   match must be always set to true when calling this function
1997 ****************************************************************************/
1998
1999 static int file_find(struct file_list **list, const char *directory,
2000                       const char *expression, bool match)
2001 {
2002         SMB_STRUCT_DIR *dir;
2003         struct file_list *entry;
2004         struct stat statbuf;
2005         int ret;
2006         char *path;
2007         bool isdir;
2008         const char *dname;
2009
2010         dir = sys_opendir(directory);
2011         if (!dir)
2012                 return -1;
2013
2014         while ((dname = readdirname(dir))) {
2015                 if (!strcmp("..", dname))
2016                         continue;
2017                 if (!strcmp(".", dname))
2018                         continue;
2019
2020                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
2021                         continue;
2022                 }
2023
2024                 isdir = false;
2025                 if (!match || !gen_fnmatch(expression, dname)) {
2026                         if (recurse) {
2027                                 ret = stat(path, &statbuf);
2028                                 if (ret == 0) {
2029                                         if (S_ISDIR(statbuf.st_mode)) {
2030                                                 isdir = true;
2031                                                 ret = file_find(list, path, expression, false);
2032                                         }
2033                                 } else {
2034                                         d_printf("file_find: cannot stat file %s\n", path);
2035                                 }
2036
2037                                 if (ret == -1) {
2038                                         SAFE_FREE(path);
2039                                         sys_closedir(dir);
2040                                         return -1;
2041                                 }
2042                         }
2043                         entry = SMB_MALLOC_P(struct file_list);
2044                         if (!entry) {
2045                                 d_printf("Out of memory in file_find\n");
2046                                 sys_closedir(dir);
2047                                 return -1;
2048                         }
2049                         entry->file_path = path;
2050                         entry->isdir = isdir;
2051                         DLIST_ADD(*list, entry);
2052                 } else {
2053                         SAFE_FREE(path);
2054                 }
2055         }
2056
2057         sys_closedir(dir);
2058         return 0;
2059 }
2060
2061 /****************************************************************************
2062  mput some files.
2063 ****************************************************************************/
2064
2065 static int cmd_mput(void)
2066 {
2067         TALLOC_CTX *ctx = talloc_tos();
2068         char *p = NULL;
2069
2070         while (next_token_talloc(ctx, &cmd_ptr,&p,NULL)) {
2071                 int ret;
2072                 struct file_list *temp_list;
2073                 char *quest, *lname, *rname;
2074
2075                 file_list = NULL;
2076
2077                 ret = file_find(&file_list, ".", p, true);
2078                 if (ret) {
2079                         free_file_list(file_list);
2080                         continue;
2081                 }
2082
2083                 quest = NULL;
2084                 lname = NULL;
2085                 rname = NULL;
2086
2087                 for (temp_list = file_list; temp_list;
2088                      temp_list = temp_list->next) {
2089
2090                         SAFE_FREE(lname);
2091                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0) {
2092                                 continue;
2093                         }
2094                         trim_string(lname, "./", "/");
2095
2096                         /* check if it's a directory */
2097                         if (temp_list->isdir) {
2098                                 /* if (!recurse) continue; */
2099
2100                                 SAFE_FREE(quest);
2101                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) {
2102                                         break;
2103                                 }
2104                                 if (prompt && !yesno(quest)) { /* No */
2105                                         /* Skip the directory */
2106                                         lname[strlen(lname)-1] = '/';
2107                                         if (!seek_list(temp_list, lname))
2108                                                 break;
2109                                 } else { /* Yes */
2110                                         SAFE_FREE(rname);
2111                                         if(asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2112                                                 break;
2113                                         }
2114                                         normalize_name(rname);
2115                                         if (!NT_STATUS_IS_OK(cli_chkpath(cli, rname)) &&
2116                                             !do_mkdir(rname)) {
2117                                                 DEBUG (0, ("Unable to make dir, skipping..."));
2118                                                 /* Skip the directory */
2119                                                 lname[strlen(lname)-1] = '/';
2120                                                 if (!seek_list(temp_list, lname)) {
2121                                                         break;
2122                                                 }
2123                                         }
2124                                 }
2125                                 continue;
2126                         } else {
2127                                 SAFE_FREE(quest);
2128                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) {
2129                                         break;
2130                                 }
2131                                 if (prompt && !yesno(quest)) {
2132                                         /* No */
2133                                         continue;
2134                                 }
2135
2136                                 /* Yes */
2137                                 SAFE_FREE(rname);
2138                                 if (asprintf(&rname, "%s%s", client_get_cur_dir(), lname) < 0) {
2139                                         break;
2140                                 }
2141                         }
2142
2143                         normalize_name(rname);
2144
2145                         do_put(rname, lname, false);
2146                 }
2147                 free_file_list(file_list);
2148                 SAFE_FREE(quest);
2149                 SAFE_FREE(lname);
2150                 SAFE_FREE(rname);
2151         }
2152
2153         return 0;
2154 }
2155
2156 /****************************************************************************
2157  Cancel a print job.
2158 ****************************************************************************/
2159
2160 static int do_cancel(int job)
2161 {
2162         if (cli_printjob_del(cli, job)) {
2163                 d_printf("Job %d cancelled\n",job);
2164                 return 0;
2165         } else {
2166                 d_printf("Error cancelling job %d : %s\n",job,cli_errstr(cli));
2167                 return 1;
2168         }
2169 }
2170
2171 /****************************************************************************
2172  Cancel a print job.
2173 ****************************************************************************/
2174
2175 static int cmd_cancel(void)
2176 {
2177         TALLOC_CTX *ctx = talloc_tos();
2178         char *buf = NULL;
2179         int job;
2180
2181         if (!next_token_talloc(ctx, &cmd_ptr, &buf,NULL)) {
2182                 d_printf("cancel <jobid> ...\n");
2183                 return 1;
2184         }
2185         do {
2186                 job = atoi(buf);
2187                 do_cancel(job);
2188         } while (next_token_talloc(ctx, &cmd_ptr,&buf,NULL));
2189
2190         return 0;
2191 }
2192
2193 /****************************************************************************
2194  Print a file.
2195 ****************************************************************************/
2196
2197 static int cmd_print(void)
2198 {
2199         TALLOC_CTX *ctx = talloc_tos();
2200         char *lname = NULL;
2201         char *rname = NULL;
2202         char *p = NULL;
2203
2204         if (!next_token_talloc(ctx, &cmd_ptr, &lname,NULL)) {
2205                 d_printf("print <filename>\n");
2206                 return 1;
2207         }
2208
2209         rname = talloc_strdup(ctx, lname);
2210         if (!rname) {
2211                 return 1;
2212         }
2213         p = strrchr_m(rname,'/');
2214         if (p) {
2215                 rname = talloc_asprintf(ctx,
2216                                         "%s-%d",
2217                                         p+1,
2218                                         (int)sys_getpid());
2219         }
2220         if (strequal(lname,"-")) {
2221                 rname = talloc_asprintf(ctx,
2222                                 "stdin-%d",
2223                                 (int)sys_getpid());
2224         }
2225         if (!rname) {
2226                 return 1;
2227         }
2228
2229         return do_put(rname, lname, false);
2230 }
2231
2232 /****************************************************************************
2233  Show a print queue entry.
2234 ****************************************************************************/
2235
2236 static void queue_fn(struct print_job_info *p)
2237 {
2238         d_printf("%-6d   %-9d    %s\n", (int)p->id, (int)p->size, p->name);
2239 }
2240
2241 /****************************************************************************
2242  Show a print queue.
2243 ****************************************************************************/
2244
2245 static int cmd_queue(void)
2246 {
2247         cli_print_queue(cli, queue_fn);
2248         return 0;
2249 }
2250
2251 /****************************************************************************
2252  Delete some files.
2253 ****************************************************************************/
2254
2255 static NTSTATUS do_del(struct cli_state *cli_state, struct file_info *finfo,
2256                    const char *dir)
2257 {
2258         TALLOC_CTX *ctx = talloc_tos();
2259         char *mask = NULL;
2260         NTSTATUS status;
2261
2262         mask = talloc_asprintf(ctx,
2263                                 "%s%c%s",
2264                                 dir,
2265                                 CLI_DIRSEP_CHAR,
2266                                 finfo->name);
2267         if (!mask) {
2268                 return NT_STATUS_NO_MEMORY;
2269         }
2270
2271         if (finfo->mode & aDIR) {
2272                 TALLOC_FREE(mask);
2273                 return NT_STATUS_OK;
2274         }
2275
2276         status = cli_unlink(cli_state, mask, aSYSTEM | aHIDDEN);
2277         if (!NT_STATUS_IS_OK(status)) {
2278                 d_printf("%s deleting remote file %s\n",
2279                          nt_errstr(status), mask);
2280         }
2281         TALLOC_FREE(mask);
2282         return status;
2283 }
2284
2285 /****************************************************************************
2286  Delete some files.
2287 ****************************************************************************/
2288
2289 static int cmd_del(void)
2290 {
2291         TALLOC_CTX *ctx = talloc_tos();
2292         char *mask = NULL;
2293         char *buf = NULL;
2294         NTSTATUS status = NT_STATUS_OK;
2295         uint16 attribute = aSYSTEM | aHIDDEN;
2296
2297         if (recurse) {
2298                 attribute |= aDIR;
2299         }
2300
2301         mask = talloc_strdup(ctx, client_get_cur_dir());
2302         if (!mask) {
2303                 return 1;
2304         }
2305         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2306                 d_printf("del <filename>\n");
2307                 return 1;
2308         }
2309         mask = talloc_asprintf_append(mask, "%s", buf);
2310         if (!mask) {
2311                 return 1;
2312         }
2313
2314         status = do_list(mask,attribute,do_del,false,false);
2315         if (!NT_STATUS_IS_OK(status)) {
2316                 return 1;
2317         }
2318         return 0;
2319 }
2320
2321 /****************************************************************************
2322  Wildcard delete some files.
2323 ****************************************************************************/
2324
2325 static int cmd_wdel(void)
2326 {
2327         TALLOC_CTX *ctx = talloc_tos();
2328         char *mask = NULL;
2329         char *buf = NULL;
2330         uint16 attribute;
2331         struct cli_state *targetcli;
2332         char *targetname = NULL;
2333         NTSTATUS status;
2334
2335         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2336                 d_printf("wdel 0x<attrib> <wcard>\n");
2337                 return 1;
2338         }
2339
2340         attribute = (uint16)strtol(buf, (char **)NULL, 16);
2341
2342         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2343                 d_printf("wdel 0x<attrib> <wcard>\n");
2344                 return 1;
2345         }
2346
2347         mask = talloc_asprintf(ctx, "%s%s",
2348                         client_get_cur_dir(),
2349                         buf);
2350         if (!mask) {
2351                 return 1;
2352         }
2353
2354         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2355                 d_printf("cmd_wdel %s: %s\n", mask, cli_errstr(cli));
2356                 return 1;
2357         }
2358
2359         status = cli_unlink(targetcli, targetname, attribute);
2360         if (!NT_STATUS_IS_OK(status)) {
2361                 d_printf("%s deleting remote files %s\n", nt_errstr(status),
2362                          targetname);
2363         }
2364         return 0;
2365 }
2366
2367 /****************************************************************************
2368 ****************************************************************************/
2369
2370 static int cmd_open(void)
2371 {
2372         TALLOC_CTX *ctx = talloc_tos();
2373         char *mask = NULL;
2374         char *buf = NULL;
2375         char *targetname = NULL;
2376         struct cli_state *targetcli;
2377         uint16_t fnum = (uint16_t)-1;
2378
2379         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2380                 d_printf("open <filename>\n");
2381                 return 1;
2382         }
2383         mask = talloc_asprintf(ctx,
2384                         "%s%s",
2385                         client_get_cur_dir(),
2386                         buf);
2387         if (!mask) {
2388                 return 1;
2389         }
2390
2391         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2392                 d_printf("open %s: %s\n", mask, cli_errstr(cli));
2393                 return 1;
2394         }
2395
2396         if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
2397                         FILE_READ_DATA|FILE_WRITE_DATA, 0,
2398                         FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
2399                 if (NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
2400                                 FILE_READ_DATA, 0,
2401                                 FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
2402                         d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2403                 } else {
2404                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2405                 }
2406         } else {
2407                 d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
2408         }
2409         return 0;
2410 }
2411
2412 static int cmd_posix_encrypt(void)
2413 {
2414         TALLOC_CTX *ctx = talloc_tos();
2415         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2416
2417         if (cli->use_kerberos) {
2418                 status = cli_gss_smb_encryption_start(cli);
2419         } else {
2420                 char *domain = NULL;
2421                 char *user = NULL;
2422                 char *password = NULL;
2423
2424                 if (!next_token_talloc(ctx, &cmd_ptr,&domain,NULL)) {
2425                         d_printf("posix_encrypt domain user password\n");
2426                         return 1;
2427                 }
2428
2429                 if (!next_token_talloc(ctx, &cmd_ptr,&user,NULL)) {
2430                         d_printf("posix_encrypt domain user password\n");
2431                         return 1;
2432                 }
2433
2434                 if (!next_token_talloc(ctx, &cmd_ptr,&password,NULL)) {
2435                         d_printf("posix_encrypt domain user password\n");
2436                         return 1;
2437                 }
2438
2439                 status = cli_raw_ntlm_smb_encryption_start(cli,
2440                                                         user,
2441                                                         password,
2442                                                         domain);
2443         }
2444
2445         if (!NT_STATUS_IS_OK(status)) {
2446                 d_printf("posix_encrypt failed with error %s\n", nt_errstr(status));
2447         } else {
2448                 d_printf("encryption on\n");
2449                 smb_encrypt = true;
2450         }
2451
2452         return 0;
2453 }
2454
2455 /****************************************************************************
2456 ****************************************************************************/
2457
2458 static int cmd_posix_open(void)
2459 {
2460         TALLOC_CTX *ctx = talloc_tos();
2461         char *mask = NULL;
2462         char *buf = NULL;
2463         char *targetname = NULL;
2464         struct cli_state *targetcli;
2465         mode_t mode;
2466         uint16_t fnum;
2467
2468         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2469                 d_printf("posix_open <filename> 0<mode>\n");
2470                 return 1;
2471         }
2472         mask = talloc_asprintf(ctx,
2473                         "%s%s",
2474                         client_get_cur_dir(),
2475                         buf);
2476         if (!mask) {
2477                 return 1;
2478         }
2479
2480         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2481                 d_printf("posix_open <filename> 0<mode>\n");
2482                 return 1;
2483         }
2484         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2485
2486         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2487                 d_printf("posix_open %s: %s\n", mask, cli_errstr(cli));
2488                 return 1;
2489         }
2490
2491         if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode, &fnum))) {
2492                 if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode, &fnum))) {
2493                         d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2494                 } else {
2495                         d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2496                 }
2497         } else {
2498                 d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
2499         }
2500
2501         return 0;
2502 }
2503
2504 static int cmd_posix_mkdir(void)
2505 {
2506         TALLOC_CTX *ctx = talloc_tos();
2507         char *mask = NULL;
2508         char *buf = NULL;
2509         char *targetname = NULL;
2510         struct cli_state *targetcli;
2511         mode_t mode;
2512
2513         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2514                 d_printf("posix_mkdir <filename> 0<mode>\n");
2515                 return 1;
2516         }
2517         mask = talloc_asprintf(ctx,
2518                         "%s%s",
2519                         client_get_cur_dir(),
2520                         buf);
2521         if (!mask) {
2522                 return 1;
2523         }
2524
2525         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2526                 d_printf("posix_mkdir <filename> 0<mode>\n");
2527                 return 1;
2528         }
2529         mode = (mode_t)strtol(buf, (char **)NULL, 8);
2530
2531         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2532                 d_printf("posix_mkdir %s: %s\n", mask, cli_errstr(cli));
2533                 return 1;
2534         }
2535
2536         if (!NT_STATUS_IS_OK(cli_posix_mkdir(targetcli, targetname, mode))) {
2537                 d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
2538         } else {
2539                 d_printf("posix_mkdir created directory %s\n", targetname);
2540         }
2541         return 0;
2542 }
2543
2544 static int cmd_posix_unlink(void)
2545 {
2546         TALLOC_CTX *ctx = talloc_tos();
2547         char *mask = NULL;
2548         char *buf = NULL;
2549         char *targetname = NULL;
2550         struct cli_state *targetcli;
2551
2552         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2553                 d_printf("posix_unlink <filename>\n");
2554                 return 1;
2555         }
2556         mask = talloc_asprintf(ctx,
2557                         "%s%s",
2558                         client_get_cur_dir(),
2559                         buf);
2560         if (!mask) {
2561                 return 1;
2562         }
2563
2564         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2565                 d_printf("posix_unlink %s: %s\n", mask, cli_errstr(cli));
2566                 return 1;
2567         }
2568
2569         if (!NT_STATUS_IS_OK(cli_posix_unlink(targetcli, targetname))) {
2570                 d_printf("Failed to unlink file %s. %s\n", targetname, cli_errstr(cli));
2571         } else {
2572                 d_printf("posix_unlink deleted file %s\n", targetname);
2573         }
2574
2575         return 0;
2576 }
2577
2578 static int cmd_posix_rmdir(void)
2579 {
2580         TALLOC_CTX *ctx = talloc_tos();
2581         char *mask = NULL;
2582         char *buf = NULL;
2583         char *targetname = NULL;
2584         struct cli_state *targetcli;
2585
2586         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2587                 d_printf("posix_rmdir <filename>\n");
2588                 return 1;
2589         }
2590         mask = talloc_asprintf(ctx,
2591                         "%s%s",
2592                         client_get_cur_dir(),
2593                         buf);
2594         if (!mask) {
2595                 return 1;
2596         }
2597
2598         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2599                 d_printf("posix_rmdir %s: %s\n", mask, cli_errstr(cli));
2600                 return 1;
2601         }
2602
2603         if (!NT_STATUS_IS_OK(cli_posix_rmdir(targetcli, targetname))) {
2604                 d_printf("Failed to unlink directory %s. %s\n", targetname, cli_errstr(cli));
2605         } else {
2606                 d_printf("posix_rmdir deleted directory %s\n", targetname);
2607         }
2608
2609         return 0;
2610 }
2611
2612 static int cmd_close(void)
2613 {
2614         TALLOC_CTX *ctx = talloc_tos();
2615         char *buf = NULL;
2616         int fnum;
2617
2618         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2619                 d_printf("close <fnum>\n");
2620                 return 1;
2621         }
2622
2623         fnum = atoi(buf);
2624         /* We really should use the targetcli here.... */
2625         if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
2626                 d_printf("close %d: %s\n", fnum, cli_errstr(cli));
2627                 return 1;
2628         }
2629         return 0;
2630 }
2631
2632 static int cmd_posix(void)
2633 {
2634         TALLOC_CTX *ctx = talloc_tos();
2635         uint16 major, minor;
2636         uint32 caplow, caphigh;
2637         char *caps;
2638         NTSTATUS status;
2639
2640         if (!SERVER_HAS_UNIX_CIFS(cli)) {
2641                 d_printf("Server doesn't support UNIX CIFS extensions.\n");
2642                 return 1;
2643         }
2644
2645         status = cli_unix_extensions_version(cli, &major, &minor, &caplow,
2646                                              &caphigh);
2647         if (!NT_STATUS_IS_OK(status)) {
2648                 d_printf("Can't get UNIX CIFS extensions version from "
2649                          "server: %s\n", nt_errstr(status));
2650                 return 1;
2651         }
2652
2653         d_printf("Server supports CIFS extensions %u.%u\n", (unsigned int)major, (unsigned int)minor);
2654
2655         caps = talloc_strdup(ctx, "");
2656         if (!caps) {
2657                 return 1;
2658         }
2659         if (caplow & CIFS_UNIX_FCNTL_LOCKS_CAP) {
2660                 caps = talloc_asprintf_append(caps, "locks ");
2661                 if (!caps) {
2662                         return 1;
2663                 }
2664         }
2665         if (caplow & CIFS_UNIX_POSIX_ACLS_CAP) {
2666                 caps = talloc_asprintf_append(caps, "acls ");
2667                 if (!caps) {
2668                         return 1;
2669                 }
2670         }
2671         if (caplow & CIFS_UNIX_XATTTR_CAP) {
2672                 caps = talloc_asprintf_append(caps, "eas ");
2673                 if (!caps) {
2674                         return 1;
2675                 }
2676         }
2677         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2678                 caps = talloc_asprintf_append(caps, "pathnames ");
2679                 if (!caps) {
2680                         return 1;
2681                 }
2682         }
2683         if (caplow & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2684                 caps = talloc_asprintf_append(caps, "posix_path_operations ");
2685                 if (!caps) {
2686                         return 1;
2687                 }
2688         }
2689         if (caplow & CIFS_UNIX_LARGE_READ_CAP) {
2690                 caps = talloc_asprintf_append(caps, "large_read ");
2691                 if (!caps) {
2692                         return 1;
2693                 }
2694         }
2695         if (caplow & CIFS_UNIX_LARGE_WRITE_CAP) {
2696                 caps = talloc_asprintf_append(caps, "large_write ");
2697                 if (!caps) {
2698                         return 1;
2699                 }
2700         }
2701         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP) {
2702                 caps = talloc_asprintf_append(caps, "posix_encrypt ");
2703                 if (!caps) {
2704                         return 1;
2705                 }
2706         }
2707         if (caplow & CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP) {
2708                 caps = talloc_asprintf_append(caps, "mandatory_posix_encrypt ");
2709                 if (!caps) {
2710                         return 1;
2711                 }
2712         }
2713
2714         if (*caps && caps[strlen(caps)-1] == ' ') {
2715                 caps[strlen(caps)-1] = '\0';
2716         }
2717
2718         d_printf("Server supports CIFS capabilities %s\n", caps);
2719
2720         status = cli_set_unix_extensions_capabilities(cli, major, minor,
2721                                                       caplow, caphigh);
2722         if (!NT_STATUS_IS_OK(status)) {
2723                 d_printf("Can't set UNIX CIFS extensions capabilities. %s.\n",
2724                          nt_errstr(status));
2725                 return 1;
2726         }
2727
2728         if (caplow & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
2729                 CLI_DIRSEP_CHAR = '/';
2730                 *CLI_DIRSEP_STR = '/';
2731                 client_set_cur_dir(CLI_DIRSEP_STR);
2732         }
2733
2734         return 0;
2735 }
2736
2737 static int cmd_lock(void)
2738 {
2739         TALLOC_CTX *ctx = talloc_tos();
2740         char *buf = NULL;
2741         uint64_t start, len;
2742         enum brl_type lock_type;
2743         int fnum;
2744
2745         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2746                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2747                 return 1;
2748         }
2749         fnum = atoi(buf);
2750
2751         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2752                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2753                 return 1;
2754         }
2755
2756         if (*buf == 'r' || *buf == 'R') {
2757                 lock_type = READ_LOCK;
2758         } else if (*buf == 'w' || *buf == 'W') {
2759                 lock_type = WRITE_LOCK;
2760         } else {
2761                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2762                 return 1;
2763         }
2764
2765         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2766                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2767                 return 1;
2768         }
2769
2770         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2771
2772         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2773                 d_printf("lock <fnum> [r|w] <hex-start> <hex-len>\n");
2774                 return 1;
2775         }
2776
2777         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2778
2779         if (!NT_STATUS_IS_OK(cli_posix_lock(cli, fnum, start, len, true, lock_type))) {
2780                 d_printf("lock failed %d: %s\n", fnum, cli_errstr(cli));
2781         }
2782
2783         return 0;
2784 }
2785
2786 static int cmd_unlock(void)
2787 {
2788         TALLOC_CTX *ctx = talloc_tos();
2789         char *buf = NULL;
2790         uint64_t start, len;
2791         int fnum;
2792
2793         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2794                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2795                 return 1;
2796         }
2797         fnum = atoi(buf);
2798
2799         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2800                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2801                 return 1;
2802         }
2803
2804         start = (uint64_t)strtol(buf, (char **)NULL, 16);
2805
2806         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2807                 d_printf("unlock <fnum> <hex-start> <hex-len>\n");
2808                 return 1;
2809         }
2810
2811         len = (uint64_t)strtol(buf, (char **)NULL, 16);
2812
2813         if (!NT_STATUS_IS_OK(cli_posix_unlock(cli, fnum, start, len))) {
2814                 d_printf("unlock failed %d: %s\n", fnum, cli_errstr(cli));
2815         }
2816
2817         return 0;
2818 }
2819
2820
2821 /****************************************************************************
2822  Remove a directory.
2823 ****************************************************************************/
2824
2825 static int cmd_rmdir(void)
2826 {
2827         TALLOC_CTX *ctx = talloc_tos();
2828         char *mask = NULL;
2829         char *buf = NULL;
2830         char *targetname = NULL;
2831         struct cli_state *targetcli;
2832
2833         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2834                 d_printf("rmdir <dirname>\n");
2835                 return 1;
2836         }
2837         mask = talloc_asprintf(ctx,
2838                         "%s%s",
2839                         client_get_cur_dir(),
2840                         buf);
2841         if (!mask) {
2842                 return 1;
2843         }
2844
2845         if (!cli_resolve_path(ctx, "", auth_info, cli, mask, &targetcli, &targetname)) {
2846                 d_printf("rmdir %s: %s\n", mask, cli_errstr(cli));
2847                 return 1;
2848         }
2849
2850         if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetname))) {
2851                 d_printf("%s removing remote directory file %s\n",
2852                          cli_errstr(targetcli),mask);
2853         }
2854
2855         return 0;
2856 }
2857
2858 /****************************************************************************
2859  UNIX hardlink.
2860 ****************************************************************************/
2861
2862 static int cmd_link(void)
2863 {
2864         TALLOC_CTX *ctx = talloc_tos();
2865         char *oldname = NULL;
2866         char *newname = NULL;
2867         char *buf = NULL;
2868         char *buf2 = NULL;
2869         char *targetname = NULL;
2870         struct cli_state *targetcli;
2871
2872         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2873             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2874                 d_printf("link <oldname> <newname>\n");
2875                 return 1;
2876         }
2877         oldname = talloc_asprintf(ctx,
2878                         "%s%s",
2879                         client_get_cur_dir(),
2880                         buf);
2881         if (!oldname) {
2882                 return 1;
2883         }
2884         newname = talloc_asprintf(ctx,
2885                         "%s%s",
2886                         client_get_cur_dir(),
2887                         buf2);
2888         if (!newname) {
2889                 return 1;
2890         }
2891
2892         if (!cli_resolve_path(ctx, "", auth_info, cli, oldname, &targetcli, &targetname)) {
2893                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2894                 return 1;
2895         }
2896
2897         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2898                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2899                 return 1;
2900         }
2901
2902         if (!NT_STATUS_IS_OK(cli_posix_hardlink(targetcli, targetname, newname))) {
2903                 d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
2904                 return 1;
2905         }
2906         return 0;
2907 }
2908
2909 /****************************************************************************
2910  UNIX readlink.
2911 ****************************************************************************/
2912
2913 static int cmd_readlink(void)
2914 {
2915         TALLOC_CTX *ctx = talloc_tos();
2916         char *name= NULL;
2917         char *buf = NULL;
2918         char *targetname = NULL;
2919         char linkname[PATH_MAX+1];
2920         struct cli_state *targetcli;
2921
2922         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
2923                 d_printf("readlink <name>\n");
2924                 return 1;
2925         }
2926         name = talloc_asprintf(ctx,
2927                         "%s%s",
2928                         client_get_cur_dir(),
2929                         buf);
2930         if (!name) {
2931                 return 1;
2932         }
2933
2934         if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
2935                 d_printf("readlink %s: %s\n", name, cli_errstr(cli));
2936                 return 1;
2937         }
2938
2939         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
2940                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2941                 return 1;
2942         }
2943
2944         if (!NT_STATUS_IS_OK(cli_posix_readlink(targetcli, name,
2945                         linkname, PATH_MAX+1))) {
2946                 d_printf("%s readlink on file %s\n",
2947                         cli_errstr(targetcli), name);
2948                 return 1;
2949         }
2950
2951         d_printf("%s -> %s\n", name, linkname);
2952
2953         return 0;
2954 }
2955
2956
2957 /****************************************************************************
2958  UNIX symlink.
2959 ****************************************************************************/
2960
2961 static int cmd_symlink(void)
2962 {
2963         TALLOC_CTX *ctx = talloc_tos();
2964         char *oldname = NULL;
2965         char *newname = NULL;
2966         char *buf = NULL;
2967         char *buf2 = NULL;
2968         struct cli_state *newcli;
2969
2970         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
2971             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
2972                 d_printf("symlink <oldname> <newname>\n");
2973                 return 1;
2974         }
2975         /* Oldname (link target) must be an untouched blob. */
2976         oldname = buf;
2977
2978         newname = talloc_asprintf(ctx,
2979                         "%s%s",
2980                         client_get_cur_dir(),
2981                         buf2);
2982         if (!newname) {
2983                 return 1;
2984         }
2985
2986         /* New name must be present in share namespace. */
2987         if (!cli_resolve_path(ctx, "", auth_info, cli, newname, &newcli, &newname)) {
2988                 d_printf("link %s: %s\n", oldname, cli_errstr(cli));
2989                 return 1;
2990         }
2991
2992         if (!SERVER_HAS_UNIX_CIFS(newcli)) {
2993                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2994                 return 1;
2995         }
2996
2997         if (!NT_STATUS_IS_OK(cli_posix_symlink(newcli, oldname, newname))) {
2998                 d_printf("%s symlinking files (%s -> %s)\n",
2999                         cli_errstr(newcli), newname, newname);
3000                 return 1;
3001         }
3002
3003         return 0;
3004 }
3005
3006 /****************************************************************************
3007  UNIX chmod.
3008 ****************************************************************************/
3009
3010 static int cmd_chmod(void)
3011 {
3012         TALLOC_CTX *ctx = talloc_tos();
3013         char *src = NULL;
3014         char *buf = NULL;
3015         char *buf2 = NULL;
3016         char *targetname = NULL;
3017         struct cli_state *targetcli;
3018         mode_t mode;
3019
3020         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3021             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3022                 d_printf("chmod mode file\n");
3023                 return 1;
3024         }
3025         src = talloc_asprintf(ctx,
3026                         "%s%s",
3027                         client_get_cur_dir(),
3028                         buf2);
3029         if (!src) {
3030                 return 1;
3031         }
3032
3033         mode = (mode_t)strtol(buf, NULL, 8);
3034
3035         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3036                 d_printf("chmod %s: %s\n", src, cli_errstr(cli));
3037                 return 1;
3038         }
3039
3040         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3041                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3042                 return 1;
3043         }
3044
3045         if (!NT_STATUS_IS_OK(cli_posix_chmod(targetcli, targetname, mode))) {
3046                 d_printf("%s chmod file %s 0%o\n",
3047                         cli_errstr(targetcli), src, (unsigned int)mode);
3048                 return 1;
3049         }
3050
3051         return 0;
3052 }
3053
3054 static const char *filetype_to_str(mode_t mode)
3055 {
3056         if (S_ISREG(mode)) {
3057                 return "regular file";
3058         } else if (S_ISDIR(mode)) {
3059                 return "directory";
3060         } else
3061 #ifdef S_ISCHR
3062         if (S_ISCHR(mode)) {
3063                 return "character device";
3064         } else
3065 #endif
3066 #ifdef S_ISBLK
3067         if (S_ISBLK(mode)) {
3068                 return "block device";
3069         } else
3070 #endif
3071 #ifdef S_ISFIFO
3072         if (S_ISFIFO(mode)) {
3073                 return "fifo";
3074         } else
3075 #endif
3076 #ifdef S_ISLNK
3077         if (S_ISLNK(mode)) {
3078                 return "symbolic link";
3079         } else
3080 #endif
3081 #ifdef S_ISSOCK
3082         if (S_ISSOCK(mode)) {
3083                 return "socket";
3084         } else
3085 #endif
3086         return "";
3087 }
3088
3089 static char rwx_to_str(mode_t m, mode_t bt, char ret)
3090 {
3091         if (m & bt) {
3092                 return ret;
3093         } else {
3094                 return '-';
3095         }
3096 }
3097
3098 static char *unix_mode_to_str(char *s, mode_t m)
3099 {
3100         char *p = s;
3101         const char *str = filetype_to_str(m);
3102
3103         switch(str[0]) {
3104                 case 'd':
3105                         *p++ = 'd';
3106                         break;
3107                 case 'c':
3108                         *p++ = 'c';
3109                         break;
3110                 case 'b':
3111                         *p++ = 'b';
3112                         break;
3113                 case 'f':
3114                         *p++ = 'p';
3115                         break;
3116                 case 's':
3117                         *p++ = str[1] == 'y' ? 'l' : 's';
3118                         break;
3119                 case 'r':
3120                 default:
3121                         *p++ = '-';
3122                         break;
3123         }
3124         *p++ = rwx_to_str(m, S_IRUSR, 'r');
3125         *p++ = rwx_to_str(m, S_IWUSR, 'w');
3126         *p++ = rwx_to_str(m, S_IXUSR, 'x');
3127         *p++ = rwx_to_str(m, S_IRGRP, 'r');
3128         *p++ = rwx_to_str(m, S_IWGRP, 'w');
3129         *p++ = rwx_to_str(m, S_IXGRP, 'x');
3130         *p++ = rwx_to_str(m, S_IROTH, 'r');
3131         *p++ = rwx_to_str(m, S_IWOTH, 'w');
3132         *p++ = rwx_to_str(m, S_IXOTH, 'x');
3133         *p++ = '\0';
3134         return s;
3135 }
3136
3137 /****************************************************************************
3138  Utility function for UNIX getfacl.
3139 ****************************************************************************/
3140
3141 static char *perms_to_string(fstring permstr, unsigned char perms)
3142 {
3143         fstrcpy(permstr, "---");
3144         if (perms & SMB_POSIX_ACL_READ) {
3145                 permstr[0] = 'r';
3146         }
3147         if (perms & SMB_POSIX_ACL_WRITE) {
3148                 permstr[1] = 'w';
3149         }
3150         if (perms & SMB_POSIX_ACL_EXECUTE) {
3151                 permstr[2] = 'x';
3152         }
3153         return permstr;
3154 }
3155
3156 /****************************************************************************
3157  UNIX getfacl.
3158 ****************************************************************************/
3159
3160 static int cmd_getfacl(void)
3161 {
3162         TALLOC_CTX *ctx = talloc_tos();
3163         char *src = NULL;
3164         char *name = NULL;
3165         char *targetname = NULL;
3166         struct cli_state *targetcli;
3167         uint16 major, minor;
3168         uint32 caplow, caphigh;
3169         char *retbuf = NULL;
3170         size_t rb_size = 0;
3171         SMB_STRUCT_STAT sbuf;
3172         uint16 num_file_acls = 0;
3173         uint16 num_dir_acls = 0;
3174         uint16 i;
3175         NTSTATUS status;
3176
3177         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3178                 d_printf("getfacl filename\n");
3179                 return 1;
3180         }
3181         src = talloc_asprintf(ctx,
3182                         "%s%s",
3183                         client_get_cur_dir(),
3184                         name);
3185         if (!src) {
3186                 return 1;
3187         }
3188
3189         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3190                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3191                 return 1;
3192         }
3193
3194         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3195                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3196                 return 1;
3197         }
3198
3199         status = cli_unix_extensions_version(targetcli, &major, &minor,
3200                                              &caplow, &caphigh);
3201         if (!NT_STATUS_IS_OK(status)) {
3202                 d_printf("Can't get UNIX CIFS version from server: %s.\n",
3203                          nt_errstr(status));
3204                 return 1;
3205         }
3206
3207         if (!(caplow & CIFS_UNIX_POSIX_ACLS_CAP)) {
3208                 d_printf("This server supports UNIX extensions "
3209                         "but doesn't support POSIX ACLs.\n");
3210                 return 1;
3211         }
3212
3213         if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
3214                 d_printf("%s getfacl doing a stat on file %s\n",
3215                         cli_errstr(targetcli), src);
3216                 return 1;
3217         }
3218
3219         if (!NT_STATUS_IS_OK(cli_posix_getfacl(targetcli, targetname, ctx, &rb_size, &retbuf))) {
3220                 d_printf("%s getfacl file %s\n",
3221                         cli_errstr(targetcli), src);
3222                 return 1;
3223         }
3224
3225         /* ToDo : Print out the ACL values. */
3226         if (rb_size < 6 || SVAL(retbuf,0) != SMB_POSIX_ACL_VERSION) {
3227                 d_printf("getfacl file %s, unknown POSIX acl version %u.\n",
3228                         src, (unsigned int)CVAL(retbuf,0) );
3229                 return 1;
3230         }
3231
3232         num_file_acls = SVAL(retbuf,2);
3233         num_dir_acls = SVAL(retbuf,4);
3234         if (rb_size != SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)) {
3235                 d_printf("getfacl file %s, incorrect POSIX acl buffer size (should be %u, was %u).\n",
3236                         src,
3237                         (unsigned int)(SMB_POSIX_ACL_HEADER_SIZE + SMB_POSIX_ACL_ENTRY_SIZE*(num_file_acls+num_dir_acls)),
3238                         (unsigned int)rb_size);
3239                 return 1;
3240         }
3241
3242         d_printf("# file: %s\n", src);
3243         d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
3244
3245         if (num_file_acls == 0 && num_dir_acls == 0) {
3246                 d_printf("No acls found.\n");
3247         }
3248
3249         for (i = 0; i < num_file_acls; i++) {
3250                 uint32 uorg;
3251                 fstring permstring;
3252                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE));
3253                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3254
3255                 switch(tagtype) {
3256                         case SMB_POSIX_ACL_USER_OBJ:
3257                                 d_printf("user::");
3258                                 break;
3259                         case SMB_POSIX_ACL_USER:
3260                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3261                                 d_printf("user:%u:", uorg);
3262                                 break;
3263                         case SMB_POSIX_ACL_GROUP_OBJ:
3264                                 d_printf("group::");
3265                                 break;
3266                         case SMB_POSIX_ACL_GROUP:
3267                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3268                                 d_printf("group:%u:", uorg);
3269                                 break;
3270                         case SMB_POSIX_ACL_MASK:
3271                                 d_printf("mask::");
3272                                 break;
3273                         case SMB_POSIX_ACL_OTHER:
3274                                 d_printf("other::");
3275                                 break;
3276                         default:
3277                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3278                                         src, (unsigned int)tagtype );
3279                                 SAFE_FREE(retbuf);
3280                                 return 1;
3281                 }
3282
3283                 d_printf("%s\n", perms_to_string(permstring, perms));
3284         }
3285
3286         for (i = 0; i < num_dir_acls; i++) {
3287                 uint32 uorg;
3288                 fstring permstring;
3289                 unsigned char tagtype = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE));
3290                 unsigned char perms = CVAL(retbuf, SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+1);
3291
3292                 switch(tagtype) {
3293                         case SMB_POSIX_ACL_USER_OBJ:
3294                                 d_printf("default:user::");
3295                                 break;
3296                         case SMB_POSIX_ACL_USER:
3297                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3298                                 d_printf("default:user:%u:", uorg);
3299                                 break;
3300                         case SMB_POSIX_ACL_GROUP_OBJ:
3301                                 d_printf("default:group::");
3302                                 break;
3303                         case SMB_POSIX_ACL_GROUP:
3304                                 uorg = IVAL(retbuf,SMB_POSIX_ACL_HEADER_SIZE+((i+num_file_acls)*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3305                                 d_printf("default:group:%u:", uorg);
3306                                 break;
3307                         case SMB_POSIX_ACL_MASK:
3308                                 d_printf("default:mask::");
3309                                 break;
3310                         case SMB_POSIX_ACL_OTHER:
3311                                 d_printf("default:other::");
3312                                 break;
3313                         default:
3314                                 d_printf("getfacl file %s, incorrect POSIX acl tagtype (%u).\n",
3315                                         src, (unsigned int)tagtype );
3316                                 SAFE_FREE(retbuf);
3317                                 return 1;
3318                 }
3319
3320                 d_printf("%s\n", perms_to_string(permstring, perms));
3321         }
3322
3323         return 0;
3324 }
3325
3326 static void printf_cb(const char *buf, void *private_data)
3327 {
3328         printf("%s", buf);
3329 }
3330
3331 /****************************************************************************
3332  Get the EA list of a file
3333 ****************************************************************************/
3334
3335 static int cmd_geteas(void)
3336 {
3337         TALLOC_CTX *ctx = talloc_tos();
3338         char *src = NULL;
3339         char *name = NULL;
3340         char *targetname = NULL;
3341         struct cli_state *targetcli;
3342         NTSTATUS status;
3343         size_t i, num_eas;
3344         struct ea_struct *eas;
3345
3346         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3347                 d_printf("geteas filename\n");
3348                 return 1;
3349         }
3350         src = talloc_asprintf(ctx,
3351                         "%s%s",
3352                         client_get_cur_dir(),
3353                         name);
3354         if (!src) {
3355                 return 1;
3356         }
3357
3358         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
3359                               &targetname)) {
3360                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3361                 return 1;
3362         }
3363
3364         status = cli_get_ea_list_path(targetcli, targetname, talloc_tos(),
3365                                       &num_eas, &eas);
3366         if (!NT_STATUS_IS_OK(status)) {
3367                 d_printf("cli_get_ea_list_path: %s\n", nt_errstr(status));
3368                 return 1;
3369         }
3370
3371         for (i=0; i<num_eas; i++) {
3372                 d_printf("%s (%d) =\n", eas[i].name, (int)eas[i].flags);
3373                 dump_data_cb(eas[i].value.data, eas[i].value.length, false,
3374                              printf_cb, NULL);
3375                 d_printf("\n");
3376         }
3377
3378         TALLOC_FREE(eas);
3379
3380         return 0;
3381 }
3382
3383 /****************************************************************************
3384  Set an EA of a file
3385 ****************************************************************************/
3386
3387 static int cmd_setea(void)
3388 {
3389         TALLOC_CTX *ctx = talloc_tos();
3390         char *src = NULL;
3391         char *name = NULL;
3392         char *eaname = NULL;
3393         char *eavalue = NULL;
3394         char *targetname = NULL;
3395         struct cli_state *targetcli;
3396         NTSTATUS status;
3397
3398         if (!next_token_talloc(ctx, &cmd_ptr, &name, NULL)
3399             || !next_token_talloc(ctx, &cmd_ptr, &eaname, NULL)) {
3400                 d_printf("setea filename eaname value\n");
3401                 return 1;
3402         }
3403         if (!next_token_talloc(ctx, &cmd_ptr, &eavalue, NULL)) {
3404                 eavalue = talloc_strdup(ctx, "");
3405         }
3406         src = talloc_asprintf(ctx,
3407                         "%s%s",
3408                         client_get_cur_dir(),
3409                         name);
3410         if (!src) {
3411                 return 1;
3412         }
3413
3414         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli,
3415                               &targetname)) {
3416                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3417                 return 1;
3418         }
3419
3420         status =  cli_set_ea_path(targetcli, targetname, eaname, eavalue,
3421                                   strlen(eavalue));
3422         if (!NT_STATUS_IS_OK(status)) {
3423                 d_printf("set_ea %s: %s\n", src, nt_errstr(status));
3424                 return 1;
3425         }
3426
3427         return 0;
3428 }
3429
3430 /****************************************************************************
3431  UNIX stat.
3432 ****************************************************************************/
3433
3434 static int cmd_stat(void)
3435 {
3436         TALLOC_CTX *ctx = talloc_tos();
3437         char *src = NULL;
3438         char *name = NULL;
3439         char *targetname = NULL;
3440         struct cli_state *targetcli;
3441         fstring mode_str;
3442         SMB_STRUCT_STAT sbuf;
3443         struct tm *lt;
3444         time_t tmp_time;
3445
3446         if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
3447                 d_printf("stat file\n");
3448                 return 1;
3449         }
3450         src = talloc_asprintf(ctx,
3451                         "%s%s",
3452                         client_get_cur_dir(),
3453                         name);
3454         if (!src) {
3455                 return 1;
3456         }
3457
3458         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3459                 d_printf("stat %s: %s\n", src, cli_errstr(cli));
3460                 return 1;
3461         }
3462
3463         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3464                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3465                 return 1;
3466         }
3467
3468         if (!NT_STATUS_IS_OK(cli_posix_stat(targetcli, targetname, &sbuf))) {
3469                 d_printf("%s stat file %s\n",
3470                         cli_errstr(targetcli), src);
3471                 return 1;
3472         }
3473
3474         /* Print out the stat values. */
3475         d_printf("File: %s\n", src);
3476         d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
3477                 (double)sbuf.st_ex_size,
3478                 (unsigned int)sbuf.st_ex_blocks,
3479                 filetype_to_str(sbuf.st_ex_mode));
3480
3481 #if defined(S_ISCHR) && defined(S_ISBLK)
3482         if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
3483                 d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
3484                         (double)sbuf.st_ex_ino,
3485                         (unsigned int)sbuf.st_ex_nlink,
3486                         unix_dev_major(sbuf.st_ex_rdev),
3487                         unix_dev_minor(sbuf.st_ex_rdev));
3488         } else
3489 #endif
3490                 d_printf("Inode: %.0f\tLinks: %u\n",
3491                         (double)sbuf.st_ex_ino,
3492                         (unsigned int)sbuf.st_ex_nlink);
3493
3494         d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
3495                 ((int)sbuf.st_ex_mode & 0777),
3496                 unix_mode_to_str(mode_str, sbuf.st_ex_mode),
3497                 (unsigned int)sbuf.st_ex_uid,
3498                 (unsigned int)sbuf.st_ex_gid);
3499
3500         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
3501         lt = localtime(&tmp_time);
3502         if (lt) {
3503                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3504         } else {
3505                 fstrcpy(mode_str, "unknown");
3506         }
3507         d_printf("Access: %s\n", mode_str);
3508
3509         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
3510         lt = localtime(&tmp_time);
3511         if (lt) {
3512                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3513         } else {
3514                 fstrcpy(mode_str, "unknown");
3515         }
3516         d_printf("Modify: %s\n", mode_str);
3517
3518         tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
3519         lt = localtime(&tmp_time);
3520         if (lt) {
3521                 strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
3522         } else {
3523                 fstrcpy(mode_str, "unknown");
3524         }
3525         d_printf("Change: %s\n", mode_str);
3526
3527         return 0;
3528 }
3529
3530
3531 /****************************************************************************
3532  UNIX chown.
3533 ****************************************************************************/
3534
3535 static int cmd_chown(void)
3536 {
3537         TALLOC_CTX *ctx = talloc_tos();
3538         char *src = NULL;
3539         uid_t uid;
3540         gid_t gid;
3541         char *buf, *buf2, *buf3;
3542         struct cli_state *targetcli;
3543         char *targetname = NULL;
3544
3545         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3546             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL) ||
3547             !next_token_talloc(ctx, &cmd_ptr,&buf3,NULL)) {
3548                 d_printf("chown uid gid file\n");
3549                 return 1;
3550         }
3551
3552         uid = (uid_t)atoi(buf);
3553         gid = (gid_t)atoi(buf2);
3554
3555         src = talloc_asprintf(ctx,
3556                         "%s%s",
3557                         client_get_cur_dir(),
3558                         buf3);
3559         if (!src) {
3560                 return 1;
3561         }
3562         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname) ) {
3563                 d_printf("chown %s: %s\n", src, cli_errstr(cli));
3564                 return 1;
3565         }
3566
3567         if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
3568                 d_printf("Server doesn't support UNIX CIFS calls.\n");
3569                 return 1;
3570         }
3571
3572         if (!NT_STATUS_IS_OK(cli_posix_chown(targetcli, targetname, uid, gid))) {
3573                 d_printf("%s chown file %s uid=%d, gid=%d\n",
3574                         cli_errstr(targetcli), src, (int)uid, (int)gid);
3575                 return 1;
3576         }
3577
3578         return 0;
3579 }
3580
3581 /****************************************************************************
3582  Rename some file.
3583 ****************************************************************************/
3584
3585 static int cmd_rename(void)
3586 {
3587         TALLOC_CTX *ctx = talloc_tos();
3588         char *src, *dest;
3589         char *buf, *buf2;
3590         struct cli_state *targetcli;
3591         char *targetsrc;
3592         char *targetdest;
3593
3594         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3595             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3596                 d_printf("rename <src> <dest>\n");
3597                 return 1;
3598         }
3599
3600         src = talloc_asprintf(ctx,
3601                         "%s%s",
3602                         client_get_cur_dir(),
3603                         buf);
3604         if (!src) {
3605                 return 1;
3606         }
3607
3608         dest = talloc_asprintf(ctx,
3609                         "%s%s",
3610                         client_get_cur_dir(),
3611                         buf2);
3612         if (!dest) {
3613                 return 1;
3614         }
3615
3616         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetsrc)) {
3617                 d_printf("rename %s: %s\n", src, cli_errstr(cli));
3618                 return 1;
3619         }
3620
3621         if (!cli_resolve_path(ctx, "", auth_info, cli, dest, &targetcli, &targetdest)) {
3622                 d_printf("rename %s: %s\n", dest, cli_errstr(cli));
3623                 return 1;
3624         }
3625
3626         if (!NT_STATUS_IS_OK(cli_rename(targetcli, targetsrc, targetdest))) {
3627                 d_printf("%s renaming files %s -> %s \n",
3628                         cli_errstr(targetcli),
3629                         targetsrc,
3630                         targetdest);
3631                 return 1;
3632         }
3633
3634         return 0;
3635 }
3636
3637 /****************************************************************************
3638  Print the volume name.
3639 ****************************************************************************/
3640
3641 static int cmd_volume(void)
3642 {
3643         fstring volname;
3644         uint32 serial_num;
3645         time_t create_date;
3646         NTSTATUS status;
3647
3648         status = cli_get_fs_volume_info(cli, volname, &serial_num,
3649                                         &create_date);
3650         if (!NT_STATUS_IS_OK(status)) {
3651                 d_printf("Error %s getting volume info\n", nt_errstr(status));
3652                 return 1;
3653         }
3654
3655         d_printf("Volume: |%s| serial number 0x%x\n",
3656                         volname, (unsigned int)serial_num);
3657         return 0;
3658 }
3659
3660 /****************************************************************************
3661  Hard link files using the NT call.
3662 ****************************************************************************/
3663
3664 static int cmd_hardlink(void)
3665 {
3666         TALLOC_CTX *ctx = talloc_tos();
3667         char *src, *dest;
3668         char *buf, *buf2;
3669         struct cli_state *targetcli;
3670         char *targetname;
3671
3672         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL) ||
3673             !next_token_talloc(ctx, &cmd_ptr,&buf2,NULL)) {
3674                 d_printf("hardlink <src> <dest>\n");
3675                 return 1;
3676         }
3677
3678         src = talloc_asprintf(ctx,
3679                         "%s%s",
3680                         client_get_cur_dir(),
3681                         buf);
3682         if (!src) {
3683                 return 1;
3684         }
3685
3686         dest = talloc_asprintf(ctx,
3687                         "%s%s",
3688                         client_get_cur_dir(),
3689                         buf2);
3690         if (!dest) {
3691                 return 1;
3692         }
3693
3694         if (!cli_resolve_path(ctx, "", auth_info, cli, src, &targetcli, &targetname)) {
3695                 d_printf("hardlink %s: %s\n", src, cli_errstr(cli));
3696                 return 1;
3697         }
3698
3699         if (!NT_STATUS_IS_OK(cli_nt_hardlink(targetcli, targetname, dest))) {
3700                 d_printf("%s doing an NT hard link of files\n",cli_errstr(targetcli));
3701                 return 1;
3702         }
3703
3704         return 0;
3705 }
3706
3707 /****************************************************************************
3708  Toggle the prompt flag.
3709 ****************************************************************************/
3710
3711 static int cmd_prompt(void)
3712 {
3713         prompt = !prompt;
3714         DEBUG(2,("prompting is now %s\n",prompt?"on":"off"));
3715         return 1;
3716 }
3717
3718 /****************************************************************************
3719  Set the newer than time.
3720 ****************************************************************************/
3721
3722 static int cmd_newer(void)
3723 {
3724         TALLOC_CTX *ctx = talloc_tos();
3725         char *buf;
3726         bool ok;
3727         SMB_STRUCT_STAT sbuf;
3728
3729         ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
3730         if (ok && (sys_stat(buf, &sbuf, false) == 0)) {
3731                 newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
3732                 DEBUG(1,("Getting files newer than %s",
3733                          time_to_asc(newer_than)));
3734         } else {
3735                 newer_than = 0;
3736         }
3737
3738         if (ok && newer_than == 0) {
3739                 d_printf("Error setting newer-than time\n");
3740                 return 1;
3741         }
3742
3743         return 0;
3744 }
3745
3746 /****************************************************************************
3747  Set the archive level.
3748 ****************************************************************************/
3749
3750 static int cmd_archive(void)
3751 {
3752         TALLOC_CTX *ctx = talloc_tos();
3753         char *buf;
3754
3755         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3756                 archive_level = atoi(buf);
3757         } else {
3758                 d_printf("Archive level is %d\n",archive_level);
3759         }
3760
3761         return 0;
3762 }
3763
3764 /****************************************************************************
3765  Toggle the lowercaseflag.
3766 ****************************************************************************/
3767
3768 static int cmd_lowercase(void)
3769 {
3770         lowercase = !lowercase;
3771         DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off"));
3772         return 0;
3773 }
3774
3775 /****************************************************************************
3776  Toggle the case sensitive flag.
3777 ****************************************************************************/
3778
3779 static int cmd_setcase(void)
3780 {
3781         bool orig_case_sensitive = cli_set_case_sensitive(cli, false);
3782
3783         cli_set_case_sensitive(cli, !orig_case_sensitive);
3784         DEBUG(2,("filename case sensitivity is now %s\n",!orig_case_sensitive ?
3785                 "on":"off"));
3786         return 0;
3787 }
3788
3789 /****************************************************************************
3790  Toggle the showacls flag.
3791 ****************************************************************************/
3792
3793 static int cmd_showacls(void)
3794 {
3795         showacls = !showacls;
3796         DEBUG(2,("showacls is now %s\n",showacls?"on":"off"));
3797         return 0;
3798 }
3799
3800
3801 /****************************************************************************
3802  Toggle the recurse flag.
3803 ****************************************************************************/
3804
3805 static int cmd_recurse(void)
3806 {
3807         recurse = !recurse;
3808         DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off"));
3809         return 0;
3810 }
3811
3812 /****************************************************************************
3813  Toggle the translate flag.
3814 ****************************************************************************/
3815
3816 static int cmd_translate(void)
3817 {
3818         translation = !translation;
3819         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
3820                  translation?"on":"off"));
3821         return 0;
3822 }
3823
3824 /****************************************************************************
3825  Do the lcd command.
3826  ****************************************************************************/
3827
3828 static int cmd_lcd(void)
3829 {
3830         TALLOC_CTX *ctx = talloc_tos();
3831         char *buf;
3832         char *d;
3833
3834         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
3835                 if (chdir(buf) == -1) {
3836                         d_printf("chdir to %s failed (%s)\n",
3837                                 buf, strerror(errno));
3838                 }
3839         }
3840         d = TALLOC_ARRAY(ctx, char, PATH_MAX+1);
3841         if (!d) {
3842                 return 1;
3843         }
3844         DEBUG(2,("the local directory is now %s\n",sys_getwd(d)));
3845         return 0;
3846 }
3847
3848 /****************************************************************************
3849  Get a file restarting at end of local file.
3850  ****************************************************************************/
3851
3852 static int cmd_reget(void)
3853 {
3854         TALLOC_CTX *ctx = talloc_tos();
3855         char *local_name = NULL;
3856         char *remote_name = NULL;
3857         char *fname = NULL;
3858         char *p = NULL;
3859
3860         remote_name = talloc_strdup(ctx, client_get_cur_dir());
3861         if (!remote_name) {
3862                 return 1;
3863         }
3864
3865         if (!next_token_talloc(ctx, &cmd_ptr, &fname, NULL)) {
3866                 d_printf("reget <filename>\n");
3867                 return 1;
3868         }
3869         remote_name = talloc_asprintf_append(remote_name, "%s", fname);
3870         if (!remote_name) {
3871                 return 1;
3872         }
3873         remote_name = clean_name(ctx,remote_name);
3874         if (!remote_name) {
3875                 return 1;
3876         }
3877
3878         local_name = fname;
3879         next_token_talloc(ctx, &cmd_ptr, &p, NULL);
3880         if (p) {
3881                 local_name = p;
3882         }
3883
3884         return do_get(remote_name, local_name, true);
3885 }
3886
3887 /****************************************************************************
3888  Put a file restarting at end of local file.
3889  ****************************************************************************/
3890
3891 static int cmd_reput(void)
3892 {
3893         TALLOC_CTX *ctx = talloc_tos();
3894         char *local_name = NULL;
3895         char *remote_name = NULL;
3896         char *buf;
3897         SMB_STRUCT_STAT st;
3898
3899         remote_name = talloc_strdup(ctx, client_get_cur_dir());
3900         if (!remote_name) {
3901                 return 1;
3902         }
3903
3904         if (!next_token_talloc(ctx, &cmd_ptr, &local_name, NULL)) {
3905                 d_printf("reput <filename>\n");
3906                 return 1;
3907         }
3908
3909         if (!file_exist_stat(local_name, &st, false)) {
3910                 d_printf("%s does not exist\n", local_name);
3911                 return 1;
3912         }
3913
3914         if (next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
3915                 remote_name = talloc_asprintf_append(remote_name,
3916                                                 "%s", buf);
3917         } else {
3918                 remote_name = talloc_asprintf_append(remote_name,
3919                                                 "%s", local_name);
3920         }
3921         if (!remote_name) {
3922                 return 1;
3923         }
3924
3925         remote_name = clean_name(ctx, remote_name);
3926         if (!remote_name) {
3927                 return 1;
3928         }
3929
3930         return do_put(remote_name, local_name, true);
3931 }
3932
3933 /****************************************************************************
3934  List a share name.
3935  ****************************************************************************/
3936
3937 static void browse_fn(const char *name, uint32 m,
3938                       const char *comment, void *state)
3939 {
3940         const char *typestr = "";
3941
3942         switch (m & 7) {
3943         case STYPE_DISKTREE:
3944                 typestr = "Disk";
3945                 break;
3946         case STYPE_PRINTQ:
3947                 typestr = "Printer";
3948                 break;
3949         case STYPE_DEVICE:
3950                 typestr = "Device";
3951                 break;
3952         case STYPE_IPC:
3953                 typestr = "IPC";
3954                 break;
3955         }
3956         /* FIXME: If the remote machine returns non-ascii characters
3957            in any of these fields, they can corrupt the output.  We
3958            should remove them. */
3959         if (!grepable) {
3960                 d_printf("\t%-15s %-10.10s%s\n",
3961                         name,typestr,comment);
3962         } else {
3963                 d_printf ("%s|%s|%s\n",typestr,name,comment);
3964         }
3965 }
3966
3967 static bool browse_host_rpc(bool sort)
3968 {
3969         NTSTATUS status;
3970         struct rpc_pipe_client *pipe_hnd = NULL;
3971         TALLOC_CTX *frame = talloc_stackframe();
3972         WERROR werr;
3973         struct srvsvc_NetShareInfoCtr info_ctr;
3974         struct srvsvc_NetShareCtr1 ctr1;
3975         uint32_t resume_handle = 0;
3976         uint32_t total_entries = 0;
3977         int i;
3978         struct dcerpc_binding_handle *b;
3979
3980         status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
3981                                           &pipe_hnd);
3982
3983         if (!NT_STATUS_IS_OK(status)) {
3984                 DEBUG(10, ("Could not connect to srvsvc pipe: %s\n",
3985                            nt_errstr(status)));
3986                 TALLOC_FREE(frame);
3987                 return false;
3988         }
3989
3990         b = pipe_hnd->binding_handle;
3991
3992         ZERO_STRUCT(info_ctr);
3993         ZERO_STRUCT(ctr1);
3994
3995         info_ctr.level = 1;
3996         info_ctr.ctr.ctr1 = &ctr1;
3997
3998         status = dcerpc_srvsvc_NetShareEnumAll(b, frame,
3999                                               pipe_hnd->desthost,
4000                                               &info_ctr,
4001                                               0xffffffff,
4002                                               &total_entries,
4003                                               &resume_handle,
4004                                               &werr);
4005
4006         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) {
4007                 TALLOC_FREE(pipe_hnd);
4008                 TALLOC_FREE(frame);
4009                 return false;
4010         }
4011
4012         for (i=0; i < info_ctr.ctr.ctr1->count; i++) {
4013                 struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i];
4014                 browse_fn(info.name, info.type, info.comment, NULL);
4015         }
4016
4017         TALLOC_FREE(pipe_hnd);
4018         TALLOC_FREE(frame);
4019         return true;
4020 }
4021
4022 /****************************************************************************
4023  Try and browse available connections on a host.
4024 ****************************************************************************/
4025
4026 static bool browse_host(bool sort)
4027 {
4028         int ret;
4029         if (!grepable) {
4030                 d_printf("\n\tSharename       Type      Comment\n");
4031                 d_printf("\t---------       ----      -------\n");
4032         }
4033
4034         if (browse_host_rpc(sort)) {
4035                 return true;
4036         }
4037
4038         if((ret = cli_RNetShareEnum(cli, browse_fn, NULL)) == -1)
4039                 d_printf("Error returning browse list: %s\n", cli_errstr(cli));
4040
4041         return (ret != -1);
4042 }
4043
4044 /****************************************************************************
4045  List a server name.
4046 ****************************************************************************/
4047
4048 static void server_fn(const char *name, uint32 m,
4049                       const char *comment, void *state)
4050 {
4051
4052         if (!grepable){
4053                 d_printf("\t%-16s     %s\n", name, comment);
4054         } else {
4055                 d_printf("%s|%s|%s\n",(char *)state, name, comment);
4056         }
4057 }
4058
4059 /****************************************************************************
4060  Try and browse available connections on a host.
4061 ****************************************************************************/
4062
4063 static bool list_servers(const char *wk_grp)
4064 {
4065         fstring state;
4066
4067         if (!cli->server_domain)
4068                 return false;
4069
4070         if (!grepable) {
4071                 d_printf("\n\tServer               Comment\n");
4072                 d_printf("\t---------            -------\n");
4073         };
4074         fstrcpy( state, "Server" );
4075         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_ALL, server_fn,
4076                           state);
4077
4078         if (!grepable) {
4079                 d_printf("\n\tWorkgroup            Master\n");
4080                 d_printf("\t---------            -------\n");
4081         };
4082
4083         fstrcpy( state, "Workgroup" );
4084         cli_NetServerEnum(cli, cli->server_domain, SV_TYPE_DOMAIN_ENUM,
4085                           server_fn, state);
4086         return true;
4087 }
4088
4089 /****************************************************************************
4090  Print or set current VUID
4091 ****************************************************************************/
4092
4093 static int cmd_vuid(void)
4094 {
4095         TALLOC_CTX *ctx = talloc_tos();
4096         char *buf;
4097
4098         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4099                 d_printf("Current VUID is %d\n", cli->vuid);
4100                 return 0;
4101         }
4102
4103         cli->vuid = atoi(buf);
4104         return 0;
4105 }
4106
4107 /****************************************************************************
4108  Setup a new VUID, by issuing a session setup
4109 ****************************************************************************/
4110
4111 static int cmd_logon(void)
4112 {
4113         TALLOC_CTX *ctx = talloc_tos();
4114         char *l_username, *l_password;
4115         NTSTATUS nt_status;
4116
4117         if (!next_token_talloc(ctx, &cmd_ptr,&l_username,NULL)) {
4118                 d_printf("logon <username> [<password>]\n");
4119                 return 0;
4120         }
4121
4122         if (!next_token_talloc(ctx, &cmd_ptr,&l_password,NULL)) {
4123                 char *pass = getpass("Password: ");
4124                 if (pass) {
4125                         l_password = talloc_strdup(ctx,pass);
4126                 }
4127         }
4128         if (!l_password) {
4129                 return 1;
4130         }
4131
4132         nt_status = cli_session_setup(cli, l_username,
4133                                       l_password, strlen(l_password),
4134                                       l_password, strlen(l_password),
4135                                       lp_workgroup());
4136         if (!NT_STATUS_IS_OK(nt_status)) {
4137                 d_printf("session setup failed: %s\n", nt_errstr(nt_status));
4138                 return -1;
4139         }
4140
4141         d_printf("Current VUID is %d\n", cli->vuid);
4142         return 0;
4143 }
4144
4145
4146 /****************************************************************************
4147  list active connections
4148 ****************************************************************************/
4149
4150 static int cmd_list_connect(void)
4151 {
4152         cli_cm_display(cli);
4153         return 0;
4154 }
4155
4156 /****************************************************************************
4157  display the current active client connection
4158 ****************************************************************************/
4159
4160 static int cmd_show_connect( void )
4161 {
4162         TALLOC_CTX *ctx = talloc_tos();
4163         struct cli_state *targetcli;
4164         char *targetpath;
4165
4166         if (!cli_resolve_path(ctx, "", auth_info, cli, client_get_cur_dir(),
4167                                 &targetcli, &targetpath ) ) {
4168                 d_printf("showconnect %s: %s\n", cur_dir, cli_errstr(cli));
4169                 return 1;
4170         }
4171
4172         d_printf("//%s/%s\n", targetcli->desthost, targetcli->share);
4173         return 0;
4174 }
4175
4176 /****************************************************************************
4177  iosize command
4178 ***************************************************************************/
4179
4180 int cmd_iosize(void)
4181 {
4182         TALLOC_CTX *ctx = talloc_tos();
4183         char *buf;
4184         int iosize;
4185
4186         if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4187                 if (!smb_encrypt) {
4188                         d_printf("iosize <n> or iosize 0x<n>. "
4189                                 "Minimum is 16384 (0x4000), "
4190                                 "max is 16776960 (0xFFFF00)\n");
4191                 } else {
4192                         d_printf("iosize <n> or iosize 0x<n>. "
4193                                 "(Encrypted connection) ,"
4194                                 "Minimum is 16384 (0x4000), "
4195                                 "max is 130048 (0x1FC00)\n");
4196                 }
4197                 return 1;
4198         }
4199
4200         iosize = strtol(buf,NULL,0);
4201         if (smb_encrypt && (iosize < 0x4000 || iosize > 0xFC00)) {
4202                 d_printf("iosize out of range for encrypted "
4203                         "connection (min = 16384 (0x4000), "
4204                         "max = 130048 (0x1FC00)");
4205                 return 1;
4206         } else if (!smb_encrypt && (iosize < 0x4000 || iosize > 0xFFFF00)) {
4207                 d_printf("iosize out of range (min = 16384 (0x4000), "
4208                         "max = 16776960 (0xFFFF00)");
4209                 return 1;
4210         }
4211
4212         io_bufsize = iosize;
4213         d_printf("iosize is now %d\n", io_bufsize);
4214         return 0;
4215 }
4216
4217 /****************************************************************************
4218 history
4219 ****************************************************************************/
4220 static int cmd_history(void)
4221 {
4222 #if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
4223         HIST_ENTRY **hlist;
4224         int i;
4225
4226         hlist = history_list();
4227
4228         for (i = 0; hlist && hlist[i]; i++) {
4229                 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
4230         }
4231 #else
4232         DEBUG(0,("no history without readline support\n"));
4233 #endif
4234
4235         return 0;
4236 }
4237
4238 /* Some constants for completing filename arguments */
4239
4240 #define COMPL_NONE        0          /* No completions */
4241 #define COMPL_REMOTE      1          /* Complete remote filename */
4242 #define COMPL_LOCAL       2          /* Complete local filename */
4243
4244 /* This defines the commands supported by this client.
4245  * NOTE: The "!" must be the last one in the list because it's fn pointer
4246  *       field is NULL, and NULL in that field is used in process_tok()
4247  *       (below) to indicate the end of the list.  crh
4248  */
4249 static struct {
4250         const char *name;
4251         int (*fn)(void);
4252         const char *description;
4253         char compl_args[2];      /* Completion argument info */
4254 } commands[] = {
4255   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
4256   {"allinfo",cmd_allinfo,"<file> show all available info",
4257    {COMPL_NONE,COMPL_NONE}},
4258   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
4259   {"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
4260   {"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
4261   {"cancel",cmd_cancel,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
4262   {"case_sensitive",cmd_setcase,"toggle the case sensitive flag to server",{COMPL_NONE,COMPL_NONE}},
4263   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
4264   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
4265   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
4266   {"close",cmd_close,"<fid> close a file given a fid",{COMPL_REMOTE,COMPL_REMOTE}},
4267   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
4268   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
4269   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
4270   {"echo",cmd_echo,"ping the server",{COMPL_NONE,COMPL_NONE}},
4271   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
4272   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
4273   {"getfacl",cmd_getfacl,"<file name> get the POSIX ACL on a file (UNIX extensions only)",{COMPL_REMOTE,COMPL_LOCAL}},
4274   {"geteas", cmd_geteas, "<file name> get the EA list of a file",
4275    {COMPL_REMOTE, COMPL_LOCAL}},
4276   {"hardlink",cmd_hardlink,"<src> <dest> create a Windows hard link",{COMPL_REMOTE,COMPL_REMOTE}},
4277   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
4278   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
4279   {"iosize",cmd_iosize,"iosize <number> (default 64512)",{COMPL_NONE,COMPL_NONE}},
4280   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
4281   {"link",cmd_link,"<oldname> <newname> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
4282   {"lock",cmd_lock,"lock <fnum> [r|w] <hex-start> <hex-len> : set a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
4283   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
4284   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
4285   {"l",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
4286   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
4287   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
4288   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
4289   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
4290   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
4291   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
4292   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
4293   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
4294   {"posix", cmd_posix, "turn on all POSIX capabilities", {COMPL_REMOTE,COMPL_NONE}},
4295   {"posix_encrypt",cmd_posix_encrypt,"<domain> <user> <password> start up transport encryption",{COMPL_REMOTE,COMPL_NONE}},
4296   {"posix_open",cmd_posix_open,"<name> 0<mode> open_flags mode open a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
4297   {"posix_mkdir",cmd_posix_mkdir,"<name> 0<mode> creates a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
4298   {"posix_rmdir",cmd_posix_rmdir,"<name> removes a directory using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
4299   {"posix_unlink",cmd_posix_unlink,"<name> removes a file using POSIX interface",{COMPL_REMOTE,COMPL_NONE}},
4300   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
4301   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
4302   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
4303   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
4304   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
4305   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
4306   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
4307   {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
4308   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
4309   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
4310   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
4311   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
4312   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
4313   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
4314   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
4315   {"showacls",cmd_showacls,"toggle if ACLs are shown or not",{COMPL_NONE,COMPL_NONE}},  
4316   {"setea", cmd_setea, "<file name> <eaname> <eaval> Set an EA of a file",
4317    {COMPL_REMOTE, COMPL_LOCAL}},
4318   {"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
4319   {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
4320   {"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
4321   {"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
4322   {"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
4323   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
4324   {"unlock",cmd_unlock,"unlock <fnum> <hex-start> <hex-len> : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}},
4325   {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}},
4326   {"vuid",cmd_vuid,"change current vuid",{COMPL_NONE,COMPL_NONE}},
4327   {"wdel",cmd_wdel,"<attrib> <mask> wildcard delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
4328   {"logon",cmd_logon,"establish new logon",{COMPL_NONE,COMPL_NONE}},
4329   {"listconnect",cmd_list_connect,"list open connections",{COMPL_NONE,COMPL_NONE}},
4330   {"showconnect",cmd_show_connect,"display the current active connection",{COMPL_NONE,COMPL_NONE}},
4331   {"..",cmd_cd_oneup,"change the remote directory (up one level)",{COMPL_REMOTE,COMPL_NONE}},
4332
4333   /* Yes, this must be here, see crh's comment above. */
4334   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
4335   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
4336 };
4337
4338 /*******************************************************************
4339  Lookup a command string in the list of commands, including
4340  abbreviations.
4341 ******************************************************************/
4342
4343 static int process_tok(char *tok)
4344 {
4345         int i = 0, matches = 0;
4346         int cmd=0;
4347         int tok_len = strlen(tok);
4348
4349         while (commands[i].fn != NULL) {
4350                 if (strequal(commands[i].name,tok)) {
4351                         matches = 1;
4352                         cmd = i;
4353                         break;
4354                 } else if (strnequal(commands[i].name, tok, tok_len)) {
4355                         matches++;
4356                         cmd = i;
4357                 }
4358                 i++;
4359         }
4360
4361         if (matches == 0)
4362                 return(-1);
4363         else if (matches == 1)
4364                 return(cmd);
4365         else
4366                 return(-2);
4367 }
4368
4369 /****************************************************************************
4370  Help.
4371 ****************************************************************************/
4372
4373 static int cmd_help(void)
4374 {
4375         TALLOC_CTX *ctx = talloc_tos();
4376         int i=0,j;
4377         char *buf;
4378
4379         if (next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
4380                 if ((i = process_tok(buf)) >= 0)
4381                         d_printf("HELP %s:\n\t%s\n\n",
4382                                 commands[i].name,commands[i].description);
4383         } else {
4384                 while (commands[i].description) {
4385                         for (j=0; commands[i].description && (j<5); j++) {
4386                                 d_printf("%-15s",commands[i].name);
4387                                 i++;
4388                         }
4389                         d_printf("\n");
4390                 }
4391         }
4392         return 0;
4393 }
4394
4395 /****************************************************************************
4396  Process a -c command string.
4397 ****************************************************************************/
4398
4399 static int process_command_string(const char *cmd_in)
4400 {
4401         TALLOC_CTX *ctx = talloc_tos();
4402         char *cmd = talloc_strdup(ctx, cmd_in);
4403         int rc = 0;
4404
4405         if (!cmd) {
4406                 return 1;
4407         }
4408         /* establish the connection if not already */
4409
4410         if (!cli) {
4411                 cli = cli_cm_open(talloc_tos(), NULL,
4412                                 have_ip ? dest_ss_str : desthost,
4413                                 service, auth_info,
4414                                 true, smb_encrypt,
4415                                 max_protocol, port, name_type);
4416                 if (!cli) {
4417                         return 1;
4418                 }
4419         }
4420
4421         while (cmd[0] != '\0')    {
4422                 char *line;
4423                 char *p;
4424                 char *tok;
4425                 int i;
4426
4427                 if ((p = strchr_m(cmd, ';')) == 0) {
4428                         line = cmd;
4429                         cmd += strlen(cmd);
4430                 } else {
4431                         *p = '\0';
4432                         line = cmd;
4433                         cmd = p + 1;
4434                 }
4435
4436                 /* and get the first part of the command */
4437                 cmd_ptr = line;
4438                 if (!next_token_talloc(ctx, &cmd_ptr,&tok,NULL)) {
4439                         continue;
4440                 }
4441
4442                 if ((i = process_tok(tok)) >= 0) {
4443                         rc = commands[i].fn();
4444                 } else if (i == -2) {
4445                         d_printf("%s: command abbreviation ambiguous\n",tok);
4446                 } else {
4447                         d_printf("%s: command not found\n",tok);
4448                 }
4449         }
4450
4451         return rc;
4452 }
4453
4454 #define MAX_COMPLETIONS 100
4455
4456 struct completion_remote {
4457         char *dirmask;
4458         char **matches;
4459         int count, samelen;
4460         const char *text;
4461         int len;
4462 };
4463
4464 static NTSTATUS completion_remote_filter(const char *mnt,
4465                                 struct file_info *f,
4466                                 const char *mask,
4467                                 void *state)
4468 {
4469         struct completion_remote *info = (struct completion_remote *)state;
4470
4471         if (info->count >= MAX_COMPLETIONS - 1) {
4472                 return NT_STATUS_OK;
4473         }
4474         if (strncmp(info->text, f->name, info->len) != 0) {
4475                 return NT_STATUS_OK;
4476         }
4477         if (ISDOT(f->name) || ISDOTDOT(f->name)) {
4478                 return NT_STATUS_OK;
4479         }
4480
4481         if ((info->dirmask[0] == 0) && !(f->mode & aDIR))
4482                 info->matches[info->count] = SMB_STRDUP(f->name);
4483         else {
4484                 TALLOC_CTX *ctx = talloc_stackframe();
4485                 char *tmp;
4486
4487                 tmp = talloc_strdup(ctx,info->dirmask);
4488                 if (!tmp) {
4489                         TALLOC_FREE(ctx);
4490                         return NT_STATUS_NO_MEMORY;
4491                 }
4492                 tmp = talloc_asprintf_append(tmp, "%s", f->name);
4493                 if (!tmp) {
4494                         TALLOC_FREE(ctx);
4495                         return NT_STATUS_NO_MEMORY;
4496                 }
4497                 if (f->mode & aDIR) {
4498                         tmp = talloc_asprintf_append(tmp, "%s",
4499                                                      CLI_DIRSEP_STR);
4500                 }
4501                 if (!tmp) {
4502                         TALLOC_FREE(ctx);
4503                         return NT_STATUS_NO_MEMORY;
4504                 }
4505                 info->matches[info->count] = SMB_STRDUP(tmp);
4506                 TALLOC_FREE(ctx);
4507         }
4508         if (info->matches[info->count] == NULL) {
4509                 return NT_STATUS_OK;
4510         }
4511         if (f->mode & aDIR) {
4512                 smb_readline_ca_char(0);
4513         }
4514         if (info->count == 1) {
4515                 info->samelen = strlen(info->matches[info->count]);
4516         } else {
4517                 while (strncmp(info->matches[info->count],
4518                                info->matches[info->count-1],
4519                                info->samelen) != 0) {
4520                         info->samelen--;
4521                 }
4522         }
4523         info->count++;
4524         return NT_STATUS_OK;
4525 }
4526
4527 static char **remote_completion(const char *text, int len)
4528 {
4529         TALLOC_CTX *ctx = talloc_stackframe();
4530         char *dirmask = NULL;
4531         char *targetpath = NULL;
4532         struct cli_state *targetcli = NULL;
4533         int i;
4534         struct completion_remote info = { NULL, NULL, 1, 0, NULL, 0 };
4535         NTSTATUS status;
4536
4537         /* can't have non-static initialisation on Sun CC, so do it
4538            at run time here */
4539         info.samelen = len;
4540         info.text = text;
4541         info.len = len;
4542
4543         info.matches = SMB_MALLOC_ARRAY(char *,MAX_COMPLETIONS);
4544         if (!info.matches) {
4545                 TALLOC_FREE(ctx);
4546                 return NULL;
4547         }
4548
4549         /*
4550          * We're leaving matches[0] free to fill it later with the text to
4551          * display: Either the one single match or the longest common subset
4552          * of the matches.
4553          */
4554         info.matches[0] = NULL;
4555         info.count = 1;
4556
4557         for (i = len-1; i >= 0; i--) {
4558                 if ((text[i] == '/') || (text[i] == CLI_DIRSEP_CHAR)) {
4559                         break;
4560                 }
4561         }
4562
4563         info.text = text+i+1;
4564         info.samelen = info.len = len-i-1;
4565
4566         if (i > 0) {
4567                 info.dirmask = SMB_MALLOC_ARRAY(char, i+2);
4568                 if (!info.dirmask) {
4569                         goto cleanup;
4570                 }
4571                 strncpy(info.dirmask, text, i+1);
4572                 info.dirmask[i+1] = 0;
4573                 dirmask = talloc_asprintf(ctx,
4574                                         "%s%*s*",
4575                                         client_get_cur_dir(),
4576                                         i-1,
4577                                         text);
4578         } else {
4579                 info.dirmask = SMB_STRDUP("");
4580                 if (!info.dirmask) {
4581                         goto cleanup;
4582                 }
4583                 dirmask = talloc_asprintf(ctx,
4584                                         "%s*",
4585                                         client_get_cur_dir());
4586         }
4587         if (!dirmask) {
4588                 goto cleanup;
4589         }
4590
4591         if (!cli_resolve_path(ctx, "", auth_info, cli, dirmask, &targetcli, &targetpath)) {
4592                 goto cleanup;
4593         }
4594         status = cli_list(targetcli, targetpath, aDIR | aSYSTEM | aHIDDEN,
4595                           completion_remote_filter, (void *)&info);
4596         if (!NT_STATUS_IS_OK(status)) {
4597                 goto cleanup;
4598         }
4599
4600         if (info.count == 1) {
4601                 /*
4602                  * No matches at all, NULL indicates there is nothing
4603                  */
4604                 SAFE_FREE(info.matches[0]);
4605                 SAFE_FREE(info.matches);
4606                 TALLOC_FREE(ctx);
4607                 return NULL;
4608         }
4609
4610         if (info.count == 2) {
4611                 /*
4612                  * Exactly one match in matches[1], indicate this is the one
4613                  * in matches[0].
4614                  */
4615                 info.matches[0] = info.matches[1];
4616                 info.matches[1] = NULL;
4617                 info.count -= 1;
4618                 TALLOC_FREE(ctx);
4619                 return info.matches;
4620         }
4621
4622         /*
4623          * We got more than one possible match, set the result to the maximum
4624          * common subset
4625          */
4626
4627         info.matches[0] = SMB_STRNDUP(info.matches[1], info.samelen);
4628         info.matches[info.count] = NULL;
4629         return info.matches;
4630
4631 cleanup:
4632         for (i = 0; i < info.count; i++) {
4633                 SAFE_FREE(info.matches[i]);
4634         }
4635         SAFE_FREE(info.matches);
4636         SAFE_FREE(info.dirmask);
4637         TALLOC_FREE(ctx);
4638         return NULL;
4639 }
4640
4641 static char **completion_fn(const char *text, int start, int end)
4642 {
4643         smb_readline_ca_char(' ');
4644
4645         if (start) {
4646                 const char *buf, *sp;
4647                 int i;
4648                 char compl_type;
4649
4650                 buf = smb_readline_get_line_buffer();
4651                 if (buf == NULL)
4652                         return NULL;
4653
4654                 sp = strchr(buf, ' ');
4655                 if (sp == NULL)
4656                         return NULL;
4657
4658                 for (i = 0; commands[i].name; i++) {
4659                         if ((strncmp(commands[i].name, buf, sp - buf) == 0) &&
4660                             (commands[i].name[sp - buf] == 0)) {
4661                                 break;
4662                         }
4663                 }
4664                 if (commands[i].name == NULL)
4665                         return NULL;
4666
4667                 while (*sp == ' ')
4668                         sp++;
4669
4670                 if (sp == (buf + start))
4671                         compl_type = commands[i].compl_args[0];
4672                 else
4673                         compl_type = commands[i].compl_args[1];
4674
4675                 if (compl_type == COMPL_REMOTE)
4676                         return remote_completion(text, end - start);
4677                 else /* fall back to local filename completion */
4678                         return NULL;
4679         } else {
4680                 char **matches;
4681                 int i, len, samelen = 0, count=1;
4682
4683                 matches = SMB_MALLOC_ARRAY(char *, MAX_COMPLETIONS);
4684                 if (!matches) {
4685                         return NULL;
4686                 }
4687                 matches[0] = NULL;
4688
4689                 len = strlen(text);
4690                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
4691                         if (strncmp(text, commands[i].name, len) == 0) {
4692                                 matches[count] = SMB_STRDUP(commands[i].name);
4693                                 if (!matches[count])
4694                                         goto cleanup;
4695                                 if (count == 1)
4696                                         samelen = strlen(matches[count]);
4697                                 else
4698                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
4699                                                 samelen--;
4700                                 count++;
4701                         }
4702                 }
4703
4704                 switch (count) {
4705                 case 0: /* should never happen */
4706                 case 1:
4707                         goto cleanup;
4708                 case 2:
4709                         matches[0] = SMB_STRDUP(matches[1]);
4710                         break;
4711                 default:
4712                         matches[0] = (char *)SMB_MALLOC(samelen+1);
4713                         if (!matches[0])
4714                                 goto cleanup;
4715                         strncpy(matches[0], matches[1], samelen);
4716                         matches[0][samelen] = 0;
4717                 }
4718                 matches[count] = NULL;
4719                 return matches;
4720
4721 cleanup:
4722                 for (i = 0; i < count; i++)
4723                         free(matches[i]);
4724
4725                 free(matches);
4726                 return NULL;
4727         }
4728 }
4729
4730 static bool finished;
4731
4732 /****************************************************************************
4733  Make sure we swallow keepalives during idle time.
4734 ****************************************************************************/
4735
4736 static void readline_callback(void)
4737 {
4738         fd_set fds;
4739         struct timeval timeout;
4740         static time_t last_t;
4741         struct timespec now;
4742         time_t t;
4743
4744         clock_gettime_mono(&now);
4745         t = now.tv_sec;
4746
4747         if (t - last_t < 5)
4748                 return;
4749
4750         last_t = t;
4751
4752  again:
4753
4754         if (cli->fd == -1)
4755                 return;
4756
4757         FD_ZERO(&fds);
4758         FD_SET(cli->fd,&fds);
4759
4760         timeout.tv_sec = 0;
4761         timeout.tv_usec = 0;
4762         sys_select_intr(cli->fd+1,&fds,NULL,NULL,&timeout);
4763
4764         /* We deliberately use receive_smb_raw instead of
4765            client_receive_smb as we want to receive
4766            session keepalives and then drop them here.
4767         */
4768         if (FD_ISSET(cli->fd,&fds)) {
4769                 NTSTATUS status;
4770                 size_t len;
4771
4772                 set_smb_read_error(&cli->smb_rw_error, SMB_READ_OK);
4773
4774                 status = receive_smb_raw(cli->fd, cli->inbuf, cli->bufsize, 0, 0, &len);
4775
4776                 if (!NT_STATUS_IS_OK(status)) {
4777                         DEBUG(0, ("Read from server failed, maybe it closed "
4778                                   "the connection\n"));
4779
4780                         finished = true;
4781                         smb_readline_done();
4782                         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
4783                                 set_smb_read_error(&cli->smb_rw_error,
4784                                                    SMB_READ_EOF);
4785                                 return;
4786                         }
4787
4788                         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
4789                                 set_smb_read_error(&cli->smb_rw_error,
4790                                                    SMB_READ_TIMEOUT);
4791                                 return;
4792                         }
4793
4794                         set_smb_read_error(&cli->smb_rw_error, SMB_READ_ERROR);
4795                         return;
4796                 }
4797                 if(CVAL(cli->inbuf,0) != SMBkeepalive) {
4798                         DEBUG(0, ("Read from server "
4799                                 "returned unexpected packet!\n"));
4800                         return;
4801                 }
4802
4803                 goto again;
4804         }
4805
4806         /* Ping the server to keep the connection alive using SMBecho. */
4807         {
4808                 NTSTATUS status;
4809                 unsigned char garbage[16];
4810                 memset(garbage, 0xf0, sizeof(garbage));
4811                 status = cli_echo(cli, 1, data_blob_const(garbage, sizeof(garbage)));
4812
4813                 if (!NT_STATUS_IS_OK(status)) {
4814                         DEBUG(0, ("SMBecho failed. Maybe server has closed "
4815                                 "the connection\n"));
4816                         finished = true;
4817                         smb_readline_done();
4818                 }
4819         }
4820 }
4821
4822 /****************************************************************************
4823  Process commands on stdin.
4824 ****************************************************************************/
4825
4826 static int process_stdin(void)
4827 {
4828         int rc = 0;
4829
4830         while (!finished) {
4831                 TALLOC_CTX *frame = talloc_stackframe();
4832                 char *tok = NULL;
4833                 char *the_prompt = NULL;
4834                 char *line = NULL;
4835                 int i;
4836
4837                 /* display a prompt */
4838                 if (asprintf(&the_prompt, "smb: %s> ", client_get_cur_dir()) < 0) {
4839                         TALLOC_FREE(frame);
4840                         break;
4841                 }
4842                 line = smb_readline(the_prompt, readline_callback, completion_fn);
4843                 SAFE_FREE(the_prompt);
4844                 if (!line) {
4845                         TALLOC_FREE(frame);
4846                         break;
4847                 }
4848
4849                 /* special case - first char is ! */
4850                 if (*line == '!') {
4851                         if (system(line + 1) == -1) {
4852                                 d_printf("system() command %s failed.\n",
4853                                         line+1);
4854                         }
4855                         SAFE_FREE(line);
4856                         TALLOC_FREE(frame);
4857                         continue;
4858                 }
4859
4860                 /* and get the first part of the command */
4861                 cmd_ptr = line;
4862                 if (!next_token_talloc(frame, &cmd_ptr,&tok,NULL)) {
4863                         TALLOC_FREE(frame);
4864                         SAFE_FREE(line);
4865                         continue;
4866                 }
4867
4868                 if ((i = process_tok(tok)) >= 0) {
4869                         rc = commands[i].fn();
4870                 } else if (i == -2) {
4871                         d_printf("%s: command abbreviation ambiguous\n",tok);
4872                 } else {
4873                         d_printf("%s: command not found\n",tok);
4874                 }
4875                 SAFE_FREE(line);
4876                 TALLOC_FREE(frame);
4877         }
4878         return rc;
4879 }
4880
4881 /****************************************************************************
4882  Process commands from the client.
4883 ****************************************************************************/
4884
4885 static int process(const char *base_directory)
4886 {
4887         int rc = 0;
4888
4889         cli = cli_cm_open(talloc_tos(), NULL,
4890                         have_ip ? dest_ss_str : desthost,
4891                         service, auth_info, true, smb_encrypt,
4892                         max_protocol, port, name_type);
4893         if (!cli) {
4894                 return 1;
4895         }
4896
4897         if (base_directory && *base_directory) {
4898                 rc = do_cd(base_directory);
4899                 if (rc) {
4900                         cli_shutdown(cli);
4901                         return rc;
4902                 }
4903         }
4904
4905         if (cmdstr) {
4906                 rc = process_command_string(cmdstr);
4907         } else {
4908                 process_stdin();
4909         }
4910
4911         cli_shutdown(cli);
4912         return rc;
4913 }
4914
4915 /****************************************************************************
4916  Handle a -L query.
4917 ****************************************************************************/
4918
4919 static int do_host_query(const char *query_host)
4920 {
4921         cli = cli_cm_open(talloc_tos(), NULL,
4922                         have_ip ? dest_ss_str : query_host, "IPC$", auth_info, true, smb_encrypt,
4923                         max_protocol, port, name_type);
4924         if (!cli)
4925                 return 1;
4926
4927         browse_host(true);
4928
4929         /* Ensure that the host can do IPv4 */
4930
4931         if (!interpret_addr(query_host)) {
4932                 struct sockaddr_storage ss;
4933                 if (interpret_string_addr(&ss, query_host, 0) &&
4934                                 (ss.ss_family != AF_INET)) {
4935                         d_printf("%s is an IPv6 address -- no workgroup available\n",
4936                                 query_host);
4937                         return 1;
4938                 }
4939         }
4940
4941         if (port != 139) {
4942
4943                 /* Workgroups simply don't make sense over anything
4944                    else but port 139... */
4945
4946                 cli_shutdown(cli);
4947                 cli = cli_cm_open(talloc_tos(), NULL,
4948                                 have_ip ? dest_ss_str : query_host, "IPC$",
4949                                 auth_info, true, smb_encrypt,
4950                                 max_protocol, 139, name_type);
4951         }
4952
4953         if (cli == NULL) {
4954                 d_printf("NetBIOS over TCP disabled -- no workgroup available\n");
4955                 return 1;
4956         }
4957
4958         list_servers(lp_workgroup());
4959
4960         cli_shutdown(cli);
4961
4962         return(0);
4963 }
4964
4965 /****************************************************************************
4966  Handle a tar operation.
4967 ****************************************************************************/
4968
4969 static int do_tar_op(const char *base_directory)
4970 {
4971         int ret;
4972
4973         /* do we already have a connection? */
4974         if (!cli) {
4975                 cli = cli_cm_open(talloc_tos(), NULL,
4976                         have_ip ? dest_ss_str : desthost,
4977                         service, auth_info, true, smb_encrypt,
4978                         max_protocol, port, name_type);
4979                 if (!cli)
4980                         return 1;
4981         }
4982
4983         recurse=true;
4984
4985         if (base_directory && *base_directory)  {
4986                 ret = do_cd(base_directory);
4987                 if (ret) {
4988                         cli_shutdown(cli);
4989                         return ret;
4990                 }
4991         }
4992
4993         ret=process_tar();
4994
4995         cli_shutdown(cli);
4996
4997         return(ret);
4998 }
4999
5000 /****************************************************************************
5001  Handle a message operation.
5002 ****************************************************************************/
5003
5004 static int do_message_op(struct user_auth_info *a_info)
5005 {
5006         struct sockaddr_storage ss;
5007         struct nmb_name called, calling;
5008         fstring server_name;
5009         char name_type_hex[10];
5010         int msg_port;
5011         NTSTATUS status;
5012
5013         make_nmb_name(&calling, calling_name, 0x0);
5014         make_nmb_name(&called , desthost, name_type);
5015
5016         fstrcpy(server_name, desthost);
5017         snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
5018         fstrcat(server_name, name_type_hex);
5019
5020         zero_sockaddr(&ss);
5021         if (have_ip)
5022                 ss = dest_ss;
5023
5024         /* we can only do messages over port 139 (to windows clients at least) */
5025
5026         msg_port = port ? port : 139;
5027
5028         if (!(cli=cli_initialise())) {
5029                 d_printf("Connection to %s failed\n", desthost);
5030                 return 1;
5031         }
5032         cli_set_port(cli, msg_port);
5033
5034         status = cli_connect(cli, server_name, &ss);
5035         if (!NT_STATUS_IS_OK(status)) {
5036                 d_printf("Connection to %s failed. Error %s\n", desthost, nt_errstr(status));
5037                 return 1;
5038         }
5039
5040         if (!cli_session_request(cli, &calling, &called)) {
5041                 d_printf("session request failed\n");
5042                 cli_shutdown(cli);
5043                 return 1;
5044         }
5045
5046         send_message(get_cmdline_auth_info_username(a_info));
5047         cli_shutdown(cli);
5048
5049         return 0;
5050 }
5051
5052 /****************************************************************************
5053   main program
5054 ****************************************************************************/
5055
5056  int main(int argc,char *argv[])
5057 {
5058         char *base_directory = NULL;
5059         int opt;
5060         char *query_host = NULL;
5061         bool message = false;
5062         static const char *new_name_resolve_order = NULL;
5063         poptContext pc;
5064         char *p;
5065         int rc = 0;
5066         fstring new_workgroup;
5067         bool tar_opt = false;
5068         bool service_opt = false;
5069         struct poptOption long_options[] = {
5070                 POPT_AUTOHELP
5071
5072                 { "name-resolve", 'R', POPT_ARG_STRING, &new_name_resolve_order, 'R', "Use these name resolution services only", "NAME-RESOLVE-ORDER" },
5073                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
5074                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
5075                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
5076                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
5077                 { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" },
5078                 { "tar", 'T', POPT_ARG_STRING, NULL, 'T', "Command line tar", "<c|x>IXFqgbNan" },
5079                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
5080                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
5081                 { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" },
5082                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
5083                 { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" },
5084                 { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" },
5085                 POPT_COMMON_SAMBA
5086                 POPT_COMMON_CONNECTION
5087                 POPT_COMMON_CREDENTIALS
5088                 POPT_TABLEEND
5089         };
5090         TALLOC_CTX *frame = talloc_stackframe();
5091
5092         if (!client_set_cur_dir("\\")) {
5093                 exit(ENOMEM);
5094         }
5095
5096         /* initialize the workgroup name so we can determine whether or
5097            not it was set by a command line option */
5098
5099         set_global_myworkgroup( "" );
5100         set_global_myname( "" );
5101
5102         /* set default debug level to 1 regardless of what smb.conf sets */
5103         setup_logging( "smbclient", DEBUG_DEFAULT_STDERR );
5104         load_case_tables();
5105
5106         lp_set_cmdline("log level", "1");
5107
5108         auth_info = user_auth_info_init(frame);
5109         if (auth_info == NULL) {
5110                 exit(1);
5111         }
5112         popt_common_set_auth_info(auth_info);
5113
5114         /* skip argv(0) */
5115         pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
5116         poptSetOtherOptionHelp(pc, "service <password>");
5117
5118         lp_set_in_client(true); /* Make sure that we tell lp_load we are */
5119
5120         while ((opt = poptGetNextOpt(pc)) != -1) {
5121
5122                 /* if the tar option has been called previouslt, now we need to eat out the leftovers */
5123                 /* I see no other way to keep things sane --SSS */
5124                 if (tar_opt == true) {
5125                         while (poptPeekArg(pc)) {
5126                                 poptGetArg(pc);
5127                         }
5128                         tar_opt = false;
5129                 }
5130
5131                 /* if the service has not yet been specified lets see if it is available in the popt stack */
5132                 if (!service_opt && poptPeekArg(pc)) {
5133                         service = talloc_strdup(frame, poptGetArg(pc));
5134                         if (!service) {
5135                                 exit(ENOMEM);
5136                         }
5137                         service_opt = true;
5138                 }
5139
5140                 /* if the service has already been retrieved then check if we have also a password */
5141                 if (service_opt
5142                     && (!get_cmdline_auth_info_got_pass(auth_info))
5143                     && poptPeekArg(pc)) {
5144                         set_cmdline_auth_info_password(auth_info,
5145                                                        poptGetArg(pc));
5146                 }
5147
5148                 switch (opt) {
5149                 case 'M':
5150                         /* Messages are sent to NetBIOS name type 0x3
5151                          * (Messenger Service).  Make sure we default
5152                          * to port 139 instead of port 445. srl,crh
5153                          */
5154                         name_type = 0x03;
5155                         desthost = talloc_strdup(frame,poptGetOptArg(pc));
5156                         if (!desthost) {
5157                                 exit(ENOMEM);
5158                         }
5159                         if( !port )
5160                                 port = 139;
5161                         message = true;
5162                         break;
5163                 case 'I':
5164                         {
5165                                 if (!interpret_string_addr(&dest_ss, poptGetOptArg(pc), 0)) {
5166                                         exit(1);
5167                                 }
5168                                 have_ip = true;
5169                                 print_sockaddr(dest_ss_str, sizeof(dest_ss_str), &dest_ss);
5170                         }
5171                         break;
5172                 case 'E':
5173                         setup_logging("smbclient", DEBUG_STDERR );
5174                         display_set_stderr();
5175                         break;
5176
5177                 case 'L':
5178                         query_host = talloc_strdup(frame, poptGetOptArg(pc));
5179                         if (!query_host) {
5180                                 exit(ENOMEM);
5181                         }
5182                         break;
5183                 case 'm':
5184                         max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol);
5185                         break;
5186                 case 'T':
5187                         /* We must use old option processing for this. Find the
5188                          * position of the -T option in the raw argv[]. */
5189                         {
5190                                 int i;
5191                                 for (i = 1; i < argc; i++) {
5192                                         if (strncmp("-T", argv[i],2)==0)
5193                                                 break;
5194                                 }
5195                                 i++;
5196                                 if (!tar_parseargs(argc, argv, poptGetOptArg(pc), i)) {
5197                                         poptPrintUsage(pc, stderr, 0);
5198                                         exit(1);
5199                                 }
5200                         }
5201                         /* this must be the last option, mark we have parsed it so that we know we have */
5202                         tar_opt = true;
5203                         break;
5204                 case 'D':
5205                         base_directory = talloc_strdup(frame, poptGetOptArg(pc));
5206                         if (!base_directory) {
5207                                 exit(ENOMEM);
5208                         }
5209                         break;
5210                 case 'g':
5211                         grepable=true;
5212                         break;
5213                 case 'e':
5214                         smb_encrypt=true;
5215                         break;
5216                 case 'B':
5217                         return(do_smb_browse());
5218
5219                 }
5220         }
5221
5222         /* We may still have some leftovers after the last popt option has been called */
5223         if (tar_opt == true) {
5224                 while (poptPeekArg(pc)) {
5225                         poptGetArg(pc);
5226                 }
5227                 tar_opt = false;
5228         }
5229
5230         /* if the service has not yet been specified lets see if it is available in the popt stack */
5231         if (!service_opt && poptPeekArg(pc)) {
5232                 service = talloc_strdup(frame,poptGetArg(pc));
5233                 if (!service) {
5234                         exit(ENOMEM);
5235                 }
5236                 service_opt = true;
5237         }
5238
5239         /* if the service has already been retrieved then check if we have also a password */
5240         if (service_opt
5241             && !get_cmdline_auth_info_got_pass(auth_info)
5242             && poptPeekArg(pc)) {
5243                 set_cmdline_auth_info_password(auth_info,
5244                                                poptGetArg(pc));
5245         }
5246
5247         /* save the workgroup...
5248
5249            FIXME!! do we need to do this for other options as well
5250            (or maybe a generic way to keep lp_load() from overwriting
5251            everything)?  */
5252
5253         fstrcpy( new_workgroup, lp_workgroup() );
5254         calling_name = talloc_strdup(frame, global_myname() );
5255         if (!calling_name) {
5256                 exit(ENOMEM);
5257         }
5258
5259         if ( override_logfile )
5260                 setup_logging( lp_logfile(), DEBUG_FILE );
5261
5262         if (!lp_load(get_dyn_CONFIGFILE(),true,false,false,true)) {
5263                 fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n",
5264                         argv[0], get_dyn_CONFIGFILE());
5265         }
5266
5267         if (get_cmdline_auth_info_use_machine_account(auth_info) &&
5268             !set_cmdline_auth_info_machine_account_creds(auth_info)) {
5269                 exit(-1);
5270         }
5271
5272         load_interfaces();
5273
5274         if (service_opt && service) {
5275                 size_t len;
5276
5277                 /* Convert any '/' characters in the service name to '\' characters */
5278                 string_replace(service, '/','\\');
5279                 if (count_chars(service,'\\') < 3) {
5280                         d_printf("\n%s: Not enough '\\' characters in service\n",service);
5281                         poptPrintUsage(pc, stderr, 0);
5282                         exit(1);
5283                 }
5284                 /* Remove trailing slashes */
5285                 len = strlen(service);
5286                 while(len > 0 && service[len - 1] == '\\') {
5287                         --len;
5288                         service[len] = '\0';
5289                 }
5290         }
5291
5292         if ( strlen(new_workgroup) != 0 ) {
5293                 set_global_myworkgroup( new_workgroup );
5294         }
5295
5296         if ( strlen(calling_name) != 0 ) {
5297                 set_global_myname( calling_name );
5298         } else {
5299                 TALLOC_FREE(calling_name);
5300                 calling_name = talloc_strdup(frame, global_myname() );
5301         }
5302
5303         smb_encrypt = get_cmdline_auth_info_smb_encrypt(auth_info);
5304         if (!init_names()) {
5305                 fprintf(stderr, "init_names() failed\n");
5306                 exit(1);
5307         }
5308
5309         if(new_name_resolve_order)
5310                 lp_set_name_resolve_order(new_name_resolve_order);
5311
5312         if (!tar_type && !query_host && !service && !message) {
5313                 poptPrintUsage(pc, stderr, 0);
5314                 exit(1);
5315         }
5316
5317         poptFreeContext(pc);
5318
5319         DEBUG(3,("Client started (version %s).\n", samba_version_string()));
5320
5321         /* Ensure we have a password (or equivalent). */
5322         set_cmdline_auth_info_getpass(auth_info);
5323
5324         if (tar_type) {
5325                 if (cmdstr)
5326                         process_command_string(cmdstr);
5327                 return do_tar_op(base_directory);
5328         }
5329
5330         if (query_host && *query_host) {
5331                 char *qhost = query_host;
5332                 char *slash;
5333
5334                 while (*qhost == '\\' || *qhost == '/')
5335                         qhost++;
5336
5337                 if ((slash = strchr_m(qhost, '/'))
5338                     || (slash = strchr_m(qhost, '\\'))) {
5339                         *slash = 0;
5340                 }
5341
5342                 if ((p=strchr_m(qhost, '#'))) {
5343                         *p = 0;
5344                         p++;
5345                         sscanf(p, "%x", &name_type);
5346                 }
5347
5348                 return do_host_query(qhost);
5349         }
5350
5351         if (message) {
5352                 return do_message_op(auth_info);
5353         }
5354
5355         if (process(base_directory)) {
5356                 return 1;
5357         }
5358
5359         TALLOC_FREE(frame);
5360         return rc;
5361 }