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