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