root/src/vfs/smbfs/helpers/libsmb/clientgen.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. cli_set_port
  2. cli_receive_smb
  3. cli_send_smb
  4. cli_smb_errstr
  5. cli_errstr
  6. cli_setup_packet
  7. fix_char_ptr
  8. cli_send_trans
  9. cli_receive_trans
  10. cli_api_pipe
  11. cli_api
  12. cli_NetWkstaUserLogon
  13. cli_RNetShareEnum
  14. cli_NetServerEnum
  15. cli_session_setup
  16. cli_ulogoff
  17. cli_send_tconX
  18. cli_tdis
  19. cli_rename
  20. cli_unlink
  21. cli_mkdir
  22. cli_rmdir
  23. cli_nt_create
  24. cli_open
  25. cli_close
  26. cli_lock
  27. cli_unlock
  28. cli_issue_read
  29. cli_read
  30. cli_issue_write
  31. cli_write
  32. cli_smbwrite
  33. cli_getattrE
  34. cli_getatr
  35. cli_setatr
  36. cli_qpathinfo
  37. cli_qpathinfo2
  38. cli_qfileinfo
  39. interpret_long_filename
  40. cli_list
  41. cli_negprot
  42. cli_session_request
  43. cli_connect
  44. cli_initialise
  45. cli_shutdown
  46. cli_error
  47. cli_sockopt
  48. cli_setpid
  49. cli_reestablish_connection
  50. cli_establish_connection
  51. cli_chkpath
  52. cli_message_start
  53. cli_message_text
  54. cli_message_end
  55. cli_dskattr

   1 /*
   2    Unix SMB/Netbios implementation.
   3    Version 1.9.
   4    SMB client generic functions
   5 
   6    Copyright (C) Andrew Tridgell 1994-1998
   7 
   8    Copyright (C) 2011-2019
   9    Free Software Foundation, Inc.
  10 
  11    This file is part of the Midnight Commander.
  12 
  13    The Midnight Commander is free software: you can redistribute it
  14    and/or modify it under the terms of the GNU General Public License as
  15    published by the Free Software Foundation, either version 3 of the License,
  16    or (at your option) any later version.
  17 
  18    The Midnight Commander is distributed in the hope that it will be useful,
  19    but WITHOUT ANY WARRANTY; without even the implied warranty of
  20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21    GNU General Public License for more details.
  22 
  23    You should have received a copy of the GNU General Public License
  24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  25  */
  26 
  27 #define NO_SYSLOG
  28 
  29 #include "includes.h"
  30 #include "trans2.h"
  31 
  32 
  33 extern int DEBUGLEVEL;
  34 extern pstring user_socket_options;
  35 
  36 /*
  37  * Change the port number used to call on 
  38  */
  39 int
  40 cli_set_port (struct cli_state *cli, int port)
     /* [previous][next][first][last][top][bottom][index][help]  */
  41 {
  42     if (port > 0)
  43         cli->port = port;
  44 
  45     return cli->port;
  46 }
  47 
  48 /****************************************************************************
  49 recv an smb
  50 ****************************************************************************/
  51 static BOOL
  52 cli_receive_smb (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
  53 {
  54     return client_receive_smb (cli->fd, cli->inbuf, cli->timeout);
  55 }
  56 
  57 /****************************************************************************
  58   send an smb to a fd and re-establish if necessary
  59 ****************************************************************************/
  60 static BOOL
  61 cli_send_smb (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
  62 {
  63     size_t len;
  64     size_t nwritten = 0;
  65     ssize_t ret;
  66     BOOL reestablished = False;
  67 
  68     len = smb_len (cli->outbuf) + 4;
  69 
  70     while (nwritten < len)
  71     {
  72         ret = write_socket (cli->fd, cli->outbuf + nwritten, len - nwritten);
  73         if (ret <= 0 && errno == EPIPE && !reestablished)
  74         {
  75             if (cli_reestablish_connection (cli))
  76             {
  77                 reestablished = True;
  78                 nwritten = 0;
  79                 continue;
  80             }
  81         }
  82         if (ret <= 0)
  83         {
  84             DEBUG (0, ("Error writing %d bytes to client. %d. Exiting\n", (int) len, (int) ret));
  85             close_sockets ();
  86             exit (1);
  87         }
  88         nwritten += ret;
  89     }
  90 
  91     return True;
  92 }
  93 
  94 /*****************************************************
  95  RAP error codes - a small start but will be extended.
  96 *******************************************************/
  97 
  98 struct
  99 {
 100     int err;
 101     const char *message;
 102 } const rap_errmap[] = {
 103     {5, "User has insufficient privilege"},
 104     {86, "The specified password is invalid"},
 105     {2226, "Operation only permitted on a Primary Domain Controller"},
 106     {2242, "The password of this user has expired."},
 107     {2243, "The password of this user cannot change."},
 108     {2244, "This password cannot be used now (password history conflict)."},
 109     {2245, "The password is shorter than required."},
 110     {2246, "The password of this user is too recent to change."},
 111     {0, NULL}
 112 };
 113 
 114 /****************************************************************************
 115   return a description of an SMB error
 116 ****************************************************************************/
 117 static char *
 118 cli_smb_errstr (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 119 {
 120     return smb_errstr (cli->inbuf);
 121 }
 122 
 123 /******************************************************
 124  Return an error message - either an SMB error or a RAP
 125  error.
 126 *******************************************************/
 127 
 128 char *
 129 cli_errstr (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 130 {
 131     static fstring error_message;
 132     uint8 errclass;
 133     uint32 errnum;
 134     uint32 nt_rpc_error;
 135     int i;
 136 
 137     /*  
 138      * Errors are of three kinds - smb errors,
 139      * dealt with by cli_smb_errstr, NT errors,
 140      * whose code is in cli.nt_error, and rap
 141      * errors, whose error code is in cli.rap_error.
 142      */
 143 
 144     cli_error (cli, &errclass, &errnum, &nt_rpc_error);
 145 
 146     if (errclass != 0)
 147     {
 148         return cli_smb_errstr (cli);
 149     }
 150 
 151     /*
 152      * Was it an NT error ?
 153      */
 154 
 155     if (nt_rpc_error)
 156     {
 157         const char *nt_msg = get_nt_error_msg (nt_rpc_error);
 158 
 159         if (nt_msg == NULL)
 160         {
 161             slprintf (error_message, sizeof (fstring) - 1, "NT code %d", nt_rpc_error);
 162         }
 163         else
 164         {
 165             fstrcpy (error_message, nt_msg);
 166         }
 167 
 168         return error_message;
 169     }
 170 
 171     /*
 172      * Must have been a rap error.
 173      */
 174 
 175     slprintf (error_message, sizeof (error_message) - 1, "code %d", cli->rap_error);
 176 
 177     for (i = 0; rap_errmap[i].message != NULL; i++)
 178     {
 179         if (rap_errmap[i].err == cli->rap_error)
 180         {
 181             fstrcpy (error_message, rap_errmap[i].message);
 182             break;
 183         }
 184     }
 185 
 186     return error_message;
 187 }
 188 
 189 /****************************************************************************
 190 setup basics in a outgoing packet
 191 ****************************************************************************/
 192 static void
 193 cli_setup_packet (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 194 {
 195     cli->rap_error = 0;
 196     cli->nt_error = 0;
 197     SSVAL (cli->outbuf, smb_pid, cli->pid);
 198     SSVAL (cli->outbuf, smb_uid, cli->vuid);
 199     SSVAL (cli->outbuf, smb_mid, cli->mid);
 200     if (cli->protocol > PROTOCOL_CORE)
 201     {
 202         SCVAL (cli->outbuf, smb_flg, 0x8);
 203         SSVAL (cli->outbuf, smb_flg2, 0x1);
 204     }
 205 }
 206 
 207 #if 0
 208 /*****************************************************************************
 209  Convert a character pointer in a cli_call_api() response to a form we can use.
 210  This function contains code to prevent core dumps if the server returns 
 211  invalid data.
 212 *****************************************************************************/
 213 static char *
 214 fix_char_ptr (unsigned int datap, unsigned int converter, char *rdata, int rdrcnt)
     /* [previous][next][first][last][top][bottom][index][help]  */
 215 {
 216     if (datap == 0)
 217     {                           /* turn NULL pointers into zero length strings */
 218         return "";
 219     }
 220     else
 221     {
 222         unsigned int offset = datap - converter;
 223 
 224         if (offset >= rdrcnt)
 225         {
 226             DEBUG (1, ("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
 227                        datap, converter, rdrcnt));
 228             return "<ERROR>";
 229         }
 230         else
 231         {
 232             return &rdata[offset];
 233         }
 234     }
 235 }
 236 #endif /* 0 */
 237 /****************************************************************************
 238   send a SMB trans or trans2 request
 239   ****************************************************************************/
 240 static BOOL
 241 cli_send_trans (struct cli_state *cli, int trans,
     /* [previous][next][first][last][top][bottom][index][help]  */
 242                 const char *name, int pipe_name_len,
 243                 int fid, int flags,
 244                 uint16 * setup, int lsetup, int msetup,
 245                 char *param, int lparam, int mparam, char *data, int ldata, int mdata)
 246 {
 247     int i;
 248     int this_ldata, this_lparam;
 249     int tot_data = 0, tot_param = 0;
 250     char *outdata, *outparam;
 251     char *p;
 252 
 253     this_lparam = MIN (lparam, cli->max_xmit - (500 + lsetup * 2));     /* hack */
 254     this_ldata = MIN (ldata, cli->max_xmit - (500 + lsetup * 2 + this_lparam));
 255 
 256     memset (cli->outbuf, '\0', smb_size);
 257     set_message (cli->outbuf, 14 + lsetup, 0, True);
 258     CVAL (cli->outbuf, smb_com) = trans;
 259     SSVAL (cli->outbuf, smb_tid, cli->cnum);
 260     cli_setup_packet (cli);
 261 
 262     outparam = smb_buf (cli->outbuf) + (trans == SMBtrans ? pipe_name_len + 1 : 3);
 263     outdata = outparam + this_lparam;
 264 
 265     /* primary request */
 266     SSVAL (cli->outbuf, smb_tpscnt, lparam);    /* tpscnt */
 267     SSVAL (cli->outbuf, smb_tdscnt, ldata);     /* tdscnt */
 268     SSVAL (cli->outbuf, smb_mprcnt, mparam);    /* mprcnt */
 269     SSVAL (cli->outbuf, smb_mdrcnt, mdata);     /* mdrcnt */
 270     SCVAL (cli->outbuf, smb_msrcnt, msetup);    /* msrcnt */
 271     SSVAL (cli->outbuf, smb_flags, flags);      /* flags */
 272     SIVAL (cli->outbuf, smb_timeout, 0);        /* timeout */
 273     SSVAL (cli->outbuf, smb_pscnt, this_lparam);        /* pscnt */
 274     SSVAL (cli->outbuf, smb_psoff, smb_offset (outparam, cli->outbuf)); /* psoff */
 275     SSVAL (cli->outbuf, smb_dscnt, this_ldata); /* dscnt */
 276     SSVAL (cli->outbuf, smb_dsoff, smb_offset (outdata, cli->outbuf));  /* dsoff */
 277     SCVAL (cli->outbuf, smb_suwcnt, lsetup);    /* suwcnt */
 278     for (i = 0; i < lsetup; i++)        /* setup[] */
 279         SSVAL (cli->outbuf, smb_setup + i * 2, setup[i]);
 280     p = smb_buf (cli->outbuf);
 281     if (trans == SMBtrans)
 282     {
 283         memcpy (p, name, pipe_name_len + 1);    /* name[] */
 284     }
 285     else
 286     {
 287         *p++ = 0;               /* put in a null smb_name */
 288         *p++ = 'D';
 289         *p++ = ' ';             /* observed in OS/2 */
 290     }
 291     if (this_lparam)            /* param[] */
 292         memcpy (outparam, param, this_lparam);
 293     if (this_ldata)             /* data[] */
 294         memcpy (outdata, data, this_ldata);
 295     set_message (cli->outbuf, 14 + lsetup,      /* wcnt, bcc */
 296                  PTR_DIFF (outdata + this_ldata, smb_buf (cli->outbuf)), False);
 297 
 298     show_msg (cli->outbuf);
 299     cli_send_smb (cli);
 300 
 301     if (this_ldata < ldata || this_lparam < lparam)
 302     {
 303         /* receive interim response */
 304         if (!cli_receive_smb (cli) || CVAL (cli->inbuf, smb_rcls) != 0)
 305         {
 306             return (False);
 307         }
 308 
 309         tot_data = this_ldata;
 310         tot_param = this_lparam;
 311 
 312         while (tot_data < ldata || tot_param < lparam)
 313         {
 314             this_lparam = MIN (lparam - tot_param, cli->max_xmit - 500);        /* hack */
 315             this_ldata = MIN (ldata - tot_data, cli->max_xmit - (500 + this_lparam));
 316 
 317             set_message (cli->outbuf, trans == SMBtrans ? 8 : 9, 0, True);
 318             CVAL (cli->outbuf, smb_com) = trans == SMBtrans ? SMBtranss : SMBtranss2;
 319 
 320             outparam = smb_buf (cli->outbuf);
 321             outdata = outparam + this_lparam;
 322 
 323             /* secondary request */
 324             SSVAL (cli->outbuf, smb_tpscnt, lparam);    /* tpscnt */
 325             SSVAL (cli->outbuf, smb_tdscnt, ldata);     /* tdscnt */
 326             SSVAL (cli->outbuf, smb_spscnt, this_lparam);       /* pscnt */
 327             SSVAL (cli->outbuf, smb_spsoff, smb_offset (outparam, cli->outbuf));        /* psoff */
 328             SSVAL (cli->outbuf, smb_spsdisp, tot_param);        /* psdisp */
 329             SSVAL (cli->outbuf, smb_sdscnt, this_ldata);        /* dscnt */
 330             SSVAL (cli->outbuf, smb_sdsoff, smb_offset (outdata, cli->outbuf)); /* dsoff */
 331             SSVAL (cli->outbuf, smb_sdsdisp, tot_data); /* dsdisp */
 332             if (trans == SMBtrans2)
 333                 SSVALS (cli->outbuf, smb_sfid, fid);    /* fid */
 334             if (this_lparam)    /* param[] */
 335                 memcpy (outparam, param, this_lparam);
 336             if (this_ldata)     /* data[] */
 337                 memcpy (outdata, data, this_ldata);
 338             set_message (cli->outbuf, trans == SMBtrans ? 8 : 9,        /* wcnt, bcc */
 339                          PTR_DIFF (outdata + this_ldata, smb_buf (cli->outbuf)), False);
 340 
 341             show_msg (cli->outbuf);
 342             cli_send_smb (cli);
 343 
 344             tot_data += this_ldata;
 345             tot_param += this_lparam;
 346         }
 347     }
 348 
 349     return (True);
 350 }
 351 
 352 
 353 /****************************************************************************
 354   receive a SMB trans or trans2 response allocating the necessary memory
 355   ****************************************************************************/
 356 static BOOL
 357 cli_receive_trans (struct cli_state *cli, int trans,
     /* [previous][next][first][last][top][bottom][index][help]  */
 358                    char **param, int *param_len, char **data, int *data_len)
 359 {
 360     int total_data = 0;
 361     int total_param = 0;
 362     int this_data, this_param;
 363     uint8 eclass;
 364     uint32 ecode;
 365 
 366     *data_len = *param_len = 0;
 367 
 368     if (!cli_receive_smb (cli))
 369         return False;
 370 
 371     show_msg (cli->inbuf);
 372 
 373     /* sanity check */
 374     if (CVAL (cli->inbuf, smb_com) != trans)
 375     {
 376         DEBUG (0, ("Expected %s response, got command 0x%02x\n",
 377                    trans == SMBtrans ? "SMBtrans" : "SMBtrans2", CVAL (cli->inbuf, smb_com)));
 378         return (False);
 379     }
 380 
 381     /*
 382      * An NT RPC pipe call can return ERRDOS, ERRmoredata
 383      * to a trans call. This is not an error and should not
 384      * be treated as such.
 385      */
 386 
 387     if (cli_error (cli, &eclass, &ecode, NULL))
 388     {
 389         if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
 390             return (False);
 391     }
 392 
 393     /* parse out the lengths */
 394     total_data = SVAL (cli->inbuf, smb_tdrcnt);
 395     total_param = SVAL (cli->inbuf, smb_tprcnt);
 396 
 397     /* allocate it */
 398     *data = Realloc (*data, total_data);
 399     *param = Realloc (*param, total_param);
 400 
 401     while (1)
 402     {
 403         this_data = SVAL (cli->inbuf, smb_drcnt);
 404         this_param = SVAL (cli->inbuf, smb_prcnt);
 405 
 406         if (this_data + *data_len > total_data || this_param + *param_len > total_param)
 407         {
 408             DEBUG (1, ("Data overflow in cli_receive_trans\n"));
 409             return False;
 410         }
 411 
 412         if (this_data)
 413             memcpy (*data + SVAL (cli->inbuf, smb_drdisp),
 414                     smb_base (cli->inbuf) + SVAL (cli->inbuf, smb_droff), this_data);
 415         if (this_param)
 416             memcpy (*param + SVAL (cli->inbuf, smb_prdisp),
 417                     smb_base (cli->inbuf) + SVAL (cli->inbuf, smb_proff), this_param);
 418         *data_len += this_data;
 419         *param_len += this_param;
 420 
 421         /* parse out the total lengths again - they can shrink! */
 422         total_data = SVAL (cli->inbuf, smb_tdrcnt);
 423         total_param = SVAL (cli->inbuf, smb_tprcnt);
 424 
 425         if (total_data <= *data_len && total_param <= *param_len)
 426             break;
 427 
 428         if (!cli_receive_smb (cli))
 429             return False;
 430 
 431         show_msg (cli->inbuf);
 432 
 433         /* sanity check */
 434         if (CVAL (cli->inbuf, smb_com) != trans)
 435         {
 436             DEBUG (0, ("Expected %s response, got command 0x%02x\n",
 437                        trans == SMBtrans ? "SMBtrans" : "SMBtrans2", CVAL (cli->inbuf, smb_com)));
 438             return (False);
 439         }
 440         if (cli_error (cli, &eclass, &ecode, NULL))
 441         {
 442             if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
 443                 return (False);
 444         }
 445     }
 446 
 447     return (True);
 448 }
 449 
 450 #if 0
 451 /****************************************************************************
 452 Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
 453 ****************************************************************************/
 454 BOOL
 455 cli_api_pipe (struct cli_state * cli, char *pipe_name, int pipe_name_len,
     /* [previous][next][first][last][top][bottom][index][help]  */
 456               uint16 * setup, uint32 setup_count, uint32 max_setup_count,
 457               char *params, uint32 param_count, uint32 max_param_count,
 458               char *data, uint32 data_count, uint32 max_data_count,
 459               char **rparam, uint32 * rparam_count, char **rdata, uint32 * rdata_count)
 460 {
 461     if (pipe_name_len == 0)
 462         pipe_name_len = strlen (pipe_name);
 463 
 464     cli_send_trans (cli, SMBtrans, pipe_name, pipe_name_len, 0, 0,      /* fid, flags */
 465                     setup, setup_count, max_setup_count,
 466                     params, param_count, max_param_count, data, data_count, max_data_count);
 467 
 468     return (cli_receive_trans (cli, SMBtrans,
 469                                rparam, (int *) rparam_count, rdata, (int *) rdata_count));
 470 }
 471 #endif /*0 */
 472 
 473 /****************************************************************************
 474 call a remote api
 475 ****************************************************************************/
 476 BOOL
 477 cli_api (struct cli_state *cli,
     /* [previous][next][first][last][top][bottom][index][help]  */
 478          char *param, int prcnt, int mprcnt,
 479          char *data, int drcnt, int mdrcnt, char **rparam, int *rprcnt, char **rdata, int *rdrcnt)
 480 {
 481     cli_send_trans (cli, SMBtrans, PIPE_LANMAN, strlen (PIPE_LANMAN),   /* Name, length */
 482                     0, 0,       /* fid, flags */
 483                     NULL, 0, 0, /* Setup, length, max */
 484                     param, prcnt, mprcnt,       /* Params, length, max */
 485                     data, drcnt, mdrcnt /* Data, length, max */
 486         );
 487 
 488     return (cli_receive_trans (cli, SMBtrans, rparam, rprcnt, rdata, rdrcnt));
 489 }
 490 
 491 #if 0
 492 /****************************************************************************
 493 perform a NetWkstaUserLogon
 494 ****************************************************************************/
 495 BOOL
 496 cli_NetWkstaUserLogon (struct cli_state * cli, char *user, char *workstation)
     /* [previous][next][first][last][top][bottom][index][help]  */
 497 {
 498     char *rparam = NULL;
 499     char *rdata = NULL;
 500     char *p;
 501     int rdrcnt, rprcnt;
 502     pstring param;
 503 
 504     memset (param, 0, sizeof (param));
 505 
 506     /* send a SMBtrans command with api NetWkstaUserLogon */
 507     p = param;
 508     SSVAL (p, 0, 132);          /* api number */
 509     p += 2;
 510     pstrcpy (p, "OOWb54WrLh");
 511     p = skip_string (p, 1);
 512     pstrcpy (p, "WB21BWDWWDDDDDDDzzzD");
 513     p = skip_string (p, 1);
 514     SSVAL (p, 0, 1);
 515     p += 2;
 516     pstrcpy (p, user);
 517     strupper (p);
 518     p += 21;
 519     p++;
 520     p += 15;
 521     p++;
 522     pstrcpy (p, workstation);
 523     strupper (p);
 524     p += 16;
 525     SSVAL (p, 0, CLI_BUFFER_SIZE);
 526     p += 2;
 527     SSVAL (p, 0, CLI_BUFFER_SIZE);
 528     p += 2;
 529 
 530     if (cli_api (cli, param, PTR_DIFF (p, param), 1024, /* param, length, max */
 531                  NULL, 0, CLI_BUFFER_SIZE,      /* data, length, max */
 532                  &rparam, &rprcnt,      /* return params, return size */
 533                  &rdata, &rdrcnt        /* return data, return size */
 534         ))
 535     {
 536         cli->rap_error = SVAL (rparam, 0);
 537         p = rdata;
 538 
 539         if (cli->rap_error == 0)
 540         {
 541             DEBUG (4, ("NetWkstaUserLogon success\n"));
 542             cli->privileges = SVAL (p, 24);
 543             fstrcpy (cli->eff_name, p + 2);
 544         }
 545         else
 546         {
 547             DEBUG (1, ("NetwkstaUserLogon gave error %d\n", cli->rap_error));
 548         }
 549     }
 550 
 551     if (rparam)
 552         free (rparam);
 553     if (rdata)
 554         free (rdata);
 555     return (cli->rap_error == 0);
 556 }
 557 #endif /*0 */
 558 
 559 /****************************************************************************
 560 call a NetShareEnum - try and browse available connections on a host
 561 ****************************************************************************/
 562 int
 563 cli_RNetShareEnum (struct cli_state *cli, void (*fn) (const char *, uint32, const char *, void *),
     /* [previous][next][first][last][top][bottom][index][help]  */
 564                    void *state)
 565 {
 566     char *rparam = NULL;
 567     char *rdata = NULL;
 568     char *p;
 569     int rdrcnt, rprcnt;
 570     pstring param;
 571     int count = -1;
 572 
 573     /* now send a SMBtrans command with api RNetShareEnum */
 574     p = param;
 575     SSVAL (p, 0, 0);            /* api number */
 576     p += 2;
 577     pstrcpy (p, "WrLeh");
 578     p = skip_string (p, 1);
 579     pstrcpy (p, "B13BWz");
 580     p = skip_string (p, 1);
 581     SSVAL (p, 0, 1);
 582     /*
 583      * Win2k needs a *smaller* buffer than 0xFFFF here -
 584      * it returns "out of server memory" with 0xFFFF !!! JRA.
 585      */
 586     SSVAL (p, 2, 0xFFE0);
 587     p += 4;
 588 
 589     if (cli_api (cli, param, PTR_DIFF (p, param), 1024, /* Param, length, maxlen */
 590                  NULL, 0, 0xFFE0,       /* data, length, maxlen - Win2k needs a small buffer here too ! */
 591                  &rparam, &rprcnt,      /* return params, length */
 592                  &rdata, &rdrcnt))      /* return data, length */
 593     {
 594         int res = SVAL (rparam, 0);
 595         int converter = SVAL (rparam, 2);
 596         int i;
 597 
 598         if (res == 0 || res == ERRmoredata)
 599         {
 600             count = SVAL (rparam, 4);
 601             p = rdata;
 602 
 603             for (i = 0; i < count; i++, p += 20)
 604             {
 605                 char *sname = p;
 606                 int type = SVAL (p, 14);
 607                 int comment_offset = IVAL (p, 16) & 0xFFFF;
 608                 const char *cmnt = comment_offset ? (rdata + comment_offset - converter) : "";
 609                 fn (sname, type, cmnt, state);
 610             }
 611         }
 612         else
 613         {
 614             DEBUG (4, ("NetShareEnum res=%d\n", res));
 615         }
 616     }
 617     else
 618     {
 619         DEBUG (4, ("NetShareEnum failed\n"));
 620     }
 621 
 622     if (rparam)
 623         free (rparam);
 624     if (rdata)
 625         free (rdata);
 626 
 627     return count;
 628 }
 629 
 630 
 631 /****************************************************************************
 632 call a NetServerEnum for the specified workgroup and servertype mask.
 633 This function then calls the specified callback function for each name returned.
 634 
 635 The callback function takes 3 arguments: the machine name, the server type and
 636 the comment.
 637 ****************************************************************************/
 638 BOOL
 639 cli_NetServerEnum (struct cli_state * cli, char *workgroup, uint32 stype,
     /* [previous][next][first][last][top][bottom][index][help]  */
 640                    void (*fn) (const char *, uint32, const char *, void *), void *state)
 641 {
 642     char *rparam = NULL;
 643     char *rdata = NULL;
 644     int rdrcnt, rprcnt;
 645     char *p;
 646     pstring param;
 647     int uLevel = 1;
 648     int count = -1;
 649 
 650     /* send a SMBtrans command with api NetServerEnum */
 651     p = param;
 652     SSVAL (p, 0, 0x68);         /* api number */
 653     p += 2;
 654     pstrcpy (p, "WrLehDz");
 655     p = skip_string (p, 1);
 656 
 657     pstrcpy (p, "B16BBDz");
 658 
 659     p = skip_string (p, 1);
 660     SSVAL (p, 0, uLevel);
 661     SSVAL (p, 2, CLI_BUFFER_SIZE);
 662     p += 4;
 663     SIVAL (p, 0, stype);
 664     p += 4;
 665 
 666     pstrcpy (p, workgroup);
 667     p = skip_string (p, 1);
 668 
 669     if (cli_api (cli, param, PTR_DIFF (p, param), 8,    /* params, length, max */
 670                  NULL, 0, CLI_BUFFER_SIZE,      /* data, length, max */
 671                  &rparam, &rprcnt,      /* return params, return size */
 672                  &rdata, &rdrcnt        /* return data, return size */
 673         ))
 674     {
 675         int res = SVAL (rparam, 0);
 676         int converter = SVAL (rparam, 2);
 677         int i;
 678 
 679         if (res == 0 || res == ERRmoredata)
 680         {
 681             count = SVAL (rparam, 4);
 682             p = rdata;
 683 
 684             for (i = 0; i < count; i++, p += 26)
 685             {
 686                 char *sname = p;
 687                 int comment_offset = (IVAL (p, 22) & 0xFFFF) - converter;
 688                 const char *cmnt = comment_offset ? (rdata + comment_offset) : "";
 689                 if (comment_offset < 0 || comment_offset > rdrcnt)
 690                     continue;
 691 
 692                 stype = IVAL (p, 18) & ~SV_TYPE_LOCAL_LIST_ONLY;
 693 
 694                 fn (sname, stype, cmnt, state);
 695             }
 696         }
 697     }
 698 
 699     if (rparam)
 700         free (rparam);
 701     if (rdata)
 702         free (rdata);
 703 
 704     return (count > 0);
 705 }
 706 
 707 
 708 
 709 
 710 static struct
 711 {
 712     int prot;
 713     const char *name;
 714 }
 715 const prots[] = {
 716     {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
 717     {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
 718     {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
 719     {PROTOCOL_LANMAN1, "LANMAN1.0"},
 720     {PROTOCOL_LANMAN2, "LM1.2X002"},
 721     {PROTOCOL_LANMAN2, "Samba"},
 722     {PROTOCOL_NT1, "NT LANMAN 1.0"},
 723     {PROTOCOL_NT1, "NT LM 0.12"},
 724     {-1, NULL}
 725 };
 726 
 727 
 728 /****************************************************************************
 729 send a session setup 
 730 ****************************************************************************/
 731 BOOL
 732 cli_session_setup (struct cli_state *cli,
     /* [previous][next][first][last][top][bottom][index][help]  */
 733                    char *user,
 734                    char *pass, int passlen, char *ntpass, int ntpasslen, char *workgroup)
 735 {
 736     char *p;
 737     fstring pword, ntpword;
 738 
 739     if (cli->protocol < PROTOCOL_LANMAN1)
 740         return True;
 741 
 742     if ((size_t) passlen > sizeof (pword) - 1 || (size_t) ntpasslen > sizeof (ntpword) - 1)
 743     {
 744         return False;
 745     }
 746 
 747     if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0'))
 748     {
 749         /* Null session connect. */
 750         pword[0] = '\0';
 751         ntpword[0] = '\0';
 752     }
 753     else
 754     {
 755         if ((cli->sec_mode & 2) && passlen != 24)
 756         {
 757             passlen = 24;
 758             ntpasslen = 24;
 759             SMBencrypt ((uchar *) pass, (uchar *) cli->cryptkey, (uchar *) pword);
 760             SMBNTencrypt ((uchar *) ntpass, (uchar *) cli->cryptkey, (uchar *) ntpword);
 761         }
 762         else
 763         {
 764             fstrcpy (pword, pass);
 765             fstrcpy (ntpword, "");
 766             ntpasslen = 0;
 767         }
 768     }
 769 
 770     /* if in share level security then don't send a password now */
 771     if (!(cli->sec_mode & 1))
 772     {
 773         fstrcpy (pword, "");
 774         passlen = 1;
 775         fstrcpy (ntpword, "");
 776         ntpasslen = 1;
 777     }
 778 
 779     /* send a session setup command */
 780     memset (cli->outbuf, '\0', smb_size);
 781 
 782     if (cli->protocol < PROTOCOL_NT1)
 783     {
 784         set_message (cli->outbuf, 10, 1 + strlen (user) + passlen, True);
 785         CVAL (cli->outbuf, smb_com) = SMBsesssetupX;
 786         cli_setup_packet (cli);
 787 
 788         CVAL (cli->outbuf, smb_vwv0) = 0xFF;
 789         SSVAL (cli->outbuf, smb_vwv2, cli->max_xmit);
 790         SSVAL (cli->outbuf, smb_vwv3, 2);
 791         SSVAL (cli->outbuf, smb_vwv4, 1);
 792         SIVAL (cli->outbuf, smb_vwv5, cli->sesskey);
 793         SSVAL (cli->outbuf, smb_vwv7, passlen);
 794         p = smb_buf (cli->outbuf);
 795         memcpy (p, pword, passlen);
 796         p += passlen;
 797         pstrcpy (p, user);
 798         strupper (p);
 799         unix_to_dos (p, True);
 800     }
 801     else
 802     {
 803         set_message (cli->outbuf, 13, 0, True);
 804         CVAL (cli->outbuf, smb_com) = SMBsesssetupX;
 805         cli_setup_packet (cli);
 806 
 807         CVAL (cli->outbuf, smb_vwv0) = 0xFF;
 808         SSVAL (cli->outbuf, smb_vwv2, CLI_BUFFER_SIZE);
 809         SSVAL (cli->outbuf, smb_vwv3, 2);
 810         SSVAL (cli->outbuf, smb_vwv4, cli->pid);
 811         SIVAL (cli->outbuf, smb_vwv5, cli->sesskey);
 812         SSVAL (cli->outbuf, smb_vwv7, passlen);
 813         SSVAL (cli->outbuf, smb_vwv8, ntpasslen);
 814         SSVAL (cli->outbuf, smb_vwv11, 0);
 815         p = smb_buf (cli->outbuf);
 816         memcpy (p, pword, passlen);
 817         p += SVAL (cli->outbuf, smb_vwv7);
 818         memcpy (p, ntpword, ntpasslen);
 819         p += SVAL (cli->outbuf, smb_vwv8);
 820         pstrcpy (p, user);
 821         strupper (p);
 822         unix_to_dos (p, True);
 823         p = skip_string (p, 1);
 824         pstrcpy (p, workgroup);
 825         strupper (p);
 826         p = skip_string (p, 1);
 827         pstrcpy (p, "Unix");
 828         p = skip_string (p, 1);
 829         pstrcpy (p, "Samba");
 830         p = skip_string (p, 1);
 831         set_message (cli->outbuf, 13, PTR_DIFF (p, smb_buf (cli->outbuf)), False);
 832     }
 833 
 834     cli_send_smb (cli);
 835     if (!cli_receive_smb (cli))
 836         return False;
 837 
 838     show_msg (cli->inbuf);
 839 
 840     if (CVAL (cli->inbuf, smb_rcls) != 0)
 841     {
 842         return False;
 843     }
 844 
 845     /* use the returned vuid from now on */
 846     cli->vuid = SVAL (cli->inbuf, smb_uid);
 847 
 848     if (cli->protocol >= PROTOCOL_NT1)
 849     {
 850         /*
 851          * Save off some of the connected server
 852          * info.
 853          */
 854         char *server_domain, *server_os, *server_type;
 855         server_os = smb_buf (cli->inbuf);
 856         server_type = skip_string (server_os, 1);
 857         server_domain = skip_string (server_type, 1);
 858         fstrcpy (cli->server_os, server_os);
 859         fstrcpy (cli->server_type, server_type);
 860         fstrcpy (cli->server_domain, server_domain);
 861     }
 862 
 863     fstrcpy (cli->user_name, user);
 864 
 865     return True;
 866 }
 867 
 868 /****************************************************************************
 869  Send a uloggoff.
 870 *****************************************************************************/
 871 #if 0
 872 BOOL
 873 cli_ulogoff (struct cli_state * cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 874 {
 875     memset (cli->outbuf, '\0', smb_size);
 876     set_message (cli->outbuf, 2, 0, True);
 877     CVAL (cli->outbuf, smb_com) = SMBulogoffX;
 878     cli_setup_packet (cli);
 879     SSVAL (cli->outbuf, smb_vwv0, 0xFF);
 880     SSVAL (cli->outbuf, smb_vwv2, 0);   /* no additional info */
 881 
 882     cli_send_smb (cli);
 883     if (!cli_receive_smb (cli))
 884         return False;
 885 
 886     return CVAL (cli->inbuf, smb_rcls) == 0;
 887 }
 888 #endif /*0 */
 889 
 890 /****************************************************************************
 891 send a tconX
 892 ****************************************************************************/
 893 BOOL
 894 cli_send_tconX (struct cli_state * cli,
     /* [previous][next][first][last][top][bottom][index][help]  */
 895                 const char *share, const char *dev, const char *pass, int passlen)
 896 {
 897     fstring fullshare, pword;
 898     char *p;
 899     memset (cli->outbuf, '\0', smb_size);
 900     memset (cli->inbuf, '\0', smb_size);
 901 
 902     fstrcpy (cli->share, share);
 903 
 904     /* in user level security don't send a password now */
 905     if (cli->sec_mode & 1)
 906     {
 907         passlen = 1;
 908         pass = "";
 909     }
 910 
 911     if ((cli->sec_mode & 2) && *pass && passlen != 24)
 912     {
 913         passlen = 24;
 914         SMBencrypt ((uchar *) pass, (uchar *) cli->cryptkey, (uchar *) pword);
 915     }
 916     else
 917     {
 918         memcpy (pword, pass, passlen);
 919     }
 920 
 921     slprintf (fullshare, sizeof (fullshare) - 1, "\\\\%s\\%s", cli->desthost, share);
 922     unix_to_dos (fullshare, True);
 923     strupper (fullshare);
 924 
 925     set_message (cli->outbuf, 4, 2 + strlen (fullshare) + passlen + strlen (dev), True);
 926     CVAL (cli->outbuf, smb_com) = SMBtconX;
 927     cli_setup_packet (cli);
 928 
 929     SSVAL (cli->outbuf, smb_vwv0, 0xFF);
 930     SSVAL (cli->outbuf, smb_vwv3, passlen);
 931 
 932     p = smb_buf (cli->outbuf);
 933     memcpy (p, pword, passlen);
 934     p += passlen;
 935     fstrcpy (p, fullshare);
 936     p = skip_string (p, 1);
 937     pstrcpy (p, dev);
 938 
 939     SCVAL (cli->inbuf, smb_rcls, 1);
 940 
 941     cli_send_smb (cli);
 942     if (!cli_receive_smb (cli))
 943         return False;
 944 
 945     if (CVAL (cli->inbuf, smb_rcls) != 0)
 946     {
 947         return False;
 948     }
 949 
 950     fstrcpy (cli->dev, "A:");
 951 
 952     if (cli->protocol >= PROTOCOL_NT1)
 953     {
 954         fstrcpy (cli->dev, smb_buf (cli->inbuf));
 955     }
 956 
 957     if (strcasecmp (share, "IPC$") == 0)
 958     {
 959         fstrcpy (cli->dev, "IPC");
 960     }
 961 
 962     /* only grab the device if we have a recent protocol level */
 963     if (cli->protocol >= PROTOCOL_NT1 && smb_buflen (cli->inbuf) == 3)
 964     {
 965         /* almost certainly win95 - enable bug fixes */
 966         cli->win95 = True;
 967     }
 968 
 969     cli->cnum = SVAL (cli->inbuf, smb_tid);
 970     return True;
 971 }
 972 
 973 #if 0
 974 /****************************************************************************
 975 send a tree disconnect
 976 ****************************************************************************/
 977 BOOL
 978 cli_tdis (struct cli_state * cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
 979 {
 980     memset (cli->outbuf, '\0', smb_size);
 981     set_message (cli->outbuf, 0, 0, True);
 982     CVAL (cli->outbuf, smb_com) = SMBtdis;
 983     SSVAL (cli->outbuf, smb_tid, cli->cnum);
 984     cli_setup_packet (cli);
 985 
 986     cli_send_smb (cli);
 987     if (!cli_receive_smb (cli))
 988         return False;
 989 
 990     return CVAL (cli->inbuf, smb_rcls) == 0;
 991 }
 992 #endif /*0 */
 993 
 994 /****************************************************************************
 995 rename a file
 996 ****************************************************************************/
 997 BOOL
 998 cli_rename (struct cli_state * cli, char *fname_src, char *fname_dst)
     /* [previous][next][first][last][top][bottom][index][help]  */
 999 {
1000     char *p;
1001 
1002     memset (cli->outbuf, '\0', smb_size);
1003     memset (cli->inbuf, '\0', smb_size);
1004 
1005     set_message (cli->outbuf, 1, 4 + strlen (fname_src) + strlen (fname_dst), True);
1006 
1007     CVAL (cli->outbuf, smb_com) = SMBmv;
1008     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1009     cli_setup_packet (cli);
1010 
1011     SSVAL (cli->outbuf, smb_vwv0, aSYSTEM | aHIDDEN);
1012 
1013     p = smb_buf (cli->outbuf);
1014     *p++ = 4;
1015     pstrcpy (p, fname_src);
1016     p = skip_string (p, 1);
1017     *p++ = 4;
1018     pstrcpy (p, fname_dst);
1019 
1020     cli_send_smb (cli);
1021     if (!cli_receive_smb (cli))
1022     {
1023         return False;
1024     }
1025 
1026     if (CVAL (cli->inbuf, smb_rcls) != 0)
1027     {
1028         return False;
1029     }
1030 
1031     return True;
1032 }
1033 
1034 /****************************************************************************
1035 delete a file
1036 ****************************************************************************/
1037 BOOL
1038 cli_unlink (struct cli_state * cli, char *fname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1039 {
1040     char *p;
1041 
1042     memset (cli->outbuf, '\0', smb_size);
1043     memset (cli->inbuf, '\0', smb_size);
1044 
1045     set_message (cli->outbuf, 1, 2 + strlen (fname), True);
1046 
1047     CVAL (cli->outbuf, smb_com) = SMBunlink;
1048     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1049     cli_setup_packet (cli);
1050 
1051     SSVAL (cli->outbuf, smb_vwv0, aSYSTEM | aHIDDEN);
1052 
1053     p = smb_buf (cli->outbuf);
1054     *p++ = 4;
1055     pstrcpy (p, fname);
1056 
1057     cli_send_smb (cli);
1058     if (!cli_receive_smb (cli))
1059     {
1060         return False;
1061     }
1062 
1063     if (CVAL (cli->inbuf, smb_rcls) != 0)
1064     {
1065         return False;
1066     }
1067 
1068     return True;
1069 }
1070 
1071 /****************************************************************************
1072 create a directory
1073 ****************************************************************************/
1074 BOOL
1075 cli_mkdir (struct cli_state * cli, char *dname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1076 {
1077     char *p;
1078 
1079     memset (cli->outbuf, '\0', smb_size);
1080     memset (cli->inbuf, '\0', smb_size);
1081 
1082     set_message (cli->outbuf, 0, 2 + strlen (dname), True);
1083 
1084     CVAL (cli->outbuf, smb_com) = SMBmkdir;
1085     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1086     cli_setup_packet (cli);
1087 
1088     p = smb_buf (cli->outbuf);
1089     *p++ = 4;
1090     pstrcpy (p, dname);
1091 
1092     cli_send_smb (cli);
1093     if (!cli_receive_smb (cli))
1094     {
1095         return False;
1096     }
1097 
1098     if (CVAL (cli->inbuf, smb_rcls) != 0)
1099     {
1100         return False;
1101     }
1102 
1103     return True;
1104 }
1105 
1106 /****************************************************************************
1107 remove a directory
1108 ****************************************************************************/
1109 BOOL
1110 cli_rmdir (struct cli_state * cli, char *dname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1111 {
1112     char *p;
1113 
1114     memset (cli->outbuf, '\0', smb_size);
1115     memset (cli->inbuf, '\0', smb_size);
1116 
1117     set_message (cli->outbuf, 0, 2 + strlen (dname), True);
1118 
1119     CVAL (cli->outbuf, smb_com) = SMBrmdir;
1120     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1121     cli_setup_packet (cli);
1122 
1123     p = smb_buf (cli->outbuf);
1124     *p++ = 4;
1125     pstrcpy (p, dname);
1126 
1127     cli_send_smb (cli);
1128     if (!cli_receive_smb (cli))
1129     {
1130         return False;
1131     }
1132 
1133     if (CVAL (cli->inbuf, smb_rcls) != 0)
1134     {
1135         return False;
1136     }
1137 
1138     return True;
1139 }
1140 
1141 #if 0
1142 /****************************************************************************
1143 open a file
1144 ****************************************************************************/
1145 int
1146 cli_nt_create (struct cli_state *cli, char *fname)
     /* [previous][next][first][last][top][bottom][index][help]  */
1147 {
1148     char *p;
1149 
1150     memset (cli->outbuf, '\0', smb_size);
1151     memset (cli->inbuf, '\0', smb_size);
1152 
1153     set_message (cli->outbuf, 24, 1 + strlen (fname), True);
1154 
1155     CVAL (cli->outbuf, smb_com) = SMBntcreateX;
1156     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1157     cli_setup_packet (cli);
1158 
1159     SSVAL (cli->outbuf, smb_vwv0, 0xFF);
1160     SIVAL (cli->outbuf, smb_ntcreate_Flags, 0x06);
1161     SIVAL (cli->outbuf, smb_ntcreate_RootDirectoryFid, 0x0);
1162     SIVAL (cli->outbuf, smb_ntcreate_DesiredAccess, 0x2019f);
1163     SIVAL (cli->outbuf, smb_ntcreate_FileAttributes, 0x0);
1164     SIVAL (cli->outbuf, smb_ntcreate_ShareAccess, 0x03);
1165     SIVAL (cli->outbuf, smb_ntcreate_CreateDisposition, 0x01);
1166     SIVAL (cli->outbuf, smb_ntcreate_CreateOptions, 0x0);
1167     SIVAL (cli->outbuf, smb_ntcreate_ImpersonationLevel, 0x02);
1168     SSVAL (cli->outbuf, smb_ntcreate_NameLength, strlen (fname));
1169 
1170     p = smb_buf (cli->outbuf);
1171     pstrcpy (p, fname);
1172     p = skip_string (p, 1);
1173 
1174     cli_send_smb (cli);
1175     if (!cli_receive_smb (cli))
1176     {
1177         return -1;
1178     }
1179 
1180     if (CVAL (cli->inbuf, smb_rcls) != 0)
1181     {
1182         return -1;
1183     }
1184 
1185     return SVAL (cli->inbuf, smb_vwv2 + 1);
1186 }
1187 #endif /*0 */
1188 
1189 /****************************************************************************
1190 open a file
1191 ****************************************************************************/
1192 int
1193 cli_open (struct cli_state *cli, char *fname, int flags, int share_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1194 {
1195     char *p;
1196     unsigned openfn = 0;
1197     unsigned accessmode = 0;
1198 
1199     /* you must open for RW not just write - otherwise getattrE doesn't
1200        work! */
1201     if ((flags & O_ACCMODE) == O_WRONLY && strncmp (cli->dev, "LPT", 3))
1202     {
1203         flags = (flags & ~O_ACCMODE) | O_RDWR;
1204     }
1205 
1206     if (flags & O_CREAT)
1207         openfn |= (1 << 4);
1208     if (!(flags & O_EXCL))
1209     {
1210         if (flags & O_TRUNC)
1211             openfn |= (1 << 1);
1212         else
1213             openfn |= (1 << 0);
1214     }
1215 
1216     accessmode = (share_mode << 4);
1217 
1218     if ((flags & O_ACCMODE) == O_RDWR)
1219     {
1220         accessmode |= 2;
1221     }
1222     else if ((flags & O_ACCMODE) == O_WRONLY)
1223     {
1224         accessmode |= 1;
1225     }
1226 
1227 #if defined(O_SYNC)
1228     if ((flags & O_SYNC) == O_SYNC)
1229     {
1230         accessmode |= (1 << 14);
1231     }
1232 #endif /* O_SYNC */
1233 
1234     memset (cli->outbuf, '\0', smb_size);
1235     memset (cli->inbuf, '\0', smb_size);
1236 
1237     set_message (cli->outbuf, 15, 1 + strlen (fname), True);
1238 
1239     CVAL (cli->outbuf, smb_com) = SMBopenX;
1240     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1241     cli_setup_packet (cli);
1242 
1243     SSVAL (cli->outbuf, smb_vwv0, 0xFF);
1244     SSVAL (cli->outbuf, smb_vwv2, 0);   /* no additional info */
1245     SSVAL (cli->outbuf, smb_vwv3, accessmode);
1246     SSVAL (cli->outbuf, smb_vwv4, aSYSTEM | aHIDDEN);
1247     SSVAL (cli->outbuf, smb_vwv5, 0);
1248     SSVAL (cli->outbuf, smb_vwv8, openfn);
1249 
1250     p = smb_buf (cli->outbuf);
1251     pstrcpy (p, fname);
1252     p = skip_string (p, 1);
1253 
1254     cli_send_smb (cli);
1255     if (!cli_receive_smb (cli))
1256     {
1257         return -1;
1258     }
1259 
1260     if (CVAL (cli->inbuf, smb_rcls) != 0)
1261     {
1262         return -1;
1263     }
1264 
1265     return SVAL (cli->inbuf, smb_vwv2);
1266 }
1267 
1268 
1269 
1270 
1271 /****************************************************************************
1272   close a file
1273 ****************************************************************************/
1274 BOOL
1275 cli_close (struct cli_state * cli, int fnum)
     /* [previous][next][first][last][top][bottom][index][help]  */
1276 {
1277     memset (cli->outbuf, '\0', smb_size);
1278     memset (cli->inbuf, '\0', smb_size);
1279 
1280     set_message (cli->outbuf, 3, 0, True);
1281 
1282     CVAL (cli->outbuf, smb_com) = SMBclose;
1283     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1284     cli_setup_packet (cli);
1285 
1286     SSVAL (cli->outbuf, smb_vwv0, fnum);
1287     SIVALS (cli->outbuf, smb_vwv1, -1);
1288 
1289     cli_send_smb (cli);
1290     if (!cli_receive_smb (cli))
1291     {
1292         return False;
1293     }
1294 
1295     if (CVAL (cli->inbuf, smb_rcls) != 0)
1296     {
1297         return False;
1298     }
1299 
1300     return True;
1301 }
1302 
1303 #if 0
1304 /****************************************************************************
1305   lock a file
1306 ****************************************************************************/
1307 BOOL
1308 cli_lock (struct cli_state * cli, int fnum, uint32 offset, uint32 len, int timeout)
     /* [previous][next][first][last][top][bottom][index][help]  */
1309 {
1310     char *p;
1311     int saved_timeout = cli->timeout;
1312 
1313     memset (cli->outbuf, '\0', smb_size);
1314     memset (cli->inbuf, '\0', smb_size);
1315 
1316     set_message (cli->outbuf, 8, 10, True);
1317 
1318     CVAL (cli->outbuf, smb_com) = SMBlockingX;
1319     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1320     cli_setup_packet (cli);
1321 
1322     CVAL (cli->outbuf, smb_vwv0) = 0xFF;
1323     SSVAL (cli->outbuf, smb_vwv2, fnum);
1324     CVAL (cli->outbuf, smb_vwv3) = 0;
1325     SIVALS (cli->outbuf, smb_vwv4, timeout);
1326     SSVAL (cli->outbuf, smb_vwv6, 0);
1327     SSVAL (cli->outbuf, smb_vwv7, 1);
1328 
1329     p = smb_buf (cli->outbuf);
1330     SSVAL (p, 0, cli->pid);
1331     SIVAL (p, 2, offset);
1332     SIVAL (p, 6, len);
1333     cli_send_smb (cli);
1334 
1335     cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout;
1336 
1337     if (!cli_receive_smb (cli))
1338     {
1339         cli->timeout = saved_timeout;
1340         return False;
1341     }
1342 
1343     cli->timeout = saved_timeout;
1344 
1345     if (CVAL (cli->inbuf, smb_rcls) != 0)
1346     {
1347         return False;
1348     }
1349 
1350     return True;
1351 }
1352 
1353 /****************************************************************************
1354   unlock a file
1355 ****************************************************************************/
1356 BOOL
1357 cli_unlock (struct cli_state * cli, int fnum, uint32 offset, uint32 len, int timeout)
     /* [previous][next][first][last][top][bottom][index][help]  */
1358 {
1359     char *p;
1360 
1361     memset (cli->outbuf, '\0', smb_size);
1362     memset (cli->inbuf, '\0', smb_size);
1363 
1364     set_message (cli->outbuf, 8, 10, True);
1365 
1366     CVAL (cli->outbuf, smb_com) = SMBlockingX;
1367     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1368     cli_setup_packet (cli);
1369 
1370     CVAL (cli->outbuf, smb_vwv0) = 0xFF;
1371     SSVAL (cli->outbuf, smb_vwv2, fnum);
1372     CVAL (cli->outbuf, smb_vwv3) = 0;
1373     SIVALS (cli->outbuf, smb_vwv4, timeout);
1374     SSVAL (cli->outbuf, smb_vwv6, 1);
1375     SSVAL (cli->outbuf, smb_vwv7, 0);
1376 
1377     p = smb_buf (cli->outbuf);
1378     SSVAL (p, 0, cli->pid);
1379     SIVAL (p, 2, offset);
1380     SIVAL (p, 6, len);
1381 
1382     cli_send_smb (cli);
1383     if (!cli_receive_smb (cli))
1384     {
1385         return False;
1386     }
1387 
1388     if (CVAL (cli->inbuf, smb_rcls) != 0)
1389     {
1390         return False;
1391     }
1392 
1393     return True;
1394 }
1395 #endif /*0 */
1396 
1397 
1398 /****************************************************************************
1399 issue a single SMBread and don't wait for a reply
1400 ****************************************************************************/
1401 static void
1402 cli_issue_read (struct cli_state *cli, int fnum, off_t offset, size_t size, int i)
     /* [previous][next][first][last][top][bottom][index][help]  */
1403 {
1404     memset (cli->outbuf, '\0', smb_size);
1405     memset (cli->inbuf, '\0', smb_size);
1406 
1407     set_message (cli->outbuf, 10, 0, True);
1408 
1409     CVAL (cli->outbuf, smb_com) = SMBreadX;
1410     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1411     cli_setup_packet (cli);
1412 
1413     CVAL (cli->outbuf, smb_vwv0) = 0xFF;
1414     SSVAL (cli->outbuf, smb_vwv2, fnum);
1415     SIVAL (cli->outbuf, smb_vwv3, offset);
1416     SSVAL (cli->outbuf, smb_vwv5, size);
1417     SSVAL (cli->outbuf, smb_vwv6, size);
1418     SSVAL (cli->outbuf, smb_mid, cli->mid + i);
1419 
1420     cli_send_smb (cli);
1421 }
1422 
1423 /****************************************************************************
1424   read from a file
1425 ****************************************************************************/
1426 size_t
1427 cli_read (struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
1428 {
1429     char *p;
1430     int total = -1;
1431     int issued = 0;
1432     int received = 0;
1433     int mpx = MAX (cli->max_mux - 1, 1);
1434     int block = (cli->max_xmit - (smb_size + 32)) & ~1023;
1435     int mid;
1436     int blocks = (size + (block - 1)) / block;
1437 
1438     if (size == 0)
1439         return 0;
1440 
1441     while (received < blocks)
1442     {
1443         int size2;
1444 
1445         while (issued - received < mpx && issued < blocks)
1446         {
1447             int size1 = MIN (block, (int) size - issued * block);
1448             cli_issue_read (cli, fnum, offset + issued * block, size1, issued);
1449             issued++;
1450         }
1451 
1452         if (!cli_receive_smb (cli))
1453         {
1454             return total;
1455         }
1456 
1457         received++;
1458         mid = SVAL (cli->inbuf, smb_mid) - cli->mid;
1459         size2 = SVAL (cli->inbuf, smb_vwv5);
1460 
1461         if (CVAL (cli->inbuf, smb_rcls) != 0)
1462         {
1463             blocks = MIN (blocks, mid - 1);
1464             continue;
1465         }
1466 
1467         if (size2 <= 0)
1468         {
1469             blocks = MIN (blocks, mid - 1);
1470             /* this distinguishes EOF from an error */
1471             total = MAX (total, 0);
1472             continue;
1473         }
1474 
1475         if (size2 > block)
1476         {
1477             DEBUG (0, ("server returned more than we wanted!\n"));
1478             exit (1);
1479         }
1480         if (mid >= issued)
1481         {
1482             DEBUG (0, ("invalid mid from server!\n"));
1483             exit (1);
1484         }
1485         p = smb_base (cli->inbuf) + SVAL (cli->inbuf, smb_vwv6);
1486 
1487         memcpy (buf + mid * block, p, size2);
1488 
1489         total = MAX (total, mid * block + size2);
1490     }
1491 
1492     while (received < issued)
1493     {
1494         cli_receive_smb (cli);
1495         received++;
1496     }
1497 
1498     return total;
1499 }
1500 
1501 
1502 /****************************************************************************
1503 issue a single SMBwrite and don't wait for a reply
1504 ****************************************************************************/
1505 static void
1506 cli_issue_write (struct cli_state *cli, int fnum, off_t offset, uint16 mode, const char *buf,
     /* [previous][next][first][last][top][bottom][index][help]  */
1507                  size_t size, int i)
1508 {
1509     char *p;
1510 
1511     memset (cli->outbuf, '\0', smb_size);
1512     memset (cli->inbuf, '\0', smb_size);
1513 
1514     set_message (cli->outbuf, 12, size, True);
1515 
1516     CVAL (cli->outbuf, smb_com) = SMBwriteX;
1517     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1518     cli_setup_packet (cli);
1519 
1520     CVAL (cli->outbuf, smb_vwv0) = 0xFF;
1521     SSVAL (cli->outbuf, smb_vwv2, fnum);
1522 
1523     SIVAL (cli->outbuf, smb_vwv3, offset);
1524     SIVAL (cli->outbuf, smb_vwv5, IS_BITS_SET_ALL (mode, 0x0008) ? 0xFFFFFFFF : 0);
1525     SSVAL (cli->outbuf, smb_vwv7, mode);
1526 
1527     SSVAL (cli->outbuf, smb_vwv8, IS_BITS_SET_ALL (mode, 0x0008) ? size : 0);
1528     SSVAL (cli->outbuf, smb_vwv10, size);
1529     SSVAL (cli->outbuf, smb_vwv11, smb_buf (cli->outbuf) - smb_base (cli->outbuf));
1530 
1531     p = smb_base (cli->outbuf) + SVAL (cli->outbuf, smb_vwv11);
1532     memcpy (p, buf, size);
1533 
1534     SSVAL (cli->outbuf, smb_mid, cli->mid + i);
1535 
1536     show_msg (cli->outbuf);
1537     cli_send_smb (cli);
1538 }
1539 
1540 /****************************************************************************
1541   write to a file
1542   write_mode: 0x0001 disallow write cacheing
1543               0x0002 return bytes remaining
1544               0x0004 use raw named pipe protocol
1545               0x0008 start of message mode named pipe protocol
1546 ****************************************************************************/
1547 ssize_t
1548 cli_write (struct cli_state *cli,
     /* [previous][next][first][last][top][bottom][index][help]  */
1549            int fnum, uint16 write_mode, const char *buf, off_t offset, size_t size)
1550 {
1551     int bwritten = 0;
1552     int issued = 0;
1553     int received = 0;
1554     int mpx = MAX (cli->max_mux - 1, 1);
1555     int block = (cli->max_xmit - (smb_size + 32)) & ~1023;
1556     int blocks = (size + (block - 1)) / block;
1557 
1558     while (received < blocks)
1559     {
1560 
1561         while ((issued - received < mpx) && (issued < blocks))
1562         {
1563             int bsent = issued * block;
1564             int size1 = MIN (block, (int) size - bsent);
1565 
1566             cli_issue_write (cli, fnum, offset + bsent, write_mode, buf + bsent, size1, issued);
1567             issued++;
1568         }
1569 
1570         if (!cli_receive_smb (cli))
1571         {
1572             return bwritten;
1573         }
1574 
1575         received++;
1576 
1577         if (CVAL (cli->inbuf, smb_rcls) != 0)
1578         {
1579             break;
1580         }
1581 
1582         bwritten += SVAL (cli->inbuf, smb_vwv2);
1583     }
1584 
1585     while (received < issued && cli_receive_smb (cli))
1586     {
1587         received++;
1588     }
1589 
1590     return bwritten;
1591 }
1592 
1593 #if 0
1594 /****************************************************************************
1595   write to a file using a SMBwrite and not bypassing 0 byte writes
1596 ****************************************************************************/
1597 ssize_t
1598 cli_smbwrite (struct cli_state * cli, int fnum, const char *buf, off_t offset, size_t size)
     /* [previous][next][first][last][top][bottom][index][help]  */
1599 {
1600     char *p;
1601 
1602     memset (cli->outbuf, '\0', smb_size);
1603     memset (cli->inbuf, '\0', smb_size);
1604 
1605     set_message (cli->outbuf, 5, 3 + size, True);
1606 
1607     CVAL (cli->outbuf, smb_com) = SMBwrite;
1608     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1609     cli_setup_packet (cli);
1610 
1611     SSVAL (cli->outbuf, smb_vwv0, fnum);
1612     SSVAL (cli->outbuf, smb_vwv1, size);
1613     SIVAL (cli->outbuf, smb_vwv2, offset);
1614     SSVAL (cli->outbuf, smb_vwv4, 0);
1615 
1616     p = smb_buf (cli->outbuf);
1617     *p++ = 1;
1618     SSVAL (p, 0, size);
1619     memcpy (p + 2, buf, size);
1620 
1621     cli_send_smb (cli);
1622     if (!cli_receive_smb (cli))
1623     {
1624         return False;
1625     }
1626 
1627     if (CVAL (cli->inbuf, smb_rcls) != 0)
1628     {
1629         return -1;
1630     }
1631 
1632     return SVAL (cli->inbuf, smb_vwv0);
1633 }
1634 #endif /*0 */
1635 
1636 /****************************************************************************
1637 do a SMBgetattrE call
1638 ****************************************************************************/
1639 BOOL
1640 cli_getattrE (struct cli_state * cli, int fd,
     /* [previous][next][first][last][top][bottom][index][help]  */
1641               uint16 * attr, size_t * size, time_t * c_time, time_t * a_time, time_t * m_time)
1642 {
1643     memset (cli->outbuf, '\0', smb_size);
1644     memset (cli->inbuf, '\0', smb_size);
1645 
1646     set_message (cli->outbuf, 2, 0, True);
1647 
1648     CVAL (cli->outbuf, smb_com) = SMBgetattrE;
1649     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1650     cli_setup_packet (cli);
1651 
1652     SSVAL (cli->outbuf, smb_vwv0, fd);
1653 
1654     cli_send_smb (cli);
1655     if (!cli_receive_smb (cli))
1656     {
1657         return False;
1658     }
1659 
1660     if (CVAL (cli->inbuf, smb_rcls) != 0)
1661     {
1662         return False;
1663     }
1664 
1665     if (size)
1666     {
1667         *size = IVAL (cli->inbuf, smb_vwv6);
1668     }
1669 
1670     if (attr)
1671     {
1672         *attr = SVAL (cli->inbuf, smb_vwv10);
1673     }
1674 
1675     if (c_time)
1676     {
1677         *c_time = make_unix_date3 (cli->inbuf + smb_vwv0);
1678     }
1679 
1680     if (a_time)
1681     {
1682         *a_time = make_unix_date3 (cli->inbuf + smb_vwv2);
1683     }
1684 
1685     if (m_time)
1686     {
1687         *m_time = make_unix_date3 (cli->inbuf + smb_vwv4);
1688     }
1689 
1690     return True;
1691 }
1692 
1693 #if 0
1694 /****************************************************************************
1695 do a SMBgetatr call
1696 ****************************************************************************/
1697 BOOL
1698 cli_getatr (struct cli_state * cli, char *fname, uint16 * attr, size_t * size, time_t * t)
     /* [previous][next][first][last][top][bottom][index][help]  */
1699 {
1700     char *p;
1701 
1702     memset (cli->outbuf, '\0', smb_size);
1703     memset (cli->inbuf, '\0', smb_size);
1704 
1705     set_message (cli->outbuf, 0, strlen (fname) + 2, True);
1706 
1707     CVAL (cli->outbuf, smb_com) = SMBgetatr;
1708     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1709     cli_setup_packet (cli);
1710 
1711     p = smb_buf (cli->outbuf);
1712     *p = 4;
1713     pstrcpy (p + 1, fname);
1714 
1715     cli_send_smb (cli);
1716     if (!cli_receive_smb (cli))
1717     {
1718         return False;
1719     }
1720 
1721     if (CVAL (cli->inbuf, smb_rcls) != 0)
1722     {
1723         return False;
1724     }
1725 
1726     if (size)
1727     {
1728         *size = IVAL (cli->inbuf, smb_vwv3);
1729     }
1730 
1731     if (t)
1732     {
1733         *t = make_unix_date3 (cli->inbuf + smb_vwv1);
1734     }
1735 
1736     if (attr)
1737     {
1738         *attr = SVAL (cli->inbuf, smb_vwv0);
1739     }
1740 
1741 
1742     return True;
1743 }
1744 #endif /* 0 */
1745 
1746 /****************************************************************************
1747 do a SMBsetatr call
1748 ****************************************************************************/
1749 BOOL
1750 cli_setatr (struct cli_state * cli, char *fname, uint16 attr, time_t t)
     /* [previous][next][first][last][top][bottom][index][help]  */
1751 {
1752     char *p;
1753 
1754     memset (cli->outbuf, '\0', smb_size);
1755     memset (cli->inbuf, '\0', smb_size);
1756 
1757     set_message (cli->outbuf, 8, strlen (fname) + 4, True);
1758 
1759     CVAL (cli->outbuf, smb_com) = SMBsetatr;
1760     SSVAL (cli->outbuf, smb_tid, cli->cnum);
1761     cli_setup_packet (cli);
1762 
1763     SSVAL (cli->outbuf, smb_vwv0, attr);
1764     put_dos_date3 (cli->outbuf, smb_vwv1, t);
1765 
1766     p = smb_buf (cli->outbuf);
1767     *p = 4;
1768     pstrcpy (p + 1, fname);
1769     p = skip_string (p, 1);
1770     *p = 4;
1771 
1772     cli_send_smb (cli);
1773     if (!cli_receive_smb (cli))
1774     {
1775         return False;
1776     }
1777 
1778     if (CVAL (cli->inbuf, smb_rcls) != 0)
1779     {
1780         return False;
1781     }
1782 
1783     return True;
1784 }
1785 
1786 #if 0
1787 /****************************************************************************
1788 send a qpathinfo call
1789 ****************************************************************************/
1790 BOOL
1791 cli_qpathinfo (struct cli_state * cli, const char *fname,
     /* [previous][next][first][last][top][bottom][index][help]  */
1792                time_t * c_time, time_t * a_time, time_t * m_time, size_t * size, uint16 * mode)
1793 {
1794     int data_len = 0;
1795     int param_len = 0;
1796     uint16 setup = TRANSACT2_QPATHINFO;
1797     pstring param;
1798     char *rparam = NULL, *rdata = NULL;
1799     int count = 8;
1800     BOOL ret;
1801     time_t (*date_fn) (void *);
1802 
1803     param_len = strlen (fname) + 7;
1804 
1805     memset (param, 0, param_len);
1806     SSVAL (param, 0, SMB_INFO_STANDARD);
1807     pstrcpy (&param[6], fname);
1808 
1809     do
1810     {
1811         ret = (cli_send_trans (cli, SMBtrans2, NULL, 0, /* Name, length */
1812                                -1, 0,   /* fid, flags */
1813                                &setup, 1, 0,    /* setup, length, max */
1814                                param, param_len, 10,    /* param, length, max */
1815                                NULL, data_len, cli->max_xmit    /* data, length, max */
1816                ) && cli_receive_trans (cli, SMBtrans2, &rparam, &param_len, &rdata, &data_len));
1817         if (!ret)
1818         {
1819             /* we need to work around a Win95 bug - sometimes
1820                it gives ERRSRV/ERRerror temprarily */
1821             uint8 eclass;
1822             uint32 ecode;
1823             cli_error (cli, &eclass, &ecode, NULL);
1824             if (eclass != ERRSRV || ecode != ERRerror)
1825                 break;
1826             msleep (100);
1827         }
1828     }
1829     while (count-- && ret == False);
1830 
1831     if (!ret || !rdata || data_len < 22)
1832     {
1833         return False;
1834     }
1835 
1836     if (cli->win95)
1837     {
1838         date_fn = make_unix_date;
1839     }
1840     else
1841     {
1842         date_fn = make_unix_date2;
1843     }
1844 
1845     if (c_time)
1846     {
1847         *c_time = date_fn (rdata + 0);
1848     }
1849     if (a_time)
1850     {
1851         *a_time = date_fn (rdata + 4);
1852     }
1853     if (m_time)
1854     {
1855         *m_time = date_fn (rdata + 8);
1856     }
1857     if (size)
1858     {
1859         *size = IVAL (rdata, 12);
1860     }
1861     if (mode)
1862     {
1863         *mode = SVAL (rdata, l1_attrFile);
1864     }
1865 
1866     if (rdata)
1867         free (rdata);
1868     if (rparam)
1869         free (rparam);
1870     return True;
1871 }
1872 
1873 /****************************************************************************
1874 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1875 ****************************************************************************/
1876 BOOL
1877 cli_qpathinfo2 (struct cli_state * cli, const char *fname,
     /* [previous][next][first][last][top][bottom][index][help]  */
1878                 time_t * c_time, time_t * a_time, time_t * m_time,
1879                 time_t * w_time, size_t * size, uint16 * mode, SMB_INO_T * ino)
1880 {
1881     int data_len = 0;
1882     int param_len = 0;
1883     uint16 setup = TRANSACT2_QPATHINFO;
1884     pstring param;
1885     char *rparam = NULL, *rdata = NULL;
1886 
1887     param_len = strlen (fname) + 7;
1888 
1889     memset (param, 0, param_len);
1890     SSVAL (param, 0, SMB_QUERY_FILE_ALL_INFO);
1891     pstrcpy (&param[6], fname);
1892 
1893     if (!cli_send_trans (cli, SMBtrans2, NULL, 0,       /* name, length */
1894                          -1, 0, /* fid, flags */
1895                          &setup, 1, 0,  /* setup, length, max */
1896                          param, param_len, 10,  /* param, length, max */
1897                          NULL, data_len, cli->max_xmit  /* data, length, max */
1898         ))
1899     {
1900         return False;
1901     }
1902 
1903     if (!cli_receive_trans (cli, SMBtrans2, &rparam, &param_len, &rdata, &data_len))
1904     {
1905         return False;
1906     }
1907 
1908     if (!rdata || data_len < 22)
1909     {
1910         return False;
1911     }
1912 
1913     if (c_time)
1914     {
1915         *c_time = interpret_long_date (rdata + 0) - cli->serverzone;
1916     }
1917     if (a_time)
1918     {
1919         *a_time = interpret_long_date (rdata + 8) - cli->serverzone;
1920     }
1921     if (m_time)
1922     {
1923         *m_time = interpret_long_date (rdata + 16) - cli->serverzone;
1924     }
1925     if (w_time)
1926     {
1927         *w_time = interpret_long_date (rdata + 24) - cli->serverzone;
1928     }
1929     if (mode)
1930     {
1931         *mode = SVAL (rdata, 32);
1932     }
1933     if (size)
1934     {
1935         *size = IVAL (rdata, 48);
1936     }
1937     if (ino)
1938     {
1939         *ino = IVAL (rdata, 64);
1940     }
1941 
1942     if (rdata)
1943         free (rdata);
1944     if (rparam)
1945         free (rparam);
1946     return True;
1947 }
1948 #endif /* 0 */
1949 
1950 /****************************************************************************
1951 send a qfileinfo call
1952 ****************************************************************************/
1953 BOOL
1954 cli_qfileinfo (struct cli_state * cli, int fnum,
     /* [previous][next][first][last][top][bottom][index][help]  */
1955                uint16 * mode, size_t * size,
1956                time_t * c_time, time_t * a_time, time_t * m_time, time_t * w_time, SMB_INO_T * ino)
1957 {
1958     int data_len = 0;
1959     int param_len = 0;
1960     uint16 setup = TRANSACT2_QFILEINFO;
1961     pstring param;
1962     char *rparam = NULL, *rdata = NULL;
1963 
1964     /* if its a win95 server then fail this - win95 totally screws it
1965        up */
1966     if (cli->win95)
1967         return False;
1968 
1969     param_len = 4;
1970 
1971     memset (param, 0, param_len);
1972     SSVAL (param, 0, fnum);
1973     SSVAL (param, 2, SMB_QUERY_FILE_ALL_INFO);
1974 
1975     if (!cli_send_trans (cli, SMBtrans2, NULL, 0,       /* name, length */
1976                          -1, 0, /* fid, flags */
1977                          &setup, 1, 0,  /* setup, length, max */
1978                          param, param_len, 2,   /* param, length, max */
1979                          NULL, data_len, cli->max_xmit  /* data, length, max */
1980         ))
1981     {
1982         return False;
1983     }
1984 
1985     if (!cli_receive_trans (cli, SMBtrans2, &rparam, &param_len, &rdata, &data_len))
1986     {
1987         return False;
1988     }
1989 
1990     if (!rdata || data_len < 68)
1991     {
1992         return False;
1993     }
1994 
1995     if (c_time)
1996     {
1997         *c_time = interpret_long_date (rdata + 0) - cli->serverzone;
1998     }
1999     if (a_time)
2000     {
2001         *a_time = interpret_long_date (rdata + 8) - cli->serverzone;
2002     }
2003     if (m_time)
2004     {
2005         *m_time = interpret_long_date (rdata + 16) - cli->serverzone;
2006     }
2007     if (w_time)
2008     {
2009         *w_time = interpret_long_date (rdata + 24) - cli->serverzone;
2010     }
2011     if (mode)
2012     {
2013         *mode = SVAL (rdata, 32);
2014     }
2015     if (size)
2016     {
2017         *size = IVAL (rdata, 48);
2018     }
2019     if (ino)
2020     {
2021         *ino = IVAL (rdata, 64);
2022     }
2023 
2024     if (rdata)
2025         free (rdata);
2026     if (rparam)
2027         free (rparam);
2028     return True;
2029 }
2030 
2031 
2032 /****************************************************************************
2033 interpret a long filename structure - this is mostly guesses at the moment
2034 The length of the structure is returned
2035 The structure of a long filename depends on the info level. 260 is used
2036 by NT and 2 is used by OS/2
2037 ****************************************************************************/
2038 static int
2039 interpret_long_filename (int level, char *p, file_info * finfo)
     /* [previous][next][first][last][top][bottom][index][help]  */
2040 {
2041     extern file_info const def_finfo;
2042 
2043     if (finfo)
2044         memcpy (finfo, &def_finfo, sizeof (*finfo));
2045 
2046     switch (level)
2047     {
2048     case 1:                    /* OS/2 understands this */
2049         if (finfo)
2050         {
2051             /* these dates are converted to GMT by make_unix_date */
2052             finfo->ctime = make_unix_date2 (p + 4);
2053             finfo->atime = make_unix_date2 (p + 8);
2054             finfo->mtime = make_unix_date2 (p + 12);
2055             finfo->size = IVAL (p, 16);
2056             finfo->mode = CVAL (p, 24);
2057             pstrcpy (finfo->name, p + 27);
2058         }
2059         return (28 + CVAL (p, 26));
2060 
2061     case 2:                    /* this is what OS/2 uses mostly */
2062         if (finfo)
2063         {
2064             /* these dates are converted to GMT by make_unix_date */
2065             finfo->ctime = make_unix_date2 (p + 4);
2066             finfo->atime = make_unix_date2 (p + 8);
2067             finfo->mtime = make_unix_date2 (p + 12);
2068             finfo->size = IVAL (p, 16);
2069             finfo->mode = CVAL (p, 24);
2070             pstrcpy (finfo->name, p + 31);
2071         }
2072         return (32 + CVAL (p, 30));
2073 
2074         /* levels 3 and 4 are untested */
2075     case 3:
2076         if (finfo)
2077         {
2078             /* these dates are probably like the other ones */
2079             finfo->ctime = make_unix_date2 (p + 8);
2080             finfo->atime = make_unix_date2 (p + 12);
2081             finfo->mtime = make_unix_date2 (p + 16);
2082             finfo->size = IVAL (p, 20);
2083             finfo->mode = CVAL (p, 28);
2084             pstrcpy (finfo->name, p + 33);
2085         }
2086         return (SVAL (p, 4) + 4);
2087 
2088     case 4:
2089         if (finfo)
2090         {
2091             /* these dates are probably like the other ones */
2092             finfo->ctime = make_unix_date2 (p + 8);
2093             finfo->atime = make_unix_date2 (p + 12);
2094             finfo->mtime = make_unix_date2 (p + 16);
2095             finfo->size = IVAL (p, 20);
2096             finfo->mode = CVAL (p, 28);
2097             pstrcpy (finfo->name, p + 37);
2098         }
2099         return (SVAL (p, 4) + 4);
2100 
2101     case 260:                  /* NT uses this, but also accepts 2 */
2102         if (finfo)
2103         {
2104             int ret = SVAL (p, 0);
2105             int namelen;
2106             p += 4;             /* next entry offset */
2107             p += 4;             /* fileindex */
2108 
2109             /* these dates appear to arrive in a
2110                weird way. It seems to be localtime
2111                plus the serverzone given in the
2112                initial connect. This is GMT when
2113                DST is not in effect and one hour
2114                from GMT otherwise. Can this really
2115                be right??
2116 
2117                I suppose this could be called
2118                kludge-GMT. Is is the GMT you get
2119                by using the current DST setting on
2120                a different localtime. It will be
2121                cheap to calculate, I suppose, as
2122                no DST tables will be needed */
2123 
2124             finfo->ctime = interpret_long_date (p);
2125             p += 8;
2126             finfo->atime = interpret_long_date (p);
2127             p += 8;
2128             finfo->mtime = interpret_long_date (p);
2129             p += 8;
2130             p += 8;
2131             finfo->size = IVAL (p, 0);
2132             p += 8;
2133             p += 8;             /* alloc size */
2134             finfo->mode = CVAL (p, 0);
2135             p += 4;
2136             namelen = IVAL (p, 0);
2137             p += 4;
2138             p += 4;             /* EA size */
2139             p += 2;             /* short name len? */
2140             p += 24;            /* short name? */
2141             StrnCpy (finfo->name, p, namelen);
2142             return (ret);
2143         }
2144         return (SVAL (p, 0));
2145     }
2146 
2147     DEBUG (1, ("Unknown long filename format %d\n", level));
2148     return (SVAL (p, 0));
2149 }
2150 
2151 
2152 /****************************************************************************
2153   do a directory listing, calling fn on each file found
2154   ****************************************************************************/
2155 int
2156 cli_list (struct cli_state *cli, const char *Mask, uint16 attribute,
     /* [previous][next][first][last][top][bottom][index][help]  */
2157           void (*fn) (file_info *, const char *, void *), void *state)
2158 {
2159     int max_matches = 512;
2160     /* NT uses 260, OS/2 uses 2. Both accept 1. */
2161     int info_level = cli->protocol < PROTOCOL_NT1 ? 1 : 260;
2162     char *p, *p2;
2163     pstring mask;
2164     file_info finfo;
2165     int i;
2166     char *dirlist = NULL;
2167     int dirlist_len = 0;
2168     int total_received = -1;
2169     BOOL First = True;
2170     int ff_resume_key = 0;
2171     int ff_searchcount = 0;
2172     int ff_eos = 0;
2173     int ff_lastname = 0;
2174     int ff_dir_handle = 0;
2175     int loop_count = 0;
2176     char *rparam = NULL, *rdata = NULL;
2177     int param_len, data_len;
2178 
2179     uint16 setup;
2180     pstring param;
2181 
2182     pstrcpy (mask, Mask);
2183 
2184     while (ff_eos == 0)
2185     {
2186         loop_count++;
2187         if (loop_count > 200)
2188         {
2189             DEBUG (0, ("Error: Looping in FIND_NEXT??\n"));
2190             break;
2191         }
2192 
2193         param_len = 12 + strlen (mask) + 1;
2194 
2195         if (First)
2196         {
2197             setup = TRANSACT2_FINDFIRST;
2198             SSVAL (param, 0, attribute);        /* attribute */
2199             SSVAL (param, 2, max_matches);      /* max count */
2200             SSVAL (param, 4, 8 + 4 + 2);        /* resume required + close on end + continue */
2201             SSVAL (param, 6, info_level);
2202             SIVAL (param, 8, 0);
2203             pstrcpy (param + 12, mask);
2204         }
2205         else
2206         {
2207             setup = TRANSACT2_FINDNEXT;
2208             SSVAL (param, 0, ff_dir_handle);
2209             SSVAL (param, 2, max_matches);      /* max count */
2210             SSVAL (param, 4, info_level);
2211             SIVAL (param, 6, ff_resume_key);    /* ff_resume_key */
2212             SSVAL (param, 10, 8 + 4 + 2);       /* resume required + close on end + continue */
2213             pstrcpy (param + 12, mask);
2214 
2215             DEBUG (5, ("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
2216                        ff_dir_handle, ff_resume_key, ff_lastname, mask));
2217         }
2218 
2219         if (!cli_send_trans (cli, SMBtrans2, NULL, 0,   /* Name, length */
2220                              -1, 0,     /* fid, flags */
2221                              &setup, 1, 0,      /* setup, length, max */
2222                              param, param_len, 10,      /* param, length, max */
2223                              NULL, 0, cli->max_xmit     /* data, length, max */
2224             ))
2225         {
2226             break;
2227         }
2228 
2229         if (!cli_receive_trans (cli, SMBtrans2, &rparam, &param_len, &rdata, &data_len))
2230         {
2231             /* we need to work around a Win95 bug - sometimes
2232                it gives ERRSRV/ERRerror temprarily */
2233             uint8 eclass;
2234             uint32 ecode;
2235             cli_error (cli, &eclass, &ecode, NULL);
2236             if (eclass != ERRSRV || ecode != ERRerror)
2237                 break;
2238             msleep (100);
2239             continue;
2240         }
2241 
2242         if (total_received == -1)
2243             total_received = 0;
2244 
2245         /* parse out some important return info */
2246         p = rparam;
2247         if (First)
2248         {
2249             ff_dir_handle = SVAL (p, 0);
2250             ff_searchcount = SVAL (p, 2);
2251             ff_eos = SVAL (p, 4);
2252             ff_lastname = SVAL (p, 8);
2253         }
2254         else
2255         {
2256             ff_searchcount = SVAL (p, 0);
2257             ff_eos = SVAL (p, 2);
2258             ff_lastname = SVAL (p, 6);
2259         }
2260 
2261         if (ff_searchcount == 0)
2262             break;
2263 
2264         /* point to the data bytes */
2265         p = rdata;
2266 
2267         /* we might need the lastname for continuations */
2268         if (ff_lastname > 0)
2269         {
2270             switch (info_level)
2271             {
2272             case 260:
2273                 ff_resume_key = 0;
2274                 StrnCpy (mask, p + ff_lastname, data_len - ff_lastname);
2275                 break;
2276             case 1:
2277                 pstrcpy (mask, p + ff_lastname + 1);
2278                 ff_resume_key = 0;
2279                 break;
2280             }
2281         }
2282         else
2283         {
2284             pstrcpy (mask, "");
2285         }
2286 
2287         /* and add them to the dirlist pool */
2288         dirlist = Realloc (dirlist, dirlist_len + data_len);
2289 
2290         if (!dirlist)
2291         {
2292             DEBUG (0, ("Failed to expand dirlist\n"));
2293             break;
2294         }
2295 
2296         /* put in a length for the last entry, to ensure we can chain entries 
2297            into the next packet */
2298         for (p2 = p, i = 0; i < (ff_searchcount - 1); i++)
2299             p2 += interpret_long_filename (info_level, p2, NULL);
2300         SSVAL (p2, 0, data_len - PTR_DIFF (p2, p));
2301 
2302         /* grab the data for later use */
2303         memcpy (dirlist + dirlist_len, p, data_len);
2304         dirlist_len += data_len;
2305 
2306         total_received += ff_searchcount;
2307 
2308         if (rdata)
2309             free (rdata);
2310         rdata = NULL;
2311         if (rparam)
2312             free (rparam);
2313         rparam = NULL;
2314 
2315         DEBUG (3, ("received %d entries (eos=%d resume=%d)\n",
2316                    ff_searchcount, ff_eos, ff_resume_key));
2317 
2318         First = False;
2319     }
2320 
2321     for (p = dirlist, i = 0; i < total_received; i++)
2322     {
2323         p += interpret_long_filename (info_level, p, &finfo);
2324         fn (&finfo, Mask, state);
2325     }
2326 
2327     /* free up the dirlist buffer */
2328     if (dirlist)
2329         free (dirlist);
2330     return (total_received);
2331 }
2332 
2333 
2334 /****************************************************************************
2335 send a negprot command
2336 ****************************************************************************/
2337 BOOL
2338 cli_negprot (struct cli_state * cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
2339 {
2340     char *p;
2341     int numprots;
2342     int plength;
2343 
2344     memset (cli->outbuf, '\0', smb_size);
2345 
2346     /* setup the protocol strings */
2347     for (plength = 0, numprots = 0;
2348          prots[numprots].name && prots[numprots].prot <= cli->protocol; numprots++)
2349         plength += strlen (prots[numprots].name) + 2;
2350 
2351     set_message (cli->outbuf, 0, plength, True);
2352 
2353     p = smb_buf (cli->outbuf);
2354     for (numprots = 0; prots[numprots].name && prots[numprots].prot <= cli->protocol; numprots++)
2355     {
2356         *p++ = 2;
2357         pstrcpy (p, prots[numprots].name);
2358         p += strlen (p) + 1;
2359     }
2360 
2361     CVAL (cli->outbuf, smb_com) = SMBnegprot;
2362     cli_setup_packet (cli);
2363 
2364     CVAL (smb_buf (cli->outbuf), 0) = 2;
2365 
2366     cli_send_smb (cli);
2367     if (!cli_receive_smb (cli))
2368         return False;
2369 
2370     show_msg (cli->inbuf);
2371 
2372     if (CVAL (cli->inbuf, smb_rcls) != 0 || ((int) SVAL (cli->inbuf, smb_vwv0) >= numprots))
2373     {
2374         return (False);
2375     }
2376 
2377     cli->protocol = prots[SVAL (cli->inbuf, smb_vwv0)].prot;
2378 
2379 
2380     if (cli->protocol >= PROTOCOL_NT1)
2381     {
2382         /* NT protocol */
2383         cli->sec_mode = CVAL (cli->inbuf, smb_vwv1);
2384         cli->max_mux = SVAL (cli->inbuf, smb_vwv1 + 1);
2385         cli->max_xmit = IVAL (cli->inbuf, smb_vwv3 + 1);
2386         cli->sesskey = IVAL (cli->inbuf, smb_vwv7 + 1);
2387         cli->serverzone = SVALS (cli->inbuf, smb_vwv15 + 1) * 60;
2388         /* this time arrives in real GMT */
2389         cli->servertime = interpret_long_date (cli->inbuf + smb_vwv11 + 1);
2390         memcpy (cli->cryptkey, smb_buf (cli->inbuf), 8);
2391         cli->capabilities = IVAL (cli->inbuf, smb_vwv9 + 1);
2392         if (cli->capabilities & 1)
2393         {
2394             cli->readbraw_supported = True;
2395             cli->writebraw_supported = True;
2396         }
2397     }
2398     else if (cli->protocol >= PROTOCOL_LANMAN1)
2399     {
2400         cli->sec_mode = SVAL (cli->inbuf, smb_vwv1);
2401         cli->max_xmit = SVAL (cli->inbuf, smb_vwv2);
2402         cli->sesskey = IVAL (cli->inbuf, smb_vwv6);
2403         cli->serverzone = SVALS (cli->inbuf, smb_vwv10) * 60;
2404         /* this time is converted to GMT by make_unix_date */
2405         cli->servertime = make_unix_date (cli->inbuf + smb_vwv8);
2406         cli->readbraw_supported = ((SVAL (cli->inbuf, smb_vwv5) & 0x1) != 0);
2407         cli->writebraw_supported = ((SVAL (cli->inbuf, smb_vwv5) & 0x2) != 0);
2408         memcpy (cli->cryptkey, smb_buf (cli->inbuf), 8);
2409     }
2410     else
2411     {
2412         /* the old core protocol */
2413         cli->sec_mode = 0;
2414         cli->serverzone = TimeDiff (time (NULL));
2415     }
2416 
2417     cli->max_xmit = MIN (cli->max_xmit, CLI_BUFFER_SIZE);
2418 
2419     return True;
2420 }
2421 
2422 
2423 /****************************************************************************
2424   send a session request.  see rfc1002.txt 4.3 and 4.3.2
2425 ****************************************************************************/
2426 BOOL
2427 cli_session_request (struct cli_state * cli, struct nmb_name * calling, struct nmb_name * called)
     /* [previous][next][first][last][top][bottom][index][help]  */
2428 {
2429     char *p;
2430     int len = 4;
2431     /* send a session request (RFC 1002) */
2432 
2433     memcpy (&(cli->calling), calling, sizeof (*calling));
2434     memcpy (&(cli->called), called, sizeof (*called));
2435 
2436     /* put in the destination name */
2437     p = cli->outbuf + len;
2438     name_mangle (cli->called.name, p, cli->called.name_type);
2439     len += name_len (p);
2440 
2441     /* and my name */
2442     p = cli->outbuf + len;
2443     name_mangle (cli->calling.name, p, cli->calling.name_type);
2444     len += name_len (p);
2445 
2446     /* setup the packet length */
2447     _smb_setlen (cli->outbuf, len);
2448     CVAL (cli->outbuf, 0) = 0x81;
2449 
2450 #ifdef WITH_SSL
2451   retry:
2452 #endif /* WITH_SSL */
2453 
2454     cli_send_smb (cli);
2455     DEBUG (5, ("Sent session request\n"));
2456 
2457     if (!cli_receive_smb (cli))
2458         return False;
2459 
2460     if (CVAL (cli->inbuf, 0) == 0x84)
2461     {
2462         /* C. Hoch  9/14/95 Start */
2463         /* For information, here is the response structure.
2464          * We do the byte-twiddling to for portability.
2465          struct RetargetResponse{
2466          unsigned char type;
2467          unsigned char flags;
2468          int16 length;
2469          int32 ip_addr;
2470          int16 port;
2471          };
2472          */
2473         int port = (CVAL (cli->inbuf, 8) << 8) + CVAL (cli->inbuf, 9);
2474         /* SESSION RETARGET */
2475         putip ((char *) &cli->dest_ip, cli->inbuf + 4);
2476 
2477         close_sockets ();
2478         cli->fd = open_socket_out (SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
2479         if (cli->fd == -1)
2480             return False;
2481 
2482         DEBUG (3, ("Retargeted\n"));
2483 
2484         set_socket_options (cli->fd, user_socket_options);
2485 
2486         /* Try again */
2487         return cli_session_request (cli, calling, called);
2488     }                           /* C. Hoch 9/14/95 End */
2489 
2490 #ifdef WITH_SSL
2491     if (CVAL (cli->inbuf, 0) == 0x83 && CVAL (cli->inbuf, 4) == 0x8e)
2492     {                           /* use ssl */
2493         if (!sslutil_fd_is_ssl (cli->fd))
2494         {
2495             if (sslutil_connect (cli->fd) == 0)
2496                 goto retry;
2497         }
2498     }
2499 #endif /* WITH_SSL */
2500 
2501     if (CVAL (cli->inbuf, 0) != 0x82)
2502     {
2503         /* This is the wrong place to put the error... JRA. */
2504         cli->rap_error = CVAL (cli->inbuf, 0);
2505         return False;
2506     }
2507     return (True);
2508 }
2509 
2510 
2511 /****************************************************************************
2512 open the client sockets
2513 ****************************************************************************/
2514 BOOL
2515 cli_connect (struct cli_state * cli, const char *host, struct in_addr * ip)
     /* [previous][next][first][last][top][bottom][index][help]  */
2516 {
2517     extern struct in_addr ipzero;
2518 
2519     fstrcpy (cli->desthost, host);
2520 
2521     if (!ip || ip_equal (*ip, ipzero))
2522     {
2523         if (!resolve_name (cli->desthost, &cli->dest_ip, 0x20))
2524         {
2525             return False;
2526         }
2527         if (ip)
2528             *ip = cli->dest_ip;
2529     }
2530     else
2531     {
2532         cli->dest_ip = *ip;
2533     }
2534 
2535     if (cli->port == 0)
2536         cli->port = 139;        /* Set to default */
2537 
2538     cli->fd = open_socket_out (SOCK_STREAM, &cli->dest_ip, cli->port, cli->timeout);
2539     if (cli->fd == -1)
2540         return False;
2541 
2542     return True;
2543 }
2544 
2545 
2546 /****************************************************************************
2547 initialise a client structure
2548 ****************************************************************************/
2549 struct cli_state *
2550 cli_initialise (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
2551 {
2552     if (!cli)
2553     {
2554         cli = (struct cli_state *) malloc (sizeof (*cli));
2555         if (!cli)
2556             return NULL;
2557         ZERO_STRUCTP (cli);
2558     }
2559 
2560     if (cli->initialised)
2561     {
2562         cli_shutdown (cli);
2563     }
2564 
2565     ZERO_STRUCTP (cli);
2566 
2567     cli->port = 0;
2568     cli->fd = -1;
2569     cli->cnum = -1;
2570     cli->pid = (uint16) getpid ();
2571     cli->mid = 1;
2572     cli->vuid = UID_FIELD_INVALID;
2573     cli->protocol = PROTOCOL_NT1;
2574     cli->timeout = 20000;       /* Timeout is in milliseconds. */
2575     cli->bufsize = CLI_BUFFER_SIZE + 4;
2576     cli->max_xmit = cli->bufsize;
2577     cli->outbuf = (char *) malloc (cli->bufsize);
2578     cli->inbuf = (char *) malloc (cli->bufsize);
2579     if (!cli->outbuf || !cli->inbuf)
2580     {
2581         return False;
2582     }
2583 
2584     cli->initialised = 1;
2585 
2586     return cli;
2587 }
2588 
2589 /****************************************************************************
2590 shutdown a client structure
2591 ****************************************************************************/
2592 void
2593 cli_shutdown (struct cli_state *cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
2594 {
2595     if (cli->outbuf)
2596     {
2597         free (cli->outbuf);
2598     }
2599     if (cli->inbuf)
2600     {
2601         free (cli->inbuf);
2602     }
2603 #ifdef WITH_SSL
2604     if (cli->fd != -1)
2605         sslutil_disconnect (cli->fd);
2606 #endif /* WITH_SSL */
2607     if (cli->fd != -1)
2608         close (cli->fd);
2609     memset (cli, 0, sizeof (*cli));
2610 }
2611 
2612 
2613 /****************************************************************************
2614   return error codes for the last packet
2615   returns 0 if there was no error and the best approx of a unix errno
2616   otherwise
2617 
2618   for 32 bit "warnings", a return code of 0 is expected.
2619 
2620 ****************************************************************************/
2621 int
2622 cli_error (struct cli_state *cli, uint8 * eclass, uint32 * num, uint32 * nt_rpc_error)
     /* [previous][next][first][last][top][bottom][index][help]  */
2623 {
2624     int flgs2 = SVAL (cli->inbuf, smb_flg2);
2625     char rcls;
2626     int code;
2627 
2628     if (eclass)
2629         *eclass = 0;
2630     if (num)
2631         *num = 0;
2632     if (nt_rpc_error)
2633         *nt_rpc_error = cli->nt_error;
2634 
2635     if (flgs2 & FLAGS2_32_BIT_ERROR_CODES)
2636     {
2637         /* 32 bit error codes detected */
2638         uint32 nt_err = IVAL (cli->inbuf, smb_rcls);
2639         if (num)
2640             *num = nt_err;
2641         DEBUG (10, ("cli_error: 32 bit codes: code=%08x\n", nt_err));
2642         if (!IS_BITS_SET_ALL (nt_err, 0xc0000000))
2643             return 0;
2644 
2645         switch (nt_err & 0xFFFFFF)
2646         {
2647         case NT_STATUS_ACCESS_VIOLATION:
2648             return EACCES;
2649         case NT_STATUS_NO_SUCH_FILE:
2650             return ENOENT;
2651         case NT_STATUS_NO_SUCH_DEVICE:
2652             return ENODEV;
2653         case NT_STATUS_INVALID_HANDLE:
2654             return EBADF;
2655         case NT_STATUS_NO_MEMORY:
2656             return ENOMEM;
2657         case NT_STATUS_ACCESS_DENIED:
2658             return EACCES;
2659         case NT_STATUS_OBJECT_NAME_NOT_FOUND:
2660             return ENOENT;
2661         case NT_STATUS_SHARING_VIOLATION:
2662             return EBUSY;
2663         case NT_STATUS_OBJECT_PATH_INVALID:
2664             return ENOTDIR;
2665         case NT_STATUS_OBJECT_NAME_COLLISION:
2666             return EEXIST;
2667         }
2668 
2669         /* for all other cases - a default code */
2670         return EINVAL;
2671     }
2672 
2673     rcls = CVAL (cli->inbuf, smb_rcls);
2674     code = SVAL (cli->inbuf, smb_err);
2675     if (rcls == 0)
2676         return 0;
2677 
2678     if (eclass)
2679         *eclass = rcls;
2680     if (num)
2681         *num = code;
2682 
2683     if (rcls == ERRDOS)
2684     {
2685         switch (code)
2686         {
2687         case ERRbadfile:
2688             return ENOENT;
2689         case ERRbadpath:
2690             return ENOTDIR;
2691         case ERRnoaccess:
2692             return EACCES;
2693         case ERRfilexists:
2694             return EEXIST;
2695         case ERRrename:
2696             return EEXIST;
2697         case ERRbadshare:
2698             return EBUSY;
2699         case ERRlock:
2700             return EBUSY;
2701         }
2702     }
2703     if (rcls == ERRSRV)
2704     {
2705         switch (code)
2706         {
2707         case ERRbadpw:
2708             return EPERM;
2709         case ERRaccess:
2710             return EACCES;
2711         case ERRnoresource:
2712             return ENOMEM;
2713         case ERRinvdevice:
2714             return ENODEV;
2715         case ERRinvnetname:
2716             return ENODEV;
2717         }
2718     }
2719     /* for other cases */
2720     return EINVAL;
2721 }
2722 
2723 #if 0
2724 /****************************************************************************
2725 set socket options on a open connection
2726 ****************************************************************************/
2727 void
2728 cli_sockopt (struct cli_state *cli, char *options)
     /* [previous][next][first][last][top][bottom][index][help]  */
2729 {
2730     set_socket_options (cli->fd, options);
2731 }
2732 
2733 /****************************************************************************
2734 set the PID to use for smb messages. Return the old pid.
2735 ****************************************************************************/
2736 uint16
2737 cli_setpid (struct cli_state *cli, uint16 pid)
     /* [previous][next][first][last][top][bottom][index][help]  */
2738 {
2739     uint16 ret = cli->pid;
2740     cli->pid = pid;
2741     return ret;
2742 }
2743 #endif /* 0 */
2744 
2745 /****************************************************************************
2746 re-establishes a connection
2747 ****************************************************************************/
2748 BOOL
2749 cli_reestablish_connection (struct cli_state * cli)
     /* [previous][next][first][last][top][bottom][index][help]  */
2750 {
2751     struct nmb_name calling;
2752     struct nmb_name called;
2753     fstring dest_host;
2754     fstring share;
2755     fstring dev;
2756     BOOL do_tcon = False;
2757     int oldfd = cli->fd;
2758 
2759     if (!cli->initialised || cli->fd == -1)
2760     {
2761         DEBUG (3, ("cli_reestablish_connection: not connected\n"));
2762         return False;
2763     }
2764 
2765     /* copy the parameters necessary to re-establish the connection */
2766 
2767     if (cli->cnum != 0)
2768     {
2769         fstrcpy (share, cli->share);
2770         fstrcpy (dev, cli->dev);
2771         do_tcon = True;
2772     }
2773 
2774     memcpy (&called, &(cli->called), sizeof (called));
2775     memcpy (&calling, &(cli->calling), sizeof (calling));
2776     fstrcpy (dest_host, cli->full_dest_host_name);
2777 
2778     DEBUG (5, ("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2779                nmb_namestr (&calling), nmb_namestr (&called),
2780                inet_ntoa (cli->dest_ip), cli->user_name, cli->domain));
2781 
2782     cli->fd = -1;
2783 
2784     if (cli_establish_connection (cli,
2785                                   dest_host, &cli->dest_ip,
2786                                   &calling, &called, share, dev, False, do_tcon))
2787     {
2788         if (cli->fd != oldfd)
2789         {
2790             if (dup2 (cli->fd, oldfd) == oldfd)
2791             {
2792                 close (cli->fd);
2793             }
2794         }
2795         return True;
2796     }
2797     return False;
2798 }
2799 
2800 /****************************************************************************
2801 establishes a connection right up to doing tconX, reading in a password.
2802 ****************************************************************************/
2803 BOOL
2804 cli_establish_connection (struct cli_state * cli,
     /* [previous][next][first][last][top][bottom][index][help]  */
2805                           char *dest_host, struct in_addr * dest_ip,
2806                           struct nmb_name * calling, struct nmb_name * called,
2807                           char *service, char *service_type, BOOL do_shutdown, BOOL do_tcon)
2808 {
2809     DEBUG (5, ("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2810                nmb_namestr (calling), nmb_namestr (called), inet_ntoa (*dest_ip),
2811                cli->user_name, cli->domain));
2812 
2813     /* establish connection */
2814 
2815     if ((!cli->initialised))
2816     {
2817         return False;
2818     }
2819 
2820     if (cli->fd == -1)
2821     {
2822         if (!cli_connect (cli, dest_host, dest_ip))
2823         {
2824             DEBUG (1, ("cli_establish_connection: failed to connect to %s (%s)\n",
2825                        nmb_namestr (calling), inet_ntoa (*dest_ip)));
2826             return False;
2827         }
2828     }
2829 
2830     if (!cli_session_request (cli, calling, called))
2831     {
2832         DEBUG (1, ("failed session request\n"));
2833         if (do_shutdown)
2834             cli_shutdown (cli);
2835         return False;
2836     }
2837 
2838     if (!cli_negprot (cli))
2839     {
2840         DEBUG (1, ("failed negprot\n"));
2841         if (do_shutdown)
2842             cli_shutdown (cli);
2843         return False;
2844     }
2845 
2846     if (cli->pwd.cleartext || cli->pwd.null_pwd)
2847     {
2848         fstring passwd;
2849         int pass_len;
2850 
2851         if (cli->pwd.null_pwd)
2852         {
2853             /* attempt null session */
2854             passwd[0] = 0;
2855             pass_len = 1;
2856         }
2857         else
2858         {
2859             /* attempt clear-text session */
2860             pwd_get_cleartext (&(cli->pwd), passwd);
2861             pass_len = strlen (passwd);
2862         }
2863 
2864         /* attempt clear-text session */
2865         if (!cli_session_setup (cli, cli->user_name, passwd, pass_len, NULL, 0, cli->domain))
2866         {
2867             DEBUG (1, ("failed session setup\n"));
2868             if (do_shutdown)
2869             {
2870                 cli_shutdown (cli);
2871             }
2872             return False;
2873         }
2874         if (do_tcon)
2875         {
2876             if (!cli_send_tconX (cli, service, service_type, (char *) passwd, strlen (passwd)))
2877             {
2878                 DEBUG (1, ("failed tcon_X\n"));
2879                 if (do_shutdown)
2880                 {
2881                     cli_shutdown (cli);
2882                 }
2883                 return False;
2884             }
2885         }
2886     }
2887     else
2888     {
2889         /* attempt encrypted session */
2890         unsigned char nt_sess_pwd[24];
2891         unsigned char lm_sess_pwd[24];
2892 
2893         /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2894         pwd_make_lm_nt_owf (&(cli->pwd), cli->cryptkey);
2895         pwd_get_lm_nt_owf (&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2896 
2897         /* attempt encrypted session */
2898         if (!cli_session_setup (cli, cli->user_name,
2899                                 (char *) lm_sess_pwd, sizeof (lm_sess_pwd),
2900                                 (char *) nt_sess_pwd, sizeof (nt_sess_pwd), cli->domain))
2901         {
2902             DEBUG (1, ("failed session setup\n"));
2903             if (do_shutdown)
2904                 cli_shutdown (cli);
2905             return False;
2906         }
2907 
2908         if (do_tcon)
2909         {
2910             if (!cli_send_tconX (cli, service, service_type,
2911                                  (char *) nt_sess_pwd, sizeof (nt_sess_pwd)))
2912             {
2913                 DEBUG (1, ("failed tcon_X\n"));
2914                 if (do_shutdown)
2915                     cli_shutdown (cli);
2916                 return False;
2917             }
2918         }
2919     }
2920 
2921     if (do_shutdown)
2922         cli_shutdown (cli);
2923 
2924     return True;
2925 }
2926 
2927 
2928 /****************************************************************************
2929 check for existence of a dir
2930 ****************************************************************************/
2931 BOOL
2932 cli_chkpath (struct cli_state * cli, char *path)
     /* [previous][next][first][last][top][bottom][index][help]  */
2933 {
2934     pstring path2;
2935     char *p;
2936 
2937     safe_strcpy (path2, path, sizeof (pstring) - 1);
2938     trim_string (path2, NULL, "\\");
2939     if (!*path2)
2940         *path2 = '\\';
2941 
2942     memset (cli->outbuf, '\0', smb_size);
2943     set_message (cli->outbuf, 0, 4 + strlen (path2), True);
2944     SCVAL (cli->outbuf, smb_com, SMBchkpth);
2945     SSVAL (cli->outbuf, smb_tid, cli->cnum);
2946     cli_setup_packet (cli);
2947     p = smb_buf (cli->outbuf);
2948     *p++ = 4;
2949     safe_strcpy (p, path2, strlen (path2));
2950 
2951     cli_send_smb (cli);
2952     if (!cli_receive_smb (cli))
2953     {
2954         return False;
2955     }
2956 
2957     if (cli_error (cli, NULL, NULL, NULL))
2958         return False;
2959 
2960     return True;
2961 }
2962 
2963 #if 0
2964 /****************************************************************************
2965 start a message sequence
2966 ****************************************************************************/
2967 BOOL
2968 cli_message_start (struct cli_state * cli, char *host, char *username, int *grp)
     /* [previous][next][first][last][top][bottom][index][help]  */
2969 {
2970     char *p;
2971 
2972     /* send a SMBsendstrt command */
2973     memset (cli->outbuf, '\0', smb_size);
2974     set_message (cli->outbuf, 0, 0, True);
2975     CVAL (cli->outbuf, smb_com) = SMBsendstrt;
2976     SSVAL (cli->outbuf, smb_tid, cli->cnum);
2977     cli_setup_packet (cli);
2978 
2979     p = smb_buf (cli->outbuf);
2980     *p++ = 4;
2981     pstrcpy (p, username);
2982     p = skip_string (p, 1);
2983     *p++ = 4;
2984     pstrcpy (p, host);
2985     p = skip_string (p, 1);
2986 
2987     set_message (cli->outbuf, 0, PTR_DIFF (p, smb_buf (cli->outbuf)), False);
2988 
2989     cli_send_smb (cli);
2990 
2991     if (!cli_receive_smb (cli))
2992     {
2993         return False;
2994     }
2995 
2996     if (cli_error (cli, NULL, NULL, NULL))
2997         return False;
2998 
2999     *grp = SVAL (cli->inbuf, smb_vwv0);
3000 
3001     return True;
3002 }
3003 
3004 
3005 /****************************************************************************
3006 send a message 
3007 ****************************************************************************/
3008 BOOL
3009 cli_message_text (struct cli_state * cli, char *msg, int len, int grp)
     /* [previous][next][first][last][top][bottom][index][help]  */
3010 {
3011     char *p;
3012 
3013     memset (cli->outbuf, '\0', smb_size);
3014     set_message (cli->outbuf, 1, len + 3, True);
3015     CVAL (cli->outbuf, smb_com) = SMBsendtxt;
3016     SSVAL (cli->outbuf, smb_tid, cli->cnum);
3017     cli_setup_packet (cli);
3018 
3019     SSVAL (cli->outbuf, smb_vwv0, grp);
3020 
3021     p = smb_buf (cli->outbuf);
3022     *p = 1;
3023     SSVAL (p, 1, len);
3024     memcpy (p + 3, msg, len);
3025     cli_send_smb (cli);
3026 
3027     if (!cli_receive_smb (cli))
3028     {
3029         return False;
3030     }
3031 
3032     if (cli_error (cli, NULL, NULL, NULL))
3033         return False;
3034 
3035     return True;
3036 }
3037 
3038 /****************************************************************************
3039 end a message 
3040 ****************************************************************************/
3041 BOOL
3042 cli_message_end (struct cli_state * cli, int grp)
     /* [previous][next][first][last][top][bottom][index][help]  */
3043 {
3044     memset (cli->outbuf, '\0', smb_size);
3045     set_message (cli->outbuf, 1, 0, True);
3046     CVAL (cli->outbuf, smb_com) = SMBsendend;
3047     SSVAL (cli->outbuf, smb_tid, cli->cnum);
3048 
3049     SSVAL (cli->outbuf, smb_vwv0, grp);
3050 
3051     cli_setup_packet (cli);
3052 
3053     cli_send_smb (cli);
3054 
3055     if (!cli_receive_smb (cli))
3056     {
3057         return False;
3058     }
3059 
3060     if (cli_error (cli, NULL, NULL, NULL))
3061         return False;
3062 
3063     return True;
3064 }
3065 #endif /*0 */
3066 
3067 #if 0                           /* May be useful one day */
3068 /****************************************************************************
3069 query disk space
3070 ****************************************************************************/
3071 BOOL
3072 cli_dskattr (struct cli_state * cli, int *bsize, int *total, int *avail)
     /* [previous][next][first][last][top][bottom][index][help]  */
3073 {
3074     memset (cli->outbuf, '\0', smb_size);
3075     set_message (cli->outbuf, 0, 0, True);
3076     CVAL (cli->outbuf, smb_com) = SMBdskattr;
3077     SSVAL (cli->outbuf, smb_tid, cli->cnum);
3078     cli_setup_packet (cli);
3079 
3080     cli_send_smb (cli);
3081     if (!cli_receive_smb (cli))
3082     {
3083         return False;
3084     }
3085 
3086     *bsize = SVAL (cli->inbuf, smb_vwv1) * SVAL (cli->inbuf, smb_vwv2);
3087     *total = SVAL (cli->inbuf, smb_vwv0);
3088     *avail = SVAL (cli->inbuf, smb_vwv3);
3089 
3090     return True;
3091 }
3092 #endif /* 0 */

/* [previous][next][first][last][top][bottom][index][help]  */