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