Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : SMB client generic functions
4 : Copyright (C) Andrew Tridgell 1994-1998
5 : Copyright (C) Jeremy Allison 2007.
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "libsmb/libsmb.h"
23 : #include "../lib/util/tevent_ntstatus.h"
24 : #include "../libcli/smb/smb_signing.h"
25 : #include "../libcli/smb/smb_seal.h"
26 : #include "async_smb.h"
27 : #include "../libcli/smb/smbXcli_base.h"
28 : #include "../libcli/smb/smb2_negotiate_context.h"
29 : #include "../librpc/ndr/libndr.h"
30 : #include "../include/client.h"
31 :
32 : /****************************************************************************
33 : Change the timeout (in milliseconds).
34 : ****************************************************************************/
35 :
36 12067 : unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout)
37 : {
38 12067 : unsigned int old_timeout = cli->timeout;
39 12067 : DBG_DEBUG("Changing connection timeout for server '%s' from %d (ms) to "
40 : "%d (ms).\n",
41 : smbXcli_conn_remote_name(cli->conn),
42 : cli->timeout,
43 : timeout);
44 12067 : cli->timeout = timeout;
45 12067 : return old_timeout;
46 : }
47 :
48 : /****************************************************************************
49 : Set the 'backup_intent' flag.
50 : ****************************************************************************/
51 :
52 20 : bool cli_set_backup_intent(struct cli_state *cli, bool flag)
53 : {
54 20 : bool old_state = cli->backup_intent;
55 20 : cli->backup_intent = flag;
56 20 : return old_state;
57 : }
58 :
59 : /****************************************************************************
60 : Initialise a client structure. Always returns a talloc'ed struct.
61 : Set the signing state (used from the command line).
62 : ****************************************************************************/
63 :
64 : struct GUID cli_state_client_guid;
65 :
66 18034 : struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx,
67 : int fd,
68 : const char *remote_name,
69 : enum smb_signing_setting signing_state,
70 : int flags)
71 : {
72 18034 : struct cli_state *cli = NULL;
73 18034 : bool use_spnego = lp_client_use_spnego();
74 18034 : bool force_dos_errors = false;
75 18034 : bool force_ascii = false;
76 18034 : bool use_level_II_oplocks = false;
77 18034 : uint32_t smb1_capabilities = 0;
78 18034 : uint32_t smb2_capabilities = 0;
79 0 : struct smb311_capabilities smb3_capabilities =
80 18034 : smb311_capabilities_parse("client",
81 18034 : lp_client_smb3_signing_algorithms(),
82 18034 : lp_client_smb3_encryption_algorithms());
83 0 : struct GUID client_guid;
84 :
85 18034 : if (!GUID_all_zero(&cli_state_client_guid)) {
86 0 : client_guid = cli_state_client_guid;
87 : } else {
88 18034 : const char *str = NULL;
89 :
90 18034 : str = lp_parm_const_string(-1, "libsmb", "client_guid", NULL);
91 18034 : if (str != NULL) {
92 2 : GUID_from_string(str, &client_guid);
93 : } else {
94 18032 : client_guid = GUID_random();
95 : }
96 : }
97 :
98 : /* Check the effective uid - make sure we are not setuid */
99 18034 : if (is_setuid_root()) {
100 0 : DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
101 0 : return NULL;
102 : }
103 :
104 18034 : cli = talloc_zero(mem_ctx, struct cli_state);
105 18034 : if (!cli) {
106 0 : return NULL;
107 : }
108 :
109 18034 : cli->server_domain = talloc_strdup(cli, "");
110 18034 : if (!cli->server_domain) {
111 0 : goto error;
112 : }
113 18034 : cli->server_os = talloc_strdup(cli, "");
114 18034 : if (!cli->server_os) {
115 0 : goto error;
116 : }
117 18034 : cli->server_type = talloc_strdup(cli, "");
118 18034 : if (!cli->server_type) {
119 0 : goto error;
120 : }
121 :
122 18034 : cli->raw_status = NT_STATUS_INTERNAL_ERROR;
123 18034 : cli->map_dos_errors = true; /* remove this */
124 18034 : cli->timeout = CLIENT_TIMEOUT;
125 :
126 : /* Set the CLI_FORCE_DOSERR environment variable to test
127 : client routines using DOS errors instead of STATUS32
128 : ones. This intended only as a temporary hack. */
129 18034 : if (getenv("CLI_FORCE_DOSERR")) {
130 0 : force_dos_errors = true;
131 : }
132 18034 : if (flags & CLI_FULL_CONNECTION_FORCE_DOS_ERRORS) {
133 0 : force_dos_errors = true;
134 : }
135 :
136 18034 : if (getenv("CLI_FORCE_ASCII")) {
137 0 : force_ascii = true;
138 : }
139 18034 : if (!lp_unicode()) {
140 0 : force_ascii = true;
141 : }
142 18034 : if (flags & CLI_FULL_CONNECTION_FORCE_ASCII) {
143 0 : force_ascii = true;
144 : }
145 :
146 18034 : if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
147 0 : use_spnego = false;
148 : }
149 :
150 18034 : if (flags & CLI_FULL_CONNECTION_OPLOCKS) {
151 8 : cli->use_oplocks = true;
152 : }
153 18034 : if (flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) {
154 8 : use_level_II_oplocks = true;
155 : }
156 :
157 18034 : if (signing_state == SMB_SIGNING_IPC_DEFAULT) {
158 : /*
159 : * Ensure for IPC/RPC the default is to require
160 : * signing unless explicitly turned off by the
161 : * administrator.
162 : */
163 10 : signing_state = lp_client_ipc_signing();
164 : }
165 :
166 18034 : if (signing_state == SMB_SIGNING_DEFAULT) {
167 14167 : signing_state = lp_client_signing();
168 : }
169 :
170 18034 : smb1_capabilities = 0;
171 18034 : smb1_capabilities |= CAP_LARGE_FILES;
172 18034 : smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
173 18034 : smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
174 18034 : smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS;
175 18034 : smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
176 18034 : smb1_capabilities |= CAP_LWIO;
177 :
178 18034 : if (!force_dos_errors) {
179 18034 : smb1_capabilities |= CAP_STATUS32;
180 : }
181 :
182 18034 : if (!force_ascii) {
183 18034 : smb1_capabilities |= CAP_UNICODE;
184 : }
185 :
186 18034 : if (use_spnego) {
187 17825 : smb1_capabilities |= CAP_EXTENDED_SECURITY;
188 : }
189 :
190 18034 : if (use_level_II_oplocks) {
191 8 : smb1_capabilities |= CAP_LEVEL_II_OPLOCKS;
192 : }
193 :
194 18034 : smb2_capabilities = SMB2_CAP_ALL;
195 :
196 18034 : cli->conn = smbXcli_conn_create(cli, fd, remote_name,
197 : signing_state,
198 : smb1_capabilities,
199 : &client_guid,
200 : smb2_capabilities,
201 : &smb3_capabilities);
202 18034 : if (cli->conn == NULL) {
203 0 : goto error;
204 : }
205 :
206 18034 : cli->smb1.pid = (uint32_t)getpid();
207 18034 : cli->smb1.vc_num = cli->smb1.pid;
208 18034 : cli->smb1.session = smbXcli_session_create(cli, cli->conn);
209 18034 : if (cli->smb1.session == NULL) {
210 0 : goto error;
211 : }
212 :
213 18034 : cli->initialised = 1;
214 18034 : return cli;
215 :
216 : /* Clean up after malloc() error */
217 :
218 0 : error:
219 :
220 0 : TALLOC_FREE(cli);
221 0 : return NULL;
222 : }
223 :
224 : /****************************************************************************
225 : Close all pipes open on this session.
226 : ****************************************************************************/
227 :
228 14514 : static void cli_nt_pipes_close(struct cli_state *cli)
229 : {
230 15074 : while (cli->pipe_list != NULL) {
231 : /*
232 : * No TALLOC_FREE here!
233 : */
234 560 : talloc_free(cli->pipe_list);
235 : }
236 14514 : }
237 :
238 : /****************************************************************************
239 : Shutdown a client structure.
240 : ****************************************************************************/
241 :
242 14514 : static void _cli_shutdown(struct cli_state *cli)
243 : {
244 14514 : cli_nt_pipes_close(cli);
245 :
246 : /*
247 : * tell our peer to free his resources. Without this, when an
248 : * application attempts to do a graceful shutdown and calls
249 : * smbc_free_context() to clean up all connections, some connections
250 : * can remain active on the peer end, until some (long) timeout period
251 : * later. This tree disconnect forces the peer to clean up, since the
252 : * connection will be going away.
253 : */
254 14514 : if (cli_state_has_tcon(cli)) {
255 13320 : cli_tdis(cli);
256 : }
257 :
258 14514 : smbXcli_conn_disconnect(cli->conn, NT_STATUS_OK);
259 :
260 14514 : TALLOC_FREE(cli);
261 14514 : }
262 :
263 14518 : void cli_shutdown(struct cli_state *cli)
264 : {
265 0 : struct cli_state *cli_head;
266 14518 : if (cli == NULL) {
267 4 : return;
268 : }
269 15145 : DLIST_HEAD(cli, cli_head);
270 14514 : if (cli_head == cli) {
271 : /*
272 : * head of a DFS list, shutdown all subsidiary DFS
273 : * connections.
274 : */
275 0 : struct cli_state *p, *next;
276 :
277 14282 : for (p = cli_head->next; p; p = next) {
278 0 : next = p->next;
279 0 : DLIST_REMOVE(cli_head, p);
280 0 : _cli_shutdown(p);
281 : }
282 : } else {
283 232 : DLIST_REMOVE(cli_head, cli);
284 : }
285 :
286 14514 : _cli_shutdown(cli);
287 : }
288 :
289 7723 : uint16_t cli_state_get_vc_num(struct cli_state *cli)
290 : {
291 7723 : return cli->smb1.vc_num;
292 : }
293 :
294 : /****************************************************************************
295 : Set the PID to use for smb messages. Return the old pid.
296 : ****************************************************************************/
297 :
298 89 : uint32_t cli_setpid(struct cli_state *cli, uint32_t pid)
299 : {
300 89 : uint32_t ret = cli->smb1.pid;
301 89 : cli->smb1.pid = pid;
302 89 : return ret;
303 : }
304 :
305 4650 : uint32_t cli_getpid(struct cli_state *cli)
306 : {
307 4650 : return cli->smb1.pid;
308 : }
309 :
310 0 : bool cli_state_is_encryption_on(struct cli_state *cli)
311 : {
312 0 : if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
313 0 : return smb1cli_conn_encryption_on(cli->conn);
314 : }
315 :
316 0 : if (cli->smb2.tcon == NULL) {
317 0 : return false;
318 : }
319 :
320 0 : return smb2cli_tcon_is_encryption_on(cli->smb2.tcon);
321 : }
322 :
323 33821 : bool cli_state_has_tcon(struct cli_state *cli)
324 : {
325 0 : uint32_t tid;
326 33821 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
327 26543 : if (cli->smb2.tcon == NULL) {
328 8005 : return false;
329 : }
330 18538 : tid = cli_state_get_tid(cli);
331 18538 : if (tid == UINT32_MAX) {
332 0 : return false;
333 : }
334 : } else {
335 7278 : if (cli->smb1.tcon == NULL) {
336 3967 : return false;
337 : }
338 3311 : tid = cli_state_get_tid(cli);
339 3311 : if (tid == UINT16_MAX) {
340 11 : return false;
341 : }
342 : }
343 21838 : return true;
344 : }
345 :
346 21878 : uint32_t cli_state_get_tid(struct cli_state *cli)
347 : {
348 21878 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
349 18538 : return smb2cli_tcon_current_id(cli->smb2.tcon);
350 : } else {
351 3340 : return (uint32_t)smb1cli_tcon_current_id(cli->smb1.tcon);
352 : }
353 : }
354 :
355 54 : uint32_t cli_state_set_tid(struct cli_state *cli, uint32_t tid)
356 : {
357 0 : uint32_t ret;
358 54 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
359 0 : ret = smb2cli_tcon_current_id(cli->smb2.tcon);
360 0 : smb2cli_tcon_set_id(cli->smb2.tcon, tid);
361 : } else {
362 54 : ret = smb1cli_tcon_current_id(cli->smb1.tcon);
363 54 : smb1cli_tcon_set_id(cli->smb1.tcon, tid);
364 : }
365 54 : return ret;
366 : }
367 :
368 8536 : static struct smbXcli_tcon *cli_state_save_tcon(struct cli_state *cli)
369 : {
370 : /*
371 : * Note. This used to make a deep copy of either
372 : * cli->smb2.tcon or cli->smb1.tcon, but this leaves
373 : * the original pointer in place which will then get
374 : * TALLOC_FREE()'d when the new connection is made on
375 : * this cli_state.
376 : *
377 : * As there may be pipes open on the old connection with
378 : * talloc'ed state allocated using the tcon pointer as a
379 : * parent we can't deep copy and then free this as that
380 : * closes the open pipes.
381 : *
382 : * This call is used to temporarily swap out a tcon pointer
383 : * to allow a new tcon on the same cli_state.
384 : *
385 : * Just return the raw pointer and set the old value to NULL.
386 : * We know we MUST be calling cli_state_restore_tcon() below
387 : * to restore before closing the session.
388 : *
389 : * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=13992
390 : */
391 8536 : struct smbXcli_tcon *tcon_ret = NULL;
392 :
393 8536 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
394 8409 : tcon_ret = cli->smb2.tcon;
395 8409 : cli->smb2.tcon = NULL; /* *Not* TALLOC_FREE(). */
396 : } else {
397 127 : tcon_ret = cli->smb1.tcon;
398 127 : cli->smb1.tcon = NULL; /* *Not* TALLOC_FREE(). */
399 : }
400 8536 : return tcon_ret;
401 : }
402 :
403 8536 : void cli_state_save_tcon_share(struct cli_state *cli,
404 : struct smbXcli_tcon **_tcon_ret,
405 : char **_sharename_ret)
406 : {
407 8536 : *_tcon_ret = cli_state_save_tcon(cli);
408 : /*
409 : * No talloc_copy as cli->share is already
410 : * allocated off cli.
411 : */
412 8536 : *_sharename_ret = cli->share;
413 8536 : cli->share = NULL;
414 8536 : }
415 :
416 19325 : static void cli_state_restore_tcon(struct cli_state *cli,
417 : struct smbXcli_tcon *tcon)
418 : {
419 19325 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
420 16070 : TALLOC_FREE(cli->smb2.tcon);
421 16070 : cli->smb2.tcon = tcon;
422 : } else {
423 3255 : TALLOC_FREE(cli->smb1.tcon);
424 3255 : cli->smb1.tcon = tcon;
425 : }
426 19325 : }
427 :
428 19325 : void cli_state_restore_tcon_share(struct cli_state *cli,
429 : struct smbXcli_tcon *tcon,
430 : char *share)
431 : {
432 : /* cli->share will have been replaced by a cli_tree_connect() call. */
433 19325 : TALLOC_FREE(cli->share);
434 19325 : cli->share = share;
435 19325 : cli_state_restore_tcon(cli, tcon);
436 19325 : }
437 :
438 34 : uint16_t cli_state_get_uid(struct cli_state *cli)
439 : {
440 34 : return smb1cli_session_current_id(cli->smb1.session);
441 : }
442 :
443 787 : uint16_t cli_state_set_uid(struct cli_state *cli, uint16_t uid)
444 : {
445 787 : uint16_t ret = smb1cli_session_current_id(cli->smb1.session);
446 787 : smb1cli_session_set_id(cli->smb1.session, uid);
447 787 : return ret;
448 : }
449 :
450 : /****************************************************************************
451 : Set the case sensitivity flag on the packets. Returns old state.
452 : ****************************************************************************/
453 :
454 0 : bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive)
455 : {
456 0 : bool ret;
457 0 : uint32_t fs_attrs;
458 0 : struct smbXcli_tcon *tcon;
459 :
460 0 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
461 0 : tcon = cli->smb2.tcon;
462 : } else {
463 0 : tcon = cli->smb1.tcon;
464 : }
465 :
466 0 : fs_attrs = smbXcli_tcon_get_fs_attributes(tcon);
467 0 : if (fs_attrs & FILE_CASE_SENSITIVE_SEARCH) {
468 0 : ret = true;
469 : } else {
470 0 : ret = false;
471 : }
472 0 : if (case_sensitive) {
473 0 : fs_attrs |= FILE_CASE_SENSITIVE_SEARCH;
474 : } else {
475 0 : fs_attrs &= ~FILE_CASE_SENSITIVE_SEARCH;
476 : }
477 0 : smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
478 :
479 0 : return ret;
480 : }
481 :
482 22177 : uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs)
483 : {
484 22177 : uint32_t ret = smb1cli_conn_max_xmit(cli->conn);
485 :
486 22177 : if (ofs >= ret) {
487 0 : return 0;
488 : }
489 :
490 22177 : ret -= ofs;
491 :
492 22177 : return ret;
493 : }
494 :
495 12 : time_t cli_state_server_time(struct cli_state *cli)
496 : {
497 0 : NTTIME nt;
498 0 : time_t t;
499 :
500 12 : nt = smbXcli_conn_server_system_time(cli->conn);
501 12 : t = nt_time_to_unix(nt);
502 :
503 12 : return t;
504 : }
505 :
506 : struct cli_echo_state {
507 : uint8_t dummy;
508 : };
509 :
510 : static void cli_echo_done1(struct tevent_req *subreq);
511 : static void cli_echo_done2(struct tevent_req *subreq);
512 :
513 121 : struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
514 : struct cli_state *cli, uint16_t num_echos,
515 : DATA_BLOB data)
516 : {
517 0 : struct tevent_req *req, *subreq;
518 0 : struct cli_echo_state *state;
519 :
520 121 : req = tevent_req_create(mem_ctx, &state, struct cli_echo_state);
521 121 : if (req == NULL) {
522 0 : return NULL;
523 : }
524 :
525 121 : if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
526 100 : subreq = smb2cli_echo_send(
527 100 : state, ev, cli->conn, cli->timeout);
528 100 : if (tevent_req_nomem(subreq, req)) {
529 0 : return tevent_req_post(req, ev);
530 : }
531 100 : tevent_req_set_callback(subreq, cli_echo_done2, req);
532 100 : return req;
533 : }
534 :
535 21 : subreq = smb1cli_echo_send(
536 21 : state, ev, cli->conn, cli->timeout, num_echos, data);
537 21 : if (tevent_req_nomem(subreq, req)) {
538 0 : return tevent_req_post(req, ev);
539 : }
540 21 : tevent_req_set_callback(subreq, cli_echo_done1, req);
541 :
542 21 : return req;
543 : }
544 :
545 21 : static void cli_echo_done1(struct tevent_req *subreq)
546 : {
547 21 : NTSTATUS status = smb1cli_echo_recv(subreq);
548 21 : return tevent_req_simple_finish_ntstatus(subreq, status);
549 : }
550 :
551 100 : static void cli_echo_done2(struct tevent_req *subreq)
552 : {
553 100 : NTSTATUS status = smb2cli_echo_recv(subreq);
554 100 : return tevent_req_simple_finish_ntstatus(subreq, status);
555 : }
556 :
557 : /**
558 : * Get the result out from an echo request
559 : * @param[in] req The async_req from cli_echo_send
560 : * @retval Did the server reply correctly?
561 : */
562 :
563 121 : NTSTATUS cli_echo_recv(struct tevent_req *req)
564 : {
565 121 : return tevent_req_simple_recv_ntstatus(req);
566 : }
567 :
568 : /**
569 : * @brief Send/Receive SMBEcho requests
570 : * @param[in] mem_ctx The memory context to put the async_req on
571 : * @param[in] ev The event context that will call us back
572 : * @param[in] cli The connection to send the echo to
573 : * @param[in] num_echos How many times do we want to get the reply?
574 : * @param[in] data The data we want to get back
575 : * @retval Did the server reply correctly?
576 : */
577 :
578 68 : NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
579 : {
580 68 : TALLOC_CTX *frame = talloc_stackframe();
581 0 : struct tevent_context *ev;
582 0 : struct tevent_req *req;
583 68 : NTSTATUS status = NT_STATUS_OK;
584 :
585 68 : if (smbXcli_conn_has_async_calls(cli->conn)) {
586 : /*
587 : * Can't use sync call while an async call is in flight
588 : */
589 0 : status = NT_STATUS_INVALID_PARAMETER;
590 0 : goto fail;
591 : }
592 :
593 68 : ev = samba_tevent_context_init(frame);
594 68 : if (ev == NULL) {
595 0 : status = NT_STATUS_NO_MEMORY;
596 0 : goto fail;
597 : }
598 :
599 68 : req = cli_echo_send(frame, ev, cli, num_echos, data);
600 68 : if (req == NULL) {
601 0 : status = NT_STATUS_NO_MEMORY;
602 0 : goto fail;
603 : }
604 :
605 68 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
606 0 : goto fail;
607 : }
608 :
609 68 : status = cli_echo_recv(req);
610 68 : fail:
611 68 : TALLOC_FREE(frame);
612 68 : return status;
613 : }
614 :
615 327834 : NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli,
616 : uint8_t smb_command, uint8_t additional_flags,
617 : uint8_t wct, uint16_t *vwv,
618 : uint32_t num_bytes, const uint8_t *bytes,
619 : struct tevent_req **result_parent,
620 : uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
621 : uint32_t *pnum_bytes, uint8_t **pbytes)
622 : {
623 0 : struct tevent_context *ev;
624 327834 : struct tevent_req *req = NULL;
625 327834 : NTSTATUS status = NT_STATUS_NO_MEMORY;
626 :
627 327834 : if (smbXcli_conn_has_async_calls(cli->conn)) {
628 0 : return NT_STATUS_INVALID_PARAMETER;
629 : }
630 327834 : ev = samba_tevent_context_init(mem_ctx);
631 327834 : if (ev == NULL) {
632 0 : goto fail;
633 : }
634 327834 : req = cli_smb_send(mem_ctx, ev, cli, smb_command, additional_flags, 0,
635 : wct, vwv, num_bytes, bytes);
636 327834 : if (req == NULL) {
637 0 : goto fail;
638 : }
639 327834 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
640 0 : goto fail;
641 : }
642 327834 : status = cli_smb_recv(req, NULL, NULL, min_wct, pwct, pvwv,
643 : pnum_bytes, pbytes);
644 327834 : fail:
645 327834 : TALLOC_FREE(ev);
646 327834 : if (NT_STATUS_IS_OK(status) && (result_parent != NULL)) {
647 109 : *result_parent = req;
648 : }
649 327834 : return status;
650 : }
|