LCOV - code coverage report
Current view: top level - source3/libsmb - clisymlink.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 69 182 37.9 %
Date: 2021-09-23 10:06:22 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             : 
      31             : struct cli_symlink_state {
      32             :         struct tevent_context *ev;
      33             :         struct cli_state *cli;
      34             :         const char *link_target;
      35             :         const char *newpath;
      36             :         uint32_t flags;
      37             : 
      38             :         uint16_t fnum;
      39             : 
      40             :         uint16_t setup[4];
      41             :         NTSTATUS set_reparse_status;
      42             : };
      43             : 
      44             : static void cli_symlink_create_done(struct tevent_req *subreq);
      45             : static void cli_symlink_set_reparse_done(struct tevent_req *subreq);
      46             : static void cli_symlink_delete_on_close_done(struct tevent_req *subreq);
      47             : static void cli_symlink_close_done(struct tevent_req *subreq);
      48             : 
      49          14 : struct tevent_req *cli_symlink_send(TALLOC_CTX *mem_ctx,
      50             :                                     struct tevent_context *ev,
      51             :                                     struct cli_state *cli,
      52             :                                     const char *link_target,
      53             :                                     const char *newpath,
      54             :                                     uint32_t flags)
      55             : {
      56             :         struct tevent_req *req, *subreq;
      57             :         struct cli_symlink_state *state;
      58             : 
      59          14 :         req = tevent_req_create(mem_ctx, &state, struct cli_symlink_state);
      60          14 :         if (req == NULL) {
      61           0 :                 return NULL;
      62             :         }
      63          14 :         state->ev = ev;
      64          14 :         state->cli = cli;
      65          14 :         state->link_target = link_target;
      66          14 :         state->newpath = newpath;
      67          14 :         state->flags = flags;
      68             : 
      69          14 :         subreq = cli_ntcreate_send(
      70          14 :                 state, ev, cli, state->newpath, 0,
      71             :                 SYNCHRONIZE_ACCESS|DELETE_ACCESS|
      72             :                 FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
      73             :                 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_NONE, FILE_CREATE,
      74             :                 FILE_OPEN_REPARSE_POINT|FILE_SYNCHRONOUS_IO_NONALERT|
      75             :                 FILE_NON_DIRECTORY_FILE,
      76             :                 SMB2_IMPERSONATION_IMPERSONATION, 0);
      77          14 :         if (tevent_req_nomem(subreq, req)) {
      78           0 :                 return tevent_req_post(req, ev);
      79             :         }
      80          14 :         tevent_req_set_callback(subreq, cli_symlink_create_done, req);
      81          14 :         return req;
      82             : }
      83             : 
      84          14 : static void cli_symlink_create_done(struct tevent_req *subreq)
      85             : {
      86          14 :         struct tevent_req *req = tevent_req_callback_data(
      87             :                 subreq, struct tevent_req);
      88          14 :         struct cli_symlink_state *state = tevent_req_data(
      89             :                 req, struct cli_symlink_state);
      90             :         DATA_BLOB data;
      91             :         NTSTATUS status;
      92             : 
      93          14 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
      94          14 :         TALLOC_FREE(subreq);
      95          14 :         if (tevent_req_nterror(req, status)) {
      96           0 :                 return;
      97             :         }
      98             : 
      99          14 :         if (!symlink_reparse_buffer_marshall(
     100             :                     state->link_target, NULL, state->flags, state,
     101             :                     &data.data, &data.length)) {
     102           0 :                 tevent_req_oom(req);
     103           0 :                 return;
     104             :         }
     105             : 
     106          14 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     107          14 :                 subreq = cli_smb2_set_reparse_point_fnum_send(state,
     108             :                                                 state->ev,
     109             :                                                 state->cli,
     110          14 :                                                 state->fnum,
     111             :                                                 data);
     112             :         } else {
     113           0 :                 SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
     114           0 :                 SSVAL(state->setup, 4, state->fnum);
     115           0 :                 SCVAL(state->setup, 6, 1); /* IsFcntl */
     116           0 :                 SCVAL(state->setup, 7, 0); /* IsFlags */
     117             : 
     118             : 
     119           0 :                 subreq = cli_trans_send(state, state->ev, state->cli, 0,
     120             :                                 SMBnttrans,
     121             :                                 NULL, -1, /* name, fid */
     122             :                                 NT_TRANSACT_IOCTL, 0,
     123           0 :                                 state->setup, 4, 0, /* setup */
     124             :                                 NULL, 0, 0,         /* param */
     125           0 :                                 data.data, data.length, 0); /* data */
     126             :         }
     127             : 
     128          14 :         if (tevent_req_nomem(subreq, req)) {
     129           0 :                 return;
     130             :         }
     131          14 :         tevent_req_set_callback(subreq, cli_symlink_set_reparse_done, req);
     132             : }
     133             : 
     134          14 : static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
     135             : {
     136          14 :         struct tevent_req *req = tevent_req_callback_data(
     137             :                 subreq, struct tevent_req);
     138          14 :         struct cli_symlink_state *state = tevent_req_data(
     139             :                 req, struct cli_symlink_state);
     140             : 
     141          14 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     142          12 :                 state->set_reparse_status =
     143           2 :                         cli_smb2_set_reparse_point_fnum_recv(subreq);
     144             :         } else {
     145           0 :                 state->set_reparse_status = cli_trans_recv(
     146             :                         subreq, NULL, NULL,
     147             :                         NULL, 0, NULL,  /* rsetup */
     148             :                         NULL, 0, NULL,  /* rparam */
     149             :                         NULL, 0, NULL); /* rdata */
     150             :         }
     151          14 :         TALLOC_FREE(subreq);
     152             : 
     153          14 :         if (NT_STATUS_IS_OK(state->set_reparse_status)) {
     154           0 :                 subreq = cli_close_send(state, state->ev, state->cli,
     155           0 :                                         state->fnum);
     156           0 :                 if (tevent_req_nomem(subreq, req)) {
     157           0 :                         return;
     158             :                 }
     159           0 :                 tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     160           0 :                 return;
     161             :         }
     162          14 :         subreq = cli_nt_delete_on_close_send(
     163          14 :                 state, state->ev, state->cli, state->fnum, true);
     164          14 :         if (tevent_req_nomem(subreq, req)) {
     165           0 :                 return;
     166             :         }
     167          14 :         tevent_req_set_callback(subreq, cli_symlink_delete_on_close_done, req);
     168             : }
     169             : 
     170          14 : static void cli_symlink_delete_on_close_done(struct tevent_req *subreq)
     171             : {
     172          14 :         struct tevent_req *req = tevent_req_callback_data(
     173             :                 subreq, struct tevent_req);
     174          14 :         struct cli_symlink_state *state = tevent_req_data(
     175             :                 req, struct cli_symlink_state);
     176             : 
     177             :         /*
     178             :          * Ignore status, we can't do much anyway in case of failure
     179             :          */
     180             : 
     181          14 :         (void)cli_nt_delete_on_close_recv(subreq);
     182          14 :         TALLOC_FREE(subreq);
     183             : 
     184          14 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     185          14 :         if (tevent_req_nomem(subreq, req)) {
     186           0 :                 return;
     187             :         }
     188          14 :         tevent_req_set_callback(subreq, cli_symlink_close_done, req);
     189             : }
     190             : 
     191          14 : static void cli_symlink_close_done(struct tevent_req *subreq)
     192             : {
     193          14 :         struct tevent_req *req = tevent_req_callback_data(
     194             :                 subreq, struct tevent_req);
     195          14 :         struct cli_symlink_state *state = tevent_req_data(
     196             :                 req, struct cli_symlink_state);
     197             :         NTSTATUS status;
     198             : 
     199          14 :         status = cli_close_recv(subreq);
     200          14 :         TALLOC_FREE(subreq);
     201             : 
     202          14 :         if (tevent_req_nterror(req, status)) {
     203          14 :                 return;
     204             :         }
     205          14 :         if (tevent_req_nterror(req, state->set_reparse_status)) {
     206          14 :                 return;
     207             :         }
     208           0 :         tevent_req_done(req);
     209             : }
     210             : 
     211          14 : NTSTATUS cli_symlink_recv(struct tevent_req *req)
     212             : {
     213          14 :         return tevent_req_simple_recv_ntstatus(req);
     214             : }
     215             : 
     216          14 : NTSTATUS cli_symlink(struct cli_state *cli, const char *link_target,
     217             :                      const char *newname, uint32_t flags)
     218             : {
     219          14 :         TALLOC_CTX *frame = talloc_stackframe();
     220             :         struct tevent_context *ev;
     221             :         struct tevent_req *req;
     222          14 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     223             : 
     224          14 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     225           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     226           0 :                 goto fail;
     227             :         }
     228          14 :         ev = samba_tevent_context_init(frame);
     229          14 :         if (ev == NULL) {
     230           0 :                 goto fail;
     231             :         }
     232          14 :         req = cli_symlink_send(frame, ev, cli, link_target, newname, flags);
     233          14 :         if (req == NULL) {
     234           0 :                 goto fail;
     235             :         }
     236          14 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     237           0 :                 goto fail;
     238             :         }
     239          14 :         status = cli_symlink_recv(req);
     240          14 :  fail:
     241          14 :         TALLOC_FREE(frame);
     242          14 :         return status;
     243             : }
     244             : 
     245             : struct cli_readlink_state {
     246             :         struct tevent_context *ev;
     247             :         struct cli_state *cli;
     248             :         uint16_t fnum;
     249             : 
     250             :         uint16_t setup[4];
     251             :         NTSTATUS get_reparse_status;
     252             :         uint8_t *data;
     253             :         uint32_t num_data;
     254             : };
     255             : 
     256             : static void cli_readlink_opened(struct tevent_req *subreq);
     257             : static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
     258             : static void cli_readlink_closed(struct tevent_req *subreq);
     259             : 
     260           0 : struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
     261             :                                      struct tevent_context *ev,
     262             :                                      struct cli_state *cli,
     263             :                                      const char *fname)
     264             : {
     265             :         struct tevent_req *req, *subreq;
     266             :         struct cli_readlink_state *state;
     267             : 
     268           0 :         req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
     269           0 :         if (req == NULL) {
     270           0 :                 return NULL;
     271             :         }
     272           0 :         state->ev = ev;
     273           0 :         state->cli = cli;
     274             : 
     275           0 :         subreq = cli_ntcreate_send(
     276             :                 state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
     277             :                 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
     278             :                 FILE_OPEN, FILE_OPEN_REPARSE_POINT,
     279             :                 SMB2_IMPERSONATION_IMPERSONATION, 0);
     280           0 :         if (tevent_req_nomem(subreq, req)) {
     281           0 :                 return tevent_req_post(req, ev);
     282             :         }
     283           0 :         tevent_req_set_callback(subreq, cli_readlink_opened, req);
     284           0 :         return req;
     285             : }
     286             : 
     287           0 : static void cli_readlink_opened(struct tevent_req *subreq)
     288             : {
     289           0 :         struct tevent_req *req = tevent_req_callback_data(
     290             :                 subreq, struct tevent_req);
     291           0 :         struct cli_readlink_state *state = tevent_req_data(
     292             :                 req, struct cli_readlink_state);
     293             :         NTSTATUS status;
     294             : 
     295           0 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
     296           0 :         TALLOC_FREE(subreq);
     297           0 :         if (tevent_req_nterror(req, status)) {
     298           0 :                 return;
     299             :         }
     300             : 
     301           0 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     302           0 :                 subreq = cli_smb2_get_reparse_point_fnum_send(state,
     303             :                                                 state->ev,
     304             :                                                 state->cli,
     305           0 :                                                 state->fnum);
     306             :         } else {
     307           0 :                 SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
     308           0 :                 SSVAL(state->setup, 4, state->fnum);
     309           0 :                 SCVAL(state->setup, 6, 1); /* IsFcntl */
     310           0 :                 SCVAL(state->setup, 7, 0); /* IsFlags */
     311             : 
     312           0 :                 subreq = cli_trans_send(state, state->ev, state->cli,
     313             :                                 0, SMBnttrans,
     314             :                                 NULL, -1, /* name, fid */
     315             :                                 NT_TRANSACT_IOCTL, 0,
     316           0 :                                 state->setup, 4, 0, /* setup */
     317             :                                 NULL, 0, 0,         /* param */
     318             :                                 NULL, 0, 16384); /* data */
     319             :         }
     320             : 
     321           0 :         if (tevent_req_nomem(subreq, req)) {
     322           0 :                 return;
     323             :         }
     324           0 :         tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
     325             : }
     326             : 
     327           0 : static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
     328             : {
     329           0 :         struct tevent_req *req = tevent_req_callback_data(
     330             :                 subreq, struct tevent_req);
     331           0 :         struct cli_readlink_state *state = tevent_req_data(
     332             :                 req, struct cli_readlink_state);
     333             : 
     334           0 :         if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
     335             :                 DATA_BLOB recv_data;
     336           0 :                 state->get_reparse_status =
     337           0 :                         cli_smb2_get_reparse_point_fnum_recv(subreq,
     338             :                                                         state,
     339             :                                                         &recv_data);
     340           0 :                 if (NT_STATUS_IS_OK(state->get_reparse_status)) {
     341           0 :                         state->data = recv_data.data;
     342           0 :                         state->num_data = recv_data.length;
     343             :                 }
     344             :         } else {
     345           0 :                 state->get_reparse_status = cli_trans_recv(
     346             :                         subreq, state, NULL,
     347             :                         NULL, 0, NULL,  /* rsetup */
     348             :                         NULL, 0, NULL,  /* rparam */
     349             :                         &state->data, 20, &state->num_data); /* rdata */
     350             :         }
     351           0 :         TALLOC_FREE(subreq);
     352             : 
     353           0 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
     354           0 :         if (tevent_req_nomem(subreq, req)) {
     355           0 :                 return;
     356             :         }
     357           0 :         tevent_req_set_callback(subreq, cli_readlink_closed, req);
     358             : }
     359             : 
     360           0 : static void cli_readlink_closed(struct tevent_req *subreq)
     361             : {
     362           0 :         struct tevent_req *req = tevent_req_callback_data(
     363             :                 subreq, struct tevent_req);
     364             :         NTSTATUS status;
     365             : 
     366           0 :         status = cli_close_recv(subreq);
     367           0 :         TALLOC_FREE(subreq);
     368           0 :         if (tevent_req_nterror(req, status)) {
     369           0 :                 return;
     370             :         }
     371           0 :         tevent_req_done(req);
     372             : }
     373             : 
     374           0 : NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     375             :                            char **psubstitute_name, char **pprint_name,
     376             :                            uint32_t *pflags)
     377             : {
     378           0 :         struct cli_readlink_state *state = tevent_req_data(
     379             :                 req, struct cli_readlink_state);
     380             :         NTSTATUS status;
     381             :         char *substitute_name;
     382             :         char *print_name;
     383             :         uint32_t flags;
     384             : 
     385           0 :         if (tevent_req_is_nterror(req, &status)) {
     386           0 :                 return status;
     387             :         }
     388             : 
     389           0 :         if (!symlink_reparse_buffer_parse(state->data, state->num_data,
     390             :                                           talloc_tos(), &substitute_name,
     391             :                                           &print_name, &flags)) {
     392           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     393             :         }
     394             : 
     395           0 :         if (psubstitute_name != NULL) {
     396           0 :                 *psubstitute_name = talloc_move(mem_ctx, &substitute_name);
     397             :         }
     398           0 :         TALLOC_FREE(substitute_name);
     399             : 
     400           0 :         if (pprint_name != NULL) {
     401           0 :                 *pprint_name = talloc_move(mem_ctx, &print_name);
     402             :         }
     403           0 :         TALLOC_FREE(print_name);
     404             : 
     405           0 :         if (pflags != NULL) {
     406           0 :                 *pflags = flags;
     407             :         }
     408           0 :         return NT_STATUS_OK;
     409             : }
     410             : 
     411           0 : NTSTATUS cli_readlink(struct cli_state *cli, const char *fname,
     412             :                        TALLOC_CTX *mem_ctx, char **psubstitute_name,
     413             :                       char **pprint_name, uint32_t *pflags)
     414             : {
     415           0 :         TALLOC_CTX *frame = talloc_stackframe();
     416             :         struct tevent_context *ev;
     417             :         struct tevent_req *req;
     418           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     419             : 
     420           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     421           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     422           0 :                 goto fail;
     423             :         }
     424           0 :         ev = samba_tevent_context_init(frame);
     425           0 :         if (ev == NULL) {
     426           0 :                 goto fail;
     427             :         }
     428           0 :         req = cli_readlink_send(frame, ev, cli, fname);
     429           0 :         if (req == NULL) {
     430           0 :                 goto fail;
     431             :         }
     432           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     433           0 :                 goto fail;
     434             :         }
     435           0 :         status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
     436             :                                    pprint_name, pflags);
     437           0 :  fail:
     438           0 :         TALLOC_FREE(frame);
     439           0 :         return status;
     440             : }

Generated by: LCOV version 1.13