LCOV - code coverage report
Current view: top level - source3/libsmb - clisymlink.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 126 298 42.3 %
Date: 2024-02-28 12:06:22 Functions: 13 21 61.9 %

          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.h"
      31             : 
      32             : struct cli_create_reparse_point_state {
      33             :         struct tevent_context *ev;
      34             :         struct cli_state *cli;
      35             :         DATA_BLOB reparse_blob;
      36             :         uint16_t fnum;
      37             :         NTSTATUS set_reparse_status;
      38             : };
      39             : 
      40             : static void cli_create_reparse_point_opened(struct tevent_req *subreq);
      41             : static void cli_create_reparse_point_done(struct tevent_req *subreq);
      42             : static void cli_create_reparse_point_doc_done(struct tevent_req *subreq);
      43             : static void cli_create_reparse_point_closed(struct tevent_req *subreq);
      44             : 
      45          14 : struct tevent_req *cli_create_reparse_point_send(TALLOC_CTX *mem_ctx,
      46             :                                                  struct tevent_context *ev,
      47             :                                                  struct cli_state *cli,
      48             :                                                  const char *fname,
      49             :                                                  DATA_BLOB reparse_blob)
      50             : {
      51          14 :         struct tevent_req *req = NULL, *subreq = NULL;
      52          14 :         struct cli_create_reparse_point_state *state = NULL;
      53             : 
      54          14 :         req = tevent_req_create(mem_ctx,
      55             :                                 &state,
      56             :                                 struct cli_create_reparse_point_state);
      57          14 :         if (req == NULL) {
      58           0 :                 return NULL;
      59             :         }
      60          14 :         state->ev = ev;
      61          14 :         state->cli = cli;
      62          14 :         state->reparse_blob = reparse_blob;
      63             : 
      64             :         /*
      65             :          * The create arguments were taken from a Windows->Windows
      66             :          * symlink create call.
      67             :          */
      68          14 :         subreq = cli_ntcreate_send(
      69             :                 state,
      70             :                 ev,
      71             :                 cli,
      72             :                 fname,
      73             :                 0,
      74             :                 SYNCHRONIZE_ACCESS | DELETE_ACCESS | FILE_READ_ATTRIBUTES |
      75             :                         FILE_WRITE_ATTRIBUTES,
      76             :                 FILE_ATTRIBUTE_NORMAL,
      77             :                 FILE_SHARE_NONE,
      78             :                 FILE_CREATE,
      79             :                 FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_NONALERT |
      80             :                         FILE_NON_DIRECTORY_FILE,
      81             :                 SMB2_IMPERSONATION_IMPERSONATION,
      82             :                 0);
      83          14 :         if (tevent_req_nomem(subreq, req)) {
      84           0 :                 return tevent_req_post(req, ev);
      85             :         }
      86          14 :         tevent_req_set_callback(subreq, cli_create_reparse_point_opened, req);
      87          14 :         return req;
      88             : }
      89             : 
      90          14 : static void cli_create_reparse_point_opened(struct tevent_req *subreq)
      91             : {
      92           0 :         struct tevent_req *req =
      93          14 :                 tevent_req_callback_data(subreq, struct tevent_req);
      94           0 :         struct cli_create_reparse_point_state *state =
      95          14 :                 tevent_req_data(req, struct cli_create_reparse_point_state);
      96           0 :         NTSTATUS status;
      97             : 
      98          14 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
      99          14 :         TALLOC_FREE(subreq);
     100          14 :         if (tevent_req_nterror(req, status)) {
     101           0 :                 return;
     102             :         }
     103             : 
     104          14 :         subreq = cli_fsctl_send(state,
     105             :                                 state->ev,
     106             :                                 state->cli,
     107          14 :                                 state->fnum,
     108             :                                 FSCTL_SET_REPARSE_POINT,
     109          14 :                                 &state->reparse_blob,
     110             :                                 0);
     111          14 :         if (tevent_req_nomem(subreq, req)) {
     112           0 :                 return;
     113             :         }
     114          14 :         tevent_req_set_callback(subreq, cli_create_reparse_point_done, req);
     115             : }
     116             : 
     117          14 : static void cli_create_reparse_point_done(struct tevent_req *subreq)
     118             : {
     119          14 :         struct tevent_req *req = tevent_req_callback_data(
     120             :                 subreq, struct tevent_req);
     121           0 :         struct cli_create_reparse_point_state *state =
     122          14 :                 tevent_req_data(req, struct cli_create_reparse_point_state);
     123             : 
     124          14 :         state->set_reparse_status = cli_fsctl_recv(subreq, NULL, NULL);
     125          14 :         TALLOC_FREE(subreq);
     126             : 
     127          14 :         if (NT_STATUS_IS_OK(state->set_reparse_status)) {
     128           0 :                 subreq = cli_close_send(state,
     129             :                                         state->ev,
     130             :                                         state->cli,
     131           0 :                                         state->fnum,
     132             :                                         0);
     133           0 :                 if (tevent_req_nomem(subreq, req)) {
     134           0 :                         return;
     135             :                 }
     136           0 :                 tevent_req_set_callback(subreq,
     137             :                                         cli_create_reparse_point_closed,
     138             :                                         req);
     139           0 :                 return;
     140             :         }
     141          14 :         subreq = cli_nt_delete_on_close_send(
     142          14 :                 state, state->ev, state->cli, state->fnum, true);
     143          14 :         if (tevent_req_nomem(subreq, req)) {
     144           0 :                 return;
     145             :         }
     146          14 :         tevent_req_set_callback(subreq,
     147             :                                 cli_create_reparse_point_doc_done,
     148             :                                 req);
     149             : }
     150             : 
     151          14 : static void cli_create_reparse_point_doc_done(struct tevent_req *subreq)
     152             : {
     153          14 :         struct tevent_req *req = tevent_req_callback_data(
     154             :                 subreq, struct tevent_req);
     155           0 :         struct cli_create_reparse_point_state *state =
     156          14 :                 tevent_req_data(req, struct cli_create_reparse_point_state);
     157             : 
     158             :         /*
     159             :          * Ignore status, we can't do much anyway in case of failure
     160             :          */
     161             : 
     162          14 :         (void)cli_nt_delete_on_close_recv(subreq);
     163          14 :         TALLOC_FREE(subreq);
     164             : 
     165          14 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum, 0);
     166          14 :         if (tevent_req_nomem(subreq, req)) {
     167           0 :                 return;
     168             :         }
     169          14 :         tevent_req_set_callback(subreq, cli_create_reparse_point_closed, req);
     170             : }
     171             : 
     172          14 : static void cli_create_reparse_point_closed(struct tevent_req *subreq)
     173             : {
     174          14 :         struct tevent_req *req = tevent_req_callback_data(
     175             :                 subreq, struct tevent_req);
     176           0 :         struct cli_create_reparse_point_state *state =
     177          14 :                 tevent_req_data(req, struct cli_create_reparse_point_state);
     178           0 :         NTSTATUS status;
     179             : 
     180          14 :         status = cli_close_recv(subreq);
     181          14 :         TALLOC_FREE(subreq);
     182             : 
     183          14 :         if (tevent_req_nterror(req, status)) {
     184          14 :                 return;
     185             :         }
     186          14 :         if (tevent_req_nterror(req, state->set_reparse_status)) {
     187          14 :                 return;
     188             :         }
     189           0 :         tevent_req_done(req);
     190             : }
     191             : 
     192           0 : NTSTATUS cli_create_reparse_point_recv(struct tevent_req *req)
     193             : {
     194           0 :         return tevent_req_simple_recv_ntstatus(req);
     195             : }
     196             : 
     197             : struct cli_symlink_state {
     198             :         uint8_t dummy;
     199             : };
     200             : 
     201             : static void cli_symlink_done(struct tevent_req *subreq);
     202             : 
     203          14 : struct tevent_req *cli_symlink_send(TALLOC_CTX *mem_ctx,
     204             :                                     struct tevent_context *ev,
     205             :                                     struct cli_state *cli,
     206             :                                     const char *link_target,
     207             :                                     const char *newpath,
     208             :                                     uint32_t flags)
     209             : {
     210          14 :         struct tevent_req *req = NULL, *subreq = NULL;
     211          14 :         struct cli_symlink_state *state = NULL;
     212          14 :         struct reparse_data_buffer reparse_buf = {
     213             :                 .tag = IO_REPARSE_TAG_SYMLINK,
     214             :                 .parsed.lnk.substitute_name =
     215             :                         discard_const_p(char, link_target),
     216             :                 .parsed.lnk.print_name = discard_const_p(char, link_target),
     217             :                 .parsed.lnk.flags = flags,
     218             :         };
     219           0 :         uint8_t *buf;
     220           0 :         ssize_t buflen;
     221             : 
     222          14 :         req = tevent_req_create(mem_ctx, &state, struct cli_symlink_state);
     223          14 :         if (req == NULL) {
     224           0 :                 return NULL;
     225             :         }
     226             : 
     227          14 :         buflen = reparse_data_buffer_marshall(&reparse_buf, NULL, 0);
     228          14 :         if (buflen == -1) {
     229           0 :                 tevent_req_oom(req);
     230           0 :                 return tevent_req_post(req, ev);
     231             :         }
     232             : 
     233          14 :         buf = talloc_array(state, uint8_t, buflen);
     234          14 :         if (tevent_req_nomem(buf, req)) {
     235           0 :                 return tevent_req_post(req, ev);
     236             :         }
     237             : 
     238          14 :         buflen = reparse_data_buffer_marshall(&reparse_buf, buf, buflen);
     239          14 :         if (buflen != talloc_array_length(buf)) {
     240           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     241           0 :                 return tevent_req_post(req, ev);
     242             :         }
     243             : 
     244          14 :         subreq = cli_create_reparse_point_send(state,
     245             :                                                ev,
     246             :                                                cli,
     247             :                                                newpath,
     248          14 :                                                (DATA_BLOB){
     249             :                                                        .data = buf,
     250             :                                                        .length = buflen,
     251             :                                                });
     252          14 :         if (tevent_req_nomem(subreq, req)) {
     253           0 :                 return tevent_req_post(req, ev);
     254             :         }
     255          14 :         tevent_req_set_callback(subreq, cli_symlink_done, req);
     256          14 :         return req;
     257             : }
     258             : 
     259          14 : static void cli_symlink_done(struct tevent_req *subreq)
     260             : {
     261          14 :         NTSTATUS status = cli_symlink_recv(subreq);
     262          14 :         tevent_req_simple_finish_ntstatus(subreq, status);
     263          14 : }
     264             : 
     265          28 : NTSTATUS cli_symlink_recv(struct tevent_req *req)
     266             : {
     267          28 :         return tevent_req_simple_recv_ntstatus(req);
     268             : }
     269             : 
     270          14 : NTSTATUS cli_symlink(struct cli_state *cli, const char *link_target,
     271             :                      const char *newname, uint32_t flags)
     272             : {
     273          14 :         TALLOC_CTX *frame = talloc_stackframe();
     274           0 :         struct tevent_context *ev;
     275           0 :         struct tevent_req *req;
     276          14 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     277             : 
     278          14 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     279           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     280           0 :                 goto fail;
     281             :         }
     282          14 :         ev = samba_tevent_context_init(frame);
     283          14 :         if (ev == NULL) {
     284           0 :                 goto fail;
     285             :         }
     286          14 :         req = cli_symlink_send(frame, ev, cli, link_target, newname, flags);
     287          14 :         if (req == NULL) {
     288           0 :                 goto fail;
     289             :         }
     290          14 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     291           0 :                 goto fail;
     292             :         }
     293          14 :         status = cli_symlink_recv(req);
     294          14 :  fail:
     295          14 :         TALLOC_FREE(frame);
     296          14 :         return status;
     297             : }
     298             : 
     299             : struct cli_get_reparse_data_state {
     300             :         struct tevent_context *ev;
     301             :         struct cli_state *cli;
     302             :         uint16_t fnum;
     303             : 
     304             :         NTSTATUS get_reparse_status;
     305             :         uint8_t *data;
     306             :         uint32_t datalen;
     307             : };
     308             : 
     309             : static void cli_get_reparse_data_opened(struct tevent_req *subreq);
     310             : static void cli_get_reparse_data_done(struct tevent_req *subreq);
     311             : static void cli_get_reparse_data_closed(struct tevent_req *subreq);
     312             : 
     313           0 : struct tevent_req *cli_get_reparse_data_send(TALLOC_CTX *mem_ctx,
     314             :                                              struct tevent_context *ev,
     315             :                                              struct cli_state *cli,
     316             :                                              const char *fname)
     317             : {
     318           0 :         struct tevent_req *req = NULL, *subreq = NULL;
     319           0 :         struct cli_get_reparse_data_state *state = NULL;
     320             : 
     321           0 :         req = tevent_req_create(mem_ctx,
     322             :                                 &state,
     323             :                                 struct cli_get_reparse_data_state);
     324           0 :         if (req == NULL) {
     325           0 :                 return NULL;
     326             :         }
     327           0 :         state->ev = ev;
     328           0 :         state->cli = cli;
     329             : 
     330           0 :         subreq = cli_ntcreate_send(state,
     331             :                                    ev,
     332             :                                    cli,
     333             :                                    fname,
     334             :                                    0,
     335             :                                    FILE_READ_ATTRIBUTES | FILE_READ_EA,
     336             :                                    0,
     337             :                                    FILE_SHARE_READ | FILE_SHARE_WRITE |
     338             :                                            FILE_SHARE_DELETE,
     339             :                                    FILE_OPEN,
     340             :                                    FILE_OPEN_REPARSE_POINT,
     341             :                                    SMB2_IMPERSONATION_IMPERSONATION,
     342             :                                    0);
     343           0 :         if (tevent_req_nomem(subreq, req)) {
     344           0 :                 return tevent_req_post(req, ev);
     345             :         }
     346           0 :         tevent_req_set_callback(subreq, cli_get_reparse_data_opened, req);
     347           0 :         return req;
     348             : }
     349             : 
     350           0 : static void cli_get_reparse_data_opened(struct tevent_req *subreq)
     351             : {
     352           0 :         struct tevent_req *req =
     353           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     354           0 :         struct cli_get_reparse_data_state *state =
     355           0 :                 tevent_req_data(req, struct cli_get_reparse_data_state);
     356           0 :         NTSTATUS status;
     357             : 
     358           0 :         status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
     359           0 :         TALLOC_FREE(subreq);
     360           0 :         if (tevent_req_nterror(req, status)) {
     361           0 :                 return;
     362             :         }
     363             : 
     364           0 :         subreq = cli_fsctl_send(state,
     365             :                                 state->ev,
     366             :                                 state->cli,
     367           0 :                                 state->fnum,
     368             :                                 FSCTL_GET_REPARSE_POINT,
     369             :                                 NULL,
     370             :                                 65536);
     371             : 
     372           0 :         if (tevent_req_nomem(subreq, req)) {
     373           0 :                 return;
     374             :         }
     375           0 :         tevent_req_set_callback(subreq, cli_get_reparse_data_done, req);
     376             : }
     377             : 
     378           0 : static void cli_get_reparse_data_done(struct tevent_req *subreq)
     379             : {
     380           0 :         struct tevent_req *req =
     381           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     382           0 :         struct cli_get_reparse_data_state *state =
     383           0 :                 tevent_req_data(req, struct cli_get_reparse_data_state);
     384           0 :         DATA_BLOB out = {
     385             :                 .data = NULL,
     386             :         };
     387             : 
     388           0 :         state->get_reparse_status = cli_fsctl_recv(subreq, state, &out);
     389           0 :         TALLOC_FREE(subreq);
     390             : 
     391           0 :         if (NT_STATUS_IS_OK(state->get_reparse_status)) {
     392           0 :                 state->data = out.data;
     393           0 :                 state->datalen = out.length;
     394             :         }
     395             : 
     396           0 :         subreq = cli_close_send(state, state->ev, state->cli, state->fnum, 0);
     397           0 :         if (tevent_req_nomem(subreq, req)) {
     398           0 :                 return;
     399             :         }
     400           0 :         tevent_req_set_callback(subreq, cli_get_reparse_data_closed, req);
     401             : }
     402             : 
     403           0 : static void cli_get_reparse_data_closed(struct tevent_req *subreq)
     404             : {
     405           0 :         struct tevent_req *req =
     406           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     407           0 :         struct cli_get_reparse_data_state *state =
     408           0 :                 tevent_req_data(req, struct cli_get_reparse_data_state);
     409           0 :         NTSTATUS status;
     410             : 
     411           0 :         status = cli_close_recv(subreq);
     412           0 :         TALLOC_FREE(subreq);
     413           0 :         if (tevent_req_nterror(req, status)) {
     414           0 :                 return;
     415             :         }
     416           0 :         if (tevent_req_nterror(req, state->get_reparse_status)) {
     417           0 :                 return;
     418             :         }
     419           0 :         tevent_req_done(req);
     420             : }
     421             : 
     422           0 : NTSTATUS cli_get_reparse_data_recv(struct tevent_req *req,
     423             :                                    TALLOC_CTX *mem_ctx,
     424             :                                    uint8_t **_data,
     425             :                                    uint32_t *_datalen)
     426             : {
     427           0 :         struct cli_get_reparse_data_state *state =
     428           0 :                 tevent_req_data(req, struct cli_get_reparse_data_state);
     429           0 :         NTSTATUS status;
     430             : 
     431           0 :         if (tevent_req_is_nterror(req, &status)) {
     432           0 :                 return status;
     433             :         }
     434             : 
     435           0 :         *_data = talloc_move(mem_ctx, &state->data);
     436           0 :         *_datalen = state->datalen;
     437             : 
     438           0 :         tevent_req_received(req);
     439             : 
     440           0 :         return NT_STATUS_OK;
     441             : }
     442             : 
     443           0 : NTSTATUS cli_get_reparse_data(struct cli_state *cli,
     444             :                               const char *fname,
     445             :                               TALLOC_CTX *mem_ctx,
     446             :                               uint8_t **_data,
     447             :                               uint32_t *_datalen)
     448             : {
     449           0 :         TALLOC_CTX *frame = talloc_stackframe();
     450           0 :         struct tevent_context *ev;
     451           0 :         struct tevent_req *req;
     452           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     453             : 
     454           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     455           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     456           0 :                 goto fail;
     457             :         }
     458           0 :         ev = samba_tevent_context_init(frame);
     459           0 :         if (ev == NULL) {
     460           0 :                 goto fail;
     461             :         }
     462           0 :         req = cli_get_reparse_data_send(frame, ev, cli, fname);
     463           0 :         if (req == NULL) {
     464           0 :                 goto fail;
     465             :         }
     466           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     467           0 :                 goto fail;
     468             :         }
     469           0 :         status = cli_get_reparse_data_recv(req, mem_ctx, _data, _datalen);
     470           0 : fail:
     471           0 :         TALLOC_FREE(frame);
     472           0 :         return status;
     473             : }
     474             : 
     475             : struct cli_readlink_state {
     476             :         struct tevent_context *ev;
     477             :         struct cli_state *cli;
     478             :         uint16_t fnum;
     479             : 
     480             :         uint16_t setup[4];
     481             :         uint8_t *data;
     482             :         uint32_t num_data;
     483             :         char *target;
     484             : };
     485             : 
     486             : static void cli_readlink_posix1_done(struct tevent_req *subreq);
     487             : static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
     488             : 
     489          16 : struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
     490             :                                      struct tevent_context *ev,
     491             :                                      struct cli_state *cli,
     492             :                                      const char *fname)
     493             : {
     494           0 :         struct tevent_req *req, *subreq;
     495           0 :         struct cli_readlink_state *state;
     496             : 
     497          16 :         req = tevent_req_create(mem_ctx, &state, struct cli_readlink_state);
     498          16 :         if (req == NULL) {
     499           0 :                 return NULL;
     500             :         }
     501          16 :         state->ev = ev;
     502          16 :         state->cli = cli;
     503             : 
     504          16 :         if (cli->requested_posix_capabilities != 0) {
     505             :                 /*
     506             :                  * Only happens for negotiated SMB1 posix caps
     507             :                  */
     508          16 :                 subreq = cli_posix_readlink_send(state, ev, cli, fname);
     509          16 :                 if (tevent_req_nomem(subreq, req)) {
     510           0 :                         return tevent_req_post(req, ev);
     511             :                 }
     512          16 :                 tevent_req_set_callback(subreq, cli_readlink_posix1_done, req);
     513          16 :                 return req;
     514             :         }
     515             : 
     516           0 :         subreq = cli_get_reparse_data_send(state, ev, cli, fname);
     517           0 :         if (tevent_req_nomem(subreq, req)) {
     518           0 :                 return tevent_req_post(req, ev);
     519             :         }
     520           0 :         tevent_req_set_callback(subreq, cli_readlink_got_reparse_data, req);
     521           0 :         return req;
     522             : }
     523             : 
     524          16 : static void cli_readlink_posix1_done(struct tevent_req *subreq)
     525             : {
     526          16 :         struct tevent_req *req = tevent_req_callback_data(
     527             :                 subreq, struct tevent_req);
     528          16 :         struct cli_readlink_state *state = tevent_req_data(
     529             :                 req, struct cli_readlink_state);
     530           0 :         NTSTATUS status;
     531             : 
     532          16 :         status = cli_posix_readlink_recv(subreq, state, &state->target);
     533          16 :         TALLOC_FREE(subreq);
     534          16 :         if (tevent_req_nterror(req, status)) {
     535           0 :                 return;
     536             :         }
     537          16 :         tevent_req_done(req);
     538             : }
     539             : 
     540           0 : static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
     541             : {
     542           0 :         struct tevent_req *req = tevent_req_callback_data(
     543             :                 subreq, struct tevent_req);
     544           0 :         struct cli_readlink_state *state = tevent_req_data(
     545             :                 req, struct cli_readlink_state);
     546           0 :         NTSTATUS status;
     547             : 
     548           0 :         status = cli_get_reparse_data_recv(subreq,
     549             :                                            state,
     550             :                                            &state->data,
     551             :                                            &state->num_data);
     552           0 :         TALLOC_FREE(subreq);
     553           0 :         if (tevent_req_nterror(req, status)) {
     554           0 :                 return;
     555             :         }
     556           0 :         tevent_req_done(req);
     557             : }
     558             : 
     559          16 : NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     560             :                            char **psubstitute_name, char **pprint_name,
     561             :                            uint32_t *pflags)
     562             : {
     563          16 :         struct cli_readlink_state *state = tevent_req_data(
     564             :                 req, struct cli_readlink_state);
     565          16 :         struct reparse_data_buffer buf = {
     566             :                 .tag = 0,
     567             :         };
     568           0 :         NTSTATUS status;
     569             : 
     570          16 :         if (tevent_req_is_nterror(req, &status)) {
     571           0 :                 return status;
     572             :         }
     573             : 
     574          16 :         if (state->target != NULL) {
     575             :                 /*
     576             :                  * SMB1 posix version
     577             :                  */
     578          16 :                 if (psubstitute_name != NULL) {
     579          16 :                         *psubstitute_name = talloc_move(
     580             :                                 mem_ctx, &state->target);
     581             :                 }
     582          16 :                 if (pprint_name != NULL) {
     583           0 :                         *pprint_name = NULL;
     584             :                 }
     585          16 :                 if (pflags != NULL) {
     586           0 :                         *pflags = 0;
     587             :                 }
     588          16 :                 return NT_STATUS_OK;
     589             :         }
     590             : 
     591           0 :         status = reparse_data_buffer_parse(state,
     592             :                                            &buf,
     593           0 :                                            state->data,
     594           0 :                                            state->num_data);
     595           0 :         if (!NT_STATUS_IS_OK(status)) {
     596           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     597             :         }
     598           0 :         if (buf.tag != IO_REPARSE_TAG_SYMLINK) {
     599           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     600             :         }
     601             : 
     602           0 :         if (psubstitute_name != NULL) {
     603           0 :                 *psubstitute_name =
     604           0 :                         talloc_move(mem_ctx, &buf.parsed.lnk.substitute_name);
     605             :         }
     606             : 
     607           0 :         if (pprint_name != NULL) {
     608           0 :                 *pprint_name =
     609           0 :                         talloc_move(mem_ctx, &buf.parsed.lnk.print_name);
     610             :         }
     611             : 
     612           0 :         if (pflags != NULL) {
     613           0 :                 *pflags = buf.parsed.lnk.flags;
     614             :         }
     615             : 
     616           0 :         tevent_req_received(req);
     617             : 
     618           0 :         return NT_STATUS_OK;
     619             : }
     620             : 
     621          16 : NTSTATUS cli_readlink(struct cli_state *cli, const char *fname,
     622             :                        TALLOC_CTX *mem_ctx, char **psubstitute_name,
     623             :                       char **pprint_name, uint32_t *pflags)
     624             : {
     625          16 :         TALLOC_CTX *frame = talloc_stackframe();
     626           0 :         struct tevent_context *ev;
     627           0 :         struct tevent_req *req;
     628          16 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     629             : 
     630          16 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     631           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     632           0 :                 goto fail;
     633             :         }
     634          16 :         ev = samba_tevent_context_init(frame);
     635          16 :         if (ev == NULL) {
     636           0 :                 goto fail;
     637             :         }
     638          16 :         req = cli_readlink_send(frame, ev, cli, fname);
     639          16 :         if (req == NULL) {
     640           0 :                 goto fail;
     641             :         }
     642          16 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     643           0 :                 goto fail;
     644             :         }
     645          16 :         status = cli_readlink_recv(req, mem_ctx, psubstitute_name,
     646             :                                    pprint_name, pflags);
     647          16 :  fail:
     648          16 :         TALLOC_FREE(frame);
     649          16 :         return status;
     650             : }

Generated by: LCOV version 1.14