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