1/*
2   Unix SMB/Netbios implementation.
3   Version 3.0
4   MSDfs services for Samba
5   Copyright (C) Shirish Kalele 2000
6
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.
11
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.
16
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.
20
21*/
22
23#include "includes.h"
24
25extern uint32 global_client_caps;
26
27/**********************************************************************
28  Parse the pathname  of the form \hostname\service\reqpath
29  into the dfs_path structure
30 **********************************************************************/
31
32static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
33{
34	pstring pathname_local;
35	char* p,*temp;
36
37	pstrcpy(pathname_local,pathname);
38	p = temp = pathname_local;
39
40	ZERO_STRUCTP(pdp);
41
42	trim_char(temp,'\\','\\');
43	DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
44
45	/* now tokenize */
46	/* parse out hostname */
47	p = strchr_m(temp,'\\');
48	if(p == NULL)
49		return False;
50	*p = '\0';
51	pstrcpy(pdp->hostname,temp);
52	DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
53
54	/* parse out servicename */
55	temp = p+1;
56	p = strchr_m(temp,'\\');
57	if(p == NULL) {
58		pstrcpy(pdp->servicename,temp);
59		pdp->reqpath[0] = '\0';
60		return True;
61	}
62	*p = '\0';
63	pstrcpy(pdp->servicename,temp);
64	DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
65
66	/* rest is reqpath */
67	check_path_syntax(pdp->reqpath, p+1,True);
68
69	DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
70	return True;
71}
72
73/**********************************************************************
74  Parse the pathname  of the form /hostname/service/reqpath
75  into the dfs_path structure
76 **********************************************************************/
77
78static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path* pdp)
79{
80	pstring pathname_local;
81	char* p,*temp;
82
83	pstrcpy(pathname_local,pathname);
84	p = temp = pathname_local;
85
86	ZERO_STRUCTP(pdp);
87
88	trim_char(temp,'/','/');
89	DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming \\'s\n",temp));
90
91	/* now tokenize */
92	/* parse out hostname */
93	p = strchr_m(temp,'/');
94	if(p == NULL)
95		return False;
96	*p = '\0';
97	pstrcpy(pdp->hostname,temp);
98	DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname));
99
100	/* parse out servicename */
101	temp = p+1;
102	p = strchr_m(temp,'/');
103	if(p == NULL) {
104		pstrcpy(pdp->servicename,temp);
105		pdp->reqpath[0] = '\0';
106		return True;
107	}
108	*p = '\0';
109	pstrcpy(pdp->servicename,temp);
110	DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
111
112	/* rest is reqpath */
113	check_path_syntax(pdp->reqpath, p+1,True);
114
115	DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
116	return True;
117}
118
119/********************************************************
120 Fake up a connection struct for the VFS layer.
121 Note this CHANGES CWD !!!! JRA.
122*********************************************************/
123
124static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
125{
126	ZERO_STRUCTP(conn);
127	conn->service = snum;
128	conn->connectpath = path;
129	pstring_sub(conn->connectpath , "%S", lp_servicename(snum));
130
131	/* needed for smbd_vfs_init() */
132
133        if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
134                DEBUG(0,("talloc_init(connection_struct) failed!\n"));
135                return False;
136        }
137
138	if (!smbd_vfs_init(conn)) {
139		DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
140		talloc_destroy( conn->mem_ctx );
141		return False;
142	}
143
144	/*
145	 * Windows seems to insist on doing trans2getdfsreferral() calls on the IPC$
146	 * share as the anonymous user. If we try to chdir as that user we will
147	 * fail.... WTF ? JRA.
148	 */
149
150	if (vfs_ChDir(conn,conn->connectpath) != 0) {
151		DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. Error was %s\n",
152					conn->connectpath, strerror(errno) ));
153		talloc_destroy( conn->mem_ctx );
154		return False;
155	}
156	return True;
157}
158
159
160/**********************************************************************
161 Parse the contents of a symlink to verify if it is an msdfs referral
162 A valid referral is of the form: msdfs:server1\share1,server2\share2
163 **********************************************************************/
164
165static BOOL parse_symlink(char* buf,struct referral** preflist,
166				 int* refcount)
167{
168	pstring temp;
169	char* prot;
170	char* alt_path[MAX_REFERRAL_COUNT];
171	int count=0, i;
172	struct referral* reflist;
173
174	pstrcpy(temp,buf);
175
176	prot = strtok(temp,":");
177
178	if (!strequal(prot, "msdfs"))
179		return False;
180
181	/* No referral list requested. Just yes/no. */
182	if (!preflist)
183		return True;
184
185	/* parse out the alternate paths */
186	while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
187		count++;
188
189	DEBUG(10,("parse_symlink: count=%d\n", count));
190
191	reflist = *preflist = SMB_MALLOC_ARRAY(struct referral, count);
192	if(reflist == NULL) {
193		DEBUG(0,("parse_symlink: Malloc failed!\n"));
194		return False;
195	}
196
197	for(i=0;i<count;i++) {
198		char *p;
199
200		/* replace all /'s in the alternate path by a \ */
201		for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) {
202			*p = '\\';
203		}
204
205		/* Remove leading '\\'s */
206		p = alt_path[i];
207		while (*p && (*p == '\\')) {
208			p++;
209		}
210
211		pstrcpy(reflist[i].alternate_path, "\\");
212		pstrcat(reflist[i].alternate_path, p);
213		reflist[i].proximity = 0;
214		reflist[i].ttl = REFERRAL_TTL;
215		DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
216	}
217
218	if(refcount)
219		*refcount = count;
220
221	return True;
222}
223
224/**********************************************************************
225 Returns true if the unix path is a valid msdfs symlink
226 **********************************************************************/
227
228BOOL is_msdfs_link(connection_struct* conn, char * path,
229		   struct referral** reflistp, int* refcnt,
230		   SMB_STRUCT_STAT *sbufp)
231{
232	SMB_STRUCT_STAT st;
233	pstring referral;
234	int referral_len = 0;
235
236	if (!path || !conn)
237		return False;
238
239	if (sbufp == NULL)
240		sbufp = &st;
241
242	if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
243		DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
244		return False;
245	}
246
247	if (S_ISLNK(sbufp->st_mode)) {
248		/* open the link and read it */
249		referral_len = SMB_VFS_READLINK(conn, path, referral,
250						      sizeof(pstring));
251		if (referral_len == -1) {
252			DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
253			return False;
254		}
255
256		referral[referral_len] = '\0';
257		DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
258		if (parse_symlink(referral, reflistp, refcnt))
259			return True;
260	}
261	return False;
262}
263
264/*****************************************************************
265 Used by other functions to decide if a dfs path is remote,
266and to get the list of referred locations for that remote path.
267
268findfirst_flag: For findfirsts, dfs links themselves are not
269redirected, but paths beyond the links are. For normal smb calls,
270even dfs links need to be redirected.
271
272self_referralp: clients expect a dfs referral for the same share when
273they request referrals for dfs roots on a server.
274
275consumedcntp: how much of the dfs path is being redirected. the client
276should try the remaining path on the redirected server.
277
278*****************************************************************/
279
280static BOOL resolve_dfs_path(pstring dfspath, struct dfs_path* dp,
281		      connection_struct* conn,
282		      BOOL findfirst_flag,
283		      struct referral** reflistpp, int* refcntp,
284		      BOOL* self_referralp, int* consumedcntp)
285{
286	pstring localpath;
287	int consumed_level = 1;
288	char *p;
289	BOOL bad_path = False;
290	SMB_STRUCT_STAT sbuf;
291	pstring reqpath;
292
293	if (!dp || !conn) {
294		DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
295		return False;
296	}
297
298	if (dp->reqpath[0] == '\0') {
299		if (self_referralp) {
300			DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
301			*self_referralp = True;
302		}
303		return False;
304	}
305
306	DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
307
308	unix_convert(dp->reqpath,conn,0,&bad_path,&sbuf);
309	/* JRA... should we strlower the last component here.... ? */
310	pstrcpy(localpath, dp->reqpath);
311
312	/* check if need to redirect */
313	if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
314		if (findfirst_flag) {
315			DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
316				 "for dfs link %s.\n", dfspath));
317			return False;
318		} else {
319			DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n",
320				 dfspath));
321			if (consumedcntp)
322				*consumedcntp = strlen(dfspath);
323			return True;
324		}
325	}
326
327	/* redirect if any component in the path is a link */
328	pstrcpy(reqpath, dp->reqpath);
329	p = strrchr_m(reqpath, '/');
330	while (p) {
331		*p = '\0';
332		pstrcpy(localpath, reqpath);
333		if (is_msdfs_link(conn, localpath, reflistpp, refcntp, NULL)) {
334			DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
335
336			/* To find the path consumed, we truncate the original
337			   DFS pathname passed to use to remove the last
338			   component. The length of the resulting string is
339			   the path consumed
340			*/
341			if (consumedcntp) {
342				char *q;
343				pstring buf;
344				pstrcpy(buf, dfspath);
345				trim_char(buf, '\0', '\\');
346				for (; consumed_level; consumed_level--) {
347					q = strrchr_m(buf, '\\');
348					if (q)
349						*q = 0;
350				}
351				*consumedcntp = strlen(buf);
352				DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
353			}
354
355			return True;
356		}
357		p = strrchr_m(reqpath, '/');
358		consumed_level++;
359	}
360
361	return False;
362}
363
364/*****************************************************************
365  Decides if a dfs pathname should be redirected or not.
366  If not, the pathname is converted to a tcon-relative local unix path
367*****************************************************************/
368
369BOOL dfs_redirect(pstring pathname, connection_struct* conn,
370		  BOOL findfirst_flag)
371{
372	struct dfs_path dp;
373
374	if (!conn || !pathname)
375		return False;
376
377	parse_processed_dfs_path(pathname, &dp);
378
379	/* if dfs pathname for a non-dfs share, convert to tcon-relative
380	   path and return false */
381	if (!lp_msdfs_root(SNUM(conn))) {
382		pstrcpy(pathname, dp.reqpath);
383		return False;
384	}
385
386	if (!strequal(dp.servicename, lp_servicename(SNUM(conn)) ))
387		return False;
388
389	if (resolve_dfs_path(pathname, &dp, conn, findfirst_flag,
390			     NULL, NULL, NULL, NULL)) {
391		DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
392		return True;
393	} else {
394		DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
395
396		/* Form non-dfs tcon-relative path */
397		pstrcpy(pathname, dp.reqpath);
398		DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n",
399			 pathname));
400		return False;
401	}
402
403	/* never reached */
404}
405
406/**********************************************************************
407 Return a self referral.
408**********************************************************************/
409
410static BOOL self_ref(char *pathname, struct junction_map *jucn,
411			int *consumedcntp, BOOL *self_referralp)
412{
413	struct referral *ref;
414
415	if (self_referralp != NULL)
416		*self_referralp = True;
417
418	jucn->referral_count = 1;
419	if((ref = SMB_MALLOC_P(struct referral)) == NULL) {
420		DEBUG(0,("self_ref: malloc failed for referral\n"));
421		return False;
422	}
423
424	pstrcpy(ref->alternate_path,pathname);
425	ref->proximity = 0;
426	ref->ttl = REFERRAL_TTL;
427	jucn->referral_list = ref;
428	if (consumedcntp)
429		*consumedcntp = strlen(pathname);
430
431	return True;
432}
433
434/**********************************************************************
435 Gets valid referrals for a dfs path and fills up the
436 junction_map structure
437**********************************************************************/
438
439BOOL get_referred_path(char *pathname, struct junction_map *jucn,
440		       int *consumedcntp, BOOL *self_referralp)
441{
442	struct dfs_path dp;
443
444	struct connection_struct conns;
445	struct connection_struct* conn = &conns;
446	pstring conn_path;
447	int snum;
448	BOOL ret = False;
449	BOOL self_referral = False;
450
451	if (!pathname || !jucn)
452		return False;
453
454	ZERO_STRUCT(conns);
455
456	if (self_referralp)
457		*self_referralp = False;
458	else
459		self_referralp = &self_referral;
460
461	parse_dfs_path(pathname, &dp);
462
463	/* Verify hostname in path */
464	if ( !strequal(get_local_machine_name(), dp.hostname) ) {
465		/* Hostname mismatch, check if one of our IP addresses */
466		if (!ismyip(*interpret_addr2(dp.hostname))) {
467			DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
468				dp.hostname, pathname));
469			return False;
470		}
471	}
472
473	pstrcpy(jucn->service_name, dp.servicename);
474	pstrcpy(jucn->volume_name, dp.reqpath);
475
476	/* Verify the share is a dfs root */
477	snum = lp_servicenumber(jucn->service_name);
478	if(snum < 0) {
479		if ((snum = find_service(jucn->service_name)) < 0)
480			return False;
481	}
482
483	if (!lp_msdfs_root(snum)) {
484		DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
485			 dp.servicename, pathname));
486		goto out;
487	}
488
489	/*
490	 * Self referrals are tested with a anonymous IPC connection and
491	 * a GET_DFS_REFERRAL call to \\server\share. (which means dp.reqpath[0] points
492	 * to an empty string). create_conn_struct cd's into the directory and will
493	 * fail if it cannot (as the anonymous user). Cope with this.
494	 */
495
496	if (dp.reqpath[0] == '\0') {
497
498		struct referral* ref;
499
500		if (*lp_msdfs_proxy(snum) == '\0')
501			return self_ref(pathname, jucn, consumedcntp,
502					self_referralp);
503
504		jucn->referral_count = 1;
505		if ((ref = SMB_MALLOC_P(struct referral)) == NULL) {
506			DEBUG(0, ("malloc failed for referral\n"));
507			goto out;
508		}
509
510		pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
511		if (dp.reqpath[0] != '\0')
512			pstrcat(ref->alternate_path, dp.reqpath);
513		ref->proximity = 0;
514		ref->ttl = REFERRAL_TTL;
515		jucn->referral_list = ref;
516		if (consumedcntp)
517			*consumedcntp = strlen(pathname);
518		ret = True;
519		goto out;
520	}
521
522	pstrcpy(conn_path, lp_pathname(snum));
523	if (!create_conn_struct(conn, snum, conn_path))
524		return False;
525
526	/* If not remote & not a self referral, return False */
527	if (!resolve_dfs_path(pathname, &dp, conn, False,
528			      &jucn->referral_list, &jucn->referral_count,
529			      self_referralp, consumedcntp)) {
530		if (!*self_referralp) {
531			DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
532			goto out;
533		}
534	}
535
536	/* if self_referral, fill up the junction map */
537	if (*self_referralp) {
538		if (self_ref(pathname, jucn, consumedcntp, self_referralp) == False) {
539			goto out;
540		}
541	}
542
543	ret = True;
544
545out:
546	if (conn->mem_ctx)
547		talloc_destroy( conn->mem_ctx );
548
549	return ret;
550}
551
552static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
553				   struct junction_map* junction,
554				   int consumedcnt,
555				   BOOL self_referral)
556{
557	char* pdata = *ppdata;
558
559	unsigned char uni_requestedpath[1024];
560	int uni_reqpathoffset1,uni_reqpathoffset2;
561	int uni_curroffset;
562	int requestedpathlen=0;
563	int offset;
564	int reply_size = 0;
565	int i=0;
566
567	DEBUG(10,("setting up version2 referral\nRequested path:\n"));
568
569	requestedpathlen = rpcstr_push(uni_requestedpath, pathname, -1,
570				       STR_TERMINATE);
571
572	dump_data(10, (const char *) uni_requestedpath,requestedpathlen);
573
574	DEBUG(10,("ref count = %u\n",junction->referral_count));
575
576	uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
577			VERSION2_REFERRAL_SIZE * junction->referral_count;
578
579	uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
580
581	uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
582
583	reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
584					2 * requestedpathlen;
585	DEBUG(10,("reply_size: %u\n",reply_size));
586
587	/* add up the unicode lengths of all the referral paths */
588	for(i=0;i<junction->referral_count;i++) {
589		DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
590		reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
591	}
592
593	DEBUG(10,("reply_size = %u\n",reply_size));
594	/* add the unexplained 0x16 bytes */
595	reply_size += 0x16;
596
597	pdata = SMB_REALLOC(pdata,reply_size);
598	if(pdata == NULL) {
599		DEBUG(0,("malloc failed for Realloc!\n"));
600		return -1;
601	} else
602		*ppdata = pdata;
603
604	/* copy in the dfs requested paths.. required for offset calculations */
605	memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
606	memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
607
608	/* create the header */
609	SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
610	SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
611	if(self_referral)
612		SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
613	else
614		SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
615
616	offset = 8;
617	/* add the referral elements */
618	for(i=0;i<junction->referral_count;i++) {
619		struct referral* ref = &junction->referral_list[i];
620		int unilen;
621
622		SSVAL(pdata,offset,2); /* version 2 */
623		SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
624		if(self_referral)
625			SSVAL(pdata,offset+4,1);
626		else
627			SSVAL(pdata,offset+4,0);
628		SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
629		SIVAL(pdata,offset+8,ref->proximity);
630		SIVAL(pdata,offset+12,ref->ttl);
631
632		SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
633		SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
634		/* copy referred path into current offset */
635		unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
636				     -1, STR_UNICODE);
637
638		SSVAL(pdata,offset+20,uni_curroffset-offset);
639
640		uni_curroffset += unilen;
641		offset += VERSION2_REFERRAL_SIZE;
642	}
643	/* add in the unexplained 22 (0x16) bytes at the end */
644	memset(pdata+uni_curroffset,'\0',0x16);
645	return reply_size;
646}
647
648static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
649				   struct junction_map* junction,
650				   int consumedcnt,
651				   BOOL self_referral)
652{
653	char* pdata = *ppdata;
654
655	unsigned char uni_reqpath[1024];
656	int uni_reqpathoffset1, uni_reqpathoffset2;
657	int uni_curroffset;
658	int reply_size = 0;
659
660	int reqpathlen = 0;
661	int offset,i=0;
662
663	DEBUG(10,("setting up version3 referral\n"));
664
665	reqpathlen = rpcstr_push(uni_reqpath, pathname, -1, STR_TERMINATE);
666
667	dump_data(10, (char *) uni_reqpath,reqpathlen);
668
669	uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
670	uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
671	reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
672
673	for(i=0;i<junction->referral_count;i++) {
674		DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
675		reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
676	}
677
678	pdata = SMB_REALLOC(pdata,reply_size);
679	if(pdata == NULL) {
680		DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
681		return -1;
682	} else
683		*ppdata = pdata;
684
685	/* create the header */
686	SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
687	SSVAL(pdata,2,junction->referral_count); /* number of referral */
688	if(self_referral)
689		SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
690	else
691		SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
692
693	/* copy in the reqpaths */
694	memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
695	memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
696
697	offset = 8;
698	for(i=0;i<junction->referral_count;i++) {
699		struct referral* ref = &(junction->referral_list[i]);
700		int unilen;
701
702		SSVAL(pdata,offset,3); /* version 3 */
703		SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
704		if(self_referral)
705			SSVAL(pdata,offset+4,1);
706		else
707			SSVAL(pdata,offset+4,0);
708
709		SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
710		SIVAL(pdata,offset+8,ref->ttl);
711
712		SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
713		SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
714		/* copy referred path into current offset */
715		unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
716				     -1, STR_UNICODE | STR_TERMINATE);
717		SSVAL(pdata,offset+16,uni_curroffset-offset);
718		/* copy 0x10 bytes of 00's in the ServiceSite GUID */
719		memset(pdata+offset+18,'\0',16);
720
721		uni_curroffset += unilen;
722		offset += VERSION3_REFERRAL_SIZE;
723	}
724	return reply_size;
725}
726
727/******************************************************************
728 * Set up the Dfs referral for the dfs pathname
729 ******************************************************************/
730
731int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char** ppdata)
732{
733	struct junction_map junction;
734	int consumedcnt;
735	BOOL self_referral = False;
736	pstring buf;
737	int reply_size = 0;
738	char *pathnamep = pathname;
739
740	ZERO_STRUCT(junction);
741
742	/* get the junction entry */
743	if (!pathnamep)
744		return -1;
745
746	/* Trim pathname sent by client so it begins with only one backslash.
747	   Two backslashes confuse some dfs clients
748	 */
749	while (pathnamep[0] == '\\' && pathnamep[1] == '\\')
750		pathnamep++;
751
752	pstrcpy(buf, pathnamep);
753	/* The following call can change cwd. */
754	if (!get_referred_path(buf, &junction, &consumedcnt, &self_referral)) {
755		vfs_ChDir(orig_conn,orig_conn->connectpath);
756		return -1;
757	}
758	vfs_ChDir(orig_conn,orig_conn->connectpath);
759
760	if (!self_referral) {
761		pathnamep[consumedcnt] = '\0';
762
763		if( DEBUGLVL( 3 ) ) {
764			int i=0;
765			dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
766			for(i=0;i<junction.referral_count;i++)
767				dbgtext(" %s",junction.referral_list[i].alternate_path);
768			dbgtext(".\n");
769		}
770	}
771
772	/* create the referral depeding on version */
773	DEBUG(10,("max_referral_level :%d\n",max_referral_level));
774	if(max_referral_level<2 || max_referral_level>3)
775		max_referral_level = 2;
776
777	switch(max_referral_level) {
778	case 2:
779		reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
780						     consumedcnt, self_referral);
781		SAFE_FREE(junction.referral_list);
782		break;
783	case 3:
784		reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
785						     consumedcnt, self_referral);
786		SAFE_FREE(junction.referral_list);
787		break;
788	default:
789		DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
790		return -1;
791	}
792
793	DEBUG(10,("DFS Referral pdata:\n"));
794	dump_data(10,*ppdata,reply_size);
795	return reply_size;
796}
797
798/**********************************************************************
799 The following functions are called by the NETDFS RPC pipe functions
800 **********************************************************************/
801
802/**********************************************************************
803 Creates a junction structure from a Dfs pathname
804 **********************************************************************/
805BOOL create_junction(char* pathname, struct junction_map* jucn)
806{
807        struct dfs_path dp;
808
809        parse_dfs_path(pathname,&dp);
810
811        /* check if path is dfs : validate first token */
812        if ( !strequal(get_local_machine_name(),dp.hostname) ) {
813
814	   /* Hostname mismatch, check if one of our IP addresses */
815	   if (!ismyip(*interpret_addr2(dp.hostname))) {
816                DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
817			 dp.hostname, pathname));
818                return False;
819	   }
820        }
821
822        /* Check for a non-DFS share */
823        if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
824                DEBUG(4,("create_junction: %s is not an msdfs root.\n",
825			 dp.servicename));
826                return False;
827        }
828
829        pstrcpy(jucn->service_name,dp.servicename);
830        pstrcpy(jucn->volume_name,dp.reqpath);
831        return True;
832}
833
834/**********************************************************************
835 Forms a valid Unix pathname from the junction
836 **********************************************************************/
837
838static BOOL junction_to_local_path(struct junction_map* jucn, char* path,
839				   int max_pathlen, connection_struct *conn)
840{
841	int snum;
842	pstring conn_path;
843
844	if(!path || !jucn)
845		return False;
846
847	snum = lp_servicenumber(jucn->service_name);
848	if(snum < 0)
849		return False;
850
851	safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
852	safe_strcat(path, "/", max_pathlen-1);
853	safe_strcat(path, jucn->volume_name, max_pathlen-1);
854
855	pstrcpy(conn_path, lp_pathname(snum));
856	if (!create_conn_struct(conn, snum, conn_path))
857		return False;
858
859	return True;
860}
861
862BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
863{
864	pstring path;
865	pstring msdfs_link;
866	connection_struct conns;
867 	connection_struct *conn = &conns;
868	int i=0;
869	BOOL insert_comma = False;
870	BOOL ret = False;
871
872	if(!junction_to_local_path(jucn, path, sizeof(path), conn))
873		return False;
874
875	/* form the msdfs_link contents */
876	pstrcpy(msdfs_link, "msdfs:");
877	for(i=0; i<jucn->referral_count; i++) {
878		char* refpath = jucn->referral_list[i].alternate_path;
879
880		trim_char(refpath, '\\', '\\');
881		if(*refpath == '\0') {
882			if (i == 0)
883				insert_comma = False;
884			continue;
885		}
886		if (i > 0 && insert_comma)
887			pstrcat(msdfs_link, ",");
888
889		pstrcat(msdfs_link, refpath);
890		if (!insert_comma)
891			insert_comma = True;
892
893	}
894
895	DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
896
897	if(exists)
898		if(SMB_VFS_UNLINK(conn,path)!=0)
899			goto out;
900
901	if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
902		DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
903				path, msdfs_link, strerror(errno)));
904		goto out;
905	}
906
907
908	ret = True;
909
910out:
911	talloc_destroy( conn->mem_ctx );
912	return ret;
913}
914
915BOOL remove_msdfs_link(struct junction_map* jucn)
916{
917	pstring path;
918	connection_struct conns;
919 	connection_struct *conn = &conns;
920	BOOL ret = False;
921
922	if( junction_to_local_path(jucn, path, sizeof(path), conn) ) {
923		if( SMB_VFS_UNLINK(conn, path) == 0 )
924			ret = True;
925
926		talloc_destroy( conn->mem_ctx );
927	}
928
929	return ret;
930}
931
932static BOOL form_junctions(int snum, struct junction_map* jucn, int* jn_count)
933{
934	int cnt = *jn_count;
935	DIR *dirp;
936	char* dname;
937	pstring connect_path;
938	char* service_name = lp_servicename(snum);
939	connection_struct conns;
940	connection_struct *conn = &conns;
941	struct referral *ref = NULL;
942	BOOL ret = False;
943
944	pstrcpy(connect_path,lp_pathname(snum));
945
946	if(*connect_path == '\0')
947		return False;
948
949	/*
950	 * Fake up a connection struct for the VFS layer.
951	 */
952
953	if (!create_conn_struct(conn, snum, connect_path))
954		return False;
955
956	/* form a junction for the msdfs root - convention
957	   DO NOT REMOVE THIS: NT clients will not work with us
958	   if this is not present
959	*/
960	pstrcpy(jucn[cnt].service_name, service_name);
961	jucn[cnt].volume_name[0] = '\0';
962	jucn[cnt].referral_count = 1;
963
964	ref = jucn[cnt].referral_list = SMB_MALLOC_P(struct referral);
965	if (jucn[cnt].referral_list == NULL) {
966		DEBUG(0, ("Malloc failed!\n"));
967		goto out;
968	}
969
970	ref->proximity = 0;
971	ref->ttl = REFERRAL_TTL;
972	if (*lp_msdfs_proxy(snum) != '\0') {
973		pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
974		*jn_count = ++cnt;
975		ret = True;
976		goto out;
977	}
978
979	slprintf(ref->alternate_path, sizeof(pstring)-1,
980		 "\\\\%s\\%s", get_local_machine_name(), service_name);
981	cnt++;
982
983	/* Now enumerate all dfs links */
984	dirp = SMB_VFS_OPENDIR(conn, ".");
985	if(!dirp)
986		goto out;
987
988	while((dname = vfs_readdirname(conn, dirp)) != NULL) {
989		if (is_msdfs_link(conn, dname, &(jucn[cnt].referral_list),
990				  &(jucn[cnt].referral_count), NULL)) {
991			pstrcpy(jucn[cnt].service_name, service_name);
992			pstrcpy(jucn[cnt].volume_name, dname);
993			cnt++;
994		}
995	}
996
997	SMB_VFS_CLOSEDIR(conn,dirp);
998	*jn_count = cnt;
999out:
1000	talloc_destroy(conn->mem_ctx);
1001	return ret;
1002}
1003
1004int enum_msdfs_links(struct junction_map* jucn)
1005{
1006	int i=0;
1007	int jn_count = 0;
1008
1009	if(!lp_host_msdfs())
1010		return 0;
1011
1012	for(i=0;i < lp_numservices();i++) {
1013		if(lp_msdfs_root(i))
1014			form_junctions(i,jucn,&jn_count);
1015	}
1016	return jn_count;
1017}
1018