s3:libsmb: use local variables in cli_state_create()
[nivanova/samba-autobuild/.git] / source3 / libsmb / clientgen.c
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 "smb_signing.h"
25 #include "async_smb.h"
26
27 /*******************************************************************
28  Setup the word count and byte count for a client smb message.
29 ********************************************************************/
30
31 int cli_set_message(char *buf,int num_words,int num_bytes,bool zero)
32 {
33         if (zero && (num_words || num_bytes)) {
34                 memset(buf + smb_size,'\0',num_words*2 + num_bytes);
35         }
36         SCVAL(buf,smb_wct,num_words);
37         SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
38         smb_setlen(buf,smb_size + num_words*2 + num_bytes - 4);
39         return (smb_size + num_words*2 + num_bytes);
40 }
41
42 /****************************************************************************
43  Change the timeout (in milliseconds).
44 ****************************************************************************/
45
46 unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout)
47 {
48         unsigned int old_timeout = cli->timeout;
49         cli->timeout = timeout;
50         return old_timeout;
51 }
52
53 /****************************************************************************
54  convenience routine to find if we negotiated ucs2
55 ****************************************************************************/
56
57 bool cli_ucs2(struct cli_state *cli)
58 {
59         return ((cli_state_capabilities(cli) & CAP_UNICODE) != 0);
60 }
61
62 /****************************************************************************
63  Setup basics in a outgoing packet.
64 ****************************************************************************/
65
66 void cli_setup_packet_buf(struct cli_state *cli, char *buf)
67 {
68         uint16 flags2;
69         cli->rap_error = 0;
70         SIVAL(buf,smb_rcls,0);
71         SSVAL(buf,smb_pid,cli->smb1.pid);
72         memset(buf+smb_pidhigh, 0, 12);
73         SSVAL(buf,smb_uid, cli_state_get_uid(cli));
74         SSVAL(buf,smb_mid, 0);
75
76         if (cli_state_protocol(cli) <= PROTOCOL_CORE) {
77                 return;
78         }
79
80         if (cli->case_sensitive) {
81                 SCVAL(buf,smb_flg,0x0);
82         } else {
83                 /* Default setting, case insensitive. */
84                 SCVAL(buf,smb_flg,0x8);
85         }
86         flags2 = FLAGS2_LONG_PATH_COMPONENTS;
87         if (cli_state_capabilities(cli) & CAP_UNICODE)
88                 flags2 |= FLAGS2_UNICODE_STRINGS;
89         if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot)
90                 flags2 |= FLAGS2_DFS_PATHNAMES;
91         if (cli_state_capabilities(cli) & CAP_STATUS32)
92                 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
93         if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY)
94                 flags2 |= FLAGS2_EXTENDED_SECURITY;
95         SSVAL(buf,smb_flg2, flags2);
96 }
97
98 /****************************************************************************
99  Initialize Domain, user or password.
100 ****************************************************************************/
101
102 NTSTATUS cli_set_domain(struct cli_state *cli, const char *domain)
103 {
104         TALLOC_FREE(cli->domain);
105         cli->domain = talloc_strdup(cli, domain ? domain : "");
106         if (cli->domain == NULL) {
107                 return NT_STATUS_NO_MEMORY;
108         }
109         return NT_STATUS_OK;
110 }
111
112 NTSTATUS cli_set_username(struct cli_state *cli, const char *username)
113 {
114         TALLOC_FREE(cli->user_name);
115         cli->user_name = talloc_strdup(cli, username ? username : "");
116         if (cli->user_name == NULL) {
117                 return NT_STATUS_NO_MEMORY;
118         }
119         return NT_STATUS_OK;
120 }
121
122 NTSTATUS cli_set_password(struct cli_state *cli, const char *password)
123 {
124         TALLOC_FREE(cli->password);
125
126         /* Password can be NULL. */
127         if (password) {
128                 cli->password = talloc_strdup(cli, password);
129                 if (cli->password == NULL) {
130                         return NT_STATUS_NO_MEMORY;
131                 }
132         } else {
133                 /* Use zero NTLMSSP hashes and session key. */
134                 cli->password = NULL;
135         }
136
137         return NT_STATUS_OK;
138 }
139
140 /****************************************************************************
141  Initialise credentials of a client structure.
142 ****************************************************************************/
143
144 NTSTATUS cli_init_creds(struct cli_state *cli, const char *username, const char *domain, const char *password)
145 {
146         NTSTATUS status = cli_set_username(cli, username);
147         if (!NT_STATUS_IS_OK(status)) {
148                 return status;
149         }
150         status = cli_set_domain(cli, domain);
151         if (!NT_STATUS_IS_OK(status)) {
152                 return status;
153         }
154         DEBUG(10,("cli_init_creds: user %s domain %s\n", cli->user_name, cli->domain));
155
156         return cli_set_password(cli, password);
157 }
158
159 /****************************************************************************
160  Initialise a client structure. Always returns a talloc'ed struct.
161  Set the signing state (used from the command line).
162 ****************************************************************************/
163
164 struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx,
165                                    int fd,
166                                    const char *remote_name,
167                                    const char *remote_realm,
168                                    int signing_state, int flags)
169 {
170         struct cli_state *cli = NULL;
171         bool allow_smb_signing;
172         bool desire_smb_signing;
173         bool mandatory_signing;
174         socklen_t ss_length;
175         int ret;
176         bool use_spnego = lp_client_use_spnego();
177         bool force_dos_errors = false;
178         bool force_ascii = false;
179         bool use_level_II_oplocks = false;
180
181         /* Check the effective uid - make sure we are not setuid */
182         if (is_setuid_root()) {
183                 DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
184                 return NULL;
185         }
186
187         cli = talloc_zero(mem_ctx, struct cli_state);
188         if (!cli) {
189                 return NULL;
190         }
191
192         cli->dfs_mountpoint = talloc_strdup(cli, "");
193         if (!cli->dfs_mountpoint) {
194                 goto error;
195         }
196         cli->raw_status = NT_STATUS_INTERNAL_ERROR;
197         cli->protocol = PROTOCOL_NT1;
198         cli->timeout = 20000; /* Timeout is in milliseconds. */
199         cli->max_xmit = CLI_BUFFER_SIZE+4;
200         cli->case_sensitive = false;
201
202         /* Set the CLI_FORCE_DOSERR environment variable to test
203            client routines using DOS errors instead of STATUS32
204            ones.  This intended only as a temporary hack. */    
205         if (getenv("CLI_FORCE_DOSERR")) {
206                 force_dos_errors = true;
207         }
208         if (flags & CLI_FULL_CONNECTION_FORCE_DOS_ERRORS) {
209                 force_dos_errors = true;
210         }
211
212         if (getenv("CLI_FORCE_ASCII")) {
213                 force_ascii = true;
214         }
215         if (flags & CLI_FULL_CONNECTION_FORCE_ASCII) {
216                 force_ascii = true;
217         }
218
219         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
220                 use_spnego = false;
221         } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
222                 cli->use_kerberos = true;
223         }
224         if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
225              cli->use_kerberos) {
226                 cli->fallback_after_kerberos = true;
227         }
228
229         if (flags & CLI_FULL_CONNECTION_USE_CCACHE) {
230                 cli->use_ccache = true;
231         }
232
233         if (flags & CLI_FULL_CONNECTION_OPLOCKS) {
234                 cli->use_oplocks = true;
235         }
236         if (flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) {
237                 use_level_II_oplocks = true;
238         }
239
240         if (signing_state == Undefined) {
241                 signing_state = lp_client_signing();
242         }
243
244         switch (signing_state) {
245         case false:
246                 /* never */
247                 allow_smb_signing = false;
248                 desire_smb_signing = false;
249                 mandatory_signing = false;
250                 break;
251         case true:
252                 /* if the server supports it */
253                 allow_smb_signing = true;
254                 desire_smb_signing = true;
255                 mandatory_signing = false;
256                 break;
257         default:
258         case Undefined:
259         case Auto:
260                 /* if the server requires it */
261                 allow_smb_signing = true;
262                 desire_smb_signing = false;
263                 mandatory_signing = false;
264                 break;
265         case Required:
266                 /* always */
267                 allow_smb_signing = true;
268                 desire_smb_signing = true;
269                 mandatory_signing = true;
270                 break;
271         }
272
273         /* initialise signing */
274         cli->signing_state = smb_signing_init(cli,
275                                               allow_smb_signing,
276                                               desire_smb_signing,
277                                               mandatory_signing);
278         if (!cli->signing_state) {
279                 goto error;
280         }
281
282         cli->capabilities = 0;
283         cli->capabilities |= CAP_LARGE_FILES;
284         cli->capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
285         cli->capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND;
286         cli->capabilities |= CAP_DFS | CAP_W2K_SMBS;
287         cli->capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX;
288         cli->capabilities |= CAP_LWIO;
289
290         if (!force_dos_errors) {
291                 cli->capabilities |= CAP_STATUS32;
292         }
293
294         if (!force_ascii) {
295                 cli->capabilities |= CAP_UNICODE;
296         }
297
298         if (use_spnego) {
299                 cli->capabilities |= CAP_EXTENDED_SECURITY;
300         }
301
302         if (use_level_II_oplocks) {
303                 cli->capabilities |= CAP_LEVEL_II_OPLOCKS;
304         }
305
306         cli->conn.outgoing = tevent_queue_create(cli, "cli_outgoing");
307         if (cli->conn.outgoing == NULL) {
308                 goto error;
309         }
310         cli->conn.pending = NULL;
311
312         cli->conn.remote_name = talloc_strdup(cli, remote_name);
313         if (cli->conn.remote_name == NULL) {
314                 goto error;
315         }
316
317         if (remote_realm) {
318                 cli->conn.remote_realm = talloc_strdup(cli, remote_realm);
319                 if (cli->conn.remote_realm == NULL) {
320                         goto error;
321                 }
322         }
323
324         cli->conn.fd = fd;
325
326         ss_length = sizeof(cli->conn.local_ss);
327         ret = getsockname(fd,
328                           (struct sockaddr *)(void *)&cli->conn.local_ss,
329                           &ss_length);
330         if (ret == -1) {
331                 goto error;
332         }
333         ss_length = sizeof(cli->conn.remote_ss);
334         ret = getpeername(fd,
335                           (struct sockaddr *)(void *)&cli->conn.remote_ss,
336                           &ss_length);
337         if (ret == -1) {
338                 goto error;
339         }
340
341         cli->smb1.mid = 1;
342         cli->smb1.pid = (uint16_t)sys_getpid();
343         cli->smb1.vc_num = cli->smb1.pid;
344         cli->smb1.tid = UINT16_MAX;
345         cli->smb1.uid = UID_FIELD_INVALID;
346
347         cli->initialised = 1;
348         return cli;
349
350         /* Clean up after malloc() error */
351
352  error:
353
354         TALLOC_FREE(cli);
355         return NULL;
356 }
357
358 bool cli_state_encryption_on(struct cli_state *cli)
359 {
360         return common_encryption_on(cli->trans_enc_state);
361 }
362
363
364 /****************************************************************************
365  Close all pipes open on this session.
366 ****************************************************************************/
367
368 void cli_nt_pipes_close(struct cli_state *cli)
369 {
370         while (cli->pipe_list != NULL) {
371                 /*
372                  * No TALLOC_FREE here!
373                  */
374                 talloc_free(cli->pipe_list);
375         }
376 }
377
378 /****************************************************************************
379  Shutdown a client structure.
380 ****************************************************************************/
381
382 static void _cli_shutdown(struct cli_state *cli)
383 {
384         cli_nt_pipes_close(cli);
385
386         /*
387          * tell our peer to free his resources.  Wihtout this, when an
388          * application attempts to do a graceful shutdown and calls
389          * smbc_free_context() to clean up all connections, some connections
390          * can remain active on the peer end, until some (long) timeout period
391          * later.  This tree disconnect forces the peer to clean up, since the
392          * connection will be going away.
393          */
394         if (cli_state_has_tcon(cli)) {
395                 cli_tdis(cli);
396         }
397         
398         data_blob_free(&cli->secblob);
399         data_blob_free(&cli->user_session_key);
400
401         cli_state_disconnect(cli);
402
403         /*
404          * Need to free pending first, they remove themselves
405          */
406         while (cli->conn.pending) {
407                 talloc_free(cli->conn.pending[0]);
408         }
409         TALLOC_FREE(cli);
410 }
411
412 void cli_shutdown(struct cli_state *cli)
413 {
414         struct cli_state *cli_head;
415         if (cli == NULL) {
416                 return;
417         }
418         DLIST_HEAD(cli, cli_head);
419         if (cli_head == cli) {
420                 /*
421                  * head of a DFS list, shutdown all subsidiary DFS
422                  * connections.
423                  */
424                 struct cli_state *p, *next;
425
426                 for (p = cli_head->next; p; p = next) {
427                         next = p->next;
428                         DLIST_REMOVE(cli_head, p);
429                         _cli_shutdown(p);
430                 }
431         } else {
432                 DLIST_REMOVE(cli_head, cli);
433         }
434
435         _cli_shutdown(cli);
436 }
437
438 /****************************************************************************
439  Set socket options on a open connection.
440 ****************************************************************************/
441
442 void cli_sockopt(struct cli_state *cli, const char *options)
443 {
444         set_socket_options(cli->conn.fd, options);
445 }
446
447 const struct sockaddr_storage *cli_state_local_sockaddr(struct cli_state *cli)
448 {
449         return &cli->conn.local_ss;
450 }
451
452 const struct sockaddr_storage *cli_state_remote_sockaddr(struct cli_state *cli)
453 {
454         return &cli->conn.remote_ss;
455 }
456
457 const char *cli_state_remote_name(struct cli_state *cli)
458 {
459         return cli->conn.remote_name;
460 }
461
462 const char *cli_state_remote_realm(struct cli_state *cli)
463 {
464         return cli->conn.remote_realm;
465 }
466
467 uint16_t cli_state_get_vc_num(struct cli_state *cli)
468 {
469         return cli->smb1.vc_num;
470 }
471
472 uint32_t cli_state_server_session_key(struct cli_state *cli)
473 {
474         return cli->sesskey;
475 }
476
477 /****************************************************************************
478  Set the PID to use for smb messages. Return the old pid.
479 ****************************************************************************/
480
481 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
482 {
483         uint16_t ret = cli->smb1.pid;
484         cli->smb1.pid = pid;
485         return ret;
486 }
487
488 uint16_t cli_getpid(struct cli_state *cli)
489 {
490         return cli->smb1.pid;
491 }
492
493 bool cli_state_has_tcon(struct cli_state *cli)
494 {
495         if (cli->smb1.tid == UINT16_MAX) {
496                 return false;
497         }
498
499         return true;
500 }
501
502 uint16_t cli_state_get_tid(struct cli_state *cli)
503 {
504         return cli->smb1.tid;
505 }
506
507 uint16_t cli_state_set_tid(struct cli_state *cli, uint16_t tid)
508 {
509         uint16_t ret = cli->smb1.tid;
510         cli->smb1.tid = tid;
511         return ret;
512 }
513
514 uint16_t cli_state_get_uid(struct cli_state *cli)
515 {
516         return cli->smb1.uid;
517 }
518
519 uint16_t cli_state_set_uid(struct cli_state *cli, uint16_t uid)
520 {
521         uint16_t ret = cli->smb1.uid;
522         cli->smb1.uid = uid;
523         return ret;
524 }
525
526 /****************************************************************************
527  Set the case sensitivity flag on the packets. Returns old state.
528 ****************************************************************************/
529
530 bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive)
531 {
532         bool ret = cli->case_sensitive;
533         cli->case_sensitive = case_sensitive;
534         return ret;
535 }
536
537 enum protocol_types cli_state_protocol(struct cli_state *cli)
538 {
539         return cli->protocol;
540 }
541
542 uint32_t cli_state_capabilities(struct cli_state *cli)
543 {
544         return cli->capabilities;
545 }
546
547 uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs)
548 {
549         uint32_t ret = cli->max_xmit;
550
551         if (ofs >= ret) {
552                 return 0;
553         }
554
555         ret -= ofs;
556
557         return ret;
558 }
559
560 uint16_t cli_state_max_requests(struct cli_state *cli)
561 {
562         return cli->max_mux;
563 }
564
565 uint16_t cli_state_security_mode(struct cli_state *cli)
566 {
567         return cli->sec_mode;
568 }
569
570 int cli_state_server_time_zone(struct cli_state *cli)
571 {
572         return cli->serverzone;
573 }
574
575 time_t cli_state_server_time(struct cli_state *cli)
576 {
577         return cli->servertime;
578 }
579
580 struct cli_echo_state {
581         uint16_t vwv[1];
582         DATA_BLOB data;
583         int num_echos;
584 };
585
586 static void cli_echo_done(struct tevent_req *subreq);
587
588 struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev,
589                                  struct cli_state *cli, uint16_t num_echos,
590                                  DATA_BLOB data)
591 {
592         struct tevent_req *req, *subreq;
593         struct cli_echo_state *state;
594
595         req = tevent_req_create(mem_ctx, &state, struct cli_echo_state);
596         if (req == NULL) {
597                 return NULL;
598         }
599         SSVAL(state->vwv, 0, num_echos);
600         state->data = data;
601         state->num_echos = num_echos;
602
603         subreq = cli_smb_send(state, ev, cli, SMBecho, 0, 1, state->vwv,
604                               data.length, data.data);
605         if (subreq == NULL) {
606                 goto fail;
607         }
608         tevent_req_set_callback(subreq, cli_echo_done, req);
609         return req;
610  fail:
611         TALLOC_FREE(req);
612         return NULL;
613 }
614
615 static void cli_echo_done(struct tevent_req *subreq)
616 {
617         struct tevent_req *req = tevent_req_callback_data(
618                 subreq, struct tevent_req);
619         struct cli_echo_state *state = tevent_req_data(
620                 req, struct cli_echo_state);
621         NTSTATUS status;
622         uint32_t num_bytes;
623         uint8_t *bytes;
624         uint8_t *inbuf;
625
626         status = cli_smb_recv(subreq, state, &inbuf, 0, NULL, NULL,
627                               &num_bytes, &bytes);
628         if (!NT_STATUS_IS_OK(status)) {
629                 tevent_req_nterror(req, status);
630                 return;
631         }
632         if ((num_bytes != state->data.length)
633             || (memcmp(bytes, state->data.data, num_bytes) != 0)) {
634                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
635                 return;
636         }
637
638         state->num_echos -=1;
639         if (state->num_echos == 0) {
640                 tevent_req_done(req);
641                 return;
642         }
643
644         if (!cli_smb_req_set_pending(subreq)) {
645                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
646                 return;
647         }
648 }
649
650 /**
651  * Get the result out from an echo request
652  * @param[in] req       The async_req from cli_echo_send
653  * @retval Did the server reply correctly?
654  */
655
656 NTSTATUS cli_echo_recv(struct tevent_req *req)
657 {
658         return tevent_req_simple_recv_ntstatus(req);
659 }
660
661 /**
662  * @brief Send/Receive SMBEcho requests
663  * @param[in] mem_ctx   The memory context to put the async_req on
664  * @param[in] ev        The event context that will call us back
665  * @param[in] cli       The connection to send the echo to
666  * @param[in] num_echos How many times do we want to get the reply?
667  * @param[in] data      The data we want to get back
668  * @retval Did the server reply correctly?
669  */
670
671 NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data)
672 {
673         TALLOC_CTX *frame = talloc_stackframe();
674         struct event_context *ev;
675         struct tevent_req *req;
676         NTSTATUS status = NT_STATUS_OK;
677
678         if (cli_has_async_calls(cli)) {
679                 /*
680                  * Can't use sync call while an async call is in flight
681                  */
682                 status = NT_STATUS_INVALID_PARAMETER;
683                 goto fail;
684         }
685
686         ev = event_context_init(frame);
687         if (ev == NULL) {
688                 status = NT_STATUS_NO_MEMORY;
689                 goto fail;
690         }
691
692         req = cli_echo_send(frame, ev, cli, num_echos, data);
693         if (req == NULL) {
694                 status = NT_STATUS_NO_MEMORY;
695                 goto fail;
696         }
697
698         if (!tevent_req_poll(req, ev)) {
699                 status = map_nt_error_from_unix(errno);
700                 goto fail;
701         }
702
703         status = cli_echo_recv(req);
704  fail:
705         TALLOC_FREE(frame);
706         return status;
707 }
708
709 /**
710  * Is the SMB command able to hold an AND_X successor
711  * @param[in] cmd       The SMB command in question
712  * @retval Can we add a chained request after "cmd"?
713  */
714 bool is_andx_req(uint8_t cmd)
715 {
716         switch (cmd) {
717         case SMBtconX:
718         case SMBlockingX:
719         case SMBopenX:
720         case SMBreadX:
721         case SMBwriteX:
722         case SMBsesssetupX:
723         case SMBulogoffX:
724         case SMBntcreateX:
725                 return true;
726                 break;
727         default:
728                 break;
729         }
730
731         return false;
732 }
733
734 NTSTATUS cli_smb(TALLOC_CTX *mem_ctx, struct cli_state *cli,
735                  uint8_t smb_command, uint8_t additional_flags,
736                  uint8_t wct, uint16_t *vwv,
737                  uint32_t num_bytes, const uint8_t *bytes,
738                  struct tevent_req **result_parent,
739                  uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
740                  uint32_t *pnum_bytes, uint8_t **pbytes)
741 {
742         struct tevent_context *ev;
743         struct tevent_req *req = NULL;
744         NTSTATUS status = NT_STATUS_NO_MEMORY;
745
746         if (cli_has_async_calls(cli)) {
747                 return NT_STATUS_INVALID_PARAMETER;
748         }
749         ev = tevent_context_init(mem_ctx);
750         if (ev == NULL) {
751                 goto fail;
752         }
753         req = cli_smb_send(mem_ctx, ev, cli, smb_command, additional_flags,
754                            wct, vwv, num_bytes, bytes);
755         if (req == NULL) {
756                 goto fail;
757         }
758         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
759                 goto fail;
760         }
761         status = cli_smb_recv(req, NULL, NULL, min_wct, pwct, pvwv,
762                               pnum_bytes, pbytes);
763 fail:
764         TALLOC_FREE(ev);
765         if (NT_STATUS_IS_OK(status) && (result_parent != NULL)) {
766                 *result_parent = req;
767         }
768         return status;
769 }