44dafa7e43f2537bca7affe6356ffe4339b58b6f
[samba.git] / source3 / libsmb / clitrans.c
1 /*
2    Unix SMB/CIFS implementation.
3    client transaction calls
4    Copyright (C) Andrew Tridgell 1994-1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24
25 struct trans_recvblob {
26         uint8_t *data;
27         uint32_t max, total, received;
28 };
29
30 struct cli_trans_state {
31         struct cli_state *cli;
32         struct event_context *ev;
33         uint8_t cmd;
34         uint16_t mid;
35         uint32_t seqnum;
36         const char *pipe_name;
37         uint8_t *pipe_name_conv;
38         size_t pipe_name_conv_len;
39         uint16_t fid;
40         uint16_t function;
41         int flags;
42         uint16_t *setup;
43         uint8_t num_setup, max_setup;
44         uint8_t *param;
45         uint32_t num_param, param_sent;
46         uint8_t *data;
47         uint32_t num_data, data_sent;
48
49         uint8_t num_rsetup;
50         uint16_t *rsetup;
51         struct trans_recvblob rparam;
52         struct trans_recvblob rdata;
53         uint16_t recv_flags2;
54
55         TALLOC_CTX *secondary_request_ctx;
56
57         struct iovec iov[4];
58         uint8_t pad[4];
59         uint16_t vwv[32];
60 };
61
62 static NTSTATUS cli_pull_trans(uint8_t *inbuf,
63                                uint8_t wct, uint16_t *vwv,
64                                uint16_t num_bytes, uint8_t *bytes,
65                                uint8_t smb_cmd, bool expect_first_reply,
66                                uint8_t *pnum_setup, uint16_t **psetup,
67                                uint32_t *ptotal_param, uint32_t *pnum_param,
68                                uint32_t *pparam_disp, uint8_t **pparam,
69                                uint32_t *ptotal_data, uint32_t *pnum_data,
70                                uint32_t *pdata_disp, uint8_t **pdata)
71 {
72         uint32_t param_ofs, data_ofs;
73
74         if (expect_first_reply) {
75                 if ((wct != 0) || (num_bytes != 0)) {
76                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
77                 }
78                 return NT_STATUS_OK;
79         }
80
81         switch (smb_cmd) {
82         case SMBtrans:
83         case SMBtrans2:
84                 if (wct < 10) {
85                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
86                 }
87                 *ptotal_param   = SVAL(vwv + 0, 0);
88                 *ptotal_data    = SVAL(vwv + 1, 0);
89                 *pnum_param     = SVAL(vwv + 3, 0);
90                 param_ofs       = SVAL(vwv + 4, 0);
91                 *pparam_disp    = SVAL(vwv + 5, 0);
92                 *pnum_data      = SVAL(vwv + 6, 0);
93                 data_ofs        = SVAL(vwv + 7, 0);
94                 *pdata_disp     = SVAL(vwv + 8, 0);
95                 *pnum_setup     = CVAL(vwv + 9, 0);
96                 if (wct < 10 + (*pnum_setup)) {
97                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
98                 }
99                 *psetup = vwv + 10;
100
101                 break;
102         case SMBnttrans:
103                 if (wct < 18) {
104                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
105                 }
106                 *ptotal_param   = IVAL(vwv, 3);
107                 *ptotal_data    = IVAL(vwv, 7);
108                 *pnum_param     = IVAL(vwv, 11);
109                 param_ofs       = IVAL(vwv, 15);
110                 *pparam_disp    = IVAL(vwv, 19);
111                 *pnum_data      = IVAL(vwv, 23);
112                 data_ofs        = IVAL(vwv, 27);
113                 *pdata_disp     = IVAL(vwv, 31);
114                 *pnum_setup     = CVAL(vwv, 35);
115                 *psetup         = vwv + 18;
116                 break;
117
118         default:
119                 return NT_STATUS_INTERNAL_ERROR;
120         }
121
122         /*
123          * Check for buffer overflows. data_ofs needs to be checked against
124          * the incoming buffer length, data_disp against the total
125          * length. Likewise for param_ofs/param_disp.
126          */
127
128         if (trans_oob(smb_len(inbuf), param_ofs, *pnum_param)
129             || trans_oob(*ptotal_param, *pparam_disp, *pnum_param)
130             || trans_oob(smb_len(inbuf), data_ofs, *pnum_data)
131             || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
132                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
133         }
134
135         *pparam = (uint8_t *)inbuf + 4 + param_ofs;
136         *pdata = (uint8_t *)inbuf + 4 + data_ofs;
137
138         return NT_STATUS_OK;
139 }
140
141 static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
142                                     struct trans_recvblob *blob,
143                                     uint32_t total, uint32_t thistime,
144                                     uint8_t *buf, uint32_t displacement)
145 {
146         if (blob->data == NULL) {
147                 if (total > blob->max) {
148                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
149                 }
150                 blob->total = total;
151                 blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total);
152                 if (blob->data == NULL) {
153                         return NT_STATUS_NO_MEMORY;
154                 }
155         }
156
157         if (total > blob->total) {
158                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
159         }
160
161         if (thistime) {
162                 memcpy(blob->data + displacement, buf, thistime);
163                 blob->received += thistime;
164         }
165
166         return NT_STATUS_OK;
167 }
168
169 static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct,
170                              int *piov_count)
171 {
172         uint8_t wct = 0;
173         struct iovec *iov = state->iov;
174         uint8_t *pad = state->pad;
175         uint16_t *vwv = state->vwv;
176         uint16_t param_offset;
177         uint16_t this_param = 0;
178         uint16_t this_data = 0;
179         uint32_t useable_space;
180         uint8_t cmd;
181
182         cmd = state->cmd;
183
184         if ((state->param_sent != 0) || (state->data_sent != 0)) {
185                 /* The secondary commands are one after the primary ones */
186                 cmd += 1;
187         }
188
189         param_offset = smb_size - 4;
190
191         switch (cmd) {
192         case SMBtrans:
193                 pad[0] = 0;
194                 iov[0].iov_base = (void *)pad;
195                 iov[0].iov_len = 1;
196                 iov[1].iov_base = (void *)state->pipe_name_conv;
197                 iov[1].iov_len = state->pipe_name_conv_len;
198                 wct = 14 + state->num_setup;
199                 param_offset += iov[0].iov_len + iov[1].iov_len;
200                 iov += 2;
201                 break;
202         case SMBtrans2:
203                 pad[0] = 0;
204                 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
205                 pad[2] = ' ';
206                 iov[0].iov_base = (void *)pad;
207                 iov[0].iov_len = 3;
208                 wct = 14 + state->num_setup;
209                 param_offset += 3;
210                 iov += 1;
211                 break;
212         case SMBtranss:
213                 wct = 8;
214                 break;
215         case SMBtranss2:
216                 wct = 9;
217                 break;
218         case SMBnttrans:
219                 wct = 19 + state->num_setup;
220                 break;
221         case SMBnttranss:
222                 wct = 18;
223                 break;
224         }
225
226         useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct;
227
228         if (state->param_sent < state->num_param) {
229                 this_param = MIN(state->num_param - state->param_sent,
230                                  useable_space);
231                 iov[0].iov_base = (void *)(state->param + state->param_sent);
232                 iov[0].iov_len = this_param;
233                 iov += 1;
234         }
235
236         if (state->data_sent < state->num_data) {
237                 this_data = MIN(state->num_data - state->data_sent,
238                                 useable_space - this_param);
239                 iov[0].iov_base = (void *)(state->data + state->data_sent);
240                 iov[0].iov_len = this_data;
241                 iov += 1;
242         }
243
244         param_offset += wct * sizeof(uint16_t);
245
246         DEBUG(10, ("num_setup=%u, max_setup=%u, "
247                    "param_total=%u, this_param=%u, max_param=%u, "
248                    "data_total=%u, this_data=%u, max_data=%u, "
249                    "param_offset=%u, param_disp=%u, data_disp=%u\n",
250                    (unsigned)state->num_setup, (unsigned)state->max_setup,
251                    (unsigned)state->num_param, (unsigned)this_param,
252                    (unsigned)state->rparam.max,
253                    (unsigned)state->num_data, (unsigned)this_data,
254                    (unsigned)state->rdata.max,
255                    (unsigned)param_offset,
256                    (unsigned)state->param_sent, (unsigned)state->data_sent));
257
258         switch (cmd) {
259         case SMBtrans:
260         case SMBtrans2:
261                 SSVAL(vwv + 0, 0, state->num_param);
262                 SSVAL(vwv + 1, 0, state->num_data);
263                 SSVAL(vwv + 2, 0, state->rparam.max);
264                 SSVAL(vwv + 3, 0, state->rdata.max);
265                 SCVAL(vwv + 4, 0, state->max_setup);
266                 SCVAL(vwv + 4, 1, 0);   /* reserved */
267                 SSVAL(vwv + 5, 0, state->flags);
268                 SIVAL(vwv + 6, 0, 0);   /* timeout */
269                 SSVAL(vwv + 8, 0, 0);   /* reserved */
270                 SSVAL(vwv + 9, 0, this_param);
271                 SSVAL(vwv +10, 0, param_offset);
272                 SSVAL(vwv +11, 0, this_data);
273                 SSVAL(vwv +12, 0, param_offset + this_param);
274                 SCVAL(vwv +13, 0, state->num_setup);
275                 SCVAL(vwv +13, 1, 0);   /* reserved */
276                 memcpy(vwv + 14, state->setup,
277                        sizeof(uint16_t) * state->num_setup);
278                 break;
279         case SMBtranss:
280         case SMBtranss2:
281                 SSVAL(vwv + 0, 0, state->num_param);
282                 SSVAL(vwv + 1, 0, state->num_data);
283                 SSVAL(vwv + 2, 0, this_param);
284                 SSVAL(vwv + 3, 0, param_offset);
285                 SSVAL(vwv + 4, 0, state->param_sent);
286                 SSVAL(vwv + 5, 0, this_data);
287                 SSVAL(vwv + 6, 0, param_offset + this_param);
288                 SSVAL(vwv + 7, 0, state->data_sent);
289                 if (cmd == SMBtranss2) {
290                         SSVAL(vwv + 8, 0, state->fid);
291                 }
292                 break;
293         case SMBnttrans:
294                 SCVAL(vwv,  0, state->max_setup);
295                 SSVAL(vwv,  1, 0); /* reserved */
296                 SIVAL(vwv,  3, state->num_param);
297                 SIVAL(vwv,  7, state->num_data);
298                 SIVAL(vwv, 11, state->rparam.max);
299                 SIVAL(vwv, 15, state->rdata.max);
300                 SIVAL(vwv, 19, this_param);
301                 SIVAL(vwv, 23, param_offset);
302                 SIVAL(vwv, 27, this_data);
303                 SIVAL(vwv, 31, param_offset + this_param);
304                 SCVAL(vwv, 35, state->num_setup);
305                 SSVAL(vwv, 36, state->function);
306                 memcpy(vwv + 19, state->setup,
307                        sizeof(uint16_t) * state->num_setup);
308                 break;
309         case SMBnttranss:
310                 SSVAL(vwv,  0, 0); /* reserved */
311                 SCVAL(vwv,  2, 0); /* reserved */
312                 SIVAL(vwv,  3, state->num_param);
313                 SIVAL(vwv,  7, state->num_data);
314                 SIVAL(vwv, 11, this_param);
315                 SIVAL(vwv, 15, param_offset);
316                 SIVAL(vwv, 19, state->param_sent);
317                 SIVAL(vwv, 23, this_data);
318                 SIVAL(vwv, 27, param_offset + this_param);
319                 SIVAL(vwv, 31, state->data_sent);
320                 SCVAL(vwv, 35, 0); /* reserved */
321                 break;
322         }
323
324         state->param_sent += this_param;
325         state->data_sent += this_data;
326
327         *pwct = wct;
328         *piov_count = iov - state->iov;
329 }
330
331 static void cli_trans_done(struct tevent_req *subreq);
332
333 struct tevent_req *cli_trans_send(
334         TALLOC_CTX *mem_ctx, struct event_context *ev,
335         struct cli_state *cli, uint8_t cmd,
336         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
337         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
338         uint8_t *param, uint32_t num_param, uint32_t max_param,
339         uint8_t *data, uint32_t num_data, uint32_t max_data)
340 {
341         struct tevent_req *req, *subreq;
342         struct cli_trans_state *state;
343         int iov_count;
344         uint8_t wct;
345         NTSTATUS status;
346
347         req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
348         if (req == NULL) {
349                 return NULL;
350         }
351
352         if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
353                 if ((num_param > 0xffff) || (max_param > 0xffff)
354                     || (num_data > 0xffff) || (max_data > 0xffff)) {
355                         DEBUG(3, ("Attempt to send invalid trans2 request "
356                                   "(setup %u, params %u/%u, data %u/%u)\n",
357                                   (unsigned)num_setup,
358                                   (unsigned)num_param, (unsigned)max_param,
359                                   (unsigned)num_data, (unsigned)max_data));
360                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
361                         return tevent_req_post(req, ev);
362                 }
363         }
364
365         /*
366          * The largest wct will be for nttrans (19+num_setup). Make sure we
367          * don't overflow state->vwv in cli_trans_format.
368          */
369
370         if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
371                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
372                 return tevent_req_post(req, ev);
373         }
374
375         state->cli = cli;
376         state->ev = ev;
377         state->cmd = cmd;
378         state->flags = flags;
379         state->num_rsetup = 0;
380         state->rsetup = NULL;
381         ZERO_STRUCT(state->rparam);
382         ZERO_STRUCT(state->rdata);
383
384         if ((pipe_name != NULL)
385             && (!convert_string_talloc(state, CH_UNIX,
386                                        cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
387                                        pipe_name, strlen(pipe_name) + 1,
388                                        &state->pipe_name_conv,
389                                        &state->pipe_name_conv_len))) {
390                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
391                 return tevent_req_post(req, ev);
392         }
393         state->fid = fid;       /* trans2 */
394         state->function = function; /* nttrans */
395
396         state->setup = setup;
397         state->num_setup = num_setup;
398         state->max_setup = max_setup;
399
400         state->param = param;
401         state->num_param = num_param;
402         state->param_sent = 0;
403         state->rparam.max = max_param;
404
405         state->data = data;
406         state->num_data = num_data;
407         state->data_sent = 0;
408         state->rdata.max = max_data;
409
410         cli_trans_format(state, &wct, &iov_count);
411
412         subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv,
413                                     iov_count, state->iov);
414         if (tevent_req_nomem(subreq, req)) {
415                 return tevent_req_post(req, ev);
416         }
417         state->mid = cli_smb_req_mid(subreq);
418         status = cli_smb_req_send(subreq);
419         if (!NT_STATUS_IS_OK(status)) {
420                 tevent_req_nterror(req, status);
421                 return tevent_req_post(req, state->ev);
422         }
423         cli_state_seqnum_persistent(cli, state->mid);
424         tevent_req_set_callback(subreq, cli_trans_done, req);
425         return req;
426 }
427
428 static void cli_trans_done(struct tevent_req *subreq)
429 {
430         struct tevent_req *req = tevent_req_callback_data(
431                 subreq, struct tevent_req);
432         struct cli_trans_state *state = tevent_req_data(
433                 req, struct cli_trans_state);
434         NTSTATUS status;
435         bool sent_all;
436         uint8_t wct;
437         uint16_t *vwv;
438         uint32_t num_bytes;
439         uint8_t *bytes;
440         uint8_t *inbuf;
441         uint8_t num_setup       = 0;
442         uint16_t *setup         = NULL;
443         uint32_t total_param    = 0;
444         uint32_t num_param      = 0;
445         uint32_t param_disp     = 0;
446         uint32_t total_data     = 0;
447         uint32_t num_data       = 0;
448         uint32_t data_disp      = 0;
449         uint8_t *param          = NULL;
450         uint8_t *data           = NULL;
451
452         status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
453                               &num_bytes, &bytes);
454         /*
455          * Do not TALLOC_FREE(subreq) here, we might receive more than
456          * one response for the same mid.
457          */
458
459         /*
460          * We can receive something like STATUS_MORE_ENTRIES, so don't use
461          * !NT_STATUS_IS_OK(status) here.
462          */
463
464         if (NT_STATUS_IS_ERR(status)) {
465                 goto fail;
466         }
467
468         sent_all = ((state->param_sent == state->num_param)
469                     && (state->data_sent == state->num_data));
470
471         status = cli_pull_trans(
472                 inbuf, wct, vwv, num_bytes, bytes,
473                 state->cmd, !sent_all, &num_setup, &setup,
474                 &total_param, &num_param, &param_disp, &param,
475                 &total_data, &num_data, &data_disp, &data);
476
477         if (!NT_STATUS_IS_OK(status)) {
478                 goto fail;
479         }
480
481         if (!sent_all) {
482                 int iov_count;
483
484                 TALLOC_FREE(subreq);
485
486                 cli_trans_format(state, &wct, &iov_count);
487
488                 subreq = cli_smb_req_create(state, state->ev, state->cli,
489                                             state->cmd + 1, 0, wct, state->vwv,
490                                             iov_count, state->iov);
491                 if (tevent_req_nomem(subreq, req)) {
492                         return;
493                 }
494                 cli_smb_req_set_mid(subreq, state->mid);
495
496                 status = cli_smb_req_send(subreq);
497
498                 if (!NT_STATUS_IS_OK(status)) {
499                         goto fail;
500                 }
501                 tevent_req_set_callback(subreq, cli_trans_done, req);
502                 return;
503         }
504
505         status = cli_trans_pull_blob(
506                 state, &state->rparam, total_param, num_param, param,
507                 param_disp);
508
509         if (!NT_STATUS_IS_OK(status)) {
510                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
511                 goto fail;
512         }
513
514         status = cli_trans_pull_blob(
515                 state, &state->rdata, total_data, num_data, data,
516                 data_disp);
517
518         if (!NT_STATUS_IS_OK(status)) {
519                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
520                 goto fail;
521         }
522
523         if ((state->rparam.total == state->rparam.received)
524             && (state->rdata.total == state->rdata.received)) {
525                 state->recv_flags2 = SVAL(inbuf, smb_flg2);
526                 TALLOC_FREE(subreq);
527                 cli_state_seqnum_remove(state->cli, state->mid);
528                 tevent_req_done(req);
529                 return;
530         }
531
532         TALLOC_FREE(inbuf);
533
534         if (!cli_smb_req_set_pending(subreq)) {
535                 status = NT_STATUS_NO_MEMORY;
536                 goto fail;
537         }
538         return;
539
540  fail:
541         cli_state_seqnum_remove(state->cli, state->mid);
542         TALLOC_FREE(subreq);
543         tevent_req_nterror(req, status);
544 }
545
546 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
547                         uint16_t *recv_flags2,
548                         uint16_t **setup, uint8_t min_setup,
549                         uint8_t *num_setup,
550                         uint8_t **param, uint32_t min_param,
551                         uint32_t *num_param,
552                         uint8_t **data, uint32_t min_data,
553                         uint32_t *num_data)
554 {
555         struct cli_trans_state *state = tevent_req_data(
556                 req, struct cli_trans_state);
557         NTSTATUS status;
558
559         if (tevent_req_is_nterror(req, &status)) {
560                 return status;
561         }
562
563         if ((state->num_rsetup < min_setup)
564             || (state->rparam.total < min_param)
565             || (state->rdata.total < min_data)) {
566                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
567         }
568
569         if (recv_flags2 != NULL) {
570                 *recv_flags2 = state->recv_flags2;
571         }
572
573         if (setup != NULL) {
574                 *setup = talloc_move(mem_ctx, &state->rsetup);
575                 *num_setup = state->num_rsetup;
576         } else {
577                 TALLOC_FREE(state->rsetup);
578         }
579
580         if (param != NULL) {
581                 *param = talloc_move(mem_ctx, &state->rparam.data);
582                 *num_param = state->rparam.total;
583         } else {
584                 TALLOC_FREE(state->rparam.data);
585         }
586
587         if (data != NULL) {
588                 *data = talloc_move(mem_ctx, &state->rdata.data);
589                 *num_data = state->rdata.total;
590         } else {
591                 TALLOC_FREE(state->rdata.data);
592         }
593
594         return NT_STATUS_OK;
595 }
596
597 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
598                    uint8_t trans_cmd,
599                    const char *pipe_name, uint16_t fid, uint16_t function,
600                    int flags,
601                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
602                    uint8_t *param, uint32_t num_param, uint32_t max_param,
603                    uint8_t *data, uint32_t num_data, uint32_t max_data,
604                    uint16_t *recv_flags2,
605                    uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
606                    uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
607                    uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
608 {
609         TALLOC_CTX *frame = talloc_stackframe();
610         struct event_context *ev;
611         struct tevent_req *req;
612         NTSTATUS status = NT_STATUS_OK;
613
614         if (cli_has_async_calls(cli)) {
615                 /*
616                  * Can't use sync call while an async call is in flight
617                  */
618                 status = NT_STATUS_INVALID_PARAMETER;
619                 goto fail;
620         }
621
622         ev = event_context_init(frame);
623         if (ev == NULL) {
624                 status = NT_STATUS_NO_MEMORY;
625                 goto fail;
626         }
627
628         req = cli_trans_send(frame, ev, cli, trans_cmd,
629                              pipe_name, fid, function, flags,
630                              setup, num_setup, max_setup,
631                              param, num_param, max_param,
632                              data, num_data, max_data);
633         if (req == NULL) {
634                 status = NT_STATUS_NO_MEMORY;
635                 goto fail;
636         }
637
638         if (!tevent_req_poll(req, ev)) {
639                 status = map_nt_error_from_unix(errno);
640                 goto fail;
641         }
642
643         status = cli_trans_recv(req, mem_ctx, recv_flags2,
644                                 rsetup, min_rsetup, num_rsetup,
645                                 rparam, min_rparam, num_rparam,
646                                 rdata, min_rdata, num_rdata);
647  fail:
648         TALLOC_FREE(frame);
649         return status;
650 }