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