s3:rpc_client: add rpccli_is_connected()
[Samba/gebeck_regimport.git] / source3 / rpc_client / rpc_transport_np.c
blob0fe3d026e2a80a5f13bfdb4800811276f38d5dab
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC client transport over named pipes
4 * Copyright (C) Volker Lendecke 2009
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.
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.
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/>.
20 #include "includes.h"
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_RPC_CLI
25 struct rpc_transport_np_state {
26 struct cli_state *cli;
27 const char *pipe_name;
28 uint16_t fnum;
31 static bool rpc_np_is_connected(void *priv)
33 struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
34 priv, struct rpc_transport_np_state);
35 bool ok;
37 if (np_transport->cli == NULL) {
38 return false;
41 ok = cli_state_is_connected(np_transport->cli);
42 if (!ok) {
43 np_transport->cli = NULL;
44 return false;
47 return true;
50 static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s)
52 if (!rpc_np_is_connected(s)) {
53 DEBUG(10, ("socket was closed, no need to send close request.\n"));
54 return 0;
57 /* TODO: do not use a sync call with a destructor!!! */
58 if (!NT_STATUS_IS_OK(cli_close(s->cli, s->fnum))) {
59 DEBUG(1, ("rpc_transport_np_state_destructor: cli_close "
60 "failed on pipe %s. Error was %s\n", s->pipe_name,
61 cli_errstr(s->cli)));
63 DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name));
65 * We can't do much on failure
67 return 0;
70 struct rpc_np_write_state {
71 struct rpc_transport_np_state *np_transport;
72 size_t size;
73 size_t written;
76 static void rpc_np_write_done(struct tevent_req *subreq);
78 static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx,
79 struct event_context *ev,
80 const uint8_t *data, size_t size,
81 void *priv)
83 struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
84 priv, struct rpc_transport_np_state);
85 struct tevent_req *req, *subreq;
86 struct rpc_np_write_state *state;
87 bool ok;
89 req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state);
90 if (req == NULL) {
91 return NULL;
94 ok = rpc_np_is_connected(np_transport);
95 if (!ok) {
96 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
97 return tevent_req_post(req, ev);
100 state->np_transport = np_transport;
101 state->size = size;
104 subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli,
105 np_transport->fnum,
106 8, /* 8 means message mode. */
107 data, 0, size);
108 if (tevent_req_nomem(subreq, req)) {
109 return tevent_req_post(req, ev);
111 tevent_req_set_callback(subreq, rpc_np_write_done, req);
112 return req;
115 static void rpc_np_write_done(struct tevent_req *subreq)
117 struct tevent_req *req = tevent_req_callback_data(
118 subreq, struct tevent_req);
119 struct rpc_np_write_state *state = tevent_req_data(
120 req, struct rpc_np_write_state);
121 NTSTATUS status;
123 status = cli_write_andx_recv(subreq, &state->written);
124 TALLOC_FREE(subreq);
125 if (!NT_STATUS_IS_OK(status)) {
126 state->np_transport->cli = NULL;
127 tevent_req_nterror(req, status);
128 return;
130 tevent_req_done(req);
133 static NTSTATUS rpc_np_write_recv(struct tevent_req *req, ssize_t *pwritten)
135 struct rpc_np_write_state *state = tevent_req_data(
136 req, struct rpc_np_write_state);
137 NTSTATUS status;
139 if (tevent_req_is_nterror(req, &status)) {
140 return status;
142 *pwritten = state->written;
143 return NT_STATUS_OK;
146 struct rpc_np_read_state {
147 struct rpc_transport_np_state *np_transport;
148 uint8_t *data;
149 size_t size;
150 ssize_t received;
153 static void rpc_np_read_done(struct tevent_req *subreq);
155 static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx,
156 struct event_context *ev,
157 uint8_t *data, size_t size,
158 void *priv)
160 struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
161 priv, struct rpc_transport_np_state);
162 struct tevent_req *req, *subreq;
163 struct rpc_np_read_state *state;
164 bool ok;
166 req = tevent_req_create(mem_ctx, &state, struct rpc_np_read_state);
167 if (req == NULL) {
168 return NULL;
171 ok = rpc_np_is_connected(np_transport);
172 if (!ok) {
173 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
174 return tevent_req_post(req, ev);
177 state->np_transport = np_transport;
178 state->data = data;
179 state->size = size;
181 subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli,
182 np_transport->fnum, 0, size);
183 if (subreq == NULL) {
184 goto fail;
186 tevent_req_set_callback(subreq, rpc_np_read_done, req);
187 return req;
188 fail:
189 TALLOC_FREE(req);
190 return NULL;
193 static void rpc_np_read_done(struct tevent_req *subreq)
195 struct tevent_req *req = tevent_req_callback_data(
196 subreq, struct tevent_req);
197 struct rpc_np_read_state *state = tevent_req_data(
198 req, struct rpc_np_read_state);
199 NTSTATUS status;
200 uint8_t *rcvbuf;
202 /* We must free subreq in this function as there is
203 a timer event attached to it. */
205 status = cli_read_andx_recv(subreq, &state->received, &rcvbuf);
207 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
208 * child of that.
210 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
211 status = NT_STATUS_OK;
213 if (!NT_STATUS_IS_OK(status)) {
214 TALLOC_FREE(subreq);
215 state->np_transport->cli = NULL;
216 tevent_req_nterror(req, status);
217 return;
220 if (state->received > state->size) {
221 TALLOC_FREE(subreq);
222 state->np_transport->cli = NULL;
223 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
224 return;
227 if (state->received == 0) {
228 TALLOC_FREE(subreq);
229 state->np_transport->cli = NULL;
230 tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN);
231 return;
234 memcpy(state->data, rcvbuf, state->received);
235 TALLOC_FREE(subreq);
236 tevent_req_done(req);
239 static NTSTATUS rpc_np_read_recv(struct tevent_req *req, ssize_t *preceived)
241 struct rpc_np_read_state *state = tevent_req_data(
242 req, struct rpc_np_read_state);
243 NTSTATUS status;
245 if (tevent_req_is_nterror(req, &status)) {
246 return status;
248 *preceived = state->received;
249 return NT_STATUS_OK;
252 struct rpc_np_trans_state {
253 struct rpc_transport_np_state *np_transport;
254 uint16_t setup[2];
255 uint32_t max_rdata_len;
256 uint8_t *rdata;
257 uint32_t rdata_len;
260 static void rpc_np_trans_done(struct tevent_req *subreq);
262 static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx,
263 struct event_context *ev,
264 uint8_t *data, size_t data_len,
265 uint32_t max_rdata_len,
266 void *priv)
268 struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
269 priv, struct rpc_transport_np_state);
270 struct tevent_req *req, *subreq;
271 struct rpc_np_trans_state *state;
272 bool ok;
274 req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state);
275 if (req == NULL) {
276 return NULL;
279 ok = rpc_np_is_connected(np_transport);
280 if (!ok) {
281 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
282 return tevent_req_post(req, ev);
285 state->np_transport = np_transport;
286 state->max_rdata_len = max_rdata_len;
288 SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD);
289 SSVAL(state->setup+1, 0, np_transport->fnum);
291 subreq = cli_trans_send(
292 state, ev, np_transport->cli, SMBtrans,
293 "\\PIPE\\", 0, 0, 0, state->setup, 2, 0,
294 NULL, 0, 0, data, data_len, max_rdata_len);
295 if (subreq == NULL) {
296 goto fail;
298 tevent_req_set_callback(subreq, rpc_np_trans_done, req);
299 return req;
301 fail:
302 TALLOC_FREE(req);
303 return NULL;
306 static void rpc_np_trans_done(struct tevent_req *subreq)
308 struct tevent_req *req = tevent_req_callback_data(
309 subreq, struct tevent_req);
310 struct rpc_np_trans_state *state = tevent_req_data(
311 req, struct rpc_np_trans_state);
312 NTSTATUS status;
314 status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
315 &state->rdata, &state->rdata_len);
316 TALLOC_FREE(subreq);
317 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
318 status = NT_STATUS_OK;
320 if (!NT_STATUS_IS_OK(status)) {
321 state->np_transport->cli = NULL;
322 tevent_req_nterror(req, status);
323 return;
326 if (state->rdata_len > state->max_rdata_len) {
327 state->np_transport->cli = NULL;
328 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
329 return;
332 if (state->rdata_len == 0) {
333 state->np_transport->cli = NULL;
334 tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN);
335 return;
338 tevent_req_done(req);
341 static NTSTATUS rpc_np_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
342 uint8_t **prdata, uint32_t *prdata_len)
344 struct rpc_np_trans_state *state = tevent_req_data(
345 req, struct rpc_np_trans_state);
346 NTSTATUS status;
348 if (tevent_req_is_nterror(req, &status)) {
349 return status;
351 *prdata = talloc_move(mem_ctx, &state->rdata);
352 *prdata_len = state->rdata_len;
353 return NT_STATUS_OK;
356 struct rpc_transport_np_init_state {
357 struct rpc_cli_transport *transport;
358 struct rpc_transport_np_state *transport_np;
361 static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq);
363 struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx,
364 struct event_context *ev,
365 struct cli_state *cli,
366 const struct ndr_syntax_id *abstract_syntax)
368 struct tevent_req *req, *subreq;
369 struct rpc_transport_np_init_state *state;
370 bool ok;
372 req = tevent_req_create(mem_ctx, &state,
373 struct rpc_transport_np_init_state);
374 if (req == NULL) {
375 return NULL;
378 ok = cli_state_is_connected(cli);
379 if (!ok) {
380 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
381 return tevent_req_post(req, ev);
384 state->transport = talloc(state, struct rpc_cli_transport);
385 if (tevent_req_nomem(state->transport, req)) {
386 return tevent_req_post(req, ev);
388 state->transport_np = talloc(state->transport,
389 struct rpc_transport_np_state);
390 if (tevent_req_nomem(state->transport_np, req)) {
391 return tevent_req_post(req, ev);
393 state->transport->priv = state->transport_np;
395 state->transport_np->pipe_name = get_pipe_name_from_syntax(
396 state->transport_np, abstract_syntax);
397 state->transport_np->cli = cli;
399 subreq = cli_ntcreate_send(
400 state, ev, cli, state->transport_np->pipe_name, 0,
401 DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
402 FILE_OPEN, 0, 0);
403 if (tevent_req_nomem(subreq, req)) {
404 return tevent_req_post(req, ev);
406 tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open,
407 req);
408 return req;
411 static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq)
413 struct tevent_req *req = tevent_req_callback_data(
414 subreq, struct tevent_req);
415 struct rpc_transport_np_init_state *state = tevent_req_data(
416 req, struct rpc_transport_np_init_state);
417 NTSTATUS status;
419 status = cli_ntcreate_recv(subreq, &state->transport_np->fnum);
420 TALLOC_FREE(subreq);
421 if (!NT_STATUS_IS_OK(status)) {
422 tevent_req_nterror(req, status);
423 return;
426 talloc_set_destructor(state->transport_np,
427 rpc_transport_np_state_destructor);
428 tevent_req_done(req);
431 NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req,
432 TALLOC_CTX *mem_ctx,
433 struct rpc_cli_transport **presult)
435 struct rpc_transport_np_init_state *state = tevent_req_data(
436 req, struct rpc_transport_np_init_state);
437 NTSTATUS status;
439 if (tevent_req_is_nterror(req, &status)) {
440 return status;
443 state->transport->write_send = rpc_np_write_send;
444 state->transport->write_recv = rpc_np_write_recv;
445 state->transport->read_send = rpc_np_read_send;
446 state->transport->read_recv = rpc_np_read_recv;
447 state->transport->trans_send = rpc_np_trans_send;
448 state->transport->trans_recv = rpc_np_trans_recv;
449 state->transport->is_connected = rpc_np_is_connected;
451 *presult = talloc_move(mem_ctx, &state->transport);
452 return NT_STATUS_OK;
455 NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
456 const struct ndr_syntax_id *abstract_syntax,
457 struct rpc_cli_transport **presult)
459 TALLOC_CTX *frame = talloc_stackframe();
460 struct event_context *ev;
461 struct tevent_req *req;
462 NTSTATUS status = NT_STATUS_OK;
464 ev = event_context_init(frame);
465 if (ev == NULL) {
466 status = NT_STATUS_NO_MEMORY;
467 goto fail;
470 req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax);
471 if (req == NULL) {
472 status = NT_STATUS_NO_MEMORY;
473 goto fail;
476 if (!tevent_req_poll(req, ev)) {
477 status = map_nt_error_from_unix(errno);
478 goto fail;
481 status = rpc_transport_np_init_recv(req, mem_ctx, presult);
482 fail:
483 TALLOC_FREE(frame);
484 return status;
487 struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
489 struct rpc_transport_np_state *state = talloc_get_type(
490 p->transport->priv, struct rpc_transport_np_state);
492 if (state == NULL) {
493 return NULL;
495 return state->cli;
498 void rpccli_close_np_fd(struct rpc_pipe_client *p)
500 struct cli_state *cli = rpc_pipe_np_smb_conn(p);
501 if (cli) {
502 if (cli->fd != -1) {
503 close(cli->fd);
504 cli->fd = -1;
507 return;