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