libsmb: Pass NTTIME to interpret_long_date()
[samba.git] / source3 / libsmb / clirap.c
index a52fe3162b1a4db9a28fc7b0cbcc52404523eb46..7944eeb847c2e2daf2783f299066812d97ebace4 100644 (file)
@@ -29,6 +29,7 @@
 #include "trans2.h"
 #include "../libcli/smb/smbXcli_base.h"
 #include "cli_smb2_fnum.h"
+#include "lib/util/string_wrappers.h"
 
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
@@ -551,137 +552,6 @@ done:
        return (cli->rap_error == 0);
 }
 
-/****************************************************************************
- Send a qpathinfo call.
-****************************************************************************/
-
-struct cli_qpathinfo1_state {
-       struct cli_state *cli;
-       uint32_t num_data;
-       uint8_t *data;
-};
-
-static void cli_qpathinfo1_done(struct tevent_req *subreq);
-
-struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
-                                      struct tevent_context *ev,
-                                      struct cli_state *cli,
-                                      const char *fname)
-{
-       struct tevent_req *req = NULL, *subreq = NULL;
-       struct cli_qpathinfo1_state *state = NULL;
-
-       req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
-       if (req == NULL) {
-               return NULL;
-       }
-       state->cli = cli;
-       subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
-                                   22, CLI_BUFFER_SIZE);
-       if (tevent_req_nomem(subreq, req)) {
-               return tevent_req_post(req, ev);
-       }
-       tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
-       return req;
-}
-
-static void cli_qpathinfo1_done(struct tevent_req *subreq)
-{
-       struct tevent_req *req = tevent_req_callback_data(
-               subreq, struct tevent_req);
-       struct cli_qpathinfo1_state *state = tevent_req_data(
-               req, struct cli_qpathinfo1_state);
-       NTSTATUS status;
-
-       status = cli_qpathinfo_recv(subreq, state, &state->data,
-                                   &state->num_data);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
-               return;
-       }
-       tevent_req_done(req);
-}
-
-NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
-                            time_t *change_time,
-                            time_t *access_time,
-                            time_t *write_time,
-                            off_t *size,
-                            uint32_t *pattr)
-{
-       struct cli_qpathinfo1_state *state = tevent_req_data(
-               req, struct cli_qpathinfo1_state);
-       NTSTATUS status;
-
-       time_t (*date_fn)(const void *buf, int serverzone);
-
-       if (tevent_req_is_nterror(req, &status)) {
-               return status;
-       }
-
-       if (state->cli->win95) {
-               date_fn = make_unix_date;
-       } else {
-               date_fn = make_unix_date2;
-       }
-
-       if (change_time) {
-               *change_time = date_fn(state->data+0, smb1cli_conn_server_time_zone(state->cli->conn));
-       }
-       if (access_time) {
-               *access_time = date_fn(state->data+4, smb1cli_conn_server_time_zone(state->cli->conn));
-       }
-       if (write_time) {
-               *write_time = date_fn(state->data+8, smb1cli_conn_server_time_zone(state->cli->conn));
-       }
-       if (size) {
-               *size = IVAL(state->data, 12);
-       }
-       if (pattr) {
-               *pattr = SVAL(state->data, l1_attrFile);
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS cli_qpathinfo1(struct cli_state *cli,
-                       const char *fname,
-                       time_t *change_time,
-                       time_t *access_time,
-                       time_t *write_time,
-                       off_t *size,
-                       uint32_t *pattr)
-{
-       TALLOC_CTX *frame = talloc_stackframe();
-       struct tevent_context *ev;
-       struct tevent_req *req;
-       NTSTATUS status = NT_STATUS_NO_MEMORY;
-
-       if (smbXcli_conn_has_async_calls(cli->conn)) {
-               /*
-                * Can't use sync call while an async call is in flight
-                */
-               status = NT_STATUS_INVALID_PARAMETER;
-               goto fail;
-       }
-       ev = samba_tevent_context_init(frame);
-       if (ev == NULL) {
-               goto fail;
-       }
-       req = cli_qpathinfo1_send(frame, ev, cli, fname);
-       if (req == NULL) {
-               goto fail;
-       }
-       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
-               goto fail;
-       }
-       status = cli_qpathinfo1_recv(req, change_time, access_time,
-                                    write_time, size, pattr);
- fail:
-       TALLOC_FREE(frame);
-       return status;
-}
-
 static void prep_basic_information_buf(
        uint8_t buf[40],
        struct timespec create_time,
@@ -907,10 +777,16 @@ NTSTATUS cli_setfileinfo_ext(
 ****************************************************************************/
 
 struct cli_qpathinfo2_state {
-       uint32_t num_data;
-       uint8_t *data;
+       struct timespec create_time;
+       struct timespec access_time;
+       struct timespec write_time;
+       struct timespec change_time;
+       off_t size;
+       uint32_t attr;
+       SMB_INO_T ino;
 };
 
+static void cli_qpathinfo2_done2(struct tevent_req *subreq);
 static void cli_qpathinfo2_done(struct tevent_req *subreq);
 
 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
@@ -925,6 +801,20 @@ struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
        if (req == NULL) {
                return NULL;
        }
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               subreq = cli_smb2_qpathinfo_send(state,
+                                                ev,
+                                                cli,
+                                                fname,
+                                                FSCC_FILE_ALL_INFORMATION,
+                                                0x60,
+                                                UINT16_MAX);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
+               return req;
+       }
        subreq = cli_qpathinfo_send(state, ev, cli, fname,
                                    SMB_QUERY_FILE_ALL_INFO,
                                    68, CLI_BUFFER_SIZE);
@@ -935,21 +825,66 @@ struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
        return req;
 }
 
+static void cli_qpathinfo2_done2(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq, struct tevent_req);
+       struct cli_qpathinfo2_state *state =
+               tevent_req_data(req, struct cli_qpathinfo2_state);
+       uint8_t *rdata = NULL;
+       uint32_t num_rdata;
+       NTSTATUS status;
+
+       status = cli_smb2_qpathinfo_recv(subreq, state, &rdata, &num_rdata);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       state->create_time = interpret_long_date(BVAL(rdata, 0x0));
+       state->access_time = interpret_long_date(BVAL(rdata, 0x8));
+       state->write_time = interpret_long_date(BVAL(rdata, 0x10));
+       state->change_time = interpret_long_date(BVAL(rdata, 0x18));
+       state->attr = PULL_LE_U32(rdata, 0x20);
+       state->size = PULL_LE_U64(rdata, 0x30);
+       state->ino = PULL_LE_U64(rdata, 0x40);
+
+       tevent_req_done(req);
+}
+
 static void cli_qpathinfo2_done(struct tevent_req *subreq)
 {
        struct tevent_req *req = tevent_req_callback_data(
                subreq, struct tevent_req);
        struct cli_qpathinfo2_state *state = tevent_req_data(
                req, struct cli_qpathinfo2_state);
+       uint8_t *data = NULL;
+       uint32_t num_data;
        NTSTATUS status;
 
-       status = cli_qpathinfo_recv(subreq, state, &state->data,
-                                   &state->num_data);
+       status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
+       if (tevent_req_nterror(req, status)) {
                return;
        }
+
+       state->create_time = interpret_long_date(BVAL(data, 0));
+       state->access_time = interpret_long_date(BVAL(data, 8));
+       state->write_time = interpret_long_date(BVAL(data, 16));
+       state->change_time = interpret_long_date(BVAL(data, 24));
+       state->attr = PULL_LE_U32(data, 32);
+       state->size = PULL_LE_U64(data, 48);
+
+       /*
+        * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn't
+        * return an inode number (fileid).  We can't change this to
+        * one of the FILE_ID info levels as only Win2003 and above
+        * support these [MS-SMB: 2.2.2.3.1] and the SMB1 code needs
+        * to support older servers.
+        */
+       state->ino = 0;
+
+       TALLOC_FREE(data);
+
        tevent_req_done(req);
 }
 
@@ -970,34 +905,25 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
        }
 
        if (create_time) {
-                *create_time = interpret_long_date((char *)state->data+0);
+               *create_time = state->create_time;
        }
        if (access_time) {
-               *access_time = interpret_long_date((char *)state->data+8);
+               *access_time = state->access_time;
        }
        if (write_time) {
-               *write_time = interpret_long_date((char *)state->data+16);
+               *write_time = state->write_time;
        }
        if (change_time) {
-               *change_time = interpret_long_date((char *)state->data+24);
+               *change_time = state->change_time;
        }
        if (pattr) {
-               /* SMB_QUERY_FILE_ALL_INFO returns 32-bit attributes. */
-               *pattr = IVAL(state->data, 32);
+               *pattr = state->attr;
        }
        if (size) {
-                *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
+               *size = state->size;
        }
        if (ino) {
-               /*
-                * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO
-                * which doesn't return an inode number (fileid).
-                * We can't change this to one of the FILE_ID
-                * info levels as only Win2003 and above support
-                * these [MS-SMB: 2.2.2.3.1] and the SMB1 code
-                * needs to support older servers.
-                */
-               *ino = 0;
+               *ino = state->ino;
        }
        return NT_STATUS_OK;
 }
@@ -1010,25 +936,11 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
                        off_t *size, uint32_t *pattr,
                        SMB_INO_T *ino)
 {
-       TALLOC_CTX *frame = NULL;
-       struct tevent_context *ev;
-       struct tevent_req *req;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev = NULL;
+       struct tevent_req *req = NULL;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_qpathinfo2(cli,
-                                       fname,
-                                       create_time,
-                                       access_time,
-                                       write_time,
-                                       change_time,
-                                       size,
-                                       pattr,
-                                       ino);
-       }
-
-       frame = talloc_stackframe();
-
        if (smbXcli_conn_has_async_calls(cli->conn)) {
                /*
                 * Can't use sync call while an async call is in flight
@@ -1064,6 +976,7 @@ struct cli_qpathinfo_streams_state {
 };
 
 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
+static void cli_qpathinfo_streams_done2(struct tevent_req *subreq);
 
 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
                                              struct tevent_context *ev,
@@ -1078,6 +991,22 @@ struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
        if (req == NULL) {
                return NULL;
        }
+       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+               subreq = cli_smb2_qpathinfo_send(state,
+                                                ev,
+                                                cli,
+                                                fname,
+                                                FSCC_FILE_STREAM_INFORMATION,
+                                                0,
+                                                CLI_BUFFER_SIZE);
+               if (tevent_req_nomem(subreq, req)) {
+                       return tevent_req_post(req, ev);
+               }
+               tevent_req_set_callback(subreq,
+                                       cli_qpathinfo_streams_done2,
+                                       req);
+               return req;
+       }
        subreq = cli_qpathinfo_send(state, ev, cli, fname,
                                    SMB_FILE_STREAM_INFORMATION,
                                    0, CLI_BUFFER_SIZE);
@@ -1098,12 +1027,22 @@ static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
 
        status = cli_qpathinfo_recv(subreq, state, &state->data,
                                    &state->num_data);
-       TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
-               return;
-       }
-       tevent_req_done(req);
+       tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+static void cli_qpathinfo_streams_done2(struct tevent_req *subreq)
+{
+       struct tevent_req *req =
+               tevent_req_callback_data(subreq, struct tevent_req);
+       struct cli_qpathinfo_streams_state *state =
+               tevent_req_data(req, struct cli_qpathinfo_streams_state);
+       NTSTATUS status;
+
+       status = cli_smb2_qpathinfo_recv(subreq,
+                                        state,
+                                        &state->data,
+                                        &state->num_data);
+       tevent_req_simple_finish_ntstatus(subreq, status);
 }
 
 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
@@ -1135,14 +1074,6 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
        struct tevent_req *req;
        NTSTATUS status = NT_STATUS_NO_MEMORY;
 
-       if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
-               return cli_smb2_qpathinfo_streams(cli,
-                                       fname,
-                                       mem_ctx,
-                                       pnum_streams,
-                                       pstreams);
-       }
-
        frame = talloc_stackframe();
 
        if (smbXcli_conn_has_async_calls(cli->conn)) {
@@ -1256,48 +1187,6 @@ bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
  Send a qfileinfo QUERY_FILE_NAME_INFO call.
 ****************************************************************************/
 
-NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum,
-                      TALLOC_CTX *mem_ctx, char **_name)
-{
-       uint16_t recv_flags2;
-       uint8_t *rdata;
-       uint32_t num_rdata;
-       NTSTATUS status;
-       char *name = NULL;
-       uint32_t namelen;
-
-       status = cli_qfileinfo(talloc_tos(), cli, fnum,
-                              SMB_QUERY_FILE_NAME_INFO,
-                              4, CLI_BUFFER_SIZE, &recv_flags2,
-                              &rdata, &num_rdata);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       namelen = IVAL(rdata, 0);
-       if (namelen > (num_rdata - 4)) {
-               TALLOC_FREE(rdata);
-               return NT_STATUS_INVALID_NETWORK_RESPONSE;
-       }
-
-       pull_string_talloc(mem_ctx,
-                          (const char *)rdata,
-                          recv_flags2,
-                          &name,
-                          rdata + 4,
-                          namelen,
-                          STR_UNICODE);
-       if (name == NULL) {
-               status = map_nt_error_from_unix(errno);
-               TALLOC_FREE(rdata);
-               return status;
-       }
-
-       *_name = name;
-       TALLOC_FREE(rdata);
-       return NT_STATUS_OK;
-}
-
 struct cli_qfileinfo_basic_state {
        uint32_t attr;
        off_t size;
@@ -1404,10 +1293,10 @@ static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
                return;
        }
 
-       state->create_time = interpret_long_date((char *)rdata+0);
-       state->access_time = interpret_long_date((char *)rdata+8);
-       state->write_time = interpret_long_date((char *)rdata+16);
-       state->change_time = interpret_long_date((char *)rdata+24);
+       state->create_time = interpret_long_date(BVAL(rdata, 0));
+       state->access_time = interpret_long_date(BVAL(rdata, 8));
+       state->write_time = interpret_long_date(BVAL(rdata, 16));
+       state->change_time = interpret_long_date(BVAL(rdata, 24));
        state->attr = PULL_LE_U32(rdata, 32);
        state->size = PULL_LE_U64(rdata,48);
        state->ino = PULL_LE_U32(rdata, 64);
@@ -1459,14 +1348,10 @@ static void cli_qfileinfo_basic_done2(struct tevent_req *subreq)
                return;
        }
 
-       state->create_time = interpret_long_date(
-               (const char *)outbuf.data + 0x0);
-       state->access_time = interpret_long_date(
-               (const char *)outbuf.data + 0x8);
-       state->write_time = interpret_long_date(
-               (const char *)outbuf.data + 0x10);
-       state->change_time = interpret_long_date(
-               (const char *)outbuf.data + 0x18);
+       state->create_time = interpret_long_date(BVAL(outbuf.data, 0x0));
+       state->access_time = interpret_long_date(BVAL(outbuf.data, 0x8));
+       state->write_time = interpret_long_date(BVAL(outbuf.data, 0x10));
+       state->change_time = interpret_long_date(BVAL(outbuf.data, 0x18));
        state->attr = IVAL(outbuf.data, 0x20);
        state->size = BVAL(outbuf.data, 0x30);
        state->ino = BVAL(outbuf.data, 0x40);
@@ -1621,8 +1506,7 @@ static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
        status = cli_qpathinfo_recv(subreq, state, &state->data,
                                    &state->num_data);
        TALLOC_FREE(subreq);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
+       if (tevent_req_nterror(req, status)) {
                return;
        }
        tevent_req_done(req);
@@ -1639,10 +1523,10 @@ NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
                return status;
        }
 
-       sbuf->st_ex_btime = interpret_long_date((char *)state->data);
-       sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
-       sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
-       sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
+       sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
+       sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
+       sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
+       sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
        *attributes = IVAL(state->data, 32);
        return NT_STATUS_OK;
 }