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