r14464: Don't include ndr_BASENAME.h files unless strictly required, instead
[garming/samba-autobuild/.git] / source4 / 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-2004
7    Copyright (C) James J Myers   2003 <myersjj@samba.org>
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "version.h"
26 #include "libcli/libcli.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "librpc/gen_ndr/ndr_srvsvc.h"
29 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
30 #include "librpc/gen_ndr/ndr_lsa.h"
31 #include "libcli/raw/libcliraw.h"
32 #include "libcli/util/clilsa.h"
33 #include "system/dir.h"
34 #include "system/filesys.h"
35 #include "dlinklist.h"
36 #include "system/readline.h"
37 #include "auth/gensec/gensec.h"
38 #include "system/time.h" /* needed by some systems for asctime() */
39 #include "libcli/resolve/resolve.h"
40 #include "libcli/security/proto.h"
41 #include "lib/replace/readline.h"
42 #include "librpc/gen_ndr/ndr_nbt.h"
43 #include "librpc/gen_ndr/ndr_security.h"
44
45 static int io_bufsize = 64512;
46
47 struct smbclient_context {
48         char *remote_cur_dir;
49         struct smbcli_state *cli;
50         char *fileselection;
51         time_t newer_than;
52         BOOL prompt;
53         BOOL recurse;
54         int archive_level;
55         BOOL lowercase;
56         int printmode;
57         BOOL translation;
58 };
59
60 /* timing globals */
61 static uint64_t get_total_size = 0;
62 static uint_t get_total_time_ms = 0;
63 static uint64_t put_total_size = 0;
64 static uint_t put_total_time_ms = 0;
65
66 /* Unfortunately, there is no way to pass the a context to the completion function as an argument */
67 static struct smbclient_context *rl_ctx; 
68
69 /* totals globals */
70 static double dir_total;
71
72 /*******************************************************************
73  Reduce a file name, removing .. elements.
74 ********************************************************************/
75 void dos_clean_name(char *s)
76 {
77         char *p=NULL,*r;
78
79         DEBUG(3,("dos_clean_name [%s]\n",s));
80
81         /* remove any double slashes */
82         all_string_sub(s, "\\\\", "\\", 0);
83
84         while ((p = strstr(s,"\\..\\")) != NULL) {
85                 *p = '\0';
86                 if ((r = strrchr(s,'\\')) != NULL)
87                         memmove(r,p+3,strlen(p+3)+1);
88         }
89
90         trim_string(s,NULL,"\\..");
91
92         all_string_sub(s, "\\.\\", "\\", 0);
93 }
94
95 /****************************************************************************
96 write to a local file with CR/LF->LF translation if appropriate. return the 
97 number taken from the buffer. This may not equal the number written.
98 ****************************************************************************/
99 static int writefile(int f, const void *_b, int n, BOOL translation)
100 {
101         const uint8_t *b = _b;
102         int i;
103
104         if (!translation) {
105                 return write(f,b,n);
106         }
107
108         i = 0;
109         while (i < n) {
110                 if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') {
111                         b++;i++;
112                 }
113                 if (write(f, b, 1) != 1) {
114                         break;
115                 }
116                 b++;
117                 i++;
118         }
119   
120         return(i);
121 }
122
123 /****************************************************************************
124   read from a file with LF->CR/LF translation if appropriate. return the 
125   number read. read approx n bytes.
126 ****************************************************************************/
127 static int readfile(void *_b, int n, XFILE *f, BOOL translation)
128 {
129         uint8_t *b = _b;
130         int i;
131         int c;
132
133         if (!translation)
134                 return x_fread(b,1,n,f);
135   
136         i = 0;
137         while (i < (n - 1)) {
138                 if ((c = x_getc(f)) == EOF) {
139                         break;
140                 }
141       
142                 if (c == '\n') { /* change all LFs to CR/LF */
143                         b[i++] = '\r';
144                 }
145       
146                 b[i++] = c;
147         }
148   
149         return(i);
150 }
151  
152
153 /****************************************************************************
154 send a message
155 ****************************************************************************/
156 static void send_message(struct smbcli_state *cli, const char *desthost)
157 {
158         char msg[1600];
159         int total_len = 0;
160         int grp_id;
161
162         if (!smbcli_message_start(cli->tree, desthost, cli_credentials_get_username(cmdline_credentials), &grp_id)) {
163                 d_printf("message start: %s\n", smbcli_errstr(cli->tree));
164                 return;
165         }
166
167
168         d_printf("Connected. Type your message, ending it with a Control-D\n");
169
170         while (!feof(stdin) && total_len < 1600) {
171                 int maxlen = MIN(1600 - total_len,127);
172                 int l=0;
173                 int c;
174
175                 for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) {
176                         if (c == '\n')
177                                 msg[l++] = '\r';
178                         msg[l] = c;   
179                 }
180
181                 if (!smbcli_message_text(cli->tree, msg, l, grp_id)) {
182                         d_printf("SMBsendtxt failed (%s)\n",smbcli_errstr(cli->tree));
183                         return;
184                 }      
185                 
186                 total_len += l;
187         }
188
189         if (total_len >= 1600)
190                 d_printf("the message was truncated to 1600 bytes\n");
191         else
192                 d_printf("sent %d bytes\n",total_len);
193
194         if (!smbcli_message_end(cli->tree, grp_id)) {
195                 d_printf("SMBsendend failed (%s)\n",smbcli_errstr(cli->tree));
196                 return;
197         }      
198 }
199
200
201
202 /****************************************************************************
203 check the space on a device
204 ****************************************************************************/
205 static int do_dskattr(struct smbclient_context *ctx)
206 {
207         int total, bsize, avail;
208
209         if (NT_STATUS_IS_ERR(smbcli_dskattr(ctx->cli->tree, &bsize, &total, &avail))) {
210                 d_printf("Error in dskattr: %s\n",smbcli_errstr(ctx->cli->tree)); 
211                 return 1;
212         }
213
214         d_printf("\n\t\t%d blocks of size %d. %d blocks available\n",
215                  total, bsize, avail);
216
217         return 0;
218 }
219
220 /****************************************************************************
221 show cd/pwd
222 ****************************************************************************/
223 static int cmd_pwd(struct smbclient_context *ctx, const char **args)
224 {
225         d_printf("Current directory is %s\n", ctx->remote_cur_dir);
226         return 0;
227 }
228
229 /*
230   convert a string to dos format
231 */
232 static void dos_format(char *s)
233 {
234         string_replace(s, '/', '\\');
235 }
236
237 /****************************************************************************
238 change directory - inner section
239 ****************************************************************************/
240 static int do_cd(struct smbclient_context *ctx, const char *newdir)
241 {
242         char *dname;
243       
244         /* Save the current directory in case the
245            new directory is invalid */
246         if (newdir[0] == '\\')
247                 dname = talloc_strdup(NULL, newdir);
248         else
249                 dname = talloc_asprintf(NULL, "%s\\%s", ctx->remote_cur_dir, newdir);
250
251         dos_format(dname);
252
253         if (*(dname+strlen(dname)-1) != '\\') {
254                 dname = talloc_append_string(NULL, dname, "\\");
255         }
256         dos_clean_name(dname);
257         
258         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, dname))) {
259                 d_printf("cd %s: %s\n", dname, smbcli_errstr(ctx->cli->tree));
260                 talloc_free(dname);
261         } else {
262                 ctx->remote_cur_dir = dname;
263         }
264         
265         return 0;
266 }
267
268 /****************************************************************************
269 change directory
270 ****************************************************************************/
271 static int cmd_cd(struct smbclient_context *ctx, const char **args)
272 {
273         int rc = 0;
274
275         if (args[1]) 
276                 rc = do_cd(ctx, args[1]);
277         else
278                 d_printf("Current directory is %s\n",ctx->remote_cur_dir);
279
280         return rc;
281 }
282
283
284 BOOL mask_match(struct smbcli_state *c, const char *string, const char *pattern, 
285                 BOOL is_case_sensitive)
286 {
287         char *p2, *s2;
288         BOOL ret;
289
290         if (strcmp(string,"..") == 0)
291                 string = ".";
292         if (strcmp(pattern,".") == 0)
293                 return False;
294         
295         if (is_case_sensitive)
296                 return ms_fnmatch(pattern, string, 
297                                   c->transport->negotiate.protocol) == 0;
298
299         p2 = strlower_talloc(NULL, pattern);
300         s2 = strlower_talloc(NULL, string);
301         ret = ms_fnmatch(p2, s2, c->transport->negotiate.protocol) == 0;
302         talloc_free(p2);
303         talloc_free(s2);
304
305         return ret;
306 }
307
308
309
310 /*******************************************************************
311   decide if a file should be operated on
312   ********************************************************************/
313 static BOOL do_this_one(struct smbclient_context *ctx, struct clilist_file_info *finfo)
314 {
315         if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) return(True);
316
317         if (ctx->fileselection && 
318             !mask_match(ctx->cli, finfo->name,ctx->fileselection,False)) {
319                 DEBUG(3,("mask_match %s failed\n", finfo->name));
320                 return False;
321         }
322
323         if (ctx->newer_than && finfo->mtime < ctx->newer_than) {
324                 DEBUG(3,("newer_than %s failed\n", finfo->name));
325                 return(False);
326         }
327
328         if ((ctx->archive_level==1 || ctx->archive_level==2) && !(finfo->attrib & FILE_ATTRIBUTE_ARCHIVE)) {
329                 DEBUG(3,("archive %s failed\n", finfo->name));
330                 return(False);
331         }
332         
333         return(True);
334 }
335
336 /****************************************************************************
337   display info about a file
338   ****************************************************************************/
339 static void display_finfo(struct smbclient_context *ctx, struct clilist_file_info *finfo)
340 {
341         if (do_this_one(ctx, finfo)) {
342                 time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */
343                 char *astr = attrib_string(NULL, finfo->attrib);
344                 d_printf("  %-30s%7.7s %8.0f  %s",
345                          finfo->name,
346                          astr,
347                          (double)finfo->size,
348                          asctime(localtime(&t)));
349                 dir_total += finfo->size;
350                 talloc_free(astr);
351         }
352 }
353
354
355 /****************************************************************************
356    accumulate size of a file
357   ****************************************************************************/
358 static void do_du(struct smbclient_context *ctx, struct clilist_file_info *finfo)
359 {
360         if (do_this_one(ctx, finfo)) {
361                 dir_total += finfo->size;
362         }
363 }
364
365 static BOOL do_list_recurse;
366 static BOOL do_list_dirs;
367 static char *do_list_queue = 0;
368 static long do_list_queue_size = 0;
369 static long do_list_queue_start = 0;
370 static long do_list_queue_end = 0;
371 static void (*do_list_fn)(struct smbclient_context *, struct clilist_file_info *);
372
373 /****************************************************************************
374 functions for do_list_queue
375   ****************************************************************************/
376
377 /*
378  * The do_list_queue is a NUL-separated list of strings stored in a
379  * char*.  Since this is a FIFO, we keep track of the beginning and
380  * ending locations of the data in the queue.  When we overflow, we
381  * double the size of the char*.  When the start of the data passes
382  * the midpoint, we move everything back.  This is logically more
383  * complex than a linked list, but easier from a memory management
384  * angle.  In any memory error condition, do_list_queue is reset.
385  * Functions check to ensure that do_list_queue is non-NULL before
386  * accessing it.
387  */
388 static void reset_do_list_queue(void)
389 {
390         SAFE_FREE(do_list_queue);
391         do_list_queue_size = 0;
392         do_list_queue_start = 0;
393         do_list_queue_end = 0;
394 }
395
396 static void init_do_list_queue(void)
397 {
398         reset_do_list_queue();
399         do_list_queue_size = 1024;
400         do_list_queue = malloc(do_list_queue_size);
401         if (do_list_queue == 0) { 
402                 d_printf("malloc fail for size %d\n",
403                          (int)do_list_queue_size);
404                 reset_do_list_queue();
405         } else {
406                 memset(do_list_queue, 0, do_list_queue_size);
407         }
408 }
409
410 static void adjust_do_list_queue(void)
411 {
412         /*
413          * If the starting point of the queue is more than half way through,
414          * move everything toward the beginning.
415          */
416         if (do_list_queue && (do_list_queue_start == do_list_queue_end))
417         {
418                 DEBUG(4,("do_list_queue is empty\n"));
419                 do_list_queue_start = do_list_queue_end = 0;
420                 *do_list_queue = '\0';
421         }
422         else if (do_list_queue_start > (do_list_queue_size / 2))
423         {
424                 DEBUG(4,("sliding do_list_queue backward\n"));
425                 memmove(do_list_queue,
426                         do_list_queue + do_list_queue_start,
427                         do_list_queue_end - do_list_queue_start);
428                 do_list_queue_end -= do_list_queue_start;
429                 do_list_queue_start = 0;
430         }
431            
432 }
433
434 static void add_to_do_list_queue(const char* entry)
435 {
436         char *dlq;
437         long new_end = do_list_queue_end + ((long)strlen(entry)) + 1;
438         while (new_end > do_list_queue_size)
439         {
440                 do_list_queue_size *= 2;
441                 DEBUG(4,("enlarging do_list_queue to %d\n",
442                          (int)do_list_queue_size));
443                 dlq = realloc_p(do_list_queue, char, do_list_queue_size);
444                 if (! dlq) {
445                         d_printf("failure enlarging do_list_queue to %d bytes\n",
446                                  (int)do_list_queue_size);
447                         reset_do_list_queue();
448                 }
449                 else
450                 {
451                         do_list_queue = dlq;
452                         memset(do_list_queue + do_list_queue_size / 2,
453                                0, do_list_queue_size / 2);
454                 }
455         }
456         if (do_list_queue)
457         {
458                 safe_strcpy(do_list_queue + do_list_queue_end, entry, 
459                             do_list_queue_size - do_list_queue_end - 1);
460                 do_list_queue_end = new_end;
461                 DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n",
462                          entry, (int)do_list_queue_start, (int)do_list_queue_end));
463         }
464 }
465
466 static char *do_list_queue_head(void)
467 {
468         return do_list_queue + do_list_queue_start;
469 }
470
471 static void remove_do_list_queue_head(void)
472 {
473         if (do_list_queue_end > do_list_queue_start)
474         {
475                 do_list_queue_start += strlen(do_list_queue_head()) + 1;
476                 adjust_do_list_queue();
477                 DEBUG(4,("removed head of do_list_queue (start=%d, end=%d)\n",
478                          (int)do_list_queue_start, (int)do_list_queue_end));
479         }
480 }
481
482 static int do_list_queue_empty(void)
483 {
484         return (! (do_list_queue && *do_list_queue));
485 }
486
487 /****************************************************************************
488 a helper for do_list
489   ****************************************************************************/
490 static void do_list_helper(struct clilist_file_info *f, const char *mask, void *state)
491 {
492         struct smbclient_context *ctx = state;
493
494         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY) {
495                 if (do_list_dirs && do_this_one(ctx, f)) {
496                         do_list_fn(ctx, f);
497                 }
498                 if (do_list_recurse && 
499                     !strequal(f->name,".") && 
500                     !strequal(f->name,"..")) {
501                         char *mask2;
502                         char *p;
503
504                         mask2 = talloc_strdup(NULL, mask);
505                         p = strrchr_m(mask2,'\\');
506                         if (!p) return;
507                         p[1] = 0;
508                         mask2 = talloc_asprintf_append(mask2, "%s\\*", f->name);
509                         add_to_do_list_queue(mask2);
510                 }
511                 return;
512         }
513
514         if (do_this_one(ctx, f)) {
515                 do_list_fn(ctx, f);
516         }
517 }
518
519
520 /****************************************************************************
521 a wrapper around smbcli_list that adds recursion
522   ****************************************************************************/
523 static void do_list(struct smbclient_context *ctx, const char *mask,uint16_t attribute,
524              void (*fn)(struct smbclient_context *, struct clilist_file_info *),BOOL rec, BOOL dirs)
525 {
526         static int in_do_list = 0;
527
528         if (in_do_list && rec)
529         {
530                 fprintf(stderr, "INTERNAL ERROR: do_list called recursively when the recursive flag is true\n");
531                 exit(1);
532         }
533
534         in_do_list = 1;
535
536         do_list_recurse = rec;
537         do_list_dirs = dirs;
538         do_list_fn = fn;
539
540         if (rec)
541         {
542                 init_do_list_queue();
543                 add_to_do_list_queue(mask);
544                 
545                 while (! do_list_queue_empty())
546                 {
547                         /*
548                          * Need to copy head so that it doesn't become
549                          * invalid inside the call to smbcli_list.  This
550                          * would happen if the list were expanded
551                          * during the call.
552                          * Fix from E. Jay Berkenbilt (ejb@ql.org)
553                          */
554                         char *head;
555                         head = do_list_queue_head();
556                         smbcli_list(ctx->cli->tree, head, attribute, do_list_helper, ctx);
557                         remove_do_list_queue_head();
558                         if ((! do_list_queue_empty()) && (fn == display_finfo))
559                         {
560                                 char* next_file = do_list_queue_head();
561                                 char* save_ch = 0;
562                                 if ((strlen(next_file) >= 2) &&
563                                     (next_file[strlen(next_file) - 1] == '*') &&
564                                     (next_file[strlen(next_file) - 2] == '\\'))
565                                 {
566                                         save_ch = next_file +
567                                                 strlen(next_file) - 2;
568                                         *save_ch = '\0';
569                                 }
570                                 d_printf("\n%s\n",next_file);
571                                 if (save_ch)
572                                 {
573                                         *save_ch = '\\';
574                                 }
575                         }
576                 }
577         }
578         else
579         {
580                 if (smbcli_list(ctx->cli->tree, mask, attribute, do_list_helper, ctx) == -1)
581                 {
582                         d_printf("%s listing %s\n", smbcli_errstr(ctx->cli->tree), mask);
583                 }
584         }
585
586         in_do_list = 0;
587         reset_do_list_queue();
588 }
589
590 /****************************************************************************
591   get a directory listing
592   ****************************************************************************/
593 static int cmd_dir(struct smbclient_context *ctx, const char **args)
594 {
595         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
596         char *mask;
597         int rc;
598         
599         dir_total = 0;
600         
601         mask = talloc_strdup(ctx, ctx->remote_cur_dir);
602         if(mask[strlen(mask)-1]!='\\')
603                 mask = talloc_append_string(ctx, mask,"\\");
604         
605         if (args[1]) {
606                 mask = talloc_strdup(ctx, args[1]);
607                 if (mask[0] != '\\')
608                         mask = talloc_append_string(ctx, mask, "\\");
609                 dos_format(mask);
610         }
611         else {
612                 if (ctx->cli->tree->session->transport->negotiate.protocol <= 
613                     PROTOCOL_LANMAN1) { 
614                         mask = talloc_append_string(ctx, mask, "*.*");
615                 } else {
616                         mask = talloc_append_string(ctx, mask, "*");
617                 }
618         }
619
620         do_list(ctx, mask, attribute, display_finfo, ctx->recurse, True);
621
622         rc = do_dskattr(ctx);
623
624         DEBUG(3, ("Total bytes listed: %.0f\n", dir_total));
625
626         return rc;
627 }
628
629
630 /****************************************************************************
631   get a directory listing
632   ****************************************************************************/
633 static int cmd_du(struct smbclient_context *ctx, const char **args)
634 {
635         uint16_t attribute = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
636         int rc;
637         char *mask;
638         
639         dir_total = 0;
640         
641         if (args[1]) {
642                 if (args[1][0] == '\\')
643                         mask = talloc_strdup(ctx, args[1]);
644                 else
645                         mask = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
646                 dos_format(mask);
647         } else {
648                 mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
649         }
650
651         do_list(ctx, mask, attribute, do_du, ctx->recurse, True);
652
653         talloc_free(mask);
654
655         rc = do_dskattr(ctx);
656
657         d_printf("Total number of bytes: %.0f\n", dir_total);
658
659         return rc;
660 }
661
662
663 /****************************************************************************
664   get a file from rname to lname
665   ****************************************************************************/
666 static int do_get(struct smbclient_context *ctx, char *rname, const char *lname, BOOL reget)
667 {  
668         int handle = 0, fnum;
669         BOOL newhandle = False;
670         uint8_t *data;
671         struct timeval tp_start;
672         int read_size = io_bufsize;
673         uint16_t attr;
674         size_t size;
675         off_t start = 0;
676         off_t nread = 0;
677         int rc = 0;
678
679         GetTimeOfDay(&tp_start);
680
681         if (ctx->lowercase) {
682                 strlower(discard_const_p(char, lname));
683         }
684
685         fnum = smbcli_open(ctx->cli->tree, rname, O_RDONLY, DENY_NONE);
686
687         if (fnum == -1) {
688                 d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
689                 return 1;
690         }
691
692         if(!strcmp(lname,"-")) {
693                 handle = fileno(stdout);
694         } else {
695                 if (reget) {
696                         handle = open(lname, O_WRONLY|O_CREAT, 0644);
697                         if (handle >= 0) {
698                                 start = lseek(handle, 0, SEEK_END);
699                                 if (start == -1) {
700                                         d_printf("Error seeking local file\n");
701                                         return 1;
702                                 }
703                         }
704                 } else {
705                         handle = open(lname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
706                 }
707                 newhandle = True;
708         }
709         if (handle < 0) {
710                 d_printf("Error opening local file %s\n",lname);
711                 return 1;
712         }
713
714
715         if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, 
716                            &attr, &size, NULL, NULL, NULL, NULL, NULL)) &&
717             NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, 
718                           &attr, &size, NULL, NULL, NULL))) {
719                 d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
720                 return 1;
721         }
722
723         DEBUG(2,("getting file %s of size %.0f as %s ", 
724                  rname, (double)size, lname));
725
726         if(!(data = (uint8_t *)malloc(read_size))) { 
727                 d_printf("malloc fail for size %d\n", read_size);
728                 smbcli_close(ctx->cli->tree, fnum);
729                 return 1;
730         }
731
732         while (1) {
733                 int n = smbcli_read(ctx->cli->tree, fnum, data, nread + start, read_size);
734
735                 if (n <= 0) break;
736  
737                 if (writefile(handle,data, n, ctx->translation) != n) {
738                         d_printf("Error writing local file\n");
739                         rc = 1;
740                         break;
741                 }
742       
743                 nread += n;
744         }
745
746         if (nread + start < size) {
747                 DEBUG (0, ("Short read when getting file %s. Only got %ld bytes.\n",
748                             rname, (long)nread));
749
750                 rc = 1;
751         }
752
753         SAFE_FREE(data);
754         
755         if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
756                 d_printf("Error %s closing remote file\n",smbcli_errstr(ctx->cli->tree));
757                 rc = 1;
758         }
759
760         if (newhandle) {
761                 close(handle);
762         }
763
764         if (ctx->archive_level >= 2 && (attr & FILE_ATTRIBUTE_ARCHIVE)) {
765                 smbcli_setatr(ctx->cli->tree, rname, attr & ~(uint16_t)FILE_ATTRIBUTE_ARCHIVE, 0);
766         }
767
768         {
769                 struct timeval tp_end;
770                 int this_time;
771                 
772                 GetTimeOfDay(&tp_end);
773                 this_time = 
774                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
775                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
776                 get_total_time_ms += this_time;
777                 get_total_size += nread;
778                 
779                 DEBUG(2,("(%3.1f kb/s) (average %3.1f kb/s)\n",
780                          nread / (1.024*this_time + 1.0e-4),
781                          get_total_size / (1.024*get_total_time_ms)));
782         }
783         
784         return rc;
785 }
786
787
788 /****************************************************************************
789   get a file
790   ****************************************************************************/
791 static int cmd_get(struct smbclient_context *ctx, const char **args)
792 {
793         const char *lname;
794         char *rname;
795
796         if (!args[1]) {
797                 d_printf("get <filename>\n");
798                 return 1;
799         }
800
801         rname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
802
803         if (args[2]) 
804                 lname = args[2];
805         else 
806                 lname = args[1];
807         
808         dos_clean_name(rname);
809         
810         return do_get(ctx, rname, lname, False);
811 }
812
813 /****************************************************************************
814  Put up a yes/no prompt.
815 ****************************************************************************/
816 static BOOL yesno(char *p)
817 {
818         char ans[4];
819         printf("%s",p);
820
821         if (!fgets(ans,sizeof(ans)-1,stdin))
822                 return(False);
823
824         if (*ans == 'y' || *ans == 'Y')
825                 return(True);
826
827         return(False);
828 }
829
830 /****************************************************************************
831   do a mget operation on one file
832   ****************************************************************************/
833 static void do_mget(struct smbclient_context *ctx, struct clilist_file_info *finfo)
834 {
835         char *rname;
836         char *quest;
837         char *mget_mask;
838         char *saved_curdir;
839
840         if (strequal(finfo->name,".") || strequal(finfo->name,".."))
841                 return;
842
843         if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)
844                 asprintf(&quest, "Get directory %s? ",finfo->name);
845         else
846                 asprintf(&quest, "Get file %s? ",finfo->name);
847
848         if (ctx->prompt && !yesno(quest)) return;
849
850         SAFE_FREE(quest);
851
852         if (!(finfo->attrib & FILE_ATTRIBUTE_DIRECTORY)) {
853                 asprintf(&rname, "%s%s",ctx->remote_cur_dir,finfo->name);
854                 do_get(ctx, rname, finfo->name, False);
855                 SAFE_FREE(rname);
856                 return;
857         }
858
859         /* handle directories */
860         saved_curdir = talloc_strdup(NULL, ctx->remote_cur_dir);
861
862         ctx->remote_cur_dir = talloc_asprintf_append(NULL, "%s\\", finfo->name);
863
864         string_replace(discard_const_p(char, finfo->name), '\\', '/');
865         if (ctx->lowercase) {
866                 strlower(discard_const_p(char, finfo->name));
867         }
868         
869         if (!directory_exist(finfo->name) && 
870             mkdir(finfo->name,0777) != 0) {
871                 d_printf("failed to create directory %s\n",finfo->name);
872                 return;
873         }
874         
875         if (chdir(finfo->name) != 0) {
876                 d_printf("failed to chdir to directory %s\n",finfo->name);
877                 return;
878         }
879
880         mget_mask = talloc_asprintf(NULL, "%s*", ctx->remote_cur_dir);
881         
882         do_list(ctx, mget_mask, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY,do_mget,False, True);
883         chdir("..");
884         talloc_free(ctx->remote_cur_dir);
885
886         ctx->remote_cur_dir = saved_curdir;
887 }
888
889
890 /****************************************************************************
891 view the file using the pager
892 ****************************************************************************/
893 static int cmd_more(struct smbclient_context *ctx, const char **args)
894 {
895         char *rname;
896         char *pager_cmd;
897         char *lname;
898         char *pager;
899         int fd;
900         int rc = 0;
901
902         lname = talloc_asprintf(ctx, "%s/smbmore.XXXXXX",tmpdir());
903         fd = mkstemp(lname);
904         if (fd == -1) {
905                 d_printf("failed to create temporary file for more\n");
906                 return 1;
907         }
908         close(fd);
909
910         if (!args[1]) {
911                 d_printf("more <filename>\n");
912                 unlink(lname);
913                 return 1;
914         }
915         rname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
916         dos_clean_name(rname);
917
918         rc = do_get(ctx, rname, lname, False);
919
920         pager=getenv("PAGER");
921
922         pager_cmd = talloc_asprintf(ctx, "%s %s",(pager? pager:PAGER), lname);
923         system(pager_cmd);
924         unlink(lname);
925         
926         return rc;
927 }
928
929
930
931 /****************************************************************************
932 do a mget command
933 ****************************************************************************/
934 static int cmd_mget(struct smbclient_context *ctx, const char **args)
935 {
936         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
937         char *mget_mask;
938         int i;
939
940         if (ctx->recurse)
941                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
942         
943         for (i = 1; args[i]; i++) {
944                 mget_mask = talloc_strdup(ctx,ctx->remote_cur_dir);
945                 if(mget_mask[strlen(mget_mask)-1]!='\\')
946                         mget_mask = talloc_append_string(ctx, mget_mask, "\\");
947                 
948                 mget_mask = talloc_strdup(ctx, args[i]);
949                 if (mget_mask[0] != '\\')
950                         mget_mask = talloc_append_string(ctx, mget_mask, "\\");
951                 do_list(ctx, mget_mask, attribute,do_mget,False,True);
952         }
953
954         if (!*mget_mask) {
955                 mget_mask = talloc_asprintf(ctx, "%s\\*", ctx->remote_cur_dir);
956                 do_list(ctx, mget_mask, attribute,do_mget,False,True);
957         }
958
959         talloc_free(mget_mask);
960         
961         return 0;
962 }
963
964
965 /****************************************************************************
966 make a directory of name "name"
967 ****************************************************************************/
968 static NTSTATUS do_mkdir(struct smbclient_context *ctx, char *name)
969 {
970         NTSTATUS status;
971
972         if (NT_STATUS_IS_ERR(status = smbcli_mkdir(ctx->cli->tree, name))) {
973                 d_printf("%s making remote directory %s\n",
974                          smbcli_errstr(ctx->cli->tree),name);
975                 return status;
976         }
977
978         return status;
979 }
980
981
982 /****************************************************************************
983  Exit client.
984 ****************************************************************************/
985 static int cmd_quit(struct smbclient_context *ctx, const char **args)
986 {
987         talloc_free(ctx);
988         exit(0);
989         /* NOTREACHED */
990         return 0;
991 }
992
993
994 /****************************************************************************
995   make a directory
996   ****************************************************************************/
997 static int cmd_mkdir(struct smbclient_context *ctx, const char **args)
998 {
999         char *mask, *p;
1000   
1001         if (!args[1]) {
1002                 if (!ctx->recurse)
1003                         d_printf("mkdir <dirname>\n");
1004                 return 1;
1005         }
1006
1007         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir,args[1]);
1008
1009         if (ctx->recurse) {
1010                 dos_clean_name(mask);
1011
1012                 trim_string(mask,".",NULL);
1013                 for (p = strtok(mask,"/\\"); p; p = strtok(p, "/\\")) {
1014                         char *parent = talloc_strndup(ctx, mask, PTR_DIFF(p, mask));
1015                         
1016                         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, parent))) { 
1017                                 do_mkdir(ctx, parent);
1018                         }
1019
1020                         talloc_free(parent);
1021                 }        
1022         } else {
1023                 do_mkdir(ctx, mask);
1024         }
1025         
1026         return 0;
1027 }
1028
1029 /****************************************************************************
1030 show 8.3 name of a file
1031 ****************************************************************************/
1032 static int cmd_altname(struct smbclient_context *ctx, const char **args)
1033 {
1034         const char *altname;
1035         char *name;
1036   
1037         if (!args[1]) {
1038                 d_printf("altname <file>\n");
1039                 return 1;
1040         }
1041
1042         name = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1043
1044         if (!NT_STATUS_IS_OK(smbcli_qpathinfo_alt_name(ctx->cli->tree, name, &altname))) {
1045                 d_printf("%s getting alt name for %s\n",
1046                          smbcli_errstr(ctx->cli->tree),name);
1047                 return(False);
1048         }
1049         d_printf("%s\n", altname);
1050
1051         return 0;
1052 }
1053
1054
1055 /****************************************************************************
1056   put a single file
1057   ****************************************************************************/
1058 static int do_put(struct smbclient_context *ctx, char *rname, char *lname, BOOL reput)
1059 {
1060         int fnum;
1061         XFILE *f;
1062         size_t start = 0;
1063         off_t nread = 0;
1064         uint8_t *buf = NULL;
1065         int maxwrite = io_bufsize;
1066         int rc = 0;
1067         
1068         struct timeval tp_start;
1069         GetTimeOfDay(&tp_start);
1070
1071         if (reput) {
1072                 fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT, DENY_NONE);
1073                 if (fnum >= 0) {
1074                         if (NT_STATUS_IS_ERR(smbcli_qfileinfo(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL)) &&
1075                             NT_STATUS_IS_ERR(smbcli_getattrE(ctx->cli->tree, fnum, NULL, &start, NULL, NULL, NULL))) {
1076                                 d_printf("getattrib: %s\n",smbcli_errstr(ctx->cli->tree));
1077                                 return 1;
1078                         }
1079                 }
1080         } else {
1081                 fnum = smbcli_open(ctx->cli->tree, rname, O_RDWR|O_CREAT|O_TRUNC, 
1082                                 DENY_NONE);
1083         }
1084   
1085         if (fnum == -1) {
1086                 d_printf("%s opening remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
1087                 return 1;
1088         }
1089
1090         /* allow files to be piped into smbclient
1091            jdblair 24.jun.98
1092
1093            Note that in this case this function will exit(0) rather
1094            than returning. */
1095         if (!strcmp(lname, "-")) {
1096                 f = x_stdin;
1097                 /* size of file is not known */
1098         } else {
1099                 f = x_fopen(lname,O_RDONLY, 0);
1100                 if (f && reput) {
1101                         if (x_tseek(f, start, SEEK_SET) == -1) {
1102                                 d_printf("Error seeking local file\n");
1103                                 return 1;
1104                         }
1105                 }
1106         }
1107
1108         if (!f) {
1109                 d_printf("Error opening local file %s\n",lname);
1110                 return 1;
1111         }
1112
1113   
1114         DEBUG(1,("putting file %s as %s ",lname,
1115                  rname));
1116   
1117         buf = (uint8_t *)malloc(maxwrite);
1118         if (!buf) {
1119                 d_printf("ERROR: Not enough memory!\n");
1120                 return 1;
1121         }
1122         while (!x_feof(f)) {
1123                 int n = maxwrite;
1124                 int ret;
1125
1126                 if ((n = readfile(buf,n,f,ctx->translation)) < 1) {
1127                         if((n == 0) && x_feof(f))
1128                                 break; /* Empty local file. */
1129
1130                         d_printf("Error reading local file: %s\n", strerror(errno));
1131                         rc = 1;
1132                         break;
1133                 }
1134
1135                 ret = smbcli_write(ctx->cli->tree, fnum, 0, buf, nread + start, n);
1136
1137                 if (n != ret) {
1138                         d_printf("Error writing file: %s\n", smbcli_errstr(ctx->cli->tree));
1139                         rc = 1;
1140                         break;
1141                 } 
1142
1143                 nread += n;
1144         }
1145
1146         if (NT_STATUS_IS_ERR(smbcli_close(ctx->cli->tree, fnum))) {
1147                 d_printf("%s closing remote file %s\n",smbcli_errstr(ctx->cli->tree),rname);
1148                 x_fclose(f);
1149                 SAFE_FREE(buf);
1150                 return 1;
1151         }
1152
1153         
1154         if (f != x_stdin) {
1155                 x_fclose(f);
1156         }
1157
1158         SAFE_FREE(buf);
1159
1160         {
1161                 struct timeval tp_end;
1162                 int this_time;
1163                 
1164                 GetTimeOfDay(&tp_end);
1165                 this_time = 
1166                         (tp_end.tv_sec - tp_start.tv_sec)*1000 +
1167                         (tp_end.tv_usec - tp_start.tv_usec)/1000;
1168                 put_total_time_ms += this_time;
1169                 put_total_size += nread;
1170                 
1171                 DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
1172                          nread / (1.024*this_time + 1.0e-4),
1173                          put_total_size / (1.024*put_total_time_ms)));
1174         }
1175
1176         if (f == x_stdin) {
1177                 talloc_free(ctx);
1178                 exit(0);
1179         }
1180         
1181         return rc;
1182 }
1183
1184  
1185
1186 /****************************************************************************
1187   put a file
1188   ****************************************************************************/
1189 static int cmd_put(struct smbclient_context *ctx, const char **args)
1190 {
1191         char *lname;
1192         char *rname;
1193         
1194         if (!args[1]) {
1195                 d_printf("put <filename>\n");
1196                 return 1;
1197         }
1198
1199         lname = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
1200   
1201         if (args[2])
1202                 rname = talloc_strdup(ctx, args[2]);
1203         else
1204                 rname = talloc_strdup(ctx, lname);
1205         
1206         dos_clean_name(rname);
1207
1208         /* allow '-' to represent stdin
1209            jdblair, 24.jun.98 */
1210         if (!file_exist(lname) && (strcmp(lname,"-"))) {
1211                 d_printf("%s does not exist\n",lname);
1212                 return 1;
1213         }
1214
1215         return do_put(ctx, rname, lname, False);
1216 }
1217
1218 /*************************************
1219   File list structure
1220 *************************************/
1221
1222 static struct file_list {
1223         struct file_list *prev, *next;
1224         char *file_path;
1225         BOOL isdir;
1226 } *file_list;
1227
1228 /****************************************************************************
1229   Free a file_list structure
1230 ****************************************************************************/
1231
1232 static void free_file_list (struct file_list * list)
1233 {
1234         struct file_list *tmp;
1235         
1236         while (list)
1237         {
1238                 tmp = list;
1239                 DLIST_REMOVE(list, list);
1240                 SAFE_FREE(tmp->file_path);
1241                 SAFE_FREE(tmp);
1242         }
1243 }
1244
1245 /****************************************************************************
1246   seek in a directory/file list until you get something that doesn't start with
1247   the specified name
1248   ****************************************************************************/
1249 static BOOL seek_list(struct file_list *list, char *name)
1250 {
1251         while (list) {
1252                 trim_string(list->file_path,"./","\n");
1253                 if (strncmp(list->file_path, name, strlen(name)) != 0) {
1254                         return(True);
1255                 }
1256                 list = list->next;
1257         }
1258       
1259         return(False);
1260 }
1261
1262 /****************************************************************************
1263   set the file selection mask
1264   ****************************************************************************/
1265 static int cmd_select(struct smbclient_context *ctx, const char **args)
1266 {
1267         talloc_free(ctx->fileselection);
1268         ctx->fileselection = talloc_strdup(NULL, args[1]);
1269
1270         return 0;
1271 }
1272
1273 /*******************************************************************
1274   A readdir wrapper which just returns the file name.
1275  ********************************************************************/
1276 static const char *readdirname(DIR *p)
1277 {
1278         struct dirent *ptr;
1279         char *dname;
1280
1281         if (!p)
1282                 return(NULL);
1283   
1284         ptr = (struct dirent *)readdir(p);
1285         if (!ptr)
1286                 return(NULL);
1287
1288         dname = ptr->d_name;
1289
1290 #ifdef NEXT2
1291         if (telldir(p) < 0)
1292                 return(NULL);
1293 #endif
1294
1295 #ifdef HAVE_BROKEN_READDIR
1296         /* using /usr/ucb/cc is BAD */
1297         dname = dname - 2;
1298 #endif
1299
1300         {
1301                 static char *buf;
1302                 int len = NAMLEN(ptr);
1303                 buf = talloc_strndup(NULL, dname, len);
1304                 dname = buf;
1305         }
1306
1307         return(dname);
1308 }
1309
1310 /****************************************************************************
1311   Recursive file matching function act as find
1312   match must be always set to True when calling this function
1313 ****************************************************************************/
1314 static int file_find(struct smbclient_context *ctx, struct file_list **list, const char *directory, 
1315                       const char *expression, BOOL match)
1316 {
1317         DIR *dir;
1318         struct file_list *entry;
1319         struct stat statbuf;
1320         int ret;
1321         char *path;
1322         BOOL isdir;
1323         const char *dname;
1324
1325         dir = opendir(directory);
1326         if (!dir) return -1;
1327         
1328         while ((dname = readdirname(dir))) {
1329                 if (!strcmp("..", dname)) continue;
1330                 if (!strcmp(".", dname)) continue;
1331                 
1332                 if (asprintf(&path, "%s/%s", directory, dname) <= 0) {
1333                         continue;
1334                 }
1335
1336                 isdir = False;
1337                 if (!match || !gen_fnmatch(expression, dname)) {
1338                         if (ctx->recurse) {
1339                                 ret = stat(path, &statbuf);
1340                                 if (ret == 0) {
1341                                         if (S_ISDIR(statbuf.st_mode)) {
1342                                                 isdir = True;
1343                                                 ret = file_find(ctx, list, path, expression, False);
1344                                         }
1345                                 } else {
1346                                         d_printf("file_find: cannot stat file %s\n", path);
1347                                 }
1348                                 
1349                                 if (ret == -1) {
1350                                         SAFE_FREE(path);
1351                                         closedir(dir);
1352                                         return -1;
1353                                 }
1354                         }
1355                         entry = malloc_p(struct file_list);
1356                         if (!entry) {
1357                                 d_printf("Out of memory in file_find\n");
1358                                 closedir(dir);
1359                                 return -1;
1360                         }
1361                         entry->file_path = path;
1362                         entry->isdir = isdir;
1363                         DLIST_ADD(*list, entry);
1364                 } else {
1365                         SAFE_FREE(path);
1366                 }
1367         }
1368
1369         closedir(dir);
1370         return 0;
1371 }
1372
1373 /****************************************************************************
1374   mput some files
1375   ****************************************************************************/
1376 static int cmd_mput(struct smbclient_context *ctx, const char **args)
1377 {
1378         int i;
1379         
1380         for (i = 1; args[i]; i++) {
1381                 int ret;
1382                 struct file_list *temp_list;
1383                 char *quest, *lname, *rname;
1384
1385                 printf("%s\n", args[i]);
1386         
1387                 file_list = NULL;
1388
1389                 ret = file_find(ctx, &file_list, ".", args[i], True);
1390                 if (ret) {
1391                         free_file_list(file_list);
1392                         continue;
1393                 }
1394                 
1395                 quest = NULL;
1396                 lname = NULL;
1397                 rname = NULL;
1398                                 
1399                 for (temp_list = file_list; temp_list; 
1400                      temp_list = temp_list->next) {
1401
1402                         SAFE_FREE(lname);
1403                         if (asprintf(&lname, "%s/", temp_list->file_path) <= 0)
1404                                 continue;
1405                         trim_string(lname, "./", "/");
1406                         
1407                         /* check if it's a directory */
1408                         if (temp_list->isdir) {
1409                                 /* if (!recurse) continue; */
1410                                 
1411                                 SAFE_FREE(quest);
1412                                 if (asprintf(&quest, "Put directory %s? ", lname) < 0) break;
1413                                 if (ctx->prompt && !yesno(quest)) { /* No */
1414                                         /* Skip the directory */
1415                                         lname[strlen(lname)-1] = '/';
1416                                         if (!seek_list(temp_list, lname))
1417                                                 break;              
1418                                 } else { /* Yes */
1419                                         SAFE_FREE(rname);
1420                                         if(asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
1421                                         dos_format(rname);
1422                                         if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, rname)) && 
1423                                             NT_STATUS_IS_ERR(do_mkdir(ctx, rname))) {
1424                                                 DEBUG (0, ("Unable to make dir, skipping..."));
1425                                                 /* Skip the directory */
1426                                                 lname[strlen(lname)-1] = '/';
1427                                                 if (!seek_list(temp_list, lname))
1428                                                         break;
1429                                         }
1430                                 }
1431                                 continue;
1432                         } else {
1433                                 SAFE_FREE(quest);
1434                                 if (asprintf(&quest,"Put file %s? ", lname) < 0) break;
1435                                 if (ctx->prompt && !yesno(quest)) /* No */
1436                                         continue;
1437                                 
1438                                 /* Yes */
1439                                 SAFE_FREE(rname);
1440                                 if (asprintf(&rname, "%s%s", ctx->remote_cur_dir, lname) < 0) break;
1441                         }
1442
1443                         dos_format(rname);
1444
1445                         do_put(ctx, rname, lname, False);
1446                 }
1447                 free_file_list(file_list);
1448                 SAFE_FREE(quest);
1449                 SAFE_FREE(lname);
1450                 SAFE_FREE(rname);
1451         }
1452
1453         return 0;
1454 }
1455
1456
1457 /****************************************************************************
1458   print a file
1459   ****************************************************************************/
1460 static int cmd_print(struct smbclient_context *ctx, const char **args)
1461 {
1462         char *lname, *rname;
1463         char *p;
1464
1465         if (!args[1]) {
1466                 d_printf("print <filename>\n");
1467                 return 1;
1468         }
1469
1470         lname = talloc_strdup(ctx, args[1]);
1471
1472         rname = talloc_strdup(ctx, lname);
1473         p = strrchr_m(rname,'/');
1474         if (p) {
1475                 slprintf(rname, sizeof(rname)-1, "%s-%d", p+1, (int)getpid());
1476         }
1477
1478         if (strequal(lname,"-")) {
1479                 slprintf(rname, sizeof(rname)-1, "stdin-%d", (int)getpid());
1480         }
1481
1482         return do_put(ctx, rname, lname, False);
1483 }
1484
1485
1486 static int cmd_rewrite(struct smbclient_context *ctx, const char **args)
1487 {
1488         d_printf("REWRITE: command not implemented (FIXME!)\n");
1489         
1490         return 0;
1491 }
1492
1493 /****************************************************************************
1494 delete some files
1495 ****************************************************************************/
1496 static int cmd_del(struct smbclient_context *ctx, const char **args)
1497 {
1498         char *mask;
1499         uint16_t attribute = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
1500
1501         if (ctx->recurse)
1502                 attribute |= FILE_ATTRIBUTE_DIRECTORY;
1503         
1504         if (!args[1]) {
1505                 d_printf("del <filename>\n");
1506                 return 1;
1507         }
1508         mask = talloc_asprintf(ctx,"%s%s", ctx->remote_cur_dir, args[1]);
1509
1510         if (NT_STATUS_IS_ERR(smbcli_unlink(ctx->cli->tree, mask))) {
1511                 d_printf("%s deleting remote file %s\n",smbcli_errstr(ctx->cli->tree),mask);
1512         }
1513         
1514         return 0;
1515 }
1516
1517
1518 /****************************************************************************
1519 delete a whole directory tree
1520 ****************************************************************************/
1521 static int cmd_deltree(struct smbclient_context *ctx, const char **args)
1522 {
1523         char *dname;
1524         int ret;
1525
1526         if (!args[1]) {
1527                 d_printf("deltree <dirname>\n");
1528                 return 1;
1529         }
1530
1531         dname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1532         
1533         ret = smbcli_deltree(ctx->cli->tree, dname);
1534
1535         if (ret == -1) {
1536                 printf("Failed to delete tree %s - %s\n", dname, smbcli_errstr(ctx->cli->tree));
1537                 return -1;
1538         }
1539
1540         printf("Deleted %d files in %s\n", ret, dname);
1541         
1542         return 0;
1543 }
1544
1545 typedef struct {
1546         const char  *level_name;
1547         enum smb_fsinfo_level level;
1548 } fsinfo_level_t;
1549
1550 fsinfo_level_t fsinfo_levels[] = {
1551         {"dskattr", RAW_QFS_DSKATTR},
1552         {"allocation", RAW_QFS_ALLOCATION},
1553         {"volume", RAW_QFS_VOLUME},
1554         {"volumeinfo", RAW_QFS_VOLUME_INFO},
1555         {"sizeinfo", RAW_QFS_SIZE_INFO},
1556         {"deviceinfo", RAW_QFS_DEVICE_INFO},
1557         {"attributeinfo", RAW_QFS_ATTRIBUTE_INFO},
1558         {"unixinfo", RAW_QFS_UNIX_INFO},
1559         {"volume-information", RAW_QFS_VOLUME_INFORMATION},
1560         {"size-information", RAW_QFS_SIZE_INFORMATION},
1561         {"device-information", RAW_QFS_DEVICE_INFORMATION},
1562         {"attribute-information", RAW_QFS_ATTRIBUTE_INFORMATION},
1563         {"quota-information", RAW_QFS_QUOTA_INFORMATION},
1564         {"fullsize-information", RAW_QFS_FULL_SIZE_INFORMATION},
1565         {"objectid", RAW_QFS_OBJECTID_INFORMATION},
1566         {NULL, RAW_QFS_GENERIC}
1567 };
1568
1569
1570 static int cmd_fsinfo(struct smbclient_context *ctx, const char **args)
1571 {
1572         union smb_fsinfo fsinfo;
1573         NTSTATUS status;
1574         fsinfo_level_t *fsinfo_level;
1575         
1576         if (!args[1]) {
1577                 d_printf("fsinfo <level>, where level is one of following:\n");
1578                 fsinfo_level = fsinfo_levels;
1579                 while(fsinfo_level->level_name) {
1580                         d_printf("%s\n", fsinfo_level->level_name);
1581                         fsinfo_level++;
1582                 }
1583                 return 1;
1584         }
1585         
1586         fsinfo_level = fsinfo_levels;
1587         while(fsinfo_level->level_name && !strequal(args[1],fsinfo_level->level_name)) {
1588                 fsinfo_level++;
1589         }
1590   
1591         if (!fsinfo_level->level_name) {
1592                 d_printf("wrong level name!\n");
1593                 return 1;
1594         }
1595   
1596         fsinfo.generic.level = fsinfo_level->level;
1597         status = smb_raw_fsinfo(ctx->cli->tree, ctx, &fsinfo);
1598         if (!NT_STATUS_IS_OK(status)) {
1599                 d_printf("fsinfo-level-%s - %s\n", fsinfo_level->level_name, nt_errstr(status));
1600                 return 1;
1601         }
1602
1603         d_printf("fsinfo-level-%s:\n", fsinfo_level->level_name);
1604         switch(fsinfo.generic.level) {
1605         case RAW_QFS_DSKATTR:
1606                 d_printf("\tunits_total:                %hu\n", 
1607                          (unsigned short) fsinfo.dskattr.out.units_total);
1608                 d_printf("\tblocks_per_unit:            %hu\n", 
1609                          (unsigned short) fsinfo.dskattr.out.blocks_per_unit);
1610                 d_printf("\tblocks_size:                %hu\n", 
1611                          (unsigned short) fsinfo.dskattr.out.block_size);
1612                 d_printf("\tunits_free:                 %hu\n", 
1613                          (unsigned short) fsinfo.dskattr.out.units_free);
1614                 break;
1615         case RAW_QFS_ALLOCATION:
1616                 d_printf("\tfs_id:                      %lu\n", 
1617                          (unsigned long) fsinfo.allocation.out.fs_id);
1618                 d_printf("\tsectors_per_unit:           %lu\n", 
1619                          (unsigned long) fsinfo.allocation.out.sectors_per_unit);
1620                 d_printf("\ttotal_alloc_units:          %lu\n", 
1621                          (unsigned long) fsinfo.allocation.out.total_alloc_units);
1622                 d_printf("\tavail_alloc_units:          %lu\n", 
1623                          (unsigned long) fsinfo.allocation.out.avail_alloc_units);
1624                 d_printf("\tbytes_per_sector:           %hu\n", 
1625                          (unsigned short) fsinfo.allocation.out.bytes_per_sector);
1626                 break;
1627         case RAW_QFS_VOLUME:
1628                 d_printf("\tserial_number:              %lu\n", 
1629                          (unsigned long) fsinfo.volume.out.serial_number);
1630                 d_printf("\tvolume_name:                %s\n", fsinfo.volume.out.volume_name.s);
1631                 break;
1632         case RAW_QFS_VOLUME_INFO:
1633         case RAW_QFS_VOLUME_INFORMATION:
1634                 d_printf("\tcreate_time:                %s\n",
1635                          nt_time_string(ctx,fsinfo.volume_info.out.create_time));
1636                 d_printf("\tserial_number:              %lu\n", 
1637                          (unsigned long) fsinfo.volume_info.out.serial_number);
1638                 d_printf("\tvolume_name:                %s\n", fsinfo.volume_info.out.volume_name.s);
1639                 break;
1640         case RAW_QFS_SIZE_INFO:
1641         case RAW_QFS_SIZE_INFORMATION:
1642                 d_printf("\ttotal_alloc_units:          %llu\n", 
1643                          (unsigned long long) fsinfo.size_info.out.total_alloc_units);
1644                 d_printf("\tavail_alloc_units:          %llu\n", 
1645                          (unsigned long long) fsinfo.size_info.out.avail_alloc_units);
1646                 d_printf("\tsectors_per_unit:           %lu\n", 
1647                          (unsigned long) fsinfo.size_info.out.sectors_per_unit);
1648                 d_printf("\tbytes_per_sector:           %lu\n", 
1649                          (unsigned long) fsinfo.size_info.out.bytes_per_sector);
1650                 break;
1651         case RAW_QFS_DEVICE_INFO:
1652         case RAW_QFS_DEVICE_INFORMATION:
1653                 d_printf("\tdevice_type:                %lu\n", 
1654                          (unsigned long) fsinfo.device_info.out.device_type);
1655                 d_printf("\tcharacteristics:            0x%lx\n", 
1656                          (unsigned long) fsinfo.device_info.out.characteristics);
1657                 break;
1658         case RAW_QFS_ATTRIBUTE_INFORMATION:
1659         case RAW_QFS_ATTRIBUTE_INFO:
1660                 d_printf("\tfs_attr:                    0x%lx\n", 
1661                          (unsigned long) fsinfo.attribute_info.out.fs_attr);
1662                 d_printf("\tmax_file_component_length:  %lu\n", 
1663                          (unsigned long) fsinfo.attribute_info.out.max_file_component_length);
1664                 d_printf("\tfs_type:                    %s\n", fsinfo.attribute_info.out.fs_type.s);
1665                 break;
1666         case RAW_QFS_UNIX_INFO:
1667                 d_printf("\tmajor_version:              %hu\n", 
1668                          (unsigned short) fsinfo.unix_info.out.major_version);
1669                 d_printf("\tminor_version:              %hu\n", 
1670                          (unsigned short) fsinfo.unix_info.out.minor_version);
1671                 d_printf("\tcapability:                 0x%llx\n", 
1672                          (unsigned long long) fsinfo.unix_info.out.capability);
1673                 break;
1674         case RAW_QFS_QUOTA_INFORMATION:
1675                 d_printf("\tunknown[3]:                 [%llu,%llu,%llu]\n", 
1676                          (unsigned long long) fsinfo.quota_information.out.unknown[0],
1677                          (unsigned long long) fsinfo.quota_information.out.unknown[1],
1678                          (unsigned long long) fsinfo.quota_information.out.unknown[2]);
1679                 d_printf("\tquota_soft:                 %llu\n", 
1680                          (unsigned long long) fsinfo.quota_information.out.quota_soft);
1681                 d_printf("\tquota_hard:                 %llu\n", 
1682                          (unsigned long long) fsinfo.quota_information.out.quota_hard);
1683                 d_printf("\tquota_flags:                0x%llx\n", 
1684                          (unsigned long long) fsinfo.quota_information.out.quota_flags);
1685                 break;
1686         case RAW_QFS_FULL_SIZE_INFORMATION:
1687                 d_printf("\ttotal_alloc_units:          %llu\n", 
1688                          (unsigned long long) fsinfo.full_size_information.out.total_alloc_units);
1689                 d_printf("\tcall_avail_alloc_units:     %llu\n", 
1690                          (unsigned long long) fsinfo.full_size_information.out.call_avail_alloc_units);
1691                 d_printf("\tactual_avail_alloc_units:   %llu\n", 
1692                          (unsigned long long) fsinfo.full_size_information.out.actual_avail_alloc_units);
1693                 d_printf("\tsectors_per_unit:           %lu\n", 
1694                          (unsigned long) fsinfo.full_size_information.out.sectors_per_unit);
1695                 d_printf("\tbytes_per_sector:           %lu\n", 
1696                          (unsigned long) fsinfo.full_size_information.out.bytes_per_sector);
1697                 break;
1698         case RAW_QFS_OBJECTID_INFORMATION:
1699                 d_printf("\tGUID:                       %s\n", 
1700                          GUID_string(ctx,&fsinfo.objectid_information.out.guid));
1701                 d_printf("\tunknown[6]:                 [%llu,%llu,%llu,%llu,%llu,%llu]\n", 
1702                          (unsigned long long) fsinfo.objectid_information.out.unknown[0],
1703                          (unsigned long long) fsinfo.objectid_information.out.unknown[2],
1704                          (unsigned long long) fsinfo.objectid_information.out.unknown[3],
1705                          (unsigned long long) fsinfo.objectid_information.out.unknown[4],
1706                          (unsigned long long) fsinfo.objectid_information.out.unknown[5],
1707                          (unsigned long long) fsinfo.objectid_information.out.unknown[6] );
1708                 break;
1709         case RAW_QFS_GENERIC:
1710                 d_printf("\twrong level returned\n");
1711                 break;
1712         }
1713   
1714         return 0;
1715 }
1716
1717 /****************************************************************************
1718 show as much information as possible about a file
1719 ****************************************************************************/
1720 static int cmd_allinfo(struct smbclient_context *ctx, const char **args)
1721 {
1722         char *fname;
1723         union smb_fileinfo finfo;
1724         NTSTATUS status;
1725
1726         if (!args[1]) {
1727                 d_printf("allinfo <filename>\n");
1728                 return 1;
1729         }
1730         fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1731
1732         /* first a ALL_INFO QPATHINFO */
1733         finfo.generic.level = RAW_FILEINFO_ALL_INFO;
1734         finfo.generic.in.file.path = fname;
1735         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1736         if (!NT_STATUS_IS_OK(status)) {
1737                 d_printf("%s - %s\n", fname, nt_errstr(status));
1738                 return 1;
1739         }
1740
1741         d_printf("\tcreate_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.create_time));
1742         d_printf("\taccess_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.access_time));
1743         d_printf("\twrite_time:     %s\n", nt_time_string(ctx, finfo.all_info.out.write_time));
1744         d_printf("\tchange_time:    %s\n", nt_time_string(ctx, finfo.all_info.out.change_time));
1745         d_printf("\tattrib:         0x%x\n", finfo.all_info.out.attrib);
1746         d_printf("\talloc_size:     %lu\n", (unsigned long)finfo.all_info.out.alloc_size);
1747         d_printf("\tsize:           %lu\n", (unsigned long)finfo.all_info.out.size);
1748         d_printf("\tnlink:          %u\n", finfo.all_info.out.nlink);
1749         d_printf("\tdelete_pending: %u\n", finfo.all_info.out.delete_pending);
1750         d_printf("\tdirectory:      %u\n", finfo.all_info.out.directory);
1751         d_printf("\tea_size:        %u\n", finfo.all_info.out.ea_size);
1752         d_printf("\tfname:          '%s'\n", finfo.all_info.out.fname.s);
1753
1754         /* 8.3 name if any */
1755         finfo.generic.level = RAW_FILEINFO_ALT_NAME_INFO;
1756         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1757         if (NT_STATUS_IS_OK(status)) {
1758                 d_printf("\talt_name:       %s\n", finfo.alt_name_info.out.fname.s);
1759         }
1760
1761         /* file_id if available */
1762         finfo.generic.level = RAW_FILEINFO_INTERNAL_INFORMATION;
1763         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1764         if (NT_STATUS_IS_OK(status)) {
1765                 d_printf("\tfile_id         %.0f\n", 
1766                          (double)finfo.internal_information.out.file_id);
1767         }
1768
1769         /* the EAs, if any */
1770         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1771         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1772         if (NT_STATUS_IS_OK(status)) {
1773                 int i;
1774                 for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1775                         d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1776                                  finfo.all_eas.out.eas[i].flags,
1777                                  (int)finfo.all_eas.out.eas[i].value.length,
1778                                  finfo.all_eas.out.eas[i].name.s);
1779                 }
1780         }
1781
1782         /* streams, if available */
1783         finfo.generic.level = RAW_FILEINFO_STREAM_INFO;
1784         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1785         if (NT_STATUS_IS_OK(status)) {
1786                 int i;
1787                 for (i=0;i<finfo.stream_info.out.num_streams;i++) {
1788                         d_printf("\tstream %d:\n", i);
1789                         d_printf("\t\tsize       %ld\n", 
1790                                  (long)finfo.stream_info.out.streams[i].size);
1791                         d_printf("\t\talloc size %ld\n", 
1792                                  (long)finfo.stream_info.out.streams[i].alloc_size);
1793                         d_printf("\t\tname       %s\n", finfo.stream_info.out.streams[i].stream_name.s);
1794                 }
1795         }       
1796
1797         /* dev/inode if available */
1798         finfo.generic.level = RAW_FILEINFO_COMPRESSION_INFORMATION;
1799         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1800         if (NT_STATUS_IS_OK(status)) {
1801                 d_printf("\tcompressed size %ld\n", (long)finfo.compression_info.out.compressed_size);
1802                 d_printf("\tformat          %ld\n", (long)finfo.compression_info.out.format);
1803                 d_printf("\tunit_shift      %ld\n", (long)finfo.compression_info.out.unit_shift);
1804                 d_printf("\tchunk_shift     %ld\n", (long)finfo.compression_info.out.chunk_shift);
1805                 d_printf("\tcluster_shift   %ld\n", (long)finfo.compression_info.out.cluster_shift);
1806         }
1807
1808         return 0;
1809 }
1810
1811
1812 /****************************************************************************
1813 shows EA contents
1814 ****************************************************************************/
1815 static int cmd_eainfo(struct smbclient_context *ctx, const char **args)
1816 {
1817         char *fname;
1818         union smb_fileinfo finfo;
1819         NTSTATUS status;
1820         int i;
1821
1822         if (!args[1]) {
1823                 d_printf("eainfo <filename>\n");
1824                 return 1;
1825         }
1826         fname = talloc_strdup(ctx, args[1]);
1827
1828         finfo.generic.level = RAW_FILEINFO_ALL_EAS;
1829         finfo.generic.in.file.path = fname;
1830         status = smb_raw_pathinfo(ctx->cli->tree, ctx, &finfo);
1831         
1832         if (!NT_STATUS_IS_OK(status)) {
1833                 d_printf("RAW_FILEINFO_ALL_EAS - %s\n", nt_errstr(status));
1834                 return 1;
1835         }
1836
1837         d_printf("%s has %d EAs\n", fname, finfo.all_eas.out.num_eas);
1838
1839         for (i=0;i<finfo.all_eas.out.num_eas;i++) {
1840                 d_printf("\tEA[%d] flags=%d len=%d '%s'\n", i,
1841                          finfo.all_eas.out.eas[i].flags,
1842                          (int)finfo.all_eas.out.eas[i].value.length,
1843                          finfo.all_eas.out.eas[i].name.s);
1844                 fflush(stdout);
1845                 dump_data(0, 
1846                           finfo.all_eas.out.eas[i].value.data,
1847                           finfo.all_eas.out.eas[i].value.length);
1848         }
1849
1850         return 0;
1851 }
1852
1853
1854 /****************************************************************************
1855 show any ACL on a file
1856 ****************************************************************************/
1857 static int cmd_acl(struct smbclient_context *ctx, const char **args)
1858 {
1859         char *fname;
1860         union smb_fileinfo query;
1861         NTSTATUS status;
1862         int fnum;
1863
1864         if (!args[1]) {
1865                 d_printf("acl <filename>\n");
1866                 return 1;
1867         }
1868         fname = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
1869
1870         fnum = smbcli_nt_create_full(ctx->cli->tree, fname, 0, 
1871                                      SEC_STD_READ_CONTROL,
1872                                      0,
1873                                      NTCREATEX_SHARE_ACCESS_DELETE|
1874                                      NTCREATEX_SHARE_ACCESS_READ|
1875                                      NTCREATEX_SHARE_ACCESS_WRITE, 
1876                                      NTCREATEX_DISP_OPEN,
1877                                      0, 0);
1878         if (fnum == -1) {
1879                 d_printf("%s - %s\n", fname, smbcli_errstr(ctx->cli->tree));
1880                 return -1;
1881         }
1882
1883         query.query_secdesc.level = RAW_FILEINFO_SEC_DESC;
1884         query.query_secdesc.in.file.fnum = fnum;
1885         query.query_secdesc.in.secinfo_flags = 0x7;
1886
1887         status = smb_raw_fileinfo(ctx->cli->tree, ctx, &query);
1888         if (!NT_STATUS_IS_OK(status)) {
1889                 d_printf("%s - %s\n", fname, nt_errstr(status));
1890                 return 1;
1891         }
1892
1893         NDR_PRINT_DEBUG(security_descriptor, query.query_secdesc.out.sd);
1894
1895         return 0;
1896 }
1897
1898 /****************************************************************************
1899 lookup a name or sid
1900 ****************************************************************************/
1901 static int cmd_lookup(struct smbclient_context *ctx, const char **args)
1902 {
1903         NTSTATUS status;
1904         struct dom_sid *sid;
1905
1906         if (!args[1]) {
1907                 d_printf("lookup <sid|name>\n");
1908                 return 1;
1909         }
1910
1911         sid = dom_sid_parse_talloc(ctx, args[1]);
1912         if (sid == NULL) {
1913                 const char *sidstr;
1914                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sidstr);
1915                 if (!NT_STATUS_IS_OK(status)) {
1916                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1917                         return 1;
1918                 }
1919
1920                 d_printf("%s\n", sidstr);
1921         } else {
1922                 const char *name;
1923                 status = smblsa_lookup_sid(ctx->cli, args[1], ctx, &name);
1924                 if (!NT_STATUS_IS_OK(status)) {
1925                         d_printf("lsa_LookupSids - %s\n", nt_errstr(status));
1926                         return 1;
1927                 }
1928
1929                 d_printf("%s\n", name);
1930         }
1931
1932         return 0;
1933 }
1934
1935 /****************************************************************************
1936 show privileges for a user
1937 ****************************************************************************/
1938 static int cmd_privileges(struct smbclient_context *ctx, const char **args)
1939 {
1940         NTSTATUS status;
1941         struct dom_sid *sid;
1942         struct lsa_RightSet rights;
1943         unsigned i;
1944
1945         if (!args[1]) {
1946                 d_printf("privileges <sid|name>\n");
1947                 return 1;
1948         }
1949
1950         sid = dom_sid_parse_talloc(ctx, args[1]);
1951         if (sid == NULL) {
1952                 const char *sid_str;
1953                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
1954                 if (!NT_STATUS_IS_OK(status)) {
1955                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1956                         return 1;
1957                 }
1958                 sid = dom_sid_parse_talloc(ctx, sid_str);
1959         }
1960
1961         status = smblsa_sid_privileges(ctx->cli, sid, ctx, &rights);
1962         if (!NT_STATUS_IS_OK(status)) {
1963                 d_printf("lsa_EnumAccountRights - %s\n", nt_errstr(status));
1964                 return 1;
1965         }
1966
1967         for (i=0;i<rights.count;i++) {
1968                 d_printf("\t%s\n", rights.names[i].string);
1969         }
1970
1971         return 0;
1972 }
1973
1974
1975 /****************************************************************************
1976 add privileges for a user
1977 ****************************************************************************/
1978 static int cmd_addprivileges(struct smbclient_context *ctx, const char **args)
1979 {
1980         NTSTATUS status;
1981         struct dom_sid *sid;
1982         struct lsa_RightSet rights;
1983         int i;
1984
1985         if (!args[1]) {
1986                 d_printf("addprivileges <sid|name> <privilege...>\n");
1987                 return 1;
1988         }
1989
1990         sid = dom_sid_parse_talloc(ctx, args[1]);
1991         if (sid == NULL) {
1992                 const char *sid_str;
1993                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
1994                 if (!NT_STATUS_IS_OK(status)) {
1995                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
1996                         return 1;
1997                 }
1998                 sid = dom_sid_parse_talloc(ctx, sid_str);
1999         }
2000
2001         ZERO_STRUCT(rights);
2002         for (i = 2; args[i]; i++) {
2003                 rights.names = talloc_realloc(ctx, rights.names, 
2004                                               struct lsa_StringLarge, rights.count+1);
2005                 rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
2006                 rights.count++;
2007         }
2008
2009
2010         status = smblsa_sid_add_privileges(ctx->cli, sid, ctx, &rights);
2011         if (!NT_STATUS_IS_OK(status)) {
2012                 d_printf("lsa_AddAccountRights - %s\n", nt_errstr(status));
2013                 return 1;
2014         }
2015
2016         return 0;
2017 }
2018
2019 /****************************************************************************
2020 delete privileges for a user
2021 ****************************************************************************/
2022 static int cmd_delprivileges(struct smbclient_context *ctx, const char **args)
2023 {
2024         NTSTATUS status;
2025         struct dom_sid *sid;
2026         struct lsa_RightSet rights;
2027         int i;
2028
2029         if (!args[1]) {
2030                 d_printf("delprivileges <sid|name> <privilege...>\n");
2031                 return 1;
2032         }
2033
2034         sid = dom_sid_parse_talloc(ctx, args[1]);
2035         if (sid == NULL) {
2036                 const char *sid_str;
2037                 status = smblsa_lookup_name(ctx->cli, args[1], ctx, &sid_str);
2038                 if (!NT_STATUS_IS_OK(status)) {
2039                         d_printf("lsa_LookupNames - %s\n", nt_errstr(status));
2040                         return 1;
2041                 }
2042                 sid = dom_sid_parse_talloc(ctx, sid_str);
2043         }
2044
2045         ZERO_STRUCT(rights);
2046         for (i = 2; args[i]; i++) {
2047                 rights.names = talloc_realloc(ctx, rights.names, 
2048                                               struct lsa_StringLarge, rights.count+1);
2049                 rights.names[rights.count].string = talloc_strdup(ctx, args[i]);
2050                 rights.count++;
2051         }
2052
2053
2054         status = smblsa_sid_del_privileges(ctx->cli, sid, ctx, &rights);
2055         if (!NT_STATUS_IS_OK(status)) {
2056                 d_printf("lsa_RemoveAccountRights - %s\n", nt_errstr(status));
2057                 return 1;
2058         }
2059
2060         return 0;
2061 }
2062
2063
2064 /****************************************************************************
2065 ****************************************************************************/
2066 static int cmd_open(struct smbclient_context *ctx, const char **args)
2067 {
2068         char *mask;
2069         
2070         if (!args[1]) {
2071                 d_printf("open <filename>\n");
2072                 return 1;
2073         }
2074         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2075
2076         smbcli_open(ctx->cli->tree, mask, O_RDWR, DENY_ALL);
2077
2078         return 0;
2079 }
2080
2081
2082 /****************************************************************************
2083 remove a directory
2084 ****************************************************************************/
2085 static int cmd_rmdir(struct smbclient_context *ctx, const char **args)
2086 {
2087         char *mask;
2088   
2089         if (!args[1]) {
2090                 d_printf("rmdir <dirname>\n");
2091                 return 1;
2092         }
2093         mask = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2094
2095         if (NT_STATUS_IS_ERR(smbcli_rmdir(ctx->cli->tree, mask))) {
2096                 d_printf("%s removing remote directory file %s\n",
2097                          smbcli_errstr(ctx->cli->tree),mask);
2098         }
2099         
2100         return 0;
2101 }
2102
2103 /****************************************************************************
2104  UNIX hardlink.
2105 ****************************************************************************/
2106 static int cmd_link(struct smbclient_context *ctx, const char **args)
2107 {
2108         char *src,*dest;
2109   
2110         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2111                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2112                 return 1;
2113         }
2114
2115         
2116         if (!args[1] || !args[2]) {
2117                 d_printf("link <src> <dest>\n");
2118                 return 1;
2119         }
2120
2121         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2122         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2123
2124         if (NT_STATUS_IS_ERR(smbcli_unix_hardlink(ctx->cli->tree, src, dest))) {
2125                 d_printf("%s linking files (%s -> %s)\n", smbcli_errstr(ctx->cli->tree), src, dest);
2126                 return 1;
2127         }  
2128
2129         return 0;
2130 }
2131
2132 /****************************************************************************
2133  UNIX symlink.
2134 ****************************************************************************/
2135
2136 static int cmd_symlink(struct smbclient_context *ctx, const char **args)
2137 {
2138         char *src,*dest;
2139   
2140         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2141                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2142                 return 1;
2143         }
2144
2145         if (!args[1] || !args[2]) {
2146                 d_printf("symlink <src> <dest>\n");
2147                 return 1;
2148         }
2149
2150         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2151         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2152
2153         if (NT_STATUS_IS_ERR(smbcli_unix_symlink(ctx->cli->tree, src, dest))) {
2154                 d_printf("%s symlinking files (%s -> %s)\n",
2155                         smbcli_errstr(ctx->cli->tree), src, dest);
2156                 return 1;
2157         } 
2158
2159         return 0;
2160 }
2161
2162 /****************************************************************************
2163  UNIX chmod.
2164 ****************************************************************************/
2165
2166 static int cmd_chmod(struct smbclient_context *ctx, const char **args)
2167 {
2168         char *src;
2169         mode_t mode;
2170   
2171         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2172                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2173                 return 1;
2174         }
2175
2176         if (!args[1] || !args[2]) {
2177                 d_printf("chmod mode file\n");
2178                 return 1;
2179         }
2180
2181         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2182         
2183         mode = (mode_t)strtol(args[1], NULL, 8);
2184
2185         if (NT_STATUS_IS_ERR(smbcli_unix_chmod(ctx->cli->tree, src, mode))) {
2186                 d_printf("%s chmod file %s 0%o\n",
2187                         smbcli_errstr(ctx->cli->tree), src, (uint_t)mode);
2188                 return 1;
2189         } 
2190
2191         return 0;
2192 }
2193
2194 /****************************************************************************
2195  UNIX chown.
2196 ****************************************************************************/
2197
2198 static int cmd_chown(struct smbclient_context *ctx, const char **args)
2199 {
2200         char *src;
2201         uid_t uid;
2202         gid_t gid;
2203   
2204         if (!(ctx->cli->transport->negotiate.capabilities & CAP_UNIX)) {
2205                 d_printf("Server doesn't support UNIX CIFS calls.\n");
2206                 return 1;
2207         }
2208
2209         if (!args[1] || !args[2] || !args[3]) {
2210                 d_printf("chown uid gid file\n");
2211                 return 1;
2212         }
2213
2214         uid = (uid_t)atoi(args[1]);
2215         gid = (gid_t)atoi(args[2]);
2216         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[3]);
2217
2218         if (NT_STATUS_IS_ERR(smbcli_unix_chown(ctx->cli->tree, src, uid, gid))) {
2219                 d_printf("%s chown file %s uid=%d, gid=%d\n",
2220                         smbcli_errstr(ctx->cli->tree), src, (int)uid, (int)gid);
2221                 return 1;
2222         } 
2223
2224         return 0;
2225 }
2226
2227 /****************************************************************************
2228 rename some files
2229 ****************************************************************************/
2230 static int cmd_rename(struct smbclient_context *ctx, const char **args)
2231 {
2232         char *src,*dest;
2233   
2234         if (!args[1] || !args[2]) {
2235                 d_printf("rename <src> <dest>\n");
2236                 return 1;
2237         }
2238
2239         src = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[1]);
2240         dest = talloc_asprintf(ctx, "%s%s", ctx->remote_cur_dir, args[2]);
2241
2242         if (NT_STATUS_IS_ERR(smbcli_rename(ctx->cli->tree, src, dest))) {
2243                 d_printf("%s renaming files\n",smbcli_errstr(ctx->cli->tree));
2244                 return 1;
2245         }
2246         
2247         return 0;
2248 }
2249
2250
2251 /****************************************************************************
2252 toggle the prompt flag
2253 ****************************************************************************/
2254 static int cmd_prompt(struct smbclient_context *ctx, const char **args)
2255 {
2256         ctx->prompt = !ctx->prompt;
2257         DEBUG(2,("prompting is now %s\n",ctx->prompt?"on":"off"));
2258         
2259         return 1;
2260 }
2261
2262
2263 /****************************************************************************
2264 set the newer than time
2265 ****************************************************************************/
2266 static int cmd_newer(struct smbclient_context *ctx, const char **args)
2267 {
2268         struct stat sbuf;
2269
2270         if (args[1] && (stat(args[1],&sbuf) == 0)) {
2271                 ctx->newer_than = sbuf.st_mtime;
2272                 DEBUG(1,("Getting files newer than %s",
2273                          asctime(localtime(&ctx->newer_than))));
2274         } else {
2275                 ctx->newer_than = 0;
2276         }
2277
2278         if (args[1] && ctx->newer_than == 0) {
2279                 d_printf("Error setting newer-than time\n");
2280                 return 1;
2281         }
2282
2283         return 0;
2284 }
2285
2286 /****************************************************************************
2287 set the archive level
2288 ****************************************************************************/
2289 static int cmd_archive(struct smbclient_context *ctx, const char **args)
2290 {
2291         if (args[1]) {
2292                 ctx->archive_level = atoi(args[1]);
2293         } else
2294                 d_printf("Archive level is %d\n",ctx->archive_level);
2295
2296         return 0;
2297 }
2298
2299 /****************************************************************************
2300 toggle the lowercaseflag
2301 ****************************************************************************/
2302 static int cmd_lowercase(struct smbclient_context *ctx, const char **args)
2303 {
2304         ctx->lowercase = !ctx->lowercase;
2305         DEBUG(2,("filename lowercasing is now %s\n",ctx->lowercase?"on":"off"));
2306
2307         return 0;
2308 }
2309
2310
2311
2312
2313 /****************************************************************************
2314 toggle the recurse flag
2315 ****************************************************************************/
2316 static int cmd_recurse(struct smbclient_context *ctx, const char **args)
2317 {
2318         ctx->recurse = !ctx->recurse;
2319         DEBUG(2,("directory recursion is now %s\n",ctx->recurse?"on":"off"));
2320
2321         return 0;
2322 }
2323
2324 /****************************************************************************
2325 toggle the translate flag
2326 ****************************************************************************/
2327 static int cmd_translate(struct smbclient_context *ctx, const char **args)
2328 {
2329         ctx->translation = !ctx->translation;
2330         DEBUG(2,("CR/LF<->LF and print text translation now %s\n",
2331                  ctx->translation?"on":"off"));
2332
2333         return 0;
2334 }
2335
2336
2337 /****************************************************************************
2338 do a printmode command
2339 ****************************************************************************/
2340 static int cmd_printmode(struct smbclient_context *ctx, const char **args)
2341 {
2342         if (args[1]) {
2343                 if (strequal(args[1],"text")) {
2344                         ctx->printmode = 0;      
2345                 } else {
2346                         if (strequal(args[1],"graphics"))
2347                                 ctx->printmode = 1;
2348                         else
2349                                 ctx->printmode = atoi(args[1]);
2350                 }
2351         }
2352
2353         switch(ctx->printmode)
2354         {
2355                 case 0: 
2356                         DEBUG(2,("the printmode is now text\n"));
2357                         break;
2358                 case 1: 
2359                         DEBUG(2,("the printmode is now graphics\n"));
2360                         break;
2361                 default: 
2362                         DEBUG(2,("the printmode is now %d\n", ctx->printmode));
2363                         break;
2364         }
2365         
2366         return 0;
2367 }
2368
2369 /****************************************************************************
2370  do the lcd command
2371  ****************************************************************************/
2372 static int cmd_lcd(struct smbclient_context *ctx, const char **args)
2373 {
2374         char d[PATH_MAX];
2375         
2376         if (args[1]) 
2377                 chdir(args[1]);
2378         DEBUG(2,("the local directory is now %s\n",getcwd(d, PATH_MAX)));
2379
2380         return 0;
2381 }
2382
2383 /****************************************************************************
2384 history
2385 ****************************************************************************/
2386 static int cmd_history(struct smbclient_context *ctx, const char **args)
2387 {
2388 #if defined(HAVE_LIBREADLINE)
2389         HIST_ENTRY **hlist;
2390         int i;
2391
2392         hlist = history_list();
2393         
2394         for (i = 0; hlist && hlist[i]; i++) {
2395                 DEBUG(0, ("%d: %s\n", i, hlist[i]->line));
2396         }
2397 #else
2398         DEBUG(0,("no history without readline support\n"));
2399 #endif
2400
2401         return 0;
2402 }
2403
2404 /****************************************************************************
2405  get a file restarting at end of local file
2406  ****************************************************************************/
2407 static int cmd_reget(struct smbclient_context *ctx, const char **args)
2408 {
2409         char *local_name;
2410         char *remote_name;
2411
2412         if (!args[1]) {
2413                 d_printf("reget <filename>\n");
2414                 return 1;
2415         }
2416         remote_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
2417         dos_clean_name(remote_name);
2418         
2419         if (args[2]) 
2420                 local_name = talloc_strdup(ctx, args[2]);
2421         else
2422                 local_name = talloc_strdup(ctx, args[1]);
2423         
2424         return do_get(ctx, remote_name, local_name, True);
2425 }
2426
2427 /****************************************************************************
2428  put a file restarting at end of local file
2429  ****************************************************************************/
2430 static int cmd_reput(struct smbclient_context *ctx, const char **args)
2431 {
2432         char *local_name;
2433         char *remote_name;
2434         
2435         if (!args[1]) {
2436                 d_printf("reput <filename>\n");
2437                 return 1;
2438         }
2439         local_name = talloc_asprintf(ctx, "%s\\%s", ctx->remote_cur_dir, args[1]);
2440   
2441         if (!file_exist(local_name)) {
2442                 d_printf("%s does not exist\n", local_name);
2443                 return 1;
2444         }
2445
2446         if (args[2]) 
2447                 remote_name = talloc_strdup(ctx, args[2]);
2448         else
2449                 remote_name = talloc_strdup(ctx, args[1]);
2450         
2451         dos_clean_name(remote_name);
2452
2453         return do_put(ctx, remote_name, local_name, True);
2454 }
2455
2456
2457 /*
2458   return a string representing a share type
2459 */
2460 static const char *share_type_str(uint32_t type)
2461 {
2462         switch (type & 0xF) {
2463         case STYPE_DISKTREE: 
2464                 return "Disk";
2465         case STYPE_PRINTQ: 
2466                 return "Printer";
2467         case STYPE_DEVICE: 
2468                 return "Device";
2469         case STYPE_IPC: 
2470                 return "IPC";
2471         default:
2472                 return "Unknown";
2473         }
2474 }
2475
2476
2477 /*
2478   display a list of shares from a level 1 share enum
2479 */
2480 static void display_share_result(struct srvsvc_NetShareCtr1 *ctr1)
2481 {
2482         int i;
2483
2484         for (i=0;i<ctr1->count;i++) {
2485                 struct srvsvc_NetShareInfo1 *info = ctr1->array+i;
2486
2487                 printf("\t%-15s %-10.10s %s\n", 
2488                        info->name, 
2489                        share_type_str(info->type), 
2490                        info->comment);
2491         }
2492 }
2493
2494
2495
2496 /****************************************************************************
2497 try and browse available shares on a host
2498 ****************************************************************************/
2499 static BOOL browse_host(const char *query_host)
2500 {
2501         struct dcerpc_pipe *p;
2502         char *binding;
2503         NTSTATUS status;
2504         struct srvsvc_NetShareEnumAll r;
2505         uint32_t resume_handle = 0;
2506         TALLOC_CTX *mem_ctx = talloc_init("browse_host");
2507         struct srvsvc_NetShareCtr1 ctr1;
2508
2509         binding = talloc_asprintf(mem_ctx, "ncacn_np:%s", query_host);
2510
2511         status = dcerpc_pipe_connect(mem_ctx, &p, binding, 
2512                                          &dcerpc_table_srvsvc,
2513                                      cmdline_credentials, NULL);
2514         if (!NT_STATUS_IS_OK(status)) {
2515                 d_printf("Failed to connect to %s - %s\n", 
2516                          binding, nt_errstr(status));
2517                 talloc_free(mem_ctx);
2518                 return False;
2519         }
2520
2521         r.in.server_unc = talloc_asprintf(mem_ctx,"\\\\%s",dcerpc_server_name(p));
2522         r.in.level = 1;
2523         r.in.ctr.ctr1 = &ctr1;
2524         r.in.max_buffer = ~0;
2525         r.in.resume_handle = &resume_handle;
2526
2527         d_printf("\n\tSharename       Type       Comment\n");
2528         d_printf("\t---------       ----       -------\n");
2529
2530         do {
2531                 ZERO_STRUCT(ctr1);
2532                 status = dcerpc_srvsvc_NetShareEnumAll(p, mem_ctx, &r);
2533
2534                 if (NT_STATUS_IS_OK(status) && 
2535                     (W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA) ||
2536                      W_ERROR_IS_OK(r.out.result)) &&
2537                     r.out.ctr.ctr1) {
2538                         display_share_result(r.out.ctr.ctr1);
2539                         resume_handle += r.out.ctr.ctr1->count;
2540                 }
2541         } while (NT_STATUS_IS_OK(status) && W_ERROR_EQUAL(r.out.result, WERR_MORE_DATA));
2542
2543         talloc_free(mem_ctx);
2544
2545         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(r.out.result)) {
2546                 d_printf("Failed NetShareEnumAll %s - %s/%s\n", 
2547                          binding, nt_errstr(status), win_errstr(r.out.result));
2548                 return False;
2549         }
2550
2551         return False;
2552 }
2553
2554 /****************************************************************************
2555 try and browse available connections on a host
2556 ****************************************************************************/
2557 static BOOL list_servers(const char *wk_grp)
2558 {
2559         d_printf("REWRITE: list servers not implemented\n");
2560         return False;
2561 }
2562
2563 /* Some constants for completing filename arguments */
2564
2565 #define COMPL_NONE        0          /* No completions */
2566 #define COMPL_REMOTE      1          /* Complete remote filename */
2567 #define COMPL_LOCAL       2          /* Complete local filename */
2568
2569 static int cmd_help(struct smbclient_context *ctx, const char **args);
2570
2571 /* This defines the commands supported by this client.
2572  * NOTE: The "!" must be the last one in the list because it's fn pointer
2573  *       field is NULL, and NULL in that field is used in process_tok()
2574  *       (below) to indicate the end of the list.  crh
2575  */
2576 static struct
2577 {
2578   const char *name;
2579   int (*fn)(struct smbclient_context *ctx, const char **args);
2580   const char *description;
2581   char compl_args[2];      /* Completion argument info */
2582 } commands[] = 
2583 {
2584   {"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2585   {"addprivileges",cmd_addprivileges,"<sid|name> <privilege...> add privileges for a user",{COMPL_NONE,COMPL_NONE}},
2586   {"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
2587   {"acl",cmd_acl,"<file> show file ACL",{COMPL_NONE,COMPL_NONE}},
2588   {"allinfo",cmd_allinfo,"<file> show all possible info about a file",{COMPL_NONE,COMPL_NONE}},
2589   {"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}},
2590   {"cancel",cmd_rewrite,"<jobid> cancel a print queue entry",{COMPL_NONE,COMPL_NONE}},
2591   {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}},
2592   {"chmod",cmd_chmod,"<src> <mode> chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}},
2593   {"chown",cmd_chown,"<src> <uid> <gid> chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}},
2594   {"del",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2595   {"delprivileges",cmd_delprivileges,"<sid|name> <privilege...> remove privileges for a user",{COMPL_NONE,COMPL_NONE}},
2596   {"deltree",cmd_deltree,"<dir> delete a whole directory tree",{COMPL_REMOTE,COMPL_NONE}},
2597   {"dir",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2598   {"du",cmd_du,"<mask> computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2599   {"eainfo",cmd_eainfo,"<file> show EA contents for a file",{COMPL_NONE,COMPL_NONE}},
2600   {"exit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2601   {"fsinfo",cmd_fsinfo,"query file system info",{COMPL_NONE,COMPL_NONE}},
2602   {"get",cmd_get,"<remote name> [local name] get a file",{COMPL_REMOTE,COMPL_LOCAL}},
2603   {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
2604   {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}},
2605   {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}},
2606   {"link",cmd_link,"<src> <dest> create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}},
2607   {"lookup",cmd_lookup,"<sid|name> show SID for name or name for SID",{COMPL_NONE,COMPL_NONE}},
2608   {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}},  
2609   {"ls",cmd_dir,"<mask> list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}},
2610   {"mask",cmd_select,"<mask> mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}},
2611   {"md",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2612   {"mget",cmd_mget,"<mask> get all the matching files",{COMPL_REMOTE,COMPL_NONE}},
2613   {"mkdir",cmd_mkdir,"<directory> make a directory",{COMPL_NONE,COMPL_NONE}},
2614   {"more",cmd_more,"<remote name> view a remote file with your pager",{COMPL_REMOTE,COMPL_NONE}},  
2615   {"mput",cmd_mput,"<mask> put all matching files",{COMPL_REMOTE,COMPL_NONE}},
2616   {"newer",cmd_newer,"<file> only mget files newer than the specified local file",{COMPL_LOCAL,COMPL_NONE}},
2617   {"open",cmd_open,"<mask> open a file",{COMPL_REMOTE,COMPL_NONE}},
2618   {"privileges",cmd_privileges,"<user> show privileges for a user",{COMPL_NONE,COMPL_NONE}},
2619   {"print",cmd_print,"<file name> print a file",{COMPL_NONE,COMPL_NONE}},
2620   {"printmode",cmd_printmode,"<graphics or text> set the print mode",{COMPL_NONE,COMPL_NONE}},
2621   {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2622   {"put",cmd_put,"<local name> [remote name] put a file",{COMPL_LOCAL,COMPL_REMOTE}},
2623   {"pwd",cmd_pwd,"show current remote directory (same as 'cd' with no args)",{COMPL_NONE,COMPL_NONE}},
2624   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2625   {"queue",cmd_rewrite,"show the print queue",{COMPL_NONE,COMPL_NONE}},
2626   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
2627   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2628   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
2629   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
2630   {"rename",cmd_rename,"<src> <dest> rename some files",{COMPL_REMOTE,COMPL_REMOTE}},
2631   {"reput",cmd_reput,"<local name> [remote name] put a file restarting at end of remote file",{COMPL_LOCAL,COMPL_REMOTE}},
2632   {"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
2633   {"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
2634   {"symlink",cmd_symlink,"<src> <dest> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
2635   {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}},
2636   
2637   /* Yes, this must be here, see crh's comment above. */
2638   {"!",NULL,"run a shell command on the local system",{COMPL_NONE,COMPL_NONE}},
2639   {NULL,NULL,NULL,{COMPL_NONE,COMPL_NONE}}
2640 };
2641
2642
2643 /*******************************************************************
2644   lookup a command string in the list of commands, including 
2645   abbreviations
2646   ******************************************************************/
2647 static int process_tok(const char *tok)
2648 {
2649         int i = 0, matches = 0;
2650         int cmd=0;
2651         int tok_len = strlen(tok);
2652         
2653         while (commands[i].fn != NULL) {
2654                 if (strequal(commands[i].name,tok)) {
2655                         matches = 1;
2656                         cmd = i;
2657                         break;
2658                 } else if (strncasecmp(commands[i].name, tok, tok_len) == 0) {
2659                         matches++;
2660                         cmd = i;
2661                 }
2662                 i++;
2663         }
2664   
2665         if (matches == 0)
2666                 return(-1);
2667         else if (matches == 1)
2668                 return(cmd);
2669         else
2670                 return(-2);
2671 }
2672
2673 /****************************************************************************
2674 help
2675 ****************************************************************************/
2676 static int cmd_help(struct smbclient_context *ctx, const char **args)
2677 {
2678         int i=0,j;
2679         
2680         if (args[1]) {
2681                 if ((i = process_tok(args[1])) >= 0)
2682                         d_printf("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description);
2683         } else {
2684                 while (commands[i].description) {
2685                         for (j=0; commands[i].description && (j<5); j++) {
2686                                 d_printf("%-15s",commands[i].name);
2687                                 i++;
2688                         }
2689                         d_printf("\n");
2690                 }
2691         }
2692         return 0;
2693 }
2694
2695 static int process_line(struct smbclient_context *ctx, const char *cline);
2696 /****************************************************************************
2697 process a -c command string
2698 ****************************************************************************/
2699 static int process_command_string(struct smbclient_context *ctx, const char *cmd)
2700 {
2701         const char **lines;
2702         int i, rc = 0;
2703
2704         lines = str_list_make(NULL, cmd, ";");
2705         for (i = 0; lines[i]; i++) {
2706                 rc |= process_line(ctx, lines[i]);
2707         }
2708         talloc_free(lines);
2709
2710         return rc;
2711 }       
2712
2713 #define MAX_COMPLETIONS 100
2714
2715 typedef struct {
2716         char *dirmask;
2717         char **matches;
2718         int count, samelen;
2719         const char *text;
2720         int len;
2721 } completion_remote_t;
2722
2723 static void completion_remote_filter(struct clilist_file_info *f, const char *mask, void *state)
2724 {
2725         completion_remote_t *info = (completion_remote_t *)state;
2726
2727         if ((info->count < MAX_COMPLETIONS - 1) && (strncmp(info->text, f->name, info->len) == 0) && (strcmp(f->name, ".") != 0) && (strcmp(f->name, "..") != 0)) {
2728                 if ((info->dirmask[0] == 0) && !(f->attrib & FILE_ATTRIBUTE_DIRECTORY))
2729                         info->matches[info->count] = strdup(f->name);
2730                 else {
2731                         char *tmp;
2732
2733                         if (info->dirmask[0] != 0)
2734                                 tmp = talloc_asprintf(NULL, "%s/%s", info->dirmask, f->name);
2735                         else
2736                                 tmp = talloc_strdup(NULL, f->name);
2737                         
2738                         if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2739                                 tmp = talloc_append_string(NULL, tmp, "/");
2740                         info->matches[info->count] = tmp;
2741                 }
2742                 if (info->matches[info->count] == NULL)
2743                         return;
2744                 if (f->attrib & FILE_ATTRIBUTE_DIRECTORY)
2745                         smb_readline_ca_char(0);
2746
2747                 if (info->count == 1)
2748                         info->samelen = strlen(info->matches[info->count]);
2749                 else
2750                         while (strncmp(info->matches[info->count], info->matches[info->count-1], info->samelen) != 0)
2751                                 info->samelen--;
2752                 info->count++;
2753         }
2754 }
2755
2756 static char **remote_completion(const char *text, int len)
2757 {
2758         char *dirmask;
2759         int i;
2760         completion_remote_t info;
2761
2762         info.samelen = len;
2763         info.text = text;
2764         info.len = len;
2765  
2766         if (len >= PATH_MAX)
2767                 return(NULL);
2768
2769         info.matches = malloc_array_p(char *, MAX_COMPLETIONS);
2770         if (!info.matches) return NULL;
2771         info.matches[0] = NULL;
2772
2773         for (i = len-1; i >= 0; i--)
2774                 if ((text[i] == '/') || (text[i] == '\\'))
2775                         break;
2776         info.text = text+i+1;
2777         info.samelen = info.len = len-i-1;
2778
2779         if (i > 0) {
2780                 info.dirmask = talloc_strndup(NULL, text, i+1);
2781                 info.dirmask[i+1] = 0;
2782                 asprintf(&dirmask, "%s%*s*", rl_ctx->remote_cur_dir, i-1, text);
2783         } else
2784                 asprintf(&dirmask, "%s*", rl_ctx->remote_cur_dir);
2785
2786         if (smbcli_list(rl_ctx->cli->tree, dirmask, 
2787                      FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 
2788                      completion_remote_filter, &info) < 0)
2789                 goto cleanup;
2790
2791         if (info.count == 2)
2792                 info.matches[0] = strdup(info.matches[1]);
2793         else {
2794                 info.matches[0] = malloc(info.samelen+1);
2795                 if (!info.matches[0])
2796                         goto cleanup;
2797                 strncpy(info.matches[0], info.matches[1], info.samelen);
2798                 info.matches[0][info.samelen] = 0;
2799         }
2800         info.matches[info.count] = NULL;
2801         return info.matches;
2802
2803 cleanup:
2804         for (i = 0; i < info.count; i++)
2805                 free(info.matches[i]);
2806         free(info.matches);
2807         return NULL;
2808 }
2809
2810 static char **completion_fn(const char *text, int start, int end)
2811 {
2812         smb_readline_ca_char(' ');
2813
2814         if (start) {
2815                 const char *buf, *sp;
2816                 int i;
2817                 char compl_type;
2818
2819                 buf = smb_readline_get_line_buffer();
2820                 if (buf == NULL)
2821                         return NULL;
2822                 
2823                 sp = strchr(buf, ' ');
2824                 if (sp == NULL)
2825                         return NULL;
2826                 
2827                 for (i = 0; commands[i].name; i++)
2828                         if ((strncmp(commands[i].name, text, sp - buf) == 0) && (commands[i].name[sp - buf] == 0))
2829                                 break;
2830                 if (commands[i].name == NULL)
2831                         return NULL;
2832
2833                 while (*sp == ' ')
2834                         sp++;
2835
2836                 if (sp == (buf + start))
2837                         compl_type = commands[i].compl_args[0];
2838                 else
2839                         compl_type = commands[i].compl_args[1];
2840
2841                 if (compl_type == COMPL_REMOTE)
2842                         return remote_completion(text, end - start);
2843                 else /* fall back to local filename completion */
2844                         return NULL;
2845         } else {
2846                 char **matches;
2847                 int i, len, samelen = 0, count=1;
2848
2849                 matches = malloc_array_p(char *, MAX_COMPLETIONS);
2850                 if (!matches) return NULL;
2851                 matches[0] = NULL;
2852
2853                 len = strlen(text);
2854                 for (i=0;commands[i].fn && count < MAX_COMPLETIONS-1;i++) {
2855                         if (strncmp(text, commands[i].name, len) == 0) {
2856                                 matches[count] = strdup(commands[i].name);
2857                                 if (!matches[count])
2858                                         goto cleanup;
2859                                 if (count == 1)
2860                                         samelen = strlen(matches[count]);
2861                                 else
2862                                         while (strncmp(matches[count], matches[count-1], samelen) != 0)
2863                                                 samelen--;
2864                                 count++;
2865                         }
2866                 }
2867
2868                 switch (count) {
2869                 case 0: /* should never happen */
2870                 case 1:
2871                         goto cleanup;
2872                 case 2:
2873                         matches[0] = strdup(matches[1]);
2874                         break;
2875                 default:
2876                         matches[0] = malloc(samelen+1);
2877                         if (!matches[0])
2878                                 goto cleanup;
2879                         strncpy(matches[0], matches[1], samelen);
2880                         matches[0][samelen] = 0;
2881                 }
2882                 matches[count] = NULL;
2883                 return matches;
2884
2885 cleanup:
2886                 while (i >= 0) {
2887                         free(matches[i]);
2888                         i--;
2889                 }
2890                 free(matches);
2891                 return NULL;
2892         }
2893 }
2894
2895 /****************************************************************************
2896 make sure we swallow keepalives during idle time
2897 ****************************************************************************/
2898 static void readline_callback(void)
2899 {
2900         static time_t last_t;
2901         time_t t;
2902
2903         t = time(NULL);
2904
2905         if (t - last_t < 5) return;
2906
2907         last_t = t;
2908
2909         smbcli_transport_process(rl_ctx->cli->transport);
2910
2911         if (rl_ctx->cli->tree) {
2912                 smbcli_chkpath(rl_ctx->cli->tree, "\\");
2913         }
2914 }
2915
2916 static int process_line(struct smbclient_context *ctx, const char *cline)
2917 {
2918         const char **args;
2919         int i;
2920
2921         /* and get the first part of the command */
2922         args = str_list_make_shell(ctx, cline, NULL);
2923         if (!args || !args[0])
2924                 return 0;
2925
2926         if ((i = process_tok(args[0])) >= 0) {
2927                 i = commands[i].fn(ctx, args);
2928         } else if (i == -2) {
2929                 d_printf("%s: command abbreviation ambiguous\n",args[0]);
2930         } else {
2931                 d_printf("%s: command not found\n",args[0]);
2932         }
2933
2934         talloc_free(args);
2935
2936         return i;
2937 }
2938
2939 /****************************************************************************
2940 process commands on stdin
2941 ****************************************************************************/
2942 static int process_stdin(struct smbclient_context *ctx)
2943 {
2944         int rc = 0;
2945         while (1) {
2946                 /* display a prompt */
2947                 char *the_prompt = talloc_asprintf(ctx, "smb: %s> ", ctx->remote_cur_dir);
2948                 char *cline = smb_readline(the_prompt, readline_callback, completion_fn);
2949                 talloc_free(the_prompt);
2950                         
2951                 if (!cline) break;
2952                 
2953                 /* special case - first char is ! */
2954                 if (*cline == '!') {
2955                         system(cline + 1);
2956                         continue;
2957                 }
2958
2959                 rc |= process_command_string(ctx, cline); 
2960         }
2961
2962         return rc;
2963 }
2964
2965
2966 /***************************************************** 
2967 return a connection to a server
2968 *******************************************************/
2969 static struct smbclient_context *do_connect(TALLOC_CTX *mem_ctx, 
2970                                        const char *server, const char *share, struct cli_credentials *cred)
2971 {
2972         NTSTATUS status;
2973         struct smbclient_context *ctx = talloc_zero(mem_ctx, struct smbclient_context);
2974         if (!ctx) {
2975                 return NULL;
2976         }
2977
2978         rl_ctx = ctx; /* Ugly hack */
2979
2980         if (strncmp(share, "\\\\", 2) == 0 ||
2981             strncmp(share, "//", 2) == 0) {
2982                 smbcli_parse_unc(share, ctx, &server, &share);
2983         }
2984
2985         ctx->remote_cur_dir = talloc_strdup(ctx, "\\");
2986         
2987         status = smbcli_full_connection(ctx, &ctx->cli, server,
2988                                         share, NULL, cred, NULL);
2989         if (!NT_STATUS_IS_OK(status)) {
2990                 d_printf("Connection to \\\\%s\\%s failed - %s\n", 
2991                          server, share, nt_errstr(status));
2992                 talloc_free(ctx);
2993                 return NULL;
2994         }
2995
2996         return ctx;
2997 }
2998
2999 /****************************************************************************
3000 handle a -L query
3001 ****************************************************************************/
3002 static int do_host_query(const char *query_host)
3003 {
3004         browse_host(query_host);
3005         list_servers(lp_workgroup());
3006         return(0);
3007 }
3008
3009
3010 /****************************************************************************
3011 handle a message operation
3012 ****************************************************************************/
3013 static int do_message_op(const char *desthost, const char *destip, int name_type)
3014 {
3015         struct nbt_name called, calling;
3016         const char *server_name;
3017         struct smbcli_state *cli;
3018
3019         make_nbt_name_client(&calling, lp_netbios_name());
3020
3021         nbt_choose_called_name(NULL, &called, desthost, name_type);
3022
3023         server_name = destip ? destip : desthost;
3024
3025         if (!(cli=smbcli_state_init(NULL)) || !smbcli_socket_connect(cli, server_name)) {
3026                 d_printf("Connection to %s failed\n", server_name);
3027                 return 1;
3028         }
3029
3030         if (!smbcli_transport_establish(cli, &calling, &called)) {
3031                 d_printf("session request failed\n");
3032                 talloc_free(cli);
3033                 return 1;
3034         }
3035
3036         send_message(cli, desthost);
3037         talloc_free(cli);
3038
3039         return 0;
3040 }
3041
3042
3043 /****************************************************************************
3044   main program
3045 ****************************************************************************/
3046  int main(int argc,char *argv[])
3047 {
3048         const char *base_directory = NULL;
3049         const char *dest_ip;
3050         int opt;
3051         const char *query_host = NULL;
3052         BOOL message = False;
3053         const char *desthost;
3054 #ifdef KANJI
3055         const char *term_code = KANJI;
3056 #else
3057         const char *term_code = "";
3058 #endif /* KANJI */
3059         poptContext pc;
3060         const char *service = NULL;
3061         int port = 0;
3062         char *p;
3063         int rc = 0;
3064         int name_type = 0x20;
3065         TALLOC_CTX *mem_ctx;
3066         struct smbclient_context *ctx;
3067         const char *cmdstr = NULL;
3068
3069         struct poptOption long_options[] = {
3070                 POPT_AUTOHELP
3071
3072                 { "message", 'M', POPT_ARG_STRING, NULL, 'M', "Send message", "HOST" },
3073                 { "ip-address", 'I', POPT_ARG_STRING, NULL, 'I', "Use this IP to connect to", "IP" },
3074                 { "stderr", 'E', POPT_ARG_NONE, NULL, 'E', "Write messages to stderr instead of stdout" },
3075                 { "list", 'L', POPT_ARG_STRING, NULL, 'L', "Get a list of shares available on a host", "HOST" },
3076                 { "terminal", 't', POPT_ARG_STRING, NULL, 't', "Terminal I/O code {sjis|euc|jis7|jis8|junet|hex}", "CODE" },
3077                 { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" },
3078                 { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, 
3079                 { "send-buffer", 'b', POPT_ARG_INT, NULL, 'b', "Changes the transmit/send buffer", "BYTES" },
3080                 { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" },
3081                 POPT_COMMON_SAMBA
3082                 POPT_COMMON_CONNECTION
3083                 POPT_COMMON_CREDENTIALS
3084                 POPT_COMMON_VERSION
3085                 POPT_TABLEEND
3086         };
3087         
3088         mem_ctx = talloc_init("client.c/main");
3089         if (!mem_ctx) {
3090                 d_printf("\nclient.c: Not enough memory\n");
3091                 exit(1);
3092         }
3093
3094         pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0);
3095         poptSetOtherOptionHelp(pc, "[OPTIONS] service <password>");
3096
3097         while ((opt = poptGetNextOpt(pc)) != -1) {
3098                 switch (opt) {
3099                 case 'M':
3100                         /* Messages are sent to NetBIOS name type 0x3
3101                          * (Messenger Service).  Make sure we default
3102                          * to port 139 instead of port 445. srl,crh
3103                          */
3104                         name_type = 0x03; 
3105                         desthost = strdup(poptGetOptArg(pc));
3106                         if( 0 == port ) port = 139;
3107                         message = True;
3108                         break;
3109                 case 'I':
3110                         dest_ip = poptGetOptArg(pc);
3111                         break;
3112                 case 'L':
3113                         query_host = strdup(poptGetOptArg(pc));
3114                         break;
3115                 case 't':
3116                         term_code = strdup(poptGetOptArg(pc));
3117                         break;
3118                 case 'D':
3119                         base_directory = strdup(poptGetOptArg(pc));
3120                         break;
3121                 case 'b':
3122                         io_bufsize = MAX(1, atoi(poptGetOptArg(pc)));
3123                         break;
3124                 }
3125         }
3126
3127         gensec_init();
3128
3129         if(poptPeekArg(pc)) {
3130                 char *s = strdup(poptGetArg(pc)); 
3131
3132                 /* Convert any '/' characters in the service name to '\' characters */
3133                 string_replace(s, '/','\\');
3134
3135                 service = s;
3136
3137                 if (count_chars(s,'\\') < 3) {
3138                         d_printf("\n%s: Not enough '\\' characters in service\n",s);
3139                         poptPrintUsage(pc, stderr, 0);
3140                         exit(1);
3141                 }
3142         }
3143
3144         if (poptPeekArg(pc)) { 
3145                 cli_credentials_set_password(cmdline_credentials, poptGetArg(pc), CRED_SPECIFIED);
3146         }
3147
3148         /*init_names(); */
3149
3150         if (!query_host && !service && !message) {
3151                 poptPrintUsage(pc, stderr, 0);
3152                 exit(1);
3153         }
3154
3155         poptFreeContext(pc);
3156
3157         DEBUG( 3, ( "Client started (version %s).\n", SAMBA_VERSION_STRING ) );
3158
3159         if (query_host && (p=strchr_m(query_host,'#'))) {
3160                 *p = 0;
3161                 p++;
3162                 sscanf(p, "%x", &name_type);
3163         }
3164   
3165         if (query_host) {
3166                 return do_host_query(query_host);
3167         }
3168
3169         if (message) {
3170                 return do_message_op(desthost, dest_ip, name_type);
3171         }
3172         
3173
3174         ctx = do_connect(mem_ctx, desthost, service, cmdline_credentials);
3175         if (!ctx)
3176                 return 1;
3177
3178         if (base_directory) 
3179                 do_cd(ctx, base_directory);
3180         
3181         if (cmdstr) {
3182                 rc = process_command_string(ctx, cmdstr);
3183         } else {
3184                 rc = process_stdin(ctx);
3185         }
3186   
3187         talloc_free(mem_ctx);
3188
3189         return rc;
3190 }