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