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