Minor comment updates ...
[Samba/gebeck_regimport.git] / source3 / msdfs / msdfs.c
blobce29c506bbce9a91e4e94cc93c9454fb50fe3432
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDfs services for Samba
5 Copyright (C) Shirish Kalele 2000
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.
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.
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.
23 #include "includes.h"
25 extern fstring local_machine;
26 extern uint32 global_client_caps;
28 /**********************************************************************
29 Parse the pathname of the form \hostname\service\reqpath
30 into the dfs_path structure
31 **********************************************************************/
33 static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
35 pstring pathname_local;
36 char* p,*temp;
38 pstrcpy(pathname_local,pathname);
39 p = temp = pathname_local;
41 ZERO_STRUCTP(pdp);
43 trim_char(temp,'\\','\\');
44 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
46 /* now tokenize */
47 /* parse out hostname */
48 p = strchr(temp,'\\');
49 if(p == NULL)
50 return False;
51 *p = '\0';
52 pstrcpy(pdp->hostname,temp);
53 DEBUG(10,("hostname: %s\n",pdp->hostname));
55 /* parse out servicename */
56 temp = p+1;
57 p = strchr(temp,'\\');
58 if(p == NULL) {
59 pstrcpy(pdp->servicename,temp);
60 pdp->reqpath[0] = '\0';
61 return True;
63 *p = '\0';
64 pstrcpy(pdp->servicename,temp);
65 DEBUG(10,("servicename: %s\n",pdp->servicename));
67 /* rest is reqpath */
68 pstrcpy(pdp->reqpath, p+1);
69 p = pdp->reqpath;
70 while (*p) {
71 if (*p == '\\') *p = '/';
72 p++;
75 DEBUG(10,("rest of the path: %s\n",pdp->reqpath));
76 return True;
79 /********************************************************
80 Fake up a connection struct for the VFS layer.
81 Note this CHANGES CWD !!!! JRA.
82 *********************************************************/
84 static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
86 ZERO_STRUCTP(conn);
87 conn->service = snum;
88 conn->connectpath = path;
89 pstring_sub(conn->connectpath , "%S", lp_servicename(snum));
91 /* needed for smbd_vfs_init() */
93 if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
94 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
95 return False;
98 if (!smbd_vfs_init(conn)) {
99 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
100 talloc_destroy( conn->mem_ctx );
101 return False;
103 if (vfs_ChDir(conn,conn->connectpath) != 0) {
104 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. Error was %s\n",
105 conn->connectpath, strerror(errno) ));
106 talloc_destroy( conn->mem_ctx );
107 return False;
109 return True;
113 /**********************************************************************
114 Parse the contents of a symlink to verify if it is an msdfs referral
115 A valid referral is of the form: msdfs:server1\share1,server2\share2
116 **********************************************************************/
117 static BOOL parse_symlink(char* buf,struct referral** preflist,
118 int* refcount)
120 pstring temp;
121 char* prot;
122 char* alt_path[MAX_REFERRAL_COUNT];
123 int count=0, i;
124 struct referral* reflist;
126 pstrcpy(temp,buf);
128 prot = strtok(temp,":");
130 if (!strequal(prot, "msdfs"))
131 return False;
133 /* No referral list requested. Just yes/no. */
134 if (!preflist)
135 return True;
137 /* parse out the alternate paths */
138 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
139 count++;
141 DEBUG(10,("parse_symlink: count=%d\n", count));
143 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
144 if(reflist == NULL) {
145 DEBUG(0,("parse_symlink: Malloc failed!\n"));
146 return False;
149 for(i=0;i<count;i++) {
150 /* replace / in the alternate path by a \ */
151 char* p = strchr(alt_path[i],'/');
152 if(p)
153 *p = '\\';
155 pstrcpy(reflist[i].alternate_path, "\\");
156 pstrcat(reflist[i].alternate_path, alt_path[i]);
157 reflist[i].proximity = 0;
158 reflist[i].ttl = REFERRAL_TTL;
159 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
162 if(refcount)
163 *refcount = count;
165 return True;
168 /**********************************************************************
169 Returns true if the unix path is a valid msdfs symlink
170 **********************************************************************/
172 BOOL is_msdfs_link(connection_struct* conn, char * path,
173 struct referral** reflistp, int* refcnt,
174 SMB_STRUCT_STAT *sbufp)
176 SMB_STRUCT_STAT st;
177 pstring referral;
178 int referral_len = 0;
180 if (!path || !conn)
181 return False;
183 if (sbufp == NULL)
184 sbufp = &st;
186 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
187 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
188 return False;
191 if (S_ISLNK(sbufp->st_mode)) {
192 /* open the link and read it */
193 referral_len = SMB_VFS_READLINK(conn, path, referral,
194 sizeof(pstring));
195 if (referral_len == -1) {
196 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
197 return False;
200 referral[referral_len] = '\0';
201 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
202 if (parse_symlink(referral, reflistp, refcnt))
203 return True;
205 return False;
208 /*****************************************************************
209 Used by other functions to decide if a dfs path is remote,
210 and to get the list of referred locations for that remote path.
212 findfirst_flag: For findfirsts, dfs links themselves are not
213 redirected, but paths beyond the links are. For normal smb calls,
214 even dfs links need to be redirected.
216 self_referralp: clients expect a dfs referral for the same share when
217 they request referrals for dfs roots on a server.
219 consumedcntp: how much of the dfs path is being redirected. the client
220 should try the remaining path on the redirected server.
222 *****************************************************************/
224 static BOOL resolve_dfs_path(pstring dfspath, struct dfs_path* dp,
225 connection_struct* conn,
226 BOOL findfirst_flag,
227 struct referral** reflistpp, int* refcntp,
228 BOOL* self_referralp, int* consumedcntp)
230 pstring localpath;
231 int consumed_level = 1;
232 char *p;
233 BOOL bad_path = False;
234 SMB_STRUCT_STAT sbuf;
235 pstring reqpath;
237 if (!dp || !conn) {
238 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
239 return False;
242 if (dp->reqpath[0] == '\0') {
243 if (self_referralp) {
244 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
245 *self_referralp = True;
247 return False;
250 DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
252 unix_convert(dp->reqpath,conn,0,&bad_path,&sbuf);
253 /* JRA... should we strlower the last component here.... ? */
254 pstrcpy(localpath, dp->reqpath);
256 /* check if need to redirect */
257 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
258 if (findfirst_flag) {
259 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
260 "for dfs link %s.\n", dfspath));
261 return False;
262 } else {
263 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n",
264 dfspath));
265 if (consumedcntp)
266 *consumedcntp = strlen(dfspath);
267 return True;
271 /* redirect if any component in the path is a link */
272 pstrcpy(reqpath, dp->reqpath);
273 p = strrchr(reqpath, '/');
274 while (p) {
275 *p = '\0';
276 pstrcpy(localpath, reqpath);
277 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
278 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
280 /* To find the path consumed, we truncate the original
281 DFS pathname passed to use to remove the last
282 component. The length of the resulting string is
283 the path consumed
285 if (consumedcntp) {
286 char *q;
287 pstring buf;
288 pstrcpy(buf, dfspath);
289 trim_char(buf, '\0', '\\');
290 for (; consumed_level; consumed_level--) {
291 q = strrchr(buf, '\\');
292 if (q)
293 *q = 0;
295 *consumedcntp = strlen(buf);
296 DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
299 return True;
301 p = strrchr(reqpath, '/');
302 consumed_level++;
305 return False;
308 /*****************************************************************
309 Decides if a dfs pathname should be redirected or not.
310 If not, the pathname is converted to a tcon-relative local unix path
311 *****************************************************************/
313 BOOL dfs_redirect(pstring pathname, connection_struct* conn,
314 BOOL findfirst_flag)
316 struct dfs_path dp;
318 if (!conn || !pathname)
319 return False;
321 parse_dfs_path(pathname, &dp);
323 /* if dfs pathname for a non-dfs share, convert to tcon-relative
324 path and return false */
325 if (!lp_msdfs_root(SNUM(conn))) {
326 pstrcpy(pathname, dp.reqpath);
327 return False;
330 if (!strequal(dp.servicename, lp_servicename(SNUM(conn)) ))
331 return False;
333 if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag,
334 NULL, NULL, NULL, NULL)) {
335 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
336 return True;
337 } else {
338 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
340 /* Form non-dfs tcon-relative path */
341 pstrcpy(pathname, dp.reqpath);
342 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n",
343 pathname));
344 return False;
347 /* never reached */
350 /**********************************************************************
351 Gets valid referrals for a dfs path and fills up the
352 junction_map structure
353 **********************************************************************/
355 BOOL get_referred_path(char *pathname, struct junction_map* jn,
356 int* consumedcntp, BOOL* self_referralp)
358 struct dfs_path dp;
360 struct connection_struct conns;
361 struct connection_struct* conn = &conns;
362 pstring conn_path;
363 int snum;
364 BOOL ret = False;
366 BOOL self_referral = False;
368 if (!pathname || !jn)
369 return False;
371 if (self_referralp)
372 *self_referralp = False;
373 else
374 self_referralp = &self_referral;
376 parse_dfs_path(pathname, &dp);
378 /* Verify hostname in path */
379 if (local_machine && (!strequal(local_machine, dp.hostname))) {
380 /* Hostname mismatch, check if one of our IP addresses */
381 if (!ismyip(*interpret_addr2(dp.hostname))) {
382 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
383 dp.hostname, pathname));
384 return False;
388 pstrcpy(jn->service_name, dp.servicename);
389 pstrcpy(jn->volume_name, dp.reqpath);
391 /* Verify the share is a dfs root */
392 snum = lp_servicenumber(jn->service_name);
393 if(snum < 0) {
394 if ((snum = find_service(jn->service_name)) < 0)
395 return False;
398 pstrcpy(conn_path, lp_pathname(snum));
399 if (!create_conn_struct(conn, snum, conn_path))
400 return False;
402 if (!lp_msdfs_root(SNUM(conn))) {
403 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
404 dp.servicename, pathname));
405 goto out;
408 if (*lp_msdfs_proxy(snum) != '\0') {
409 struct referral* ref;
410 jn->referral_count = 1;
411 if ((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
412 DEBUG(0, ("malloc failed for referral\n"));
413 goto out;
416 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
417 if (dp.reqpath[0] != '\0')
418 pstrcat(ref->alternate_path, dp.reqpath);
419 ref->proximity = 0;
420 ref->ttl = REFERRAL_TTL;
421 jn->referral_list = ref;
422 if (consumedcntp)
423 *consumedcntp = strlen(pathname);
424 ret = True;
425 goto out;
428 /* If not remote & not a self referral, return False */
429 if (!resolve_dfs_path(pathname, &dp, conn, False,
430 &jn->referral_list, &jn->referral_count,
431 self_referralp, consumedcntp)) {
432 if (!*self_referralp) {
433 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
434 goto out;
438 /* if self_referral, fill up the junction map */
439 if (*self_referralp) {
440 struct referral* ref;
441 jn->referral_count = 1;
442 if((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
443 DEBUG(0,("malloc failed for referral\n"));
444 goto out;
447 pstrcpy(ref->alternate_path,pathname);
448 ref->proximity = 0;
449 ref->ttl = REFERRAL_TTL;
450 jn->referral_list = ref;
451 if (consumedcntp)
452 *consumedcntp = strlen(pathname);
455 ret = True;
456 out:
457 talloc_destroy( conn->mem_ctx );
459 return ret;
462 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
463 struct junction_map* junction,
464 int consumedcnt,
465 BOOL self_referral)
467 char* pdata = *ppdata;
469 unsigned char uni_requestedpath[1024];
470 int uni_reqpathoffset1,uni_reqpathoffset2;
471 int uni_curroffset;
472 int requestedpathlen=0;
473 int offset;
474 int reply_size = 0;
475 int i=0;
477 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
479 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
480 STR_TERMINATE);
482 dump_data(10, (const char *) uni_requestedpath,requestedpathlen);
484 DEBUG(10,("ref count = %u\n",junction->referral_count));
486 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
487 VERSION2_REFERRAL_SIZE * junction->referral_count;
489 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
491 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
493 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
494 2 * requestedpathlen;
495 DEBUG(10,("reply_size: %u\n",reply_size));
497 /* add up the unicode lengths of all the referral paths */
498 for(i=0;i<junction->referral_count;i++) {
499 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
500 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
503 DEBUG(10,("reply_size = %u\n",reply_size));
504 /* add the unexplained 0x16 bytes */
505 reply_size += 0x16;
507 pdata = Realloc(pdata,reply_size);
508 if(pdata == NULL) {
509 DEBUG(0,("malloc failed for Realloc!\n"));
510 return -1;
511 } else
512 *ppdata = pdata;
514 /* copy in the dfs requested paths.. required for offset calculations */
515 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
516 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
518 /* create the header */
519 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
520 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
521 if(self_referral)
522 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
523 else
524 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
526 offset = 8;
527 /* add the referral elements */
528 for(i=0;i<junction->referral_count;i++) {
529 struct referral* ref = &(junction->referral_list[i]);
530 int unilen;
532 SSVAL(pdata,offset,2); /* version 2 */
533 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
534 if(self_referral)
535 SSVAL(pdata,offset+4,1);
536 else
537 SSVAL(pdata,offset+4,0);
538 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
539 SIVAL(pdata,offset+8,ref->proximity);
540 SIVAL(pdata,offset+12,ref->ttl);
542 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
543 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
544 /* copy referred path into current offset */
545 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
546 -1, STR_UNICODE);
548 SSVAL(pdata,offset+20,uni_curroffset-offset);
550 uni_curroffset += unilen;
551 offset += VERSION2_REFERRAL_SIZE;
553 /* add in the unexplained 22 (0x16) bytes at the end */
554 memset(pdata+uni_curroffset,'\0',0x16);
555 return reply_size;
558 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
559 struct junction_map* junction,
560 int consumedcnt,
561 BOOL self_referral)
563 char* pdata = *ppdata;
565 unsigned char uni_reqpath[1024];
566 int uni_reqpathoffset1, uni_reqpathoffset2;
567 int uni_curroffset;
568 int reply_size = 0;
570 int reqpathlen = 0;
571 int offset,i=0;
573 DEBUG(10,("setting up version3 referral\n"));
575 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
577 dump_data(10, (char *) uni_reqpath,reqpathlen);
579 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
580 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
581 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
583 for(i=0;i<junction->referral_count;i++) {
584 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
585 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
588 pdata = Realloc(pdata,reply_size);
589 if(pdata == NULL) {
590 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
591 return -1;
592 } else
593 *ppdata = pdata;
595 /* create the header */
596 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
597 SSVAL(pdata,2,junction->referral_count); /* number of referral */
598 if(self_referral)
599 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
600 else
601 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
603 /* copy in the reqpaths */
604 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
605 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
607 offset = 8;
608 for(i=0;i<junction->referral_count;i++) {
609 struct referral* ref = &(junction->referral_list[i]);
610 int unilen;
612 SSVAL(pdata,offset,3); /* version 3 */
613 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
614 if(self_referral)
615 SSVAL(pdata,offset+4,1);
616 else
617 SSVAL(pdata,offset+4,0);
619 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
620 SIVAL(pdata,offset+8,ref->ttl);
622 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
623 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
624 /* copy referred path into current offset */
625 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
626 -1, STR_UNICODE | STR_TERMINATE);
627 SSVAL(pdata,offset+16,uni_curroffset-offset);
628 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
629 memset(pdata+offset+18,'\0',16);
631 uni_curroffset += unilen;
632 offset += VERSION3_REFERRAL_SIZE;
634 return reply_size;
637 /******************************************************************
638 * Set up the Dfs referral for the dfs pathname
639 ******************************************************************/
641 int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char** ppdata)
643 struct junction_map junction;
644 int consumedcnt;
645 BOOL self_referral = False;
646 pstring buf;
647 int reply_size = 0;
648 char *pathnamep = pathname;
650 ZERO_STRUCT(junction);
652 /* get the junction entry */
653 if (!pathnamep)
654 return -1;
656 /* Trim pathname sent by client so it begins with only one backslash.
657 Two backslashes confuse some dfs clients
659 while (pathnamep[0] == '\\' && pathnamep[1] == '\\')
660 pathnamep++;
662 pstrcpy(buf, pathnamep);
663 /* The following call can change cwd. */
664 if (!get_referred_path(buf, &junction, &consumedcnt, &self_referral)) {
665 vfs_ChDir(orig_conn,orig_conn->connectpath);
666 return -1;
668 vfs_ChDir(orig_conn,orig_conn->connectpath);
670 if (!self_referral) {
671 pathnamep[consumedcnt] = '\0';
673 if( DEBUGLVL( 3 ) ) {
674 int i=0;
675 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
676 for(i=0;i<junction.referral_count;i++)
677 dbgtext(" %s",junction.referral_list[i].alternate_path);
678 dbgtext(".\n");
682 /* create the referral depeding on version */
683 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
684 if(max_referral_level<2 || max_referral_level>3)
685 max_referral_level = 2;
687 switch(max_referral_level) {
688 case 2:
689 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
690 consumedcnt, self_referral);
691 SAFE_FREE(junction.referral_list);
692 break;
693 case 3:
694 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
695 consumedcnt, self_referral);
696 SAFE_FREE(junction.referral_list);
697 break;
698 default:
699 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
700 return -1;
703 DEBUG(10,("DFS Referral pdata:\n"));
704 dump_data(10,*ppdata,reply_size);
705 return reply_size;
708 /**********************************************************************
709 The following functions are called by the NETDFS RPC pipe functions
710 **********************************************************************/
712 /**********************************************************************
713 Creates a junction structure from a Dfs pathname
714 **********************************************************************/
715 BOOL create_junction(char* pathname, struct junction_map* jn)
717 struct dfs_path dp;
719 parse_dfs_path(pathname,&dp);
721 /* check if path is dfs : validate first token */
722 if (local_machine && (!strequal(local_machine,dp.hostname))) {
724 /* Hostname mismatch, check if one of our IP addresses */
725 if (!ismyip(*interpret_addr2(dp.hostname))) {
726 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
727 dp.hostname, pathname));
728 return False;
732 /* Check for a non-DFS share */
733 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
734 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
735 dp.servicename));
736 return False;
739 pstrcpy(jn->service_name,dp.servicename);
740 pstrcpy(jn->volume_name,dp.reqpath);
741 return True;
744 /**********************************************************************
745 Forms a valid Unix pathname from the junction
746 **********************************************************************/
748 static BOOL junction_to_local_path(struct junction_map* jn, char* path,
749 int max_pathlen, connection_struct *conn)
751 int snum;
752 pstring conn_path;
754 if(!path || !jn)
755 return False;
757 snum = lp_servicenumber(jn->service_name);
758 if(snum < 0)
759 return False;
761 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
762 safe_strcat(path, "/", max_pathlen-1);
763 safe_strcat(path, jn->volume_name, max_pathlen-1);
765 pstrcpy(conn_path, lp_pathname(snum));
766 if (!create_conn_struct(conn, snum, conn_path))
767 return False;
769 return True;
772 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
774 pstring path;
775 pstring msdfs_link;
776 connection_struct conns;
777 connection_struct *conn = &conns;
778 int i=0;
779 BOOL insert_comma = False;
780 BOOL ret = False;
782 if(!junction_to_local_path(jn, path, sizeof(path), conn))
783 return False;
785 /* form the msdfs_link contents */
786 pstrcpy(msdfs_link, "msdfs:");
787 for(i=0; i<jn->referral_count; i++) {
788 char* refpath = jn->referral_list[i].alternate_path;
790 trim_char(refpath, '\\', '\\');
791 if(*refpath == '\0') {
792 if (i == 0)
793 insert_comma = False;
794 continue;
796 if (i > 0 && insert_comma)
797 pstrcat(msdfs_link, ",");
799 pstrcat(msdfs_link, refpath);
800 if (!insert_comma)
801 insert_comma = True;
805 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
807 if(exists)
808 if(SMB_VFS_UNLINK(conn,path)!=0)
809 goto out;
811 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
812 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
813 path, msdfs_link, strerror(errno)));
814 goto out;
818 ret = True;
820 out:
821 talloc_destroy( conn->mem_ctx );
822 return ret;
825 BOOL remove_msdfs_link(struct junction_map* jn)
827 pstring path;
828 connection_struct conns;
829 connection_struct *conn = &conns;
830 BOOL ret = False;
832 if( junction_to_local_path(jn, path, sizeof(path), conn) ) {
833 if( SMB_VFS_UNLINK(conn, path) == 0 )
834 ret = True;
836 talloc_destroy( conn->mem_ctx );
839 return ret;
842 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
844 int cnt = *jn_count;
845 DIR *dirp;
846 char* dname;
847 pstring connect_path;
848 char* service_name = lp_servicename(snum);
849 connection_struct conns;
850 connection_struct *conn = &conns;
851 struct referral *ref = NULL;
852 BOOL ret = False;
854 pstrcpy(connect_path,lp_pathname(snum));
856 if(*connect_path == '\0')
857 return False;
860 * Fake up a connection struct for the VFS layer.
863 if (!create_conn_struct(conn, snum, connect_path))
864 return False;
866 /* form a junction for the msdfs root - convention
867 DO NOT REMOVE THIS: NT clients will not work with us
868 if this is not present
870 pstrcpy(jn[cnt].service_name, service_name);
871 jn[cnt].volume_name[0] = '\0';
872 jn[cnt].referral_count = 1;
874 ref = jn[cnt].referral_list
875 = (struct referral*) malloc(sizeof(struct referral));
876 if (jn[cnt].referral_list == NULL) {
877 DEBUG(0, ("Malloc failed!\n"));
878 goto out;
881 ref->proximity = 0;
882 ref->ttl = REFERRAL_TTL;
883 if (*lp_msdfs_proxy(snum) != '\0') {
884 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
885 *jn_count = ++cnt;
886 ret = True;
887 goto out;
890 slprintf(ref->alternate_path, sizeof(pstring)-1,
891 "\\\\%s\\%s", local_machine, service_name);
892 cnt++;
894 /* Now enumerate all dfs links */
895 dirp = SMB_VFS_OPENDIR(conn, ".");
896 if(!dirp)
897 goto out;
899 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
900 if (is_msdfs_link(conn, dname, &(jn[cnt].referral_list),
901 &(jn[cnt].referral_count), NULL)) {
902 pstrcpy(jn[cnt].service_name, service_name);
903 pstrcpy(jn[cnt].volume_name, dname);
904 cnt++;
908 SMB_VFS_CLOSEDIR(conn,dirp);
909 *jn_count = cnt;
910 out:
911 talloc_destroy(conn->mem_ctx);
912 return ret;
915 int enum_msdfs_links(struct junction_map* jn)
917 int i=0;
918 int jn_count = 0;
920 if(!lp_host_msdfs())
921 return 0;
923 for(i=0;i < lp_numservices();i++) {
924 if(lp_msdfs_root(i))
925 form_junctions(i,jn,&jn_count);
927 return jn_count;