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