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