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