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