s3-tevent: only include ../lib/util/tevent wrappers where needed.
[Samba.git] / source3 / libsmb / clirap.c
blobc6f7fe9c0d98489e3aa6b0bbff68a9a01327e824
1 /*
2 Unix SMB/CIFS implementation.
3 client RAP calls
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/>.
22 #include "includes.h"
23 #include "../libcli/auth/libcli_auth.h"
24 #include "../librpc/gen_ndr/rap.h"
25 #include "../lib/crypto/arcfour.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "async_smb.h"
28 #include "libsmb/clirap.h"
29 #include "trans2.h"
31 #define PIPE_LANMAN "\\PIPE\\LANMAN"
33 /****************************************************************************
34 Call a remote api
35 ****************************************************************************/
37 bool cli_api(struct cli_state *cli,
38 char *param, int prcnt, int mprcnt,
39 char *data, int drcnt, int mdrcnt,
40 char **rparam, unsigned int *rprcnt,
41 char **rdata, unsigned int *rdrcnt)
43 NTSTATUS status;
45 uint8_t *my_rparam, *my_rdata;
46 uint32_t num_my_rparam, num_my_rdata;
48 status = cli_trans(talloc_tos(), cli, SMBtrans,
49 PIPE_LANMAN, 0, /* name, fid */
50 0, 0, /* function, flags */
51 NULL, 0, 0, /* setup */
52 (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
53 (uint8_t *)data, drcnt, mdrcnt, /* Data, length, max */
54 NULL, /* recv_flags2 */
55 NULL, 0, NULL, /* rsetup */
56 &my_rparam, 0, &num_my_rparam,
57 &my_rdata, 0, &num_my_rdata);
58 if (!NT_STATUS_IS_OK(status)) {
59 return false;
63 * I know this memcpy massively hurts, but there are just tons
64 * of callers of cli_api that eventually need changing to
65 * talloc
68 *rparam = (char *)memdup(my_rparam, num_my_rparam);
69 if (*rparam == NULL) {
70 goto fail;
72 *rprcnt = num_my_rparam;
73 TALLOC_FREE(my_rparam);
75 *rdata = (char *)memdup(my_rdata, num_my_rdata);
76 if (*rdata == NULL) {
77 goto fail;
79 *rdrcnt = num_my_rdata;
80 TALLOC_FREE(my_rdata);
82 return true;
83 fail:
84 TALLOC_FREE(my_rdata);
85 TALLOC_FREE(my_rparam);
86 *rparam = NULL;
87 *rprcnt = 0;
88 *rdata = NULL;
89 *rdrcnt = 0;
90 return false;
93 /****************************************************************************
94 Perform a NetWkstaUserLogon.
95 ****************************************************************************/
97 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
99 char *rparam = NULL;
100 char *rdata = NULL;
101 char *p;
102 unsigned int rdrcnt,rprcnt;
103 char param[1024];
105 memset(param, 0, sizeof(param));
107 /* send a SMBtrans command with api NetWkstaUserLogon */
108 p = param;
109 SSVAL(p,0,132); /* api number */
110 p += 2;
111 strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
112 p = skip_string(param,sizeof(param),p);
113 strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
114 p = skip_string(param,sizeof(param),p);
115 SSVAL(p,0,1);
116 p += 2;
117 strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
118 strupper_m(p);
119 p += 21;
120 p++;
121 p += 15;
122 p++;
123 strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
124 strupper_m(p);
125 p += 16;
126 SSVAL(p, 0, CLI_BUFFER_SIZE);
127 p += 2;
128 SSVAL(p, 0, CLI_BUFFER_SIZE);
129 p += 2;
131 if (cli_api(cli,
132 param, PTR_DIFF(p,param),1024, /* param, length, max */
133 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
134 &rparam, &rprcnt, /* return params, return size */
135 &rdata, &rdrcnt /* return data, return size */
136 )) {
137 cli->rap_error = rparam? SVAL(rparam,0) : -1;
138 p = rdata;
140 if (cli->rap_error == 0) {
141 DEBUG(4,("NetWkstaUserLogon success\n"));
142 cli->privileges = SVAL(p, 24);
143 /* The cli->eff_name field used to be set here
144 but it wasn't used anywhere else. */
145 } else {
146 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
150 SAFE_FREE(rparam);
151 SAFE_FREE(rdata);
152 return (cli->rap_error == 0);
155 /****************************************************************************
156 Call a NetShareEnum - try and browse available connections on a host.
157 ****************************************************************************/
159 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
161 char *rparam = NULL;
162 char *rdata = NULL;
163 char *p;
164 unsigned int rdrcnt,rprcnt;
165 char param[1024];
166 int count = -1;
168 /* now send a SMBtrans command with api RNetShareEnum */
169 p = param;
170 SSVAL(p,0,0); /* api number */
171 p += 2;
172 strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
173 p = skip_string(param,sizeof(param),p);
174 strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
175 p = skip_string(param,sizeof(param),p);
176 SSVAL(p,0,1);
178 * Win2k needs a *smaller* buffer than 0xFFFF here -
179 * it returns "out of server memory" with 0xFFFF !!! JRA.
181 SSVAL(p,2,0xFFE0);
182 p += 4;
184 if (cli_api(cli,
185 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
186 NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
187 &rparam, &rprcnt, /* return params, length */
188 &rdata, &rdrcnt)) /* return data, length */
190 int res = rparam? SVAL(rparam,0) : -1;
192 if (res == 0 || res == ERRmoredata) {
193 int converter=SVAL(rparam,2);
194 int i;
195 char *rdata_end = rdata + rdrcnt;
197 count=SVAL(rparam,4);
198 p = rdata;
200 for (i=0;i<count;i++,p+=20) {
201 char *sname;
202 int type;
203 int comment_offset;
204 const char *cmnt;
205 const char *p1;
206 char *s1, *s2;
207 size_t len;
208 TALLOC_CTX *frame = talloc_stackframe();
210 if (p + 20 > rdata_end) {
211 TALLOC_FREE(frame);
212 break;
215 sname = p;
216 type = SVAL(p,14);
217 comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
218 if (comment_offset < 0 ||
219 comment_offset > (int)rdrcnt) {
220 TALLOC_FREE(frame);
221 break;
223 cmnt = comment_offset?(rdata+comment_offset):"";
225 /* Work out the comment length. */
226 for (p1 = cmnt, len = 0; *p1 &&
227 p1 < rdata_end; len++)
228 p1++;
229 if (!*p1) {
230 len++;
232 pull_string_talloc(frame,rdata,0,
233 &s1,sname,14,STR_ASCII);
234 pull_string_talloc(frame,rdata,0,
235 &s2,cmnt,len,STR_ASCII);
236 if (!s1 || !s2) {
237 TALLOC_FREE(frame);
238 continue;
241 fn(s1, type, s2, state);
243 TALLOC_FREE(frame);
245 } else {
246 DEBUG(4,("NetShareEnum res=%d\n", res));
248 } else {
249 DEBUG(4,("NetShareEnum failed\n"));
252 SAFE_FREE(rparam);
253 SAFE_FREE(rdata);
255 return count;
258 /****************************************************************************
259 Call a NetServerEnum for the specified workgroup and servertype mask. This
260 function then calls the specified callback function for each name returned.
262 The callback function takes 4 arguments: the machine name, the server type,
263 the comment and a state pointer.
264 ****************************************************************************/
266 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
267 void (*fn)(const char *, uint32, const char *, void *),
268 void *state)
270 char *rparam = NULL;
271 char *rdata = NULL;
272 char *rdata_end = NULL;
273 unsigned int rdrcnt,rprcnt;
274 char *p;
275 char param[1024];
276 int uLevel = 1;
277 size_t len;
278 uint32 func = RAP_NetServerEnum2;
279 char *last_entry = NULL;
280 int total_cnt = 0;
281 int return_cnt = 0;
282 int res;
284 errno = 0; /* reset */
287 * This may take more than one transaction, so we should loop until
288 * we no longer get a more data to process or we have all of the
289 * items.
291 do {
292 /* send a SMBtrans command with api NetServerEnum */
293 p = param;
294 SIVAL(p,0,func); /* api number */
295 p += 2;
297 if (func == RAP_NetServerEnum3) {
298 strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
299 } else {
300 strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
303 p = skip_string(param, sizeof(param), p);
304 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
306 p = skip_string(param, sizeof(param), p);
307 SSVAL(p,0,uLevel);
308 SSVAL(p,2,CLI_BUFFER_SIZE);
309 p += 4;
310 SIVAL(p,0,stype);
311 p += 4;
313 /* If we have more data, tell the server where
314 * to continue from.
316 len = push_ascii(p,
317 workgroup,
318 sizeof(param) - PTR_DIFF(p,param) - 1,
319 STR_TERMINATE|STR_UPPER);
321 if (len == (size_t)-1) {
322 SAFE_FREE(last_entry);
323 return false;
325 p += len;
327 if (func == RAP_NetServerEnum3) {
328 len = push_ascii(p,
329 last_entry ? last_entry : "",
330 sizeof(param) - PTR_DIFF(p,param) - 1,
331 STR_TERMINATE);
333 if (len == (size_t)-1) {
334 SAFE_FREE(last_entry);
335 return false;
337 p += len;
340 /* Next time through we need to use the continue api */
341 func = RAP_NetServerEnum3;
343 if (!cli_api(cli,
344 param, PTR_DIFF(p,param), 8, /* params, length, max */
345 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
346 &rparam, &rprcnt, /* return params, return size */
347 &rdata, &rdrcnt)) { /* return data, return size */
349 /* break out of the loop on error */
350 res = -1;
351 break;
354 rdata_end = rdata + rdrcnt;
355 res = rparam ? SVAL(rparam,0) : -1;
357 if (res == 0 || res == ERRmoredata ||
358 (res != -1 && cli_errno(cli) == 0)) {
359 char *sname = NULL;
360 int i, count;
361 int converter=SVAL(rparam,2);
363 /* Get the number of items returned in this buffer */
364 count = SVAL(rparam, 4);
366 /* The next field contains the number of items left,
367 * including those returned in this buffer. So the
368 * first time through this should contain all of the
369 * entries.
371 if (total_cnt == 0) {
372 total_cnt = SVAL(rparam, 6);
375 /* Keep track of how many we have read */
376 return_cnt += count;
377 p = rdata;
379 /* The last name in the previous NetServerEnum reply is
380 * sent back to server in the NetServerEnum3 request
381 * (last_entry). The next reply should repeat this entry
382 * as the first element. We have no proof that this is
383 * always true, but from traces that seems to be the
384 * behavior from Window Servers. So first lets do a lot
385 * of checking, just being paranoid. If the string
386 * matches then we already saw this entry so skip it.
388 * NOTE: sv1_name field must be null terminated and has
389 * a max size of 16 (NetBIOS Name).
391 if (last_entry && count && p &&
392 (strncmp(last_entry, p, 16) == 0)) {
393 count -= 1; /* Skip this entry */
394 return_cnt = -1; /* Not part of total, so don't count. */
395 p = rdata + 26; /* Skip the whole record */
398 for (i = 0; i < count; i++, p += 26) {
399 int comment_offset;
400 const char *cmnt;
401 const char *p1;
402 char *s1, *s2;
403 TALLOC_CTX *frame = talloc_stackframe();
404 uint32_t entry_stype;
406 if (p + 26 > rdata_end) {
407 TALLOC_FREE(frame);
408 break;
411 sname = p;
412 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
413 cmnt = comment_offset?(rdata+comment_offset):"";
415 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
416 TALLOC_FREE(frame);
417 continue;
420 /* Work out the comment length. */
421 for (p1 = cmnt, len = 0; *p1 &&
422 p1 < rdata_end; len++)
423 p1++;
424 if (!*p1) {
425 len++;
428 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
430 pull_string_talloc(frame,rdata,0,
431 &s1,sname,16,STR_ASCII);
432 pull_string_talloc(frame,rdata,0,
433 &s2,cmnt,len,STR_ASCII);
435 if (!s1 || !s2) {
436 TALLOC_FREE(frame);
437 continue;
440 fn(s1, entry_stype, s2, state);
441 TALLOC_FREE(frame);
444 /* We are done with the old last entry, so now we can free it */
445 if (last_entry) {
446 SAFE_FREE(last_entry); /* This will set it to null */
449 /* We always make a copy of the last entry if we have one */
450 if (sname) {
451 last_entry = smb_xstrdup(sname);
454 /* If we have more data, but no last entry then error out */
455 if (!last_entry && (res == ERRmoredata)) {
456 errno = EINVAL;
457 res = 0;
462 SAFE_FREE(rparam);
463 SAFE_FREE(rdata);
464 } while ((res == ERRmoredata) && (total_cnt > return_cnt));
466 SAFE_FREE(rparam);
467 SAFE_FREE(rdata);
468 SAFE_FREE(last_entry);
470 if (res == -1) {
471 errno = cli_errno(cli);
472 } else {
473 if (!return_cnt) {
474 /* this is a very special case, when the domain master for the
475 work group isn't part of the work group itself, there is something
476 wild going on */
477 errno = ENOENT;
481 return(return_cnt > 0);
484 /****************************************************************************
485 Send a SamOEMChangePassword command.
486 ****************************************************************************/
488 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
489 const char *old_password)
491 char param[1024];
492 unsigned char data[532];
493 char *p = param;
494 unsigned char old_pw_hash[16];
495 unsigned char new_pw_hash[16];
496 unsigned int data_len;
497 unsigned int param_len = 0;
498 char *rparam = NULL;
499 char *rdata = NULL;
500 unsigned int rprcnt, rdrcnt;
502 if (strlen(user) >= sizeof(fstring)-1) {
503 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
504 return False;
507 SSVAL(p,0,214); /* SamOEMChangePassword command. */
508 p += 2;
509 strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
510 p = skip_string(param,sizeof(param),p);
511 strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
512 p = skip_string(param,sizeof(param),p);
513 strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
514 p = skip_string(param,sizeof(param),p);
515 SSVAL(p,0,532);
516 p += 2;
518 param_len = PTR_DIFF(p,param);
521 * Get the Lanman hash of the old password, we
522 * use this as the key to make_oem_passwd_hash().
524 E_deshash(old_password, old_pw_hash);
526 encode_pw_buffer(data, new_password, STR_ASCII);
528 #ifdef DEBUG_PASSWORD
529 DEBUG(100,("make_oem_passwd_hash\n"));
530 dump_data(100, data, 516);
531 #endif
532 arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
535 * Now place the old password hash in the data.
537 E_deshash(new_password, new_pw_hash);
539 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
541 data_len = 532;
543 if (!cli_api(cli,
544 param, param_len, 4, /* param, length, max */
545 (char *)data, data_len, 0, /* data, length, max */
546 &rparam, &rprcnt,
547 &rdata, &rdrcnt)) {
548 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
549 user ));
550 return False;
553 if (rparam) {
554 cli->rap_error = SVAL(rparam,0);
557 SAFE_FREE(rparam);
558 SAFE_FREE(rdata);
560 return (cli->rap_error == 0);
563 /****************************************************************************
564 Send a qpathinfo call.
565 ****************************************************************************/
567 struct cli_qpathinfo1_state {
568 struct cli_state *cli;
569 uint32_t num_data;
570 uint8_t *data;
573 static void cli_qpathinfo1_done(struct tevent_req *subreq);
575 struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
576 struct event_context *ev,
577 struct cli_state *cli,
578 const char *fname)
580 struct tevent_req *req = NULL, *subreq = NULL;
581 struct cli_qpathinfo1_state *state = NULL;
583 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
584 if (req == NULL) {
585 return NULL;
587 state->cli = cli;
588 subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
589 22, cli->max_xmit);
590 if (tevent_req_nomem(subreq, req)) {
591 return tevent_req_post(req, ev);
593 tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
594 return req;
597 static void cli_qpathinfo1_done(struct tevent_req *subreq)
599 struct tevent_req *req = tevent_req_callback_data(
600 subreq, struct tevent_req);
601 struct cli_qpathinfo1_state *state = tevent_req_data(
602 req, struct cli_qpathinfo1_state);
603 NTSTATUS status;
605 status = cli_qpathinfo_recv(subreq, state, &state->data,
606 &state->num_data);
607 TALLOC_FREE(subreq);
608 if (!NT_STATUS_IS_OK(status)) {
609 tevent_req_nterror(req, status);
610 return;
612 tevent_req_done(req);
615 NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
616 time_t *change_time,
617 time_t *access_time,
618 time_t *write_time,
619 SMB_OFF_T *size,
620 uint16 *mode)
622 struct cli_qpathinfo1_state *state = tevent_req_data(
623 req, struct cli_qpathinfo1_state);
624 NTSTATUS status;
626 time_t (*date_fn)(const void *buf, int serverzone);
628 if (tevent_req_is_nterror(req, &status)) {
629 return status;
632 if (state->cli->win95) {
633 date_fn = make_unix_date;
634 } else {
635 date_fn = make_unix_date2;
638 if (change_time) {
639 *change_time = date_fn(state->data+0, state->cli->serverzone);
641 if (access_time) {
642 *access_time = date_fn(state->data+4, state->cli->serverzone);
644 if (write_time) {
645 *write_time = date_fn(state->data+8, state->cli->serverzone);
647 if (size) {
648 *size = IVAL(state->data, 12);
650 if (mode) {
651 *mode = SVAL(state->data, l1_attrFile);
653 return NT_STATUS_OK;
656 NTSTATUS cli_qpathinfo1(struct cli_state *cli,
657 const char *fname,
658 time_t *change_time,
659 time_t *access_time,
660 time_t *write_time,
661 SMB_OFF_T *size,
662 uint16 *mode)
664 TALLOC_CTX *frame = talloc_stackframe();
665 struct event_context *ev;
666 struct tevent_req *req;
667 NTSTATUS status = NT_STATUS_NO_MEMORY;
669 if (cli_has_async_calls(cli)) {
671 * Can't use sync call while an async call is in flight
673 status = NT_STATUS_INVALID_PARAMETER;
674 goto fail;
676 ev = event_context_init(frame);
677 if (ev == NULL) {
678 goto fail;
680 req = cli_qpathinfo1_send(frame, ev, cli, fname);
681 if (req == NULL) {
682 goto fail;
684 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
685 goto fail;
687 status = cli_qpathinfo1_recv(req, change_time, access_time,
688 write_time, size, mode);
689 fail:
690 TALLOC_FREE(frame);
691 if (!NT_STATUS_IS_OK(status)) {
692 cli_set_error(cli, status);
694 return status;
697 /****************************************************************************
698 Send a setpathinfo call.
699 ****************************************************************************/
701 NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
702 time_t create_time,
703 time_t access_time,
704 time_t write_time,
705 time_t change_time,
706 uint16 mode)
708 unsigned int data_len = 0;
709 char data[40];
710 char *p;
712 p = data;
715 * Add the create, last access, modification, and status change times
717 put_long_date(p, create_time);
718 p += 8;
720 put_long_date(p, access_time);
721 p += 8;
723 put_long_date(p, write_time);
724 p += 8;
726 put_long_date(p, change_time);
727 p += 8;
729 /* Add attributes */
730 SIVAL(p, 0, mode);
731 p += 4;
733 /* Add padding */
734 SIVAL(p, 0, 0);
735 p += 4;
737 data_len = PTR_DIFF(p, data);
739 return cli_setpathinfo(cli, SMB_FILE_BASIC_INFORMATION, fname,
740 (uint8_t *)data, data_len);
743 /****************************************************************************
744 Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
745 ****************************************************************************/
747 struct cli_qpathinfo2_state {
748 uint32_t num_data;
749 uint8_t *data;
752 static void cli_qpathinfo2_done(struct tevent_req *subreq);
754 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
755 struct event_context *ev,
756 struct cli_state *cli,
757 const char *fname)
759 struct tevent_req *req = NULL, *subreq = NULL;
760 struct cli_qpathinfo2_state *state = NULL;
762 req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
763 if (req == NULL) {
764 return NULL;
766 subreq = cli_qpathinfo_send(state, ev, cli, fname,
767 SMB_QUERY_FILE_ALL_INFO,
768 68, cli->max_xmit);
769 if (tevent_req_nomem(subreq, req)) {
770 return tevent_req_post(req, ev);
772 tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
773 return req;
776 static void cli_qpathinfo2_done(struct tevent_req *subreq)
778 struct tevent_req *req = tevent_req_callback_data(
779 subreq, struct tevent_req);
780 struct cli_qpathinfo2_state *state = tevent_req_data(
781 req, struct cli_qpathinfo2_state);
782 NTSTATUS status;
784 status = cli_qpathinfo_recv(subreq, state, &state->data,
785 &state->num_data);
786 TALLOC_FREE(subreq);
787 if (!NT_STATUS_IS_OK(status)) {
788 tevent_req_nterror(req, status);
789 return;
791 tevent_req_done(req);
794 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
795 struct timespec *create_time,
796 struct timespec *access_time,
797 struct timespec *write_time,
798 struct timespec *change_time,
799 SMB_OFF_T *size, uint16 *mode,
800 SMB_INO_T *ino)
802 struct cli_qpathinfo2_state *state = tevent_req_data(
803 req, struct cli_qpathinfo2_state);
804 NTSTATUS status;
806 if (tevent_req_is_nterror(req, &status)) {
807 return status;
810 if (create_time) {
811 *create_time = interpret_long_date((char *)state->data+0);
813 if (access_time) {
814 *access_time = interpret_long_date((char *)state->data+8);
816 if (write_time) {
817 *write_time = interpret_long_date((char *)state->data+16);
819 if (change_time) {
820 *change_time = interpret_long_date((char *)state->data+24);
822 if (mode) {
823 *mode = SVAL(state->data, 32);
825 if (size) {
826 *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
828 if (ino) {
829 *ino = IVAL(state->data, 64);
831 return NT_STATUS_OK;
834 NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
835 struct timespec *create_time,
836 struct timespec *access_time,
837 struct timespec *write_time,
838 struct timespec *change_time,
839 SMB_OFF_T *size, uint16 *mode,
840 SMB_INO_T *ino)
842 TALLOC_CTX *frame = talloc_stackframe();
843 struct event_context *ev;
844 struct tevent_req *req;
845 NTSTATUS status = NT_STATUS_NO_MEMORY;
847 if (cli_has_async_calls(cli)) {
849 * Can't use sync call while an async call is in flight
851 status = NT_STATUS_INVALID_PARAMETER;
852 goto fail;
854 ev = event_context_init(frame);
855 if (ev == NULL) {
856 goto fail;
858 req = cli_qpathinfo2_send(frame, ev, cli, fname);
859 if (req == NULL) {
860 goto fail;
862 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
863 goto fail;
865 status = cli_qpathinfo2_recv(req, create_time, access_time,
866 write_time, change_time, size, mode, ino);
867 fail:
868 TALLOC_FREE(frame);
869 if (!NT_STATUS_IS_OK(status)) {
870 cli_set_error(cli, status);
872 return status;
875 /****************************************************************************
876 Get the stream info
877 ****************************************************************************/
879 static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *data,
880 size_t data_len,
881 unsigned int *pnum_streams,
882 struct stream_struct **pstreams);
884 struct cli_qpathinfo_streams_state {
885 uint32_t num_data;
886 uint8_t *data;
889 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
891 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
892 struct tevent_context *ev,
893 struct cli_state *cli,
894 const char *fname)
896 struct tevent_req *req = NULL, *subreq = NULL;
897 struct cli_qpathinfo_streams_state *state = NULL;
899 req = tevent_req_create(mem_ctx, &state,
900 struct cli_qpathinfo_streams_state);
901 if (req == NULL) {
902 return NULL;
904 subreq = cli_qpathinfo_send(state, ev, cli, fname,
905 SMB_FILE_STREAM_INFORMATION,
906 0, cli->max_xmit);
907 if (tevent_req_nomem(subreq, req)) {
908 return tevent_req_post(req, ev);
910 tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
911 return req;
914 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
916 struct tevent_req *req = tevent_req_callback_data(
917 subreq, struct tevent_req);
918 struct cli_qpathinfo_streams_state *state = tevent_req_data(
919 req, struct cli_qpathinfo_streams_state);
920 NTSTATUS status;
922 status = cli_qpathinfo_recv(subreq, state, &state->data,
923 &state->num_data);
924 TALLOC_FREE(subreq);
925 if (!NT_STATUS_IS_OK(status)) {
926 tevent_req_nterror(req, status);
927 return;
929 tevent_req_done(req);
932 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
933 TALLOC_CTX *mem_ctx,
934 unsigned int *pnum_streams,
935 struct stream_struct **pstreams)
937 struct cli_qpathinfo_streams_state *state = tevent_req_data(
938 req, struct cli_qpathinfo_streams_state);
939 NTSTATUS status;
941 if (tevent_req_is_nterror(req, &status)) {
942 return status;
944 if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
945 pnum_streams, pstreams)) {
946 return NT_STATUS_INVALID_NETWORK_RESPONSE;
948 return NT_STATUS_OK;
951 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
952 TALLOC_CTX *mem_ctx,
953 unsigned int *pnum_streams,
954 struct stream_struct **pstreams)
956 TALLOC_CTX *frame = talloc_stackframe();
957 struct event_context *ev;
958 struct tevent_req *req;
959 NTSTATUS status = NT_STATUS_NO_MEMORY;
961 if (cli_has_async_calls(cli)) {
963 * Can't use sync call while an async call is in flight
965 status = NT_STATUS_INVALID_PARAMETER;
966 goto fail;
968 ev = event_context_init(frame);
969 if (ev == NULL) {
970 goto fail;
972 req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
973 if (req == NULL) {
974 goto fail;
976 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
977 goto fail;
979 status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
980 pstreams);
981 fail:
982 TALLOC_FREE(frame);
983 if (!NT_STATUS_IS_OK(status)) {
984 cli_set_error(cli, status);
986 return status;
989 static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
990 size_t data_len,
991 unsigned int *pnum_streams,
992 struct stream_struct **pstreams)
994 unsigned int num_streams;
995 struct stream_struct *streams;
996 unsigned int ofs;
998 num_streams = 0;
999 streams = NULL;
1000 ofs = 0;
1002 while ((data_len > ofs) && (data_len - ofs >= 24)) {
1003 uint32_t nlen, len;
1004 size_t size;
1005 void *vstr;
1006 struct stream_struct *tmp;
1007 uint8_t *tmp_buf;
1009 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
1010 struct stream_struct,
1011 num_streams+1);
1013 if (tmp == NULL) {
1014 goto fail;
1016 streams = tmp;
1018 nlen = IVAL(rdata, ofs + 0x04);
1020 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1021 rdata, ofs + 0x08);
1022 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1023 rdata, ofs + 0x10);
1025 if (nlen > data_len - (ofs + 24)) {
1026 goto fail;
1030 * We need to null-terminate src, how do I do this with
1031 * convert_string_talloc??
1034 tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
1035 if (tmp_buf == NULL) {
1036 goto fail;
1039 memcpy(tmp_buf, rdata+ofs+24, nlen);
1040 tmp_buf[nlen] = 0;
1041 tmp_buf[nlen+1] = 0;
1043 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1044 nlen+2, &vstr, &size, false))
1046 TALLOC_FREE(tmp_buf);
1047 goto fail;
1050 TALLOC_FREE(tmp_buf);
1051 streams[num_streams].name = (char *)vstr;
1052 num_streams++;
1054 len = IVAL(rdata, ofs);
1055 if (len > data_len - ofs) {
1056 goto fail;
1058 if (len == 0) break;
1059 ofs += len;
1062 *pnum_streams = num_streams;
1063 *pstreams = streams;
1064 return true;
1066 fail:
1067 TALLOC_FREE(streams);
1068 return false;
1071 /****************************************************************************
1072 Send a qfileinfo QUERY_FILE_NAME_INFO call.
1073 ****************************************************************************/
1075 NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, char *name,
1076 size_t namelen)
1078 uint8_t *rdata;
1079 uint32_t num_rdata;
1080 NTSTATUS status;
1082 status = cli_qfileinfo(talloc_tos(), cli, fnum,
1083 SMB_QUERY_FILE_NAME_INFO,
1084 4, cli->max_xmit,
1085 &rdata, &num_rdata);
1086 if (!NT_STATUS_IS_OK(status)) {
1087 return status;
1090 clistr_pull(cli->inbuf, name, rdata+4, namelen, IVAL(rdata, 0),
1091 STR_UNICODE);
1092 TALLOC_FREE(rdata);
1093 return NT_STATUS_OK;
1096 /****************************************************************************
1097 Send a qfileinfo call.
1098 ****************************************************************************/
1100 NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
1101 uint16 *mode, SMB_OFF_T *size,
1102 struct timespec *create_time,
1103 struct timespec *access_time,
1104 struct timespec *write_time,
1105 struct timespec *change_time,
1106 SMB_INO_T *ino)
1108 uint8_t *rdata;
1109 uint32_t num_rdata;
1110 NTSTATUS status;
1112 /* if its a win95 server then fail this - win95 totally screws it
1113 up */
1114 if (cli->win95) {
1115 return NT_STATUS_NOT_SUPPORTED;
1118 status = cli_qfileinfo(talloc_tos(), cli, fnum,
1119 SMB_QUERY_FILE_ALL_INFO,
1120 68, MIN(cli->max_xmit, 0xffff),
1121 &rdata, &num_rdata);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 return status;
1126 if (create_time) {
1127 *create_time = interpret_long_date((char *)rdata+0);
1129 if (access_time) {
1130 *access_time = interpret_long_date((char *)rdata+8);
1132 if (write_time) {
1133 *write_time = interpret_long_date((char *)rdata+16);
1135 if (change_time) {
1136 *change_time = interpret_long_date((char *)rdata+24);
1138 if (mode) {
1139 *mode = SVAL(rdata, 32);
1141 if (size) {
1142 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1144 if (ino) {
1145 *ino = IVAL(rdata, 64);
1148 TALLOC_FREE(rdata);
1149 return NT_STATUS_OK;
1152 /****************************************************************************
1153 Send a qpathinfo BASIC_INFO call.
1154 ****************************************************************************/
1156 struct cli_qpathinfo_basic_state {
1157 uint32_t num_data;
1158 uint8_t *data;
1161 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1163 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1164 struct event_context *ev,
1165 struct cli_state *cli,
1166 const char *fname)
1168 struct tevent_req *req = NULL, *subreq = NULL;
1169 struct cli_qpathinfo_basic_state *state = NULL;
1171 req = tevent_req_create(mem_ctx, &state,
1172 struct cli_qpathinfo_basic_state);
1173 if (req == NULL) {
1174 return NULL;
1176 subreq = cli_qpathinfo_send(state, ev, cli, fname,
1177 SMB_QUERY_FILE_BASIC_INFO,
1178 36, cli->max_xmit);
1179 if (tevent_req_nomem(subreq, req)) {
1180 return tevent_req_post(req, ev);
1182 tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1183 return req;
1186 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1188 struct tevent_req *req = tevent_req_callback_data(
1189 subreq, struct tevent_req);
1190 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1191 req, struct cli_qpathinfo_basic_state);
1192 NTSTATUS status;
1194 status = cli_qpathinfo_recv(subreq, state, &state->data,
1195 &state->num_data);
1196 TALLOC_FREE(subreq);
1197 if (!NT_STATUS_IS_OK(status)) {
1198 tevent_req_nterror(req, status);
1199 return;
1201 tevent_req_done(req);
1204 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1205 SMB_STRUCT_STAT *sbuf, uint32 *attributes)
1207 struct cli_qpathinfo_basic_state *state = tevent_req_data(
1208 req, struct cli_qpathinfo_basic_state);
1209 NTSTATUS status;
1211 if (tevent_req_is_nterror(req, &status)) {
1212 return status;
1215 sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1216 sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1217 sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1218 *attributes = IVAL(state->data, 32);
1219 return NT_STATUS_OK;
1222 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1223 SMB_STRUCT_STAT *sbuf, uint32 *attributes)
1225 TALLOC_CTX *frame = talloc_stackframe();
1226 struct event_context *ev;
1227 struct tevent_req *req;
1228 NTSTATUS status = NT_STATUS_NO_MEMORY;
1230 if (cli_has_async_calls(cli)) {
1232 * Can't use sync call while an async call is in flight
1234 status = NT_STATUS_INVALID_PARAMETER;
1235 goto fail;
1237 ev = event_context_init(frame);
1238 if (ev == NULL) {
1239 goto fail;
1241 req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1242 if (req == NULL) {
1243 goto fail;
1245 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1246 goto fail;
1248 status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1249 fail:
1250 TALLOC_FREE(frame);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 cli_set_error(cli, status);
1254 return status;
1257 /****************************************************************************
1258 Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1259 ****************************************************************************/
1261 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1263 uint8_t *rdata;
1264 uint32_t num_rdata;
1265 unsigned int len;
1266 char *converted = NULL;
1267 size_t converted_size = 0;
1268 NTSTATUS status;
1270 status = cli_qpathinfo(talloc_tos(), cli, fname,
1271 SMB_QUERY_FILE_ALT_NAME_INFO,
1272 4, cli->max_xmit, &rdata, &num_rdata);
1273 if (!NT_STATUS_IS_OK(status)) {
1274 return status;
1277 len = IVAL(rdata, 0);
1279 if (len > num_rdata - 4) {
1280 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1283 /* The returned data is a pushed string, not raw data. */
1284 if (!convert_string_talloc(talloc_tos(),
1285 cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
1286 CH_UNIX,
1287 rdata + 4,
1288 len,
1289 &converted,
1290 &converted_size,
1291 true)) {
1292 return NT_STATUS_NO_MEMORY;
1294 fstrcpy(alt_name, converted);
1296 TALLOC_FREE(converted);
1297 TALLOC_FREE(rdata);
1299 return NT_STATUS_OK;