1/* 2 * Unix SMB/CIFS implementation. 3 * RPC client transport over named pipes 4 * Copyright (C) Volker Lendecke 2009 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 22#undef DBGC_CLASS 23#define DBGC_CLASS DBGC_RPC_CLI 24 25struct rpc_transport_np_state { 26 struct cli_state *cli; 27 const char *pipe_name; 28 uint16_t fnum; 29}; 30 31static bool rpc_np_is_connected(void *priv) 32{ 33 struct rpc_transport_np_state *np_transport = talloc_get_type_abort( 34 priv, struct rpc_transport_np_state); 35 bool ok; 36 37 if (np_transport->cli == NULL) { 38 return false; 39 } 40 41 ok = cli_state_is_connected(np_transport->cli); 42 if (!ok) { 43 np_transport->cli = NULL; 44 return false; 45 } 46 47 return true; 48} 49 50static unsigned int rpc_np_set_timeout(void *priv, unsigned int timeout) 51{ 52 struct rpc_transport_np_state *np_transport = talloc_get_type_abort( 53 priv, struct rpc_transport_np_state); 54 bool ok; 55 56 if (np_transport->cli == NULL) { 57 return false; 58 } 59 60 ok = rpc_np_is_connected(np_transport); 61 if (!ok) { 62 return 0; 63 } 64 65 return cli_set_timeout(np_transport->cli, timeout); 66} 67 68static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s) 69{ 70 if (!rpc_np_is_connected(s)) { 71 DEBUG(10, ("socket was closed, no need to send close request.\n")); 72 return 0; 73 } 74 75 /* TODO: do not use a sync call with a destructor!!! */ 76 if (!NT_STATUS_IS_OK(cli_close(s->cli, s->fnum))) { 77 DEBUG(1, ("rpc_transport_np_state_destructor: cli_close " 78 "failed on pipe %s. Error was %s\n", s->pipe_name, 79 cli_errstr(s->cli))); 80 } 81 DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name)); 82 /* 83 * We can't do much on failure 84 */ 85 return 0; 86} 87 88struct rpc_np_write_state { 89 struct rpc_transport_np_state *np_transport; 90 size_t size; 91 size_t written; 92}; 93 94static void rpc_np_write_done(struct tevent_req *subreq); 95 96static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx, 97 struct event_context *ev, 98 const uint8_t *data, size_t size, 99 void *priv) 100{ 101 struct rpc_transport_np_state *np_transport = talloc_get_type_abort( 102 priv, struct rpc_transport_np_state); 103 struct tevent_req *req, *subreq; 104 struct rpc_np_write_state *state; 105 bool ok; 106 107 req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state); 108 if (req == NULL) { 109 return NULL; 110 } 111 112 ok = rpc_np_is_connected(np_transport); 113 if (!ok) { 114 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID); 115 return tevent_req_post(req, ev); 116 } 117 118 state->np_transport = np_transport; 119 state->size = size; 120 121 122 subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli, 123 np_transport->fnum, 124 8, /* 8 means message mode. */ 125 data, 0, size); 126 if (tevent_req_nomem(subreq, req)) { 127 return tevent_req_post(req, ev); 128 } 129 tevent_req_set_callback(subreq, rpc_np_write_done, req); 130 return req; 131} 132 133static void rpc_np_write_done(struct tevent_req *subreq) 134{ 135 struct tevent_req *req = tevent_req_callback_data( 136 subreq, struct tevent_req); 137 struct rpc_np_write_state *state = tevent_req_data( 138 req, struct rpc_np_write_state); 139 NTSTATUS status; 140 141 status = cli_write_andx_recv(subreq, &state->written); 142 TALLOC_FREE(subreq); 143 if (!NT_STATUS_IS_OK(status)) { 144 state->np_transport->cli = NULL; 145 tevent_req_nterror(req, status); 146 return; 147 } 148 tevent_req_done(req); 149} 150 151static NTSTATUS rpc_np_write_recv(struct tevent_req *req, ssize_t *pwritten) 152{ 153 struct rpc_np_write_state *state = tevent_req_data( 154 req, struct rpc_np_write_state); 155 NTSTATUS status; 156 157 if (tevent_req_is_nterror(req, &status)) { 158 return status; 159 } 160 *pwritten = state->written; 161 return NT_STATUS_OK; 162} 163 164struct rpc_np_read_state { 165 struct rpc_transport_np_state *np_transport; 166 uint8_t *data; 167 size_t size; 168 ssize_t received; 169}; 170 171static void rpc_np_read_done(struct tevent_req *subreq); 172 173static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx, 174 struct event_context *ev, 175 uint8_t *data, size_t size, 176 void *priv) 177{ 178 struct rpc_transport_np_state *np_transport = talloc_get_type_abort( 179 priv, struct rpc_transport_np_state); 180 struct tevent_req *req, *subreq; 181 struct rpc_np_read_state *state; 182 bool ok; 183 184 req = tevent_req_create(mem_ctx, &state, struct rpc_np_read_state); 185 if (req == NULL) { 186 return NULL; 187 } 188 189 ok = rpc_np_is_connected(np_transport); 190 if (!ok) { 191 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID); 192 return tevent_req_post(req, ev); 193 } 194 195 state->np_transport = np_transport; 196 state->data = data; 197 state->size = size; 198 199 subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli, 200 np_transport->fnum, 0, size); 201 if (subreq == NULL) { 202 goto fail; 203 } 204 tevent_req_set_callback(subreq, rpc_np_read_done, req); 205 return req; 206 fail: 207 TALLOC_FREE(req); 208 return NULL; 209} 210 211static void rpc_np_read_done(struct tevent_req *subreq) 212{ 213 struct tevent_req *req = tevent_req_callback_data( 214 subreq, struct tevent_req); 215 struct rpc_np_read_state *state = tevent_req_data( 216 req, struct rpc_np_read_state); 217 NTSTATUS status; 218 uint8_t *rcvbuf; 219 220 /* We must free subreq in this function as there is 221 a timer event attached to it. */ 222 223 status = cli_read_andx_recv(subreq, &state->received, &rcvbuf); 224 /* 225 * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a 226 * child of that. 227 */ 228 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { 229 status = NT_STATUS_OK; 230 } 231 if (!NT_STATUS_IS_OK(status)) { 232 TALLOC_FREE(subreq); 233 state->np_transport->cli = NULL; 234 tevent_req_nterror(req, status); 235 return; 236 } 237 238 if (state->received > state->size) { 239 TALLOC_FREE(subreq); 240 state->np_transport->cli = NULL; 241 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 242 return; 243 } 244 245 if (state->received == 0) { 246 TALLOC_FREE(subreq); 247 state->np_transport->cli = NULL; 248 tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN); 249 return; 250 } 251 252 memcpy(state->data, rcvbuf, state->received); 253 TALLOC_FREE(subreq); 254 tevent_req_done(req); 255} 256 257static NTSTATUS rpc_np_read_recv(struct tevent_req *req, ssize_t *preceived) 258{ 259 struct rpc_np_read_state *state = tevent_req_data( 260 req, struct rpc_np_read_state); 261 NTSTATUS status; 262 263 if (tevent_req_is_nterror(req, &status)) { 264 return status; 265 } 266 *preceived = state->received; 267 return NT_STATUS_OK; 268} 269 270struct rpc_np_trans_state { 271 struct rpc_transport_np_state *np_transport; 272 uint16_t setup[2]; 273 uint32_t max_rdata_len; 274 uint8_t *rdata; 275 uint32_t rdata_len; 276}; 277 278static void rpc_np_trans_done(struct tevent_req *subreq); 279 280static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, 281 struct event_context *ev, 282 uint8_t *data, size_t data_len, 283 uint32_t max_rdata_len, 284 void *priv) 285{ 286 struct rpc_transport_np_state *np_transport = talloc_get_type_abort( 287 priv, struct rpc_transport_np_state); 288 struct tevent_req *req, *subreq; 289 struct rpc_np_trans_state *state; 290 bool ok; 291 292 req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state); 293 if (req == NULL) { 294 return NULL; 295 } 296 297 ok = rpc_np_is_connected(np_transport); 298 if (!ok) { 299 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID); 300 return tevent_req_post(req, ev); 301 } 302 303 state->np_transport = np_transport; 304 state->max_rdata_len = max_rdata_len; 305 306 SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD); 307 SSVAL(state->setup+1, 0, np_transport->fnum); 308 309 subreq = cli_trans_send( 310 state, ev, np_transport->cli, SMBtrans, 311 "\\PIPE\\", 0, 0, 0, state->setup, 2, 0, 312 NULL, 0, 0, data, data_len, max_rdata_len); 313 if (subreq == NULL) { 314 goto fail; 315 } 316 tevent_req_set_callback(subreq, rpc_np_trans_done, req); 317 return req; 318 319 fail: 320 TALLOC_FREE(req); 321 return NULL; 322} 323 324static void rpc_np_trans_done(struct tevent_req *subreq) 325{ 326 struct tevent_req *req = tevent_req_callback_data( 327 subreq, struct tevent_req); 328 struct rpc_np_trans_state *state = tevent_req_data( 329 req, struct rpc_np_trans_state); 330 NTSTATUS status; 331 332 status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL, 333 &state->rdata, &state->rdata_len); 334 TALLOC_FREE(subreq); 335 if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) { 336 status = NT_STATUS_OK; 337 } 338 if (!NT_STATUS_IS_OK(status)) { 339 state->np_transport->cli = NULL; 340 tevent_req_nterror(req, status); 341 return; 342 } 343 344 if (state->rdata_len > state->max_rdata_len) { 345 state->np_transport->cli = NULL; 346 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); 347 return; 348 } 349 350 if (state->rdata_len == 0) { 351 state->np_transport->cli = NULL; 352 tevent_req_nterror(req, NT_STATUS_PIPE_BROKEN); 353 return; 354 } 355 356 tevent_req_done(req); 357} 358 359static NTSTATUS rpc_np_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, 360 uint8_t **prdata, uint32_t *prdata_len) 361{ 362 struct rpc_np_trans_state *state = tevent_req_data( 363 req, struct rpc_np_trans_state); 364 NTSTATUS status; 365 366 if (tevent_req_is_nterror(req, &status)) { 367 return status; 368 } 369 *prdata = talloc_move(mem_ctx, &state->rdata); 370 *prdata_len = state->rdata_len; 371 return NT_STATUS_OK; 372} 373 374struct rpc_transport_np_init_state { 375 struct rpc_cli_transport *transport; 376 struct rpc_transport_np_state *transport_np; 377}; 378 379static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq); 380 381struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, 382 struct event_context *ev, 383 struct cli_state *cli, 384 const struct ndr_syntax_id *abstract_syntax) 385{ 386 struct tevent_req *req, *subreq; 387 struct rpc_transport_np_init_state *state; 388 bool ok; 389 390 req = tevent_req_create(mem_ctx, &state, 391 struct rpc_transport_np_init_state); 392 if (req == NULL) { 393 return NULL; 394 } 395 396 ok = cli_state_is_connected(cli); 397 if (!ok) { 398 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID); 399 return tevent_req_post(req, ev); 400 } 401 402 state->transport = talloc(state, struct rpc_cli_transport); 403 if (tevent_req_nomem(state->transport, req)) { 404 return tevent_req_post(req, ev); 405 } 406 state->transport_np = talloc(state->transport, 407 struct rpc_transport_np_state); 408 if (tevent_req_nomem(state->transport_np, req)) { 409 return tevent_req_post(req, ev); 410 } 411 state->transport->priv = state->transport_np; 412 413 state->transport_np->pipe_name = get_pipe_name_from_syntax( 414 state->transport_np, abstract_syntax); 415 state->transport_np->cli = cli; 416 417 subreq = cli_ntcreate_send( 418 state, ev, cli, state->transport_np->pipe_name, 0, 419 DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 420 FILE_OPEN, 0, 0); 421 if (tevent_req_nomem(subreq, req)) { 422 return tevent_req_post(req, ev); 423 } 424 tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open, 425 req); 426 return req; 427} 428 429static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq) 430{ 431 struct tevent_req *req = tevent_req_callback_data( 432 subreq, struct tevent_req); 433 struct rpc_transport_np_init_state *state = tevent_req_data( 434 req, struct rpc_transport_np_init_state); 435 NTSTATUS status; 436 437 status = cli_ntcreate_recv(subreq, &state->transport_np->fnum); 438 TALLOC_FREE(subreq); 439 if (!NT_STATUS_IS_OK(status)) { 440 tevent_req_nterror(req, status); 441 return; 442 } 443 444 talloc_set_destructor(state->transport_np, 445 rpc_transport_np_state_destructor); 446 tevent_req_done(req); 447} 448 449NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req, 450 TALLOC_CTX *mem_ctx, 451 struct rpc_cli_transport **presult) 452{ 453 struct rpc_transport_np_init_state *state = tevent_req_data( 454 req, struct rpc_transport_np_init_state); 455 NTSTATUS status; 456 457 if (tevent_req_is_nterror(req, &status)) { 458 return status; 459 } 460 461 state->transport->write_send = rpc_np_write_send; 462 state->transport->write_recv = rpc_np_write_recv; 463 state->transport->read_send = rpc_np_read_send; 464 state->transport->read_recv = rpc_np_read_recv; 465 state->transport->trans_send = rpc_np_trans_send; 466 state->transport->trans_recv = rpc_np_trans_recv; 467 state->transport->is_connected = rpc_np_is_connected; 468 state->transport->set_timeout = rpc_np_set_timeout; 469 470 *presult = talloc_move(mem_ctx, &state->transport); 471 return NT_STATUS_OK; 472} 473 474NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, 475 const struct ndr_syntax_id *abstract_syntax, 476 struct rpc_cli_transport **presult) 477{ 478 TALLOC_CTX *frame = talloc_stackframe(); 479 struct event_context *ev; 480 struct tevent_req *req; 481 NTSTATUS status = NT_STATUS_OK; 482 483 ev = event_context_init(frame); 484 if (ev == NULL) { 485 status = NT_STATUS_NO_MEMORY; 486 goto fail; 487 } 488 489 req = rpc_transport_np_init_send(frame, ev, cli, abstract_syntax); 490 if (req == NULL) { 491 status = NT_STATUS_NO_MEMORY; 492 goto fail; 493 } 494 495 if (!tevent_req_poll(req, ev)) { 496 status = map_nt_error_from_unix(errno); 497 goto fail; 498 } 499 500 status = rpc_transport_np_init_recv(req, mem_ctx, presult); 501 fail: 502 TALLOC_FREE(frame); 503 return status; 504} 505 506struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p) 507{ 508 struct rpc_transport_np_state *state = talloc_get_type( 509 p->transport->priv, struct rpc_transport_np_state); 510 511 if (state == NULL) { 512 return NULL; 513 } 514 return state->cli; 515} 516