LCOV - code coverage report
Current view: top level - source3/smbd - msdfs.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 349 821 42.5 %
Date: 2024-06-13 04:01:37 Functions: 14 23 60.9 %

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

Generated by: LCOV version 1.13