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