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