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