diff options
Diffstat (limited to 'source3/msdfs/msdfs.c')
-rw-r--r-- | source3/msdfs/msdfs.c | 516 |
1 files changed, 328 insertions, 188 deletions
diff --git a/source3/msdfs/msdfs.c b/source3/msdfs/msdfs.c index aadc63f04e..1f39aa79fd 100644 --- a/source3/msdfs/msdfs.c +++ b/source3/msdfs/msdfs.c @@ -27,10 +27,6 @@ extern uint32 global_client_caps; #ifdef MS_DFS -#define VERSION2_REFERRAL_SIZE 0x16 -#define VERSION3_REFERRAL_SIZE 0x22 -#define REFERRAL_HEADER_SIZE 0x08 - static void create_nondfs_path(char* pathname, struct dfs_path* pdp) { pstrcpy(pathname,pdp->volumename); @@ -50,15 +46,6 @@ static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp) ZERO_STRUCTP(pdp); - /* strip off all \'s from the beginning */ - /* while(*temp=='\\') temp++; - - DEBUG(10,("temp in parse_dfs_path : .%s.\n",temp)); - - remove any trailing \'s - if(temp[strlen(temp)-1] == '\\') temp[strlen(temp)-1]='\0'; -*/ - trim_string(temp,"\\","\\"); DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp)); @@ -101,6 +88,120 @@ static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp) return True; } +/********************************************************************** + Parse the contents of a symlink to verify if it is an msdfs referral + A valid referral is of the form: msdfs:server1\share1,server2\share2 + **********************************************************************/ +static BOOL parse_symlink(char* buf,struct referral** preflist, int* refcount) +{ + pstring temp; + char* prot; + char* alt_path[MAX_REFERRAL_COUNT]; + int count=0, i; + struct referral* reflist; + + pstrcpy(temp,buf); + + prot = strtok(temp,":"); + + if(!strequal(prot, "msdfs")) + return False; + + /* It's an msdfs referral */ + if(!preflist) + return True; + + /* parse out the alternate paths */ + while(((alt_path[count] = strtok(NULL,",")) != NULL) + && count<MAX_REFERRAL_COUNT) + count++; + + DEBUG(10,("parse_symlink: count=%d\n", count)); + reflist = *preflist = (struct referral*) malloc(count * + sizeof(struct referral)); + if(reflist == NULL) + { + DEBUG(0,("parse_symlink: Malloc failed!\n")); + return False; + } + + for(i=0;i<count;i++) + { + pstrcpy(reflist[i].alternate_path, "\\"); + pstrcat(reflist[i].alternate_path, alt_path[i]); + reflist[i].proximity = 0; + reflist[i].ttl = REFERRAL_TTL; + DEBUG(10, ("parse_symlink: Created alt path: %s\n", + reflist[i].alternate_path)); + } + + if(refcount) + *refcount = count; + + return True; +} + +BOOL is_msdfs_volume(connection_struct* conn, char* path) +{ + SMB_STRUCT_STAT st; + pstring referral; + + if(!path || !conn) + return False; + + strlower(path); + + if(conn->vfs_ops.lstat(dos_to_unix(path,False),&st) != 0) + { + DEBUG(5,("is_msdfs_volume: %s does not exist.\n",path)); + return False; + } + + if(st.st_mode & S_IFLNK) + { + /* open the link and read it */ + readlink(path, referral, sizeof(pstring)); + DEBUG(5,("is_msdfs_volume: %s -> %s\n",path,referral)); + if(parse_symlink(referral, NULL, NULL)) + return True; + } + return False; +} + +static BOOL get_referred_path(struct junction_map* junction) +{ + fstring path; + pstring buf; + SMB_STRUCT_STAT st; + int snum = lp_servicenumber(junction->service_name); + + /* form the path */ + fstrcpy(path, lp_pathname(snum)); + fstrcat(path, "/"); + + strlower(junction->volume_name); + + fstrcat(path, junction->volume_name); + + DEBUG(5,("get_referred_path: lstat target: %s\n", path)); + + if(lstat(dos_to_unix(path, False),&st) != 0) + { + DEBUG(5,("get_referred_path: %s does not exist.\n",path)); + return False; + } + + if(st.st_mode & S_IFLNK) + { + /* open the link and read it to get the dfs referral */ + readlink(path, buf, sizeof(buf)); + DEBUG(5,("get_referred_path: Referral: %s\n",buf)); + if(parse_symlink(buf, &junction->referral_list, + &junction->referral_count)) + return True; + } + return False; +} /************************************************************** Decides if given pathname is Dfs and if it should be redirected @@ -110,10 +211,11 @@ BOOL dfs_redirect(char* pathname, connection_struct* conn) { struct dfs_path dp; pstring temp; + fstring path; pstrcpy(temp,pathname); - if(lp_dfsmap(SNUM(conn))==NULL || *lp_dfsmap(SNUM(conn))=='\0') + if(!lp_msdfs_root(SNUM(conn)) ) return False; parse_dfs_path(pathname,&dp); @@ -122,7 +224,10 @@ BOOL dfs_redirect(char* pathname, connection_struct* conn) return False; /* check if need to redirect */ - if(isDfsShare(dp.servicename,dp.volumename)) + fstrcpy(path, conn->connectpath); + fstrcat(path, "/"); + fstrcat(path, dp.volumename); + if(is_msdfs_volume(conn, path)) { DEBUG(4,("dfs_redirect: Redirecting %s\n",temp)); return True; @@ -167,6 +272,185 @@ BOOL dfs_findfirst_redirect(char* pathname, connection_struct* conn) } } +static int setup_ver2_dfs_referral(char* pathname, char** ppdata, + struct junction_map* junction, + BOOL self_referral) +{ + char* pdata = *ppdata; + + unsigned char uni_requestedpath[1024]; + int uni_reqpathoffset1,uni_reqpathoffset2; + int uni_curroffset; + int requestedpathlen=0; + int offset; + int reply_size = 0; + int i=0; + + DEBUG(10,("setting up version2 referral\nRequested path:\n")); + + requestedpathlen = (dos_struni2(uni_requestedpath,pathname,512)+1)*2; + + dump_data(10,uni_requestedpath,requestedpathlen); + + DEBUG(10,("ref count = %u\n",junction->referral_count)); + + uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + + VERSION2_REFERRAL_SIZE * junction->referral_count; + + uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen; + + uni_curroffset = uni_reqpathoffset2 + requestedpathlen; + + reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count + + 2 * requestedpathlen; + DEBUG(10,("reply_size: %u\n",reply_size)); + + /* add up the unicode lengths of all the referral paths */ + for(i=0;i<junction->referral_count;i++) + { + DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path)); + reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2; + } + + DEBUG(10,("reply_size = %u\n",reply_size)); + /* add the unexplained 0x16 bytes */ + reply_size += 0x16; + + pdata = *ppdata = Realloc(pdata,reply_size); + if(pdata == NULL) + { + DEBUG(0,("malloc failed for Realloc!\n")); + return -1; + } + + /* copy in the dfs requested paths.. required for offset calculations */ + memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen); + memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen); + + + /* create the header */ + SSVAL(pdata,0,requestedpathlen-2); /* path consumed */ + SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */ + if(self_referral) + SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); + else + SIVAL(pdata,4,DFSREF_STORAGE_SERVER); + + offset = 8; + /* add the referral elements */ + for(i=0;i<junction->referral_count;i++) + { + struct referral* ref = &(junction->referral_list[i]); + int unilen; + + SSVAL(pdata,offset,2); /* version 2 */ + SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE); + if(self_referral) + SSVAL(pdata,offset+4,1); + else + SSVAL(pdata,offset+4,0); + SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ + SIVAL(pdata,offset+8,ref->proximity); + SIVAL(pdata,offset+12,ref->ttl); + + SSVAL(pdata,offset+16,uni_reqpathoffset1-offset); + SSVAL(pdata,offset+18,uni_reqpathoffset2-offset); + /* copy referred path into current offset */ + unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) + +1)*2; + SSVAL(pdata,offset+20,uni_curroffset-offset); + + uni_curroffset += unilen; + offset += VERSION2_REFERRAL_SIZE; + } + /* add in the unexplained 22 (0x16) bytes at the end */ + memset(pdata+uni_curroffset,'\0',0x16); + free(junction->referral_list); + return reply_size; +} + +static int setup_ver3_dfs_referral(char* pathname, char** ppdata, + struct junction_map* junction, + BOOL self_referral) +{ + char* pdata = *ppdata; + + unsigned char uni_reqpath[1024]; + int uni_reqpathoffset1, uni_reqpathoffset2; + int uni_curroffset; + int reply_size = 0; + + int reqpathlen = 0; + int offset,i=0; + + DEBUG(10,("setting up version3 referral\n")); + + reqpathlen = (dos_struni2(uni_reqpath,pathname,512)+1)*2; + + dump_data(10,uni_reqpath,reqpathlen); + + uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * + junction->referral_count; + uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen; + reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen; + + for(i=0;i<junction->referral_count;i++) + { + DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path)); + reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2; + } + + pdata = *ppdata = Realloc(pdata,reply_size); + if(pdata == NULL) + { + DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n")); + return -1; + } + + /* create the header */ + SSVAL(pdata,0,reqpathlen-2); /* path consumed */ + SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */ + if(self_referral) + SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); + else + SIVAL(pdata,4,DFSREF_STORAGE_SERVER); + + /* copy in the reqpaths */ + memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen); + memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen); + + offset = 8; + for(i=0;i<junction->referral_count;i++) + { + struct referral* ref = &(junction->referral_list[i]); + int unilen; + + SSVAL(pdata,offset,3); /* version 3 */ + SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE); + if(self_referral) + SSVAL(pdata,offset+4,1); + else + SSVAL(pdata,offset+4,0); + + SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ + SIVAL(pdata,offset+8,ref->ttl); + + SSVAL(pdata,offset+12,uni_reqpathoffset1-offset); + SSVAL(pdata,offset+14,uni_reqpathoffset2-offset); + /* copy referred path into current offset */ + unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) + +1)*2; + SSVAL(pdata,offset+16,uni_curroffset-offset); + /* copy 0x10 bytes of 00's in the ServiceSite GUID */ + memset(pdata+offset+18,'\0',16); + + uni_curroffset += unilen; + offset += VERSION3_REFERRAL_SIZE; + } + free(junction->referral_list); + return reply_size; +} + /****************************************************************** * Set up the Dfs referral for the dfs pathname ******************************************************************/ @@ -179,7 +463,6 @@ int setup_dfs_referral(char* pathname, int max_referral_level, BOOL self_referral; - char* pdata = *ppdata; int reply_size = 0; ZERO_STRUCT(junction); @@ -189,24 +472,24 @@ int setup_dfs_referral(char* pathname, int max_referral_level, /* check if path is dfs : check hostname is the first token */ if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0)) { - DEBUG(4,("Invalid DFS referral request for %s\n",pathname)); + DEBUG(4,("setup_dfs_referral: Invalid DFS referral request for %s\n", + pathname)); return -1; } /* Check for a non-DFS share */ - { - char* map = lp_dfsmap(lp_servicenumber(dp.servicename)); - DEBUG(10,("lp_dfsmap in setup dfs referral: .%s.\n",map )); - - if(map == NULL || (*map == '\0')) - return -1; - } + if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) + { + DEBUG(4,("setup_dfs_referral: %s is not an msdfs root.\n", + dp.servicename)); + return -1; + } pstrcpy(junction.service_name,dp.servicename); pstrcpy(junction.volume_name,dp.volumename); /* get the junction entry */ - if(!get_junction_entry(&junction)) + if(!get_referred_path(&junction)) { /* refer the same pathname, create a standard referral struct */ @@ -230,7 +513,7 @@ int setup_dfs_referral(char* pathname, int max_referral_level, if( DEBUGLVL( 3 ) ) { int i=0; - dbgtext("setup_dfs_referral: Referring client request for %s to alternate path(s):",pathname); + dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathname); for(i=0;i<junction.referral_count;i++) dbgtext(" %s",junction.referral_list[i].alternate_path); dbgtext(".\n"); @@ -238,185 +521,37 @@ int setup_dfs_referral(char* pathname, int max_referral_level, } /* create the referral depeding on version */ - DEBUG(10,("MAX_REFERRAL_LEVEL :%d\n",max_referral_level)); + DEBUG(10,("max_referral_level :%d\n",max_referral_level)); if(max_referral_level<2 || max_referral_level>3) max_referral_level = 2; switch(max_referral_level) { case 2: { - unsigned char uni_requestedpath[1024]; - int uni_reqpathoffset1,uni_reqpathoffset2; - int uni_curroffset; - int requestedpathlen=0; - int offset; - int i=0; - - DEBUG(10,("setting up version2 referral\nRequested path:\n")); - - requestedpathlen = (dos_struni2(uni_requestedpath,pathname,512)+1)*2; - - dump_data(10,uni_requestedpath,requestedpathlen); - - DEBUG(10,("ref count = %u\n",junction.referral_count)); - - uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + - VERSION2_REFERRAL_SIZE * junction.referral_count; - - uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen; - - uni_curroffset = uni_reqpathoffset2 + requestedpathlen; - - reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction.referral_count + - 2 * requestedpathlen; - DEBUG(10,("reply_size: %u\n",reply_size)); - - /* add up the unicode lengths of all the referral paths */ - for(i=0;i<junction.referral_count;i++) - { - DEBUG(10,("referral %u : %s\n",i,junction.referral_list[i].alternate_path)); - reply_size += (strlen(junction.referral_list[i].alternate_path)+1)*2; - } - - DEBUG(10,("reply_size = %u\n",reply_size)); - /* add the unexplained 0x16 bytes */ - reply_size += 0x16; - - pdata = *ppdata = Realloc(pdata,reply_size); - if(pdata == NULL) - { - DEBUG(0,("malloc failed for Realloc!\n")); - return -1; - } - - /* copy in the dfs requested paths.. required for offset calculations */ - memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen); - memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen); - - - /* create the header */ - SSVAL(pdata,0,requestedpathlen-2); /* path consumed */ - SSVAL(pdata,2,junction.referral_count); /* number of referral in this pkt */ - if(self_referral) - SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); - else - SIVAL(pdata,4,DFSREF_STORAGE_SERVER); - - offset = 8; - /* add the referral elements */ - for(i=0;i<junction.referral_count;i++) - { - struct referral* ref = &(junction.referral_list[i]); - int unilen; - - SSVAL(pdata,offset,2); /* version 2 */ - SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE); - if(self_referral) - SSVAL(pdata,offset+4,1); - else - SSVAL(pdata,offset+4,0); - SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ - SIVAL(pdata,offset+8,ref->proximity); - SIVAL(pdata,offset+12,ref->ttl); - - SSVAL(pdata,offset+16,uni_reqpathoffset1-offset); - SSVAL(pdata,offset+18,uni_reqpathoffset2-offset); - /* copy referred path into current offset */ - unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) - +1)*2; - SSVAL(pdata,offset+20,uni_curroffset-offset); - - uni_curroffset += unilen; - offset += VERSION2_REFERRAL_SIZE; - } - /* add in the unexplained 22 (0x16) bytes at the end */ - memset(pdata+uni_curroffset,'\0',0x16); - free(junction.referral_list); + reply_size = setup_ver2_dfs_referral(pathname, ppdata, &junction, + self_referral); break; } - case 3: { - unsigned char uni_reqpath[1024]; - int uni_reqpathoffset1, uni_reqpathoffset2; - int uni_curroffset; - - int reqpathlen = 0; - int offset,i=0; - - DEBUG(10,("setting up version3 referral\n")); - - reqpathlen = (dos_struni2(uni_reqpath,pathname,512)+1)*2; - - dump_data(10,uni_reqpath,reqpathlen); - - uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * - junction.referral_count; - uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen; - reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen; - - for(i=0;i<junction.referral_count;i++) - { - DEBUG(10,("referral %u : %s\n",i,junction.referral_list[i].alternate_path)); - reply_size += (strlen(junction.referral_list[i].alternate_path)+1)*2; - } - - pdata = *ppdata = Realloc(pdata,reply_size); - if(pdata == NULL) - { - DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n")); - return -1; - } - - /* create the header */ - SSVAL(pdata,0,reqpathlen-2); /* path consumed */ - SSVAL(pdata,2,junction.referral_count); /* number of referral in this pkt */ - if(self_referral) - SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER); - else - SIVAL(pdata,4,DFSREF_STORAGE_SERVER); - - /* copy in the reqpaths */ - memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen); - memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen); - - offset = 8; - for(i=0;i<junction.referral_count;i++) - { - struct referral* ref = &(junction.referral_list[i]); - int unilen; - - SSVAL(pdata,offset,3); /* version 3 */ - SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE); - if(self_referral) - SSVAL(pdata,offset+4,1); - else - SSVAL(pdata,offset+4,0); - - SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */ - SIVAL(pdata,offset+8,ref->ttl); - - SSVAL(pdata,offset+12,uni_reqpathoffset1-offset); - SSVAL(pdata,offset+14,uni_reqpathoffset2-offset); - /* copy referred path into current offset */ - unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) - +1)*2; - SSVAL(pdata,offset+16,uni_curroffset-offset); - /* copy 0x10 bytes of 00's in the ServiceSite GUID */ - memset(pdata+offset+18,'\0',16); - - uni_curroffset += unilen; - offset += VERSION3_REFERRAL_SIZE; - } - free(junction.referral_list); + reply_size = setup_ver3_dfs_referral(pathname, ppdata, &junction, + self_referral); break; } + default: + { + DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", + max_referral_level)); + return -1; + } } + DEBUG(10,("DFS Referral pdata:\n")); - dump_data(10,pdata,reply_size); + dump_data(10,*ppdata,reply_size); return reply_size; } + int dfs_path_error(char* inbuf, char* outbuf) { enum remote_arch_types ra_type = get_remote_arch(); @@ -437,4 +572,9 @@ int setup_dfs_referral(char* pathname, int max_referral_level, return -1; } +BOOL is_msdfs_volume(connection_struct* conn, char* path) +{ + return False; +} + #endif |