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