LCOV - code coverage report
Current view: top level - source3/smbd - msdfs.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 373 857 43.5 %
Date: 2024-02-14 10:14:15 Functions: 15 24 62.5 %

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

Generated by: LCOV version 1.14