2 Unix SMB/Netbios implementation.
4 MSDfs services for Samba
5 Copyright (C) Shirish Kalele 2000
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #define DBGC_CLASS DBGC_MSDFS
27 extern uint32 global_client_caps;
29 /**********************************************************************
30 Parse the pathname of the form \hostname\service\reqpath
31 into the dfs_path structure
32 **********************************************************************/
34 static BOOL parse_dfs_path(const char *pathname, struct dfs_path *pdp)
36 pstring pathname_local;
39 pstrcpy(pathname_local,pathname);
40 p = temp = pathname_local;
44 trim_char(temp,'\\','\\');
45 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
48 /* parse out hostname */
49 p = strchr_m(temp,'\\');
54 pstrcpy(pdp->hostname,temp);
55 DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
57 /* parse out servicename */
59 p = strchr_m(temp,'\\');
61 pstrcpy(pdp->servicename,temp);
62 pdp->reqpath[0] = '\0';
66 pstrcpy(pdp->servicename,temp);
67 DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
70 check_path_syntax(pdp->reqpath, p+1);
72 DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
76 /**********************************************************************
77 Parse the pathname of the form /hostname/service/reqpath
78 into the dfs_path structure
79 This code is dependent on the fact that check_path_syntax() will
80 convert '\\' characters to '/'.
81 **********************************************************************/
83 static BOOL parse_processed_dfs_path(char* pathname, struct dfs_path *pdp, BOOL allow_wcards)
85 pstring pathname_local;
87 const char sepchar = '/';
89 pstrcpy(pathname_local,pathname);
90 p = temp = pathname_local;
94 trim_char(temp,sepchar,sepchar);
95 DEBUG(10,("temp in parse_processed_dfs_path: .%s. after trimming /'s\n",temp));
98 /* parse out hostname */
99 p = strchr_m(temp,sepchar);
104 pstrcpy(pdp->hostname,temp);
105 DEBUG(10,("parse_processed_dfs_path: hostname: %s\n",pdp->hostname));
107 /* parse out servicename */
109 p = strchr_m(temp,sepchar);
111 pstrcpy(pdp->servicename,temp);
112 pdp->reqpath[0] = '\0';
116 pstrcpy(pdp->servicename,temp);
117 DEBUG(10,("parse_processed_dfs_path: servicename: %s\n",pdp->servicename));
119 /* rest is reqpath */
121 BOOL path_contains_wcard;
122 check_path_syntax_wcard(pdp->reqpath, p+1, &path_contains_wcard);
124 check_path_syntax(pdp->reqpath, p+1);
127 DEBUG(10,("parse_processed_dfs_path: rest of the path: %s\n",pdp->reqpath));
131 /********************************************************
132 Fake up a connection struct for the VFS layer.
133 Note this CHANGES CWD !!!! JRA.
134 *********************************************************/
136 static BOOL create_conn_struct(connection_struct *conn, int snum, char *path)
142 pstrcpy(connpath, path);
143 pstring_sub(connpath , "%S", lp_servicename(snum));
145 /* needed for smbd_vfs_init() */
147 if ( (conn->mem_ctx=talloc_init("connection_struct")) == NULL ) {
148 DEBUG(0,("talloc_init(connection_struct) failed!\n"));
152 if (!(conn->params = TALLOC_P(conn->mem_ctx, struct share_params))) {
153 DEBUG(0, ("TALLOC failed\n"));
157 conn->params->service = snum;
159 set_conn_connectpath(conn, connpath);
161 if (!smbd_vfs_init(conn)) {
162 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
163 conn_free_internal(conn);
168 * Windows seems to insist on doing trans2getdfsreferral() calls on the IPC$
169 * share as the anonymous user. If we try to chdir as that user we will
170 * fail.... WTF ? JRA.
173 if (vfs_ChDir(conn,conn->connectpath) != 0) {
174 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. Error was %s\n",
175 conn->connectpath, strerror(errno) ));
176 conn_free_internal(conn);
183 /**********************************************************************
184 Parse the contents of a symlink to verify if it is an msdfs referral
185 A valid referral is of the form: msdfs:server1\share1,server2\share2
186 talloc CTX can be NULL here if preflist and refcount pointers are null.
187 **********************************************************************/
189 static BOOL parse_symlink(TALLOC_CTX *ctx, char *buf, struct referral **preflist, int *refcount)
193 char *alt_path[MAX_REFERRAL_COUNT];
195 struct referral *reflist;
199 prot = strtok(temp,":");
201 if (!strequal(prot, "msdfs")) {
205 /* No referral list requested. Just yes/no. */
211 DEBUG(0,("parse_symlink: logic error. TALLOC_CTX should not be null.\n"));
215 /* parse out the alternate paths */
216 while((count<MAX_REFERRAL_COUNT) &&
217 ((alt_path[count] = strtok(NULL,",")) != NULL)) {
221 DEBUG(10,("parse_symlink: count=%d\n", count));
223 reflist = *preflist = TALLOC_ARRAY(ctx, struct referral, count);
224 if(reflist == NULL) {
225 DEBUG(0,("parse_symlink: talloc failed!\n"));
229 for(i=0;i<count;i++) {
232 /* replace all /'s in the alternate path by a \ */
233 for(p = alt_path[i]; *p && ((p = strchr_m(p,'/'))!=NULL); p++) {
237 /* Remove leading '\\'s */
239 while (*p && (*p == '\\')) {
243 pstrcpy(reflist[i].alternate_path, "\\");
244 pstrcat(reflist[i].alternate_path, p);
245 reflist[i].proximity = 0;
246 reflist[i].ttl = REFERRAL_TTL;
247 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
257 /**********************************************************************
258 Returns true if the unix path is a valid msdfs symlink
259 talloc CTX can be NULL here if reflistp and refcnt pointers are null.
260 **********************************************************************/
262 BOOL is_msdfs_link(TALLOC_CTX *ctx, connection_struct *conn, const char *path,
263 struct referral **reflistp, int *refcnt,
264 SMB_STRUCT_STAT *sbufp)
268 int referral_len = 0;
270 if (!path || !conn) {
278 if (SMB_VFS_LSTAT(conn, path, sbufp) != 0) {
279 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
283 if (S_ISLNK(sbufp->st_mode)) {
284 /* open the link and read it */
285 referral_len = SMB_VFS_READLINK(conn, path, referral, sizeof(pstring)-1);
286 if (referral_len == -1) {
287 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
291 referral[referral_len] = '\0';
292 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
293 if (parse_symlink(ctx, referral, reflistp, refcnt)) {
300 /*****************************************************************
301 Used by other functions to decide if a dfs path is remote,
302 and to get the list of referred locations for that remote path.
304 findfirst_flag: For findfirsts, dfs links themselves are not
305 redirected, but paths beyond the links are. For normal smb calls,
306 even dfs links need to be redirected.
308 self_referralp: clients expect a dfs referral for the same share when
309 they request referrals for dfs roots on a server.
311 consumedcntp: how much of the dfs path is being redirected. the client
312 should try the remaining path on the redirected server.
314 TALLOC_CTX can be NULL here if struct referral **reflistpp, int *refcntp
316 *****************************************************************/
318 static BOOL resolve_dfs_path(TALLOC_CTX *ctx,
321 connection_struct *conn,
323 struct referral **reflistpp,
325 BOOL *self_referralp,
329 int consumed_level = 1;
331 SMB_STRUCT_STAT sbuf;
336 DEBUG(1,("resolve_dfs_path: NULL dfs_path* or NULL connection_struct*!\n"));
340 if (!ctx && (reflistpp || refcntp)) {
341 DEBUG(0,("resolve_dfs_path: logic error. TALLOC_CTX must not be NULL.\n"));
344 if (dp->reqpath[0] == '\0') {
345 if (self_referralp) {
346 DEBUG(6,("resolve_dfs_path: self-referral. returning False\n"));
347 *self_referralp = True;
352 DEBUG(10,("resolve_dfs_path: Conn path = %s req_path = %s\n", conn->connectpath, dp->reqpath));
355 * Note the unix path conversion here we're doing we can
356 * throw away. We're looking for a symlink for a dfs
357 * resolution, if we don't find it we'll do another
358 * unix_convert later in the codepath.
359 * If we needed to remember what we'd resolved in
360 * dp->reqpath (as the original code did) we'd
361 * pstrcpy(localhost, dp->reqpath) on any code
362 * path below that returns True - but I don't
363 * think this is needed. JRA.
366 pstrcpy(localpath, dp->reqpath);
368 status = unix_convert(conn, localpath, False, NULL, &sbuf);
369 if (!NT_STATUS_IS_OK(status)) {
373 /* check if need to redirect */
374 if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
376 DEBUG(6,("resolve_dfs_path (FindFirst) No redirection "
377 "for dfs link %s.\n", dfspath));
381 DEBUG(6,("resolve_dfs_path: %s resolves to a valid Dfs link.\n", dfspath));
383 *consumedcntp = strlen(dfspath);
388 /* redirect if any component in the path is a link */
389 pstrcpy(reqpath, localpath);
390 p = strrchr_m(reqpath, '/');
393 pstrcpy(localpath, reqpath);
394 if (is_msdfs_link(ctx, conn, localpath, reflistpp, refcntp, NULL)) {
395 DEBUG(4, ("resolve_dfs_path: Redirecting %s because parent %s is dfs link\n", dfspath, localpath));
397 /* To find the path consumed, we truncate the original
398 DFS pathname passed to use to remove the last
399 component. The length of the resulting string is
405 pstrcpy(buf, dfspath);
406 trim_char(buf, '\0', '\\');
407 for (; consumed_level; consumed_level--) {
409 /* Either '\\' or '/' may be a separator. */
410 q1 = strrchr_m(buf, '\\');
411 q2 = strrchr_m(buf, '/');
417 *consumedcntp = strlen(buf);
418 DEBUG(10, ("resolve_dfs_path: Path consumed: %s (%d)\n", buf, *consumedcntp));
423 p = strrchr_m(reqpath, '/');
430 /*****************************************************************
431 Decides if a dfs pathname should be redirected or not.
432 If not, the pathname is converted to a tcon-relative local unix path
434 search_wcard_flag: this flag performs 2 functions bother related
435 to searches. See resolve_dfs_path() and parse_processed_dfs_path()
437 *****************************************************************/
439 static BOOL dfs_redirect( connection_struct *conn, pstring pathname, BOOL search_wcard_flag )
443 if (!conn || !pathname) {
447 parse_processed_dfs_path(pathname, &dp, search_wcard_flag);
449 /* if dfs pathname for a non-dfs share, convert to tcon-relative
450 path and return false */
451 if (!lp_msdfs_root(SNUM(conn))) {
452 pstrcpy(pathname, dp.reqpath);
456 if ( !( strequal(dp.servicename, lp_servicename(SNUM(conn)))
457 || ( strequal(dp.servicename, HOMES_NAME)
458 && strequal(lp_servicename(SNUM(conn)), get_current_username()) )) )
463 if (resolve_dfs_path(NULL, pathname, &dp, conn, search_wcard_flag,
464 NULL, NULL, NULL, NULL)) {
465 DEBUG(3,("dfs_redirect: Redirecting %s\n", pathname));
468 DEBUG(3,("dfs_redirect: Not redirecting %s.\n", pathname));
470 /* Form non-dfs tcon-relative path */
471 pstrcpy(pathname, dp.reqpath);
473 DEBUG(3,("dfs_redirect: Path converted to non-dfs path %s\n", pathname));
480 /**********************************************************************
481 Return a self referral.
482 **********************************************************************/
484 static BOOL self_ref(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
485 int *consumedcntp, BOOL *self_referralp)
487 struct referral *ref;
489 if (self_referralp != NULL) {
490 *self_referralp = True;
493 jucn->referral_count = 1;
494 if((ref = TALLOC_P(ctx, struct referral)) == NULL) {
495 DEBUG(0,("self_ref: malloc failed for referral\n"));
499 pstrcpy(ref->alternate_path,pathname);
501 ref->ttl = REFERRAL_TTL;
502 jucn->referral_list = ref;
504 *consumedcntp = strlen(pathname);
510 /**********************************************************************
511 Gets valid referrals for a dfs path and fills up the
512 junction_map structure.
513 **********************************************************************/
515 BOOL get_referred_path(TALLOC_CTX *ctx, const char *pathname, struct junction_map *jucn,
516 int *consumedcntp, BOOL *self_referralp)
520 struct connection_struct conns;
521 struct connection_struct *conn = &conns;
525 BOOL self_referral = False;
527 if (!pathname || !jucn) {
533 if (self_referralp) {
534 *self_referralp = False;
536 self_referralp = &self_referral;
539 parse_dfs_path(pathname, &dp);
541 /* Verify hostname in path */
542 if (!is_myname_or_ipaddr(dp.hostname)) {
543 DEBUG(3, ("get_referred_path: Invalid hostname %s in path %s\n",
544 dp.hostname, pathname));
548 pstrcpy(jucn->service_name, dp.servicename);
549 pstrcpy(jucn->volume_name, dp.reqpath);
551 /* Verify the share is a dfs root */
552 snum = lp_servicenumber(jucn->service_name);
554 if ((snum = find_service(jucn->service_name)) < 0) {
559 if (!lp_msdfs_root(snum)) {
560 DEBUG(3,("get_referred_path: .%s. in dfs path %s is not a dfs root.\n",
561 dp.servicename, pathname));
566 * Self referrals are tested with a anonymous IPC connection and
567 * a GET_DFS_REFERRAL call to \\server\share. (which means dp.reqpath[0] points
568 * to an empty string). create_conn_struct cd's into the directory and will
569 * fail if it cannot (as the anonymous user). Cope with this.
572 if (dp.reqpath[0] == '\0') {
574 struct referral* ref;
576 if (*lp_msdfs_proxy(snum) == '\0') {
577 return self_ref(ctx, pathname, jucn, consumedcntp, self_referralp);
580 jucn->referral_count = 1;
581 if ((ref = TALLOC_P(ctx, struct referral)) == NULL) {
582 DEBUG(0, ("malloc failed for referral\n"));
586 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
587 if (dp.reqpath[0] != '\0') {
588 pstrcat(ref->alternate_path, dp.reqpath);
591 ref->ttl = REFERRAL_TTL;
592 jucn->referral_list = ref;
594 *consumedcntp = strlen(pathname);
600 pstrcpy(conn_path, lp_pathname(snum));
601 if (!create_conn_struct(conn, snum, conn_path)) {
605 /* If not remote & not a self referral, return False */
606 if (!resolve_dfs_path(ctx, pathname, &dp, conn, False,
607 &jucn->referral_list, &jucn->referral_count,
608 self_referralp, consumedcntp)) {
609 if (!*self_referralp) {
610 DEBUG(3,("get_referred_path: No valid referrals for path %s\n", pathname));
615 /* if self_referral, fill up the junction map */
616 if (*self_referralp) {
617 if (self_ref(ctx, pathname, jucn, consumedcntp, self_referralp) == False) {
626 conn_free_internal(conn);
630 static int setup_ver2_dfs_referral(char *pathname, char **ppdata,
631 struct junction_map *junction,
635 char* pdata = *ppdata;
637 unsigned char uni_requestedpath[1024];
638 int uni_reqpathoffset1,uni_reqpathoffset2;
640 int requestedpathlen=0;
645 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
647 requestedpathlen = rpcstr_push(uni_requestedpath, pathname, sizeof(pstring),
651 dump_data(0, (const char *) uni_requestedpath,requestedpathlen);
654 DEBUG(10,("ref count = %u\n",junction->referral_count));
656 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
657 VERSION2_REFERRAL_SIZE * junction->referral_count;
659 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
661 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
663 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
664 2 * requestedpathlen;
665 DEBUG(10,("reply_size: %u\n",reply_size));
667 /* add up the unicode lengths of all the referral paths */
668 for(i=0;i<junction->referral_count;i++) {
669 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
670 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
673 DEBUG(10,("reply_size = %u\n",reply_size));
674 /* add the unexplained 0x16 bytes */
677 pdata = (char *)SMB_REALLOC(pdata,reply_size);
679 DEBUG(0,("malloc failed for Realloc!\n"));
684 /* copy in the dfs requested paths.. required for offset calculations */
685 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
686 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
688 /* create the header */
689 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
690 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
692 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
694 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
698 /* add the referral elements */
699 for(i=0;i<junction->referral_count;i++) {
700 struct referral* ref = &junction->referral_list[i];
703 SSVAL(pdata,offset,2); /* version 2 */
704 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
706 SSVAL(pdata,offset+4,1);
708 SSVAL(pdata,offset+4,0);
710 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
711 SIVAL(pdata,offset+8,ref->proximity);
712 SIVAL(pdata,offset+12,ref->ttl);
714 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
715 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
716 /* copy referred path into current offset */
717 unilen = rpcstr_push(pdata+uni_curroffset, ref->alternate_path,
718 sizeof(pstring), STR_UNICODE);
720 SSVAL(pdata,offset+20,uni_curroffset-offset);
722 uni_curroffset += unilen;
723 offset += VERSION2_REFERRAL_SIZE;
725 /* add in the unexplained 22 (0x16) bytes at the end */
726 memset(pdata+uni_curroffset,'\0',0x16);
730 static int setup_ver3_dfs_referral(char *pathname, char **ppdata,
731 struct junction_map *junction,
735 char* pdata = *ppdata;
737 unsigned char uni_reqpath[1024];
738 int uni_reqpathoffset1, uni_reqpathoffset2;
745 DEBUG(10,("setting up version3 referral\n"));
747 reqpathlen = rpcstr_push(uni_reqpath, pathname, sizeof(pstring), STR_TERMINATE);
750 dump_data(0, (char *) uni_reqpath,reqpathlen);
753 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
754 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
755 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
757 for(i=0;i<junction->referral_count;i++) {
758 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
759 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
762 pdata = (char *)SMB_REALLOC(pdata,reply_size);
764 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
769 /* create the header */
770 SSVAL(pdata,0,consumedcnt * 2); /* path consumed */
771 SSVAL(pdata,2,junction->referral_count); /* number of referral */
773 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
775 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
778 /* copy in the reqpaths */
779 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
780 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
783 for(i=0;i<junction->referral_count;i++) {
784 struct referral* ref = &(junction->referral_list[i]);
787 SSVAL(pdata,offset,3); /* version 3 */
788 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
790 SSVAL(pdata,offset+4,1);
792 SSVAL(pdata,offset+4,0);
795 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
796 SIVAL(pdata,offset+8,ref->ttl);
798 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
799 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
800 /* copy referred path into current offset */
801 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
802 sizeof(pstring), STR_UNICODE | STR_TERMINATE);
803 SSVAL(pdata,offset+16,uni_curroffset-offset);
804 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
805 memset(pdata+offset+18,'\0',16);
807 uni_curroffset += unilen;
808 offset += VERSION3_REFERRAL_SIZE;
813 /******************************************************************
814 Set up the Dfs referral for the dfs pathname
815 ******************************************************************/
817 int setup_dfs_referral(connection_struct *orig_conn, char *pathname, int max_referral_level, char **ppdata)
819 struct junction_map junction;
821 BOOL self_referral = False;
824 char *pathnamep = pathname;
827 if (!(ctx=talloc_init("setup_dfs_referral"))) {
831 ZERO_STRUCT(junction);
833 /* get the junction entry */
839 /* Trim pathname sent by client so it begins with only one backslash.
840 Two backslashes confuse some dfs clients
842 while (pathnamep[0] == '\\' && pathnamep[1] == '\\') {
846 pstrcpy(buf, pathnamep);
847 /* The following call can change cwd. */
848 if (!get_referred_path(ctx, buf, &junction, &consumedcnt, &self_referral)) {
849 vfs_ChDir(orig_conn,orig_conn->connectpath);
853 vfs_ChDir(orig_conn,orig_conn->connectpath);
855 if (!self_referral) {
856 pathnamep[consumedcnt] = '\0';
858 if( DEBUGLVL( 3 ) ) {
860 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathnamep);
861 for(i=0;i<junction.referral_count;i++)
862 dbgtext(" %s",junction.referral_list[i].alternate_path);
867 /* create the referral depeding on version */
868 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
870 if (max_referral_level < 2) {
871 max_referral_level = 2;
873 if (max_referral_level > 3) {
874 max_referral_level = 3;
877 switch(max_referral_level) {
879 reply_size = setup_ver2_dfs_referral(pathnamep, ppdata, &junction,
880 consumedcnt, self_referral);
883 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata, &junction,
884 consumedcnt, self_referral);
887 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
893 DEBUGADD(0,("DFS Referral pdata:\n"));
894 dump_data(0,*ppdata,reply_size);
901 /**********************************************************************
902 The following functions are called by the NETDFS RPC pipe functions
903 **********************************************************************/
905 /*********************************************************************
906 Creates a junction structure from a Dfs pathname
907 **********************************************************************/
909 BOOL create_junction(const char *pathname, struct junction_map *jucn)
913 parse_dfs_path(pathname,&dp);
915 /* check if path is dfs : validate first token */
916 if (!is_myname_or_ipaddr(dp.hostname)) {
917 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n",
918 dp.hostname, pathname));
922 /* Check for a non-DFS share */
923 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
924 DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
928 pstrcpy(jucn->service_name,dp.servicename);
929 pstrcpy(jucn->volume_name,dp.reqpath);
930 pstrcpy(jucn->comment, lp_comment(lp_servicenumber(dp.servicename)));
934 /**********************************************************************
935 Forms a valid Unix pathname from the junction
936 **********************************************************************/
938 static BOOL junction_to_local_path(struct junction_map *jucn, char *path,
939 int max_pathlen, connection_struct *conn)
948 snum = lp_servicenumber(jucn->service_name);
953 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
954 safe_strcat(path, "/", max_pathlen-1);
955 safe_strcat(path, jucn->volume_name, max_pathlen-1);
957 pstrcpy(conn_path, lp_pathname(snum));
958 if (!create_conn_struct(conn, snum, conn_path)) {
965 BOOL create_msdfs_link(struct junction_map *jucn, BOOL exists)
969 connection_struct conns;
970 connection_struct *conn = &conns;
972 BOOL insert_comma = False;
977 if(!junction_to_local_path(jucn, path, sizeof(path), conn)) {
981 /* form the msdfs_link contents */
982 pstrcpy(msdfs_link, "msdfs:");
983 for(i=0; i<jucn->referral_count; i++) {
984 char* refpath = jucn->referral_list[i].alternate_path;
986 trim_char(refpath, '\\', '\\');
987 if(*refpath == '\0') {
989 insert_comma = False;
993 if (i > 0 && insert_comma) {
994 pstrcat(msdfs_link, ",");
997 pstrcat(msdfs_link, refpath);
1003 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
1006 if(SMB_VFS_UNLINK(conn,path)!=0) {
1011 if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1012 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
1013 path, msdfs_link, strerror(errno)));
1022 conn_free_internal(conn);
1026 BOOL remove_msdfs_link(struct junction_map *jucn)
1029 connection_struct conns;
1030 connection_struct *conn = &conns;
1035 if( junction_to_local_path(jucn, path, sizeof(path), conn) ) {
1036 if( SMB_VFS_UNLINK(conn, path) == 0 ) {
1039 talloc_destroy( conn->mem_ctx );
1042 conn_free_internal(conn);
1046 static int form_junctions(TALLOC_CTX *ctx, int snum, struct junction_map *jucn, int jn_remain)
1049 SMB_STRUCT_DIR *dirp;
1051 pstring connect_path;
1052 char* service_name = lp_servicename(snum);
1053 connection_struct conn;
1054 struct referral *ref = NULL;
1058 if (jn_remain <= 0) {
1062 pstrcpy(connect_path,lp_pathname(snum));
1064 if(*connect_path == '\0') {
1069 * Fake up a connection struct for the VFS layer.
1072 if (!create_conn_struct(&conn, snum, connect_path)) {
1076 /* form a junction for the msdfs root - convention
1077 DO NOT REMOVE THIS: NT clients will not work with us
1078 if this is not present
1080 pstrcpy(jucn[cnt].service_name, service_name);
1081 jucn[cnt].volume_name[0] = '\0';
1082 jucn[cnt].referral_count = 1;
1084 ref = jucn[cnt].referral_list = TALLOC_P(ctx, struct referral);
1085 if (jucn[cnt].referral_list == NULL) {
1086 DEBUG(0, ("Malloc failed!\n"));
1091 ref->ttl = REFERRAL_TTL;
1092 if (*lp_msdfs_proxy(snum) != '\0') {
1093 pstrcpy(ref->alternate_path, lp_msdfs_proxy(snum));
1098 slprintf(ref->alternate_path, sizeof(pstring)-1,
1099 "\\\\%s\\%s", get_local_machine_name(), service_name);
1102 /* Now enumerate all dfs links */
1103 dirp = SMB_VFS_OPENDIR(&conn, ".", NULL, 0);
1108 while ((dname = vfs_readdirname(&conn, dirp)) != NULL) {
1109 if (cnt >= jn_remain) {
1110 SMB_VFS_CLOSEDIR(&conn,dirp);
1111 DEBUG(2, ("ran out of MSDFS junction slots"));
1114 if (is_msdfs_link(ctx, &conn, dname, &jucn[cnt].referral_list,
1115 &jucn[cnt].referral_count, NULL)) {
1116 pstrcpy(jucn[cnt].service_name, service_name);
1117 pstrcpy(jucn[cnt].volume_name, dname);
1122 SMB_VFS_CLOSEDIR(&conn,dirp);
1126 conn_free_internal(&conn);
1130 int enum_msdfs_links(TALLOC_CTX *ctx, struct junction_map *jucn, int jn_max)
1136 if(!lp_host_msdfs()) {
1140 /* Ensure all the usershares are loaded. */
1142 load_registry_shares();
1143 sharecount = load_usershare_shares();
1146 for(i=0;i < sharecount && (jn_max - jn_count) > 0;i++) {
1147 if(lp_msdfs_root(i)) {
1148 jn_count += form_junctions(ctx, i,jucn,jn_max - jn_count);
1154 /******************************************************************************
1155 Core function to resolve a dfs pathname.
1156 ******************************************************************************/
1158 BOOL resolve_dfspath(connection_struct *conn, BOOL dfs_pathnames, pstring name)
1160 if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1161 dfs_redirect(conn, name, False)) {
1162 return False; /* Pathname didn't resolve. */
1167 /******************************************************************************
1168 Core function to resolve a dfs pathname possibly containing a wildcard.
1169 This function is identical to the above except for the BOOL param to
1170 dfs_redirect but I need this to be separate so it's really clear when
1171 we're allowing wildcards and when we're not. JRA.
1172 ******************************************************************************/
1174 BOOL resolve_dfspath_wcard(connection_struct *conn, BOOL dfs_pathnames, pstring name)
1176 if (dfs_pathnames && lp_host_msdfs() && lp_msdfs_root(SNUM(conn)) &&
1177 dfs_redirect(conn, name, True)) {
1178 return False; /* Pathname didn't resolve. */