More code to store ACEs and SIDs. I have almost enough to start testing
[Samba/gebeck_regimport.git] / source3 / msdfs / msdfs.c
blob69a315d4e40bf4236792a4c6ed95eb58c5fdf208
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;
215 int consumed_level = 1;
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 /* redirect if any component in the path is a link */
251 fstrcpy(reqpath, dp->reqpath);
252 p = strrchr(reqpath, '/');
253 while (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 pstrcpy(buf, dfspath);
270 trim_string(buf, NULL, "\\");
271 for (; consumed_level; consumed_level--) {
272 q = strrchr(buf, '\\');
273 if (q) *q = 0;
275 *consumedcntp = strlen(buf);
276 DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
279 return True;
281 p = strrchr(reqpath, '/');
282 consumed_level++;
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 pstring conn_path;
341 int snum;
343 BOOL self_referral = False;
345 if (!pathname || !jn)
346 return False;
348 if (self_referralp)
349 *self_referralp = False;
350 else
351 self_referralp = &self_referral;
353 parse_dfs_path(pathname, &dp);
355 /* Verify hostname in path */
356 if (local_machine && (strcasecmp(local_machine, dp.hostname) != 0)) {
358 /* Hostname mismatch, check if one of our IP addresses */
359 if (!ismyip(*interpret_addr2(dp.hostname))) {
361 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
362 dp.hostname, pathname));
363 return False;
367 pstrcpy(jn->service_name, dp.servicename);
368 pstrcpy(jn->volume_name, dp.reqpath);
370 /* Verify the share is a dfs root */
371 snum = lp_servicenumber(jn->service_name);
372 if(snum < 0) {
373 if ((snum = find_service(jn->service_name)) < 0)
374 return False;
377 pstrcpy(conn_path, lp_pathname(snum));
378 if (!create_conn_struct(conn, snum, conn_path))
379 return False;
381 if (!lp_msdfs_root(SNUM(conn))) {
382 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
383 dp.servicename, pathname));
384 return False;
387 if (*lp_msdfs_proxy(snum) != '\0') {
388 struct referral* ref;
389 jn->referral_count = 1;
390 if ((ref = (struct referral*) malloc(sizeof(struct referral)))
391 == NULL) {
392 DEBUG(0, ("malloc failed for referral\n"));
393 return False;
396 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
397 if (dp.reqpath[0] != '\0')
398 pstrcat(ref->alternate_path, dp.reqpath);
399 ref->proximity = 0;
400 ref->ttl = REFERRAL_TTL;
401 jn->referral_list = ref;
402 if (consumedcntp)
403 *consumedcntp = strlen(pathname);
404 return True;
407 /* If not remote & not a self referral, return False */
408 if (!resolve_dfs_path(pathname, &dp, conn, False,
409 &jn->referral_list, &jn->referral_count,
410 self_referralp, consumedcntp)) {
411 if (!*self_referralp) {
412 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
413 return False;
417 /* if self_referral, fill up the junction map */
418 if (*self_referralp) {
419 struct referral* ref;
420 jn->referral_count = 1;
421 if((ref = (struct referral*) malloc(sizeof(struct referral)))
422 == NULL) {
423 DEBUG(0,("malloc failed for referral\n"));
424 return False;
427 pstrcpy(ref->alternate_path,pathname);
428 ref->proximity = 0;
429 ref->ttl = REFERRAL_TTL;
430 jn->referral_list = ref;
431 if (consumedcntp)
432 *consumedcntp = strlen(pathname);
435 return True;
438 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
439 struct junction_map* junction,
440 int consumedcnt,
441 BOOL self_referral)
443 char* pdata = *ppdata;
445 unsigned char uni_requestedpath[1024];
446 int uni_reqpathoffset1,uni_reqpathoffset2;
447 int uni_curroffset;
448 int requestedpathlen=0;
449 int offset;
450 int reply_size = 0;
451 int i=0;
453 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
455 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
456 STR_TERMINATE);
458 dump_data(10, (const char *) uni_requestedpath,requestedpathlen);
460 DEBUG(10,("ref count = %u\n",junction->referral_count));
462 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
463 VERSION2_REFERRAL_SIZE * junction->referral_count;
465 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
467 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
469 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
470 2 * requestedpathlen;
471 DEBUG(10,("reply_size: %u\n",reply_size));
473 /* add up the unicode lengths of all the referral paths */
474 for(i=0;i<junction->referral_count;i++) {
475 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
476 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
479 DEBUG(10,("reply_size = %u\n",reply_size));
480 /* add the unexplained 0x16 bytes */
481 reply_size += 0x16;
483 pdata = Realloc(pdata,reply_size);
484 if(pdata == NULL) {
485 DEBUG(0,("malloc failed for Realloc!\n"));
486 return -1;
487 } else
488 *ppdata = pdata;
490 /* copy in the dfs requested paths.. required for offset calculations */
491 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
492 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
494 /* create the header */
495 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
496 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
497 if(self_referral)
498 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
499 else
500 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
502 offset = 8;
503 /* add the referral elements */
504 for(i=0;i<junction->referral_count;i++) {
505 struct referral* ref = &(junction->referral_list[i]);
506 int unilen;
508 SSVAL(pdata,offset,2); /* version 2 */
509 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
510 if(self_referral)
511 SSVAL(pdata,offset+4,1);
512 else
513 SSVAL(pdata,offset+4,0);
514 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
515 SIVAL(pdata,offset+8,ref->proximity);
516 SIVAL(pdata,offset+12,ref->ttl);
518 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
519 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
520 /* copy referred path into current offset */
521 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
522 -1, STR_UNICODE);
524 SSVAL(pdata,offset+20,uni_curroffset-offset);
526 uni_curroffset += unilen;
527 offset += VERSION2_REFERRAL_SIZE;
529 /* add in the unexplained 22 (0x16) bytes at the end */
530 memset(pdata+uni_curroffset,'\0',0x16);
531 return reply_size;
534 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
535 struct junction_map* junction,
536 int consumedcnt,
537 BOOL self_referral)
539 char* pdata = *ppdata;
541 unsigned char uni_reqpath[1024];
542 int uni_reqpathoffset1, uni_reqpathoffset2;
543 int uni_curroffset;
544 int reply_size = 0;
546 int reqpathlen = 0;
547 int offset,i=0;
549 DEBUG(10,("setting up version3 referral\n"));
551 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
553 dump_data(10, (char *) uni_reqpath,reqpathlen);
555 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
556 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
557 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
559 for(i=0;i<junction->referral_count;i++) {
560 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
561 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
564 pdata = Realloc(pdata,reply_size);
565 if(pdata == NULL) {
566 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
567 return -1;
568 } else
569 *ppdata = pdata;
571 /* create the header */
572 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
573 SSVAL(pdata,2,junction->referral_count); /* number of referral */
574 if(self_referral)
575 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
576 else
577 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
579 /* copy in the reqpaths */
580 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
581 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
583 offset = 8;
584 for(i=0;i<junction->referral_count;i++) {
585 struct referral* ref = &(junction->referral_list[i]);
586 int unilen;
588 SSVAL(pdata,offset,3); /* version 3 */
589 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
590 if(self_referral)
591 SSVAL(pdata,offset+4,1);
592 else
593 SSVAL(pdata,offset+4,0);
595 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
596 SIVAL(pdata,offset+8,ref->ttl);
598 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
599 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
600 /* copy referred path into current offset */
601 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
602 -1, STR_UNICODE | STR_TERMINATE);
603 SSVAL(pdata,offset+16,uni_curroffset-offset);
604 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
605 memset(pdata+offset+18,'\0',16);
607 uni_curroffset += unilen;
608 offset += VERSION3_REFERRAL_SIZE;
610 return reply_size;
613 /******************************************************************
614 * Set up the Dfs referral for the dfs pathname
615 ******************************************************************/
617 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
619 struct junction_map junction;
620 int consumedcnt;
621 BOOL self_referral = False;
622 pstring buf;
623 int reply_size = 0;
624 char *pathnamep = pathname;
626 ZERO_STRUCT(junction);
628 /* get the junction entry */
629 if (!pathnamep)
630 return -1;
632 /* Trim pathname sent by client so it begins with only one backslash.
633 Two backslashes confuse some dfs clients
635 while (pathnamep[0] == '\\' && pathnamep[1] == '\\')
636 pathnamep++;
638 pstrcpy(buf, pathnamep);
639 if (!get_referred_path(buf, &junction, &consumedcnt,
640 &self_referral))
641 return -1;
643 if (!self_referral)
645 pathnamep[consumedcnt] = '\0';
647 if( DEBUGLVL( 3 ) ) {
648 int i=0;
649 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
650 for(i=0;i<junction.referral_count;i++)
651 dbgtext(" %s",junction.referral_list[i].alternate_path);
652 dbgtext(".\n");
656 /* create the referral depeding on version */
657 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
658 if(max_referral_level<2 || max_referral_level>3)
659 max_referral_level = 2;
661 switch(max_referral_level) {
662 case 2:
664 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
665 consumedcnt, self_referral);
666 SAFE_FREE(junction.referral_list);
667 break;
669 case 3:
671 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
672 consumedcnt, self_referral);
673 SAFE_FREE(junction.referral_list);
674 break;
676 default:
678 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
679 return -1;
683 DEBUG(10,("DFS Referral pdata:\n"));
684 dump_data(10,*ppdata,reply_size);
685 return reply_size;
688 /**********************************************************************
689 The following functions are called by the NETDFS RPC pipe functions
690 **********************************************************************/
692 /**********************************************************************
693 Creates a junction structure from a Dfs pathname
694 **********************************************************************/
695 BOOL create_junction(char* pathname, struct junction_map* jn)
697 struct dfs_path dp;
699 parse_dfs_path(pathname,&dp);
701 /* check if path is dfs : validate first token */
702 if (local_machine && (strcasecmp(local_machine,dp.hostname)!=0)) {
704 /* Hostname mismatch, check if one of our IP addresses */
705 if (!ismyip(*interpret_addr2(dp.hostname))) {
706 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
707 dp.hostname, pathname));
708 return False;
712 /* Check for a non-DFS share */
713 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
714 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
715 dp.servicename));
716 return False;
719 pstrcpy(jn->service_name,dp.servicename);
720 pstrcpy(jn->volume_name,dp.reqpath);
721 return True;
724 /**********************************************************************
725 Forms a valid Unix pathname from the junction
726 **********************************************************************/
728 static BOOL junction_to_local_path(struct junction_map* jn, char* path,
729 int max_pathlen, connection_struct *conn)
731 int snum;
732 pstring conn_path;
734 if(!path || !jn)
735 return False;
737 snum = lp_servicenumber(jn->service_name);
738 if(snum < 0)
739 return False;
741 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
742 safe_strcat(path, "/", max_pathlen-1);
743 strlower(jn->volume_name);
744 safe_strcat(path, jn->volume_name, max_pathlen-1);
746 pstrcpy(conn_path, lp_pathname(snum));
747 if (!create_conn_struct(conn, snum, conn_path))
748 return False;
750 return True;
753 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
755 pstring path;
756 pstring msdfs_link;
757 connection_struct conns;
758 connection_struct *conn = &conns;
759 int i=0;
760 BOOL insert_comma = False;
762 if(!junction_to_local_path(jn, path, sizeof(path), conn))
763 return False;
765 /* form the msdfs_link contents */
766 pstrcpy(msdfs_link, "msdfs:");
767 for(i=0; i<jn->referral_count; i++) {
768 char* refpath = jn->referral_list[i].alternate_path;
770 trim_string(refpath, "\\", "\\");
771 if(*refpath == '\0') {
772 if (i == 0)
773 insert_comma = False;
774 continue;
776 if (i > 0 && insert_comma)
777 pstrcat(msdfs_link, ",");
779 pstrcat(msdfs_link, refpath);
780 if (!insert_comma)
781 insert_comma = True;
785 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
787 if(exists)
788 if(conn->vfs_ops.unlink(conn,path)!=0)
789 return False;
791 if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
792 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
793 path, msdfs_link, strerror(errno)));
794 return False;
796 return True;
799 BOOL remove_msdfs_link(struct junction_map* jn)
801 pstring path;
802 connection_struct conns;
803 connection_struct *conn = &conns;
805 if(!junction_to_local_path(jn, path, sizeof(path), conn))
806 return False;
808 if(conn->vfs_ops.unlink(conn, path)!=0)
809 return False;
811 return True;
814 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
816 int cnt = *jn_count;
817 DIR *dirp;
818 char* dname;
819 pstring connect_path;
820 char* service_name = lp_servicename(snum);
821 connection_struct conns;
822 connection_struct *conn = &conns;
823 struct referral *ref = NULL;
825 pstrcpy(connect_path,lp_pathname(snum));
827 if(*connect_path == '\0')
828 return False;
831 * Fake up a connection struct for the VFS layer.
834 if (!create_conn_struct(conn, snum, connect_path))
835 return False;
837 /* form a junction for the msdfs root - convention
838 DO NOT REMOVE THIS: NT clients will not work with us
839 if this is not present
841 pstrcpy(jn[cnt].service_name, service_name);
842 jn[cnt].volume_name[0] = '\0';
843 jn[cnt].referral_count = 1;
845 ref = jn[cnt].referral_list
846 = (struct referral*) malloc(sizeof(struct referral));
847 if (jn[cnt].referral_list == NULL) {
848 DEBUG(0, ("Malloc failed!\n"));
849 return False;
852 ref->proximity = 0;
853 ref->ttl = REFERRAL_TTL;
854 if (*lp_msdfs_proxy(snum) != '\0') {
855 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
856 *jn_count = ++cnt;
857 return True;
860 slprintf(ref->alternate_path, sizeof(pstring)-1,
861 "\\\\%s\\%s", local_machine, service_name);
862 cnt++;
864 /* Now enumerate all dfs links */
865 dirp = conn->vfs_ops.opendir(conn, connect_path);
866 if(!dirp)
867 return False;
869 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
870 pstring pathreal;
872 pstrcpy(pathreal, connect_path);
873 pstrcat(pathreal, "/");
874 pstrcat(pathreal, dname);
876 if (is_msdfs_link(conn, pathreal, &(jn[cnt].referral_list),
877 &(jn[cnt].referral_count), NULL)) {
878 pstrcpy(jn[cnt].service_name, service_name);
879 pstrcpy(jn[cnt].volume_name, dname);
880 cnt++;
884 conn->vfs_ops.closedir(conn,dirp);
885 *jn_count = cnt;
886 return True;
889 int enum_msdfs_links(struct junction_map* jn)
891 int i=0;
892 int jn_count = 0;
894 if(!lp_host_msdfs())
895 return -1;
897 for(i=0;*lp_servicename(i);i++) {
898 if(lp_msdfs_root(i))
899 form_junctions(i,jn,&jn_count);
901 return jn_count;