Line data Source code
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
7 :
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.
12 :
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.
17 :
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/>.
20 : */
21 :
22 : #include "includes.h"
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"
29 : #include "trans2.h"
30 : #include "../libcli/smb/smbXcli_base.h"
31 : #include "cli_smb2_fnum.h"
32 : #include "lib/util/string_wrappers.h"
33 :
34 : #include <gnutls/gnutls.h>
35 : #include <gnutls/crypto.h>
36 :
37 : #define PIPE_LANMAN "\\PIPE\\LANMAN"
38 :
39 : /****************************************************************************
40 : Call a remote api
41 : ****************************************************************************/
42 :
43 6 : bool cli_api(struct cli_state *cli,
44 : char *param, int prcnt, int mprcnt,
45 : char *data, int drcnt, int mdrcnt,
46 : char **rparam, unsigned int *rprcnt,
47 : char **rdata, unsigned int *rdrcnt)
48 : {
49 : NTSTATUS status;
50 :
51 : uint8_t *my_rparam, *my_rdata;
52 : uint32_t num_my_rparam, num_my_rdata;
53 :
54 6 : status = cli_trans(talloc_tos(), cli, SMBtrans,
55 : PIPE_LANMAN, 0, /* name, fid */
56 : 0, 0, /* function, flags */
57 : NULL, 0, 0, /* setup */
58 : (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
59 : (uint8_t *)data, drcnt, mdrcnt, /* Data, length, max */
60 : NULL, /* recv_flags2 */
61 : NULL, 0, NULL, /* rsetup */
62 : &my_rparam, 0, &num_my_rparam,
63 : &my_rdata, 0, &num_my_rdata);
64 6 : if (!NT_STATUS_IS_OK(status)) {
65 2 : return false;
66 : }
67 :
68 : /*
69 : * I know this memcpy massively hurts, but there are just tons
70 : * of callers of cli_api that eventually need changing to
71 : * talloc
72 : */
73 :
74 4 : *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
75 4 : if (*rparam == NULL) {
76 0 : goto fail;
77 : }
78 4 : *rprcnt = num_my_rparam;
79 4 : TALLOC_FREE(my_rparam);
80 :
81 4 : *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
82 4 : if (*rdata == NULL) {
83 0 : goto fail;
84 : }
85 4 : *rdrcnt = num_my_rdata;
86 4 : TALLOC_FREE(my_rdata);
87 :
88 4 : return true;
89 0 : fail:
90 0 : TALLOC_FREE(my_rdata);
91 0 : TALLOC_FREE(my_rparam);
92 0 : *rparam = NULL;
93 0 : *rprcnt = 0;
94 0 : *rdata = NULL;
95 0 : *rdrcnt = 0;
96 0 : return false;
97 : }
98 :
99 : /****************************************************************************
100 : Call a NetShareEnum - try and browse available connections on a host.
101 : ****************************************************************************/
102 :
103 0 : int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
104 : {
105 0 : char *rparam = NULL;
106 0 : char *rdata = NULL;
107 : char *p;
108 : unsigned int rdrcnt,rprcnt;
109 : char param[1024];
110 0 : int count = -1;
111 : bool ok;
112 : int res;
113 :
114 : /* now send a SMBtrans command with api RNetShareEnum */
115 0 : p = param;
116 0 : SSVAL(p,0,0); /* api number */
117 0 : p += 2;
118 0 : strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
119 0 : p = skip_string(param,sizeof(param),p);
120 0 : strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
121 0 : p = skip_string(param,sizeof(param),p);
122 0 : SSVAL(p,0,1);
123 : /*
124 : * Win2k needs a *smaller* buffer than 0xFFFF here -
125 : * it returns "out of server memory" with 0xFFFF !!! JRA.
126 : */
127 0 : SSVAL(p,2,0xFFE0);
128 0 : p += 4;
129 :
130 0 : ok = cli_api(
131 : cli,
132 0 : param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
133 : NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
134 : &rparam, &rprcnt, /* return params, length */
135 : &rdata, &rdrcnt); /* return data, length */
136 0 : if (!ok) {
137 0 : DEBUG(4,("NetShareEnum failed\n"));
138 0 : goto done;
139 : }
140 :
141 0 : if (rprcnt < 6) {
142 0 : DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
143 0 : goto done;
144 : }
145 :
146 0 : res = rparam? SVAL(rparam,0) : -1;
147 :
148 0 : if (res == 0 || res == ERRmoredata) {
149 0 : int converter=SVAL(rparam,2);
150 : int i;
151 0 : char *rdata_end = rdata + rdrcnt;
152 :
153 0 : count=SVAL(rparam,4);
154 0 : p = rdata;
155 :
156 0 : for (i=0;i<count;i++,p+=20) {
157 : char *sname;
158 : int type;
159 : int comment_offset;
160 : const char *cmnt;
161 : const char *p1;
162 : char *s1, *s2;
163 : size_t len;
164 0 : TALLOC_CTX *frame = talloc_stackframe();
165 :
166 0 : if (p + 20 > rdata_end) {
167 0 : TALLOC_FREE(frame);
168 0 : break;
169 : }
170 :
171 0 : sname = p;
172 0 : type = SVAL(p,14);
173 0 : comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
174 0 : if (comment_offset < 0 ||
175 0 : comment_offset > (int)rdrcnt) {
176 0 : TALLOC_FREE(frame);
177 0 : break;
178 : }
179 0 : cmnt = comment_offset?(rdata+comment_offset):"";
180 :
181 : /* Work out the comment length. */
182 0 : for (p1 = cmnt, len = 0; *p1 &&
183 0 : p1 < rdata_end; len++)
184 0 : p1++;
185 0 : if (!*p1) {
186 0 : len++;
187 : }
188 0 : pull_string_talloc(frame,rdata,0,
189 : &s1,sname,14,STR_ASCII);
190 0 : pull_string_talloc(frame,rdata,0,
191 : &s2,cmnt,len,STR_ASCII);
192 0 : if (!s1 || !s2) {
193 0 : TALLOC_FREE(frame);
194 0 : continue;
195 : }
196 :
197 0 : fn(s1, type, s2, state);
198 :
199 0 : TALLOC_FREE(frame);
200 : }
201 : } else {
202 0 : DEBUG(4,("NetShareEnum res=%d\n", res));
203 : }
204 :
205 0 : done:
206 0 : SAFE_FREE(rparam);
207 0 : SAFE_FREE(rdata);
208 :
209 0 : return count;
210 : }
211 :
212 : /****************************************************************************
213 : Call a NetServerEnum for the specified workgroup and servertype mask. This
214 : function then calls the specified callback function for each name returned.
215 :
216 : The callback function takes 4 arguments: the machine name, the server type,
217 : the comment and a state pointer.
218 : ****************************************************************************/
219 :
220 6 : bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
221 : void (*fn)(const char *, uint32_t, const char *, void *),
222 : void *state)
223 : {
224 6 : char *rparam = NULL;
225 6 : char *rdata = NULL;
226 6 : char *rdata_end = NULL;
227 : unsigned int rdrcnt,rprcnt;
228 : char *p;
229 : char param[1024];
230 6 : int uLevel = 1;
231 : size_t len;
232 6 : uint32_t func = RAP_NetServerEnum2;
233 6 : char *last_entry = NULL;
234 6 : int total_cnt = 0;
235 6 : int return_cnt = 0;
236 : int res;
237 :
238 6 : errno = 0; /* reset */
239 :
240 : /*
241 : * This may take more than one transaction, so we should loop until
242 : * we no longer get a more data to process or we have all of the
243 : * items.
244 : */
245 : do {
246 : /* send a SMBtrans command with api NetServerEnum */
247 6 : p = param;
248 6 : SIVAL(p,0,func); /* api number */
249 6 : p += 2;
250 :
251 6 : if (func == RAP_NetServerEnum3) {
252 0 : strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
253 : } else {
254 6 : strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
255 : }
256 :
257 6 : p = skip_string(param, sizeof(param), p);
258 6 : strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
259 :
260 6 : p = skip_string(param, sizeof(param), p);
261 6 : SSVAL(p,0,uLevel);
262 6 : SSVAL(p,2,CLI_BUFFER_SIZE);
263 6 : p += 4;
264 6 : SIVAL(p,0,stype);
265 6 : p += 4;
266 :
267 : /* If we have more data, tell the server where
268 : * to continue from.
269 : */
270 6 : len = push_ascii(p,
271 : workgroup,
272 6 : sizeof(param) - PTR_DIFF(p,param) - 1,
273 : STR_TERMINATE|STR_UPPER);
274 :
275 6 : if (len == 0) {
276 0 : SAFE_FREE(last_entry);
277 0 : return false;
278 : }
279 6 : p += len;
280 :
281 6 : if (func == RAP_NetServerEnum3) {
282 0 : len = push_ascii(p,
283 : last_entry ? last_entry : "",
284 0 : sizeof(param) - PTR_DIFF(p,param) - 1,
285 : STR_TERMINATE);
286 :
287 0 : if (len == 0) {
288 0 : SAFE_FREE(last_entry);
289 0 : return false;
290 : }
291 0 : p += len;
292 : }
293 :
294 : /* Next time through we need to use the continue api */
295 6 : func = RAP_NetServerEnum3;
296 :
297 6 : if (!cli_api(cli,
298 6 : param, PTR_DIFF(p,param), 8, /* params, length, max */
299 : NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
300 : &rparam, &rprcnt, /* return params, return size */
301 : &rdata, &rdrcnt)) { /* return data, return size */
302 :
303 : /* break out of the loop on error */
304 2 : res = -1;
305 2 : break;
306 : }
307 :
308 4 : rdata_end = rdata + rdrcnt;
309 :
310 4 : if (rprcnt < 6) {
311 0 : DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
312 0 : res = -1;
313 0 : break;
314 : }
315 :
316 4 : res = rparam ? SVAL(rparam,0) : -1;
317 :
318 4 : if (res == 0 || res == ERRmoredata ||
319 0 : (res != -1 && cli_errno(cli) == 0)) {
320 4 : char *sname = NULL;
321 : int i, count;
322 4 : int converter=SVAL(rparam,2);
323 :
324 : /* Get the number of items returned in this buffer */
325 4 : count = SVAL(rparam, 4);
326 :
327 : /* The next field contains the number of items left,
328 : * including those returned in this buffer. So the
329 : * first time through this should contain all of the
330 : * entries.
331 : */
332 4 : if (total_cnt == 0) {
333 4 : total_cnt = SVAL(rparam, 6);
334 : }
335 :
336 : /* Keep track of how many we have read */
337 4 : return_cnt += count;
338 4 : p = rdata;
339 :
340 : /* The last name in the previous NetServerEnum reply is
341 : * sent back to server in the NetServerEnum3 request
342 : * (last_entry). The next reply should repeat this entry
343 : * as the first element. We have no proof that this is
344 : * always true, but from traces that seems to be the
345 : * behavior from Window Servers. So first lets do a lot
346 : * of checking, just being paranoid. If the string
347 : * matches then we already saw this entry so skip it.
348 : *
349 : * NOTE: sv1_name field must be null terminated and has
350 : * a max size of 16 (NetBIOS Name).
351 : */
352 4 : if (last_entry && count && p &&
353 0 : (strncmp(last_entry, p, 16) == 0)) {
354 0 : count -= 1; /* Skip this entry */
355 0 : return_cnt = -1; /* Not part of total, so don't count. */
356 0 : p = rdata + 26; /* Skip the whole record */
357 : }
358 :
359 8 : for (i = 0; i < count; i++, p += 26) {
360 : int comment_offset;
361 : const char *cmnt;
362 : const char *p1;
363 : char *s1, *s2;
364 4 : TALLOC_CTX *frame = talloc_stackframe();
365 : uint32_t entry_stype;
366 :
367 4 : if (p + 26 > rdata_end) {
368 0 : TALLOC_FREE(frame);
369 0 : break;
370 : }
371 :
372 4 : sname = p;
373 4 : comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
374 4 : cmnt = comment_offset?(rdata+comment_offset):"";
375 :
376 4 : if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
377 0 : TALLOC_FREE(frame);
378 0 : continue;
379 : }
380 :
381 : /* Work out the comment length. */
382 70 : for (p1 = cmnt, len = 0; *p1 &&
383 64 : p1 < rdata_end; len++)
384 64 : p1++;
385 4 : if (!*p1) {
386 4 : len++;
387 : }
388 :
389 4 : entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
390 :
391 4 : pull_string_talloc(frame,rdata,0,
392 : &s1,sname,16,STR_ASCII);
393 4 : pull_string_talloc(frame,rdata,0,
394 : &s2,cmnt,len,STR_ASCII);
395 :
396 4 : if (!s1 || !s2) {
397 0 : TALLOC_FREE(frame);
398 0 : continue;
399 : }
400 :
401 4 : fn(s1, entry_stype, s2, state);
402 4 : TALLOC_FREE(frame);
403 : }
404 :
405 : /* We are done with the old last entry, so now we can free it */
406 4 : if (last_entry) {
407 0 : SAFE_FREE(last_entry); /* This will set it to null */
408 : }
409 :
410 : /* We always make a copy of the last entry if we have one */
411 4 : if (sname) {
412 4 : last_entry = smb_xstrdup(sname);
413 : }
414 :
415 : /* If we have more data, but no last entry then error out */
416 4 : if (!last_entry && (res == ERRmoredata)) {
417 0 : errno = EINVAL;
418 0 : res = 0;
419 : }
420 :
421 : }
422 :
423 4 : SAFE_FREE(rparam);
424 4 : SAFE_FREE(rdata);
425 4 : } while ((res == ERRmoredata) && (total_cnt > return_cnt));
426 :
427 6 : SAFE_FREE(rparam);
428 6 : SAFE_FREE(rdata);
429 6 : SAFE_FREE(last_entry);
430 :
431 6 : if (res == -1) {
432 2 : errno = cli_errno(cli);
433 : } else {
434 4 : if (!return_cnt) {
435 : /* this is a very special case, when the domain master for the
436 : work group isn't part of the work group itself, there is something
437 : wild going on */
438 0 : errno = ENOENT;
439 : }
440 : }
441 :
442 6 : return(return_cnt > 0);
443 : }
444 :
445 : /****************************************************************************
446 : Send a SamOEMChangePassword command.
447 : ****************************************************************************/
448 :
449 0 : bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
450 : const char *old_password)
451 : {
452 : char param[1024];
453 : unsigned char data[532];
454 0 : char *p = param;
455 : unsigned char old_pw_hash[16];
456 : unsigned char new_pw_hash[16];
457 : unsigned int data_len;
458 0 : unsigned int param_len = 0;
459 0 : char *rparam = NULL;
460 0 : char *rdata = NULL;
461 : unsigned int rprcnt, rdrcnt;
462 0 : gnutls_cipher_hd_t cipher_hnd = NULL;
463 0 : gnutls_datum_t old_pw_key = {
464 : .data = old_pw_hash,
465 : .size = sizeof(old_pw_hash),
466 : };
467 : int rc;
468 :
469 0 : if (strlen(user) >= sizeof(fstring)-1) {
470 0 : DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
471 0 : return False;
472 : }
473 :
474 0 : SSVAL(p,0,214); /* SamOEMChangePassword command. */
475 0 : p += 2;
476 0 : strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
477 0 : p = skip_string(param,sizeof(param),p);
478 0 : strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
479 0 : p = skip_string(param,sizeof(param),p);
480 0 : strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
481 0 : p = skip_string(param,sizeof(param),p);
482 0 : SSVAL(p,0,532);
483 0 : p += 2;
484 :
485 0 : param_len = PTR_DIFF(p,param);
486 :
487 : /*
488 : * Get the Lanman hash of the old password, we
489 : * use this as the key to make_oem_passwd_hash().
490 : */
491 0 : E_deshash(old_password, old_pw_hash);
492 :
493 0 : encode_pw_buffer(data, new_password, STR_ASCII);
494 :
495 : #ifdef DEBUG_PASSWORD
496 0 : DEBUG(100,("make_oem_passwd_hash\n"));
497 0 : dump_data(100, data, 516);
498 : #endif
499 0 : rc = gnutls_cipher_init(&cipher_hnd,
500 : GNUTLS_CIPHER_ARCFOUR_128,
501 : &old_pw_key,
502 : NULL);
503 0 : if (rc < 0) {
504 0 : DBG_ERR("gnutls_cipher_init failed: %s\n",
505 : gnutls_strerror(rc));
506 0 : return false;
507 : }
508 0 : rc = gnutls_cipher_encrypt(cipher_hnd,
509 : data,
510 : 516);
511 0 : gnutls_cipher_deinit(cipher_hnd);
512 0 : if (rc < 0) {
513 0 : return false;
514 : }
515 :
516 : /*
517 : * Now place the old password hash in the data.
518 : */
519 0 : E_deshash(new_password, new_pw_hash);
520 :
521 0 : rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
522 0 : if (rc != 0) {
523 0 : DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
524 0 : return false;
525 : }
526 :
527 0 : data_len = 532;
528 :
529 0 : if (!cli_api(cli,
530 : param, param_len, 4, /* param, length, max */
531 : (char *)data, data_len, 0, /* data, length, max */
532 : &rparam, &rprcnt,
533 : &rdata, &rdrcnt)) {
534 0 : DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
535 : user ));
536 0 : return False;
537 : }
538 :
539 0 : if (rdrcnt < 2) {
540 0 : cli->rap_error = ERRbadformat;
541 0 : goto done;
542 : }
543 :
544 0 : if (rparam) {
545 0 : cli->rap_error = SVAL(rparam,0);
546 : }
547 :
548 0 : done:
549 0 : SAFE_FREE(rparam);
550 0 : SAFE_FREE(rdata);
551 :
552 0 : return (cli->rap_error == 0);
553 : }
554 :
555 : /****************************************************************************
556 : Send a qpathinfo call.
557 : ****************************************************************************/
558 :
559 : struct cli_qpathinfo1_state {
560 : struct cli_state *cli;
561 : uint32_t num_data;
562 : uint8_t *data;
563 : };
564 :
565 : static void cli_qpathinfo1_done(struct tevent_req *subreq);
566 :
567 1 : struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
568 : struct tevent_context *ev,
569 : struct cli_state *cli,
570 : const char *fname)
571 : {
572 1 : struct tevent_req *req = NULL, *subreq = NULL;
573 1 : struct cli_qpathinfo1_state *state = NULL;
574 :
575 1 : req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
576 1 : if (req == NULL) {
577 0 : return NULL;
578 : }
579 1 : state->cli = cli;
580 1 : subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
581 : 22, CLI_BUFFER_SIZE);
582 1 : if (tevent_req_nomem(subreq, req)) {
583 0 : return tevent_req_post(req, ev);
584 : }
585 1 : tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
586 1 : return req;
587 : }
588 :
589 1 : static void cli_qpathinfo1_done(struct tevent_req *subreq)
590 : {
591 1 : struct tevent_req *req = tevent_req_callback_data(
592 : subreq, struct tevent_req);
593 1 : struct cli_qpathinfo1_state *state = tevent_req_data(
594 : req, struct cli_qpathinfo1_state);
595 : NTSTATUS status;
596 :
597 1 : status = cli_qpathinfo_recv(subreq, state, &state->data,
598 : &state->num_data);
599 1 : TALLOC_FREE(subreq);
600 1 : if (!NT_STATUS_IS_OK(status)) {
601 0 : tevent_req_nterror(req, status);
602 0 : return;
603 : }
604 1 : tevent_req_done(req);
605 : }
606 :
607 1 : NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
608 : time_t *change_time,
609 : time_t *access_time,
610 : time_t *write_time,
611 : off_t *size,
612 : uint32_t *pattr)
613 : {
614 1 : struct cli_qpathinfo1_state *state = tevent_req_data(
615 : req, struct cli_qpathinfo1_state);
616 : NTSTATUS status;
617 :
618 : time_t (*date_fn)(const void *buf, int serverzone);
619 :
620 1 : if (tevent_req_is_nterror(req, &status)) {
621 0 : return status;
622 : }
623 :
624 1 : if (state->cli->win95) {
625 0 : date_fn = make_unix_date;
626 : } else {
627 1 : date_fn = make_unix_date2;
628 : }
629 :
630 1 : if (change_time) {
631 1 : *change_time = date_fn(state->data+0, smb1cli_conn_server_time_zone(state->cli->conn));
632 : }
633 1 : if (access_time) {
634 1 : *access_time = date_fn(state->data+4, smb1cli_conn_server_time_zone(state->cli->conn));
635 : }
636 1 : if (write_time) {
637 1 : *write_time = date_fn(state->data+8, smb1cli_conn_server_time_zone(state->cli->conn));
638 : }
639 1 : if (size) {
640 1 : *size = IVAL(state->data, 12);
641 : }
642 1 : if (pattr) {
643 0 : *pattr = SVAL(state->data, l1_attrFile);
644 : }
645 1 : return NT_STATUS_OK;
646 : }
647 :
648 1 : NTSTATUS cli_qpathinfo1(struct cli_state *cli,
649 : const char *fname,
650 : time_t *change_time,
651 : time_t *access_time,
652 : time_t *write_time,
653 : off_t *size,
654 : uint32_t *pattr)
655 : {
656 1 : TALLOC_CTX *frame = talloc_stackframe();
657 : struct tevent_context *ev;
658 : struct tevent_req *req;
659 1 : NTSTATUS status = NT_STATUS_NO_MEMORY;
660 :
661 1 : if (smbXcli_conn_has_async_calls(cli->conn)) {
662 : /*
663 : * Can't use sync call while an async call is in flight
664 : */
665 0 : status = NT_STATUS_INVALID_PARAMETER;
666 0 : goto fail;
667 : }
668 1 : ev = samba_tevent_context_init(frame);
669 1 : if (ev == NULL) {
670 0 : goto fail;
671 : }
672 1 : req = cli_qpathinfo1_send(frame, ev, cli, fname);
673 1 : if (req == NULL) {
674 0 : goto fail;
675 : }
676 1 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
677 0 : goto fail;
678 : }
679 1 : status = cli_qpathinfo1_recv(req, change_time, access_time,
680 : write_time, size, pattr);
681 1 : fail:
682 1 : TALLOC_FREE(frame);
683 1 : return status;
684 : }
685 :
686 8 : static void prep_basic_information_buf(
687 : uint8_t buf[40],
688 : struct timespec create_time,
689 : struct timespec access_time,
690 : struct timespec write_time,
691 : struct timespec change_time,
692 : uint32_t attr)
693 : {
694 8 : char *p = (char *)buf;
695 : /*
696 : * Add the create, last access, modification, and status change times
697 : */
698 8 : put_long_date_full_timespec(
699 : TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
700 8 : p += 8;
701 :
702 8 : put_long_date_full_timespec(
703 : TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
704 8 : p += 8;
705 :
706 8 : put_long_date_full_timespec(
707 : TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
708 8 : p += 8;
709 :
710 8 : put_long_date_full_timespec(
711 : TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
712 8 : p += 8;
713 :
714 8 : if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
715 : /* No change. */
716 6 : attr = 0;
717 2 : } else if (attr == 0) {
718 : /* Clear all existing attributes. */
719 1 : attr = FILE_ATTRIBUTE_NORMAL;
720 : }
721 :
722 : /* Add attributes */
723 8 : SIVAL(p, 0, attr);
724 :
725 8 : p += 4;
726 :
727 : /* Add padding */
728 8 : SIVAL(p, 0, 0);
729 8 : p += 4;
730 :
731 8 : SMB_ASSERT(PTR_DIFF(p, buf) == 40);
732 8 : }
733 :
734 8 : NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
735 : struct timespec create_time,
736 : struct timespec access_time,
737 : struct timespec write_time,
738 : struct timespec change_time,
739 : uint32_t attr)
740 : {
741 : uint8_t buf[40];
742 :
743 8 : prep_basic_information_buf(
744 : buf,
745 : create_time,
746 : access_time,
747 : write_time,
748 : change_time,
749 : attr);
750 :
751 8 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
752 4 : DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
753 : /*
754 : * Split out SMB2 here as we need to select
755 : * the correct info type and level.
756 : */
757 4 : return cli_smb2_setpathinfo(cli,
758 : fname,
759 : 1, /* SMB2_SETINFO_FILE */
760 : SMB_FILE_BASIC_INFORMATION - 1000,
761 : &in_data);
762 : }
763 :
764 4 : return cli_setpathinfo(
765 : cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
766 : }
767 :
768 : struct cli_setfileinfo_ext_state {
769 : uint8_t data[40];
770 : DATA_BLOB in_data;
771 : };
772 :
773 : static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
774 : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
775 :
776 0 : struct tevent_req *cli_setfileinfo_ext_send(
777 : TALLOC_CTX *mem_ctx,
778 : struct tevent_context *ev,
779 : struct cli_state *cli,
780 : uint16_t fnum,
781 : struct timespec create_time,
782 : struct timespec access_time,
783 : struct timespec write_time,
784 : struct timespec change_time,
785 : uint32_t attr)
786 : {
787 0 : struct tevent_req *req = NULL, *subreq = NULL;
788 0 : struct cli_setfileinfo_ext_state *state = NULL;
789 :
790 0 : req = tevent_req_create(
791 : mem_ctx, &state, struct cli_setfileinfo_ext_state);
792 0 : if (req == NULL) {
793 0 : return NULL;
794 : }
795 0 : prep_basic_information_buf(
796 0 : state->data,
797 : create_time,
798 : access_time,
799 : write_time,
800 : change_time,
801 : attr);
802 :
803 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
804 0 : state->in_data = (DATA_BLOB) {
805 0 : .data = state->data, .length = sizeof(state->data),
806 : };
807 :
808 0 : subreq = cli_smb2_set_info_fnum_send(
809 : state,
810 : ev,
811 : cli,
812 : fnum,
813 : SMB2_0_INFO_FILE,
814 : SMB_FILE_BASIC_INFORMATION - 1000,
815 0 : &state->in_data,
816 : 0); /* in_additional_info */
817 0 : if (tevent_req_nomem(subreq, req)) {
818 0 : return tevent_req_post(req, ev);
819 : }
820 0 : tevent_req_set_callback(
821 : subreq, cli_setfileinfo_ext_done2, req);
822 0 : return req;
823 : }
824 :
825 0 : subreq = cli_setfileinfo_send(
826 : state,
827 : ev,
828 : cli,
829 : fnum,
830 : SMB_FILE_BASIC_INFORMATION,
831 0 : state->data,
832 : sizeof(state->data));
833 0 : if (tevent_req_nomem(subreq, req)) {
834 0 : return tevent_req_post(req, ev);
835 : }
836 0 : tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
837 0 : return req;
838 : }
839 :
840 0 : static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
841 : {
842 0 : NTSTATUS status = cli_setfileinfo_recv(subreq);
843 0 : tevent_req_simple_finish_ntstatus(subreq, status);
844 0 : }
845 :
846 0 : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
847 : {
848 0 : NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
849 0 : tevent_req_simple_finish_ntstatus(subreq, status);
850 0 : }
851 :
852 0 : NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
853 : {
854 0 : return tevent_req_simple_recv_ntstatus(req);
855 : }
856 :
857 0 : NTSTATUS cli_setfileinfo_ext(
858 : struct cli_state *cli,
859 : uint16_t fnum,
860 : struct timespec create_time,
861 : struct timespec access_time,
862 : struct timespec write_time,
863 : struct timespec change_time,
864 : uint32_t attr)
865 : {
866 0 : TALLOC_CTX *frame = NULL;
867 0 : struct tevent_context *ev = NULL;
868 0 : struct tevent_req *req = NULL;
869 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
870 :
871 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
872 : /*
873 : * Can't use sync call while an async call is in flight
874 : */
875 0 : return NT_STATUS_INVALID_PARAMETER;
876 : }
877 :
878 0 : frame = talloc_stackframe();
879 :
880 0 : ev = samba_tevent_context_init(frame);
881 0 : if (ev == NULL) {
882 0 : goto fail;
883 : }
884 0 : req = cli_setfileinfo_ext_send(
885 : ev,
886 : ev,
887 : cli,
888 : fnum,
889 : create_time,
890 : access_time,
891 : write_time,
892 : change_time,
893 : attr);
894 0 : if (req == NULL) {
895 0 : goto fail;
896 : }
897 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
898 0 : goto fail;
899 : }
900 0 : status = cli_setfileinfo_ext_recv(req);
901 0 : fail:
902 0 : TALLOC_FREE(frame);
903 0 : return status;
904 : }
905 :
906 : /****************************************************************************
907 : Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
908 : ****************************************************************************/
909 :
910 : struct cli_qpathinfo2_state {
911 : uint32_t num_data;
912 : uint8_t *data;
913 : };
914 :
915 : static void cli_qpathinfo2_done(struct tevent_req *subreq);
916 :
917 3 : struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
918 : struct tevent_context *ev,
919 : struct cli_state *cli,
920 : const char *fname)
921 : {
922 3 : struct tevent_req *req = NULL, *subreq = NULL;
923 3 : struct cli_qpathinfo2_state *state = NULL;
924 :
925 3 : req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
926 3 : if (req == NULL) {
927 0 : return NULL;
928 : }
929 3 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
930 : SMB_QUERY_FILE_ALL_INFO,
931 : 68, CLI_BUFFER_SIZE);
932 3 : if (tevent_req_nomem(subreq, req)) {
933 0 : return tevent_req_post(req, ev);
934 : }
935 3 : tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
936 3 : return req;
937 : }
938 :
939 3 : static void cli_qpathinfo2_done(struct tevent_req *subreq)
940 : {
941 3 : struct tevent_req *req = tevent_req_callback_data(
942 : subreq, struct tevent_req);
943 3 : struct cli_qpathinfo2_state *state = tevent_req_data(
944 : req, struct cli_qpathinfo2_state);
945 : NTSTATUS status;
946 :
947 3 : status = cli_qpathinfo_recv(subreq, state, &state->data,
948 : &state->num_data);
949 3 : TALLOC_FREE(subreq);
950 3 : if (!NT_STATUS_IS_OK(status)) {
951 0 : tevent_req_nterror(req, status);
952 0 : return;
953 : }
954 3 : tevent_req_done(req);
955 : }
956 :
957 3 : NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
958 : struct timespec *create_time,
959 : struct timespec *access_time,
960 : struct timespec *write_time,
961 : struct timespec *change_time,
962 : off_t *size, uint32_t *pattr,
963 : SMB_INO_T *ino)
964 : {
965 3 : struct cli_qpathinfo2_state *state = tevent_req_data(
966 : req, struct cli_qpathinfo2_state);
967 : NTSTATUS status;
968 :
969 3 : if (tevent_req_is_nterror(req, &status)) {
970 0 : return status;
971 : }
972 :
973 3 : if (create_time) {
974 3 : *create_time = interpret_long_date((char *)state->data+0);
975 : }
976 3 : if (access_time) {
977 3 : *access_time = interpret_long_date((char *)state->data+8);
978 : }
979 3 : if (write_time) {
980 3 : *write_time = interpret_long_date((char *)state->data+16);
981 : }
982 3 : if (change_time) {
983 3 : *change_time = interpret_long_date((char *)state->data+24);
984 : }
985 3 : if (pattr) {
986 : /* SMB_QUERY_FILE_ALL_INFO returns 32-bit attributes. */
987 0 : *pattr = IVAL(state->data, 32);
988 : }
989 3 : if (size) {
990 3 : *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
991 : }
992 3 : if (ino) {
993 : /*
994 : * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO
995 : * which doesn't return an inode number (fileid).
996 : * We can't change this to one of the FILE_ID
997 : * info levels as only Win2003 and above support
998 : * these [MS-SMB: 2.2.2.3.1] and the SMB1 code
999 : * needs to support older servers.
1000 : */
1001 1 : *ino = 0;
1002 : }
1003 3 : return NT_STATUS_OK;
1004 : }
1005 :
1006 55 : NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
1007 : struct timespec *create_time,
1008 : struct timespec *access_time,
1009 : struct timespec *write_time,
1010 : struct timespec *change_time,
1011 : off_t *size, uint32_t *pattr,
1012 : SMB_INO_T *ino)
1013 : {
1014 55 : TALLOC_CTX *frame = NULL;
1015 : struct tevent_context *ev;
1016 : struct tevent_req *req;
1017 55 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1018 :
1019 55 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1020 52 : return cli_smb2_qpathinfo2(cli,
1021 : fname,
1022 : create_time,
1023 : access_time,
1024 : write_time,
1025 : change_time,
1026 : size,
1027 : pattr,
1028 : ino);
1029 : }
1030 :
1031 3 : frame = talloc_stackframe();
1032 :
1033 3 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1034 : /*
1035 : * Can't use sync call while an async call is in flight
1036 : */
1037 0 : status = NT_STATUS_INVALID_PARAMETER;
1038 0 : goto fail;
1039 : }
1040 3 : ev = samba_tevent_context_init(frame);
1041 3 : if (ev == NULL) {
1042 0 : goto fail;
1043 : }
1044 3 : req = cli_qpathinfo2_send(frame, ev, cli, fname);
1045 3 : if (req == NULL) {
1046 0 : goto fail;
1047 : }
1048 3 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1049 0 : goto fail;
1050 : }
1051 3 : status = cli_qpathinfo2_recv(req, create_time, access_time,
1052 : write_time, change_time, size, pattr, ino);
1053 3 : fail:
1054 3 : TALLOC_FREE(frame);
1055 3 : return status;
1056 : }
1057 :
1058 : /****************************************************************************
1059 : Get the stream info
1060 : ****************************************************************************/
1061 :
1062 : struct cli_qpathinfo_streams_state {
1063 : uint32_t num_data;
1064 : uint8_t *data;
1065 : };
1066 :
1067 : static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
1068 :
1069 0 : struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
1070 : struct tevent_context *ev,
1071 : struct cli_state *cli,
1072 : const char *fname)
1073 : {
1074 0 : struct tevent_req *req = NULL, *subreq = NULL;
1075 0 : struct cli_qpathinfo_streams_state *state = NULL;
1076 :
1077 0 : req = tevent_req_create(mem_ctx, &state,
1078 : struct cli_qpathinfo_streams_state);
1079 0 : if (req == NULL) {
1080 0 : return NULL;
1081 : }
1082 0 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
1083 : SMB_FILE_STREAM_INFORMATION,
1084 : 0, CLI_BUFFER_SIZE);
1085 0 : if (tevent_req_nomem(subreq, req)) {
1086 0 : return tevent_req_post(req, ev);
1087 : }
1088 0 : tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1089 0 : return req;
1090 : }
1091 :
1092 0 : static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1093 : {
1094 0 : struct tevent_req *req = tevent_req_callback_data(
1095 : subreq, struct tevent_req);
1096 0 : struct cli_qpathinfo_streams_state *state = tevent_req_data(
1097 : req, struct cli_qpathinfo_streams_state);
1098 : NTSTATUS status;
1099 :
1100 0 : status = cli_qpathinfo_recv(subreq, state, &state->data,
1101 : &state->num_data);
1102 0 : TALLOC_FREE(subreq);
1103 0 : if (!NT_STATUS_IS_OK(status)) {
1104 0 : tevent_req_nterror(req, status);
1105 0 : return;
1106 : }
1107 0 : tevent_req_done(req);
1108 : }
1109 :
1110 0 : NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
1111 : TALLOC_CTX *mem_ctx,
1112 : unsigned int *pnum_streams,
1113 : struct stream_struct **pstreams)
1114 : {
1115 0 : struct cli_qpathinfo_streams_state *state = tevent_req_data(
1116 : req, struct cli_qpathinfo_streams_state);
1117 : NTSTATUS status;
1118 :
1119 0 : if (tevent_req_is_nterror(req, &status)) {
1120 0 : return status;
1121 : }
1122 0 : if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1123 : pnum_streams, pstreams)) {
1124 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1125 : }
1126 0 : return NT_STATUS_OK;
1127 : }
1128 :
1129 52 : NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
1130 : TALLOC_CTX *mem_ctx,
1131 : unsigned int *pnum_streams,
1132 : struct stream_struct **pstreams)
1133 : {
1134 52 : TALLOC_CTX *frame = NULL;
1135 : struct tevent_context *ev;
1136 : struct tevent_req *req;
1137 52 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1138 :
1139 52 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1140 52 : return cli_smb2_qpathinfo_streams(cli,
1141 : fname,
1142 : mem_ctx,
1143 : pnum_streams,
1144 : pstreams);
1145 : }
1146 :
1147 0 : frame = talloc_stackframe();
1148 :
1149 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1150 : /*
1151 : * Can't use sync call while an async call is in flight
1152 : */
1153 0 : status = NT_STATUS_INVALID_PARAMETER;
1154 0 : goto fail;
1155 : }
1156 0 : ev = samba_tevent_context_init(frame);
1157 0 : if (ev == NULL) {
1158 0 : goto fail;
1159 : }
1160 0 : req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1161 0 : if (req == NULL) {
1162 0 : goto fail;
1163 : }
1164 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1165 0 : goto fail;
1166 : }
1167 0 : status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1168 : pstreams);
1169 0 : fail:
1170 0 : TALLOC_FREE(frame);
1171 0 : return status;
1172 : }
1173 :
1174 44 : bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
1175 : size_t data_len,
1176 : unsigned int *pnum_streams,
1177 : struct stream_struct **pstreams)
1178 : {
1179 : unsigned int num_streams;
1180 : struct stream_struct *streams;
1181 : unsigned int ofs;
1182 :
1183 44 : num_streams = 0;
1184 44 : streams = NULL;
1185 44 : ofs = 0;
1186 :
1187 66 : while ((data_len > ofs) && (data_len - ofs >= 24)) {
1188 : uint32_t nlen, len;
1189 : size_t size;
1190 : void *vstr;
1191 : struct stream_struct *tmp;
1192 : uint8_t *tmp_buf;
1193 :
1194 36 : tmp = talloc_realloc(mem_ctx, streams,
1195 : struct stream_struct,
1196 : num_streams+1);
1197 :
1198 36 : if (tmp == NULL) {
1199 0 : goto fail;
1200 : }
1201 36 : streams = tmp;
1202 :
1203 36 : nlen = IVAL(rdata, ofs + 0x04);
1204 :
1205 36 : streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1206 : rdata, ofs + 0x08);
1207 36 : streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1208 : rdata, ofs + 0x10);
1209 :
1210 36 : if (nlen > data_len - (ofs + 24)) {
1211 0 : goto fail;
1212 : }
1213 :
1214 : /*
1215 : * We need to null-terminate src, how do I do this with
1216 : * convert_string_talloc??
1217 : */
1218 :
1219 36 : tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1220 36 : if (tmp_buf == NULL) {
1221 0 : goto fail;
1222 : }
1223 :
1224 36 : memcpy(tmp_buf, rdata+ofs+24, nlen);
1225 36 : tmp_buf[nlen] = 0;
1226 36 : tmp_buf[nlen+1] = 0;
1227 :
1228 36 : if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1229 36 : nlen+2, &vstr, &size))
1230 : {
1231 0 : TALLOC_FREE(tmp_buf);
1232 0 : goto fail;
1233 : }
1234 :
1235 36 : TALLOC_FREE(tmp_buf);
1236 36 : streams[num_streams].name = (char *)vstr;
1237 36 : num_streams++;
1238 :
1239 36 : len = IVAL(rdata, ofs);
1240 36 : if (len > data_len - ofs) {
1241 0 : goto fail;
1242 : }
1243 36 : if (len == 0) break;
1244 0 : ofs += len;
1245 : }
1246 :
1247 44 : *pnum_streams = num_streams;
1248 44 : *pstreams = streams;
1249 44 : return true;
1250 :
1251 0 : fail:
1252 0 : TALLOC_FREE(streams);
1253 0 : return false;
1254 : }
1255 :
1256 : /****************************************************************************
1257 : Send a qfileinfo QUERY_FILE_NAME_INFO call.
1258 : ****************************************************************************/
1259 :
1260 : struct cli_qfileinfo_basic_state {
1261 : uint32_t attr;
1262 : off_t size;
1263 : struct timespec create_time;
1264 : struct timespec access_time;
1265 : struct timespec write_time;
1266 : struct timespec change_time;
1267 : SMB_INO_T ino;
1268 : };
1269 :
1270 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq);
1271 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq);
1272 : static void cli_qfileinfo_basic_done2(struct tevent_req *subreq);
1273 :
1274 601 : struct tevent_req *cli_qfileinfo_basic_send(
1275 : TALLOC_CTX *mem_ctx,
1276 : struct tevent_context *ev,
1277 : struct cli_state *cli,
1278 : uint16_t fnum)
1279 : {
1280 601 : struct tevent_req *req = NULL, *subreq = NULL;
1281 601 : struct cli_qfileinfo_basic_state *state = NULL;
1282 :
1283 601 : req = tevent_req_create(
1284 : mem_ctx, &state, struct cli_qfileinfo_basic_state);
1285 601 : if (req == NULL) {
1286 0 : return NULL;
1287 : }
1288 :
1289 1144 : if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1290 601 : cli->win95) {
1291 : /*
1292 : * According to
1293 : * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
1294 : * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
1295 : * further down was introduced with the LAN Manager
1296 : * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
1297 : *
1298 : * The "win95" check was introduced with commit
1299 : * 27e5850fd3e1c8 in 1998. Hard to check these days,
1300 : * but leave it in.
1301 : *
1302 : * Use a lowerlevel fallback in both cases.
1303 : */
1304 :
1305 0 : subreq = cli_getattrE_send(state, ev, cli, fnum);
1306 0 : if (tevent_req_nomem(subreq, req)) {
1307 0 : return tevent_req_post(req, ev);
1308 : }
1309 0 : tevent_req_set_callback(
1310 : subreq, cli_qfileinfo_basic_doneE, req);
1311 0 : return req;
1312 : }
1313 :
1314 601 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1315 596 : subreq = cli_smb2_query_info_fnum_send(
1316 : state, /* mem_ctx */
1317 : ev, /* ev */
1318 : cli, /* cli */
1319 : fnum, /* fnum */
1320 : 1, /* in_info_type */
1321 : (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */
1322 : 0xFFFF, /* in_max_output_length */
1323 : NULL, /* in_input_buffer */
1324 : 0, /* in_additional_info */
1325 : 0); /* in_flags */
1326 596 : if (tevent_req_nomem(subreq, req)) {
1327 0 : return tevent_req_post(req, ev);
1328 : }
1329 596 : tevent_req_set_callback(
1330 : subreq, cli_qfileinfo_basic_done2, req);
1331 596 : return req;
1332 : }
1333 :
1334 5 : subreq = cli_qfileinfo_send(
1335 : state,
1336 : ev,
1337 : cli,
1338 : fnum,
1339 : SMB_QUERY_FILE_ALL_INFO, /* level */
1340 : 68, /* min_rdata */
1341 : CLI_BUFFER_SIZE); /* max_rdata */
1342 5 : if (tevent_req_nomem(subreq, req)) {
1343 0 : return tevent_req_post(req, ev);
1344 : }
1345 5 : tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1346 5 : return req;
1347 : }
1348 :
1349 5 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1350 : {
1351 5 : struct tevent_req *req = tevent_req_callback_data(
1352 : subreq, struct tevent_req);
1353 5 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1354 : req, struct cli_qfileinfo_basic_state);
1355 : uint8_t *rdata;
1356 : uint32_t num_rdata;
1357 : NTSTATUS status;
1358 :
1359 5 : status = cli_qfileinfo_recv(
1360 : subreq, state, NULL, &rdata, &num_rdata);
1361 5 : TALLOC_FREE(subreq);
1362 5 : if (tevent_req_nterror(req, status)) {
1363 0 : return;
1364 : }
1365 :
1366 5 : state->create_time = interpret_long_date((char *)rdata+0);
1367 5 : state->access_time = interpret_long_date((char *)rdata+8);
1368 5 : state->write_time = interpret_long_date((char *)rdata+16);
1369 5 : state->change_time = interpret_long_date((char *)rdata+24);
1370 5 : state->attr = PULL_LE_U32(rdata, 32);
1371 5 : state->size = PULL_LE_U64(rdata,48);
1372 5 : state->ino = PULL_LE_U32(rdata, 64);
1373 5 : TALLOC_FREE(rdata);
1374 :
1375 5 : tevent_req_done(req);
1376 : }
1377 :
1378 0 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1379 : {
1380 0 : struct tevent_req *req = tevent_req_callback_data(
1381 : subreq, struct tevent_req);
1382 0 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1383 : req, struct cli_qfileinfo_basic_state);
1384 : NTSTATUS status;
1385 :
1386 0 : status = cli_getattrE_recv(
1387 : subreq,
1388 : &state->attr,
1389 : &state->size,
1390 0 : &state->change_time.tv_sec,
1391 0 : &state->access_time.tv_sec,
1392 0 : &state->write_time.tv_sec);
1393 0 : TALLOC_FREE(subreq);
1394 0 : if (tevent_req_nterror(req, status)) {
1395 0 : return;
1396 : }
1397 0 : tevent_req_done(req);
1398 : }
1399 :
1400 596 : static void cli_qfileinfo_basic_done2(struct tevent_req *subreq)
1401 : {
1402 596 : struct tevent_req *req = tevent_req_callback_data(
1403 : subreq, struct tevent_req);
1404 596 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1405 : req, struct cli_qfileinfo_basic_state);
1406 596 : DATA_BLOB outbuf = {0};
1407 : NTSTATUS status;
1408 :
1409 596 : status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
1410 596 : TALLOC_FREE(subreq);
1411 596 : if (tevent_req_nterror(req, status)) {
1412 0 : return;
1413 : }
1414 :
1415 : /* Parse the reply. */
1416 596 : if (outbuf.length < 0x60) {
1417 0 : tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1418 0 : return;
1419 : }
1420 :
1421 596 : state->create_time = interpret_long_date(
1422 596 : (const char *)outbuf.data + 0x0);
1423 596 : state->access_time = interpret_long_date(
1424 596 : (const char *)outbuf.data + 0x8);
1425 596 : state->write_time = interpret_long_date(
1426 596 : (const char *)outbuf.data + 0x10);
1427 596 : state->change_time = interpret_long_date(
1428 596 : (const char *)outbuf.data + 0x18);
1429 596 : state->attr = IVAL(outbuf.data, 0x20);
1430 596 : state->size = BVAL(outbuf.data, 0x30);
1431 596 : state->ino = BVAL(outbuf.data, 0x40);
1432 :
1433 596 : data_blob_free(&outbuf);
1434 :
1435 596 : tevent_req_done(req);
1436 : }
1437 :
1438 601 : NTSTATUS cli_qfileinfo_basic_recv(
1439 : struct tevent_req *req,
1440 : uint32_t *attr,
1441 : off_t *size,
1442 : struct timespec *create_time,
1443 : struct timespec *access_time,
1444 : struct timespec *write_time,
1445 : struct timespec *change_time,
1446 : SMB_INO_T *ino)
1447 : {
1448 601 : struct cli_qfileinfo_basic_state *state = tevent_req_data(
1449 : req, struct cli_qfileinfo_basic_state);
1450 : NTSTATUS status;
1451 :
1452 601 : if (tevent_req_is_nterror(req, &status)) {
1453 0 : return status;
1454 : }
1455 :
1456 601 : if (create_time != NULL) {
1457 53 : *create_time = state->create_time;
1458 : }
1459 601 : if (access_time != NULL) {
1460 53 : *access_time = state->access_time;
1461 : }
1462 601 : if (write_time != NULL) {
1463 109 : *write_time = state->write_time;
1464 : }
1465 601 : if (change_time != NULL) {
1466 53 : *change_time = state->change_time;
1467 : }
1468 601 : if (attr != NULL) {
1469 117 : *attr = state->attr;
1470 : }
1471 601 : if (size != NULL) {
1472 545 : *size = state->size;
1473 : }
1474 601 : if (ino) {
1475 0 : *ino = state->ino;
1476 : }
1477 :
1478 601 : return NT_STATUS_OK;
1479 : }
1480 : /****************************************************************************
1481 : Send a qfileinfo call.
1482 : ****************************************************************************/
1483 :
1484 133 : NTSTATUS cli_qfileinfo_basic(
1485 : struct cli_state *cli,
1486 : uint16_t fnum,
1487 : uint32_t *attr,
1488 : off_t *size,
1489 : struct timespec *create_time,
1490 : struct timespec *access_time,
1491 : struct timespec *write_time,
1492 : struct timespec *change_time,
1493 : SMB_INO_T *ino)
1494 : {
1495 133 : TALLOC_CTX *frame = NULL;
1496 133 : struct tevent_context *ev = NULL;
1497 133 : struct tevent_req *req = NULL;
1498 133 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1499 :
1500 133 : frame = talloc_stackframe();
1501 :
1502 133 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1503 : /*
1504 : * Can't use sync call while an async call is in flight
1505 : */
1506 0 : status = NT_STATUS_INVALID_PARAMETER;
1507 0 : goto fail;
1508 : }
1509 133 : ev = samba_tevent_context_init(frame);
1510 133 : if (ev == NULL) {
1511 0 : goto fail;
1512 : }
1513 133 : req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1514 133 : if (req == NULL) {
1515 0 : goto fail;
1516 : }
1517 133 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1518 0 : goto fail;
1519 : }
1520 :
1521 133 : status = cli_qfileinfo_basic_recv(
1522 : req,
1523 : attr,
1524 : size,
1525 : create_time,
1526 : access_time,
1527 : write_time,
1528 : change_time,
1529 : ino);
1530 :
1531 : /* cli_smb2_query_info_fnum_recv doesn't set this */
1532 133 : cli->raw_status = status;
1533 133 : fail:
1534 133 : TALLOC_FREE(frame);
1535 133 : return status;
1536 : }
1537 :
1538 : /****************************************************************************
1539 : Send a qpathinfo BASIC_INFO call.
1540 : ****************************************************************************/
1541 :
1542 : struct cli_qpathinfo_basic_state {
1543 : uint32_t num_data;
1544 : uint8_t *data;
1545 : };
1546 :
1547 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1548 :
1549 0 : struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1550 : struct tevent_context *ev,
1551 : struct cli_state *cli,
1552 : const char *fname)
1553 : {
1554 0 : struct tevent_req *req = NULL, *subreq = NULL;
1555 0 : struct cli_qpathinfo_basic_state *state = NULL;
1556 :
1557 0 : req = tevent_req_create(mem_ctx, &state,
1558 : struct cli_qpathinfo_basic_state);
1559 0 : if (req == NULL) {
1560 0 : return NULL;
1561 : }
1562 0 : subreq = cli_qpathinfo_send(state, ev, cli, fname,
1563 : SMB_QUERY_FILE_BASIC_INFO,
1564 : 36, CLI_BUFFER_SIZE);
1565 0 : if (tevent_req_nomem(subreq, req)) {
1566 0 : return tevent_req_post(req, ev);
1567 : }
1568 0 : tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1569 0 : return req;
1570 : }
1571 :
1572 0 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1573 : {
1574 0 : struct tevent_req *req = tevent_req_callback_data(
1575 : subreq, struct tevent_req);
1576 0 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1577 : req, struct cli_qpathinfo_basic_state);
1578 : NTSTATUS status;
1579 :
1580 0 : status = cli_qpathinfo_recv(subreq, state, &state->data,
1581 : &state->num_data);
1582 0 : TALLOC_FREE(subreq);
1583 0 : if (!NT_STATUS_IS_OK(status)) {
1584 0 : tevent_req_nterror(req, status);
1585 0 : return;
1586 : }
1587 0 : tevent_req_done(req);
1588 : }
1589 :
1590 0 : NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1591 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1592 : {
1593 0 : struct cli_qpathinfo_basic_state *state = tevent_req_data(
1594 : req, struct cli_qpathinfo_basic_state);
1595 : NTSTATUS status;
1596 :
1597 0 : if (tevent_req_is_nterror(req, &status)) {
1598 0 : return status;
1599 : }
1600 :
1601 0 : sbuf->st_ex_btime = interpret_long_date((char *)state->data);
1602 0 : sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1603 0 : sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1604 0 : sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1605 0 : *attributes = IVAL(state->data, 32);
1606 0 : return NT_STATUS_OK;
1607 : }
1608 :
1609 912 : NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1610 : SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1611 : {
1612 912 : TALLOC_CTX *frame = NULL;
1613 : struct tevent_context *ev;
1614 : struct tevent_req *req;
1615 912 : NTSTATUS status = NT_STATUS_NO_MEMORY;
1616 :
1617 912 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1618 912 : return cli_smb2_qpathinfo_basic(cli,
1619 : name,
1620 : sbuf,
1621 : attributes);
1622 : }
1623 :
1624 0 : frame = talloc_stackframe();
1625 :
1626 0 : if (smbXcli_conn_has_async_calls(cli->conn)) {
1627 : /*
1628 : * Can't use sync call while an async call is in flight
1629 : */
1630 0 : status = NT_STATUS_INVALID_PARAMETER;
1631 0 : goto fail;
1632 : }
1633 0 : ev = samba_tevent_context_init(frame);
1634 0 : if (ev == NULL) {
1635 0 : goto fail;
1636 : }
1637 0 : req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1638 0 : if (req == NULL) {
1639 0 : goto fail;
1640 : }
1641 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1642 0 : goto fail;
1643 : }
1644 0 : status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1645 0 : fail:
1646 0 : TALLOC_FREE(frame);
1647 0 : return status;
1648 : }
1649 :
1650 : /****************************************************************************
1651 : Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1652 : ****************************************************************************/
1653 :
1654 56 : NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1655 : {
1656 : uint8_t *rdata;
1657 : uint32_t num_rdata;
1658 : unsigned int len;
1659 56 : char *converted = NULL;
1660 56 : size_t converted_size = 0;
1661 : NTSTATUS status;
1662 :
1663 56 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1664 56 : return cli_smb2_qpathinfo_alt_name(cli,
1665 : fname,
1666 : alt_name);
1667 : }
1668 :
1669 0 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1670 : SMB_QUERY_FILE_ALT_NAME_INFO,
1671 : 4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1672 0 : if (!NT_STATUS_IS_OK(status)) {
1673 0 : return status;
1674 : }
1675 :
1676 0 : len = IVAL(rdata, 0);
1677 :
1678 0 : if (len > num_rdata - 4) {
1679 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
1680 : }
1681 :
1682 : /* The returned data is a pushed string, not raw data. */
1683 0 : if (!convert_string_talloc(talloc_tos(),
1684 0 : smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1685 : CH_UNIX,
1686 0 : rdata + 4,
1687 : len,
1688 : &converted,
1689 : &converted_size)) {
1690 0 : return NT_STATUS_NO_MEMORY;
1691 : }
1692 0 : fstrcpy(alt_name, converted);
1693 :
1694 0 : TALLOC_FREE(converted);
1695 0 : TALLOC_FREE(rdata);
1696 :
1697 0 : return NT_STATUS_OK;
1698 : }
1699 :
1700 : /****************************************************************************
1701 : Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1702 : ****************************************************************************/
1703 :
1704 0 : NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
1705 : uint64_t *allocated, uint64_t *size,
1706 : uint32_t *nlinks,
1707 : bool *is_del_pending, bool *is_dir)
1708 : {
1709 : uint8_t *rdata;
1710 : uint32_t num_rdata;
1711 : NTSTATUS status;
1712 :
1713 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1714 0 : return NT_STATUS_NOT_IMPLEMENTED;
1715 : }
1716 :
1717 0 : status = cli_qpathinfo(talloc_tos(), cli, fname,
1718 : SMB_QUERY_FILE_STANDARD_INFO,
1719 : 24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1720 0 : if (!NT_STATUS_IS_OK(status)) {
1721 0 : return status;
1722 : }
1723 :
1724 0 : if (allocated) {
1725 0 : *allocated = BVAL(rdata, 0);
1726 : }
1727 :
1728 0 : if (size) {
1729 0 : *size = BVAL(rdata, 8);
1730 : }
1731 :
1732 0 : if (nlinks) {
1733 0 : *nlinks = IVAL(rdata, 16);
1734 : }
1735 :
1736 0 : if (is_del_pending) {
1737 0 : *is_del_pending = CVAL(rdata, 20);
1738 : }
1739 :
1740 0 : if (is_dir) {
1741 0 : *is_dir = CVAL(rdata, 20);
1742 : }
1743 :
1744 0 : TALLOC_FREE(rdata);
1745 :
1746 0 : return NT_STATUS_OK;
1747 : }
1748 :
1749 :
1750 : /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1751 52 : NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
1752 : struct timespec *create_time,
1753 : struct timespec *access_time,
1754 : struct timespec *write_time,
1755 : struct timespec *change_time,
1756 : off_t *size, uint32_t *pattr,
1757 : SMB_INO_T *ino)
1758 : {
1759 52 : NTSTATUS status = NT_STATUS_OK;
1760 52 : SMB_STRUCT_STAT st = { 0 };
1761 52 : uint32_t attr = 0;
1762 : uint64_t pos;
1763 :
1764 52 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1765 : /*
1766 : * NB. cli_qpathinfo2() checks pattr is valid before
1767 : * storing a value into it, so we don't need to use
1768 : * an intermediate attr variable as below but can
1769 : * pass pattr directly.
1770 : */
1771 52 : return cli_qpathinfo2(cli, fname,
1772 : create_time, access_time, write_time, change_time,
1773 : size, pattr, ino);
1774 : }
1775 :
1776 0 : if (create_time || access_time || write_time || change_time || pattr) {
1777 : /*
1778 : * cli_qpathinfo_basic() always indirects the passed
1779 : * in pointers so we use intermediate variables to
1780 : * collect all of them before assigning any requested
1781 : * below.
1782 : */
1783 0 : status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1784 0 : if (!NT_STATUS_IS_OK(status)) {
1785 0 : return status;
1786 : }
1787 : }
1788 :
1789 0 : if (size) {
1790 0 : status = cli_qpathinfo_standard(cli, fname,
1791 : NULL, &pos, NULL, NULL, NULL);
1792 0 : if (!NT_STATUS_IS_OK(status)) {
1793 0 : return status;
1794 : }
1795 :
1796 0 : *size = pos;
1797 : }
1798 :
1799 0 : if (create_time) {
1800 0 : *create_time = st.st_ex_btime;
1801 : }
1802 0 : if (access_time) {
1803 0 : *access_time = st.st_ex_atime;
1804 : }
1805 0 : if (write_time) {
1806 0 : *write_time = st.st_ex_mtime;
1807 : }
1808 0 : if (change_time) {
1809 0 : *change_time = st.st_ex_ctime;
1810 : }
1811 0 : if (pattr) {
1812 0 : *pattr = attr;
1813 : }
1814 0 : if (ino) {
1815 0 : *ino = 0;
1816 : }
1817 :
1818 0 : return NT_STATUS_OK;
1819 : }
|