| 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 | 
 | 
|---|
| 63 | struct 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 */
 | 
|---|
| 78 | static uint64_t get_total_size = 0;
 | 
|---|
| 79 | static uint_t get_total_time_ms = 0;
 | 
|---|
| 80 | static uint64_t put_total_size = 0;
 | 
|---|
| 81 | static 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 */
 | 
|---|
| 84 | static struct smbclient_context *rl_ctx; 
 | 
|---|
| 85 | 
 | 
|---|
| 86 | /* totals globals */
 | 
|---|
| 87 | static double dir_total;
 | 
|---|
| 88 | 
 | 
|---|
| 89 | /*******************************************************************
 | 
|---|
| 90 |  Reduce a file name, removing .. elements.
 | 
|---|
| 91 | ********************************************************************/
 | 
|---|
| 92 | static 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 | /****************************************************************************
 | 
|---|
| 113 | write to a local file with CR/LF->LF translation if appropriate. return the 
 | 
|---|
| 114 | number taken from the buffer. This may not equal the number written.
 | 
|---|
| 115 | ****************************************************************************/
 | 
|---|
| 116 | static 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 | ****************************************************************************/
 | 
|---|
| 144 | static 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 | /****************************************************************************
 | 
|---|
| 171 | send a message
 | 
|---|
| 172 | ****************************************************************************/
 | 
|---|
| 173 | static 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 | /****************************************************************************
 | 
|---|
| 220 | check the space on a device
 | 
|---|
| 221 | ****************************************************************************/
 | 
|---|
| 222 | static 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 | /****************************************************************************
 | 
|---|
| 241 | show cd/pwd
 | 
|---|
| 242 | ****************************************************************************/
 | 
|---|
| 243 | static 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 | */
 | 
|---|
| 252 | static void dos_format(char *s)
 | 
|---|
| 253 | {
 | 
|---|
| 254 |         string_replace(s, '/', '\\');
 | 
|---|
| 255 | }
 | 
|---|
| 256 | 
 | 
|---|
| 257 | /****************************************************************************
 | 
|---|
| 258 | change directory - inner section
 | 
|---|
| 259 | ****************************************************************************/
 | 
|---|
| 260 | static 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 | /****************************************************************************
 | 
|---|
| 289 | change directory
 | 
|---|
| 290 | ****************************************************************************/
 | 
|---|
| 291 | static 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 | 
 | 
|---|
| 304 | static 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 |   ********************************************************************/
 | 
|---|
| 333 | static 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 |   ****************************************************************************/
 | 
|---|
| 359 | static 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 |   ****************************************************************************/
 | 
|---|
| 378 | static 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 | 
 | 
|---|
| 385 | static bool do_list_recurse;
 | 
|---|
| 386 | static bool do_list_dirs;
 | 
|---|
| 387 | static char *do_list_queue = 0;
 | 
|---|
| 388 | static long do_list_queue_size = 0;
 | 
|---|
| 389 | static long do_list_queue_start = 0;
 | 
|---|
| 390 | static long do_list_queue_end = 0;
 | 
|---|
| 391 | static void (*do_list_fn)(struct smbclient_context *, struct clilist_file_info *);
 | 
|---|
| 392 | 
 | 
|---|
| 393 | /****************************************************************************
 | 
|---|
| 394 | functions 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 |  */
 | 
|---|
| 408 | static 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 | 
 | 
|---|
| 416 | static 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 | 
 | 
|---|
| 430 | static 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 | 
 | 
|---|
| 456 | static 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 | 
 | 
|---|
| 488 | static char *do_list_queue_head(void)
 | 
|---|
| 489 | {
 | 
|---|
| 490 |         return do_list_queue + do_list_queue_start;
 | 
|---|
| 491 | }
 | 
|---|
| 492 | 
 | 
|---|
| 493 | static 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 | 
 | 
|---|
| 504 | static int do_list_queue_empty(void)
 | 
|---|
| 505 | {
 | 
|---|
| 506 |         return (! (do_list_queue && *do_list_queue));
 | 
|---|
| 507 | }
 | 
|---|
| 508 | 
 | 
|---|
| 509 | /****************************************************************************
 | 
|---|
| 510 | a helper for do_list
 | 
|---|
| 511 |   ****************************************************************************/
 | 
|---|
| 512 | static 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 | /****************************************************************************
 | 
|---|
| 543 | a wrapper around smbcli_list that adds recursion
 | 
|---|
| 544 |   ****************************************************************************/
 | 
|---|
| 545 | static 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 |   ****************************************************************************/
 | 
|---|
| 615 | static 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 |   ****************************************************************************/
 | 
|---|
| 655 | static 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 |   ****************************************************************************/
 | 
|---|
| 688 | static 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 |   ****************************************************************************/
 | 
|---|
| 813 | static 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 | ****************************************************************************/
 | 
|---|
| 838 | static 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 |   ****************************************************************************/
 | 
|---|
| 855 | static 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 | /****************************************************************************
 | 
|---|
| 913 | view the file using the pager
 | 
|---|
| 914 | ****************************************************************************/
 | 
|---|
| 915 | static 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 | /****************************************************************************
 | 
|---|
| 954 | do a mget command
 | 
|---|
| 955 | ****************************************************************************/
 | 
|---|
| 956 | static 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 | /****************************************************************************
 | 
|---|
| 989 | make a directory of name "name"
 | 
|---|
| 990 | ****************************************************************************/
 | 
|---|
| 991 | static 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 | ****************************************************************************/
 | 
|---|
| 1008 | static 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 |   ****************************************************************************/
 | 
|---|
| 1020 | static 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 | /****************************************************************************
 | 
|---|
| 1053 | show 8.3 name of a file
 | 
|---|
| 1054 | ****************************************************************************/
 | 
|---|
| 1055 | static 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 |   ****************************************************************************/
 | 
|---|
| 1081 | static 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 |   ****************************************************************************/
 | 
|---|
| 1212 | static 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 | 
 | 
|---|
| 1249 | static 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 | 
 | 
|---|
| 1259 | static 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 |   ****************************************************************************/
 | 
|---|
| 1276 | static 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 |   ****************************************************************************/
 | 
|---|
| 1292 | static 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 |  ********************************************************************/
 | 
|---|
| 1303 | static 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 | ****************************************************************************/
 | 
|---|
| 1341 | static 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 |   ****************************************************************************/
 | 
|---|
| 1404 | static 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 |   ****************************************************************************/
 | 
|---|
| 1488 | static 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 | 
 | 
|---|
| 1514 | static 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 | /****************************************************************************
 | 
|---|
| 1522 | delete some files
 | 
|---|
| 1523 | ****************************************************************************/
 | 
|---|
| 1524 | static 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 | /****************************************************************************
 | 
|---|
| 1547 | delete a whole directory tree
 | 
|---|
| 1548 | ****************************************************************************/
 | 
|---|
| 1549 | static 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 | 
 | 
|---|
| 1573 | typedef struct {
 | 
|---|
| 1574 |         const char  *level_name;
 | 
|---|
| 1575 |         enum smb_fsinfo_level level;
 | 
|---|
| 1576 | } fsinfo_level_t;
 | 
|---|
| 1577 | 
 | 
|---|
| 1578 | fsinfo_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 | 
 | 
|---|
| 1598 | static 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 | /****************************************************************************
 | 
|---|
| 1746 | show as much information as possible about a file
 | 
|---|
| 1747 | ****************************************************************************/
 | 
|---|
| 1748 | static 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 | /****************************************************************************
 | 
|---|
| 1877 | shows EA contents
 | 
|---|
| 1878 | ****************************************************************************/
 | 
|---|
| 1879 | static 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 | /****************************************************************************
 | 
|---|
| 1919 | show any ACL on a file
 | 
|---|
| 1920 | ****************************************************************************/
 | 
|---|
| 1921 | static 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 | /****************************************************************************
 | 
|---|
| 1963 | lookup a name or sid
 | 
|---|
| 1964 | ****************************************************************************/
 | 
|---|
| 1965 | static 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 | /****************************************************************************
 | 
|---|
| 2000 | show privileges for a user
 | 
|---|
| 2001 | ****************************************************************************/
 | 
|---|
| 2002 | static 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 | /****************************************************************************
 | 
|---|
| 2040 | add privileges for a user
 | 
|---|
| 2041 | ****************************************************************************/
 | 
|---|
| 2042 | static 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 | /****************************************************************************
 | 
|---|
| 2084 | delete privileges for a user
 | 
|---|
| 2085 | ****************************************************************************/
 | 
|---|
| 2086 | static 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 | ****************************************************************************/
 | 
|---|
| 2130 | static 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 | /****************************************************************************
 | 
|---|
| 2147 | remove a directory
 | 
|---|
| 2148 | ****************************************************************************/
 | 
|---|
| 2149 | static 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 | ****************************************************************************/
 | 
|---|
| 2170 | static 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 | 
 | 
|---|
| 2200 | static 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 | 
 | 
|---|
| 2230 | static 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 | 
 | 
|---|
| 2262 | static 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 | /****************************************************************************
 | 
|---|
| 2292 | rename some files
 | 
|---|
| 2293 | ****************************************************************************/
 | 
|---|
| 2294 | static 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 | /****************************************************************************
 | 
|---|
| 2316 | toggle the prompt flag
 | 
|---|
| 2317 | ****************************************************************************/
 | 
|---|
| 2318 | static 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 | /****************************************************************************
 | 
|---|
| 2328 | set the newer than time
 | 
|---|
| 2329 | ****************************************************************************/
 | 
|---|
| 2330 | static 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 | /****************************************************************************
 | 
|---|
| 2351 | set the archive level
 | 
|---|
| 2352 | ****************************************************************************/
 | 
|---|
| 2353 | static 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 | /****************************************************************************
 | 
|---|
| 2364 | toggle the lowercaseflag
 | 
|---|
| 2365 | ****************************************************************************/
 | 
|---|
| 2366 | static 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 | /****************************************************************************
 | 
|---|
| 2378 | toggle the recurse flag
 | 
|---|
| 2379 | ****************************************************************************/
 | 
|---|
| 2380 | static 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 | /****************************************************************************
 | 
|---|
| 2389 | toggle the translate flag
 | 
|---|
| 2390 | ****************************************************************************/
 | 
|---|
| 2391 | static 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 | /****************************************************************************
 | 
|---|
| 2402 | do a printmode command
 | 
|---|
| 2403 | ****************************************************************************/
 | 
|---|
| 2404 | static 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 |  ****************************************************************************/
 | 
|---|
| 2436 | static 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 | /****************************************************************************
 | 
|---|
| 2448 | history
 | 
|---|
| 2449 | ****************************************************************************/
 | 
|---|
| 2450 | static 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 |  ****************************************************************************/
 | 
|---|
| 2471 | static 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 |  ****************************************************************************/
 | 
|---|
| 2494 | static 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 | */
 | 
|---|
| 2524 | static 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 | */
 | 
|---|
| 2544 | static 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 | /****************************************************************************
 | 
|---|
| 2561 | try and browse available shares on a host
 | 
|---|
| 2562 | ****************************************************************************/
 | 
|---|
| 2563 | static 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 | /****************************************************************************
 | 
|---|
| 2629 | try and browse available connections on a host
 | 
|---|
| 2630 | ****************************************************************************/
 | 
|---|
| 2631 | static 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 | 
 | 
|---|
| 2643 | static 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 |  */
 | 
|---|
| 2650 | static 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 |   ******************************************************************/
 | 
|---|
| 2721 | static 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 | /****************************************************************************
 | 
|---|
| 2748 | help
 | 
|---|
| 2749 | ****************************************************************************/
 | 
|---|
| 2750 | static 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 | 
 | 
|---|
| 2769 | static int process_line(struct smbclient_context *ctx, const char *cline);
 | 
|---|
| 2770 | /****************************************************************************
 | 
|---|
| 2771 | process a -c command string
 | 
|---|
| 2772 | ****************************************************************************/
 | 
|---|
| 2773 | static 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 | 
 | 
|---|
| 2789 | typedef struct {
 | 
|---|
| 2790 |         char *dirmask;
 | 
|---|
| 2791 |         char **matches;
 | 
|---|
| 2792 |         int count, samelen;
 | 
|---|
| 2793 |         const char *text;
 | 
|---|
| 2794 |         int len;
 | 
|---|
| 2795 | } completion_remote_t;
 | 
|---|
| 2796 | 
 | 
|---|
| 2797 | static 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 | 
 | 
|---|
| 2830 | static 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 | 
 | 
|---|
| 2877 | cleanup:
 | 
|---|
| 2878 |         for (i = 0; i < info.count; i++)
 | 
|---|
| 2879 |                 free(info.matches[i]);
 | 
|---|
| 2880 |         free(info.matches);
 | 
|---|
| 2881 |         return NULL;
 | 
|---|
| 2882 | }
 | 
|---|
| 2883 | 
 | 
|---|
| 2884 | static 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 | 
 | 
|---|
| 2959 | cleanup:
 | 
|---|
| 2960 |                 count--;
 | 
|---|
| 2961 |                 while (count >= 0) {
 | 
|---|
| 2962 |                         free(matches[count]);
 | 
|---|
| 2963 |                         count--;
 | 
|---|
| 2964 |                 }
 | 
|---|
| 2965 |                 free(matches);
 | 
|---|
| 2966 |                 return NULL;
 | 
|---|
| 2967 |         }
 | 
|---|
| 2968 | }
 | 
|---|
| 2969 | 
 | 
|---|
| 2970 | /****************************************************************************
 | 
|---|
| 2971 | make sure we swallow keepalives during idle time
 | 
|---|
| 2972 | ****************************************************************************/
 | 
|---|
| 2973 | static 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 | 
 | 
|---|
| 2991 | static 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 | /****************************************************************************
 | 
|---|
| 3015 | process commands on stdin
 | 
|---|
| 3016 | ****************************************************************************/
 | 
|---|
| 3017 | static 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 | /***************************************************** 
 | 
|---|
| 3045 | return a connection to a server
 | 
|---|
| 3046 | *******************************************************/
 | 
|---|
| 3047 | static 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 | /****************************************************************************
 | 
|---|
| 3092 | handle a -L query
 | 
|---|
| 3093 | ****************************************************************************/
 | 
|---|
| 3094 | static 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 | /****************************************************************************
 | 
|---|
| 3106 | handle a message operation
 | 
|---|
| 3107 | ****************************************************************************/
 | 
|---|
| 3108 | static 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 | }
 | 
|---|