LCOV - code coverage report
Current view: top level - source3/libsmb - clisymlink.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 69 184 37.5 %
Date: 2024-06-13 04:01:37 Functions: 7 13 53.8 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * Client implementation of setting symlinks using reparse points
       4             :  * Copyright (C) Volker Lendecke 2011
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/filesys.h"
      22             : #include "libsmb/libsmb.h"
      23             : #include "../lib/util/tevent_ntstatus.h"
      24             : #include "async_smb.h"
      25             : #include "libsmb/clirap.h"
      26             : #include "trans2.h"
      27             : #include "libcli/security/secdesc.h"
      28             : #include "libcli/security/security.h"
      29             : #include "../libcli/smb/smbXcli_base.h"
      30             : #include "libcli/smb/reparse_symlink.h"
      31             : 
      32             : struct cli_symlink_state {
      33             :         struct tevent_context *ev;
      34             :         struct cli_state *cli;
      35             :         const char *link_target;
      36             :         const char *newpath;
      37             :         uint32_t flags;
      38             : 
      39             :         uint16_t fnum;
      40             : 
      41             :         uint16_t setup[4];
      42             :         NTSTATUS set_reparse_status;
      43             : };
      44             : 
      45             : static void cli_symlink_create_done(struct tevent_req *subreq);
      46             : static void cli_symlink_set_reparse_done(struct tevent_req *subreq);
      47             : static void cli_symlink_delete_on_close_done(struct tevent_req *subreq);
      48             : static void cli_symlink_close_done(struct tevent_req *subreq);
      49             : 
      50           4 : struct tevent_req *cli_symlink_send(TALLOC_CTX *mem_ctx,
      51             :                                     struct tevent_context *ev,
      52             :                                     struct cli_state *cli,
      53             :                                     const char *link_target,
      54             :                                     const char *newpath,
      55             :                                     uint32_t flags)
      56             : {
      57             :         struct tevent_req *req, *subreq;
      58             :         struct cli_symlink_state *state;
      59             : 
      60           4 :         req = tevent_req_create(mem_ctx, &state, struct cli_symlink_state);
      61           4 :         if (req == NULL) {
      62           0 :                 return NULL;
      63             :         }
      64           4 :         state->ev = ev;
      65           4 :         state->cli = cli;
      66           4 :         state->link_target = link_target;
      67           4 :         state->newpath = newpath;
      68           4 :         state->flags = flags;
      69             : 
      70           4 :         subreq = cli_ntcreate_send(
      71           4 :                 state, ev, cli, state->newpath, 0,
      72             :                 SYNCHRONIZE_ACCESS|DELETE_ACCESS|
      73             :                 FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
      74             :                 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_CREATE,
      75             :                 FILE_OPEN_REPARSE_POINT|FILE_SYNCHRONOUS_IO_NONALERT|
      76             :                 FILE_NON_DIRECTORY_FILE,
      77             :                 SMB2_IMPERSONATION_IMPERSONATION, 0);
      78           4 :         if (tevent_req_nomem(subreq, req)) {
      79           0 :                 return tevent_req_post(req, ev);
      80             :         }
      81           4 :         tevent_req_set_callback(subreq, cli_symlink_create_done, req);
      82           4 :         return req;
      83             : }
      84             : 
      85           4 : static void cli_symlink_create_done(struct tevent_req *subreq)
      86             : {
      87           4 :         struct tevent_req *req = tevent_req_callback_data(
      88             :                 subreq, struct tevent_req);
      89           4 :         struct cli_symlink_state *state = tevent_req_data(
      90             :                 req, struct cli_symlink_state);
      91             :         DATA_BLOB data;
      92             :         NTSTATUS status;
      93             : 
      94           4 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
      95           4 :         TALLOC_FREE(subreq);
      96           4 :         if (tevent_req_nterror(req, status)) {
      97           0 :                 return;
      98             :         }
      99             : 
     100           4 :         if (!symlink_reparse_buffer_marshall(
     101             :                     state->link_target, NULL, state->flags, state,
     102             :                     &data.data, &data.length)) {
     103           0 :                 tevent_req_oom(req);
     104           0 :                 return;
     105             :         }
     106             : 
     107           4 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     108           4 :                 subreq = cli_smb2_set_reparse_point_fnum_send(state,
     109             :                                                 state->ev,
     110             :                                                 state->cli,
     111           4 :                                                 state->fnum,
     112             :                                                 data);
     113             :         } else {
     114           0 :                 SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
     115           0 :                 SSVAL(state->setup, 4, state->fnum);
     116           0 :                 SCVAL(state->setup, 6, 1); /* IsFcntl */
     117           0 :                 SCVAL(state->setup, 7, 0); /* IsFlags */
     118             : 
     119             : 
     120           0 :                 subreq = cli_trans_send(state, state->ev, state->cli, 0,
     121             :                                 SMBnttrans,
     122             :                                 NULL, -1, /* name, fid */
     123             :                                 NT_TRANSACT_IOCTL, 0,
     124           0 :                                 state->setup, 4, 0, /* setup */
     125             :                                 NULL, 0, 0,         /* param */
     126           0 :                                 data.data, data.length, 0); /* data */
     127             :         }
     128             : 
     129           4 :         if (tevent_req_nomem(subreq, req)) {
     130           0 :                 return;
     131             :         }
     132           4 :         tevent_req_set_callback(subreq, cli_symlink_set_reparse_done, req);
     133             : }
     134             : 
     135           4 : static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
     136             : {
     137           4 :         struct tevent_req *req = tevent_req_callback_data(
     138             :                 subreq, struct tevent_req);
     139           4 :         struct cli_symlink_state *state = tevent_req_data(
     140             :                 req, struct cli_symlink_state);
     141             : 
     142           4 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     143           2 :                 state->set_reparse_status =
     144           2 :                         cli_smb2_set_reparse_point_fnum_recv(subreq);
     145             :         } else {
     146           0 :                 state->set_reparse_status = cli_trans_recv(
     147             :                         subreq, NULL, NULL,
     148             :                         NULL, 0, NULL,  /* rsetup */
     149             :                         NULL, 0, NULL,  /* rparam */
     150             :                         NULL, 0, NULL); /* rdata */
     151             :         }
     152           4 :         TALLOC_FREE(subreq);
     153             : 
     154           4 :         if (NT_STATUS_IS_OK(state->set_reparse_status)) {
     155           0 :                 subreq = cli_close_send(state, state->ev, state->cli,
     156           0 :                                         state->fnum);
     157           0 :                 if (tevent_req_nomem(subreq, req)) {
     158           0 :                         return;
     159             :                 }
     160           0 :                 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     161           0 :                 return;
     162             :         }
     163           4 :         subreq = cli_nt_delete_on_close_send(
     164           4 :                 state, state->ev, state->cli, state->fnum, true);
     165           4 :         if (tevent_req_nomem(subreq, req)) {
     166           0 :                 return;
     167             :         }
     168           4 :         tevent_req_set_callback(subreq, cli_symlink_delete_on_close_done, req);
     169             : }
     170             : 
     171           4 : static void cli_symlink_delete_on_close_done(struct tevent_req *subreq)
     172             : {
     173           4 :         struct tevent_req *req = tevent_req_callback_data(
     174             :                 subreq, struct tevent_req);
     175           4 :         struct cli_symlink_state *state = tevent_req_data(
     176             :                 req, struct cli_symlink_state);
     177             : 
     178             :         /*
     179             :          * Ignore status, we can't do much anyway in case of failure
     180             :          */
     181             : 
     182           4 :         (void)cli_nt_delete_on_close_recv(subreq);
     183           4 :         TALLOC_FREE(subreq);
     184             : 
     185           4 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     186           4 :         if (tevent_req_nomem(subreq, req)) {
     187           0 :                 return;
     188             :         }
     189           4 :         tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     190             : }
     191             : 
     192           4 : static void cli_symlink_close_done(struct tevent_req *subreq)
     193             : {
     194           4 :         struct tevent_req *req = tevent_req_callback_data(
     195             :                 subreq, struct tevent_req);
     196           4 :         struct cli_symlink_state *state = tevent_req_data(
     197             :                 req, struct cli_symlink_state);
     198             :         NTSTATUS status;
     199             : 
     200           4 :         status = cli_close_recv(subreq);
     201           4 :         TALLOC_FREE(subreq);
     202             : 
     203           4 :         if (tevent_req_nterror(req, status)) {
     204           4 :                 return;
     205             :         }
     206           4 :         if (tevent_req_nterror(req, state->set_reparse_status)) {
     207           4 :                 return;
     208             :         }
     209           0 :         tevent_req_done(req);
     210             : }
     211             : 
     212           4 : NTSTATUS cli_symlink_recv(struct tevent_req *req)
     213             : {
     214           4 :         return tevent_req_simple_recv_ntstatus(req);
     215             : }
     216             : 
     217           4 : NTSTATUS cli_symlink(struct cli_state *cli, const char *link_target,
     218             :                      const char *newname, uint32_t flags)
     219             : {
     220           4 :         TALLOC_CTX *frame = talloc_stackframe();
     221             :         struct tevent_context *ev;
     222             :         struct tevent_req *req;
     223           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     224             : 
     225           4 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     226           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     227           0 :                 goto fail;
     228             :         }
     229           4 :         ev = samba_tevent_context_init(frame);
     230           4 :         if (ev == NULL) {
     231           0 :                 goto fail;
     232             :         }
     233           4 :         req = cli_symlink_send(frame, ev, cli, link_target, newname, flags);
     234           4 :         if (req == NULL) {
     235           0 :                 goto fail;
     236             :         }
     237           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     238           0 :                 goto fail;
     239             :         }
     240           4 :         status = cli_symlink_recv(req);
     241           4 :  fail:
     242           4 :         TALLOC_FREE(frame);
     243           4 :         return status;
     244             : }
     245             : 
     246             : struct cli_readlink_state {
     247             :         struct tevent_context *ev;
     248             :         struct cli_state *cli;
     249             :         uint16_t fnum;
     250             : 
     251             :         uint16_t setup[4];
     252             :         NTSTATUS get_reparse_status;
     253             :         uint8_t *data;
     254             :         uint32_t num_data;
     255             : };
     256             : 
     257             : static void cli_readlink_opened(struct tevent_req *subreq);
     258             : static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
     259             : static void cli_readlink_closed(struct tevent_req *subreq);
     260             : 
     261           0 : struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
     262             :                                      struct tevent_context *ev,
     263             :                                      struct cli_state *cli,
     264             :                                      const char *fname)
     265             : {
     266             :         struct tevent_req *req, *subreq;
     267             :         struct cli_readlink_state *state;
     268             : 
     269           0 :         req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
     270           0 :         if (req == NULL) {
     271           0 :                 return NULL;
     272             :         }
     273           0 :         state->ev = ev;
     274           0 :         state->cli = cli;
     275             : 
     276           0 :         subreq = cli_ntcreate_send(
     277             :                 state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
     278             :                 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     279             :                 FILE_OPEN, FILE_OPEN_REPARSE_POINT,
     280             :                 SMB2_IMPERSONATION_IMPERSONATION, 0);
     281           0 :         if (tevent_req_nomem(subreq, req)) {
     282           0 :                 return tevent_req_post(req, ev);
     283             :         }
     284           0 :         tevent_req_set_callback(subreq, cli_readlink_opened, req);
     285           0 :         return req;
     286             : }
     287             : 
     288           0 : static void cli_readlink_opened(struct tevent_req *subreq)
     289             : {
     290           0 :         struct tevent_req *req = tevent_req_callback_data(
     291             :                 subreq, struct tevent_req);
     292           0 :         struct cli_readlink_state *state = tevent_req_data(
     293             :                 req, struct cli_readlink_state);
     294             :         NTSTATUS status;
     295             : 
     296           0 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
     297           0 :         TALLOC_FREE(subreq);
     298           0 :         if (tevent_req_nterror(req, status)) {
     299           0 :                 return;
     300             :         }
     301             : 
     302           0 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     303           0 :                 subreq = cli_smb2_get_reparse_point_fnum_send(state,
     304             :                                                 state->ev,
     305             :                                                 state->cli,
     306           0 :                                                 state->fnum);
     307             :         } else {
     308           0 :                 SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
     309           0 :                 SSVAL(state->setup, 4, state->fnum);
     310           0 :                 SCVAL(state->setup, 6, 1); /* IsFcntl */
     311           0 :                 SCVAL(state->setup, 7, 0); /* IsFlags */
     312             : 
     313           0 :                 subreq = cli_trans_send(state, state->ev, state->cli,
     314             :                                 0, SMBnttrans,
     315             :                                 NULL, -1, /* name, fid */
     316             :                                 NT_TRANSACT_IOCTL, 0,
     317           0 :                                 state->setup, 4, 0, /* setup */
     318             :                                 NULL, 0, 0,         /* param */
     319             :                                 NULL, 0, 16384); /* data */
     320             :         }
     321             : 
     322           0 :         if (tevent_req_nomem(subreq, req)) {
     323           0 :                 return;
     324             :         }
     325           0 :         tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
     326             : }
     327             : 
     328           0 : static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
     329             : {
     330           0 :         struct tevent_req *req = tevent_req_callback_data(
     331             :                 subreq, struct tevent_req);
     332           0 :         struct cli_readlink_state *state = tevent_req_data(
     333             :                 req, struct cli_readlink_state);
     334             : 
     335           0 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     336             :                 DATA_BLOB recv_data;
     337           0 :                 state->get_reparse_status =
     338           0 :                         cli_smb2_get_reparse_point_fnum_recv(subreq,
     339             :                                                         state,
     340             :                                                         &recv_data);
     341           0 :                 if (NT_STATUS_IS_OK(state->get_reparse_status)) {
     342           0 :                         state->data = recv_data.data;
     343           0 :                         state->num_data = recv_data.length;
     344             :                 }
     345             :         } else {
     346           0 :                 state->get_reparse_status = cli_trans_recv(
     347             :                         subreq, state, NULL,
     348             :                         NULL, 0, NULL,  /* rsetup */
     349             :                         NULL, 0, NULL,  /* rparam */
     350             :                         &state->data, 20, &state->num_data); /* rdata */
     351             :         }
     352           0 :         TALLOC_FREE(subreq);
     353             : 
     354           0 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     355           0 :         if (tevent_req_nomem(subreq, req)) {
     356           0 :                 return;
     357             :         }
     358           0 :         tevent_req_set_callback(subreq, cli_readlink_closed, req);
     359             : }
     360             : 
     361           0 : static void cli_readlink_closed(struct tevent_req *subreq)
     362             : {
     363           0 :         struct tevent_req *req = tevent_req_callback_data(
     364             :                 subreq, struct tevent_req);
     365             :         NTSTATUS status;
     366             : 
     367           0 :         status = cli_close_recv(subreq);
     368           0 :         TALLOC_FREE(subreq);
     369           0 :         if (tevent_req_nterror(req, status)) {
     370           0 :                 return;
     371             :         }
     372           0 :         tevent_req_done(req);
     373             : }
     374             : 
     375           0 : NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     376             :                            char **psubstitute_name, char **pprint_name,
     377             :                            uint32_t *pflags)
     378             : {
     379           0 :         struct cli_readlink_state *state = tevent_req_data(
     380             :                 req, struct cli_readlink_state);
     381           0 :         struct symlink_reparse_struct *symlink = NULL;
     382             :         NTSTATUS status;
     383             : 
     384           0 :         if (tevent_req_is_nterror(req, &status)) {
     385           0 :                 return status;
     386             :         }
     387             : 
     388           0 :         symlink = symlink_reparse_buffer_parse(
     389           0 :                 talloc_tos(), state->data, state->num_data);
     390           0 :         if (symlink == NULL) {
     391           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     392             :         }
     393             : 
     394           0 :         if (psubstitute_name != NULL) {
     395           0 :                 *psubstitute_name = talloc_move(
     396             :                         mem_ctx, &symlink->substitute_name);
     397             :         }
     398             : 
     399           0 :         if (pprint_name != NULL) {
     400           0 :                 *pprint_name = talloc_move(mem_ctx, &symlink->print_name);
     401             :         }
     402             : 
     403           0 :         if (pflags != NULL) {
     404           0 :                 *pflags = symlink->flags;
     405             :         }
     406             : 
     407           0 :         TALLOC_FREE(symlink);
     408             : 
     409           0 :         return NT_STATUS_OK;
     410             : }
     411             : 
     412           0 : NTSTATUS cli_readlink(struct cli_state *cli, const char *fname,
     413             :                        TALLOC_CTX *mem_ctx, char **psubstitute_name,
     414             :                       char **pprint_name, uint32_t *pflags)
     415             : {
     416           0 :         TALLOC_CTX *frame = talloc_stackframe();
     417             :         struct tevent_context *ev;
     418             :         struct tevent_req *req;
     419           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     420             : 
     421           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     422           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     423           0 :                 goto fail;
     424             :         }
     425           0 :         ev = samba_tevent_context_init(frame);
     426           0 :         if (ev == NULL) {
     427           0 :                 goto fail;
     428             :         }
     429           0 :         req = cli_readlink_send(frame, ev, cli, fname);
     430           0 :         if (req == NULL) {
     431           0 :                 goto fail;
     432             :         }
     433           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     434           0 :                 goto fail;
     435             :         }
     436           0 :         status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
     437             :                                    pprint_name, pflags);
     438           0 :  fail:
     439           0 :         TALLOC_FREE(frame);
     440           0 :         return status;
     441             : }

Generated by: LCOV version 1.13