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