1/* 2 Unix SMB/Netbios implementation. 3 Version 3.0 4 MSDfs services for Samba 5 Copyright (C) Shirish Kalele 2000 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21*/ 22 23#include "includes.h" 24 25extern uint32 global_client_caps; 26 27/********************************************************************** 28 Parse the pathname of the form \hostname\service\reqpath 29 into the dfs_path structure 30 **********************************************************************/ 31 32static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp) 33{ 34 pstring pathname_local; 35 char* p,*temp; 36 37 pstrcpy(pathname_local,pathname); 38 p = temp = pathname_local; 39 40 ZERO_STRUCTP(pdp); 41 42 trim_char(temp,'\\','\\'); 43 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp)); 44 45 /* now tokenize */ 46 /* parse out hostname */ 47 p = strchr_m(temp,'\\'); 48 if(p == NULL) 49 return False; 50 *p = '\0'; 51 pstrcpy(pdp->hostname,temp); 52 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname)); 53 54 /* parse out servicename */ 55 temp = p+1; 56 p = strchr_m(temp,'\\'); 57 if(p == NULL) { 58 pstrcpy(pdp->servicename,temp); 59 pdp->reqpath[0] = '\0'; 60 return True; 61 } 62 *p = '\0'; 63 pstrcpy(pdp->servicename,temp); 64 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename)); 65 66 /* rest is reqpath */ 67 check_path_syntax(pdp->reqpath, p+1,True); 68 69 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath)); 70 return True; 71} 72 73/********************************************************************** 74 Parse the pathname of the form /hostname/service/reqpath 75 into the dfs_path structure 76 **********************************************************************/ 77 78static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp) 79{ 80 pstring pathname_local; 81 char* p,*temp; 82 83 pstrcpy(pathname_local,pathname); 84 p = temp = pathname_local; 85 86 ZERO_STRUCTP(pdp); 87 88 trim_char(temp,'/','/'); 89 DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming \\'s\n",temp)); 90 91 /* now tokenize */ 92 /* parse out hostname */ 93 p = strchr_m(temp,'/'); 94 if(p == NULL) 95 return False; 96 *p = '\0'; 97 pstrcpy(pdp->hostname,temp); 98 DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname)); 99 100 /* parse out servicename */ 101 temp = p+1; 102 p = strchr_m(temp,'/'); 103 if(p == NULL) { 104 pstrcpy(pdp->servicename,temp); 105 pdp->reqpath[0] = '\0'; 106 return True; 107 } 108 *p = '\0'; 109 pstrcpy(pdp->servicename,temp); 110 DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename)); 111 112 /* rest is reqpath */ 113 check_path_syntax(pdp->reqpath, p+1,True); 114 115 DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath)); 116 return True; 117} 118 119/******************************************************** 120 Fake up a connection struct for the VFS layer. 121 Note this CHANGES CWD !!!! JRA. 122*********************************************************/ 123 124static BOOL create_conn_struct( connection_struct *conn, int snum, char *path) 125{ 126 ZERO_STRUCTP(conn); 127 conn->service = snum; 128 conn->connectpath = path; 129 pstring_sub(conn->connectpath , "%S", lp_servicename(snum)); 130 131 /* needed for smbd_vfs_init() */ 132 133 if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) { 134 DEBUG(0,("talloc_init(connection_struct) failed!\n")); 135 return False; 136 } 137 138 if (!smbd_vfs_init(conn)) { 139 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n")); 140 talloc_destroy( conn->mem_ctx ); 141 return False; 142 } 143 144 /* 145 * Windows seems to insist on doing trans2getdfsreferral() calls on the IPC$ 146 * share as the anonymous user. If we try to chdir as that user we will 147 * fail.... WTF ? JRA. 148 */ 149 150 if (vfs_ChDir(conn,conn->connectpath) != 0) { 151 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. Error was %s\n", 152 conn->connectpath, strerror(errno) )); 153 talloc_destroy( conn->mem_ctx ); 154 return False; 155 } 156 return True; 157} 158 159 160/********************************************************************** 161 Parse the contents of a symlink to verify if it is an msdfs referral 162 A valid referral is of the form: msdfs:server1\share1,server2\share2 163 **********************************************************************/ 164 165static BOOL parse_symlink(char* buf,struct referral** preflist, 166 int* refcount) 167{ 168 pstring temp; 169 char* prot; 170 char* alt_path[MAX_REFERRAL_COUNT]; 171 int count=0, i; 172 struct referral* reflist; 173 174 pstrcpy(temp,buf); 175 176 prot = strtok(temp,":"); 177 178 if (!strequal(prot, "msdfs")) 179 return False; 180 181 /* No referral list requested. Just yes/no. */ 182 if (!preflist) 183 return True; 184 185 /* parse out the alternate paths */ 186 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT) 187 count++; 188 189 DEBUG(10,("parse_symlink: count=%d\n", count)); 190 191 reflist = *preflist = SMB_MALLOC_ARRAY(struct referral, count); 192 if(reflist == NULL) { 193 DEBUG(0,("parse_symlink: Malloc failed!\n")); 194 return False; 195 } 196 197 for(i=0;i<count;i++) { 198 char *p; 199 200 /* replace all /'s in the alternate path by a \ */ 201 for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) { 202 *p = '\\'; 203 } 204 205 /* Remove leading '\\'s */ 206 p = alt_path[i]; 207 while (*p && (*p == '\\')) { 208 p++; 209 } 210 211 pstrcpy(reflist[i].alternate_path, "\\"); 212 pstrcat(reflist[i].alternate_path, p); 213 reflist[i].proximity = 0; 214 reflist[i].ttl = REFERRAL_TTL; 215 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path)); 216 } 217 218 if(refcount) 219 *refcount = count; 220 221 return True; 222} 223 224/********************************************************************** 225 Returns true if the unix path is a valid msdfs symlink 226 **********************************************************************/ 227 228BOOL is_msdfs_link(connection_struct* conn, char * path, 229 struct referral** reflistp, int* refcnt, 230 SMB_STRUCT_STAT *sbufp) 231{ 232 SMB_STRUCT_STAT st; 233 pstring referral; 234 int referral_len = 0; 235 236 if (!path || !conn) 237 return False; 238 239 if (sbufp == NULL) 240 sbufp = &st; 241 242 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) { 243 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path)); 244 return False; 245 } 246 247 if (S_ISLNK(sbufp->st_mode)) { 248 /* open the link and read it */ 249 referral_len = SMB_VFS_READLINK(conn, path, referral, 250 sizeof(pstring)); 251 if (referral_len == -1) { 252 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno))); 253 return False; 254 } 255 256 referral[referral_len] = '\0'; 257 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral)); 258 if (parse_symlink(referral, reflistp, refcnt)) 259 return True; 260 } 261 return False; 262} 263 264/***************************************************************** 265 Used by other functions to decide if a dfs path is remote, 266and to get the list of referred locations for that remote path. 267 268findfirst_flag: For findfirsts, dfs links themselves are not 269redirected, but paths beyond the links are. For normal smb calls, 270even dfs links need to be redirected. 271 272self_referralp: clients expect a dfs referral for the same share when 273they request referrals for dfs roots on a server. 274 275consumedcntp: how much of the dfs path is being redirected. the client 276should try the remaining path on the redirected server. 277 278*****************************************************************/ 279 280static BOOL resolve_dfs_path(pstring dfspath, struct dfs_path* dp, 281 connection_struct* conn, 282 BOOL findfirst_flag, 283 struct referral** reflistpp, int* refcntp, 284 BOOL* self_referralp, int* consumedcntp) 285{ 286 pstring localpath; 287 int consumed_level = 1; 288 char *p; 289 BOOL bad_path = False; 290 SMB_STRUCT_STAT sbuf; 291 pstring reqpath; 292 293 if (!dp || !conn) { 294 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n")); 295 return False; 296 } 297 298 if (dp->reqpath[0] == '\0') { 299 if (self_referralp) { 300 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n")); 301 *self_referralp = True; 302 } 303 return False; 304 } 305 306 DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath)); 307 308 unix_convert(dp->reqpath,conn,0,&bad_path,&sbuf); 309 /* JRA... should we strlower the last component here.... ? */ 310 pstrcpy(localpath, dp->reqpath); 311 312 /* check if need to redirect */ 313 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) { 314 if (findfirst_flag) { 315 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection " 316 "for dfs link %s.\n", dfspath)); 317 return False; 318 } else { 319 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n", 320 dfspath)); 321 if (consumedcntp) 322 *consumedcntp = strlen(dfspath); 323 return True; 324 } 325 } 326 327 /* redirect if any component in the path is a link */ 328 pstrcpy(reqpath, dp->reqpath); 329 p = strrchr_m(reqpath, '/'); 330 while (p) { 331 *p = '\0'; 332 pstrcpy(localpath, reqpath); 333 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) { 334 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath)); 335 336 /* To find the path consumed, we truncate the original 337 DFS pathname passed to use to remove the last 338 component. The length of the resulting string is 339 the path consumed 340 */ 341 if (consumedcntp) { 342 char *q; 343 pstring buf; 344 pstrcpy(buf, dfspath); 345 trim_char(buf, '\0', '\\'); 346 for (; consumed_level; consumed_level--) { 347 q = strrchr_m(buf, '\\'); 348 if (q) 349 *q = 0; 350 } 351 *consumedcntp = strlen(buf); 352 DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp)); 353 } 354 355 return True; 356 } 357 p = strrchr_m(reqpath, '/'); 358 consumed_level++; 359 } 360 361 return False; 362} 363 364/***************************************************************** 365 Decides if a dfs pathname should be redirected or not. 366 If not, the pathname is converted to a tcon-relative local unix path 367*****************************************************************/ 368 369BOOL dfs_redirect(pstring pathname, connection_struct* conn, 370 BOOL findfirst_flag) 371{ 372 struct dfs_path dp; 373 374 if (!conn || !pathname) 375 return False; 376 377 parse_processed_dfs_path(pathname, &dp); 378 379 /* if dfs pathname for a non-dfs share, convert to tcon-relative 380 path and return false */ 381 if (!lp_msdfs_root(SNUM(conn))) { 382 pstrcpy(pathname, dp.reqpath); 383 return False; 384 } 385 386 if (!strequal(dp.servicename, lp_servicename(SNUM(conn)) )) 387 return False; 388 389 if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag, 390 NULL, NULL, NULL, NULL)) { 391 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname)); 392 return True; 393 } else { 394 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname)); 395 396 /* Form non-dfs tcon-relative path */ 397 pstrcpy(pathname, dp.reqpath); 398 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", 399 pathname)); 400 return False; 401 } 402 403 /* never reached */ 404} 405 406/********************************************************************** 407 Return a self referral. 408**********************************************************************/ 409 410static BOOL self_ref(char *pathname, struct junction_map *jucn, 411 int *consumedcntp, BOOL *self_referralp) 412{ 413 struct referral *ref; 414 415 if (self_referralp != NULL) 416 *self_referralp = True; 417 418 jucn->referral_count = 1; 419 if((ref = SMB_MALLOC_P(struct referral)) == NULL) { 420 DEBUG(0,("self_ref: malloc failed for referral\n")); 421 return False; 422 } 423 424 pstrcpy(ref->alternate_path,pathname); 425 ref->proximity = 0; 426 ref->ttl = REFERRAL_TTL; 427 jucn->referral_list = ref; 428 if (consumedcntp) 429 *consumedcntp = strlen(pathname); 430 431 return True; 432} 433 434/********************************************************************** 435 Gets valid referrals for a dfs path and fills up the 436 junction_map structure 437**********************************************************************/ 438 439BOOL get_referred_path(char *pathname, struct junction_map *jucn, 440 int *consumedcntp, BOOL *self_referralp) 441{ 442 struct dfs_path dp; 443 444 struct connection_struct conns; 445 struct connection_struct* conn = &conns; 446 pstring conn_path; 447 int snum; 448 BOOL ret = False; 449 BOOL self_referral = False; 450 451 if (!pathname || !jucn) 452 return False; 453 454 ZERO_STRUCT(conns); 455 456 if (self_referralp) 457 *self_referralp = False; 458 else 459 self_referralp = &self_referral; 460 461 parse_dfs_path(pathname, &dp); 462 463 /* Verify hostname in path */ 464 if ( !strequal(get_local_machine_name(), dp.hostname) ) { 465 /* Hostname mismatch, check if one of our IP addresses */ 466 if (!ismyip(*interpret_addr2(dp.hostname))) { 467 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n", 468 dp.hostname, pathname)); 469 return False; 470 } 471 } 472 473 pstrcpy(jucn->service_name, dp.servicename); 474 pstrcpy(jucn->volume_name, dp.reqpath); 475 476 /* Verify the share is a dfs root */ 477 snum = lp_servicenumber(jucn->service_name); 478 if(snum < 0) { 479 if ((snum = find_service(jucn->service_name)) < 0) 480 return False; 481 } 482 483 if (!lp_msdfs_root(snum)) { 484 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n", 485 dp.servicename, pathname)); 486 goto out; 487 } 488 489 /* 490 * Self referrals are tested with a anonymous IPC connection and 491 * a GET_DFS_REFERRAL call to \\server\share. (which means dp.reqpath[0] points 492 * to an empty string). create_conn_struct cd's into the directory and will 493 * fail if it cannot (as the anonymous user). Cope with this. 494 */ 495 496 if (dp.reqpath[0] == '\0') { 497 498 struct referral* ref; 499 500 if (*lp_msdfs_proxy(snum) == '\0') 501 return self_ref(pathname, jucn, consumedcntp, 502 self_referralp); 503 504 jucn->referral_count = 1; 505 if ((ref = SMB_MALLOC_P(struct referral)) == NULL) { 506 DEBUG(0, ("malloc failed for referral\n")); 507 goto out; 508 } 509 510 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum)); 511 if (dp.reqpath[0] != '\0') 512 pstrcat(ref->alternate_path, dp.reqpath); 513 ref->proximity = 0; 514 ref->ttl = REFERRAL_TTL; 515 jucn->referral_list = ref; 516 if (consumedcntp) 517 *consumedcntp = strlen(pathname); 518 ret = True; 519 goto out; 520 } 521 522 pstrcpy(conn_path, lp_pathname(snum)); 523 if (!create_conn_struct(conn, snum, conn_path)) 524 return False; 525 526 /* If not remote & not a self referral, return False */ 527 if (!resolve_dfs_path(pathname, &dp, conn, False, 528 &jucn->referral_list, &jucn->referral_count, 529 self_referralp, consumedcntp)) { 530 if (!*self_referralp) { 531 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname)); 532 goto out; 533 } 534 } 535 536 /* if self_referral, fill up the junction map */ 537 if (*self_referralp) { 538 if (self_ref(pathname, jucn, consumedcntp, self_referralp) == False) { 539 goto out; 540 } 541 } 542 543 ret = True; 544 545out: 546 if (conn->mem_ctx) 547 talloc_destroy( conn->mem_ctx ); 548 549 return ret; 550} 551 552static int setup_ver2_dfs_referral(char* pathname, char** ppdata, 553 struct junction_map* junction, 554 int consumedcnt, 555 BOOL self_referral) 556{ 557 char* pdata = *ppdata; 558 559 unsigned char uni_requestedpath[1024]; 560 int uni_reqpathoffset1,uni_reqpathoffset2; 561 int uni_curroffset; 562 int requestedpathlen=0; 563 int offset; 564 int reply_size = 0; 565 int i=0; 566 567 DEBUG(10,("setting up version2 referral\nRequested path:\n")); 568 569 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1, 570 STR_TERMINATE); 571 572 dump_data(10, (const char *) uni_requestedpath,requestedpathlen); 573 574 DEBUG(10,("ref count = %u\n",junction->referral_count)); 575 576 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + 577 VERSION2_REFERRAL_SIZE * junction->referral_count; 578 579 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen; 580 581 uni_curroffset = uni_reqpathoffset2 + requestedpathlen; 582 583 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count + 584 2 * requestedpathlen; 585 DEBUG(10,("reply_size: %u\n",reply_size)); 586 587 /* add up the unicode lengths of all the referral paths */ 588 for(i=0;i<junction->referral_count;i++) { 589 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path)); 590 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2; 591 } 592 593 DEBUG(10,("reply_size = %u\n",reply_size)); 594 /* add the unexplained 0x16 bytes */ 595 reply_size += 0x16; 596 597 pdata = SMB_REALLOC(pdata,reply_size); 598 if(pdata == NULL) { 599 DEBUG(0,("malloc failed for Realloc!\n")); 600 return -1; 601 } else 602 *ppdata = pdata; 603 604 /* copy in the dfs requested paths.. required for offset calculations */ 605 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen); 606 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen); 607 608 /* create the header */ 609 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */ 610 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */ 611 if(self_referral) 612 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); 613 else 614 SIVAL(pdata,4,DFSREF_STORAGE_SERVER); 615 616 offset = 8; 617 /* add the referral elements */ 618 for(i=0;i<junction->referral_count;i++) { 619 struct referral* ref = &junction->referral_list[i]; 620 int unilen; 621 622 SSVAL(pdata,offset,2); /* version 2 */ 623 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE); 624 if(self_referral) 625 SSVAL(pdata,offset+4,1); 626 else 627 SSVAL(pdata,offset+4,0); 628 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ 629 SIVAL(pdata,offset+8,ref->proximity); 630 SIVAL(pdata,offset+12,ref->ttl); 631 632 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset); 633 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset); 634 /* copy referred path into current offset */ 635 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path, 636 -1, STR_UNICODE); 637 638 SSVAL(pdata,offset+20,uni_curroffset-offset); 639 640 uni_curroffset += unilen; 641 offset += VERSION2_REFERRAL_SIZE; 642 } 643 /* add in the unexplained 22 (0x16) bytes at the end */ 644 memset(pdata+uni_curroffset,'\0',0x16); 645 return reply_size; 646} 647 648static int setup_ver3_dfs_referral(char* pathname, char** ppdata, 649 struct junction_map* junction, 650 int consumedcnt, 651 BOOL self_referral) 652{ 653 char* pdata = *ppdata; 654 655 unsigned char uni_reqpath[1024]; 656 int uni_reqpathoffset1, uni_reqpathoffset2; 657 int uni_curroffset; 658 int reply_size = 0; 659 660 int reqpathlen = 0; 661 int offset,i=0; 662 663 DEBUG(10,("setting up version3 referral\n")); 664 665 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE); 666 667 dump_data(10, (char *) uni_reqpath,reqpathlen); 668 669 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count; 670 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen; 671 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen; 672 673 for(i=0;i<junction->referral_count;i++) { 674 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path)); 675 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2; 676 } 677 678 pdata = SMB_REALLOC(pdata,reply_size); 679 if(pdata == NULL) { 680 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n")); 681 return -1; 682 } else 683 *ppdata = pdata; 684 685 /* create the header */ 686 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */ 687 SSVAL(pdata,2,junction->referral_count); /* number of referral */ 688 if(self_referral) 689 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); 690 else 691 SIVAL(pdata,4,DFSREF_STORAGE_SERVER); 692 693 /* copy in the reqpaths */ 694 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen); 695 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen); 696 697 offset = 8; 698 for(i=0;i<junction->referral_count;i++) { 699 struct referral* ref = &(junction->referral_list[i]); 700 int unilen; 701 702 SSVAL(pdata,offset,3); /* version 3 */ 703 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE); 704 if(self_referral) 705 SSVAL(pdata,offset+4,1); 706 else 707 SSVAL(pdata,offset+4,0); 708 709 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ 710 SIVAL(pdata,offset+8,ref->ttl); 711 712 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset); 713 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset); 714 /* copy referred path into current offset */ 715 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path, 716 -1, STR_UNICODE | STR_TERMINATE); 717 SSVAL(pdata,offset+16,uni_curroffset-offset); 718 /* copy 0x10 bytes of 00's in the ServiceSite GUID */ 719 memset(pdata+offset+18,'\0',16); 720 721 uni_curroffset += unilen; 722 offset += VERSION3_REFERRAL_SIZE; 723 } 724 return reply_size; 725} 726 727/****************************************************************** 728 * Set up the Dfs referral for the dfs pathname 729 ******************************************************************/ 730 731int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char** ppdata) 732{ 733 struct junction_map junction; 734 int consumedcnt; 735 BOOL self_referral = False; 736 pstring buf; 737 int reply_size = 0; 738 char *pathnamep = pathname; 739 740 ZERO_STRUCT(junction); 741 742 /* get the junction entry */ 743 if (!pathnamep) 744 return -1; 745 746 /* Trim pathname sent by client so it begins with only one backslash. 747 Two backslashes confuse some dfs clients 748 */ 749 while (pathnamep[0] == '\\' && pathnamep[1] == '\\') 750 pathnamep++; 751 752 pstrcpy(buf, pathnamep); 753 /* The following call can change cwd. */ 754 if (!get_referred_path(buf, &junction, &consumedcnt, &self_referral)) { 755 vfs_ChDir(orig_conn,orig_conn->connectpath); 756 return -1; 757 } 758 vfs_ChDir(orig_conn,orig_conn->connectpath); 759 760 if (!self_referral) { 761 pathnamep[consumedcnt] = '\0'; 762 763 if( DEBUGLVL( 3 ) ) { 764 int i=0; 765 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep); 766 for(i=0;i<junction.referral_count;i++) 767 dbgtext(" %s",junction.referral_list[i].alternate_path); 768 dbgtext(".\n"); 769 } 770 } 771 772 /* create the referral depeding on version */ 773 DEBUG(10,("max_referral_level :%d\n",max_referral_level)); 774 if(max_referral_level<2 || max_referral_level>3) 775 max_referral_level = 2; 776 777 switch(max_referral_level) { 778 case 2: 779 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction, 780 consumedcnt, self_referral); 781 SAFE_FREE(junction.referral_list); 782 break; 783 case 3: 784 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction, 785 consumedcnt, self_referral); 786 SAFE_FREE(junction.referral_list); 787 break; 788 default: 789 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level)); 790 return -1; 791 } 792 793 DEBUG(10,("DFS Referral pdata:\n")); 794 dump_data(10,*ppdata,reply_size); 795 return reply_size; 796} 797 798/********************************************************************** 799 The following functions are called by the NETDFS RPC pipe functions 800 **********************************************************************/ 801 802/********************************************************************** 803 Creates a junction structure from a Dfs pathname 804 **********************************************************************/ 805BOOL create_junction(char* pathname, struct junction_map* jucn) 806{ 807 struct dfs_path dp; 808 809 parse_dfs_path(pathname,&dp); 810 811 /* check if path is dfs : validate first token */ 812 if ( !strequal(get_local_machine_name(),dp.hostname) ) { 813 814 /* Hostname mismatch, check if one of our IP addresses */ 815 if (!ismyip(*interpret_addr2(dp.hostname))) { 816 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n", 817 dp.hostname, pathname)); 818 return False; 819 } 820 } 821 822 /* Check for a non-DFS share */ 823 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) { 824 DEBUG(4,("create_junction: %s is not an msdfs root.\n", 825 dp.servicename)); 826 return False; 827 } 828 829 pstrcpy(jucn->service_name,dp.servicename); 830 pstrcpy(jucn->volume_name,dp.reqpath); 831 return True; 832} 833 834/********************************************************************** 835 Forms a valid Unix pathname from the junction 836 **********************************************************************/ 837 838static BOOL junction_to_local_path(struct junction_map* jucn, char* path, 839 int max_pathlen, connection_struct *conn) 840{ 841 int snum; 842 pstring conn_path; 843 844 if(!path || !jucn) 845 return False; 846 847 snum = lp_servicenumber(jucn->service_name); 848 if(snum < 0) 849 return False; 850 851 safe_strcpy(path, lp_pathname(snum), max_pathlen-1); 852 safe_strcat(path, "/", max_pathlen-1); 853 safe_strcat(path, jucn->volume_name, max_pathlen-1); 854 855 pstrcpy(conn_path, lp_pathname(snum)); 856 if (!create_conn_struct(conn, snum, conn_path)) 857 return False; 858 859 return True; 860} 861 862BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists) 863{ 864 pstring path; 865 pstring msdfs_link; 866 connection_struct conns; 867 connection_struct *conn = &conns; 868 int i=0; 869 BOOL insert_comma = False; 870 BOOL ret = False; 871 872 if(!junction_to_local_path(jucn, path, sizeof(path), conn)) 873 return False; 874 875 /* form the msdfs_link contents */ 876 pstrcpy(msdfs_link, "msdfs:"); 877 for(i=0; i<jucn->referral_count; i++) { 878 char* refpath = jucn->referral_list[i].alternate_path; 879 880 trim_char(refpath, '\\', '\\'); 881 if(*refpath == '\0') { 882 if (i == 0) 883 insert_comma = False; 884 continue; 885 } 886 if (i > 0 && insert_comma) 887 pstrcat(msdfs_link, ","); 888 889 pstrcat(msdfs_link, refpath); 890 if (!insert_comma) 891 insert_comma = True; 892 893 } 894 895 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link)); 896 897 if(exists) 898 if(SMB_VFS_UNLINK(conn,path)!=0) 899 goto out; 900 901 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) { 902 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n", 903 path, msdfs_link, strerror(errno))); 904 goto out; 905 } 906 907 908 ret = True; 909 910out: 911 talloc_destroy( conn->mem_ctx ); 912 return ret; 913} 914 915BOOL remove_msdfs_link(struct junction_map* jucn) 916{ 917 pstring path; 918 connection_struct conns; 919 connection_struct *conn = &conns; 920 BOOL ret = False; 921 922 if( junction_to_local_path(jucn, path, sizeof(path), conn) ) { 923 if( SMB_VFS_UNLINK(conn, path) == 0 ) 924 ret = True; 925 926 talloc_destroy( conn->mem_ctx ); 927 } 928 929 return ret; 930} 931 932static BOOL form_junctions(int snum, struct junction_map* jucn, int* jn_count) 933{ 934 int cnt = *jn_count; 935 DIR *dirp; 936 char* dname; 937 pstring connect_path; 938 char* service_name = lp_servicename(snum); 939 connection_struct conns; 940 connection_struct *conn = &conns; 941 struct referral *ref = NULL; 942 BOOL ret = False; 943 944 pstrcpy(connect_path,lp_pathname(snum)); 945 946 if(*connect_path == '\0') 947 return False; 948 949 /* 950 * Fake up a connection struct for the VFS layer. 951 */ 952 953 if (!create_conn_struct(conn, snum, connect_path)) 954 return False; 955 956 /* form a junction for the msdfs root - convention 957 DO NOT REMOVE THIS: NT clients will not work with us 958 if this is not present 959 */ 960 pstrcpy(jucn[cnt].service_name, service_name); 961 jucn[cnt].volume_name[0] = '\0'; 962 jucn[cnt].referral_count = 1; 963 964 ref = jucn[cnt].referral_list = SMB_MALLOC_P(struct referral); 965 if (jucn[cnt].referral_list == NULL) { 966 DEBUG(0, ("Malloc failed!\n")); 967 goto out; 968 } 969 970 ref->proximity = 0; 971 ref->ttl = REFERRAL_TTL; 972 if (*lp_msdfs_proxy(snum) != '\0') { 973 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum)); 974 *jn_count = ++cnt; 975 ret = True; 976 goto out; 977 } 978 979 slprintf(ref->alternate_path, sizeof(pstring)-1, 980 "\\\\%s\\%s", get_local_machine_name(), service_name); 981 cnt++; 982 983 /* Now enumerate all dfs links */ 984 dirp = SMB_VFS_OPENDIR(conn, "."); 985 if(!dirp) 986 goto out; 987 988 while((dname = vfs_readdirname(conn, dirp)) != NULL) { 989 if (is_msdfs_link(conn, dname, &(jucn[cnt].referral_list), 990 &(jucn[cnt].referral_count), NULL)) { 991 pstrcpy(jucn[cnt].service_name, service_name); 992 pstrcpy(jucn[cnt].volume_name, dname); 993 cnt++; 994 } 995 } 996 997 SMB_VFS_CLOSEDIR(conn,dirp); 998 *jn_count = cnt; 999out: 1000 talloc_destroy(conn->mem_ctx); 1001 return ret; 1002} 1003 1004int enum_msdfs_links(struct junction_map* jucn) 1005{ 1006 int i=0; 1007 int jn_count = 0; 1008 1009 if(!lp_host_msdfs()) 1010 return 0; 1011 1012 for(i=0;i < lp_numservices();i++) { 1013 if(lp_msdfs_root(i)) 1014 form_junctions(i,jucn,&jn_count); 1015 } 1016 return jn_count; 1017} 1018