libcli: Make symlink_reparse_buffer_parse() more flexible
[samba.git] / source3 / libsmb / clisymlink.c
index 90f48a2029de20be4d5fb4f9569f29aedb922070..1155526f96d5fdf457968e0de5d3f665f466d7b9 100644 (file)
@@ -37,8 +37,8 @@ struct cli_symlink_state {
        uint32_t flags;
 
        uint16_t fnum;
+       DATA_BLOB in;
 
-       uint16_t setup[4];
        NTSTATUS set_reparse_status;
 };
 
@@ -88,7 +88,6 @@ static void cli_symlink_create_done(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct cli_symlink_state *state = tevent_req_data(
                req, struct cli_symlink_state);
-       DATA_BLOB data;
        NTSTATUS status;
 
        status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
@@ -98,34 +97,20 @@ static void cli_symlink_create_done(struct tevent_req *subreq)
        }
 
        if (!symlink_reparse_buffer_marshall(
-                   state->link_target, NULL, state->flags, state,
-                   &data.data, &data.length)) {
+                   state->link_target, NULL, 0, state->flags, state,
+                   &state->in.data, &state->in.length)) {
                tevent_req_oom(req);
                return;
        }
 
-       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
-               subreq = cli_smb2_set_reparse_point_fnum_send(state,
-                                               state->ev,
-                                               state->cli,
-                                               state->fnum,
-                                               data);
-       } else {
-               SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
-               SSVAL(state->setup, 4, state->fnum);
-               SCVAL(state->setup, 6, 1); /* IsFcntl */
-               SCVAL(state->setup, 7, 0); /* IsFlags */
-
-
-               subreq = cli_trans_send(state, state->ev, state->cli, 0,
-                               SMBnttrans,
-                               NULL, -1, /* name, fid */
-                               NT_TRANSACT_IOCTL, 0,
-                               state->setup, 4, 0, /* setup */
-                               NULL, 0, 0,         /* param */
-                               data.data, data.length, 0); /* data */
-       }
-
+       subreq = cli_fsctl_send(
+               state,
+               state->ev,
+               state->cli,
+               state->fnum,
+               FSCTL_SET_REPARSE_POINT,
+               &state->in,
+               0);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -139,16 +124,7 @@ static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
        struct cli_symlink_state *state = tevent_req_data(
                req, struct cli_symlink_state);
 
-       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
-               state->set_reparse_status =
-                       cli_smb2_set_reparse_point_fnum_recv(subreq);
-       } else {
-               state->set_reparse_status = cli_trans_recv(
-                       subreq, NULL, NULL,
-                       NULL, 0, NULL,  /* rsetup */
-                       NULL, 0, NULL,  /* rparam */
-                       NULL, 0, NULL); /* rdata */
-       }
+       state->set_reparse_status = cli_fsctl_recv(subreq, NULL, NULL);
        TALLOC_FREE(subreq);
 
        if (NT_STATUS_IS_OK(state->set_reparse_status)) {
@@ -252,8 +228,10 @@ struct cli_readlink_state {
        NTSTATUS get_reparse_status;
        uint8_t *data;
        uint32_t num_data;
+       char *target;
 };
 
+static void cli_readlink_posix1_done(struct tevent_req *subreq);
 static void cli_readlink_opened(struct tevent_req *subreq);
 static void cli_readlink_got_reparse_data(struct tevent_req *subreq);
 static void cli_readlink_closed(struct tevent_req *subreq);
@@ -273,6 +251,18 @@ struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
        state->ev = ev;
        state->cli = cli;
 
+       if (cli->requested_posix_capabilities != 0) {
+               /*
+                * Only happens for negotiated SMB1 posix caps
+                */
+               subreq = cli_posix_readlink_send(state, ev, cli, fname);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_readlink_posix1_done, req);
+               return req;
+       }
+
        subreq = cli_ntcreate_send(
                state, ev, cli, fname, 0, FILE_READ_ATTRIBUTES | FILE_READ_EA,
                0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
@@ -285,7 +275,7 @@ struct tevent_req *cli_readlink_send(TALLOC_CTX *mem_ctx,
        return req;
 }
 
-static void cli_readlink_opened(struct tevent_req *subreq)
+static void cli_readlink_posix1_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
@@ -293,32 +283,37 @@ static void cli_readlink_opened(struct tevent_req *subreq)
                req, struct cli_readlink_state);
        NTSTATUS status;
 
-       status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
+       status = cli_posix_readlink_recv(subreq, state, &state->target);
        TALLOC_FREE(subreq);
        if (tevent_req_nterror(req, status)) {
                return;
        }
+       tevent_req_done(req);
+}
 
-       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
-               subreq = cli_smb2_get_reparse_point_fnum_send(state,
-                                               state->ev,
-                                               state->cli,
-                                               state->fnum);
-       } else {
-               SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
-               SSVAL(state->setup, 4, state->fnum);
-               SCVAL(state->setup, 6, 1); /* IsFcntl */
-               SCVAL(state->setup, 7, 0); /* IsFlags */
+static void cli_readlink_opened(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct cli_readlink_state *state = tevent_req_data(
+               req, struct cli_readlink_state);
+       NTSTATUS status;
 
-               subreq = cli_trans_send(state, state->ev, state->cli,
-                               0, SMBnttrans,
-                               NULL, -1, /* name, fid */
-                               NT_TRANSACT_IOCTL, 0,
-                               state->setup, 4, 0, /* setup */
-                               NULL, 0, 0,         /* param */
-                               NULL, 0, 16384); /* data */
+       status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
        }
 
+       subreq = cli_fsctl_send(
+               state,
+               state->ev,
+               state->cli,
+               state->fnum,
+               FSCTL_GET_REPARSE_POINT,
+               NULL,
+               65536);
+
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -331,26 +326,16 @@ static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct cli_readlink_state *state = tevent_req_data(
                req, struct cli_readlink_state);
+       DATA_BLOB out = { .data = NULL, };
 
-       if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
-               DATA_BLOB recv_data;
-               state->get_reparse_status =
-                       cli_smb2_get_reparse_point_fnum_recv(subreq,
-                                                       state,
-                                                       &recv_data);
-               if (NT_STATUS_IS_OK(state->get_reparse_status)) {
-                       state->data = recv_data.data;
-                       state->num_data = recv_data.length;
-               }
-       } else {
-               state->get_reparse_status = cli_trans_recv(
-                       subreq, state, NULL,
-                       NULL, 0, NULL,  /* rsetup */
-                       NULL, 0, NULL,  /* rparam */
-                       &state->data, 20, &state->num_data); /* rdata */
-       }
+       state->get_reparse_status = cli_fsctl_recv(subreq, state, &out);
        TALLOC_FREE(subreq);
 
+       if (NT_STATUS_IS_OK(state->get_reparse_status)) {
+               state->data = out.data;
+               state->num_data = out.length;
+       }
+
        subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
        if (tevent_req_nomem(subreq, req)) {
                return;
@@ -383,33 +368,52 @@ NTSTATUS cli_readlink_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 {
        struct cli_readlink_state *state = tevent_req_data(
                req, struct cli_readlink_state);
-       struct symlink_reparse_struct *symlink = NULL;
+       struct symlink_reparse_struct symlink = { .flags = 0, };
        NTSTATUS status;
+       int ret;
 
        if (tevent_req_is_nterror(req, &status)) {
                return status;
        }
 
-       symlink = symlink_reparse_buffer_parse(
-               talloc_tos(), state->data, state->num_data);
-       if (symlink == NULL) {
+       if (state->target != NULL) {
+               /*
+                * SMB1 posix version
+                */
+               if (psubstitute_name != NULL) {
+                       *psubstitute_name = talloc_move(
+                               mem_ctx, &state->target);
+               }
+               if (pprint_name != NULL) {
+                       *pprint_name = NULL;
+               }
+               if (pflags != NULL) {
+                       *pflags = 0;
+               }
+               return NT_STATUS_OK;
+       }
+
+       ret = symlink_reparse_buffer_parse(
+               talloc_tos(), &symlink, state->data, state->num_data);
+       if (ret != 0) {
                return NT_STATUS_INVALID_NETWORK_RESPONSE;
        }
 
        if (psubstitute_name != NULL) {
                *psubstitute_name = talloc_move(
-                       mem_ctx, &symlink->substitute_name);
+                       mem_ctx, &symlink.substitute_name);
        }
 
        if (pprint_name != NULL) {
-               *pprint_name = talloc_move(mem_ctx, &symlink->print_name);
+               *pprint_name = talloc_move(mem_ctx, &symlink.print_name);
        }
 
        if (pflags != NULL) {
-               *pflags = symlink->flags;
+               *pflags = symlink.flags;
        }
 
-       TALLOC_FREE(symlink);
+       TALLOC_FREE(symlink.print_name);
+       TALLOC_FREE(symlink.substitute_name);
 
        return NT_STATUS_OK;
 }