Fairly large change to printing code.
[Samba.git] / source / msdfs / msdfs.c
blob3e66c1c10ca0eca36f3709d8e9cdf94edf6c76d7
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_string(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 *********************************************************/
83 static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
85 ZERO_STRUCTP(conn);
86 conn->service = snum;
87 conn->connectpath = path;
88 pstring_sub(conn->connectpath , "%S", lp_servicename(snum));
90 if (!smbd_vfs_init(conn)) {
91 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
92 return False;
94 return True;
98 /**********************************************************************
99 Parse the contents of a symlink to verify if it is an msdfs referral
100 A valid referral is of the form: msdfs:server1\share1,server2\share2
101 **********************************************************************/
102 static BOOL parse_symlink(char* buf,struct referral** preflist,
103 int* refcount)
105 pstring temp;
106 char* prot;
107 char* alt_path[MAX_REFERRAL_COUNT];
108 int count=0, i;
109 struct referral* reflist;
111 pstrcpy(temp,buf);
113 prot = strtok(temp,":");
115 if (!strequal(prot, "msdfs"))
116 return False;
118 /* No referral list requested. Just yes/no. */
119 if (!preflist)
120 return True;
122 /* parse out the alternate paths */
123 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
124 count++;
126 DEBUG(10,("parse_symlink: count=%d\n", count));
128 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
129 if(reflist == NULL) {
130 DEBUG(0,("parse_symlink: Malloc failed!\n"));
131 return False;
134 for(i=0;i<count;i++) {
135 /* replace / in the alternate path by a \ */
136 char* p = strchr(alt_path[i],'/');
137 if(p)
138 *p = '\\';
140 pstrcpy(reflist[i].alternate_path, "\\");
141 pstrcat(reflist[i].alternate_path, alt_path[i]);
142 reflist[i].proximity = 0;
143 reflist[i].ttl = REFERRAL_TTL;
144 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
147 if(refcount)
148 *refcount = count;
150 return True;
153 /**********************************************************************
154 Returns true if the unix path is a valid msdfs symlink
155 **********************************************************************/
156 BOOL is_msdfs_link(connection_struct* conn, char* path,
157 struct referral** reflistp, int* refcnt,
158 SMB_STRUCT_STAT *sbufp)
160 SMB_STRUCT_STAT st;
161 pstring referral;
162 int referral_len = 0;
164 if (!path || !conn)
165 return False;
167 strlower(path);
169 if (sbufp == NULL)
170 sbufp = &st;
172 if (conn->vfs_ops.lstat(conn, path, sbufp) != 0) {
173 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
174 return False;
177 if (S_ISLNK(sbufp->st_mode)) {
178 /* open the link and read it */
179 referral_len = conn->vfs_ops.readlink(conn, path, referral,
180 sizeof(pstring));
181 if (referral_len == -1) {
182 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
183 return False;
186 referral[referral_len] = '\0';
187 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
188 if (parse_symlink(referral, reflistp, refcnt))
189 return True;
191 return False;
194 /*****************************************************************
195 Used by other functions to decide if a dfs path is remote,
196 and to get the list of referred locations for that remote path.
198 findfirst_flag: For findfirsts, dfs links themselves are not
199 redirected, but paths beyond the links are. For normal smb calls,
200 even dfs links need to be redirected.
202 self_referralp: clients expect a dfs referral for the same share when
203 they request referrals for dfs roots on a server.
205 consumedcntp: how much of the dfs path is being redirected. the client
206 should try the remaining path on the redirected server.
207 *****************************************************************/
208 static BOOL resolve_dfs_path(char* dfspath, struct dfs_path* dp,
209 connection_struct* conn,
210 BOOL findfirst_flag,
211 struct referral** reflistpp, int* refcntp,
212 BOOL* self_referralp, int* consumedcntp)
214 fstring localpath;
216 char *p;
217 fstring reqpath;
219 if (!dp || !conn) {
220 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
221 return False;
224 if (dp->reqpath[0] == '\0') {
225 if (self_referralp) {
226 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
227 *self_referralp = True;
229 return False;
232 /* check if need to redirect */
233 fstrcpy(localpath, conn->connectpath);
234 fstrcat(localpath, "/");
235 fstrcat(localpath, dp->reqpath);
236 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
237 if (findfirst_flag) {
238 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
239 "for dfs link %s.\n", dfspath));
240 return False;
241 } else {
242 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n",
243 dfspath));
244 if (consumedcntp)
245 *consumedcntp = strlen(dfspath);
246 return True;
250 /* also redirect if the parent directory is a dfs link */
251 fstrcpy(reqpath, dp->reqpath);
252 p = strrchr(reqpath, '/');
253 if (p) {
254 *p = '\0';
255 fstrcpy(localpath, conn->connectpath);
256 fstrcat(localpath, "/");
257 fstrcat(localpath, reqpath);
258 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
259 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
261 /* To find the path consumed, we truncate the original
262 DFS pathname passed to use to remove the last
263 component. The length of the resulting string is
264 the path consumed
266 if (consumedcntp) {
267 char *q;
268 pstring buf;
269 safe_strcpy(buf, dfspath, sizeof(buf));
270 trim_string(buf, NULL, "\\");
271 q = strrchr(buf, '\\');
272 if (q)
273 *q = '\0';
274 *consumedcntp = strlen(buf);
275 DEBUG(10, ("resolve_dfs_path: Path consumed: %d\n", *consumedcntp));
278 return True;
282 return False;
285 /*****************************************************************
286 Decides if a dfs pathname should be redirected or not.
287 If not, the pathname is converted to a tcon-relative local unix path
288 *****************************************************************/
289 BOOL dfs_redirect(char* pathname, connection_struct* conn,
290 BOOL findfirst_flag)
292 struct dfs_path dp;
294 if (!conn || !pathname)
295 return False;
297 parse_dfs_path(pathname, &dp);
299 /* if dfs pathname for a non-dfs share, convert to tcon-relative
300 path and return false */
301 if (!lp_msdfs_root(SNUM(conn))) {
302 fstrcpy(pathname, dp.reqpath);
303 return False;
306 if (strcasecmp(dp.servicename, lp_servicename(SNUM(conn)) ) != 0)
307 return False;
309 if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag,
310 NULL, NULL, NULL, NULL)) {
311 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
312 return True;
313 } else {
314 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
316 /* Form non-dfs tcon-relative path */
317 fstrcpy(pathname, dp.reqpath);
318 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n",
319 pathname));
320 return False;
322 /* never reached */
323 return False;
326 /**********************************************************************
327 Gets valid referrals for a dfs path and fills up the
328 junction_map structure
329 **********************************************************************/
330 BOOL get_referred_path(char *pathname, struct junction_map* jn,
331 int* consumedcntp, BOOL* self_referralp)
333 struct dfs_path dp;
335 struct connection_struct conns;
336 struct connection_struct* conn = &conns;
337 pstring conn_path;
338 int snum;
340 BOOL self_referral = False;
342 if (!pathname || !jn)
343 return False;
345 if (self_referralp)
346 *self_referralp = False;
347 else
348 self_referralp = &self_referral;
350 parse_dfs_path(pathname, &dp);
352 /* Verify hostname in path */
353 if (local_machine && (strcasecmp(local_machine, dp.hostname) != 0)) {
355 /* Hostname mismatch, check if one of our IP addresses */
356 if (!ismyip(*interpret_addr2(dp.hostname))) {
358 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
359 dp.hostname, pathname));
360 return False;
364 pstrcpy(jn->service_name, dp.servicename);
365 pstrcpy(jn->volume_name, dp.reqpath);
367 /* Verify the share is a dfs root */
368 snum = lp_servicenumber(jn->service_name);
369 if(snum < 0) {
370 if ((snum = find_service(jn->service_name)) < 0)
371 return False;
374 pstrcpy(conn_path, lp_pathname(snum));
375 if (!create_conn_struct(conn, snum, conn_path))
376 return False;
378 if (!lp_msdfs_root(SNUM(conn))) {
379 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
380 dp.servicename, pathname));
381 return False;
384 /* If not remote & not a self referral, return False */
385 if (!resolve_dfs_path(pathname, &dp, conn, False,
386 &jn->referral_list, &jn->referral_count,
387 self_referralp, consumedcntp)) {
388 if (!*self_referralp) {
389 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
390 return False;
394 /* if self_referral, fill up the junction map */
395 if (*self_referralp) {
396 struct referral* ref;
397 jn->referral_count = 1;
398 if((ref = (struct referral*) malloc(sizeof(struct referral)))
399 == NULL) {
400 DEBUG(0,("malloc failed for referral\n"));
401 return False;
404 pstrcpy(ref->alternate_path,pathname);
405 ref->proximity = 0;
406 ref->ttl = REFERRAL_TTL;
407 jn->referral_list = ref;
408 if (consumedcntp)
409 *consumedcntp = strlen(pathname);
412 return True;
415 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
416 struct junction_map* junction,
417 int consumedcnt,
418 BOOL self_referral)
420 char* pdata = *ppdata;
422 unsigned char uni_requestedpath[1024];
423 int uni_reqpathoffset1,uni_reqpathoffset2;
424 int uni_curroffset;
425 int requestedpathlen=0;
426 int offset;
427 int reply_size = 0;
428 int i=0;
430 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
432 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
433 STR_TERMINATE);
435 dump_data(10, (const 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 = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
499 -1, STR_UNICODE);
501 SSVAL(pdata,offset+20,uni_curroffset-offset);
503 uni_curroffset += unilen;
504 offset += VERSION2_REFERRAL_SIZE;
506 /* add in the unexplained 22 (0x16) bytes at the end */
507 memset(pdata+uni_curroffset,'\0',0x16);
508 return reply_size;
511 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
512 struct junction_map* junction,
513 int consumedcnt,
514 BOOL self_referral)
516 char* pdata = *ppdata;
518 unsigned char uni_reqpath[1024];
519 int uni_reqpathoffset1, uni_reqpathoffset2;
520 int uni_curroffset;
521 int reply_size = 0;
523 int reqpathlen = 0;
524 int offset,i=0;
526 DEBUG(10,("setting up version3 referral\n"));
528 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
530 dump_data(10, (char *) uni_reqpath,reqpathlen);
532 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
533 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
534 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
536 for(i=0;i<junction->referral_count;i++) {
537 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
538 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
541 pdata = Realloc(pdata,reply_size);
542 if(pdata == NULL) {
543 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
544 return -1;
545 } else
546 *ppdata = pdata;
548 /* create the header */
549 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
550 SSVAL(pdata,2,junction->referral_count); /* number of referral */
551 if(self_referral)
552 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
553 else
554 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
556 /* copy in the reqpaths */
557 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
558 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
560 offset = 8;
561 for(i=0;i<junction->referral_count;i++) {
562 struct referral* ref = &(junction->referral_list[i]);
563 int unilen;
565 SSVAL(pdata,offset,3); /* version 3 */
566 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
567 if(self_referral)
568 SSVAL(pdata,offset+4,1);
569 else
570 SSVAL(pdata,offset+4,0);
572 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
573 SIVAL(pdata,offset+8,ref->ttl);
575 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
576 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
577 /* copy referred path into current offset */
578 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
579 -1, STR_UNICODE | STR_TERMINATE);
580 SSVAL(pdata,offset+16,uni_curroffset-offset);
581 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
582 memset(pdata+offset+18,'\0',16);
584 uni_curroffset += unilen;
585 offset += VERSION3_REFERRAL_SIZE;
587 return reply_size;
590 /******************************************************************
591 * Set up the Dfs referral for the dfs pathname
592 ******************************************************************/
594 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
596 struct junction_map junction;
597 int consumedcnt;
598 BOOL self_referral = False;
599 pstring buf;
600 int reply_size = 0;
601 char *pathnamep = pathname;
603 ZERO_STRUCT(junction);
605 /* get the junction entry */
606 if (!pathnamep)
607 return -1;
609 /* Trim pathname sent by client so it begins with only one backslash.
610 Two backslashes confuse some dfs clients
612 while (strlen(pathnamep) > 1 && pathnamep[0] == '\\'
613 && pathnamep[1] == '\\')
614 pathnamep++;
616 safe_strcpy(buf, pathnamep, sizeof(buf));
617 if (!get_referred_path(buf, &junction, &consumedcnt,
618 &self_referral))
619 return -1;
621 if (!self_referral)
623 pathnamep[consumedcnt] = '\0';
625 if( DEBUGLVL( 3 ) ) {
626 int i=0;
627 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
628 for(i=0;i<junction.referral_count;i++)
629 dbgtext(" %s",junction.referral_list[i].alternate_path);
630 dbgtext(".\n");
634 /* create the referral depeding on version */
635 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
636 if(max_referral_level<2 || max_referral_level>3)
637 max_referral_level = 2;
639 switch(max_referral_level) {
640 case 2:
642 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
643 consumedcnt, self_referral);
644 SAFE_FREE(junction.referral_list);
645 break;
647 case 3:
649 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
650 consumedcnt, self_referral);
651 SAFE_FREE(junction.referral_list);
652 break;
654 default:
656 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
657 return -1;
661 DEBUG(10,("DFS Referral pdata:\n"));
662 dump_data(10,*ppdata,reply_size);
663 return reply_size;
666 /**********************************************************************
667 The following functions are called by the NETDFS RPC pipe functions
668 **********************************************************************/
670 /**********************************************************************
671 Creates a junction structure from a Dfs pathname
672 **********************************************************************/
673 BOOL create_junction(char* pathname, struct junction_map* jn)
675 struct dfs_path dp;
677 parse_dfs_path(pathname,&dp);
679 /* check if path is dfs : validate first token */
680 if (local_machine && (strcasecmp(local_machine,dp.hostname)!=0)) {
682 /* Hostname mismatch, check if one of our IP addresses */
683 if (!ismyip(*interpret_addr2(dp.hostname))) {
684 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
685 dp.hostname, pathname));
686 return False;
690 /* Check for a non-DFS share */
691 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
692 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
693 dp.servicename));
694 return False;
697 pstrcpy(jn->service_name,dp.servicename);
698 pstrcpy(jn->volume_name,dp.reqpath);
699 return True;
702 /**********************************************************************
703 Forms a valid Unix pathname from the junction
704 **********************************************************************/
706 static BOOL junction_to_local_path(struct junction_map* jn, char* path,
707 int max_pathlen, connection_struct *conn)
709 int snum;
710 pstring conn_path;
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 pstrcpy(conn_path, lp_pathname(snum));
725 if (!create_conn_struct(conn, snum, conn_path))
726 return False;
728 return True;
731 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
733 pstring path;
734 pstring msdfs_link;
735 connection_struct conns;
736 connection_struct *conn = &conns;
737 int i=0;
738 BOOL insert_comma = False;
740 if(!junction_to_local_path(jn, path, sizeof(path), conn))
741 return False;
743 /* form the msdfs_link contents */
744 pstrcpy(msdfs_link, "msdfs:");
745 for(i=0; i<jn->referral_count; i++) {
746 char* refpath = jn->referral_list[i].alternate_path;
748 trim_string(refpath, "\\", "\\");
749 if(*refpath == '\0') {
750 if (i == 0)
751 insert_comma = False;
752 continue;
754 if (i > 0 && insert_comma)
755 pstrcat(msdfs_link, ",");
757 pstrcat(msdfs_link, refpath);
758 if (!insert_comma)
759 insert_comma = True;
763 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
765 if(exists)
766 if(conn->vfs_ops.unlink(conn,path)!=0)
767 return False;
769 if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
770 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
771 path, msdfs_link, strerror(errno)));
772 return False;
774 return True;
777 BOOL remove_msdfs_link(struct junction_map* jn)
779 pstring path;
780 connection_struct conns;
781 connection_struct *conn = &conns;
783 if(!junction_to_local_path(jn, path, sizeof(path), conn))
784 return False;
786 if(conn->vfs_ops.unlink(conn, path)!=0)
787 return False;
789 return True;
792 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
794 int cnt = *jn_count;
795 DIR *dirp;
796 char* dname;
797 pstring connect_path;
798 char* service_name = lp_servicename(snum);
799 connection_struct conns;
800 connection_struct *conn = &conns;
802 pstrcpy(connect_path,lp_pathname(snum));
804 if(*connect_path == '\0')
805 return False;
808 * Fake up a connection struct for the VFS layer.
811 if (!create_conn_struct(conn, snum, connect_path))
812 return False;
815 /* form a junction for the msdfs root - convention
816 DO NOT REMOVE THIS: NT clients will not work with us
817 if this is not present
819 struct referral *ref = NULL;
820 pstring alt_path;
821 pstrcpy(jn[cnt].service_name, service_name);
822 jn[cnt].volume_name[0] = '\0';
823 jn[cnt].referral_count = 1;
825 slprintf(alt_path,sizeof(alt_path)-1,"\\\\%s\\%s",
826 local_machine, service_name);
827 ref = jn[cnt].referral_list = (struct referral*) malloc(sizeof(struct referral));
828 if (jn[cnt].referral_list == NULL) {
829 DEBUG(0, ("Malloc failed!\n"));
830 return False;
833 safe_strcpy(ref->alternate_path, alt_path, sizeof(pstring));
834 ref->proximity = 0;
835 ref->ttl = REFERRAL_TTL;
836 cnt++;
839 dirp = conn->vfs_ops.opendir(conn, connect_path);
840 if(!dirp)
841 return False;
843 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
844 pstring pathreal;
846 pstrcpy(pathreal, connect_path);
847 pstrcat(pathreal, "/");
848 pstrcat(pathreal, dname);
850 if (is_msdfs_link(conn, pathreal, &(jn[cnt].referral_list),
851 &(jn[cnt].referral_count), NULL)) {
852 pstrcpy(jn[cnt].service_name, service_name);
853 pstrcpy(jn[cnt].volume_name, dname);
854 cnt++;
858 conn->vfs_ops.closedir(conn,dirp);
859 *jn_count = cnt;
860 return True;
863 int enum_msdfs_links(struct junction_map* jn)
865 int i=0;
866 int jn_count = 0;
868 if(!lp_host_msdfs())
869 return -1;
871 for(i=0;*lp_servicename(i);i++) {
872 if(lp_msdfs_root(i))
873 form_junctions(i,jn,&jn_count);
875 return jn_count;