LCOV - code coverage report
Current view: top level - source3/client - client.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 1566 3233 48.4 %
Date: 2024-04-21 15:09:00 Functions: 85 140 60.7 %

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

Generated by: LCOV version 1.14