dcef75e094fdc09966555554a1edf46b80de117f
[ira/wip.git] / source3 / smbd / msdfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    MSDFS services for Samba
5    Copyright (C) Shirish Kalele 2000
6    Copyright (C) Jeremy Allison 2007
7
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 3 of the License, or
11    (at your option) any later version.
12
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.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21 */
22
23 #define DBGC_CLASS DBGC_MSDFS
24 #include "includes.h"
25 #include "smbd/globals.h"
26
27 /**********************************************************************
28  Parse a DFS pathname of the form \hostname\service\reqpath
29  into the dfs_path structure.
30  If POSIX pathnames is true, the pathname may also be of the
31  form /hostname/service/reqpath.
32  We cope with either here.
33
34  Unfortunately, due to broken clients who might set the
35  SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES bit and then
36  send a local path, we have to cope with that too....
37
38  If conn != NULL then ensure the provided service is
39  the one pointed to by the connection.
40
41  This version does everything using pointers within one copy of the
42  pathname string, talloced on the struct dfs_path pointer (which
43  must be talloced). This may be too clever to live....
44  JRA.
45 **********************************************************************/
46
47 static NTSTATUS parse_dfs_path(connection_struct *conn,
48                                 const char *pathname,
49                                 bool allow_wcards,
50                                 struct dfs_path *pdp, /* MUST BE TALLOCED */
51                                 bool *ppath_contains_wcard)
52 {
53         char *pathname_local;
54         char *p,*temp;
55         char *servicename;
56         char *eos_ptr;
57         NTSTATUS status = NT_STATUS_OK;
58         char sepchar;
59
60         ZERO_STRUCTP(pdp);
61
62         /*
63          * This is the only talloc we should need to do
64          * on the struct dfs_path. All the pointers inside
65          * it should point to offsets within this string.
66          */
67
68         pathname_local = talloc_strdup(pdp, pathname);
69         if (!pathname_local) {
70                 return NT_STATUS_NO_MEMORY;
71         }
72         /* Get a pointer to the terminating '\0' */
73         eos_ptr = &pathname_local[strlen(pathname_local)];
74         p = temp = pathname_local;
75
76         pdp->posix_path = (lp_posix_pathnames() && *pathname == '/');
77
78         sepchar = pdp->posix_path ? '/' : '\\';
79
80         if (*pathname != sepchar) {
81                 DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n",
82                         pathname, sepchar ));
83                 /*
84                  * Possibly client sent a local path by mistake.
85                  * Try and convert to a local path.
86                  */
87
88                 pdp->hostname = eos_ptr; /* "" */
89                 pdp->servicename = eos_ptr; /* "" */
90
91                 /* We've got no info about separators. */
92                 pdp->posix_path = lp_posix_pathnames();
93                 p = temp;
94                 DEBUG(10,("parse_dfs_path: trying to convert %s to a "
95                         "local path\n",
96                         temp));
97                 goto local_path;
98         }
99
100         /*
101          * Safe to use on talloc'ed string as it only shrinks.
102          * It also doesn't affect the eos_ptr.
103          */
104         trim_char(temp,sepchar,sepchar);
105
106         DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n",
107                 temp, sepchar));
108
109         /* Now tokenize. */
110         /* Parse out hostname. */
111         p = strchr_m(temp,sepchar);
112         if(p == NULL) {
113                 DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n",
114                         temp));
115                 /*
116                  * Possibly client sent a local path by mistake.
117                  * Try and convert to a local path.
118                  */
119
120                 pdp->hostname = eos_ptr; /* "" */
121                 pdp->servicename = eos_ptr; /* "" */
122
123                 p = temp;
124                 DEBUG(10,("parse_dfs_path: trying to convert %s "
125                         "to a local path\n",
126                         temp));
127                 goto local_path;
128         }
129         *p = '\0';
130         pdp->hostname = temp;
131
132         DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname));
133
134         /* Parse out servicename. */
135         servicename = p+1;
136         p = strchr_m(servicename,sepchar);
137         if (p) {
138                 *p = '\0';
139         }
140
141         /* Is this really our servicename ? */
142         if (conn && !( strequal(servicename, lp_servicename(SNUM(conn)))
143                         || (strequal(servicename, HOMES_NAME)
144                         && strequal(lp_servicename(SNUM(conn)),
145                                 get_current_username()) )) ) {
146                 DEBUG(10,("parse_dfs_path: %s is not our servicename\n",
147                         servicename));
148
149                 /*
150                  * Possibly client sent a local path by mistake.
151                  * Try and convert to a local path.
152                  */
153
154                 pdp->hostname = eos_ptr; /* "" */
155                 pdp->servicename = eos_ptr; /* "" */
156
157                 /* Repair the path - replace the sepchar's
158                    we nulled out */
159                 servicename--;
160                 *servicename = sepchar;
161                 if (p) {
162                         *p = sepchar;
163                 }
164
165                 p = temp;
166                 DEBUG(10,("parse_dfs_path: trying to convert %s "
167                         "to a local path\n",
168                         temp));
169                 goto local_path;
170         }
171
172         pdp->servicename = servicename;
173
174         DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename));
175
176         if(p == NULL) {
177                 /* Client sent self referral \server\share. */
178                 pdp->reqpath = eos_ptr; /* "" */
179                 return NT_STATUS_OK;
180         }
181
182         p++;
183
184   local_path:
185
186         *ppath_contains_wcard = False;
187
188         pdp->reqpath = p;
189
190         /* Rest is reqpath. */
191         if (pdp->posix_path) {
192                 status = check_path_syntax_posix(pdp->reqpath);
193         } else {
194                 if (allow_wcards) {
195                         status = check_path_syntax_wcard(pdp->reqpath,
196                                         ppath_contains_wcard);
197                 } else {
198                         status = check_path_syntax(pdp->reqpath);
199                 }
200         }
201
202         if (!NT_STATUS_IS_OK(status)) {
203                 DEBUG(10,("parse_dfs_path: '%s' failed with %s\n",
204                         p, nt_errstr(status) ));
205                 return status;
206         }
207
208         DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath));
209         return NT_STATUS_OK;
210 }
211
212 /********************************************************
213  Fake up a connection struct for the VFS layer.
214  Note this CHANGES CWD !!!! JRA.
215 *********************************************************/
216
217 NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
218                                 connection_struct **pconn,
219                                 int snum,
220                                 const char *path,
221                                 struct auth_serversupplied_info *server_info,
222                                 char **poldcwd)
223 {
224         connection_struct *conn;
225         char *connpath;
226         char *oldcwd;
227
228         conn = TALLOC_ZERO_P(ctx, connection_struct);
229         if (conn == NULL) {
230                 return NT_STATUS_NO_MEMORY;
231         }
232
233         connpath = talloc_strdup(conn, path);
234         if (!connpath) {
235                 TALLOC_FREE(conn);
236                 return NT_STATUS_NO_MEMORY;
237         }
238         connpath = talloc_string_sub(conn,
239                                 connpath,
240                                 "%S",
241                                 lp_servicename(snum));
242         if (!connpath) {
243                 TALLOC_FREE(conn);
244                 return NT_STATUS_NO_MEMORY;
245         }
246
247         /* needed for smbd_vfs_init() */
248
249         if (!(conn->params = TALLOC_ZERO_P(conn, struct share_params))) {
250                 DEBUG(0, ("TALLOC failed\n"));
251                 TALLOC_FREE(conn);
252                 return NT_STATUS_NO_MEMORY;
253         }
254
255         conn->params->service = snum;
256
257         if (server_info != NULL) {
258                 conn->server_info = copy_serverinfo(conn, server_info);
259                 if (conn->server_info == NULL) {
260                         DEBUG(0, ("copy_serverinfo failed\n"));
261                         TALLOC_FREE(conn);
262                         return NT_STATUS_NO_MEMORY;
263                 }
264         }
265
266         set_conn_connectpath(conn, connpath);
267
268         if (!smbd_vfs_init(conn)) {
269                 NTSTATUS status = map_nt_error_from_unix(errno);
270                 DEBUG(0,("create_conn_struct: smbd_vfs_init failed.\n"));
271                 conn_free(conn);
272                 return status;
273         }
274
275         conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
276
277         /*
278          * Windows seems to insist on doing trans2getdfsreferral() calls on
279          * the IPC$ share as the anonymous user. If we try to chdir as that
280          * user we will fail.... WTF ? JRA.
281          */
282
283         oldcwd = vfs_GetWd(ctx, conn);
284         if (oldcwd == NULL) {
285                 NTSTATUS status = map_nt_error_from_unix(errno);
286                 DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
287                 conn_free(conn);
288                 return status;
289         }
290
291         if (vfs_ChDir(conn,conn->connectpath) != 0) {
292                 NTSTATUS status = map_nt_error_from_unix(errno);
293                 DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
294                         "Error was %s\n",
295                         conn->connectpath, strerror(errno) ));
296                 conn_free(conn);
297                 return status;
298         }
299
300         *pconn = conn;
301         *poldcwd = oldcwd;
302
303         return NT_STATUS_OK;
304 }
305
306 /**********************************************************************
307  Parse the contents of a symlink to verify if it is an msdfs referral
308  A valid referral is of the form:
309
310  msdfs:server1\share1,server2\share2
311  msdfs:server1\share1\pathname,server2\share2\pathname
312  msdfs:server1/share1,server2/share2
313  msdfs:server1/share1/pathname,server2/share2/pathname.
314
315  Note that the alternate paths returned here must be of the canonicalized
316  form:
317
318  \server\share or
319  \server\share\path\to\file,
320
321  even in posix path mode. This is because we have no knowledge if the
322  server we're referring to understands posix paths.
323  **********************************************************************/
324
325 static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
326                                 const char *target,
327                                 struct referral **preflist,
328                                 int *refcount)
329 {
330         char *temp = NULL;
331         char *prot;
332         char **alt_path = NULL;
333         int count = 0, i;
334         struct referral *reflist;
335         char *saveptr;
336
337         temp = talloc_strdup(ctx, target);
338         if (!temp) {
339                 return False;
340         }
341         prot = strtok_r(temp, ":", &saveptr);
342         if (!prot) {
343                 DEBUG(0,("parse_msdfs_symlink: invalid path !\n"));
344                 return False;
345         }
346
347         alt_path = TALLOC_ARRAY(ctx, char *, MAX_REFERRAL_COUNT);
348         if (!alt_path) {
349                 return False;
350         }
351
352         /* parse out the alternate paths */
353         while((count<MAX_REFERRAL_COUNT) &&
354               ((alt_path[count] = strtok_r(NULL, ",", &saveptr)) != NULL)) {
355                 count++;
356         }
357
358         DEBUG(10,("parse_msdfs_symlink: count=%d\n", count));
359
360         if (count) {
361                 reflist = *preflist = TALLOC_ZERO_ARRAY(ctx,
362                                 struct referral, count);
363                 if(reflist == NULL) {
364                         TALLOC_FREE(alt_path);
365                         return False;
366                 }
367         } else {
368                 reflist = *preflist = NULL;
369         }
370
371         for(i=0;i<count;i++) {
372                 char *p;
373
374                 /* Canonicalize link target.
375                  * Replace all /'s in the path by a \ */
376                 string_replace(alt_path[i], '/', '\\');
377
378                 /* Remove leading '\\'s */
379                 p = alt_path[i];
380                 while (*p && (*p == '\\')) {
381                         p++;
382                 }
383
384                 reflist[i].alternate_path = talloc_asprintf(ctx,
385                                 "\\%s",
386                                 p);
387                 if (!reflist[i].alternate_path) {
388                         return False;
389                 }
390
391                 reflist[i].proximity = 0;
392                 reflist[i].ttl = REFERRAL_TTL;
393                 DEBUG(10, ("parse_msdfs_symlink: Created alt path: %s\n",
394                                         reflist[i].alternate_path));
395         }
396
397         *refcount = count;
398
399         TALLOC_FREE(alt_path);
400         return True;
401 }
402
403 /**********************************************************************
404  Returns true if the unix path is a valid msdfs symlink and also
405  returns the target string from inside the link.
406 **********************************************************************/
407
408 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
409                         connection_struct *conn,
410                         const char *path,
411                         char **pp_link_target,
412                         SMB_STRUCT_STAT *sbufp)
413 {
414         int referral_len = 0;
415 #if defined(HAVE_BROKEN_READLINK)
416         char link_target_buf[PATH_MAX];
417 #else
418         char link_target_buf[7];
419 #endif
420         size_t bufsize = 0;
421         char *link_target = NULL;
422         struct smb_filename smb_fname;
423
424         if (pp_link_target) {
425                 bufsize = 1024;
426                 link_target = TALLOC_ARRAY(ctx, char, bufsize);
427                 if (!link_target) {
428                         return False;
429                 }
430                 *pp_link_target = link_target;
431         } else {
432                 bufsize = sizeof(link_target_buf);
433                 link_target = link_target_buf;
434         }
435
436         ZERO_STRUCT(smb_fname);
437         smb_fname.base_name = discard_const_p(char, path);
438
439         if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
440                 DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
441                         path));
442                 goto err;
443         }
444         if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
445                 DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
446                                         path));
447                 goto err;
448         }
449         if (sbufp != NULL) {
450                 *sbufp = smb_fname.st;
451         }
452
453         referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
454         if (referral_len == -1) {
455                 DEBUG(0,("is_msdfs_link_read_target: Error reading "
456                         "msdfs link %s: %s\n",
457                         path, strerror(errno)));
458                 goto err;
459         }
460         link_target[referral_len] = '\0';
461
462         DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
463                                 link_target));
464
465         if (!strnequal(link_target, "msdfs:", 6)) {
466                 goto err;
467         }
468         return True;
469
470   err:
471
472         if (link_target != link_target_buf) {
473                 TALLOC_FREE(link_target);
474         }
475         return False;
476 }
477
478 /**********************************************************************
479  Returns true if the unix path is a valid msdfs symlink.
480 **********************************************************************/
481
482 bool is_msdfs_link(connection_struct *conn,
483                 const char *path,
484                 SMB_STRUCT_STAT *sbufp)
485 {
486         return is_msdfs_link_internal(talloc_tos(),
487                                         conn,
488                                         path,
489                                         NULL,
490                                         sbufp);
491 }
492
493 /*****************************************************************
494  Used by other functions to decide if a dfs path is remote,
495  and to get the list of referred locations for that remote path.
496
497  search_flag: For findfirsts, dfs links themselves are not
498  redirected, but paths beyond the links are. For normal smb calls,
499  even dfs links need to be redirected.
500
501  consumedcntp: how much of the dfs path is being redirected. the client
502  should try the remaining path on the redirected server.
503
504  If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs
505  link redirect are in targetpath.
506 *****************************************************************/
507
508 static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
509                 connection_struct *conn,
510                 const char *dfspath, /* Incoming complete dfs path */
511                 const struct dfs_path *pdp, /* Parsed out
512                                                server+share+extrapath. */
513                 bool search_flag, /* Called from a findfirst ? */
514                 int *consumedcntp,
515                 char **pp_targetpath)
516 {
517         char *p = NULL;
518         char *q = NULL;
519         NTSTATUS status;
520         struct smb_filename *smb_fname = NULL;
521         char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
522                                   components). */
523
524         DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n",
525                 conn->connectpath, pdp->reqpath));
526
527         /*
528          * Note the unix path conversion here we're doing we can
529          * throw away. We're looking for a symlink for a dfs
530          * resolution, if we don't find it we'll do another
531          * unix_convert later in the codepath.
532          * If we needed to remember what we'd resolved in
533          * dp->reqpath (as the original code did) we'd
534          * copy (localhost, dp->reqpath) on any code
535          * path below that returns True - but I don't
536          * think this is needed. JRA.
537          */
538
539         status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
540                               search_flag ? UCF_ALWAYS_ALLOW_WCARD_LCOMP : 0);
541
542         if (!NT_STATUS_IS_OK(status)) {
543                 if (!NT_STATUS_EQUAL(status,
544                                      NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
545                         return status;
546                 }
547
548                 /* Create an smb_fname to use below. */
549                 status = create_synthetic_smb_fname(ctx, pdp->reqpath, NULL,
550                                                     NULL, &smb_fname);
551                 if (!NT_STATUS_IS_OK(status)) {
552                         return status;
553                 }
554         }
555
556         /* Optimization - check if we can redirect the whole path. */
557
558         if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
559                                    pp_targetpath, NULL)) {
560                 if (search_flag) {
561                         DEBUG(6,("dfs_path_lookup (FindFirst) No redirection "
562                                  "for dfs link %s.\n", dfspath));
563                         status = NT_STATUS_OK;
564                         goto out;
565                 }
566
567                 DEBUG(6,("dfs_path_lookup: %s resolves to a "
568                         "valid dfs link %s.\n", dfspath,
569                         pp_targetpath ? *pp_targetpath : ""));
570
571                 if (consumedcntp) {
572                         *consumedcntp = strlen(dfspath);
573                 }
574                 status = NT_STATUS_PATH_NOT_COVERED;
575                 goto out;
576         }
577
578         /* Prepare to test only for '/' components in the given path,
579          * so if a Windows path replace all '\\' characters with '/'.
580          * For a POSIX DFS path we know all separators are already '/'. */
581
582         canon_dfspath = talloc_strdup(ctx, dfspath);
583         if (!canon_dfspath) {
584                 status = NT_STATUS_NO_MEMORY;
585                 goto out;
586         }
587         if (!pdp->posix_path) {
588                 string_replace(canon_dfspath, '\\', '/');
589         }
590
591         /*
592          * localpath comes out of unix_convert, so it has
593          * no trailing backslash. Make sure that canon_dfspath hasn't either.
594          * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>.
595          */
596
597         trim_char(canon_dfspath,0,'/');
598
599         /*
600          * Redirect if any component in the path is a link.
601          * We do this by walking backwards through the
602          * local path, chopping off the last component
603          * in both the local path and the canonicalized
604          * DFS path. If we hit a DFS link then we're done.
605          */
606
607         p = strrchr_m(smb_fname->base_name, '/');
608         if (consumedcntp) {
609                 q = strrchr_m(canon_dfspath, '/');
610         }
611
612         while (p) {
613                 *p = '\0';
614                 if (q) {
615                         *q = '\0';
616                 }
617
618                 if (is_msdfs_link_internal(ctx, conn,
619                                            smb_fname->base_name, pp_targetpath,
620                                            NULL)) {
621                         DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
622                                   "parent %s is dfs link\n", dfspath,
623                                   smb_fname_str_dbg(smb_fname)));
624
625                         if (consumedcntp) {
626                                 *consumedcntp = strlen(canon_dfspath);
627                                 DEBUG(10, ("dfs_path_lookup: Path consumed: %s "
628                                         "(%d)\n",
629                                         canon_dfspath,
630                                         *consumedcntp));
631                         }
632
633                         status = NT_STATUS_PATH_NOT_COVERED;
634                         goto out;
635                 }
636
637                 /* Step back on the filesystem. */
638                 p = strrchr_m(smb_fname->base_name, '/');
639
640                 if (consumedcntp) {
641                         /* And in the canonicalized dfs path. */
642                         q = strrchr_m(canon_dfspath, '/');
643                 }
644         }
645
646         status = NT_STATUS_OK;
647  out:
648         TALLOC_FREE(smb_fname);
649         return status;
650 }
651
652 /*****************************************************************
653  Decides if a dfs pathname should be redirected or not.
654  If not, the pathname is converted to a tcon-relative local unix path
655
656  search_wcard_flag: this flag performs 2 functions both related
657  to searches.  See resolve_dfs_path() and parse_dfs_path_XX()
658  for details.
659
660  This function can return NT_STATUS_OK, meaning use the returned path as-is
661  (mapped into a local path).
662  or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or
663  any other NT_STATUS error which is a genuine error to be
664  returned to the client.
665 *****************************************************************/
666
667 static NTSTATUS dfs_redirect(TALLOC_CTX *ctx,
668                         connection_struct *conn,
669                         const char *path_in,
670                         bool search_wcard_flag,
671                         char **pp_path_out,
672                         bool *ppath_contains_wcard)
673 {
674         NTSTATUS status;
675         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
676
677         if (!pdp) {
678                 return NT_STATUS_NO_MEMORY;
679         }
680
681         status = parse_dfs_path(conn, path_in, search_wcard_flag, pdp,
682                         ppath_contains_wcard);
683         if (!NT_STATUS_IS_OK(status)) {
684                 TALLOC_FREE(pdp);
685                 return status;
686         }
687
688         if (pdp->reqpath[0] == '\0') {
689                 TALLOC_FREE(pdp);
690                 *pp_path_out = talloc_strdup(ctx, "");
691                 if (!*pp_path_out) {
692                         return NT_STATUS_NO_MEMORY;
693                 }
694                 DEBUG(5,("dfs_redirect: self-referral.\n"));
695                 return NT_STATUS_OK;
696         }
697
698         /* If dfs pathname for a non-dfs share, convert to tcon-relative
699            path and return OK */
700
701         if (!lp_msdfs_root(SNUM(conn))) {
702                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
703                 TALLOC_FREE(pdp);
704                 if (!*pp_path_out) {
705                         return NT_STATUS_NO_MEMORY;
706                 }
707                 return NT_STATUS_OK;
708         }
709
710         /* If it looked like a local path (zero hostname/servicename)
711          * just treat as a tcon-relative path. */
712
713         if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') {
714                 *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
715                 TALLOC_FREE(pdp);
716                 if (!*pp_path_out) {
717                         return NT_STATUS_NO_MEMORY;
718                 }
719                 return NT_STATUS_OK;
720         }
721
722         if (!( strequal(pdp->servicename, lp_servicename(SNUM(conn)))
723                         || (strequal(pdp->servicename, HOMES_NAME)
724                         && strequal(lp_servicename(SNUM(conn)),
725                                 conn->server_info->sanitized_username) )) ) {
726
727                 /* The given sharename doesn't match this connection. */
728                 TALLOC_FREE(pdp);
729
730                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
731         }
732
733         status = dfs_path_lookup(ctx, conn, path_in, pdp,
734                         search_wcard_flag, NULL, NULL);
735         if (!NT_STATUS_IS_OK(status)) {
736                 if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
737                         DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in));
738                 } else {
739                         DEBUG(10,("dfs_redirect: dfs_path_lookup "
740                                 "failed for %s with %s\n",
741                                 path_in, nt_errstr(status) ));
742                 }
743                 return status;
744         }
745
746         DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in));
747
748         /* Form non-dfs tcon-relative path */
749         *pp_path_out = talloc_strdup(ctx, pdp->reqpath);
750         TALLOC_FREE(pdp);
751         if (!*pp_path_out) {
752                 return NT_STATUS_NO_MEMORY;
753         }
754
755         DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n",
756                                 path_in,
757                                 *pp_path_out));
758
759         return NT_STATUS_OK;
760 }
761
762 /**********************************************************************
763  Return a self referral.
764 **********************************************************************/
765
766 static NTSTATUS self_ref(TALLOC_CTX *ctx,
767                         const char *dfs_path,
768                         struct junction_map *jucn,
769                         int *consumedcntp,
770                         bool *self_referralp)
771 {
772         struct referral *ref;
773
774         *self_referralp = True;
775
776         jucn->referral_count = 1;
777         if((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         ref->alternate_path = talloc_strdup(ctx, dfs_path);
782         if (!ref->alternate_path) {
783                 return NT_STATUS_NO_MEMORY;
784         }
785         ref->proximity = 0;
786         ref->ttl = REFERRAL_TTL;
787         jucn->referral_list = ref;
788         *consumedcntp = strlen(dfs_path);
789         return NT_STATUS_OK;
790 }
791
792 /**********************************************************************
793  Gets valid referrals for a dfs path and fills up the
794  junction_map structure.
795 **********************************************************************/
796
797 NTSTATUS get_referred_path(TALLOC_CTX *ctx,
798                         const char *dfs_path,
799                         struct junction_map *jucn,
800                         int *consumedcntp,
801                         bool *self_referralp)
802 {
803         struct connection_struct *conn;
804         char *targetpath = NULL;
805         int snum;
806         NTSTATUS status = NT_STATUS_NOT_FOUND;
807         bool dummy;
808         struct dfs_path *pdp = TALLOC_P(ctx, struct dfs_path);
809         char *oldpath;
810
811         if (!pdp) {
812                 return NT_STATUS_NO_MEMORY;
813         }
814
815         *self_referralp = False;
816
817         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
818         if (!NT_STATUS_IS_OK(status)) {
819                 return status;
820         }
821
822         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
823         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
824         if (!jucn->service_name || !jucn->volume_name) {
825                 TALLOC_FREE(pdp);
826                 return NT_STATUS_NO_MEMORY;
827         }
828
829         /* Verify the share is a dfs root */
830         snum = lp_servicenumber(jucn->service_name);
831         if(snum < 0) {
832                 fstring service_name;
833                 fstrcpy(service_name, jucn->service_name);
834                 if ((snum = find_service(service_name)) < 0) {
835                         return NT_STATUS_NOT_FOUND;
836                 }
837                 TALLOC_FREE(jucn->service_name);
838                 jucn->service_name = talloc_strdup(ctx, service_name);
839                 if (!jucn->service_name) {
840                         TALLOC_FREE(pdp);
841                         return NT_STATUS_NO_MEMORY;
842                 }
843         }
844
845         if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(snum) == '\0')) {
846                 DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
847                         "a dfs root.\n",
848                         pdp->servicename, dfs_path));
849                 TALLOC_FREE(pdp);
850                 return NT_STATUS_NOT_FOUND;
851         }
852
853         /*
854          * Self referrals are tested with a anonymous IPC connection and
855          * a GET_DFS_REFERRAL call to \\server\share. (which means
856          * dp.reqpath[0] points to an empty string). create_conn_struct cd's
857          * into the directory and will fail if it cannot (as the anonymous
858          * user). Cope with this.
859          */
860
861         if (pdp->reqpath[0] == '\0') {
862                 char *tmp;
863                 struct referral *ref;
864
865                 if (*lp_msdfs_proxy(snum) == '\0') {
866                         TALLOC_FREE(pdp);
867                         return self_ref(ctx,
868                                         dfs_path,
869                                         jucn,
870                                         consumedcntp,
871                                         self_referralp);
872                 }
873
874                 /*
875                  * It's an msdfs proxy share. Redirect to
876                  * the configured target share.
877                  */
878
879                 jucn->referral_count = 1;
880                 if ((ref = TALLOC_ZERO_P(ctx, struct referral)) == NULL) {
881                         TALLOC_FREE(pdp);
882                         return NT_STATUS_NO_MEMORY;
883                 }
884
885                 if (!(tmp = talloc_strdup(ctx, lp_msdfs_proxy(snum)))) {
886                         TALLOC_FREE(pdp);
887                         return NT_STATUS_NO_MEMORY;
888                 }
889
890                 trim_string(tmp, "\\", 0);
891
892                 ref->alternate_path = talloc_asprintf(ctx, "\\%s", tmp);
893                 TALLOC_FREE(tmp);
894
895                 if (!ref->alternate_path) {
896                         TALLOC_FREE(pdp);
897                         return NT_STATUS_NO_MEMORY;
898                 }
899
900                 if (pdp->reqpath[0] != '\0') {
901                         ref->alternate_path = talloc_asprintf_append(
902                                         ref->alternate_path,
903                                         "%s",
904                                         pdp->reqpath);
905                         if (!ref->alternate_path) {
906                                 TALLOC_FREE(pdp);
907                                 return NT_STATUS_NO_MEMORY;
908                         }
909                 }
910                 ref->proximity = 0;
911                 ref->ttl = REFERRAL_TTL;
912                 jucn->referral_list = ref;
913                 *consumedcntp = strlen(dfs_path);
914                 TALLOC_FREE(pdp);
915                 return NT_STATUS_OK;
916         }
917
918         status = create_conn_struct(ctx, &conn, snum, lp_pathname(snum),
919                                     NULL, &oldpath);
920         if (!NT_STATUS_IS_OK(status)) {
921                 TALLOC_FREE(pdp);
922                 return status;
923         }
924
925         /* If this is a DFS path dfs_lookup should return
926          * NT_STATUS_PATH_NOT_COVERED. */
927
928         status = dfs_path_lookup(ctx, conn, dfs_path, pdp,
929                         False, consumedcntp, &targetpath);
930
931         if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) {
932                 DEBUG(3,("get_referred_path: No valid referrals for path %s\n",
933                         dfs_path));
934                 vfs_ChDir(conn, oldpath);
935                 conn_free(conn);
936                 TALLOC_FREE(pdp);
937                 return status;
938         }
939
940         /* We know this is a valid dfs link. Parse the targetpath. */
941         if (!parse_msdfs_symlink(ctx, targetpath,
942                                 &jucn->referral_list,
943                                 &jucn->referral_count)) {
944                 DEBUG(3,("get_referred_path: failed to parse symlink "
945                         "target %s\n", targetpath ));
946                 vfs_ChDir(conn, oldpath);
947                 conn_free(conn);
948                 TALLOC_FREE(pdp);
949                 return NT_STATUS_NOT_FOUND;
950         }
951
952         vfs_ChDir(conn, oldpath);
953         conn_free(conn);
954         TALLOC_FREE(pdp);
955         return NT_STATUS_OK;
956 }
957
958 static int setup_ver2_dfs_referral(const char *pathname,
959                                 char **ppdata,
960                                 struct junction_map *junction,
961                                 bool self_referral)
962 {
963         char* pdata = *ppdata;
964
965         smb_ucs2_t *uni_requestedpath = NULL;
966         int uni_reqpathoffset1,uni_reqpathoffset2;
967         int uni_curroffset;
968         int requestedpathlen=0;
969         int offset;
970         int reply_size = 0;
971         int i=0;
972
973         DEBUG(10,("Setting up version2 referral\nRequested path:\n"));
974
975         requestedpathlen = rpcstr_push_talloc(talloc_tos(),
976                                         &uni_requestedpath, pathname);
977         if (uni_requestedpath == NULL || requestedpathlen == 0) {
978                 return -1;
979         }
980
981         if (DEBUGLVL(10)) {
982                 dump_data(0, (unsigned char *)uni_requestedpath,
983                         requestedpathlen);
984         }
985
986         DEBUG(10,("ref count = %u\n",junction->referral_count));
987
988         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
989                         VERSION2_REFERRAL_SIZE * junction->referral_count;
990
991         uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
992
993         uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
994
995         reply_size = REFERRAL_HEADER_SIZE +
996                         VERSION2_REFERRAL_SIZE*junction->referral_count +
997                         2 * requestedpathlen;
998         DEBUG(10,("reply_size: %u\n",reply_size));
999
1000         /* add up the unicode lengths of all the referral paths */
1001         for(i=0;i<junction->referral_count;i++) {
1002                 DEBUG(10,("referral %u : %s\n",
1003                         i,
1004                         junction->referral_list[i].alternate_path));
1005                 reply_size +=
1006                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1007         }
1008
1009         DEBUG(10,("reply_size = %u\n",reply_size));
1010         /* add the unexplained 0x16 bytes */
1011         reply_size += 0x16;
1012
1013         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1014         if(pdata == NULL) {
1015                 DEBUG(0,("Realloc failed!\n"));
1016                 return -1;
1017         }
1018         *ppdata = pdata;
1019
1020         /* copy in the dfs requested paths.. required for offset calculations */
1021         memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
1022         memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
1023
1024         /* create the header */
1025         SSVAL(pdata,0,requestedpathlen - 2); /* UCS2 of path consumed minus
1026                                                 2 byte null */
1027         /* number of referral in this pkt */
1028         SSVAL(pdata,2,junction->referral_count);
1029         if(self_referral) {
1030                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1031         } else {
1032                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1033         }
1034
1035         offset = 8;
1036         /* add the referral elements */
1037         for(i=0;i<junction->referral_count;i++) {
1038                 struct referral* ref = &junction->referral_list[i];
1039                 int unilen;
1040
1041                 SSVAL(pdata,offset,2); /* version 2 */
1042                 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
1043                 if(self_referral) {
1044                         SSVAL(pdata,offset+4,1);
1045                 } else {
1046                         SSVAL(pdata,offset+4,0);
1047                 }
1048
1049                 /* ref_flags :use path_consumed bytes? */
1050                 SSVAL(pdata,offset+6,0);
1051                 SIVAL(pdata,offset+8,ref->proximity);
1052                 SIVAL(pdata,offset+12,ref->ttl);
1053
1054                 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
1055                 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
1056                 /* copy referred path into current offset */
1057                 unilen = rpcstr_push(pdata+uni_curroffset,
1058                                         ref->alternate_path,
1059                                         reply_size - uni_curroffset,
1060                                         STR_UNICODE);
1061
1062                 SSVAL(pdata,offset+20,uni_curroffset-offset);
1063
1064                 uni_curroffset += unilen;
1065                 offset += VERSION2_REFERRAL_SIZE;
1066         }
1067         /* add in the unexplained 22 (0x16) bytes at the end */
1068         memset(pdata+uni_curroffset,'\0',0x16);
1069         return reply_size;
1070 }
1071
1072 static int setup_ver3_dfs_referral(const char *pathname,
1073                                 char **ppdata,
1074                                 struct junction_map *junction,
1075                                 bool self_referral)
1076 {
1077         char *pdata = *ppdata;
1078
1079         smb_ucs2_t *uni_reqpath = NULL;
1080         int uni_reqpathoffset1, uni_reqpathoffset2;
1081         int uni_curroffset;
1082         int reply_size = 0;
1083
1084         int reqpathlen = 0;
1085         int offset,i=0;
1086
1087         DEBUG(10,("setting up version3 referral\n"));
1088
1089         reqpathlen = rpcstr_push_talloc(talloc_tos(), &uni_reqpath, pathname);
1090         if (uni_reqpath == NULL || reqpathlen == 0) {
1091                 return -1;
1092         }
1093
1094         if (DEBUGLVL(10)) {
1095                 dump_data(0, (unsigned char *)uni_reqpath,
1096                         reqpathlen);
1097         }
1098
1099         uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
1100                         VERSION3_REFERRAL_SIZE * junction->referral_count;
1101         uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
1102         reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
1103
1104         for(i=0;i<junction->referral_count;i++) {
1105                 DEBUG(10,("referral %u : %s\n",
1106                         i,
1107                         junction->referral_list[i].alternate_path));
1108                 reply_size +=
1109                         (strlen(junction->referral_list[i].alternate_path)+1)*2;
1110         }
1111
1112         pdata = (char *)SMB_REALLOC(pdata,reply_size);
1113         if(pdata == NULL) {
1114                 DEBUG(0,("version3 referral setup:"
1115                         "malloc failed for Realloc!\n"));
1116                 return -1;
1117         }
1118         *ppdata = pdata;
1119
1120         /* create the header */
1121         SSVAL(pdata,0,reqpathlen - 2); /* UCS2 of path consumed minus
1122                                           2 byte null */
1123         SSVAL(pdata,2,junction->referral_count); /* number of referral */
1124         if(self_referral) {
1125                 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
1126         } else {
1127                 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
1128         }
1129
1130         /* copy in the reqpaths */
1131         memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
1132         memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
1133
1134         offset = 8;
1135         for(i=0;i<junction->referral_count;i++) {
1136                 struct referral* ref = &(junction->referral_list[i]);
1137                 int unilen;
1138
1139                 SSVAL(pdata,offset,3); /* version 3 */
1140                 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
1141                 if(self_referral) {
1142                         SSVAL(pdata,offset+4,1);
1143                 } else {
1144                         SSVAL(pdata,offset+4,0);
1145                 }
1146
1147                 /* ref_flags :use path_consumed bytes? */
1148                 SSVAL(pdata,offset+6,0);
1149                 SIVAL(pdata,offset+8,ref->ttl);
1150
1151                 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
1152                 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
1153                 /* copy referred path into current offset */
1154                 unilen = rpcstr_push(pdata+uni_curroffset,ref->alternate_path,
1155                                         reply_size - uni_curroffset,
1156                                         STR_UNICODE | STR_TERMINATE);
1157                 SSVAL(pdata,offset+16,uni_curroffset-offset);
1158                 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
1159                 memset(pdata+offset+18,'\0',16);
1160
1161                 uni_curroffset += unilen;
1162                 offset += VERSION3_REFERRAL_SIZE;
1163         }
1164         return reply_size;
1165 }
1166
1167 /******************************************************************
1168  Set up the DFS referral for the dfs pathname. This call returns
1169  the amount of the path covered by this server, and where the
1170  client should be redirected to. This is the meat of the
1171  TRANS2_GET_DFS_REFERRAL call.
1172 ******************************************************************/
1173
1174 int setup_dfs_referral(connection_struct *orig_conn,
1175                         const char *dfs_path,
1176                         int max_referral_level,
1177                         char **ppdata, NTSTATUS *pstatus)
1178 {
1179         struct junction_map *junction = NULL;
1180         int consumedcnt = 0;
1181         bool self_referral = False;
1182         int reply_size = 0;
1183         char *pathnamep = NULL;
1184         char *local_dfs_path = NULL;
1185         TALLOC_CTX *ctx;
1186
1187         if (!(ctx=talloc_init("setup_dfs_referral"))) {
1188                 *pstatus = NT_STATUS_NO_MEMORY;
1189                 return -1;
1190         }
1191
1192         /* get the junction entry */
1193         if (!dfs_path) {
1194                 talloc_destroy(ctx);
1195                 *pstatus = NT_STATUS_NOT_FOUND;
1196                 return -1;
1197         }
1198
1199         /*
1200          * Trim pathname sent by client so it begins with only one backslash.
1201          * Two backslashes confuse some dfs clients
1202          */
1203
1204         local_dfs_path = talloc_strdup(ctx,dfs_path);
1205         if (!local_dfs_path) {
1206                 *pstatus = NT_STATUS_NO_MEMORY;
1207                 talloc_destroy(ctx);
1208                 return -1;
1209         }
1210         pathnamep = local_dfs_path;
1211         while (IS_DIRECTORY_SEP(pathnamep[0]) &&
1212                         IS_DIRECTORY_SEP(pathnamep[1])) {
1213                 pathnamep++;
1214         }
1215
1216         junction = TALLOC_ZERO_P(ctx, struct junction_map);
1217         if (!junction) {
1218                 *pstatus = NT_STATUS_NO_MEMORY;
1219                 talloc_destroy(ctx);
1220                 return -1;
1221         }
1222
1223         /* The following call can change cwd. */
1224         *pstatus = get_referred_path(ctx, pathnamep, junction,
1225                         &consumedcnt, &self_referral);
1226         if (!NT_STATUS_IS_OK(*pstatus)) {
1227                 vfs_ChDir(orig_conn,orig_conn->connectpath);
1228                 talloc_destroy(ctx);
1229                 return -1;
1230         }
1231         vfs_ChDir(orig_conn,orig_conn->connectpath);
1232
1233         if (!self_referral) {
1234                 pathnamep[consumedcnt] = '\0';
1235
1236                 if( DEBUGLVL( 3 ) ) {
1237                         int i=0;
1238                         dbgtext("setup_dfs_referral: Path %s to "
1239                                 "alternate path(s):",
1240                                 pathnamep);
1241                         for(i=0;i<junction->referral_count;i++)
1242                                 dbgtext(" %s",
1243                                 junction->referral_list[i].alternate_path);
1244                         dbgtext(".\n");
1245                 }
1246         }
1247
1248         /* create the referral depeding on version */
1249         DEBUG(10,("max_referral_level :%d\n",max_referral_level));
1250
1251         if (max_referral_level < 2) {
1252                 max_referral_level = 2;
1253         }
1254         if (max_referral_level > 3) {
1255                 max_referral_level = 3;
1256         }
1257
1258         switch(max_referral_level) {
1259         case 2:
1260                 reply_size = setup_ver2_dfs_referral(pathnamep,
1261                                         ppdata, junction,
1262                                         self_referral);
1263                 break;
1264         case 3:
1265                 reply_size = setup_ver3_dfs_referral(pathnamep, ppdata,
1266                                         junction, self_referral);
1267                 break;
1268         default:
1269                 DEBUG(0,("setup_dfs_referral: Invalid dfs referral "
1270                         "version: %d\n",
1271                         max_referral_level));
1272                 talloc_destroy(ctx);
1273                 *pstatus = NT_STATUS_INVALID_LEVEL;
1274                 return -1;
1275         }
1276
1277         if (DEBUGLVL(10)) {
1278                 DEBUGADD(0,("DFS Referral pdata:\n"));
1279                 dump_data(0,(uint8 *)*ppdata,reply_size);
1280         }
1281
1282         talloc_destroy(ctx);
1283         *pstatus = NT_STATUS_OK;
1284         return reply_size;
1285 }
1286
1287 /**********************************************************************
1288  The following functions are called by the NETDFS RPC pipe functions
1289  **********************************************************************/
1290
1291 /*********************************************************************
1292  Creates a junction structure from a DFS pathname
1293 **********************************************************************/
1294
1295 bool create_junction(TALLOC_CTX *ctx,
1296                 const char *dfs_path,
1297                 struct junction_map *jucn)
1298 {
1299         int snum;
1300         bool dummy;
1301         struct dfs_path *pdp = TALLOC_P(ctx,struct dfs_path);
1302         NTSTATUS status;
1303
1304         if (!pdp) {
1305                 return False;
1306         }
1307         status = parse_dfs_path(NULL, dfs_path, False, pdp, &dummy);
1308         if (!NT_STATUS_IS_OK(status)) {
1309                 return False;
1310         }
1311
1312         /* check if path is dfs : validate first token */
1313         if (!is_myname_or_ipaddr(pdp->hostname)) {
1314                 DEBUG(4,("create_junction: Invalid hostname %s "
1315                         "in dfs path %s\n",
1316                         pdp->hostname, dfs_path));
1317                 TALLOC_FREE(pdp);
1318                 return False;
1319         }
1320
1321         /* Check for a non-DFS share */
1322         snum = lp_servicenumber(pdp->servicename);
1323
1324         if(snum < 0 || !lp_msdfs_root(snum)) {
1325                 DEBUG(4,("create_junction: %s is not an msdfs root.\n",
1326                         pdp->servicename));
1327                 TALLOC_FREE(pdp);
1328                 return False;
1329         }
1330
1331         jucn->service_name = talloc_strdup(ctx, pdp->servicename);
1332         jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
1333         jucn->comment = talloc_strdup(ctx, lp_comment(snum));
1334
1335         TALLOC_FREE(pdp);
1336         if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) {
1337                 return False;
1338         }
1339         return True;
1340 }
1341
1342 /**********************************************************************
1343  Forms a valid Unix pathname from the junction
1344  **********************************************************************/
1345
1346 static bool junction_to_local_path(const struct junction_map *jucn,
1347                                    char **pp_path_out,
1348                                    connection_struct **conn_out,
1349                                    char **oldpath)
1350 {
1351         int snum;
1352         NTSTATUS status;
1353
1354         snum = lp_servicenumber(jucn->service_name);
1355         if(snum < 0) {
1356                 return False;
1357         }
1358         status = create_conn_struct(talloc_tos(), conn_out, snum,
1359                                     lp_pathname(snum), NULL, oldpath);
1360         if (!NT_STATUS_IS_OK(status)) {
1361                 return False;
1362         }
1363
1364         *pp_path_out = talloc_asprintf(*conn_out,
1365                         "%s/%s",
1366                         lp_pathname(snum),
1367                         jucn->volume_name);
1368         if (!*pp_path_out) {
1369                 vfs_ChDir(*conn_out, *oldpath);
1370                 conn_free(*conn_out);
1371                 return False;
1372         }
1373         return True;
1374 }
1375
1376 bool create_msdfs_link(const struct junction_map *jucn)
1377 {
1378         char *path = NULL;
1379         char *cwd;
1380         char *msdfs_link = NULL;
1381         connection_struct *conn;
1382         int i=0;
1383         bool insert_comma = False;
1384         bool ret = False;
1385
1386         if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1387                 return False;
1388         }
1389
1390         /* Form the msdfs_link contents */
1391         msdfs_link = talloc_strdup(conn, "msdfs:");
1392         if (!msdfs_link) {
1393                 goto out;
1394         }
1395         for(i=0; i<jucn->referral_count; i++) {
1396                 char *refpath = jucn->referral_list[i].alternate_path;
1397
1398                 /* Alternate paths always use Windows separators. */
1399                 trim_char(refpath, '\\', '\\');
1400                 if(*refpath == '\0') {
1401                         if (i == 0) {
1402                                 insert_comma = False;
1403                         }
1404                         continue;
1405                 }
1406                 if (i > 0 && insert_comma) {
1407                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1408                                         ",%s",
1409                                         refpath);
1410                 } else {
1411                         msdfs_link = talloc_asprintf_append_buffer(msdfs_link,
1412                                         "%s",
1413                                         refpath);
1414                 }
1415
1416                 if (!msdfs_link) {
1417                         goto out;
1418                 }
1419                 if (!insert_comma) {
1420                         insert_comma = True;
1421                 }
1422         }
1423
1424         DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
1425                 path, msdfs_link));
1426
1427         if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1428                 if (errno == EEXIST) {
1429                         struct smb_filename *smb_fname = NULL;
1430                         NTSTATUS status;
1431
1432                         status = create_synthetic_smb_fname(talloc_tos(), path,
1433                                                             NULL, NULL,
1434                                                             &smb_fname);
1435                         if (!NT_STATUS_IS_OK(status)) {
1436                                 errno = map_errno_from_nt_status(status);
1437                                 goto out;
1438                         }
1439
1440                         if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
1441                                 TALLOC_FREE(smb_fname);
1442                                 goto out;
1443                         }
1444                         TALLOC_FREE(smb_fname);
1445                 }
1446                 if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
1447                         DEBUG(1,("create_msdfs_link: symlink failed "
1448                                  "%s -> %s\nError: %s\n",
1449                                  path, msdfs_link, strerror(errno)));
1450                         goto out;
1451                 }
1452         }
1453
1454         ret = True;
1455
1456 out:
1457         vfs_ChDir(conn, cwd);
1458         conn_free(conn);
1459         return ret;
1460 }
1461
1462 bool remove_msdfs_link(const struct junction_map *jucn)
1463 {
1464         char *path = NULL;
1465         char *cwd;
1466         connection_struct *conn;
1467         bool ret = False;
1468         struct smb_filename *smb_fname = NULL;
1469         NTSTATUS status;
1470
1471         if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
1472                 return false;
1473         }
1474
1475         status = create_synthetic_smb_fname(talloc_tos(), path,
1476                                             NULL, NULL,
1477                                             &smb_fname);
1478         if (!NT_STATUS_IS_OK(status)) {
1479                 errno = map_errno_from_nt_status(status);
1480                 return false;
1481         }
1482
1483         if( SMB_VFS_UNLINK(conn, smb_fname) == 0 ) {
1484                 ret = True;
1485         }
1486
1487         TALLOC_FREE(smb_fname);
1488         vfs_ChDir(conn, cwd);
1489         conn_free(conn);
1490         return ret;
1491 }
1492
1493 /*********************************************************************
1494  Return the number of DFS links at the root of this share.
1495 *********************************************************************/
1496
1497 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
1498 {
1499         size_t cnt = 0;
1500         SMB_STRUCT_DIR *dirp = NULL;
1501         const char *dname = NULL;
1502         char *talloced = NULL;
1503         const char *connect_path = lp_pathname(snum);
1504         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1505         connection_struct *conn;
1506         NTSTATUS status;
1507         char *cwd;
1508
1509         if(*connect_path == '\0') {
1510                 return 0;
1511         }
1512
1513         /*
1514          * Fake up a connection struct for the VFS layer.
1515          */
1516
1517         status = create_conn_struct(talloc_tos(), &conn, snum, connect_path,
1518                                     NULL, &cwd);
1519         if (!NT_STATUS_IS_OK(status)) {
1520                 DEBUG(3, ("create_conn_struct failed: %s\n",
1521                           nt_errstr(status)));
1522                 return 0;
1523         }
1524
1525         /* Count a link for the msdfs root - convention */
1526         cnt = 1;
1527
1528         /* No more links if this is an msdfs proxy. */
1529         if (*msdfs_proxy != '\0') {
1530                 goto out;
1531         }
1532
1533         /* Now enumerate all dfs links */
1534         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1535         if(!dirp) {
1536                 goto out;
1537         }
1538
1539         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1540                != NULL) {
1541                 if (is_msdfs_link(conn,
1542                                 dname,
1543                                 NULL)) {
1544                         cnt++;
1545                 }
1546                 TALLOC_FREE(talloced);
1547         }
1548
1549         SMB_VFS_CLOSEDIR(conn,dirp);
1550
1551 out:
1552         vfs_ChDir(conn, cwd);
1553         conn_free(conn);
1554         return cnt;
1555 }
1556
1557 /*********************************************************************
1558 *********************************************************************/
1559
1560 static int form_junctions(TALLOC_CTX *ctx,
1561                                 int snum,
1562                                 struct junction_map *jucn,
1563                                 size_t jn_remain)
1564 {
1565         size_t cnt = 0;
1566         SMB_STRUCT_DIR *dirp = NULL;
1567         const char *dname = NULL;
1568         char *talloced = NULL;
1569         const char *connect_path = lp_pathname(snum);
1570         char *service_name = lp_servicename(snum);
1571         const char *msdfs_proxy = lp_msdfs_proxy(snum);
1572         connection_struct *conn;
1573         struct referral *ref = NULL;
1574         char *cwd;
1575         NTSTATUS status;
1576
1577         if (jn_remain == 0) {
1578                 return 0;
1579         }
1580
1581         if(*connect_path == '\0') {
1582                 return 0;
1583         }
1584
1585         /*
1586          * Fake up a connection struct for the VFS layer.
1587          */
1588
1589         status = create_conn_struct(ctx, &conn, snum, connect_path, NULL,
1590                                     &cwd);
1591         if (!NT_STATUS_IS_OK(status)) {
1592                 DEBUG(3, ("create_conn_struct failed: %s\n",
1593                           nt_errstr(status)));
1594                 return 0;
1595         }
1596
1597         /* form a junction for the msdfs root - convention
1598            DO NOT REMOVE THIS: NT clients will not work with us
1599            if this is not present
1600         */
1601         jucn[cnt].service_name = talloc_strdup(ctx,service_name);
1602         jucn[cnt].volume_name = talloc_strdup(ctx, "");
1603         if (!jucn[cnt].service_name || !jucn[cnt].volume_name) {
1604                 goto out;
1605         }
1606         jucn[cnt].comment = "";
1607         jucn[cnt].referral_count = 1;
1608
1609         ref = jucn[cnt].referral_list = TALLOC_ZERO_P(ctx, struct referral);
1610         if (jucn[cnt].referral_list == NULL) {
1611                 goto out;
1612         }
1613
1614         ref->proximity = 0;
1615         ref->ttl = REFERRAL_TTL;
1616         if (*msdfs_proxy != '\0') {
1617                 ref->alternate_path = talloc_strdup(ctx,
1618                                                 msdfs_proxy);
1619         } else {
1620                 ref->alternate_path = talloc_asprintf(ctx,
1621                         "\\\\%s\\%s",
1622                         get_local_machine_name(),
1623                         service_name);
1624         }
1625
1626         if (!ref->alternate_path) {
1627                 goto out;
1628         }
1629         cnt++;
1630
1631         /* Don't enumerate if we're an msdfs proxy. */
1632         if (*msdfs_proxy != '\0') {
1633                 goto out;
1634         }
1635
1636         /* Now enumerate all dfs links */
1637         dirp = SMB_VFS_OPENDIR(conn, ".", NULL, 0);
1638         if(!dirp) {
1639                 goto out;
1640         }
1641
1642         while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
1643                != NULL) {
1644                 char *link_target = NULL;
1645                 if (cnt >= jn_remain) {
1646                         DEBUG(2, ("form_junctions: ran out of MSDFS "
1647                                 "junction slots"));
1648                         TALLOC_FREE(talloced);
1649                         goto out;
1650                 }
1651                 if (is_msdfs_link_internal(ctx,
1652                                         conn,
1653                                         dname, &link_target,
1654                                         NULL)) {
1655                         if (parse_msdfs_symlink(ctx,
1656                                         link_target,
1657                                         &jucn[cnt].referral_list,
1658                                         &jucn[cnt].referral_count)) {
1659
1660                                 jucn[cnt].service_name = talloc_strdup(ctx,
1661                                                                 service_name);
1662                                 jucn[cnt].volume_name = talloc_strdup(ctx,
1663                                                                 dname);
1664                                 if (!jucn[cnt].service_name ||
1665                                                 !jucn[cnt].volume_name) {
1666                                         TALLOC_FREE(talloced);
1667                                         goto out;
1668                                 }
1669                                 jucn[cnt].comment = "";
1670                                 cnt++;
1671                         }
1672                         TALLOC_FREE(link_target);
1673                 }
1674                 TALLOC_FREE(talloced);
1675         }
1676
1677 out:
1678
1679         if (dirp) {
1680                 SMB_VFS_CLOSEDIR(conn,dirp);
1681         }
1682
1683         vfs_ChDir(conn, cwd);
1684         conn_free(conn);
1685         return cnt;
1686 }
1687
1688 struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, size_t *p_num_jn)
1689 {
1690         struct junction_map *jn = NULL;
1691         int i=0;
1692         size_t jn_count = 0;
1693         int sharecount = 0;
1694
1695         *p_num_jn = 0;
1696         if(!lp_host_msdfs()) {
1697                 return NULL;
1698         }
1699
1700         /* Ensure all the usershares are loaded. */
1701         become_root();
1702         load_registry_shares();
1703         sharecount = load_usershare_shares();
1704         unbecome_root();
1705
1706         for(i=0;i < sharecount;i++) {
1707                 if(lp_msdfs_root(i)) {
1708                         jn_count += count_dfs_links(ctx, i);
1709                 }
1710         }
1711         if (jn_count == 0) {
1712                 return NULL;
1713         }
1714         jn = TALLOC_ARRAY(ctx,  struct junction_map, jn_count);
1715         if (!jn) {
1716                 return NULL;
1717         }
1718         for(i=0; i < sharecount; i++) {
1719                 if (*p_num_jn >= jn_count) {
1720                         break;
1721                 }
1722                 if(lp_msdfs_root(i)) {
1723                         *p_num_jn += form_junctions(ctx, i,
1724                                         &jn[*p_num_jn],
1725                                         jn_count - *p_num_jn);
1726                 }
1727         }
1728         return jn;
1729 }
1730
1731 /******************************************************************************
1732  Core function to resolve a dfs pathname possibly containing a wildcard.  If
1733  ppath_contains_wcard != NULL, it will be set to true if a wildcard is
1734  detected during dfs resolution.
1735 ******************************************************************************/
1736
1737 NTSTATUS resolve_dfspath_wcard(TALLOC_CTX *ctx,
1738                                 connection_struct *conn,
1739                                 bool dfs_pathnames,
1740                                 const char *name_in,
1741                                 char **pp_name_out,
1742                                 bool *ppath_contains_wcard)
1743 {
1744         bool path_contains_wcard;
1745         NTSTATUS status = NT_STATUS_OK;
1746
1747         if (dfs_pathnames) {
1748                 status = dfs_redirect(ctx,
1749                                         conn,
1750                                         name_in,
1751                                         True,
1752                                         pp_name_out,
1753                                         &path_contains_wcard);
1754
1755                 if (NT_STATUS_IS_OK(status) && ppath_contains_wcard != NULL) {
1756                         *ppath_contains_wcard = path_contains_wcard;
1757                 }
1758         } else {
1759                 /*
1760                  * Cheat and just return a copy of the in ptr.
1761                  * Once srvstr_get_path() uses talloc it'll
1762                  * be a talloced ptr anyway.
1763                  */
1764                 *pp_name_out = CONST_DISCARD(char *,name_in);
1765         }
1766         return status;
1767 }