Fix string overflow due to wrong size calculation
[Samba/gebeck_regimport.git] / source3 / msdfs / msdfs.c
blobb77e2111bc90d51287de22d9e9150313df586dcc
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_m(temp,'\\');
49 if(p == NULL)
50 return False;
51 *p = '\0';
52 pstrcpy(pdp->hostname,temp);
53 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
55 /* parse out servicename */
56 temp = p+1;
57 p = strchr_m(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,("parse_dfs_path: servicename: %s\n",pdp->servicename));
67 /* rest is reqpath */
68 check_path_syntax(pdp->reqpath, p+1);
70 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
71 return True;
74 /**********************************************************************
75 Parse the pathname of the form /hostname/service/reqpath
76 into the dfs_path structure
77 **********************************************************************/
79 static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp)
81 pstring pathname_local;
82 char* p,*temp;
84 pstrcpy(pathname_local,pathname);
85 p = temp = pathname_local;
87 ZERO_STRUCTP(pdp);
89 trim_char(temp,'/','/');
90 DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming \\'s\n",temp));
92 /* now tokenize */
93 /* parse out hostname */
94 p = strchr_m(temp,'/');
95 if(p == NULL)
96 return False;
97 *p = '\0';
98 pstrcpy(pdp->hostname,temp);
99 DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname));
101 /* parse out servicename */
102 temp = p+1;
103 p = strchr_m(temp,'/');
104 if(p == NULL) {
105 pstrcpy(pdp->servicename,temp);
106 pdp->reqpath[0] = '\0';
107 return True;
109 *p = '\0';
110 pstrcpy(pdp->servicename,temp);
111 DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
113 /* rest is reqpath */
114 check_path_syntax(pdp->reqpath, p+1);
116 DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
117 return True;
120 /********************************************************
121 Fake up a connection struct for the VFS layer.
122 Note this CHANGES CWD !!!! JRA.
123 *********************************************************/
125 static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
127 ZERO_STRUCTP(conn);
128 conn->service = snum;
129 conn->connectpath = path;
130 pstring_sub(conn->connectpath , "%S", lp_servicename(snum));
132 /* needed for smbd_vfs_init() */
134 if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
135 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
136 return False;
139 if (!smbd_vfs_init(conn)) {
140 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
141 talloc_destroy( conn->mem_ctx );
142 return False;
146 * Windows seems to insist on doing trans2getdfsreferral() calls on the IPC$
147 * share as the anonymous user. If we try to chdir as that user we will
148 * fail.... WTF ? JRA.
151 if (vfs_ChDir(conn,conn->connectpath) != 0) {
152 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. Error was %s\n",
153 conn->connectpath, strerror(errno) ));
154 #if 0 /* JRATEST ? */
155 talloc_destroy( conn->mem_ctx );
156 return False;
157 #endif
159 return True;
163 /**********************************************************************
164 Parse the contents of a symlink to verify if it is an msdfs referral
165 A valid referral is of the form: msdfs:server1\share1,server2\share2
166 **********************************************************************/
168 static BOOL parse_symlink(char* buf,struct referral** preflist,
169 int* refcount)
171 pstring temp;
172 char* prot;
173 char* alt_path[MAX_REFERRAL_COUNT];
174 int count=0, i;
175 struct referral* reflist;
177 pstrcpy(temp,buf);
179 prot = strtok(temp,":");
181 if (!strequal(prot, "msdfs"))
182 return False;
184 /* No referral list requested. Just yes/no. */
185 if (!preflist)
186 return True;
188 /* parse out the alternate paths */
189 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
190 count++;
192 DEBUG(10,("parse_symlink: count=%d\n", count));
194 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
195 if(reflist == NULL) {
196 DEBUG(0,("parse_symlink: Malloc failed!\n"));
197 return False;
200 for(i=0;i<count;i++) {
201 char *p;
203 /* replace all /'s in the alternate path by a \ */
204 for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) {
205 *p = '\\';
208 /* Remove leading '\\'s */
209 p = alt_path[i];
210 while (*p && (*p == '\\')) {
211 p++;
214 pstrcpy(reflist[i].alternate_path, "\\");
215 pstrcat(reflist[i].alternate_path, p);
216 reflist[i].proximity = 0;
217 reflist[i].ttl = REFERRAL_TTL;
218 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
221 if(refcount)
222 *refcount = count;
224 return True;
227 /**********************************************************************
228 Returns true if the unix path is a valid msdfs symlink
229 **********************************************************************/
231 BOOL is_msdfs_link(connection_struct* conn, char * path,
232 struct referral** reflistp, int* refcnt,
233 SMB_STRUCT_STAT *sbufp)
235 SMB_STRUCT_STAT st;
236 pstring referral;
237 int referral_len = 0;
239 if (!path || !conn)
240 return False;
242 if (sbufp == NULL)
243 sbufp = &st;
245 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
246 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
247 return False;
250 if (S_ISLNK(sbufp->st_mode)) {
251 /* open the link and read it */
252 referral_len = SMB_VFS_READLINK(conn, path, referral,
253 sizeof(pstring));
254 if (referral_len == -1) {
255 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
256 return False;
259 referral[referral_len] = '\0';
260 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
261 if (parse_symlink(referral, reflistp, refcnt))
262 return True;
264 return False;
267 /*****************************************************************
268 Used by other functions to decide if a dfs path is remote,
269 and to get the list of referred locations for that remote path.
271 findfirst_flag: For findfirsts, dfs links themselves are not
272 redirected, but paths beyond the links are. For normal smb calls,
273 even dfs links need to be redirected.
275 self_referralp: clients expect a dfs referral for the same share when
276 they request referrals for dfs roots on a server.
278 consumedcntp: how much of the dfs path is being redirected. the client
279 should try the remaining path on the redirected server.
281 *****************************************************************/
283 static BOOL resolve_dfs_path(pstring dfspath, struct dfs_path* dp,
284 connection_struct* conn,
285 BOOL findfirst_flag,
286 struct referral** reflistpp, int* refcntp,
287 BOOL* self_referralp, int* consumedcntp)
289 pstring localpath;
290 int consumed_level = 1;
291 char *p;
292 BOOL bad_path = False;
293 SMB_STRUCT_STAT sbuf;
294 pstring reqpath;
296 if (!dp || !conn) {
297 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
298 return False;
301 if (dp->reqpath[0] == '\0') {
302 if (self_referralp) {
303 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
304 *self_referralp = True;
306 return False;
309 DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
311 unix_convert(dp->reqpath,conn,0,&bad_path,&sbuf);
312 /* JRA... should we strlower the last component here.... ? */
313 pstrcpy(localpath, dp->reqpath);
315 /* check if need to redirect */
316 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
317 if (findfirst_flag) {
318 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
319 "for dfs link %s.\n", dfspath));
320 return False;
321 } else {
322 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n",
323 dfspath));
324 if (consumedcntp)
325 *consumedcntp = strlen(dfspath);
326 return True;
330 /* redirect if any component in the path is a link */
331 pstrcpy(reqpath, dp->reqpath);
332 p = strrchr_m(reqpath, '/');
333 while (p) {
334 *p = '\0';
335 pstrcpy(localpath, reqpath);
336 if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
337 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
339 /* To find the path consumed, we truncate the original
340 DFS pathname passed to use to remove the last
341 component. The length of the resulting string is
342 the path consumed
344 if (consumedcntp) {
345 char *q;
346 pstring buf;
347 pstrcpy(buf, dfspath);
348 trim_char(buf, '\0', '\\');
349 for (; consumed_level; consumed_level--) {
350 q = strrchr_m(buf, '\\');
351 if (q)
352 *q = 0;
354 *consumedcntp = strlen(buf);
355 DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
358 return True;
360 p = strrchr_m(reqpath, '/');
361 consumed_level++;
364 return False;
367 /*****************************************************************
368 Decides if a dfs pathname should be redirected or not.
369 If not, the pathname is converted to a tcon-relative local unix path
370 *****************************************************************/
372 BOOL dfs_redirect(pstring pathname, connection_struct* conn,
373 BOOL findfirst_flag)
375 struct dfs_path dp;
377 if (!conn || !pathname)
378 return False;
380 parse_processed_dfs_path(pathname, &dp);
382 /* if dfs pathname for a non-dfs share, convert to tcon-relative
383 path and return false */
384 if (!lp_msdfs_root(SNUM(conn))) {
385 pstrcpy(pathname, dp.reqpath);
386 return False;
389 if (!strequal(dp.servicename, lp_servicename(SNUM(conn)) ))
390 return False;
392 if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag,
393 NULL, NULL, NULL, NULL)) {
394 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
395 return True;
396 } else {
397 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
399 /* Form non-dfs tcon-relative path */
400 pstrcpy(pathname, dp.reqpath);
401 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n",
402 pathname));
403 return False;
406 /* never reached */
409 /**********************************************************************
410 Gets valid referrals for a dfs path and fills up the
411 junction_map structure
412 **********************************************************************/
414 BOOL get_referred_path(char *pathname, struct junction_map* jucn,
415 int* consumedcntp, BOOL* self_referralp)
417 struct dfs_path dp;
419 struct connection_struct conns;
420 struct connection_struct* conn = &conns;
421 pstring conn_path;
422 int snum;
423 BOOL ret = False;
425 BOOL self_referral = False;
427 if (!pathname || !jucn)
428 return False;
430 if (self_referralp)
431 *self_referralp = False;
432 else
433 self_referralp = &self_referral;
435 parse_dfs_path(pathname, &dp);
437 /* Verify hostname in path */
438 if (local_machine && (!strequal(local_machine, dp.hostname))) {
439 /* Hostname mismatch, check if one of our IP addresses */
440 if (!ismyip(*interpret_addr2(dp.hostname))) {
441 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
442 dp.hostname, pathname));
443 return False;
447 pstrcpy(jucn->service_name, dp.servicename);
448 pstrcpy(jucn->volume_name, dp.reqpath);
450 /* Verify the share is a dfs root */
451 snum = lp_servicenumber(jucn->service_name);
452 if(snum < 0) {
453 if ((snum = find_service(jucn->service_name)) < 0)
454 return False;
457 pstrcpy(conn_path, lp_pathname(snum));
458 if (!create_conn_struct(conn, snum, conn_path))
459 return False;
461 if (!lp_msdfs_root(SNUM(conn))) {
462 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
463 dp.servicename, pathname));
464 goto out;
467 if (*lp_msdfs_proxy(snum) != '\0') {
468 struct referral* ref;
469 jucn->referral_count = 1;
470 if ((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
471 DEBUG(0, ("malloc failed for referral\n"));
472 goto out;
475 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
476 if (dp.reqpath[0] != '\0')
477 pstrcat(ref->alternate_path, dp.reqpath);
478 ref->proximity = 0;
479 ref->ttl = REFERRAL_TTL;
480 jucn->referral_list = ref;
481 if (consumedcntp)
482 *consumedcntp = strlen(pathname);
483 ret = True;
484 goto out;
487 /* If not remote & not a self referral, return False */
488 if (!resolve_dfs_path(pathname, &dp, conn, False,
489 &jucn->referral_list, &jucn->referral_count,
490 self_referralp, consumedcntp)) {
491 if (!*self_referralp) {
492 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
493 goto out;
497 /* if self_referral, fill up the junction map */
498 if (*self_referralp) {
499 struct referral* ref;
500 jucn->referral_count = 1;
501 if((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
502 DEBUG(0,("malloc failed for referral\n"));
503 goto out;
506 pstrcpy(ref->alternate_path,pathname);
507 ref->proximity = 0;
508 ref->ttl = REFERRAL_TTL;
509 jucn->referral_list = ref;
510 if (consumedcntp)
511 *consumedcntp = strlen(pathname);
514 ret = True;
515 out:
516 talloc_destroy( conn->mem_ctx );
518 return ret;
521 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
522 struct junction_map* junction,
523 int consumedcnt,
524 BOOL self_referral)
526 char* pdata = *ppdata;
528 unsigned char uni_requestedpath[1024];
529 int uni_reqpathoffset1,uni_reqpathoffset2;
530 int uni_curroffset;
531 int requestedpathlen=0;
532 int offset;
533 int reply_size = 0;
534 int i=0;
536 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
538 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
539 STR_TERMINATE);
541 dump_data(10, (const char *) uni_requestedpath,requestedpathlen);
543 DEBUG(10,("ref count = %u\n",junction->referral_count));
545 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
546 VERSION2_REFERRAL_SIZE * junction->referral_count;
548 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
550 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
552 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
553 2 * requestedpathlen;
554 DEBUG(10,("reply_size: %u\n",reply_size));
556 /* add up the unicode lengths of all the referral paths */
557 for(i=0;i<junction->referral_count;i++) {
558 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
559 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
562 DEBUG(10,("reply_size = %u\n",reply_size));
563 /* add the unexplained 0x16 bytes */
564 reply_size += 0x16;
566 pdata = Realloc(pdata,reply_size);
567 if(pdata == NULL) {
568 DEBUG(0,("malloc failed for Realloc!\n"));
569 return -1;
570 } else
571 *ppdata = pdata;
573 /* copy in the dfs requested paths.. required for offset calculations */
574 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
575 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
577 /* create the header */
578 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
579 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
580 if(self_referral)
581 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
582 else
583 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
585 offset = 8;
586 /* add the referral elements */
587 for(i=0;i<junction->referral_count;i++) {
588 struct referral* ref = &junction->referral_list[i];
589 int unilen;
591 SSVAL(pdata,offset,2); /* version 2 */
592 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
593 if(self_referral)
594 SSVAL(pdata,offset+4,1);
595 else
596 SSVAL(pdata,offset+4,0);
597 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
598 SIVAL(pdata,offset+8,ref->proximity);
599 SIVAL(pdata,offset+12,ref->ttl);
601 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
602 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
603 /* copy referred path into current offset */
604 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
605 -1, STR_UNICODE);
607 SSVAL(pdata,offset+20,uni_curroffset-offset);
609 uni_curroffset += unilen;
610 offset += VERSION2_REFERRAL_SIZE;
612 /* add in the unexplained 22 (0x16) bytes at the end */
613 memset(pdata+uni_curroffset,'\0',0x16);
614 return reply_size;
617 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
618 struct junction_map* junction,
619 int consumedcnt,
620 BOOL self_referral)
622 char* pdata = *ppdata;
624 unsigned char uni_reqpath[1024];
625 int uni_reqpathoffset1, uni_reqpathoffset2;
626 int uni_curroffset;
627 int reply_size = 0;
629 int reqpathlen = 0;
630 int offset,i=0;
632 DEBUG(10,("setting up version3 referral\n"));
634 reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
636 dump_data(10, (char *) uni_reqpath,reqpathlen);
638 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
639 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
640 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
642 for(i=0;i<junction->referral_count;i++) {
643 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
644 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
647 pdata = Realloc(pdata,reply_size);
648 if(pdata == NULL) {
649 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
650 return -1;
651 } else
652 *ppdata = pdata;
654 /* create the header */
655 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
656 SSVAL(pdata,2,junction->referral_count); /* number of referral */
657 if(self_referral)
658 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
659 else
660 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
662 /* copy in the reqpaths */
663 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
664 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
666 offset = 8;
667 for(i=0;i<junction->referral_count;i++) {
668 struct referral* ref = &(junction->referral_list[i]);
669 int unilen;
671 SSVAL(pdata,offset,3); /* version 3 */
672 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
673 if(self_referral)
674 SSVAL(pdata,offset+4,1);
675 else
676 SSVAL(pdata,offset+4,0);
678 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
679 SIVAL(pdata,offset+8,ref->ttl);
681 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
682 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
683 /* copy referred path into current offset */
684 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
685 -1, STR_UNICODE | STR_TERMINATE);
686 SSVAL(pdata,offset+16,uni_curroffset-offset);
687 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
688 memset(pdata+offset+18,'\0',16);
690 uni_curroffset += unilen;
691 offset += VERSION3_REFERRAL_SIZE;
693 return reply_size;
696 /******************************************************************
697 * Set up the Dfs referral for the dfs pathname
698 ******************************************************************/
700 int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char** ppdata)
702 struct junction_map junction;
703 int consumedcnt;
704 BOOL self_referral = False;
705 pstring buf;
706 int reply_size = 0;
707 char *pathnamep = pathname;
709 ZERO_STRUCT(junction);
711 /* get the junction entry */
712 if (!pathnamep)
713 return -1;
715 /* Trim pathname sent by client so it begins with only one backslash.
716 Two backslashes confuse some dfs clients
718 while (pathnamep[0] == '\\' && pathnamep[1] == '\\')
719 pathnamep++;
721 pstrcpy(buf, pathnamep);
722 /* The following call can change cwd. */
723 if (!get_referred_path(buf, &junction, &consumedcnt, &self_referral)) {
724 vfs_ChDir(orig_conn,orig_conn->connectpath);
725 return -1;
727 vfs_ChDir(orig_conn,orig_conn->connectpath);
729 if (!self_referral) {
730 pathnamep[consumedcnt] = '\0';
732 if( DEBUGLVL( 3 ) ) {
733 int i=0;
734 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
735 for(i=0;i<junction.referral_count;i++)
736 dbgtext(" %s",junction.referral_list[i].alternate_path);
737 dbgtext(".\n");
741 /* create the referral depeding on version */
742 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
743 if(max_referral_level<2 || max_referral_level>3)
744 max_referral_level = 2;
746 switch(max_referral_level) {
747 case 2:
748 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
749 consumedcnt, self_referral);
750 SAFE_FREE(junction.referral_list);
751 break;
752 case 3:
753 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
754 consumedcnt, self_referral);
755 SAFE_FREE(junction.referral_list);
756 break;
757 default:
758 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
759 return -1;
762 DEBUG(10,("DFS Referral pdata:\n"));
763 dump_data(10,*ppdata,reply_size);
764 return reply_size;
767 /**********************************************************************
768 The following functions are called by the NETDFS RPC pipe functions
769 **********************************************************************/
771 /**********************************************************************
772 Creates a junction structure from a Dfs pathname
773 **********************************************************************/
774 BOOL create_junction(char* pathname, struct junction_map* jucn)
776 struct dfs_path dp;
778 parse_dfs_path(pathname,&dp);
780 /* check if path is dfs : validate first token */
781 if (local_machine && (!strequal(local_machine,dp.hostname))) {
783 /* Hostname mismatch, check if one of our IP addresses */
784 if (!ismyip(*interpret_addr2(dp.hostname))) {
785 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
786 dp.hostname, pathname));
787 return False;
791 /* Check for a non-DFS share */
792 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
793 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
794 dp.servicename));
795 return False;
798 pstrcpy(jucn->service_name,dp.servicename);
799 pstrcpy(jucn->volume_name,dp.reqpath);
800 return True;
803 /**********************************************************************
804 Forms a valid Unix pathname from the junction
805 **********************************************************************/
807 static BOOL junction_to_local_path(struct junction_map* jucn, char* path,
808 int max_pathlen, connection_struct *conn)
810 int snum;
811 pstring conn_path;
813 if(!path || !jucn)
814 return False;
816 snum = lp_servicenumber(jucn->service_name);
817 if(snum < 0)
818 return False;
820 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
821 safe_strcat(path, "/", max_pathlen-1);
822 safe_strcat(path, jucn->volume_name, max_pathlen-1);
824 pstrcpy(conn_path, lp_pathname(snum));
825 if (!create_conn_struct(conn, snum, conn_path))
826 return False;
828 return True;
831 BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
833 pstring path;
834 pstring msdfs_link;
835 connection_struct conns;
836 connection_struct *conn = &conns;
837 int i=0;
838 BOOL insert_comma = False;
839 BOOL ret = False;
841 if(!junction_to_local_path(jucn, path, sizeof(path), conn))
842 return False;
844 /* form the msdfs_link contents */
845 pstrcpy(msdfs_link, "msdfs:");
846 for(i=0; i<jucn->referral_count; i++) {
847 char* refpath = jucn->referral_list[i].alternate_path;
849 trim_char(refpath, '\\', '\\');
850 if(*refpath == '\0') {
851 if (i == 0)
852 insert_comma = False;
853 continue;
855 if (i > 0 && insert_comma)
856 pstrcat(msdfs_link, ",");
858 pstrcat(msdfs_link, refpath);
859 if (!insert_comma)
860 insert_comma = True;
864 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
866 if(exists)
867 if(SMB_VFS_UNLINK(conn,path)!=0)
868 goto out;
870 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
871 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
872 path, msdfs_link, strerror(errno)));
873 goto out;
877 ret = True;
879 out:
880 talloc_destroy( conn->mem_ctx );
881 return ret;
884 BOOL remove_msdfs_link(struct junction_map* jucn)
886 pstring path;
887 connection_struct conns;
888 connection_struct *conn = &conns;
889 BOOL ret = False;
891 if( junction_to_local_path(jucn, path, sizeof(path), conn) ) {
892 if( SMB_VFS_UNLINK(conn, path) == 0 )
893 ret = True;
895 talloc_destroy( conn->mem_ctx );
898 return ret;
901 static BOOL form_junctions(int snum, struct junction_map* jucn, int* jn_count)
903 int cnt = *jn_count;
904 DIR *dirp;
905 char* dname;
906 pstring connect_path;
907 char* service_name = lp_servicename(snum);
908 connection_struct conns;
909 connection_struct *conn = &conns;
910 struct referral *ref = NULL;
911 BOOL ret = False;
913 pstrcpy(connect_path,lp_pathname(snum));
915 if(*connect_path == '\0')
916 return False;
919 * Fake up a connection struct for the VFS layer.
922 if (!create_conn_struct(conn, snum, connect_path))
923 return False;
925 /* form a junction for the msdfs root - convention
926 DO NOT REMOVE THIS: NT clients will not work with us
927 if this is not present
929 pstrcpy(jucn[cnt].service_name, service_name);
930 jucn[cnt].volume_name[0] = '\0';
931 jucn[cnt].referral_count = 1;
933 ref = jucn[cnt].referral_list
934 = (struct referral*) malloc(sizeof(struct referral));
935 if (jucn[cnt].referral_list == NULL) {
936 DEBUG(0, ("Malloc failed!\n"));
937 goto out;
940 ref->proximity = 0;
941 ref->ttl = REFERRAL_TTL;
942 if (*lp_msdfs_proxy(snum) != '\0') {
943 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
944 *jn_count = ++cnt;
945 ret = True;
946 goto out;
949 slprintf(ref->alternate_path, sizeof(pstring)-1,
950 "\\\\%s\\%s", local_machine, service_name);
951 cnt++;
953 /* Now enumerate all dfs links */
954 dirp = SMB_VFS_OPENDIR(conn, ".");
955 if(!dirp)
956 goto out;
958 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
959 if (is_msdfs_link(conn, dname, &(jucn[cnt].referral_list),
960 &(jucn[cnt].referral_count), NULL)) {
961 pstrcpy(jucn[cnt].service_name, service_name);
962 pstrcpy(jucn[cnt].volume_name, dname);
963 cnt++;
967 SMB_VFS_CLOSEDIR(conn,dirp);
968 *jn_count = cnt;
969 out:
970 talloc_destroy(conn->mem_ctx);
971 return ret;
974 int enum_msdfs_links(struct junction_map* jucn)
976 int i=0;
977 int jn_count = 0;
979 if(!lp_host_msdfs())
980 return 0;
982 for(i=0;i < lp_numservices();i++) {
983 if(lp_msdfs_root(i))
984 form_junctions(i,jucn,&jn_count);
986 return jn_count;