2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Gerald (Jerry) Carter 2004
6 Copyright (C) James Peach 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "../libcli/auth/libcli_auth.h"
24 #include "../librpc/gen_ndr/rap.h"
25 #include "../lib/util/tevent_ntstatus.h"
26 #include "async_smb.h"
27 #include "libsmb/libsmb.h"
28 #include "libsmb/clirap.h"
30 #include "../libcli/smb/smbXcli_base.h"
31 #include "cli_smb2_fnum.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 #define PIPE_LANMAN "\\PIPE\\LANMAN"
38 /****************************************************************************
40 ****************************************************************************/
42 bool cli_api(struct cli_state *cli,
43 char *param, int prcnt, int mprcnt,
44 char *data, int drcnt, int mdrcnt,
45 char **rparam, unsigned int *rprcnt,
46 char **rdata, unsigned int *rdrcnt)
50 uint8_t *my_rparam, *my_rdata;
51 uint32_t num_my_rparam, num_my_rdata;
53 status = cli_trans(talloc_tos(), cli, SMBtrans,
54 PIPE_LANMAN, 0, /* name, fid */
55 0, 0, /* function, flags */
56 NULL, 0, 0, /* setup */
57 (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
58 (uint8_t *)data, drcnt, mdrcnt, /* Data, length, max */
59 NULL, /* recv_flags2 */
60 NULL, 0, NULL, /* rsetup */
61 &my_rparam, 0, &num_my_rparam,
62 &my_rdata, 0, &num_my_rdata);
63 if (!NT_STATUS_IS_OK(status)) {
68 * I know this memcpy massively hurts, but there are just tons
69 * of callers of cli_api that eventually need changing to
73 *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
74 if (*rparam == NULL) {
77 *rprcnt = num_my_rparam;
78 TALLOC_FREE(my_rparam);
80 *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
84 *rdrcnt = num_my_rdata;
85 TALLOC_FREE(my_rdata);
89 TALLOC_FREE(my_rdata);
90 TALLOC_FREE(my_rparam);
98 /****************************************************************************
99 Call a NetShareEnum - try and browse available connections on a host.
100 ****************************************************************************/
102 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
107 unsigned int rdrcnt,rprcnt;
113 /* now send a SMBtrans command with api RNetShareEnum */
115 SSVAL(p,0,0); /* api number */
117 strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
118 p = skip_string(param,sizeof(param),p);
119 strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
120 p = skip_string(param,sizeof(param),p);
123 * Win2k needs a *smaller* buffer than 0xFFFF here -
124 * it returns "out of server memory" with 0xFFFF !!! JRA.
131 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
132 NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
133 &rparam, &rprcnt, /* return params, length */
134 &rdata, &rdrcnt); /* return data, length */
136 DEBUG(4,("NetShareEnum failed\n"));
141 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
145 res = rparam? SVAL(rparam,0) : -1;
147 if (res == 0 || res == ERRmoredata) {
148 int converter=SVAL(rparam,2);
150 char *rdata_end = rdata + rdrcnt;
152 count=SVAL(rparam,4);
155 for (i=0;i<count;i++,p+=20) {
163 TALLOC_CTX *frame = talloc_stackframe();
165 if (p + 20 > rdata_end) {
172 comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
173 if (comment_offset < 0 ||
174 comment_offset > (int)rdrcnt) {
178 cmnt = comment_offset?(rdata+comment_offset):"";
180 /* Work out the comment length. */
181 for (p1 = cmnt, len = 0; *p1 &&
182 p1 < rdata_end; len++)
187 pull_string_talloc(frame,rdata,0,
188 &s1,sname,14,STR_ASCII);
189 pull_string_talloc(frame,rdata,0,
190 &s2,cmnt,len,STR_ASCII);
196 fn(s1, type, s2, state);
201 DEBUG(4,("NetShareEnum res=%d\n", res));
211 /****************************************************************************
212 Call a NetServerEnum for the specified workgroup and servertype mask. This
213 function then calls the specified callback function for each name returned.
215 The callback function takes 4 arguments: the machine name, the server type,
216 the comment and a state pointer.
217 ****************************************************************************/
219 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
220 void (*fn)(const char *, uint32_t, const char *, void *),
225 char *rdata_end = NULL;
226 unsigned int rdrcnt,rprcnt;
231 uint32_t func = RAP_NetServerEnum2;
232 char *last_entry = NULL;
237 errno = 0; /* reset */
240 * This may take more than one transaction, so we should loop until
241 * we no longer get a more data to process or we have all of the
245 /* send a SMBtrans command with api NetServerEnum */
247 SIVAL(p,0,func); /* api number */
250 if (func == RAP_NetServerEnum3) {
251 strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
253 strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
256 p = skip_string(param, sizeof(param), p);
257 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
259 p = skip_string(param, sizeof(param), p);
261 SSVAL(p,2,CLI_BUFFER_SIZE);
266 /* If we have more data, tell the server where
271 sizeof(param) - PTR_DIFF(p,param) - 1,
272 STR_TERMINATE|STR_UPPER);
275 SAFE_FREE(last_entry);
280 if (func == RAP_NetServerEnum3) {
282 last_entry ? last_entry : "",
283 sizeof(param) - PTR_DIFF(p,param) - 1,
287 SAFE_FREE(last_entry);
293 /* Next time through we need to use the continue api */
294 func = RAP_NetServerEnum3;
297 param, PTR_DIFF(p,param), 8, /* params, length, max */
298 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
299 &rparam, &rprcnt, /* return params, return size */
300 &rdata, &rdrcnt)) { /* return data, return size */
302 /* break out of the loop on error */
307 rdata_end = rdata + rdrcnt;
310 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
315 res = rparam ? SVAL(rparam,0) : -1;
317 if (res == 0 || res == ERRmoredata ||
318 (res != -1 && cli_errno(cli) == 0)) {
321 int converter=SVAL(rparam,2);
323 /* Get the number of items returned in this buffer */
324 count = SVAL(rparam, 4);
326 /* The next field contains the number of items left,
327 * including those returned in this buffer. So the
328 * first time through this should contain all of the
331 if (total_cnt == 0) {
332 total_cnt = SVAL(rparam, 6);
335 /* Keep track of how many we have read */
339 /* The last name in the previous NetServerEnum reply is
340 * sent back to server in the NetServerEnum3 request
341 * (last_entry). The next reply should repeat this entry
342 * as the first element. We have no proof that this is
343 * always true, but from traces that seems to be the
344 * behavior from Window Servers. So first lets do a lot
345 * of checking, just being paranoid. If the string
346 * matches then we already saw this entry so skip it.
348 * NOTE: sv1_name field must be null terminated and has
349 * a max size of 16 (NetBIOS Name).
351 if (last_entry && count && p &&
352 (strncmp(last_entry, p, 16) == 0)) {
353 count -= 1; /* Skip this entry */
354 return_cnt = -1; /* Not part of total, so don't count. */
355 p = rdata + 26; /* Skip the whole record */
358 for (i = 0; i < count; i++, p += 26) {
363 TALLOC_CTX *frame = talloc_stackframe();
364 uint32_t entry_stype;
366 if (p + 26 > rdata_end) {
372 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
373 cmnt = comment_offset?(rdata+comment_offset):"";
375 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
380 /* Work out the comment length. */
381 for (p1 = cmnt, len = 0; *p1 &&
382 p1 < rdata_end; len++)
388 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
390 pull_string_talloc(frame,rdata,0,
391 &s1,sname,16,STR_ASCII);
392 pull_string_talloc(frame,rdata,0,
393 &s2,cmnt,len,STR_ASCII);
400 fn(s1, entry_stype, s2, state);
404 /* We are done with the old last entry, so now we can free it */
406 SAFE_FREE(last_entry); /* This will set it to null */
409 /* We always make a copy of the last entry if we have one */
411 last_entry = smb_xstrdup(sname);
414 /* If we have more data, but no last entry then error out */
415 if (!last_entry && (res == ERRmoredata)) {
424 } while ((res == ERRmoredata) && (total_cnt > return_cnt));
428 SAFE_FREE(last_entry);
431 errno = cli_errno(cli);
434 /* this is a very special case, when the domain master for the
435 work group isn't part of the work group itself, there is something
441 return(return_cnt > 0);
444 /****************************************************************************
445 Send a SamOEMChangePassword command.
446 ****************************************************************************/
448 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
449 const char *old_password)
452 unsigned char data[532];
454 unsigned char old_pw_hash[16];
455 unsigned char new_pw_hash[16];
456 unsigned int data_len;
457 unsigned int param_len = 0;
460 unsigned int rprcnt, rdrcnt;
461 gnutls_cipher_hd_t cipher_hnd = NULL;
462 gnutls_datum_t old_pw_key = {
464 .size = sizeof(old_pw_hash),
468 if (strlen(user) >= sizeof(fstring)-1) {
469 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
473 SSVAL(p,0,214); /* SamOEMChangePassword command. */
475 strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
476 p = skip_string(param,sizeof(param),p);
477 strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
478 p = skip_string(param,sizeof(param),p);
479 strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
480 p = skip_string(param,sizeof(param),p);
484 param_len = PTR_DIFF(p,param);
487 * Get the Lanman hash of the old password, we
488 * use this as the key to make_oem_passwd_hash().
490 E_deshash(old_password, old_pw_hash);
492 encode_pw_buffer(data, new_password, STR_ASCII);
494 #ifdef DEBUG_PASSWORD
495 DEBUG(100,("make_oem_passwd_hash\n"));
496 dump_data(100, data, 516);
498 rc = gnutls_cipher_init(&cipher_hnd,
499 GNUTLS_CIPHER_ARCFOUR_128,
503 DBG_ERR("gnutls_cipher_init failed: %s\n",
504 gnutls_strerror(rc));
507 rc = gnutls_cipher_encrypt(cipher_hnd,
510 gnutls_cipher_deinit(cipher_hnd);
516 * Now place the old password hash in the data.
518 E_deshash(new_password, new_pw_hash);
520 rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
522 DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
529 param, param_len, 4, /* param, length, max */
530 (char *)data, data_len, 0, /* data, length, max */
533 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
539 cli->rap_error = ERRbadformat;
544 cli->rap_error = SVAL(rparam,0);
551 return (cli->rap_error == 0);
554 /****************************************************************************
555 Send a qpathinfo call.
556 ****************************************************************************/
558 struct cli_qpathinfo1_state {
559 struct cli_state *cli;
564 static void cli_qpathinfo1_done(struct tevent_req *subreq);
566 struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
567 struct tevent_context *ev,
568 struct cli_state *cli,
571 struct tevent_req *req = NULL, *subreq = NULL;
572 struct cli_qpathinfo1_state *state = NULL;
574 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
579 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
580 22, CLI_BUFFER_SIZE);
581 if (tevent_req_nomem(subreq, req)) {
582 return tevent_req_post(req, ev);
584 tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
588 static void cli_qpathinfo1_done(struct tevent_req *subreq)
590 struct tevent_req *req = tevent_req_callback_data(
591 subreq, struct tevent_req);
592 struct cli_qpathinfo1_state *state = tevent_req_data(
593 req, struct cli_qpathinfo1_state);
596 status = cli_qpathinfo_recv(subreq, state, &state->data,
599 if (!NT_STATUS_IS_OK(status)) {
600 tevent_req_nterror(req, status);
603 tevent_req_done(req);
606 NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
613 struct cli_qpathinfo1_state *state = tevent_req_data(
614 req, struct cli_qpathinfo1_state);
617 time_t (*date_fn)(const void *buf, int serverzone);
619 if (tevent_req_is_nterror(req, &status)) {
623 if (state->cli->win95) {
624 date_fn = make_unix_date;
626 date_fn = make_unix_date2;
630 *change_time = date_fn(state->data+0, smb1cli_conn_server_time_zone(state->cli->conn));
633 *access_time = date_fn(state->data+4, smb1cli_conn_server_time_zone(state->cli->conn));
636 *write_time = date_fn(state->data+8, smb1cli_conn_server_time_zone(state->cli->conn));
639 *size = IVAL(state->data, 12);
642 *pattr = SVAL(state->data, l1_attrFile);
647 NTSTATUS cli_qpathinfo1(struct cli_state *cli,
655 TALLOC_CTX *frame = talloc_stackframe();
656 struct tevent_context *ev;
657 struct tevent_req *req;
658 NTSTATUS status = NT_STATUS_NO_MEMORY;
660 if (smbXcli_conn_has_async_calls(cli->conn)) {
662 * Can't use sync call while an async call is in flight
664 status = NT_STATUS_INVALID_PARAMETER;
667 ev = samba_tevent_context_init(frame);
671 req = cli_qpathinfo1_send(frame, ev, cli, fname);
675 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
678 status = cli_qpathinfo1_recv(req, change_time, access_time,
679 write_time, size, pattr);
685 static void prep_basic_information_buf(
687 struct timespec create_time,
688 struct timespec access_time,
689 struct timespec write_time,
690 struct timespec change_time,
693 char *p = (char *)buf;
695 * Add the create, last access, modification, and status change times
697 put_long_date_full_timespec(
698 TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
701 put_long_date_full_timespec(
702 TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
705 put_long_date_full_timespec(
706 TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
709 put_long_date_full_timespec(
710 TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
713 if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
716 } else if (attr == 0) {
717 /* Clear all existing attributes. */
718 attr = FILE_ATTRIBUTE_NORMAL;
730 SMB_ASSERT(PTR_DIFF(p, buf) == 40);
733 NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
734 struct timespec create_time,
735 struct timespec access_time,
736 struct timespec write_time,
737 struct timespec change_time,
742 prep_basic_information_buf(
750 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
751 DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
753 * Split out SMB2 here as we need to select
754 * the correct info type and level.
756 return cli_smb2_setpathinfo(cli,
758 1, /* SMB2_SETINFO_FILE */
759 SMB_FILE_BASIC_INFORMATION - 1000,
763 return cli_setpathinfo(
764 cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
767 struct cli_setfileinfo_ext_state {
772 static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
773 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
775 struct tevent_req *cli_setfileinfo_ext_send(
777 struct tevent_context *ev,
778 struct cli_state *cli,
780 struct timespec create_time,
781 struct timespec access_time,
782 struct timespec write_time,
783 struct timespec change_time,
786 struct tevent_req *req = NULL, *subreq = NULL;
787 struct cli_setfileinfo_ext_state *state = NULL;
789 req = tevent_req_create(
790 mem_ctx, &state, struct cli_setfileinfo_ext_state);
794 prep_basic_information_buf(
802 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
803 state->in_data = (DATA_BLOB) {
804 .data = state->data, .length = sizeof(state->data),
807 subreq = cli_smb2_set_info_fnum_send(
813 SMB_FILE_BASIC_INFORMATION - 1000,
815 0); /* in_additional_info */
816 if (tevent_req_nomem(subreq, req)) {
817 return tevent_req_post(req, ev);
819 tevent_req_set_callback(
820 subreq, cli_setfileinfo_ext_done2, req);
824 subreq = cli_setfileinfo_send(
829 SMB_FILE_BASIC_INFORMATION,
831 sizeof(state->data));
832 if (tevent_req_nomem(subreq, req)) {
833 return tevent_req_post(req, ev);
835 tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
839 static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
841 NTSTATUS status = cli_setfileinfo_recv(subreq);
842 tevent_req_simple_finish_ntstatus(subreq, status);
845 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
847 NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
848 tevent_req_simple_finish_ntstatus(subreq, status);
851 NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
853 return tevent_req_simple_recv_ntstatus(req);
856 NTSTATUS cli_setfileinfo_ext(
857 struct cli_state *cli,
859 struct timespec create_time,
860 struct timespec access_time,
861 struct timespec write_time,
862 struct timespec change_time,
865 TALLOC_CTX *frame = NULL;
866 struct tevent_context *ev = NULL;
867 struct tevent_req *req = NULL;
868 NTSTATUS status = NT_STATUS_NO_MEMORY;
870 if (smbXcli_conn_has_async_calls(cli->conn)) {
872 * Can't use sync call while an async call is in flight
874 return NT_STATUS_INVALID_PARAMETER;
877 frame = talloc_stackframe();
879 ev = samba_tevent_context_init(frame);
883 req = cli_setfileinfo_ext_send(
896 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
899 status = cli_setfileinfo_ext_recv(req);
905 /****************************************************************************
906 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
907 ****************************************************************************/
909 struct cli_qpathinfo2_state {
914 static void cli_qpathinfo2_done(struct tevent_req *subreq);
916 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
917 struct tevent_context *ev,
918 struct cli_state *cli,
921 struct tevent_req *req = NULL, *subreq = NULL;
922 struct cli_qpathinfo2_state *state = NULL;
924 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
928 subreq = cli_qpathinfo_send(state, ev, cli, fname,
929 SMB_QUERY_FILE_ALL_INFO,
930 68, CLI_BUFFER_SIZE);
931 if (tevent_req_nomem(subreq, req)) {
932 return tevent_req_post(req, ev);
934 tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
938 static void cli_qpathinfo2_done(struct tevent_req *subreq)
940 struct tevent_req *req = tevent_req_callback_data(
941 subreq, struct tevent_req);
942 struct cli_qpathinfo2_state *state = tevent_req_data(
943 req, struct cli_qpathinfo2_state);
946 status = cli_qpathinfo_recv(subreq, state, &state->data,
949 if (!NT_STATUS_IS_OK(status)) {
950 tevent_req_nterror(req, status);
953 tevent_req_done(req);
956 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
957 struct timespec *create_time,
958 struct timespec *access_time,
959 struct timespec *write_time,
960 struct timespec *change_time,
961 off_t *size, uint32_t *pattr,
964 struct cli_qpathinfo2_state *state = tevent_req_data(
965 req, struct cli_qpathinfo2_state);
968 if (tevent_req_is_nterror(req, &status)) {
973 *create_time = interpret_long_date((char *)state->data+0);
976 *access_time = interpret_long_date((char *)state->data+8);
979 *write_time = interpret_long_date((char *)state->data+16);
982 *change_time = interpret_long_date((char *)state->data+24);
985 /* SMB_QUERY_FILE_ALL_INFO returns 32-bit attributes. */
986 *pattr = IVAL(state->data, 32);
989 *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
993 * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO
994 * which doesn't return an inode number (fileid).
995 * We can't change this to one of the FILE_ID
996 * info levels as only Win2003 and above support
997 * these [MS-SMB: 2.2.2.3.1] and the SMB1 code
998 * needs to support older servers.
1002 return NT_STATUS_OK;
1005 NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
1006 struct timespec *create_time,
1007 struct timespec *access_time,
1008 struct timespec *write_time,
1009 struct timespec *change_time,
1010 off_t *size, uint32_t *pattr,
1013 TALLOC_CTX *frame = NULL;
1014 struct tevent_context *ev;
1015 struct tevent_req *req;
1016 NTSTATUS status = NT_STATUS_NO_MEMORY;
1018 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1019 return cli_smb2_qpathinfo2(cli,
1030 frame = talloc_stackframe();
1032 if (smbXcli_conn_has_async_calls(cli->conn)) {
1034 * Can't use sync call while an async call is in flight
1036 status = NT_STATUS_INVALID_PARAMETER;
1039 ev = samba_tevent_context_init(frame);
1043 req = cli_qpathinfo2_send(frame, ev, cli, fname);
1047 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1050 status = cli_qpathinfo2_recv(req, create_time, access_time,
1051 write_time, change_time, size, pattr, ino);
1057 /****************************************************************************
1059 ****************************************************************************/
1061 struct cli_qpathinfo_streams_state {
1066 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1068 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1069 struct tevent_context *ev,
1070 struct cli_state *cli,
1073 struct tevent_req *req = NULL, *subreq = NULL;
1074 struct cli_qpathinfo_streams_state *state = NULL;
1076 req = tevent_req_create(mem_ctx, &state,
1077 struct cli_qpathinfo_streams_state);
1081 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1082 SMB_FILE_STREAM_INFORMATION,
1083 0, CLI_BUFFER_SIZE);
1084 if (tevent_req_nomem(subreq, req)) {
1085 return tevent_req_post(req, ev);
1087 tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1091 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1093 struct tevent_req *req = tevent_req_callback_data(
1094 subreq, struct tevent_req);
1095 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1096 req, struct cli_qpathinfo_streams_state);
1099 status = cli_qpathinfo_recv(subreq, state, &state->data,
1101 TALLOC_FREE(subreq);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 tevent_req_nterror(req, status);
1106 tevent_req_done(req);
1109 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1110 TALLOC_CTX *mem_ctx,
1111 unsigned int *pnum_streams,
1112 struct stream_struct **pstreams)
1114 struct cli_qpathinfo_streams_state *state = tevent_req_data(
1115 req, struct cli_qpathinfo_streams_state);
1118 if (tevent_req_is_nterror(req, &status)) {
1121 if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1122 pnum_streams, pstreams)) {
1123 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1125 return NT_STATUS_OK;
1128 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1129 TALLOC_CTX *mem_ctx,
1130 unsigned int *pnum_streams,
1131 struct stream_struct **pstreams)
1133 TALLOC_CTX *frame = NULL;
1134 struct tevent_context *ev;
1135 struct tevent_req *req;
1136 NTSTATUS status = NT_STATUS_NO_MEMORY;
1138 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1139 return cli_smb2_qpathinfo_streams(cli,
1146 frame = talloc_stackframe();
1148 if (smbXcli_conn_has_async_calls(cli->conn)) {
1150 * Can't use sync call while an async call is in flight
1152 status = NT_STATUS_INVALID_PARAMETER;
1155 ev = samba_tevent_context_init(frame);
1159 req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1163 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1166 status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1173 bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1175 unsigned int *pnum_streams,
1176 struct stream_struct **pstreams)
1178 unsigned int num_streams;
1179 struct stream_struct *streams;
1186 while ((data_len > ofs) && (data_len - ofs >= 24)) {
1190 struct stream_struct *tmp;
1193 tmp = talloc_realloc(mem_ctx, streams,
1194 struct stream_struct,
1202 nlen = IVAL(rdata, ofs + 0x04);
1204 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1206 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1209 if (nlen > data_len - (ofs + 24)) {
1214 * We need to null-terminate src, how do I do this with
1215 * convert_string_talloc??
1218 tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1219 if (tmp_buf == NULL) {
1223 memcpy(tmp_buf, rdata+ofs+24, nlen);
1225 tmp_buf[nlen+1] = 0;
1227 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1228 nlen+2, &vstr, &size))
1230 TALLOC_FREE(tmp_buf);
1234 TALLOC_FREE(tmp_buf);
1235 streams[num_streams].name = (char *)vstr;
1238 len = IVAL(rdata, ofs);
1239 if (len > data_len - ofs) {
1242 if (len == 0) break;
1246 *pnum_streams = num_streams;
1247 *pstreams = streams;
1251 TALLOC_FREE(streams);
1255 /****************************************************************************
1256 Send a qfileinfo QUERY_FILE_NAME_INFO call.
1257 ****************************************************************************/
1259 NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum,
1260 TALLOC_CTX *mem_ctx, char **_name)
1262 uint16_t recv_flags2;
1269 status = cli_qfileinfo(talloc_tos(), cli, fnum,
1270 SMB_QUERY_FILE_NAME_INFO,
1271 4, CLI_BUFFER_SIZE, &recv_flags2,
1272 &rdata, &num_rdata);
1273 if (!NT_STATUS_IS_OK(status)) {
1277 namelen = IVAL(rdata, 0);
1278 if (namelen > (num_rdata - 4)) {
1280 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1283 pull_string_talloc(mem_ctx,
1284 (const char *)rdata,
1291 status = map_nt_error_from_unix(errno);
1298 return NT_STATUS_OK;
1301 /****************************************************************************
1302 Send a qfileinfo call.
1303 ****************************************************************************/
1305 NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
1306 uint32_t *pattr, off_t *size,
1307 struct timespec *create_time,
1308 struct timespec *access_time,
1309 struct timespec *write_time,
1310 struct timespec *change_time,
1317 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1318 return cli_smb2_qfileinfo_basic(cli,
1329 /* if its a win95 server then fail this - win95 totally screws it
1332 return NT_STATUS_NOT_SUPPORTED;
1335 status = cli_qfileinfo(talloc_tos(), cli, fnum,
1336 SMB_QUERY_FILE_ALL_INFO,
1337 68, CLI_BUFFER_SIZE,
1339 &rdata, &num_rdata);
1340 if (!NT_STATUS_IS_OK(status)) {
1345 *create_time = interpret_long_date((char *)rdata+0);
1348 *access_time = interpret_long_date((char *)rdata+8);
1351 *write_time = interpret_long_date((char *)rdata+16);
1354 *change_time = interpret_long_date((char *)rdata+24);
1357 *pattr = SVAL(rdata, 32);
1360 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1363 *ino = IVAL(rdata, 64);
1367 return NT_STATUS_OK;
1370 /****************************************************************************
1371 Send a qpathinfo BASIC_INFO call.
1372 ****************************************************************************/
1374 struct cli_qpathinfo_basic_state {
1379 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1381 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1382 struct tevent_context *ev,
1383 struct cli_state *cli,
1386 struct tevent_req *req = NULL, *subreq = NULL;
1387 struct cli_qpathinfo_basic_state *state = NULL;
1389 req = tevent_req_create(mem_ctx, &state,
1390 struct cli_qpathinfo_basic_state);
1394 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1395 SMB_QUERY_FILE_BASIC_INFO,
1396 36, CLI_BUFFER_SIZE);
1397 if (tevent_req_nomem(subreq, req)) {
1398 return tevent_req_post(req, ev);
1400 tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1404 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1406 struct tevent_req *req = tevent_req_callback_data(
1407 subreq, struct tevent_req);
1408 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1409 req, struct cli_qpathinfo_basic_state);
1412 status = cli_qpathinfo_recv(subreq, state, &state->data,
1414 TALLOC_FREE(subreq);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 tevent_req_nterror(req, status);
1419 tevent_req_done(req);
1422 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1423 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1425 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1426 req, struct cli_qpathinfo_basic_state);
1429 if (tevent_req_is_nterror(req, &status)) {
1433 sbuf->st_ex_btime = interpret_long_date((char *)state->data);
1434 sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1435 sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1436 sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1437 *attributes = IVAL(state->data, 32);
1438 return NT_STATUS_OK;
1441 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1442 SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1444 TALLOC_CTX *frame = NULL;
1445 struct tevent_context *ev;
1446 struct tevent_req *req;
1447 NTSTATUS status = NT_STATUS_NO_MEMORY;
1449 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1450 return cli_smb2_qpathinfo_basic(cli,
1456 frame = talloc_stackframe();
1458 if (smbXcli_conn_has_async_calls(cli->conn)) {
1460 * Can't use sync call while an async call is in flight
1462 status = NT_STATUS_INVALID_PARAMETER;
1465 ev = samba_tevent_context_init(frame);
1469 req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1473 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1476 status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1482 /****************************************************************************
1483 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1484 ****************************************************************************/
1486 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1491 char *converted = NULL;
1492 size_t converted_size = 0;
1495 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1496 return cli_smb2_qpathinfo_alt_name(cli,
1501 status = cli_qpathinfo(talloc_tos(), cli, fname,
1502 SMB_QUERY_FILE_ALT_NAME_INFO,
1503 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1504 if (!NT_STATUS_IS_OK(status)) {
1508 len = IVAL(rdata, 0);
1510 if (len > num_rdata - 4) {
1511 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1514 /* The returned data is a pushed string, not raw data. */
1515 if (!convert_string_talloc(talloc_tos(),
1516 smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1522 return NT_STATUS_NO_MEMORY;
1524 fstrcpy(alt_name, converted);
1526 TALLOC_FREE(converted);
1529 return NT_STATUS_OK;
1532 /****************************************************************************
1533 Send a qpathinfo SMB_QUERY_FILE_STADNDARD_INFO call.
1534 ****************************************************************************/
1536 NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1537 uint64_t *allocated, uint64_t *size,
1539 bool *is_del_pending, bool *is_dir)
1545 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1546 return NT_STATUS_NOT_IMPLEMENTED;
1549 status = cli_qpathinfo(talloc_tos(), cli, fname,
1550 SMB_QUERY_FILE_STANDARD_INFO,
1551 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1552 if (!NT_STATUS_IS_OK(status)) {
1557 *allocated = BVAL(rdata, 0);
1561 *size = BVAL(rdata, 8);
1565 *nlinks = IVAL(rdata, 16);
1568 if (is_del_pending) {
1569 *is_del_pending = CVAL(rdata, 20);
1573 *is_dir = CVAL(rdata, 20);
1578 return NT_STATUS_OK;
1582 /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1583 NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1584 struct timespec *create_time,
1585 struct timespec *access_time,
1586 struct timespec *write_time,
1587 struct timespec *change_time,
1588 off_t *size, uint32_t *pattr,
1591 NTSTATUS status = NT_STATUS_OK;
1592 SMB_STRUCT_STAT st = { 0 };
1596 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1598 * NB. cli_qpathinfo2() checks pattr is valid before
1599 * storing a value into it, so we don't need to use
1600 * an intermediate attr variable as below but can
1601 * pass pattr directly.
1603 return cli_qpathinfo2(cli, fname,
1604 create_time, access_time, write_time, change_time,
1608 if (create_time || access_time || write_time || change_time || pattr) {
1610 * cli_qpathinfo_basic() always indirects the passed
1611 * in pointers so we use intermediate variables to
1612 * collect all of them before assigning any requested
1615 status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1616 if (!NT_STATUS_IS_OK(status)) {
1622 status = cli_qpathinfo_standard(cli, fname,
1623 NULL, &pos, NULL, NULL, NULL);
1624 if (!NT_STATUS_IS_OK(status)) {
1632 *create_time = st.st_ex_btime;
1635 *access_time = st.st_ex_atime;
1638 *write_time = st.st_ex_mtime;
1641 *change_time = st.st_ex_ctime;
1650 return NT_STATUS_OK;