📄 client.c
字号:
/* Unix SMB/CIFS implementation. SMB client Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Simo Sorce 2001-2002 Copyright (C) Jelmer Vernooij 2003-2004 Copyright (C) James J Myers 2003 <myersjj@samba.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*//* * TODO: remove this ... and don't use talloc_append_string() * * NOTE: I'm not changing the code yet, because I assume there're * some bugs in the existing code and I'm not sure how to fix * them correctly. */#define TALLOC_DEPRECATED 1#include "includes.h"#include "version.h"#include "libcli/libcli.h"#include "lib/events/events.h"#include "lib/cmdline/popt_common.h"#include "librpc/gen_ndr/ndr_srvsvc_c.h"#include "librpc/gen_ndr/ndr_lsa.h"#include "librpc/gen_ndr/ndr_security.h"#include "libcli/raw/libcliraw.h"#include "libcli/util/clilsa.h"#include "system/dir.h"#include "system/filesys.h"#include "lib/util/dlinklist.h"#include "system/readline.h"#include "auth/credentials/credentials.h"#include "auth/gensec/gensec.h"#include "system/time.h" /* needed by some systems for asctime() */#include "libcli/resolve/resolve.h"#include "libcli/security/security.h"#include "lib/smbreadline/smbreadline.h"#include "librpc/gen_ndr/ndr_nbt.h"#include "param/param.h"#include "librpc/rpc/dcerpc.h"struct smbclient_context { char *remote_cur_dir; struct smbcli_state *cli; char *fileselection; time_t newer_than; bool prompt; bool recurse; int archive_level; bool lowercase; int printmode; bool translation; int io_bufsize;};/* timing globals */static uint64_t get_total_size = 0;static uint_t get_total_time_ms = 0;static uint64_t put_total_size = 0;static uint_t put_total_time_ms = 0;/* Unfortunately, there is no way to pass the a context to the completion function as an argument */static struct smbclient_context *rl_ctx; /* totals globals */static double dir_total;/******************************************************************* Reduce a file name, removing .. elements.********************************************************************/static void dos_clean_name(char *s){ char *p=NULL,*r; DEBUG(3,("dos_clean_name [%s]\n",s)); /* remove any double slashes */ all_string_sub(s, "\\\\", "\\", 0); while ((p = strstr(s,"\\..\\")) != NULL) { *p = '\0'; if ((r = strrchr(s,'\\')) != NULL) memmove(r,p+3,strlen(p+3)+1); } trim_string(s,NULL,"\\.."); all_string_sub(s, "\\.\\", "\\", 0);}/****************************************************************************write to a local file with CR/LF->LF translation if appropriate. return the number taken from the buffer. This may not equal the number written.****************************************************************************/static int writefile(int f, const void *_b, int n, bool translation){ const uint8_t *b = (const uint8_t *)_b; int i; if (!translation) { return write(f,b,n); } i = 0; while (i < n) { if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') { b++;i++; } if (write(f, b, 1) != 1) { break; } b++; i++; } return(i);}/**************************************************************************** read from a file with LF->CR/LF translation if appropriate. return the number read. read approx n bytes.****************************************************************************/static int readfile(void *_b, int n, XFILE *f, bool translation){ uint8_t *b = (uint8_t *)_b; int i; int c; if (!translation) return x_fread(b,1,n,f); i = 0; while (i < (n - 1)) { if ((c = x_getc(f)) == EOF) { break; } if (c == '\n') { /* change all LFs to CR/LF */ b[i++] = '\r'; } b[i++] = c; } return(i);} /****************************************************************************send a message****************************************************************************/static void send_message(struct smbcli_state *cli, const char *desthost){ char msg[1600]; int total_len = 0; int grp_id; if (!smbcli_message_start(cli->tree, desthost, cli_credentials_get_username(cmdline_credentials), &grp_id)) { d_printf("message start: %s\n", smbcli_errstr(cli->tree)); return; } d_printf("Connected. Type your message, ending it with a Control-D\n"); while (!feof(stdin) && total_len < 1600) { int maxlen = MIN(1600 - total_len,127); int l=0; int c; for (l=0;l<maxlen && (c=fgetc(stdin))!=EOF;l++) { if (c == '\n') msg[l++] = '\r'; msg[l] = c; } if (!smbcli_message_text(cli->tree, msg, l, grp_id)) { d_printf("SMBsendtxt failed (%s)\n",smbcli_errstr(cli->tree)); return; } total_len += l; } if (total_len >= 1600) d_printf("the message was truncated to 1600 bytes\n"); else d_printf("sent %d bytes\n",total_len); if (!smbcli_message_end(cli->tree, grp_id)) { d_printf("SMBsendend failed (%s)\n",smbcli_errstr(cli->tree)); return; } }/****************************************************************************check the space on a device****************************************************************************/static int do_dskattr(struct smbclient_context *ctx){ uint32_t bsize; uint64_t total, avail; if (NT_STATUS_IS_ERR(smbcli_dskattr(ctx->cli->tree, &bsize, &total, &avail))) { d_printf("Error in dskattr: %s\n",smbcli_errstr(ctx->cli->tree)); return 1; } d_printf("\n\t\t%llu blocks of size %u. %llu blocks available\n", (unsigned long long)total, (unsigned)bsize, (unsigned long long)avail); return 0;}/****************************************************************************show cd/pwd****************************************************************************/static int cmd_pwd(struct smbclient_context *ctx, const char **args){ d_printf("Current directory is %s\n", ctx->remote_cur_dir); return 0;}/* convert a string to dos format*/static void dos_format(char *s){ string_replace(s, '/', '\\');}/****************************************************************************change directory - inner section****************************************************************************/static int do_cd(struct smbclient_context *ctx, const char *newdir){ char *dname; /* Save the current directory in case the new directory is invalid */ if (newdir[0] == '\\') dname = talloc_strdup(NULL, newdir); else dname = talloc_asprintf(NULL, "%s\\%s", ctx->remote_cur_dir, newdir); dos_format(dname); if (*(dname+strlen(dname)-1) != '\\') { dname = talloc_append_string(NULL, dname, "\\"); } dos_clean_name(dname); if (NT_STATUS_IS_ERR(smbcli_chkpath(ctx->cli->tree, dname))) { d_printf("cd %s: %s\n", dname, smbcli_errstr(ctx->cli->tree)); talloc_free(dname); } else { ctx->remote_cur_dir = dname; } return 0;}/****************************************************************************change directory****************************************************************************/static int cmd_cd(struct smbclient_context *ctx, const char **args){ int rc = 0; if (args[1]) rc = do_cd(ctx, args[1]); else d_printf("Current directory is %s\n",ctx->remote_cur_dir); return rc;}static bool mask_match(struct smbcli_state *c, const char *string, const char *pattern, bool is_case_sensitive){ char *p2, *s2; bool ret; if (ISDOTDOT(string)) string = "."; if (ISDOT(pattern)) return false; if (is_case_sensitive) return ms_fnmatch(pattern, string, c->transport->negotiate.protocol) == 0; p2 = strlower_talloc(NULL, pattern); s2 = strlower_talloc(NULL, string); ret = ms_fnmatch(p2, s2, c->transport->negotiate.protocol) == 0; talloc_free(p2); talloc_free(s2); return ret;}/******************************************************************* decide if a file should be operated on ********************************************************************/static bool do_this_one(struct smbclient_context *ctx, struct clilist_file_info *finfo){ if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) return(true); if (ctx->fileselection && !mask_match(ctx->cli, finfo->name,ctx->fileselection,false)) { DEBUG(3,("mask_match %s failed\n", finfo->name)); return false; } if (ctx->newer_than && finfo->mtime < ctx->newer_than) { DEBUG(3,("newer_than %s failed\n", finfo->name)); return(false); } if ((ctx->archive_level==1 || ctx->archive_level==2) && !(finfo->attrib & FILE_ATTRIBUTE_ARCHIVE)) { DEBUG(3,("archive %s failed\n", finfo->name)); return(false); } return(true);}/**************************************************************************** display info about a file ****************************************************************************/static void display_finfo(struct smbclient_context *ctx, struct clilist_file_info *finfo){ if (do_this_one(ctx, finfo)) { time_t t = finfo->mtime; /* the time is assumed to be passed as GMT */ char *astr = attrib_string(NULL, finfo->attrib); d_printf(" %-30s%7.7s %8.0f %s", finfo->name, astr, (double)finfo->size, asctime(localtime(&t))); dir_total += finfo->size; talloc_free(astr); }}/**************************************************************************** accumulate size of a file ****************************************************************************/static void do_du(struct smbclient_context *ctx, struct clilist_file_info *finfo){ if (do_this_one(ctx, finfo)) { dir_total += finfo->size; }}static bool do_list_recurse;static bool do_list_dirs;static char *do_list_queue = 0;static long do_list_queue_size = 0;static long do_list_queue_start = 0;static long do_list_queue_end = 0;static void (*do_list_fn)(struct smbclient_context *, struct clilist_file_info *);/****************************************************************************functions for do_list_queue ****************************************************************************//* * The do_list_queue is a NUL-separated list of strings stored in a * char*. Since this is a FIFO, we keep track of the beginning and * ending locations of the data in the queue. When we overflow, we * double the size of the char*. When the start of the data passes * the midpoint, we move everything back. This is logically more * complex than a linked list, but easier from a memory management * angle. In any memory error condition, do_list_queue is reset. * Functions check to ensure that do_list_queue is non-NULL before * accessing it. */static void reset_do_list_queue(void){ SAFE_FREE(do_list_queue); do_list_queue_size = 0; do_list_queue_start = 0; do_list_queue_end = 0;}static void init_do_list_queue(void){ reset_do_list_queue(); do_list_queue_size = 1024; do_list_queue = malloc_array_p(char, do_list_queue_size); if (do_list_queue == 0) { d_printf("malloc fail for size %d\n", (int)do_list_queue_size); reset_do_list_queue(); } else { memset(do_list_queue, 0, do_list_queue_size); }}static void adjust_do_list_queue(void){ if (do_list_queue == NULL) return; /* * If the starting point of the queue is more than half way through, * move everything toward the beginning. */ if (do_list_queue_start == do_list_queue_end) { DEBUG(4,("do_list_queue is empty\n")); do_list_queue_start = do_list_queue_end = 0; *do_list_queue = '\0'; } else if (do_list_queue_start > (do_list_queue_size / 2)) { DEBUG(4,("sliding do_list_queue backward\n")); memmove(do_list_queue, do_list_queue + do_list_queue_start, do_list_queue_end - do_list_queue_start); do_list_queue_end -= do_list_queue_start; do_list_queue_start = 0; } }static void add_to_do_list_queue(const char* entry){ char *dlq; long new_end = do_list_queue_end + ((long)strlen(entry)) + 1; while (new_end > do_list_queue_size) { do_list_queue_size *= 2; DEBUG(4,("enlarging do_list_queue to %d\n", (int)do_list_queue_size)); dlq = realloc_p(do_list_queue, char, do_list_queue_size); if (! dlq) { d_printf("failure enlarging do_list_queue to %d bytes\n", (int)do_list_queue_size); reset_do_list_queue(); } else { do_list_queue = dlq; memset(do_list_queue + do_list_queue_size / 2, 0, do_list_queue_size / 2); } } if (do_list_queue) { safe_strcpy(do_list_queue + do_list_queue_end, entry, do_list_queue_size - do_list_queue_end - 1); do_list_queue_end = new_end; DEBUG(4,("added %s to do_list_queue (start=%d, end=%d)\n", entry, (int)do_list_queue_start, (int)do_list_queue_end));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -