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