root/source3/libsmb/clirap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cli_api
  2. cli_NetWkstaUserLogon
  3. cli_RNetShareEnum
  4. cli_NetServerEnum
  5. cli_oem_change_password
  6. cli_qpathinfo
  7. cli_setpathinfo
  8. cli_qpathinfo2
  9. cli_qpathinfo_streams
  10. cli_qfilename
  11. cli_qfileinfo
  12. cli_qpathinfo_basic
  13. cli_qfileinfo_test
  14. cli_qpathinfo_alt_name

   1 /*
   2    Unix SMB/CIFS implementation.
   3    client RAP calls
   4    Copyright (C) Andrew Tridgell         1994-1998
   5    Copyright (C) Gerald (Jerry) Carter   2004
   6    Copyright (C) James Peach             2007
   7 
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12 
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17 
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 
  24 /****************************************************************************
  25  Call a remote api
  26 ****************************************************************************/
  27 
  28 bool cli_api(struct cli_state *cli,
     /* [<][>][^][v][top][bottom][index][help] */
  29              char *param, int prcnt, int mprcnt,
  30              char *data, int drcnt, int mdrcnt,
  31              char **rparam, unsigned int *rprcnt,
  32              char **rdata, unsigned int *rdrcnt)
  33 {
  34         cli_send_trans(cli,SMBtrans,
  35                  PIPE_LANMAN,             /* Name */
  36                  0,0,                     /* fid, flags */
  37                  NULL,0,0,                /* Setup, length, max */
  38                  param, prcnt, mprcnt,    /* Params, length, max */
  39                  data, drcnt, mdrcnt      /* Data, length, max */
  40                 );
  41 
  42         return (cli_receive_trans(cli,SMBtrans,
  43                             rparam, rprcnt,
  44                             rdata, rdrcnt));
  45 }
  46 
  47 /****************************************************************************
  48  Perform a NetWkstaUserLogon.
  49 ****************************************************************************/
  50 
  51 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
     /* [<][>][^][v][top][bottom][index][help] */
  52 {
  53         char *rparam = NULL;
  54         char *rdata = NULL;
  55         char *p;
  56         unsigned int rdrcnt,rprcnt;
  57         char param[1024];
  58 
  59         memset(param, 0, sizeof(param));
  60 
  61         /* send a SMBtrans command with api NetWkstaUserLogon */
  62         p = param;
  63         SSVAL(p,0,132); /* api number */
  64         p += 2;
  65         strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
  66         p = skip_string(param,sizeof(param),p);
  67         strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
  68         p = skip_string(param,sizeof(param),p);
  69         SSVAL(p,0,1);
  70         p += 2;
  71         strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
  72         strupper_m(p);
  73         p += 21;
  74         p++;
  75         p += 15;
  76         p++;
  77         strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
  78         strupper_m(p);
  79         p += 16;
  80         SSVAL(p, 0, CLI_BUFFER_SIZE);
  81         p += 2;
  82         SSVAL(p, 0, CLI_BUFFER_SIZE);
  83         p += 2;
  84 
  85         if (cli_api(cli,
  86                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
  87                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
  88                     &rparam, &rprcnt,               /* return params, return size */
  89                     &rdata, &rdrcnt                 /* return data, return size */
  90                    )) {
  91                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
  92                 p = rdata;
  93 
  94                 if (cli->rap_error == 0) {
  95                         DEBUG(4,("NetWkstaUserLogon success\n"));
  96                         cli->privileges = SVAL(p, 24);
  97                         /* The cli->eff_name field used to be set here
  98                            but it wasn't used anywhere else. */
  99                 } else {
 100                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
 101                 }
 102         }
 103 
 104         SAFE_FREE(rparam);
 105         SAFE_FREE(rdata);
 106         return (cli->rap_error == 0);
 107 }
 108 
 109 /****************************************************************************
 110  Call a NetShareEnum - try and browse available connections on a host.
 111 ****************************************************************************/
 112 
 113 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
     /* [<][>][^][v][top][bottom][index][help] */
 114 {
 115         char *rparam = NULL;
 116         char *rdata = NULL;
 117         char *p;
 118         unsigned int rdrcnt,rprcnt;
 119         char param[1024];
 120         int count = -1;
 121 
 122         /* now send a SMBtrans command with api RNetShareEnum */
 123         p = param;
 124         SSVAL(p,0,0); /* api number */
 125         p += 2;
 126         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
 127         p = skip_string(param,sizeof(param),p);
 128         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
 129         p = skip_string(param,sizeof(param),p);
 130         SSVAL(p,0,1);
 131         /*
 132          * Win2k needs a *smaller* buffer than 0xFFFF here -
 133          * it returns "out of server memory" with 0xFFFF !!! JRA.
 134          */
 135         SSVAL(p,2,0xFFE0);
 136         p += 4;
 137 
 138         if (cli_api(cli,
 139                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
 140                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
 141                     &rparam, &rprcnt,                /* return params, length */
 142                     &rdata, &rdrcnt))                /* return data, length */
 143                 {
 144                         int res = rparam? SVAL(rparam,0) : -1;
 145 
 146                         if (res == 0 || res == ERRmoredata) {
 147                                 int converter=SVAL(rparam,2);
 148                                 int i;
 149                                 char *rdata_end = rdata + rdrcnt;
 150 
 151                                 count=SVAL(rparam,4);
 152                                 p = rdata;
 153 
 154                                 for (i=0;i<count;i++,p+=20) {
 155                                         char *sname;
 156                                         int type;
 157                                         int comment_offset;
 158                                         const char *cmnt;
 159                                         const char *p1;
 160                                         char *s1, *s2;
 161                                         size_t len;
 162                                         TALLOC_CTX *frame = talloc_stackframe();
 163 
 164                                         if (p + 20 > rdata_end) {
 165                                                 TALLOC_FREE(frame);
 166                                                 break;
 167                                         }
 168 
 169                                         sname = p;
 170                                         type = SVAL(p,14);
 171                                         comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
 172                                         if (comment_offset < 0 ||
 173                                                         comment_offset > (int)rdrcnt) {
 174                                                 TALLOC_FREE(frame);
 175                                                 break;
 176                                         }
 177                                         cmnt = comment_offset?(rdata+comment_offset):"";
 178 
 179                                         /* Work out the comment length. */
 180                                         for (p1 = cmnt, len = 0; *p1 &&
 181                                                         p1 < rdata_end; len++)
 182                                                 p1++;
 183                                         if (!*p1) {
 184                                                 len++;
 185                                         }
 186                                         pull_string_talloc(frame,rdata,0,
 187                                                 &s1,sname,14,STR_ASCII);
 188                                         pull_string_talloc(frame,rdata,0,
 189                                                 &s2,cmnt,len,STR_ASCII);
 190                                         if (!s1 || !s2) {
 191                                                 TALLOC_FREE(frame);
 192                                                 continue;
 193                                         }
 194 
 195                                         fn(s1, type, s2, state);
 196 
 197                                         TALLOC_FREE(frame);
 198                                 }
 199                         } else {
 200                                 DEBUG(4,("NetShareEnum res=%d\n", res));
 201                         }
 202                 } else {
 203                         DEBUG(4,("NetShareEnum failed\n"));
 204                 }
 205 
 206         SAFE_FREE(rparam);
 207         SAFE_FREE(rdata);
 208 
 209         return count;
 210 }
 211 
 212 /****************************************************************************
 213  Call a NetServerEnum for the specified workgroup and servertype mask.  This
 214  function then calls the specified callback function for each name returned.
 215 
 216  The callback function takes 4 arguments: the machine name, the server type,
 217  the comment and a state pointer.
 218 ****************************************************************************/
 219 
 220 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
     /* [<][>][^][v][top][bottom][index][help] */
 221                        void (*fn)(const char *, uint32, const char *, void *),
 222                        void *state)
 223 {
 224         char *rparam = NULL;
 225         char *rdata = NULL;
 226         char *rdata_end = NULL;
 227         unsigned int rdrcnt,rprcnt;
 228         char *p;
 229         char param[1024];
 230         int uLevel = 1;
 231         size_t len;
 232         uint32 func = RAP_NetServerEnum2;
 233         char *last_entry = NULL;
 234         int total_cnt = 0;
 235         int return_cnt = 0;
 236         int res;
 237 
 238         errno = 0; /* reset */
 239 
 240         /*
 241          * This may take more than one transaction, so we should loop until
 242          * we no longer get a more data to process or we have all of the
 243          * items.
 244          */
 245         do {
 246                 /* send a SMBtrans command with api NetServerEnum */
 247                 p = param;
 248                 SIVAL(p,0,func); /* api number */
 249                 p += 2;
 250                 /* Next time through we need to use the continue api */
 251                 func = RAP_NetServerEnum3;
 252 
 253                 if (last_entry) {
 254                         strlcpy(p,"WrLehDOz", sizeof(param)-PTR_DIFF(p,param));
 255                 } else {
 256                         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
 257                 }
 258 
 259                 p = skip_string(param, sizeof(param), p);
 260                 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
 261 
 262                 p = skip_string(param, sizeof(param), p);
 263                 SSVAL(p,0,uLevel);
 264                 SSVAL(p,2,CLI_BUFFER_SIZE);
 265                 p += 4;
 266                 SIVAL(p,0,stype);
 267                 p += 4;
 268 
 269                 /* If we have more data, tell the server where
 270                  * to continue from.
 271                  */
 272                 len = push_ascii(p,
 273                                 last_entry ? last_entry : workgroup,
 274                                 sizeof(param) - PTR_DIFF(p,param) - 1,
 275                                 STR_TERMINATE|STR_UPPER);
 276 
 277                 if (len == (size_t)-1) {
 278                         SAFE_FREE(last_entry);
 279                         return false;
 280                 }
 281                 p += len;
 282 
 283                 if (!cli_api(cli,
 284                         param, PTR_DIFF(p,param), 8, /* params, length, max */
 285                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
 286                             &rparam, &rprcnt, /* return params, return size */
 287                             &rdata, &rdrcnt)) { /* return data, return size */
 288 
 289                         /* break out of the loop on error */
 290                         res = -1;
 291                         break;
 292                 }
 293 
 294                 rdata_end = rdata + rdrcnt;
 295                 res = rparam ? SVAL(rparam,0) : -1;
 296 
 297                 if (res == 0 || res == ERRmoredata ||
 298                     (res != -1 && cli_errno(cli) == 0)) {
 299                         char *sname = NULL;
 300                         int i, count;
 301                         int converter=SVAL(rparam,2);
 302 
 303                         /* Get the number of items returned in this buffer */
 304                         count = SVAL(rparam, 4);
 305 
 306                         /* The next field contains the number of items left,
 307                          * including those returned in this buffer. So the
 308                          * first time through this should contain all of the
 309                          * entries.
 310                          */
 311                         if (total_cnt == 0) {
 312                                 total_cnt = SVAL(rparam, 6);
 313                         }
 314 
 315                         /* Keep track of how many we have read */
 316                         return_cnt += count;
 317                         p = rdata;
 318 
 319                         /* The last name in the previous NetServerEnum reply is
 320                          * sent back to server in the NetServerEnum3 request
 321                          * (last_entry). The next reply should repeat this entry
 322                          * as the first element. We have no proof that this is
 323                          * always true, but from traces that seems to be the
 324                          * behavior from Window Servers. So first lets do a lot
 325                          * of checking, just being paranoid. If the string
 326                          * matches then we already saw this entry so skip it.
 327                          *
 328                          * NOTE: sv1_name field must be null terminated and has
 329                          * a max size of 16 (NetBIOS Name).
 330                          */
 331                         if (last_entry && count && p &&
 332                                 (strncmp(last_entry, p, 16) == 0)) {
 333                             count -= 1; /* Skip this entry */
 334                             return_cnt = -1; /* Not part of total, so don't count. */
 335                             p = rdata + 26; /* Skip the whole record */
 336                         }
 337 
 338                         for (i = 0; i < count; i++, p += 26) {
 339                                 int comment_offset;
 340                                 const char *cmnt;
 341                                 const char *p1;
 342                                 char *s1, *s2;
 343                                 TALLOC_CTX *frame = talloc_stackframe();
 344 
 345                                 if (p + 26 > rdata_end) {
 346                                         TALLOC_FREE(frame);
 347                                         break;
 348                                 }
 349 
 350                                 sname = p;
 351                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
 352                                 cmnt = comment_offset?(rdata+comment_offset):"";
 353 
 354                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
 355                                         TALLOC_FREE(frame);
 356                                         continue;
 357                                 }
 358 
 359                                 /* Work out the comment length. */
 360                                 for (p1 = cmnt, len = 0; *p1 &&
 361                                                 p1 < rdata_end; len++)
 362                                         p1++;
 363                                 if (!*p1) {
 364                                         len++;
 365                                 }
 366 
 367                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
 368 
 369                                 pull_string_talloc(frame,rdata,0,
 370                                         &s1,sname,16,STR_ASCII);
 371                                 pull_string_talloc(frame,rdata,0,
 372                                         &s2,cmnt,len,STR_ASCII);
 373 
 374                                 if (!s1 || !s2) {
 375                                         TALLOC_FREE(frame);
 376                                         continue;
 377                                 }
 378 
 379                                 fn(s1, stype, s2, state);
 380                                 TALLOC_FREE(frame);
 381                         }
 382 
 383                         /* We are done with the old last entry, so now we can free it */
 384                         if (last_entry) {
 385                                 SAFE_FREE(last_entry); /* This will set it to null */
 386                         }
 387 
 388                         /* We always make a copy of  the last entry if we have one */
 389                         if (sname) {
 390                                 last_entry = smb_xstrdup(sname);
 391                         }
 392 
 393                         /* If we have more data, but no last entry then error out */
 394                         if (!last_entry && (res == ERRmoredata)) {
 395                                 errno = EINVAL;
 396                                 res = 0;
 397                         }
 398 
 399                 }
 400 
 401                 SAFE_FREE(rparam);
 402                 SAFE_FREE(rdata);
 403         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
 404 
 405         SAFE_FREE(rparam);
 406         SAFE_FREE(rdata);
 407         SAFE_FREE(last_entry);
 408 
 409         if (res == -1) {
 410                 errno = cli_errno(cli);
 411         } else {
 412                 if (!return_cnt) {
 413                         /* this is a very special case, when the domain master for the
 414                            work group isn't part of the work group itself, there is something
 415                            wild going on */
 416                         errno = ENOENT;
 417                 }
 418             }
 419 
 420         return(return_cnt > 0);
 421 }
 422 
 423 /****************************************************************************
 424  Send a SamOEMChangePassword command.
 425 ****************************************************************************/
 426 
 427 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
     /* [<][>][^][v][top][bottom][index][help] */
 428                              const char *old_password)
 429 {
 430         char param[1024];
 431         unsigned char data[532];
 432         char *p = param;
 433         unsigned char old_pw_hash[16];
 434         unsigned char new_pw_hash[16];
 435         unsigned int data_len;
 436         unsigned int param_len = 0;
 437         char *rparam = NULL;
 438         char *rdata = NULL;
 439         unsigned int rprcnt, rdrcnt;
 440 
 441         if (strlen(user) >= sizeof(fstring)-1) {
 442                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
 443                 return False;
 444         }
 445 
 446         SSVAL(p,0,214); /* SamOEMChangePassword command. */
 447         p += 2;
 448         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
 449         p = skip_string(param,sizeof(param),p);
 450         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
 451         p = skip_string(param,sizeof(param),p);
 452         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
 453         p = skip_string(param,sizeof(param),p);
 454         SSVAL(p,0,532);
 455         p += 2;
 456 
 457         param_len = PTR_DIFF(p,param);
 458 
 459         /*
 460          * Get the Lanman hash of the old password, we
 461          * use this as the key to make_oem_passwd_hash().
 462          */
 463         E_deshash(old_password, old_pw_hash);
 464 
 465         encode_pw_buffer(data, new_password, STR_ASCII);
 466 
 467 #ifdef DEBUG_PASSWORD
 468         DEBUG(100,("make_oem_passwd_hash\n"));
 469         dump_data(100, data, 516);
 470 #endif
 471         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
 472 
 473         /*
 474          * Now place the old password hash in the data.
 475          */
 476         E_deshash(new_password, new_pw_hash);
 477 
 478         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
 479 
 480         data_len = 532;
 481 
 482         if (cli_send_trans(cli,SMBtrans,
 483                     PIPE_LANMAN,                          /* name */
 484                     0,0,                                  /* fid, flags */
 485                     NULL,0,0,                             /* setup, length, max */
 486                     param,param_len,2,                    /* param, length, max */
 487                     (char *)data,data_len,0                       /* data, length, max */
 488                    ) == False) {
 489                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
 490                         user ));
 491                 return False;
 492         }
 493 
 494         if (!cli_receive_trans(cli,SMBtrans,
 495                        &rparam, &rprcnt,
 496                        &rdata, &rdrcnt)) {
 497                 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
 498                         user ));
 499                 return False;
 500         }
 501 
 502         if (rparam) {
 503                 cli->rap_error = SVAL(rparam,0);
 504         }
 505 
 506         SAFE_FREE(rparam);
 507         SAFE_FREE(rdata);
 508 
 509         return (cli->rap_error == 0);
 510 }
 511 
 512 /****************************************************************************
 513  Send a qpathinfo call.
 514 ****************************************************************************/
 515 
 516 bool cli_qpathinfo(struct cli_state *cli,
     /* [<][>][^][v][top][bottom][index][help] */
 517                         const char *fname,
 518                         time_t *change_time,
 519                         time_t *access_time,
 520                         time_t *write_time,
 521                         SMB_OFF_T *size,
 522                         uint16 *mode)
 523 {
 524         unsigned int data_len = 0;
 525         unsigned int param_len = 0;
 526         unsigned int rparam_len, rdata_len;
 527         uint16 setup = TRANSACT2_QPATHINFO;
 528         char *param;
 529         char *rparam=NULL, *rdata=NULL;
 530         int count=8;
 531         bool ret;
 532         time_t (*date_fn)(struct cli_state *, const void *);
 533         char *p;
 534         size_t nlen = 2*(strlen(fname)+1);
 535 
 536         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
 537         if (!param) {
 538                 return false;
 539         }
 540         p = param;
 541         memset(p, '\0', 6);
 542         SSVAL(p, 0, SMB_INFO_STANDARD);
 543         p += 6;
 544         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
 545         param_len = PTR_DIFF(p, param);
 546 
 547         do {
 548                 ret = (cli_send_trans(cli, SMBtrans2,
 549                                       NULL,           /* Name */
 550                                       -1, 0,          /* fid, flags */
 551                                       &setup, 1, 0,   /* setup, length, max */
 552                                       param, param_len, 10, /* param, length, max */
 553                                       NULL, data_len, cli->max_xmit /* data, length, max */
 554                                       ) &&
 555                        cli_receive_trans(cli, SMBtrans2,
 556                                          &rparam, &rparam_len,
 557                                          &rdata, &rdata_len));
 558                 if (!cli_is_dos_error(cli)) break;
 559                 if (!ret) {
 560                         /* we need to work around a Win95 bug - sometimes
 561                            it gives ERRSRV/ERRerror temprarily */
 562                         uint8 eclass;
 563                         uint32 ecode;
 564                         cli_dos_error(cli, &eclass, &ecode);
 565                         if (eclass != ERRSRV || ecode != ERRerror) break;
 566                         smb_msleep(100);
 567                 }
 568         } while (count-- && ret==False);
 569 
 570         SAFE_FREE(param);
 571         if (!ret || !rdata || rdata_len < 22) {
 572                 return False;
 573         }
 574 
 575         if (cli->win95) {
 576                 date_fn = cli_make_unix_date;
 577         } else {
 578                 date_fn = cli_make_unix_date2;
 579         }
 580 
 581         if (change_time) {
 582                 *change_time = date_fn(cli, rdata+0);
 583         }
 584         if (access_time) {
 585                 *access_time = date_fn(cli, rdata+4);
 586         }
 587         if (write_time) {
 588                 *write_time = date_fn(cli, rdata+8);
 589         }
 590         if (size) {
 591                 *size = IVAL(rdata, 12);
 592         }
 593         if (mode) {
 594                 *mode = SVAL(rdata,l1_attrFile);
 595         }
 596 
 597         SAFE_FREE(rdata);
 598         SAFE_FREE(rparam);
 599         return True;
 600 }
 601 
 602 /****************************************************************************
 603  Send a setpathinfo call.
 604 ****************************************************************************/
 605 
 606 bool cli_setpathinfo(struct cli_state *cli, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 607                      time_t create_time,
 608                      time_t access_time,
 609                      time_t write_time,
 610                      time_t change_time,
 611                      uint16 mode)
 612 {
 613         unsigned int data_len = 0;
 614         unsigned int param_len = 0;
 615         unsigned int rparam_len, rdata_len;
 616         uint16 setup = TRANSACT2_SETPATHINFO;
 617         char *param;
 618         char data[40];
 619         char *rparam=NULL, *rdata=NULL;
 620         int count=8;
 621         bool ret;
 622         char *p;
 623         size_t nlen = 2*(strlen(fname)+1);
 624 
 625         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
 626         if (!param) {
 627                 return false;
 628         }
 629         memset(param, '\0', 6);
 630         memset(data, 0, sizeof(data));
 631 
 632         p = param;
 633 
 634         /* Add the information level */
 635         SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
 636 
 637         /* Skip reserved */
 638         p += 6;
 639 
 640         /* Add the file name */
 641         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
 642 
 643         param_len = PTR_DIFF(p, param);
 644 
 645         p = data;
 646 
 647         /*
 648          * Add the create, last access, modification, and status change times
 649          */
 650         put_long_date(p, create_time);
 651         p += 8;
 652 
 653         put_long_date(p, access_time);
 654         p += 8;
 655 
 656         put_long_date(p, write_time);
 657         p += 8;
 658 
 659         put_long_date(p, change_time);
 660         p += 8;
 661 
 662         /* Add attributes */
 663         SIVAL(p, 0, mode);
 664         p += 4;
 665 
 666         /* Add padding */
 667         SIVAL(p, 0, 0);
 668         p += 4;
 669 
 670         data_len = PTR_DIFF(p, data);
 671 
 672         do {
 673                 ret = (cli_send_trans(cli, SMBtrans2,
 674                                       NULL,           /* Name */
 675                                       -1, 0,          /* fid, flags */
 676                                       &setup, 1, 0,   /* setup, length, max */
 677                                       param, param_len, 10, /* param, length, max */
 678                                       data, data_len, cli->max_xmit /* data, length, max */
 679                                       ) &&
 680                        cli_receive_trans(cli, SMBtrans2,
 681                                          &rparam, &rparam_len,
 682                                          &rdata, &rdata_len));
 683                 if (!cli_is_dos_error(cli)) break;
 684                 if (!ret) {
 685                         /* we need to work around a Win95 bug - sometimes
 686                            it gives ERRSRV/ERRerror temprarily */
 687                         uint8 eclass;
 688                         uint32 ecode;
 689                         cli_dos_error(cli, &eclass, &ecode);
 690                         if (eclass != ERRSRV || ecode != ERRerror) break;
 691                         smb_msleep(100);
 692                 }
 693         } while (count-- && ret==False);
 694 
 695         SAFE_FREE(param);
 696         if (!ret) {
 697                 return False;
 698         }
 699 
 700         SAFE_FREE(rdata);
 701         SAFE_FREE(rparam);
 702         return True;
 703 }
 704 
 705 /****************************************************************************
 706  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
 707 ****************************************************************************/
 708 
 709 bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 710                     struct timespec *create_time,
 711                     struct timespec *access_time,
 712                     struct timespec *write_time,
 713                     struct timespec *change_time,
 714                     SMB_OFF_T *size, uint16 *mode,
 715                     SMB_INO_T *ino)
 716 {
 717         unsigned int data_len = 0;
 718         unsigned int param_len = 0;
 719         uint16 setup = TRANSACT2_QPATHINFO;
 720         char *param;
 721         char *rparam=NULL, *rdata=NULL;
 722         char *p;
 723         size_t nlen = 2*(strlen(fname)+1);
 724 
 725         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
 726         if (!param) {
 727                 return false;
 728         }
 729         p = param;
 730         memset(param, '\0', 6);
 731         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
 732         p += 6;
 733         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
 734 
 735         param_len = PTR_DIFF(p, param);
 736 
 737         if (!cli_send_trans(cli, SMBtrans2,
 738                             NULL,                         /* name */
 739                             -1, 0,                        /* fid, flags */
 740                             &setup, 1, 0,                 /* setup, length, max */
 741                             param, param_len, 10,         /* param, length, max */
 742                             NULL, data_len, cli->max_xmit /* data, length, max */
 743                            )) {
 744                 SAFE_FREE(param);
 745                 return False;
 746         }
 747 
 748         SAFE_FREE(param);
 749         if (!cli_receive_trans(cli, SMBtrans2,
 750                                &rparam, &param_len,
 751                                &rdata, &data_len)) {
 752                 return False;
 753         }
 754 
 755         if (!rdata || data_len < 22) {
 756                 return False;
 757         }
 758 
 759         if (create_time) {
 760                 *create_time = interpret_long_date(rdata+0);
 761         }
 762         if (access_time) {
 763                 *access_time = interpret_long_date(rdata+8);
 764         }
 765         if (write_time) {
 766                 *write_time = interpret_long_date(rdata+16);
 767         }
 768         if (change_time) {
 769                 *change_time = interpret_long_date(rdata+24);
 770         }
 771         if (mode) {
 772                 *mode = SVAL(rdata, 32);
 773         }
 774         if (size) {
 775                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
 776         }
 777         if (ino) {
 778                 *ino = IVAL(rdata, 64);
 779         }
 780 
 781         SAFE_FREE(rdata);
 782         SAFE_FREE(rparam);
 783         return True;
 784 }
 785 
 786 /****************************************************************************
 787  Get the stream info
 788 ****************************************************************************/
 789 
 790 bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
     /* [<][>][^][v][top][bottom][index][help] */
 791                            TALLOC_CTX *mem_ctx,
 792                            unsigned int *pnum_streams,
 793                            struct stream_struct **pstreams)
 794 {
 795         unsigned int data_len = 0;
 796         unsigned int param_len = 0;
 797         uint16 setup = TRANSACT2_QPATHINFO;
 798         char *param;
 799         char *rparam=NULL, *rdata=NULL;
 800         char *p;
 801         unsigned int num_streams;
 802         struct stream_struct *streams;
 803         unsigned int ofs;
 804         size_t namelen = 2*(strlen(fname)+1);
 805 
 806         param = SMB_MALLOC_ARRAY(char, 6+namelen+2);
 807         if (param == NULL) {
 808                 return false;
 809         }
 810         p = param;
 811         memset(p, 0, 6);
 812         SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION);
 813         p += 6;
 814         p += clistr_push(cli, p, fname, namelen, STR_TERMINATE);
 815 
 816         param_len = PTR_DIFF(p, param);
 817 
 818         if (!cli_send_trans(cli, SMBtrans2,
 819                             NULL,                     /* name */
 820                             -1, 0,                    /* fid, flags */
 821                             &setup, 1, 0,             /* setup, len, max */
 822                             param, param_len, 10,     /* param, len, max */
 823                             NULL, data_len, cli->max_xmit /* data, len, max */
 824                            )) {
 825                 return false;
 826         }
 827 
 828         if (!cli_receive_trans(cli, SMBtrans2,
 829                                &rparam, &param_len,
 830                                &rdata, &data_len)) {
 831                 return false;
 832         }
 833 
 834         if (!rdata) {
 835                 SAFE_FREE(rparam);
 836                 return false;
 837         }
 838 
 839         num_streams = 0;
 840         streams = NULL;
 841         ofs = 0;
 842 
 843         while ((data_len > ofs) && (data_len - ofs >= 24)) {
 844                 uint32_t nlen, len;
 845                 size_t size;
 846                 void *vstr;
 847                 struct stream_struct *tmp;
 848                 uint8_t *tmp_buf;
 849 
 850                 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
 851                                            struct stream_struct,
 852                                            num_streams+1);
 853 
 854                 if (tmp == NULL) {
 855                         goto fail;
 856                 }
 857                 streams = tmp;
 858 
 859                 nlen                      = IVAL(rdata, ofs + 0x04);
 860 
 861                 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
 862                         rdata, ofs + 0x08);
 863                 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
 864                         rdata, ofs + 0x10);
 865 
 866                 if (nlen > data_len - (ofs + 24)) {
 867                         goto fail;
 868                 }
 869 
 870                 /*
 871                  * We need to null-terminate src, how do I do this with
 872                  * convert_string_talloc??
 873                  */
 874 
 875                 tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
 876                 if (tmp_buf == NULL) {
 877                         goto fail;
 878                 }
 879 
 880                 memcpy(tmp_buf, rdata+ofs+24, nlen);
 881                 tmp_buf[nlen] = 0;
 882                 tmp_buf[nlen+1] = 0;
 883 
 884                 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
 885                                            nlen+2, &vstr, &size, false))
 886                 {
 887                         TALLOC_FREE(tmp_buf);
 888                         goto fail;
 889                 }
 890 
 891                 TALLOC_FREE(tmp_buf);
 892                 streams[num_streams].name = (char *)vstr;
 893                 num_streams++;
 894 
 895                 len = IVAL(rdata, ofs);
 896                 if (len > data_len - ofs) {
 897                         goto fail;
 898                 }
 899                 if (len == 0) break;
 900                 ofs += len;
 901         }
 902 
 903         SAFE_FREE(rdata);
 904         SAFE_FREE(rparam);
 905 
 906         *pnum_streams = num_streams;
 907         *pstreams = streams;
 908         return true;
 909 
 910  fail:
 911         TALLOC_FREE(streams);
 912         SAFE_FREE(rdata);
 913         SAFE_FREE(rparam);
 914         return false;
 915 }
 916 
 917 /****************************************************************************
 918  Send a qfileinfo QUERY_FILE_NAME_INFO call.
 919 ****************************************************************************/
 920 
 921 bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen)
     /* [<][>][^][v][top][bottom][index][help] */
 922 {
 923         unsigned int data_len = 0;
 924         unsigned int param_len = 0;
 925         uint16 setup = TRANSACT2_QFILEINFO;
 926         char param[4];
 927         char *rparam=NULL, *rdata=NULL;
 928 
 929         param_len = 4;
 930         SSVAL(param, 0, fnum);
 931         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
 932 
 933         if (!cli_send_trans(cli, SMBtrans2,
 934                             NULL,                         /* name */
 935                             -1, 0,                        /* fid, flags */
 936                             &setup, 1, 0,                 /* setup, length, max */
 937                             param, param_len, 2,          /* param, length, max */
 938                             NULL, data_len, cli->max_xmit /* data, length, max */
 939                            )) {
 940                 return False;
 941         }
 942 
 943         if (!cli_receive_trans(cli, SMBtrans2,
 944                                &rparam, &param_len,
 945                                &rdata, &data_len)) {
 946                 return False;
 947         }
 948 
 949         if (!rdata || data_len < 4) {
 950                 SAFE_FREE(rparam);
 951                 SAFE_FREE(rdata);
 952                 return False;
 953         }
 954 
 955         clistr_pull(cli->inbuf, name, rdata+4, namelen, IVAL(rdata, 0),
 956                     STR_UNICODE);
 957 
 958         SAFE_FREE(rparam);
 959         SAFE_FREE(rdata);
 960 
 961         return True;
 962 }
 963 
 964 /****************************************************************************
 965  Send a qfileinfo call.
 966 ****************************************************************************/
 967 
 968 bool cli_qfileinfo(struct cli_state *cli, int fnum,
     /* [<][>][^][v][top][bottom][index][help] */
 969                    uint16 *mode, SMB_OFF_T *size,
 970                    struct timespec *create_time,
 971                    struct timespec *access_time,
 972                    struct timespec *write_time,
 973                    struct timespec *change_time,
 974                    SMB_INO_T *ino)
 975 {
 976         unsigned int data_len = 0;
 977         unsigned int param_len = 0;
 978         uint16 setup;
 979         uint8_t param[4];
 980         uint8_t *rparam=NULL, *rdata=NULL;
 981         NTSTATUS status;
 982 
 983         /* if its a win95 server then fail this - win95 totally screws it
 984            up */
 985         if (cli->win95) return False;
 986 
 987         param_len = 4;
 988 
 989         SSVAL(param, 0, fnum);
 990         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
 991 
 992         SSVAL(&setup, 0, TRANSACT2_QFILEINFO);
 993 
 994         status = cli_trans(talloc_tos(), cli, SMBtrans2,
 995                            NULL, -1, 0, 0, /* name, fid, function, flags */
 996                            &setup, 1, 0,          /* setup, length, max */
 997                            param, param_len, 2,   /* param, length, max */
 998                            NULL, 0, MIN(cli->max_xmit, 0xffff), /* data, length, max */
 999                            NULL, NULL, /* rsetup, length */
1000                            &rparam, &param_len, /* rparam, length */
1001                            &rdata, &data_len);
1002 
1003         if (!NT_STATUS_IS_OK(status)) {
1004                 return false;
1005         }
1006 
1007         if (!rdata || data_len < 68) {
1008                 return False;
1009         }
1010 
1011         if (create_time) {
1012                 *create_time = interpret_long_date((char *)rdata+0);
1013         }
1014         if (access_time) {
1015                 *access_time = interpret_long_date((char *)rdata+8);
1016         }
1017         if (write_time) {
1018                 *write_time = interpret_long_date((char *)rdata+16);
1019         }
1020         if (change_time) {
1021                 *change_time = interpret_long_date((char *)rdata+24);
1022         }
1023         if (mode) {
1024                 *mode = SVAL(rdata, 32);
1025         }
1026         if (size) {
1027                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1028         }
1029         if (ino) {
1030                 *ino = IVAL(rdata, 64);
1031         }
1032 
1033         TALLOC_FREE(rdata);
1034         TALLOC_FREE(rparam);
1035         return True;
1036 }
1037 
1038 /****************************************************************************
1039  Send a qpathinfo BASIC_INFO call.
1040 ****************************************************************************/
1041 
1042 bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
     /* [<][>][^][v][top][bottom][index][help] */
1043                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
1044 {
1045         unsigned int param_len = 0;
1046         unsigned int data_len = 0;
1047         uint16 setup = TRANSACT2_QPATHINFO;
1048         char *param;
1049         char *rparam=NULL, *rdata=NULL;
1050         char *p;
1051         char *path;
1052         int len;
1053         size_t nlen;
1054         TALLOC_CTX *frame = talloc_stackframe();
1055 
1056         path = talloc_strdup(frame, name);
1057         if (!path) {
1058                 TALLOC_FREE(frame);
1059                 return false;
1060         }
1061         /* cleanup */
1062 
1063         len = strlen(path);
1064         if ( path[len-1] == '\\' || path[len-1] == '/') {
1065                 path[len-1] = '\0';
1066         }
1067         nlen = 2*(strlen(path)+1);
1068 
1069         param = TALLOC_ARRAY(frame,char,6+nlen+2);
1070         if (!param) {
1071                 return false;
1072         }
1073         p = param;
1074         memset(param, '\0', 6);
1075 
1076         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
1077         p += 6;
1078         p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
1079         param_len = PTR_DIFF(p, param);
1080 
1081 
1082         if (!cli_send_trans(cli, SMBtrans2,
1083                         NULL,                        /* name */
1084                         -1, 0,                       /* fid, flags */
1085                         &setup, 1, 0,                /* setup, length, max */
1086                         param, param_len, 2,         /* param, length, max */
1087                         NULL,  0, cli->max_xmit      /* data, length, max */
1088                         )) {
1089                 TALLOC_FREE(frame);
1090                 return False;
1091         }
1092 
1093         TALLOC_FREE(frame);
1094 
1095         if (!cli_receive_trans(cli, SMBtrans2,
1096                 &rparam, &param_len,
1097                 &rdata, &data_len)) {
1098                         return False;
1099         }
1100 
1101         if (data_len < 36) {
1102                 SAFE_FREE(rdata);
1103                 SAFE_FREE(rparam);
1104                 return False;
1105         }
1106 
1107         set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
1108         set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
1109         set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
1110 
1111         *attributes = IVAL( rdata, 32 );
1112 
1113         SAFE_FREE(rparam);
1114         SAFE_FREE(rdata);
1115 
1116         return True;
1117 }
1118 
1119 /****************************************************************************
1120  Send a qfileinfo call.
1121 ****************************************************************************/
1122 
1123 bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
     /* [<][>][^][v][top][bottom][index][help] */
1124 {
1125         unsigned int data_len = 0;
1126         unsigned int param_len = 0;
1127         uint16 setup = TRANSACT2_QFILEINFO;
1128         char param[4];
1129         char *rparam=NULL, *rdata=NULL;
1130 
1131         *poutdata = NULL;
1132         *poutlen = 0;
1133 
1134         /* if its a win95 server then fail this - win95 totally screws it
1135            up */
1136         if (cli->win95)
1137                 return False;
1138 
1139         param_len = 4;
1140 
1141         SSVAL(param, 0, fnum);
1142         SSVAL(param, 2, level);
1143 
1144         if (!cli_send_trans(cli, SMBtrans2,
1145                             NULL,                           /* name */
1146                             -1, 0,                          /* fid, flags */
1147                             &setup, 1, 0,                   /* setup, length, max */
1148                             param, param_len, 2,            /* param, length, max */
1149                             NULL, data_len, cli->max_xmit   /* data, length, max */
1150                            )) {
1151                 return False;
1152         }
1153 
1154         if (!cli_receive_trans(cli, SMBtrans2,
1155                                &rparam, &param_len,
1156                                &rdata, &data_len)) {
1157                 return False;
1158         }
1159 
1160         *poutdata = (char *)memdup(rdata, data_len);
1161         if (!*poutdata) {
1162                 SAFE_FREE(rdata);
1163                 SAFE_FREE(rparam);
1164                 return False;
1165         }
1166 
1167         *poutlen = data_len;
1168 
1169         SAFE_FREE(rdata);
1170         SAFE_FREE(rparam);
1171         return True;
1172 }
1173 
1174 /****************************************************************************
1175  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1176 ****************************************************************************/
1177 
1178 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
     /* [<][>][^][v][top][bottom][index][help] */
1179 {
1180         unsigned int data_len = 0;
1181         unsigned int param_len = 0;
1182         uint16 setup = TRANSACT2_QPATHINFO;
1183         char *param;
1184         char *rparam=NULL, *rdata=NULL;
1185         int count=8;
1186         char *p;
1187         bool ret;
1188         unsigned int len;
1189         size_t nlen = 2*(strlen(fname)+1);
1190 
1191         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
1192         if (!param) {
1193                 return NT_STATUS_NO_MEMORY;
1194         }
1195         p = param;
1196         memset(param, '\0', 6);
1197         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
1198         p += 6;
1199         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1200         param_len = PTR_DIFF(p, param);
1201 
1202         do {
1203                 ret = (cli_send_trans(cli, SMBtrans2,
1204                                       NULL,           /* Name */
1205                                       -1, 0,          /* fid, flags */
1206                                       &setup, 1, 0,   /* setup, length, max */
1207                                       param, param_len, 10, /* param, length, max */
1208                                       NULL, data_len, cli->max_xmit /* data, length, max */
1209                                       ) &&
1210                        cli_receive_trans(cli, SMBtrans2,
1211                                          &rparam, &param_len,
1212                                          &rdata, &data_len));
1213                 if (!ret && cli_is_dos_error(cli)) {
1214                         /* we need to work around a Win95 bug - sometimes
1215                            it gives ERRSRV/ERRerror temprarily */
1216                         uint8 eclass;
1217                         uint32 ecode;
1218                         cli_dos_error(cli, &eclass, &ecode);
1219                         if (eclass != ERRSRV || ecode != ERRerror) break;
1220                         smb_msleep(100);
1221                 }
1222         } while (count-- && ret==False);
1223 
1224         SAFE_FREE(param);
1225 
1226         if (!ret || !rdata || data_len < 4) {
1227                 return NT_STATUS_UNSUCCESSFUL;
1228         }
1229 
1230         len = IVAL(rdata, 0);
1231 
1232         if (len > data_len - 4) {
1233                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1234         }
1235 
1236         clistr_pull(cli->inbuf, alt_name, rdata+4, sizeof(fstring), len,
1237                     STR_UNICODE);
1238 
1239         SAFE_FREE(rdata);
1240         SAFE_FREE(rparam);
1241 
1242         return NT_STATUS_OK;
1243 }

/* [<][>][^][v][top][bottom][index][help] */