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

Generated by: LCOV version 1.14