Fix bug that assumed dos_unistr2 length was in ucs2 units, not bytes.
[Samba.git] / source / msdfs / msdfs.c
blob3be57b1d23caa56f158bc72a178cffd26e4c31ac
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 #ifdef WITH_MSDFS
30 /**********************************************************************
31 Parse the pathname of the form \hostname\service\reqpath
32 into the dfs_path structure
33 **********************************************************************/
35 static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
37 pstring pathname_local;
38 char* p,*temp;
40 pstrcpy(pathname_local,pathname);
41 p = temp = pathname_local;
43 ZERO_STRUCTP(pdp);
45 trim_string(temp,"\\","\\");
46 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
48 /* now tokenize */
49 /* parse out hostname */
50 p = strchr(temp,'\\');
51 if(p == NULL)
52 return False;
53 *p = '\0';
54 pstrcpy(pdp->hostname,temp);
55 DEBUG(10,("hostname: %s\n",pdp->hostname));
57 /* parse out servicename */
58 temp = p+1;
59 p = strchr(temp,'\\');
60 if(p == NULL) {
61 pstrcpy(pdp->servicename,temp);
62 pdp->reqpath[0] = '\0';
63 return True;
65 *p = '\0';
66 pstrcpy(pdp->servicename,temp);
67 DEBUG(10,("servicename: %s\n",pdp->servicename));
69 /* rest is reqpath */
70 pstrcpy(pdp->reqpath, p+1);
71 p = pdp->reqpath;
72 while (*p) {
73 if (*p == '\\') *p = '/';
74 p++;
77 DEBUG(10,("rest of the path: %s\n",pdp->reqpath));
78 return True;
81 /********************************************************
82 Fake up a connection struct for the VFS layer.
83 *********************************************************/
85 static BOOL create_conn_struct( connection_struct *conn, int snum)
88 ZERO_STRUCTP(conn);
89 conn->service = snum;
90 conn->connectpath = lp_pathname(snum);
91 pstring_sub(conn->connectpath, "%S", lp_servicename(snum));
93 if (!smbd_vfs_init(conn)) {
94 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
95 return False;
97 return True;
101 /**********************************************************************
102 Parse the contents of a symlink to verify if it is an msdfs referral
103 A valid referral is of the form: msdfs:server1\share1,server2\share2
104 **********************************************************************/
105 static BOOL parse_symlink(char* buf,struct referral** preflist,
106 int* refcount)
108 pstring temp;
109 char* prot;
110 char* alt_path[MAX_REFERRAL_COUNT];
111 int count=0, i;
112 struct referral* reflist;
114 pstrcpy(temp,buf);
116 prot = strtok(temp,":");
118 if (!strequal(prot, "msdfs"))
119 return False;
121 /* No referral list requested. Just yes/no. */
122 if (!preflist)
123 return True;
125 /* parse out the alternate paths */
126 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
127 count++;
129 DEBUG(10,("parse_symlink: count=%d\n", count));
131 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
132 if(reflist == NULL) {
133 DEBUG(0,("parse_symlink: Malloc failed!\n"));
134 return False;
137 for(i=0;i<count;i++) {
138 /* replace / in the alternate path by a \ */
139 char* p = strchr(alt_path[i],'/');
140 if(p)
141 *p = '\\';
143 pstrcpy(reflist[i].alternate_path, "\\");
144 pstrcat(reflist[i].alternate_path, alt_path[i]);
145 reflist[i].proximity = 0;
146 reflist[i].ttl = REFERRAL_TTL;
147 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
150 if(refcount)
151 *refcount = count;
153 return True;
156 /**********************************************************************
157 Returns true if the unix path is a valid msdfs symlink
158 **********************************************************************/
159 BOOL is_msdfs_link(connection_struct* conn, char* path,
160 struct referral** reflistp, int* refcnt,
161 SMB_STRUCT_STAT *sbufp)
163 SMB_STRUCT_STAT st;
164 pstring referral;
165 int referral_len = 0;
167 if (!path || !conn)
168 return False;
170 strlower(path);
172 if (sbufp == NULL)
173 sbufp = &st;
175 if (conn->vfs_ops.lstat(conn,dos_to_unix_static(path), sbufp) != 0) {
176 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
177 return False;
180 if (S_ISLNK(sbufp->st_mode)) {
181 /* open the link and read it */
182 referral_len = conn->vfs_ops.readlink(conn, path, referral,
183 sizeof(pstring));
184 if (referral_len == -1) {
185 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
186 return False;
189 referral[referral_len] = '\0';
190 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
191 if (parse_symlink(referral, reflistp, refcnt))
192 return True;
194 return False;
197 /*****************************************************************
198 Used by other functions to decide if a dfs path is remote,
199 and to get the list of referred locations for that remote path.
201 findfirst_flag: For findfirsts, dfs links themselves are not
202 redirected, but paths beyond the links are. For normal smb calls,
203 even dfs links need to be redirected.
205 self_referralp: clients expect a dfs referral for the same share when
206 they request referrals for dfs roots on a server.
208 consumedcntp: how much of the dfs path is being redirected. the client
209 should try the remaining path on the redirected server.
210 *****************************************************************/
211 static BOOL resolve_dfs_path(char* dfspath, struct dfs_path* dp,
212 connection_struct* conn,
213 BOOL findfirst_flag,
214 struct referral** reflistpp, int* refcntp,
215 BOOL* self_referralp, int* consumedcntp)
217 fstring localpath;
219 char *p;
220 fstring reqpath;
222 if (!dp || !conn) {
223 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
224 return False;
227 if (dp->reqpath[0] == '\0') {
228 if (self_referralp) {
229 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
230 *self_referralp = True;
232 return False;
235 /* check if need to redirect */
236 fstrcpy(localpath, conn->connectpath);
237 fstrcat(localpath, "/");
238 fstrcat(localpath, dp->reqpath);
239 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
240 if (findfirst_flag) {
241 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
242 "for dfs link %s.\n", dfspath));
243 return False;
244 } else {
245 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n",
246 dfspath));
247 if (consumedcntp)
248 *consumedcntp = strlen(dfspath);
249 return True;
253 /* also redirect if the parent directory is a dfs link */
254 fstrcpy(reqpath, dp->reqpath);
255 p = strrchr(reqpath, '/');
256 if (p) {
257 *p = '\0';
258 fstrcpy(localpath, conn->connectpath);
259 fstrcat(localpath, "/");
260 fstrcat(localpath, reqpath);
261 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
262 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
264 /* To find the path consumed, we truncate the original
265 DFS pathname passed to use to remove the last
266 component. The length of the resulting string is
267 the path consumed
269 if (consumedcntp) {
270 char *q;
271 pstring buf;
272 safe_strcpy(buf, dfspath, sizeof(buf));
273 trim_string(buf, NULL, "\\");
274 q = strrchr(buf, '\\');
275 if (q)
276 *q = '\0';
277 *consumedcntp = strlen(buf);
278 DEBUG(10, ("resolve_dfs_path: Path consumed: %d\n", *consumedcntp));
281 return True;
285 return False;
288 /*****************************************************************
289 Decides if a dfs pathname should be redirected or not.
290 If not, the pathname is converted to a tcon-relative local unix path
291 *****************************************************************/
292 BOOL dfs_redirect(char* pathname, connection_struct* conn,
293 BOOL findfirst_flag)
295 struct dfs_path dp;
297 if (!conn || !pathname)
298 return False;
300 parse_dfs_path(pathname, &dp);
302 /* if dfs pathname for a non-dfs share, convert to tcon-relative
303 path and return false */
304 if (!lp_msdfs_root(SNUM(conn))) {
305 fstrcpy(pathname, dp.reqpath);
306 return False;
309 if (strcasecmp(dp.servicename, lp_servicename(SNUM(conn)) ) != 0)
310 return False;
312 if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag,
313 NULL, NULL, NULL, NULL)) {
314 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
315 return True;
316 } else {
317 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
319 /* Form non-dfs tcon-relative path */
320 fstrcpy(pathname, dp.reqpath);
321 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n",
322 pathname));
323 return False;
325 /* never reached */
326 return False;
329 /**********************************************************************
330 Gets valid referrals for a dfs path and fills up the
331 junction_map structure
332 **********************************************************************/
333 BOOL get_referred_path(char *pathname, struct junction_map* jn,
334 int* consumedcntp, BOOL* self_referralp)
336 struct dfs_path dp;
338 struct connection_struct conns;
339 struct connection_struct* conn = &conns;
340 int snum;
342 BOOL self_referral = False;
344 if (!pathname || !jn)
345 return False;
347 if (self_referralp)
348 *self_referralp = False;
349 else
350 self_referralp = &self_referral;
352 parse_dfs_path(pathname, &dp);
354 /* Verify hostname in path */
355 if (local_machine && (strcasecmp(local_machine, dp.hostname) != 0)) {
357 /* Hostname mismatch, check if one of our IP addresses */
358 if (!ismyip(*interpret_addr2(dp.hostname))) {
360 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
361 dp.hostname, pathname));
362 return False;
366 pstrcpy(jn->service_name, dp.servicename);
367 pstrcpy(jn->volume_name, dp.reqpath);
369 /* Verify the share is a dfs root */
370 snum = lp_servicenumber(jn->service_name);
371 if(snum < 0) {
372 if ((snum = find_service(jn->service_name)) < 0)
373 return False;
376 if (!create_conn_struct(conn, snum))
377 return False;
379 if (!lp_msdfs_root(SNUM(conn))) {
380 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
381 dp.servicename, pathname));
382 return False;
385 /* If not remote & not a self referral, return False */
386 if (!resolve_dfs_path(pathname, &dp, conn, False,
387 &jn->referral_list, &jn->referral_count,
388 self_referralp, consumedcntp)) {
389 if (!*self_referralp) {
390 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
391 return False;
395 /* if self_referral, fill up the junction map */
396 if (*self_referralp) {
397 struct referral* ref;
398 jn->referral_count = 1;
399 if((ref = (struct referral*) malloc(sizeof(struct referral)))
400 == NULL) {
401 DEBUG(0,("malloc failed for referral\n"));
402 return False;
405 pstrcpy(ref->alternate_path,pathname);
406 ref->proximity = 0;
407 ref->ttl = REFERRAL_TTL;
408 jn->referral_list = ref;
409 if (consumedcntp)
410 *consumedcntp = strlen(pathname);
413 return True;
416 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
417 struct junction_map* junction,
418 int consumedcnt,
419 BOOL self_referral)
421 char* pdata = *ppdata;
423 unsigned char uni_requestedpath[1024];
424 int uni_reqpathoffset1,uni_reqpathoffset2;
425 int uni_curroffset;
426 int requestedpathlen=0;
427 int offset;
428 int reply_size = 0;
429 int i=0;
431 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
433 requestedpathlen = (dos_struni2((char *)uni_requestedpath,pathname,sizeof(uni_requestedpath)) + 1) * 2;
435 dump_data(10, (char *) uni_requestedpath,requestedpathlen);
437 DEBUG(10,("ref count = %u\n",junction->referral_count));
439 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
440 VERSION2_REFERRAL_SIZE * junction->referral_count;
442 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
444 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
446 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
447 2 * requestedpathlen;
448 DEBUG(10,("reply_size: %u\n",reply_size));
450 /* add up the unicode lengths of all the referral paths */
451 for(i=0;i<junction->referral_count;i++) {
452 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
453 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
456 DEBUG(10,("reply_size = %u\n",reply_size));
457 /* add the unexplained 0x16 bytes */
458 reply_size += 0x16;
460 pdata = Realloc(pdata,reply_size);
461 if(pdata == NULL) {
462 DEBUG(0,("malloc failed for Realloc!\n"));
463 return -1;
464 } else
465 *ppdata = pdata;
467 /* copy in the dfs requested paths.. required for offset calculations */
468 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
469 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
471 /* create the header */
472 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
473 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
474 if(self_referral)
475 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
476 else
477 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
479 offset = 8;
480 /* add the referral elements */
481 for(i=0;i<junction->referral_count;i++) {
482 struct referral* ref = &(junction->referral_list[i]);
483 int unilen;
485 SSVAL(pdata,offset,2); /* version 2 */
486 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
487 if(self_referral)
488 SSVAL(pdata,offset+4,1);
489 else
490 SSVAL(pdata,offset+4,0);
491 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
492 SIVAL(pdata,offset+8,ref->proximity);
493 SIVAL(pdata,offset+12,ref->ttl);
495 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
496 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
497 /* copy referred path into current offset */
498 unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,sizeof(uni_requestedpath)) +1)*2;
499 SSVAL(pdata,offset+20,uni_curroffset-offset);
501 uni_curroffset += unilen;
502 offset += VERSION2_REFERRAL_SIZE;
504 /* add in the unexplained 22 (0x16) bytes at the end */
505 memset(pdata+uni_curroffset,'\0',0x16);
506 return reply_size;
509 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
510 struct junction_map* junction,
511 int consumedcnt,
512 BOOL self_referral)
514 char* pdata = *ppdata;
516 unsigned char uni_reqpath[1024];
517 int uni_reqpathoffset1, uni_reqpathoffset2;
518 int uni_curroffset;
519 int reply_size = 0;
521 int reqpathlen = 0;
522 int offset,i=0;
524 DEBUG(10,("setting up version3 referral\n"));
526 reqpathlen = (dos_struni2((char *) uni_reqpath,pathname,sizeof(uni_reqpath))+1)*2;
528 dump_data(10, (char *) uni_reqpath,reqpathlen);
530 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
531 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
532 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
534 for(i=0;i<junction->referral_count;i++) {
535 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
536 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
539 pdata = Realloc(pdata,reply_size);
540 if(pdata == NULL) {
541 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
542 return -1;
543 } else
544 *ppdata = pdata;
546 /* create the header */
547 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
548 SSVAL(pdata,2,junction->referral_count); /* number of referral */
549 if(self_referral)
550 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
551 else
552 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
554 /* copy in the reqpaths */
555 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
556 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
558 offset = 8;
559 for(i=0;i<junction->referral_count;i++) {
560 struct referral* ref = &(junction->referral_list[i]);
561 int unilen;
563 SSVAL(pdata,offset,3); /* version 3 */
564 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
565 if(self_referral)
566 SSVAL(pdata,offset+4,1);
567 else
568 SSVAL(pdata,offset+4,0);
570 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
571 SIVAL(pdata,offset+8,ref->ttl);
573 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
574 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
575 /* copy referred path into current offset */
576 unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,sizeof(uni_reqpath)) +1)*2;
577 SSVAL(pdata,offset+16,uni_curroffset-offset);
578 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
579 memset(pdata+offset+18,'\0',16);
581 uni_curroffset += unilen;
582 offset += VERSION3_REFERRAL_SIZE;
584 return reply_size;
587 /******************************************************************
588 * Set up the Dfs referral for the dfs pathname
589 ******************************************************************/
591 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
593 struct junction_map junction;
594 int consumedcnt;
595 BOOL self_referral = False;
596 pstring buf;
597 int reply_size = 0;
598 char *pathnamep = pathname;
600 ZERO_STRUCT(junction);
602 /* get the junction entry */
603 if (!pathnamep)
604 return -1;
606 /* Trim pathname sent by client so it begins with only one backslash.
607 Two backslashes confuse some dfs clients
609 while (strlen(pathnamep) > 1 && pathnamep[0] == '\\'
610 && pathnamep[1] == '\\')
611 pathnamep++;
613 safe_strcpy(buf, pathnamep, sizeof(buf));
614 if (!get_referred_path(buf, &junction, &consumedcnt,
615 &self_referral))
616 return -1;
618 if (!self_referral)
620 pathnamep[consumedcnt] = '\0';
622 if( DEBUGLVL( 3 ) ) {
623 int i=0;
624 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
625 for(i=0;i<junction.referral_count;i++)
626 dbgtext(" %s",junction.referral_list[i].alternate_path);
627 dbgtext(".\n");
631 /* create the referral depeding on version */
632 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
633 if(max_referral_level<2 || max_referral_level>3)
634 max_referral_level = 2;
636 switch(max_referral_level) {
637 case 2:
639 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
640 consumedcnt, self_referral);
641 SAFE_FREE(junction.referral_list);
642 break;
644 case 3:
646 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
647 consumedcnt, self_referral);
648 SAFE_FREE(junction.referral_list);
649 break;
651 default:
653 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
654 return -1;
658 DEBUG(10,("DFS Referral pdata:\n"));
659 dump_data(10,*ppdata,reply_size);
660 return reply_size;
663 int dfs_path_error(char* inbuf, char* outbuf)
665 return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
668 /**********************************************************************
669 The following functions are called by the NETDFS RPC pipe functions
670 **********************************************************************/
672 /**********************************************************************
673 Creates a junction structure from a Dfs pathname
674 **********************************************************************/
675 BOOL create_junction(char* pathname, struct junction_map* jn)
677 struct dfs_path dp;
679 parse_dfs_path(pathname,&dp);
681 /* check if path is dfs : validate first token */
682 if (local_machine && (strcasecmp(local_machine,dp.hostname)!=0)) {
684 /* Hostname mismatch, check if one of our IP addresses */
685 if (!ismyip(*interpret_addr2(dp.hostname))) {
686 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
687 dp.hostname, pathname));
688 return False;
692 /* Check for a non-DFS share */
693 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
694 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
695 dp.servicename));
696 return False;
699 pstrcpy(jn->service_name,dp.servicename);
700 pstrcpy(jn->volume_name,dp.reqpath);
701 return True;
704 /**********************************************************************
705 Forms a valid Unix pathname from the junction
706 **********************************************************************/
707 static BOOL junction_to_local_path(struct junction_map* jn, char* path,
708 int max_pathlen, connection_struct *conn)
710 int snum;
712 if(!path || !jn)
713 return False;
715 snum = lp_servicenumber(jn->service_name);
716 if(snum < 0)
717 return False;
719 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
720 safe_strcat(path, "/", max_pathlen-1);
721 strlower(jn->volume_name);
722 safe_strcat(path, jn->volume_name, max_pathlen-1);
724 if (!create_conn_struct(conn, snum))
725 return False;
727 return True;
730 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
732 pstring path;
733 pstring msdfs_link;
734 connection_struct conns;
735 connection_struct *conn = &conns;
736 int i=0;
737 BOOL insert_comma = False;
739 if(!junction_to_local_path(jn, path, sizeof(path), conn))
740 return False;
742 /* form the msdfs_link contents */
743 pstrcpy(msdfs_link, "msdfs:");
744 for(i=0; i<jn->referral_count; i++) {
745 char* refpath = jn->referral_list[i].alternate_path;
747 trim_string(refpath, "\\", "\\");
748 if(*refpath == '\0') {
749 if (i == 0)
750 insert_comma = False;
751 continue;
753 if (i > 0 && insert_comma)
754 pstrcat(msdfs_link, ",");
756 pstrcat(msdfs_link, refpath);
757 if (!insert_comma)
758 insert_comma = True;
762 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
764 if(exists)
765 if(conn->vfs_ops.unlink(conn,path)!=0)
766 return False;
768 if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
769 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
770 path, msdfs_link, strerror(errno)));
771 return False;
773 return True;
776 BOOL remove_msdfs_link(struct junction_map* jn)
778 pstring path;
779 connection_struct conns;
780 connection_struct *conn = &conns;
782 if(!junction_to_local_path(jn, path, sizeof(path), conn))
783 return False;
785 if(conn->vfs_ops.unlink(conn, path)!=0)
786 return False;
788 return True;
791 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
793 int cnt = *jn_count;
794 DIR *dirp;
795 char* dname;
796 pstring connect_path;
797 char* service_name = lp_servicename(snum);
798 connection_struct conns;
799 connection_struct *conn = &conns;
801 pstrcpy(connect_path,lp_pathname(snum));
803 if(*connect_path == '\0')
804 return False;
807 * Fake up a connection struct for the VFS layer.
810 if (!create_conn_struct(conn, snum))
811 return False;
814 /* form a junction for the msdfs root - convention
815 DO NOT REMOVE THIS: NT clients will not work with us
816 if this is not present
818 struct referral *ref = NULL;
819 pstring alt_path;
820 pstrcpy(jn[cnt].service_name, service_name);
821 jn[cnt].volume_name[0] = '\0';
822 jn[cnt].referral_count = 1;
824 slprintf(alt_path,sizeof(alt_path)-1,"\\\\%s\\%s",
825 local_machine, service_name);
826 ref = jn[cnt].referral_list = (struct referral*) malloc(sizeof(struct referral));
827 if (jn[cnt].referral_list == NULL) {
828 DEBUG(0, ("Malloc failed!\n"));
829 return False;
832 safe_strcpy(ref->alternate_path, alt_path, sizeof(pstring));
833 ref->proximity = 0;
834 ref->ttl = REFERRAL_TTL;
835 cnt++;
838 dirp = conn->vfs_ops.opendir(conn, dos_to_unix_static(connect_path));
839 if(!dirp)
840 return False;
842 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
843 pstring pathreal;
845 pstrcpy(pathreal, connect_path);
846 pstrcat(pathreal, "/");
847 pstrcat(pathreal, dname);
849 if (is_msdfs_link(conn, pathreal, &(jn[cnt].referral_list),
850 &(jn[cnt].referral_count), NULL)) {
851 pstrcpy(jn[cnt].service_name, service_name);
852 pstrcpy(jn[cnt].volume_name, dname);
853 cnt++;
857 conn->vfs_ops.closedir(conn,dirp);
858 *jn_count = cnt;
859 return True;
862 int enum_msdfs_links(struct junction_map* jn)
864 int i=0;
865 int jn_count = 0;
867 if(!lp_host_msdfs())
868 return -1;
870 for(i=0;*lp_servicename(i);i++) {
871 if(lp_msdfs_root(i))
872 form_junctions(i,jn,&jn_count);
874 return jn_count;
878 #else
879 /* Stub functions if WITH_MSDFS not defined */
880 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
882 return -1;
885 BOOL is_msdfs_link(connection_struct* conn, char* path,
886 struct referral** reflistpp, int* refcntp,
887 SMB_STRUCT_STAT *sbufp)
889 return False;
892 #endif