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