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