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