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