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