root/source4/libcli/smb_composite/connect.c

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

DEFINITIONS

This source file includes following definitions.
  1. connect_tcon
  2. connect_session_setup_anon
  3. connect_session_setup
  4. connect_negprot
  5. connect_send_negprot
  6. connect_session_request
  7. connect_socket
  8. connect_resolve
  9. state_handler
  10. request_handler
  11. composite_handler
  12. smb_composite_connect_send
  13. smb_composite_connect_recv
  14. smb_composite_connect

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Copyright (C) Andrew Tridgell 2005
   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   a composite API for making a full SMB connection
  21 */
  22 
  23 #include "includes.h"
  24 #include "libcli/raw/libcliraw.h"
  25 #include "libcli/raw/raw_proto.h"
  26 #include "libcli/composite/composite.h"
  27 #include "libcli/smb_composite/smb_composite.h"
  28 #include "lib/events/events.h"
  29 #include "libcli/resolve/resolve.h"
  30 #include "auth/credentials/credentials.h"
  31 #include "librpc/gen_ndr/ndr_nbt.h"
  32 #include "param/param.h"
  33 
  34 /* the stages of this call */
  35 enum connect_stage {CONNECT_RESOLVE, 
  36                     CONNECT_SOCKET, 
  37                     CONNECT_SESSION_REQUEST,
  38                     CONNECT_NEGPROT,
  39                     CONNECT_SESSION_SETUP,
  40                     CONNECT_SESSION_SETUP_ANON,
  41                     CONNECT_TCON,
  42                     CONNECT_DONE
  43 };
  44 
  45 struct connect_state {
  46         enum connect_stage stage;
  47         struct smbcli_socket *sock;
  48         struct smbcli_transport *transport;
  49         struct smbcli_session *session;
  50         struct smb_composite_connect *io;
  51         union smb_tcon *io_tcon;
  52         struct smb_composite_sesssetup *io_setup;
  53         struct smbcli_request *req;
  54         struct composite_context *creq;
  55 };
  56 
  57 
  58 static void request_handler(struct smbcli_request *);
  59 static void composite_handler(struct composite_context *);
  60 
  61 /*
  62   a tree connect request has completed
  63 */
  64 static NTSTATUS connect_tcon(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
  65                              struct smb_composite_connect *io)
  66 {
  67         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
  68         NTSTATUS status;
  69 
  70         status = smb_raw_tcon_recv(state->req, c, state->io_tcon);
  71         NT_STATUS_NOT_OK_RETURN(status);
  72 
  73         io->out.tree->tid = state->io_tcon->tconx.out.tid;
  74         if (state->io_tcon->tconx.out.dev_type) {
  75                 io->out.tree->device = talloc_strdup(io->out.tree, 
  76                                                      state->io_tcon->tconx.out.dev_type);
  77         }
  78         if (state->io_tcon->tconx.out.fs_type) {
  79                 io->out.tree->fs_type = talloc_strdup(io->out.tree, 
  80                                                       state->io_tcon->tconx.out.fs_type);
  81         }
  82 
  83         state->stage = CONNECT_DONE;
  84 
  85         return NT_STATUS_OK;
  86 }
  87 
  88 
  89 /*
  90   a session setup request with anonymous fallback has completed
  91 */
  92 static NTSTATUS connect_session_setup_anon(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
  93                                            struct smb_composite_connect *io)
  94 {
  95         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
  96         NTSTATUS status;
  97 
  98         status = smb_composite_sesssetup_recv(state->creq);
  99         NT_STATUS_NOT_OK_RETURN(status);
 100 
 101         io->out.anonymous_fallback_done = true;
 102         
 103         state->session->vuid = state->io_setup->out.vuid;
 104         
 105         /* setup for a tconx */
 106         state->io_tcon = talloc(c, union smb_tcon);
 107         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
 108 
 109         /* connect to a share using a tree connect */
 110         state->io_tcon->generic.level = RAW_TCON_TCONX;
 111         state->io_tcon->tconx.in.flags = 0;
 112         state->io_tcon->tconx.in.password = data_blob(NULL, 0); 
 113         
 114         state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon, 
 115                                                  "\\\\%s\\%s", 
 116                                                  io->in.called_name, 
 117                                                  io->in.service);
 118         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
 119         if (!io->in.service_type) {
 120                 state->io_tcon->tconx.in.device = "?????";
 121         } else {
 122                 state->io_tcon->tconx.in.device = io->in.service_type;
 123         }
 124 
 125         state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
 126         NT_STATUS_HAVE_NO_MEMORY(state->req);
 127         if (state->req->state == SMBCLI_REQUEST_ERROR) {
 128                 return state->req->status;
 129         }
 130 
 131         state->req->async.fn = request_handler;
 132         state->req->async.private_data = c;
 133         state->stage = CONNECT_TCON;
 134 
 135         return NT_STATUS_OK;
 136 }
 137 
 138 /*
 139   a session setup request has completed
 140 */
 141 static NTSTATUS connect_session_setup(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 142                                       struct smb_composite_connect *io)
 143 {
 144         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 145         NTSTATUS status;
 146 
 147         status = smb_composite_sesssetup_recv(state->creq);
 148 
 149         if (!NT_STATUS_IS_OK(status) &&
 150             !cli_credentials_is_anonymous(state->io->in.credentials) &&
 151             io->in.fallback_to_anonymous) {
 152 
 153                 state->io_setup->in.credentials = cli_credentials_init(state);
 154                 NT_STATUS_HAVE_NO_MEMORY(state->io_setup->in.credentials);
 155                 cli_credentials_set_workstation(state->io_setup->in.credentials,
 156                    cli_credentials_get_workstation(state->io->in.credentials), 
 157                    CRED_SPECIFIED);
 158                 cli_credentials_set_anonymous(state->io_setup->in.credentials);
 159 
 160                 /* If the preceding attempt was with extended security, we
 161                  * have been given a uid in the NTLMSSP_CHALLENGE reply. This
 162                  * would lead to an invalid uid in the anonymous fallback */
 163                 state->session->vuid = 0;
 164                 data_blob_free(&state->session->user_session_key);
 165                 talloc_free(state->session->gensec);
 166                 state->session->gensec = NULL;
 167 
 168                 state->creq = smb_composite_sesssetup_send(state->session,
 169                                                            state->io_setup);
 170                 NT_STATUS_HAVE_NO_MEMORY(state->creq);
 171                 if (state->creq->state == COMPOSITE_STATE_ERROR) {
 172                         return state->creq->status;
 173                 }
 174                 state->creq->async.fn = composite_handler;
 175                 state->creq->async.private_data = c;
 176                 state->stage = CONNECT_SESSION_SETUP_ANON;
 177 
 178                 return NT_STATUS_OK;
 179         }
 180 
 181         NT_STATUS_NOT_OK_RETURN(status);
 182         
 183         state->session->vuid = state->io_setup->out.vuid;
 184         
 185         /* If we don't have a remote share name then this indicates that
 186          * we don't want to do a tree connect */
 187         if (!io->in.service) {
 188                 state->stage = CONNECT_DONE;
 189                 return NT_STATUS_OK;
 190         }
 191 
 192         state->io_tcon = talloc(c, union smb_tcon);
 193         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon);
 194 
 195         /* connect to a share using a tree connect */
 196         state->io_tcon->generic.level = RAW_TCON_TCONX;
 197         state->io_tcon->tconx.in.flags = 0;
 198         state->io_tcon->tconx.in.password = data_blob(NULL, 0); 
 199         
 200         state->io_tcon->tconx.in.path = talloc_asprintf(state->io_tcon, 
 201                                                  "\\\\%s\\%s", 
 202                                                  io->in.called_name, 
 203                                                  io->in.service);
 204         NT_STATUS_HAVE_NO_MEMORY(state->io_tcon->tconx.in.path);
 205         if (!io->in.service_type) {
 206                 state->io_tcon->tconx.in.device = "?????";
 207         } else {
 208                 state->io_tcon->tconx.in.device = io->in.service_type;
 209         }
 210 
 211         state->req = smb_raw_tcon_send(io->out.tree, state->io_tcon);
 212         NT_STATUS_HAVE_NO_MEMORY(state->req);
 213         if (state->req->state == SMBCLI_REQUEST_ERROR) {
 214                 return state->req->status;
 215         }
 216 
 217         state->req->async.fn = request_handler;
 218         state->req->async.private_data = c;
 219         state->stage = CONNECT_TCON;
 220 
 221         return NT_STATUS_OK;
 222 }
 223 
 224 /*
 225   a negprot request has completed
 226 */
 227 static NTSTATUS connect_negprot(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 228                                 struct smb_composite_connect *io)
 229 {
 230         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 231         NTSTATUS status;
 232 
 233         status = smb_raw_negotiate_recv(state->req);
 234         NT_STATUS_NOT_OK_RETURN(status);
 235 
 236         /* next step is a session setup */
 237         state->session = smbcli_session_init(state->transport, state, true, io->in.session_options);
 238         NT_STATUS_HAVE_NO_MEMORY(state->session);
 239         
 240         /* setup for a tconx (or at least have the structure ready to
 241          * return, if we won't go that far) */
 242         io->out.tree = smbcli_tree_init(state->session, state, true);
 243         NT_STATUS_HAVE_NO_MEMORY(io->out.tree);
 244 
 245         /* If we don't have any credentials then this indicates that
 246          * we don't want to do a session setup */
 247         if (!io->in.credentials) {
 248                 state->stage = CONNECT_DONE;
 249                 return NT_STATUS_OK;
 250         }
 251 
 252         state->io_setup = talloc(c, struct smb_composite_sesssetup);
 253         NT_STATUS_HAVE_NO_MEMORY(state->io_setup);
 254 
 255         /* prepare a session setup to establish a security context */
 256         state->io_setup->in.sesskey      = state->transport->negotiate.sesskey;
 257         state->io_setup->in.capabilities = state->transport->negotiate.capabilities;
 258         state->io_setup->in.credentials  = io->in.credentials;
 259         state->io_setup->in.workgroup    = io->in.workgroup;
 260         state->io_setup->in.gensec_settings = io->in.gensec_settings;
 261 
 262         state->creq = smb_composite_sesssetup_send(state->session, state->io_setup);
 263         NT_STATUS_HAVE_NO_MEMORY(state->creq);
 264         if (state->creq->state == COMPOSITE_STATE_ERROR) {
 265                 return state->creq->status;
 266         }
 267 
 268         state->creq->async.fn = composite_handler;
 269         state->creq->async.private_data = c;
 270 
 271         state->stage = CONNECT_SESSION_SETUP;
 272         
 273         return NT_STATUS_OK;
 274 }
 275 
 276 /*
 277   setup a negprot send 
 278 */
 279 static NTSTATUS connect_send_negprot(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 280                                      struct smb_composite_connect *io)
 281 {
 282         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 283 
 284         state->req = smb_raw_negotiate_send(state->transport, io->in.options.unicode, io->in.options.max_protocol);
 285         NT_STATUS_HAVE_NO_MEMORY(state->req);
 286 
 287         state->req->async.fn = request_handler;
 288         state->req->async.private_data = c;
 289         state->stage = CONNECT_NEGPROT;
 290         
 291         return NT_STATUS_OK;
 292 }
 293 
 294 
 295 /*
 296   a session request operation has completed
 297 */
 298 static NTSTATUS connect_session_request(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 299                                         struct smb_composite_connect *io)
 300 {
 301         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 302         NTSTATUS status;
 303 
 304         status = smbcli_transport_connect_recv(state->req);
 305         NT_STATUS_NOT_OK_RETURN(status);
 306 
 307         /* next step is a negprot */
 308         return connect_send_negprot(c, io);
 309 }
 310 
 311 /*
 312   a socket connection operation has completed
 313 */
 314 static NTSTATUS connect_socket(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 315                                struct smb_composite_connect *io)
 316 {
 317         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 318         NTSTATUS status;
 319         struct nbt_name calling, called;
 320 
 321         status = smbcli_sock_connect_recv(state->creq, state, &state->sock);
 322         NT_STATUS_NOT_OK_RETURN(status);
 323 
 324         /* the socket is up - we can initialise the smbcli transport layer */
 325         state->transport = smbcli_transport_init(state->sock, state, true, 
 326                                                  &io->in.options, io->in.iconv_convenience);
 327         NT_STATUS_HAVE_NO_MEMORY(state->transport);
 328 
 329         if (is_ipaddress(state->sock->hostname) &&
 330             (state->io->in.called_name != NULL)) {
 331                 /* If connecting to an IP address, we might want the real name
 332                  * of the host for later kerberos. The called name is a better
 333                  * approximation */
 334                 state->sock->hostname =
 335                         talloc_strdup(state->sock, io->in.called_name);
 336                 NT_STATUS_HAVE_NO_MEMORY(state->sock->hostname);
 337         }
 338 
 339         make_nbt_name_client(&calling, cli_credentials_get_workstation(io->in.credentials));
 340 
 341         nbt_choose_called_name(state, &called, io->in.called_name, NBT_NAME_SERVER);
 342 
 343         /* we have a connected socket - next step is a session
 344            request, if needed. Port 445 doesn't need it, so it goes
 345            straight to the negprot */
 346         if (state->sock->port == 445) {
 347                 status = nbt_name_dup(state->transport, &called, 
 348                                       &state->transport->called);
 349                 NT_STATUS_NOT_OK_RETURN(status);
 350                 return connect_send_negprot(c, io);
 351         }
 352 
 353         state->req = smbcli_transport_connect_send(state->transport, &calling, &called);
 354         NT_STATUS_HAVE_NO_MEMORY(state->req);
 355 
 356         state->req->async.fn = request_handler;
 357         state->req->async.private_data = c;
 358         state->stage = CONNECT_SESSION_REQUEST;
 359 
 360         return NT_STATUS_OK;
 361 }
 362 
 363 
 364 /*
 365   called when name resolution is finished
 366 */
 367 static NTSTATUS connect_resolve(struct composite_context *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 368                                 struct smb_composite_connect *io)
 369 {
 370         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 371         NTSTATUS status;
 372         const char *address;
 373 
 374         status = resolve_name_recv(state->creq, state, &address);
 375         NT_STATUS_NOT_OK_RETURN(status);
 376 
 377         state->creq = smbcli_sock_connect_send(state, address, 
 378                                                io->in.dest_ports,
 379                                                io->in.dest_host, 
 380                                                NULL, c->event_ctx, 
 381                                                   io->in.socket_options);
 382         NT_STATUS_HAVE_NO_MEMORY(state->creq);
 383 
 384         state->stage = CONNECT_SOCKET;
 385         state->creq->async.private_data = c;
 386         state->creq->async.fn = composite_handler;
 387 
 388         return NT_STATUS_OK;
 389 }
 390 
 391 
 392 /*
 393   handle and dispatch state transitions
 394 */
 395 static void state_handler(struct composite_context *c)
     /* [<][>][^][v][top][bottom][index][help] */
 396 {
 397         struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 398 
 399         switch (state->stage) {
 400         case CONNECT_RESOLVE:
 401                 c->status = connect_resolve(c, state->io);
 402                 break;
 403         case CONNECT_SOCKET:
 404                 c->status = connect_socket(c, state->io);
 405                 break;
 406         case CONNECT_SESSION_REQUEST:
 407                 c->status = connect_session_request(c, state->io);
 408                 break;
 409         case CONNECT_NEGPROT:
 410                 c->status = connect_negprot(c, state->io);
 411                 break;
 412         case CONNECT_SESSION_SETUP:
 413                 c->status = connect_session_setup(c, state->io);
 414                 break;
 415         case CONNECT_SESSION_SETUP_ANON:
 416                 c->status = connect_session_setup_anon(c, state->io);
 417                 break;
 418         case CONNECT_TCON:
 419                 c->status = connect_tcon(c, state->io);
 420                 break;
 421         }
 422 
 423         if (state->stage == CONNECT_DONE) {
 424                 /* all done! */
 425                 composite_done(c);
 426         } else {
 427                 composite_is_ok(c);
 428         }
 429 }
 430 
 431 
 432 /*
 433   handler for completion of a smbcli_request sub-request
 434 */
 435 static void request_handler(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 436 {
 437         struct composite_context *c = talloc_get_type(req->async.private_data,
 438                                                      struct composite_context);
 439         state_handler(c);
 440 }
 441 
 442 /*
 443   handler for completion of a smbcli_composite sub-request
 444 */
 445 static void composite_handler(struct composite_context *creq)
     /* [<][>][^][v][top][bottom][index][help] */
 446 {
 447         struct composite_context *c = talloc_get_type(creq->async.private_data, 
 448                                                      struct composite_context);
 449         state_handler(c);
 450 }
 451 
 452 /*
 453   a function to establish a smbcli_tree from scratch
 454 */
 455 struct composite_context *smb_composite_connect_send(struct smb_composite_connect *io,
     /* [<][>][^][v][top][bottom][index][help] */
 456                                                      TALLOC_CTX *mem_ctx,
 457                                                      struct resolve_context *resolve_ctx,
 458                                                      struct tevent_context *event_ctx)
 459 {
 460         struct composite_context *c;
 461         struct connect_state *state;
 462         struct nbt_name name;
 463 
 464         c = talloc_zero(mem_ctx, struct composite_context);
 465         if (c == NULL) goto failed;
 466 
 467         c->event_ctx = talloc_reference(c, event_ctx);
 468         if (c->event_ctx == NULL) goto failed;
 469 
 470         state = talloc_zero(c, struct connect_state);
 471         if (state == NULL) goto failed;
 472 
 473         if (io->in.gensec_settings == NULL) goto failed;
 474         state->io = io;
 475 
 476         c->state = COMPOSITE_STATE_IN_PROGRESS;
 477         c->private_data = state;
 478 
 479         state->stage = CONNECT_RESOLVE;
 480         make_nbt_name_server(&name, io->in.dest_host);
 481         state->creq = resolve_name_send(resolve_ctx, &name, c->event_ctx);
 482 
 483         if (state->creq == NULL) goto failed;
 484         state->creq->async.private_data = c;
 485         state->creq->async.fn = composite_handler;
 486 
 487         return c;
 488 failed:
 489         talloc_free(c);
 490         return NULL;
 491 }
 492 
 493 /*
 494   recv half of async composite connect code
 495 */
 496 NTSTATUS smb_composite_connect_recv(struct composite_context *c, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 497 {
 498         NTSTATUS status;
 499 
 500         status = composite_wait(c);
 501 
 502         if (NT_STATUS_IS_OK(status)) {
 503                 struct connect_state *state = talloc_get_type(c->private_data, struct connect_state);
 504                 talloc_steal(mem_ctx, state->io->out.tree);
 505         }
 506 
 507         talloc_free(c);
 508         return status;
 509 }
 510 
 511 /*
 512   sync version of smb_composite_connect 
 513 */
 514 NTSTATUS smb_composite_connect(struct smb_composite_connect *io, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 515                                struct resolve_context *resolve_ctx,
 516                                struct tevent_context *ev)
 517 {
 518         struct composite_context *c = smb_composite_connect_send(io, mem_ctx, resolve_ctx, ev);
 519         return smb_composite_connect_recv(c, mem_ctx);
 520 }

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