LCOV - code coverage report
Current view: top level - source3/smbd - msdfs.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 342 793 43.1 %
Date: 2024-05-31 13:13:24 Functions: 14 21 66.7 %

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

Generated by: LCOV version 1.14