root/source4/librpc/rpc/dcerpc_smb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pipe_dead
  2. smb_read_callback
  3. send_read_request_continue
  4. send_read_request
  5. smb_trans_callback
  6. smb_send_trans_request
  7. smb_write_callback
  8. smb_send_request
  9. smb_shutdown_pipe
  10. smb_peer_name
  11. smb_target_hostname
  12. smb_session_key
  13. dcerpc_pipe_open_smb_send
  14. pipe_open_recv
  15. dcerpc_pipe_open_smb_recv
  16. dcerpc_pipe_open_smb
  17. dcerpc_smb_tree
  18. dcerpc_smb_fnum

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    dcerpc over SMB transport
   5 
   6    Copyright (C) Tim Potter 2003
   7    Copyright (C) Andrew Tridgell 2003
   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 #include "libcli/raw/libcliraw.h"
  25 #include "libcli/composite/composite.h"
  26 #include "librpc/rpc/dcerpc.h"
  27 #include "librpc/rpc/dcerpc_proto.h"
  28 
  29 /* transport private information used by SMB pipe transport */
  30 struct smb_private {
  31         uint16_t fnum;
  32         struct smbcli_tree *tree;
  33         const char *server_name;
  34         bool dead;
  35 };
  36 
  37 
  38 /*
  39   tell the dcerpc layer that the transport is dead
  40 */
  41 static void pipe_dead(struct dcerpc_connection *c, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
  44 
  45         if (smb->dead) {
  46                 return;
  47         }
  48 
  49         smb->dead = true;
  50 
  51         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
  52                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
  53         }
  54 
  55         if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
  56                 status = NT_STATUS_END_OF_FILE;
  57         }
  58 
  59         if (c->transport.recv_data) {
  60                 c->transport.recv_data(c, NULL, status);
  61         }
  62 }
  63 
  64 
  65 /* 
  66    this holds the state of an in-flight call
  67 */
  68 struct smb_read_state {
  69         struct dcerpc_connection *c;
  70         struct smbcli_request *req;
  71         size_t received;
  72         DATA_BLOB data;
  73         union smb_read *io;
  74 };
  75 
  76 /*
  77   called when a read request has completed
  78 */
  79 static void smb_read_callback(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
  80 {
  81         struct smb_private *smb;
  82         struct smb_read_state *state;
  83         union smb_read *io;
  84         uint16_t frag_length;
  85         NTSTATUS status;
  86 
  87         state = talloc_get_type(req->async.private_data, struct smb_read_state);
  88         smb = talloc_get_type(state->c->transport.private_data, struct smb_private);
  89         io = state->io;
  90 
  91         status = smb_raw_read_recv(state->req, io);
  92         if (NT_STATUS_IS_ERR(status)) {
  93                 pipe_dead(state->c, status);
  94                 talloc_free(state);
  95                 return;
  96         }
  97 
  98         state->received += io->readx.out.nread;
  99 
 100         if (state->received < 16) {
 101                 DEBUG(0,("dcerpc_smb: short packet (length %d) in read callback!\n",
 102                          (int)state->received));
 103                 pipe_dead(state->c, NT_STATUS_INFO_LENGTH_MISMATCH);
 104                 talloc_free(state);
 105                 return;
 106         }
 107 
 108         frag_length = dcerpc_get_frag_length(&state->data);
 109 
 110         if (frag_length <= state->received) {
 111                 DATA_BLOB data = state->data;
 112                 struct dcerpc_connection *c = state->c;
 113                 data.length = state->received;
 114                 talloc_steal(state->c, data.data);
 115                 talloc_free(state);
 116                 c->transport.recv_data(c, &data, NT_STATUS_OK);
 117                 return;
 118         }
 119 
 120         /* initiate another read request, as we only got part of a fragment */
 121         state->data.data = talloc_realloc(state, state->data.data, uint8_t, frag_length);
 122 
 123         io->readx.in.mincnt = MIN(state->c->srv_max_xmit_frag, 
 124                                   frag_length - state->received);
 125         io->readx.in.maxcnt = io->readx.in.mincnt;
 126         io->readx.out.data = state->data.data + state->received;
 127 
 128         state->req = smb_raw_read_send(smb->tree, io);
 129         if (state->req == NULL) {
 130                 pipe_dead(state->c, NT_STATUS_NO_MEMORY);
 131                 talloc_free(state);
 132                 return;
 133         }
 134 
 135         state->req->async.fn = smb_read_callback;
 136         state->req->async.private_data = state;
 137 }
 138 
 139 /*
 140   trigger a read request from the server, possibly with some initial
 141   data in the read buffer
 142 */
 143 static NTSTATUS send_read_request_continue(struct dcerpc_connection *c, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 144 {
 145         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 146         union smb_read *io;
 147         struct smb_read_state *state;
 148         struct smbcli_request *req;
 149 
 150         state = talloc(smb, struct smb_read_state);
 151         if (state == NULL) {
 152                 return NT_STATUS_NO_MEMORY;
 153         }
 154 
 155         state->c = c;
 156         if (blob == NULL) {
 157                 state->received = 0;
 158                 state->data = data_blob_talloc(state, NULL, 0x2000);
 159         } else {
 160                 uint32_t frag_length = blob->length>=16?
 161                         dcerpc_get_frag_length(blob):0x2000;
 162                 state->received = blob->length;
 163                 state->data = data_blob_talloc(state, NULL, frag_length);
 164                 if (!state->data.data) {
 165                         talloc_free(state);
 166                         return NT_STATUS_NO_MEMORY;
 167                 }
 168                 memcpy(state->data.data, blob->data, blob->length);
 169         }
 170 
 171         state->io = talloc(state, union smb_read);
 172 
 173         io = state->io;
 174         io->generic.level = RAW_READ_READX;
 175         io->readx.in.file.fnum = smb->fnum;
 176         io->readx.in.mincnt = state->data.length - state->received;
 177         io->readx.in.maxcnt = io->readx.in.mincnt;
 178         io->readx.in.offset = 0;
 179         io->readx.in.remaining = 0;
 180         io->readx.in.read_for_execute = false;
 181         io->readx.out.data = state->data.data + state->received;
 182         req = smb_raw_read_send(smb->tree, io);
 183         if (req == NULL) {
 184                 return NT_STATUS_NO_MEMORY;
 185         }
 186 
 187         req->async.fn = smb_read_callback;
 188         req->async.private_data = state;
 189 
 190         state->req = req;
 191 
 192         return NT_STATUS_OK;
 193 }
 194 
 195 
 196 /*
 197   trigger a read request from the server
 198 */
 199 static NTSTATUS send_read_request(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 200 {
 201         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 202 
 203         if (smb->dead) {
 204                 return NT_STATUS_CONNECTION_DISCONNECTED;
 205         }
 206 
 207         return send_read_request_continue(c, NULL);
 208 }
 209 
 210 /* 
 211    this holds the state of an in-flight trans call
 212 */
 213 struct smb_trans_state {
 214         struct dcerpc_connection *c;
 215         struct smbcli_request *req;
 216         struct smb_trans2 *trans;
 217 };
 218 
 219 /*
 220   called when a trans request has completed
 221 */
 222 static void smb_trans_callback(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 223 {
 224         struct smb_trans_state *state = (struct smb_trans_state *)req->async.private_data;
 225         struct dcerpc_connection *c = state->c;
 226         NTSTATUS status;
 227 
 228         status = smb_raw_trans_recv(req, state, state->trans);
 229 
 230         if (NT_STATUS_IS_ERR(status)) {
 231                 pipe_dead(c, status);
 232                 return;
 233         }
 234 
 235         if (!NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
 236                 DATA_BLOB data = state->trans->out.data;
 237                 talloc_steal(c, data.data);
 238                 talloc_free(state);
 239                 c->transport.recv_data(c, &data, NT_STATUS_OK);
 240                 return;
 241         }
 242 
 243         /* there is more to receive - setup a readx */
 244         send_read_request_continue(c, &state->trans->out.data);
 245         talloc_free(state);
 246 }
 247 
 248 /*
 249   send a SMBtrans style request
 250 */
 251 static NTSTATUS smb_send_trans_request(struct dcerpc_connection *c, DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 252 {
 253         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 254         struct smb_trans2 *trans;
 255         uint16_t setup[2];
 256         struct smb_trans_state *state;
 257         uint16_t max_data;
 258 
 259         state = talloc(smb, struct smb_trans_state);
 260         if (state == NULL) {
 261                 return NT_STATUS_NO_MEMORY;
 262         }
 263 
 264         state->c = c;
 265         state->trans = talloc(state, struct smb_trans2);
 266         trans = state->trans;
 267 
 268         trans->in.data = *blob;
 269         trans->in.params = data_blob(NULL, 0);
 270         
 271         setup[0] = TRANSACT_DCERPCCMD;
 272         setup[1] = smb->fnum;
 273 
 274         if (c->srv_max_xmit_frag > 0) {
 275                 max_data = MIN(UINT16_MAX, c->srv_max_xmit_frag);
 276         } else {
 277                 max_data = UINT16_MAX;
 278         }
 279 
 280         trans->in.max_param = 0;
 281         trans->in.max_data = max_data;
 282         trans->in.max_setup = 0;
 283         trans->in.setup_count = 2;
 284         trans->in.flags = 0;
 285         trans->in.timeout = 0;
 286         trans->in.setup = setup;
 287         trans->in.trans_name = "\\PIPE\\";
 288 
 289         state->req = smb_raw_trans_send(smb->tree, trans);
 290         if (state->req == NULL) {
 291                 talloc_free(state);
 292                 return NT_STATUS_NO_MEMORY;
 293         }
 294 
 295         state->req->async.fn = smb_trans_callback;
 296         state->req->async.private_data = state;
 297 
 298         talloc_steal(state, state->req);
 299 
 300         return NT_STATUS_OK;
 301 }
 302 
 303 /*
 304   called when a write request has completed
 305 */
 306 static void smb_write_callback(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 307 {
 308         struct dcerpc_connection *c = (struct dcerpc_connection *)req->async.private_data;
 309 
 310         if (!NT_STATUS_IS_OK(req->status)) {
 311                 DEBUG(0,("dcerpc_smb: write callback error\n"));
 312                 pipe_dead(c, req->status);
 313         }
 314 
 315         smbcli_request_destroy(req);
 316 }
 317 
 318 /* 
 319    send a packet to the server
 320 */
 321 static NTSTATUS smb_send_request(struct dcerpc_connection *c, DATA_BLOB *blob, 
     /* [<][>][^][v][top][bottom][index][help] */
 322                                  bool trigger_read)
 323 {
 324         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 325         union smb_write io;
 326         struct smbcli_request *req;
 327 
 328         if (smb->dead) {
 329                 return NT_STATUS_CONNECTION_DISCONNECTED;
 330         }
 331 
 332         if (trigger_read) {
 333                 return smb_send_trans_request(c, blob);
 334         }
 335 
 336         io.generic.level = RAW_WRITE_WRITEX;
 337         io.writex.in.file.fnum = smb->fnum;
 338         io.writex.in.offset = 0;
 339         io.writex.in.wmode = PIPE_START_MESSAGE;
 340         io.writex.in.remaining = blob->length;
 341         io.writex.in.count = blob->length;
 342         io.writex.in.data = blob->data;
 343 
 344         /* we must not timeout at the smb level for rpc requests, as otherwise
 345            signing/sealing can be messed up */
 346         smb->tree->session->transport->options.request_timeout = 0;
 347 
 348         req = smb_raw_write_send(smb->tree, &io);
 349         if (req == NULL) {
 350                 return NT_STATUS_NO_MEMORY;
 351         }
 352 
 353         req->async.fn = smb_write_callback;
 354         req->async.private_data = c;
 355 
 356         if (trigger_read) {
 357                 send_read_request(c);
 358         }
 359 
 360         return NT_STATUS_OK;
 361 }
 362 
 363 /* 
 364    shutdown SMB pipe connection
 365 */
 366 static NTSTATUS smb_shutdown_pipe(struct dcerpc_connection *c, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 367 {
 368         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 369         union smb_close io;
 370         struct smbcli_request *req;
 371 
 372         /* maybe we're still starting up */
 373         if (!smb) return status;
 374 
 375         io.close.level = RAW_CLOSE_CLOSE;
 376         io.close.in.file.fnum = smb->fnum;
 377         io.close.in.write_time = 0;
 378         req = smb_raw_close_send(smb->tree, &io);
 379         if (req != NULL) {
 380                 /* we don't care if this fails, so just free it if it succeeds */
 381                 req->async.fn = (void (*)(struct smbcli_request *))talloc_free;
 382         }
 383 
 384         talloc_free(smb);
 385 
 386         return status;
 387 }
 388 
 389 /*
 390   return SMB server name (called name)
 391 */
 392 static const char *smb_peer_name(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 393 {
 394         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 395         return smb->server_name;
 396 }
 397 
 398 /*
 399   return remote name we make the actual connection (good for kerberos) 
 400 */
 401 static const char *smb_target_hostname(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 402 {
 403         struct smb_private *smb = talloc_get_type(c->transport.private_data, struct smb_private);
 404         return smb->tree->session->transport->socket->hostname;
 405 }
 406 
 407 /*
 408   fetch the user session key 
 409 */
 410 static NTSTATUS smb_session_key(struct dcerpc_connection *c, DATA_BLOB *session_key)
     /* [<][>][^][v][top][bottom][index][help] */
 411 {
 412         struct smb_private *smb = (struct smb_private *)c->transport.private_data;
 413 
 414         if (smb->tree->session->user_session_key.data) {
 415                 *session_key = smb->tree->session->user_session_key;
 416                 return NT_STATUS_OK;
 417         }
 418         return NT_STATUS_NO_USER_SESSION_KEY;
 419 }
 420 
 421 struct pipe_open_smb_state {
 422         union smb_open *open;
 423         struct dcerpc_connection *c;
 424         struct smbcli_tree *tree;
 425         struct composite_context *ctx;
 426 };
 427 
 428 static void pipe_open_recv(struct smbcli_request *req);
 429 
 430 struct composite_context *dcerpc_pipe_open_smb_send(struct dcerpc_pipe *p, 
     /* [<][>][^][v][top][bottom][index][help] */
 431                                                     struct smbcli_tree *tree,
 432                                                     const char *pipe_name)
 433 {
 434         struct composite_context *ctx;
 435         struct pipe_open_smb_state *state;
 436         struct smbcli_request *req;
 437         struct dcerpc_connection *c = p->conn;
 438 
 439         /* if we don't have a binding on this pipe yet, then create one */
 440         if (p->binding == NULL) {
 441                 NTSTATUS status;
 442                 char *s;
 443                 SMB_ASSERT(tree->session->transport->socket->hostname != NULL);
 444                 s = talloc_asprintf(p, "ncacn_np:%s", tree->session->transport->socket->hostname);
 445                 if (s == NULL) return NULL;
 446                 status = dcerpc_parse_binding(p, s, &p->binding);
 447                 talloc_free(s);
 448                 if (!NT_STATUS_IS_OK(status)) {
 449                         return NULL;
 450                 }
 451         }
 452 
 453         ctx = composite_create(c, c->event_ctx);
 454         if (ctx == NULL) return NULL;
 455 
 456         state = talloc(ctx, struct pipe_open_smb_state);
 457         if (composite_nomem(state, ctx)) return ctx;
 458         ctx->private_data = state;
 459 
 460         state->c = c;
 461         state->tree = tree;
 462         state->ctx = ctx;
 463 
 464         state->open = talloc(state, union smb_open);
 465         if (composite_nomem(state->open, ctx)) return ctx;
 466 
 467         state->open->ntcreatex.level = RAW_OPEN_NTCREATEX;
 468         state->open->ntcreatex.in.flags = 0;
 469         state->open->ntcreatex.in.root_fid = 0;
 470         state->open->ntcreatex.in.access_mask = 
 471                 SEC_STD_READ_CONTROL |
 472                 SEC_FILE_WRITE_ATTRIBUTE |
 473                 SEC_FILE_WRITE_EA |
 474                 SEC_FILE_READ_DATA |
 475                 SEC_FILE_WRITE_DATA;
 476         state->open->ntcreatex.in.file_attr = 0;
 477         state->open->ntcreatex.in.alloc_size = 0;
 478         state->open->ntcreatex.in.share_access = 
 479                 NTCREATEX_SHARE_ACCESS_READ |
 480                 NTCREATEX_SHARE_ACCESS_WRITE;
 481         state->open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
 482         state->open->ntcreatex.in.create_options = 0;
 483         state->open->ntcreatex.in.impersonation =
 484                 NTCREATEX_IMPERSONATION_IMPERSONATION;
 485         state->open->ntcreatex.in.security_flags = 0;
 486 
 487         if ((strncasecmp(pipe_name, "/pipe/", 6) == 0) || 
 488             (strncasecmp(pipe_name, "\\pipe\\", 6) == 0)) {
 489                 pipe_name += 6;
 490         }
 491         state->open->ntcreatex.in.fname =
 492                 (pipe_name[0] == '\\') ?
 493                 talloc_strdup(state->open, pipe_name) :
 494                 talloc_asprintf(state->open, "\\%s", pipe_name);
 495         if (composite_nomem(state->open->ntcreatex.in.fname, ctx)) return ctx;
 496 
 497         req = smb_raw_open_send(tree, state->open);
 498         composite_continue_smb(ctx, req, pipe_open_recv, state);
 499         return ctx;
 500 }
 501 
 502 static void pipe_open_recv(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 503 {
 504         struct pipe_open_smb_state *state = talloc_get_type(req->async.private_data,
 505                                             struct pipe_open_smb_state);
 506         struct composite_context *ctx = state->ctx;
 507         struct dcerpc_connection *c = state->c;
 508         struct smb_private *smb;
 509         
 510         ctx->status = smb_raw_open_recv(req, state, state->open);
 511         if (!composite_is_ok(ctx)) return;
 512 
 513         /*
 514           fill in the transport methods
 515         */
 516         c->transport.transport       = NCACN_NP;
 517         c->transport.private_data    = NULL;
 518         c->transport.shutdown_pipe   = smb_shutdown_pipe;
 519         c->transport.peer_name       = smb_peer_name;
 520         c->transport.target_hostname = smb_target_hostname;
 521 
 522         c->transport.send_request    = smb_send_request;
 523         c->transport.send_read       = send_read_request;
 524         c->transport.recv_data       = NULL;
 525         
 526         /* Over-ride the default session key with the SMB session key */
 527         c->security_state.session_key = smb_session_key;
 528 
 529         smb = talloc(c, struct smb_private);
 530         if (composite_nomem(smb, ctx)) return;
 531 
 532         smb->fnum       = state->open->ntcreatex.out.file.fnum;
 533         smb->tree       = talloc_reference(smb, state->tree);
 534         smb->server_name= strupper_talloc(smb,
 535                           state->tree->session->transport->called.name);
 536         if (composite_nomem(smb->server_name, ctx)) return;
 537         smb->dead       = false;
 538 
 539         c->transport.private_data = smb;
 540 
 541         composite_done(ctx);
 542 }
 543 
 544 NTSTATUS dcerpc_pipe_open_smb_recv(struct composite_context *c)
     /* [<][>][^][v][top][bottom][index][help] */
 545 {
 546         NTSTATUS status = composite_wait(c);
 547         talloc_free(c);
 548         return status;
 549 }
 550 
 551 _PUBLIC_ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p,
     /* [<][>][^][v][top][bottom][index][help] */
 552                               struct smbcli_tree *tree,
 553                               const char *pipe_name)
 554 {
 555         struct composite_context *ctx = dcerpc_pipe_open_smb_send(p, tree,
 556                                                                   pipe_name);
 557         return dcerpc_pipe_open_smb_recv(ctx);
 558 }
 559 
 560 /*
 561   return the SMB tree used for a dcerpc over SMB pipe
 562 */
 563 _PUBLIC_ struct smbcli_tree *dcerpc_smb_tree(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 564 {
 565         struct smb_private *smb;
 566 
 567         if (c->transport.transport != NCACN_NP) return NULL;
 568 
 569         smb = talloc_get_type(c->transport.private_data, struct smb_private);
 570         if (!smb) return NULL;
 571 
 572         return smb->tree;
 573 }
 574 
 575 /*
 576   return the SMB fnum used for a dcerpc over SMB pipe (hack for torture operations)
 577 */
 578 _PUBLIC_ uint16_t dcerpc_smb_fnum(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 579 {
 580         struct smb_private *smb;
 581 
 582         if (c->transport.transport != NCACN_NP) return 0;
 583 
 584         smb = talloc_get_type(c->transport.private_data, struct smb_private);
 585         if (!smb) return 0;
 586 
 587         return smb->fnum;
 588 }

/* [<][>][^][v][top][bottom][index][help] */