LCOV - code coverage report
Current view: top level - source3/libsmb - clisymlink.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 67 190 35.3 %
Date: 2024-02-14 10:14:15 Functions: 7 14 50.0 %

          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             :         DATA_BLOB in;
      41             : 
      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             :         NTSTATUS status;
      92             : 
      93           4 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
      94           4 :         TALLOC_FREE(subreq);
      95           4 :         if (tevent_req_nterror(req, status)) {
      96           0 :                 return;
      97             :         }
      98             : 
      99           4 :         if (!symlink_reparse_buffer_marshall(
     100             :                     state->link_target, NULL, 0, state->flags, state,
     101             :                     &state->in.data, &state->in.length)) {
     102           0 :                 tevent_req_oom(req);
     103           0 :                 return;
     104             :         }
     105             : 
     106           4 :         subreq = cli_fsctl_send(
     107             :                 state,
     108             :                 state->ev,
     109             :                 state->cli,
     110           4 :                 state->fnum,
     111             :                 FSCTL_SET_REPARSE_POINT,
     112           4 :                 &state->in,
     113             :                 0);
     114           4 :         if (tevent_req_nomem(subreq, req)) {
     115           0 :                 return;
     116             :         }
     117           4 :         tevent_req_set_callback(subreq, cli_symlink_set_reparse_done, req);
     118             : }
     119             : 
     120           4 : static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
     121             : {
     122           4 :         struct tevent_req *req = tevent_req_callback_data(
     123             :                 subreq, struct tevent_req);
     124           4 :         struct cli_symlink_state *state = tevent_req_data(
     125             :                 req, struct cli_symlink_state);
     126             : 
     127           4 :         state->set_reparse_status = cli_fsctl_recv(subreq, NULL, NULL);
     128           4 :         TALLOC_FREE(subreq);
     129             : 
     130           4 :         if (NT_STATUS_IS_OK(state->set_reparse_status)) {
     131           0 :                 subreq = cli_close_send(state, state->ev, state->cli,
     132           0 :                                         state->fnum);
     133           0 :                 if (tevent_req_nomem(subreq, req)) {
     134           0 :                         return;
     135             :                 }
     136           0 :                 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     137           0 :                 return;
     138             :         }
     139           4 :         subreq = cli_nt_delete_on_close_send(
     140           4 :                 state, state->ev, state->cli, state->fnum, true);
     141           4 :         if (tevent_req_nomem(subreq, req)) {
     142           0 :                 return;
     143             :         }
     144           4 :         tevent_req_set_callback(subreq, cli_symlink_delete_on_close_done, req);
     145             : }
     146             : 
     147           4 : static void cli_symlink_delete_on_close_done(struct tevent_req *subreq)
     148             : {
     149           4 :         struct tevent_req *req = tevent_req_callback_data(
     150             :                 subreq, struct tevent_req);
     151           4 :         struct cli_symlink_state *state = tevent_req_data(
     152             :                 req, struct cli_symlink_state);
     153             : 
     154             :         /*
     155             :          * Ignore status, we can't do much anyway in case of failure
     156             :          */
     157             : 
     158           4 :         (void)cli_nt_delete_on_close_recv(subreq);
     159           4 :         TALLOC_FREE(subreq);
     160             : 
     161           4 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     162           4 :         if (tevent_req_nomem(subreq, req)) {
     163           0 :                 return;
     164             :         }
     165           4 :         tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     166             : }
     167             : 
     168           4 : static void cli_symlink_close_done(struct tevent_req *subreq)
     169             : {
     170           4 :         struct tevent_req *req = tevent_req_callback_data(
     171             :                 subreq, struct tevent_req);
     172           4 :         struct cli_symlink_state *state = tevent_req_data(
     173             :                 req, struct cli_symlink_state);
     174             :         NTSTATUS status;
     175             : 
     176           4 :         status = cli_close_recv(subreq);
     177           4 :         TALLOC_FREE(subreq);
     178             : 
     179           4 :         if (tevent_req_nterror(req, status)) {
     180           4 :                 return;
     181             :         }
     182           4 :         if (tevent_req_nterror(req, state->set_reparse_status)) {
     183           4 :                 return;
     184             :         }
     185           0 :         tevent_req_done(req);
     186             : }
     187             : 
     188           4 : NTSTATUS cli_symlink_recv(struct tevent_req *req)
     189             : {
     190           4 :         return tevent_req_simple_recv_ntstatus(req);
     191             : }
     192             : 
     193           4 : NTSTATUS cli_symlink(struct cli_state *cli, const char *link_target,
     194             :                      const char *newname, uint32_t flags)
     195             : {
     196           4 :         TALLOC_CTX *frame = talloc_stackframe();
     197             :         struct tevent_context *ev;
     198             :         struct tevent_req *req;
     199           4 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     200             : 
     201           4 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     202           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     203           0 :                 goto fail;
     204             :         }
     205           4 :         ev = samba_tevent_context_init(frame);
     206           4 :         if (ev == NULL) {
     207           0 :                 goto fail;
     208             :         }
     209           4 :         req = cli_symlink_send(frame, ev, cli, link_target, newname, flags);
     210           4 :         if (req == NULL) {
     211           0 :                 goto fail;
     212             :         }
     213           4 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     214           0 :                 goto fail;
     215             :         }
     216           4 :         status = cli_symlink_recv(req);
     217           4 :  fail:
     218           4 :         TALLOC_FREE(frame);
     219           4 :         return status;
     220             : }
     221             : 
     222             : struct cli_readlink_state {
     223             :         struct tevent_context *ev;
     224             :         struct cli_state *cli;
     225             :         uint16_t fnum;
     226             : 
     227             :         uint16_t setup[4];
     228             :         NTSTATUS get_reparse_status;
     229             :         uint8_t *data;
     230             :         uint32_t num_data;
     231             :         char *target;
     232             : };
     233             : 
     234             : static void cli_readlink_posix1_done(struct tevent_req *subreq);
     235             : static void cli_readlink_opened(struct tevent_req *subreq);
     236             : static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
     237             : static void cli_readlink_closed(struct tevent_req *subreq);
     238             : 
     239           0 : struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
     240             :                                      struct tevent_context *ev,
     241             :                                      struct cli_state *cli,
     242             :                                      const char *fname)
     243             : {
     244             :         struct tevent_req *req, *subreq;
     245             :         struct cli_readlink_state *state;
     246             : 
     247           0 :         req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
     248           0 :         if (req == NULL) {
     249           0 :                 return NULL;
     250             :         }
     251           0 :         state->ev = ev;
     252           0 :         state->cli = cli;
     253             : 
     254           0 :         if (cli->requested_posix_capabilities != 0) {
     255             :                 /*
     256             :                  * Only happens for negotiated SMB1 posix caps
     257             :                  */
     258           0 :                 subreq = cli_posix_readlink_send(state, ev, cli, fname);
     259           0 :                 if (tevent_req_nomem(subreq, req)) {
     260           0 :                         return tevent_req_post(req, ev);
     261             :                 }
     262           0 :                 tevent_req_set_callback(subreq, cli_readlink_posix1_done, req);
     263           0 :                 return req;
     264             :         }
     265             : 
     266           0 :         subreq = cli_ntcreate_send(
     267             :                 state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
     268             :                 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     269             :                 FILE_OPEN, FILE_OPEN_REPARSE_POINT,
     270             :                 SMB2_IMPERSONATION_IMPERSONATION, 0);
     271           0 :         if (tevent_req_nomem(subreq, req)) {
     272           0 :                 return tevent_req_post(req, ev);
     273             :         }
     274           0 :         tevent_req_set_callback(subreq, cli_readlink_opened, req);
     275           0 :         return req;
     276             : }
     277             : 
     278           0 : static void cli_readlink_posix1_done(struct tevent_req *subreq)
     279             : {
     280           0 :         struct tevent_req *req = tevent_req_callback_data(
     281             :                 subreq, struct tevent_req);
     282           0 :         struct cli_readlink_state *state = tevent_req_data(
     283             :                 req, struct cli_readlink_state);
     284             :         NTSTATUS status;
     285             : 
     286           0 :         status = cli_posix_readlink_recv(subreq, state, &state->target);
     287           0 :         TALLOC_FREE(subreq);
     288           0 :         if (tevent_req_nterror(req, status)) {
     289           0 :                 return;
     290             :         }
     291           0 :         tevent_req_done(req);
     292             : }
     293             : 
     294           0 : static void cli_readlink_opened(struct tevent_req *subreq)
     295             : {
     296           0 :         struct tevent_req *req = tevent_req_callback_data(
     297             :                 subreq, struct tevent_req);
     298           0 :         struct cli_readlink_state *state = tevent_req_data(
     299             :                 req, struct cli_readlink_state);
     300             :         NTSTATUS status;
     301             : 
     302           0 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
     303           0 :         TALLOC_FREE(subreq);
     304           0 :         if (tevent_req_nterror(req, status)) {
     305           0 :                 return;
     306             :         }
     307             : 
     308           0 :         subreq = cli_fsctl_send(
     309             :                 state,
     310             :                 state->ev,
     311             :                 state->cli,
     312           0 :                 state->fnum,
     313             :                 FSCTL_GET_REPARSE_POINT,
     314             :                 NULL,
     315             :                 65536);
     316             : 
     317           0 :         if (tevent_req_nomem(subreq, req)) {
     318           0 :                 return;
     319             :         }
     320           0 :         tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
     321             : }
     322             : 
     323           0 : static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
     324             : {
     325           0 :         struct tevent_req *req = tevent_req_callback_data(
     326             :                 subreq, struct tevent_req);
     327           0 :         struct cli_readlink_state *state = tevent_req_data(
     328             :                 req, struct cli_readlink_state);
     329           0 :         DATA_BLOB out = { .data = NULL, };
     330             : 
     331           0 :         state->get_reparse_status = cli_fsctl_recv(subreq, state, &out);
     332           0 :         TALLOC_FREE(subreq);
     333             : 
     334           0 :         if (NT_STATUS_IS_OK(state->get_reparse_status)) {
     335           0 :                 state->data = out.data;
     336           0 :                 state->num_data = out.length;
     337             :         }
     338             : 
     339           0 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     340           0 :         if (tevent_req_nomem(subreq, req)) {
     341           0 :                 return;
     342             :         }
     343           0 :         tevent_req_set_callback(subreq, cli_readlink_closed, req);
     344             : }
     345             : 
     346           0 : static void cli_readlink_closed(struct tevent_req *subreq)
     347             : {
     348           0 :         struct tevent_req *req = tevent_req_callback_data(
     349             :                 subreq, struct tevent_req);
     350           0 :         struct cli_readlink_state *state = tevent_req_data(
     351             :                 req, struct cli_readlink_state);
     352             :         NTSTATUS status;
     353             : 
     354           0 :         status = cli_close_recv(subreq);
     355           0 :         TALLOC_FREE(subreq);
     356           0 :         if (tevent_req_nterror(req, status)) {
     357           0 :                 return;
     358             :         }
     359           0 :         if (tevent_req_nterror(req, state->get_reparse_status)) {
     360           0 :                 return;
     361             :         }
     362           0 :         tevent_req_done(req);
     363             : }
     364             : 
     365           0 : NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     366             :                            char **psubstitute_name, char **pprint_name,
     367             :                            uint32_t *pflags)
     368             : {
     369           0 :         struct cli_readlink_state *state = tevent_req_data(
     370             :                 req, struct cli_readlink_state);
     371           0 :         struct symlink_reparse_struct *symlink = NULL;
     372             :         NTSTATUS status;
     373             : 
     374           0 :         if (tevent_req_is_nterror(req, &status)) {
     375           0 :                 return status;
     376             :         }
     377             : 
     378           0 :         if (state->target != NULL) {
     379             :                 /*
     380             :                  * SMB1 posix version
     381             :                  */
     382           0 :                 if (psubstitute_name != NULL) {
     383           0 :                         *psubstitute_name = talloc_move(
     384             :                                 mem_ctx, &state->target);
     385             :                 }
     386           0 :                 if (pprint_name != NULL) {
     387           0 :                         *pprint_name = NULL;
     388             :                 }
     389           0 :                 if (pflags != NULL) {
     390           0 :                         *pflags = 0;
     391             :                 }
     392           0 :                 return NT_STATUS_OK;
     393             :         }
     394             : 
     395           0 :         symlink = symlink_reparse_buffer_parse(
     396           0 :                 talloc_tos(), state->data, state->num_data);
     397           0 :         if (symlink == NULL) {
     398           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     399             :         }
     400             : 
     401           0 :         if (psubstitute_name != NULL) {
     402           0 :                 *psubstitute_name = talloc_move(
     403             :                         mem_ctx, &symlink->substitute_name);
     404             :         }
     405             : 
     406           0 :         if (pprint_name != NULL) {
     407           0 :                 *pprint_name = talloc_move(mem_ctx, &symlink->print_name);
     408             :         }
     409             : 
     410           0 :         if (pflags != NULL) {
     411           0 :                 *pflags = symlink->flags;
     412             :         }
     413             : 
     414           0 :         TALLOC_FREE(symlink);
     415             : 
     416           0 :         return NT_STATUS_OK;
     417             : }
     418             : 
     419           0 : NTSTATUS cli_readlink(struct cli_state *cli, const char *fname,
     420             :                        TALLOC_CTX *mem_ctx, char **psubstitute_name,
     421             :                       char **pprint_name, uint32_t *pflags)
     422             : {
     423           0 :         TALLOC_CTX *frame = talloc_stackframe();
     424             :         struct tevent_context *ev;
     425             :         struct tevent_req *req;
     426           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     427             : 
     428           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     429           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     430           0 :                 goto fail;
     431             :         }
     432           0 :         ev = samba_tevent_context_init(frame);
     433           0 :         if (ev == NULL) {
     434           0 :                 goto fail;
     435             :         }
     436           0 :         req = cli_readlink_send(frame, ev, cli, fname);
     437           0 :         if (req == NULL) {
     438           0 :                 goto fail;
     439             :         }
     440           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     441           0 :                 goto fail;
     442             :         }
     443           0 :         status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
     444             :                                    pprint_name, pflags);
     445           0 :  fail:
     446           0 :         TALLOC_FREE(frame);
     447           0 :         return status;
     448             : }

Generated by: LCOV version 1.14