s3: Remove use of iconv_convenience.
[vlendec/samba-autobuild/.git] / source3 / rpc_client / ndr.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    libndr interface
5
6    Copyright (C) Jelmer Vernooij 2006
7    Copyright (C) Volker Lendecke 2009
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24
25 struct cli_do_rpc_ndr_state {
26         const struct ndr_interface_call *call;
27         prs_struct q_ps, r_ps;
28         void *r;
29 };
30
31 static void cli_do_rpc_ndr_done(struct tevent_req *subreq);
32
33 struct tevent_req *cli_do_rpc_ndr_send(TALLOC_CTX *mem_ctx,
34                                        struct tevent_context *ev,
35                                        struct rpc_pipe_client *cli,
36                                        const struct ndr_interface_table *table,
37                                        uint32_t opnum,
38                                        void *r)
39 {
40         struct tevent_req *req, *subreq;
41         struct cli_do_rpc_ndr_state *state;
42         struct ndr_push *push;
43         DATA_BLOB blob;
44         enum ndr_err_code ndr_err;
45         bool ret;
46
47         req = tevent_req_create(mem_ctx, &state,
48                                 struct cli_do_rpc_ndr_state);
49         if (req == NULL) {
50                 return NULL;
51         }
52
53         if (!ndr_syntax_id_equal(&table->syntax_id, &cli->abstract_syntax)
54             || (opnum >= table->num_calls)) {
55                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
56                 return tevent_req_post(req, ev);
57         }
58
59         state->r = r;
60         state->call = &table->calls[opnum];
61
62         if (DEBUGLEVEL >= 10) {
63                 ndr_print_function_debug(state->call->ndr_print,
64                                          state->call->name, NDR_IN, r);
65         }
66
67         push = ndr_push_init_ctx(talloc_tos());
68         if (tevent_req_nomem(push, req)) {
69                 return tevent_req_post(req, ev);
70         }
71
72         ndr_err = state->call->ndr_push(push, NDR_IN, r);
73         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
74                 tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err));
75                 TALLOC_FREE(push);
76                 return tevent_req_post(req, ev);
77         }
78
79         blob = ndr_push_blob(push);
80         ret = prs_init_data_blob(&state->q_ps, &blob, state);
81         TALLOC_FREE(push);
82
83         if (!ret) {
84                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
85                 return tevent_req_post(req, ev);
86         }
87
88         subreq = rpc_api_pipe_req_send(state, ev, cli, opnum, &state->q_ps);
89         if (tevent_req_nomem(subreq, req)) {
90                 return tevent_req_post(req, ev);
91         }
92         tevent_req_set_callback(subreq, cli_do_rpc_ndr_done, req);
93         return req;
94 }
95
96 static void cli_do_rpc_ndr_done(struct tevent_req *subreq)
97 {
98         struct tevent_req *req = tevent_req_callback_data(
99                 subreq, struct tevent_req);
100         struct cli_do_rpc_ndr_state *state = tevent_req_data(
101                 req, struct cli_do_rpc_ndr_state);
102         NTSTATUS status;
103
104         status = rpc_api_pipe_req_recv(subreq, state, &state->r_ps);
105         TALLOC_FREE(subreq);
106         prs_mem_free(&state->q_ps);
107         if (!NT_STATUS_IS_OK(status)) {
108                 tevent_req_nterror(req, status);
109                 return;
110         }
111         tevent_req_done(req);
112 }
113
114 NTSTATUS cli_do_rpc_ndr_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
115 {
116         struct cli_do_rpc_ndr_state *state = tevent_req_data(
117                 req, struct cli_do_rpc_ndr_state);
118         struct ndr_pull *pull;
119         enum ndr_err_code ndr_err;
120         NTSTATUS status;
121         DATA_BLOB blob;
122         bool ret;
123
124         if (tevent_req_is_nterror(req, &status)) {
125                 return status;
126         }
127
128         ret = prs_data_blob(&state->r_ps, &blob, talloc_tos());
129         prs_mem_free(&state->r_ps);
130         if (!ret) {
131                 return NT_STATUS_NO_MEMORY;
132         }
133
134         pull = ndr_pull_init_blob(&blob, mem_ctx);
135         if (pull == NULL) {
136                 return NT_STATUS_NO_MEMORY;
137         }
138
139         /* have the ndr parser alloc memory for us */
140         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
141         ndr_err = state->call->ndr_pull(pull, NDR_OUT, state->r);
142         TALLOC_FREE(pull);
143
144         if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145                 if (DEBUGLEVEL >= 10) {
146                         ndr_print_function_debug(state->call->ndr_print,
147                                                  state->call->name, NDR_OUT,
148                                                  state->r);
149                 }
150         } else {
151                 return ndr_map_error2ntstatus(ndr_err);
152         }
153
154         return NT_STATUS_OK;
155 }
156
157 NTSTATUS cli_do_rpc_ndr(struct rpc_pipe_client *cli,
158                         TALLOC_CTX *mem_ctx,
159                         const struct ndr_interface_table *table,
160                         uint32_t opnum, void *r)
161 {
162         TALLOC_CTX *frame = talloc_stackframe();
163         struct event_context *ev;
164         struct tevent_req *req;
165         NTSTATUS status = NT_STATUS_OK;
166
167         ev = event_context_init(frame);
168         if (ev == NULL) {
169                 status = NT_STATUS_NO_MEMORY;
170                 goto fail;
171         }
172
173         req = cli_do_rpc_ndr_send(frame, ev, cli, table, opnum, r);
174         if (req == NULL) {
175                 status = NT_STATUS_NO_MEMORY;
176                 goto fail;
177         }
178
179         if (!tevent_req_poll(req, ev)) {
180                 status = map_nt_error_from_unix(errno);
181                 goto fail;
182         }
183
184         status = cli_do_rpc_ndr_recv(req, mem_ctx);
185
186  fail:
187         TALLOC_FREE(frame);
188         return status;
189 }