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