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