s4:libcli/raw: copy smbcli_transport_connect_* to clisocket.c
[kai/samba.git] / source4 / libcli / raw / clisocket.c
index 8fcb8bb48c7e06692ec4f29247c3e774b2907a68..70a83a493f03c8d317e885766f3282b872438e04 100644 (file)
 #include "lib/socket/socket.h"
 #include "libcli/resolve/resolve.h"
 #include "param/param.h"
+#include "libcli/raw/raw_proto.h"
+
+/*
+  send a session request
+*/
+struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
+                                                    struct nbt_name *calling, 
+                                                    struct nbt_name *called)
+{
+       uint8_t *p;
+       struct smbcli_request *req;
+       DATA_BLOB calling_blob, called_blob;
+       TALLOC_CTX *tmp_ctx = talloc_new(transport);
+       NTSTATUS status;
+
+       status = nbt_name_dup(transport, called, &transport->called);
+       if (!NT_STATUS_IS_OK(status)) goto failed;
+       
+       status = nbt_name_to_blob(tmp_ctx, &calling_blob, calling);
+       if (!NT_STATUS_IS_OK(status)) goto failed;
+
+       status = nbt_name_to_blob(tmp_ctx, &called_blob, called);
+       if (!NT_STATUS_IS_OK(status)) goto failed;
+
+       /* allocate output buffer */
+       req = smbcli_request_setup_nonsmb(transport, 
+                                         NBT_HDR_SIZE + 
+                                         calling_blob.length + called_blob.length);
+       if (req == NULL) goto failed;
+
+       /* put in the destination name */
+       p = req->out.buffer + NBT_HDR_SIZE;
+       memcpy(p, called_blob.data, called_blob.length);
+       p += called_blob.length;
+
+       memcpy(p, calling_blob.data, calling_blob.length);
+       p += calling_blob.length;
+
+       _smb_setlen_nbt(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE);
+       SCVAL(req->out.buffer,0,0x81);
+
+       if (!smbcli_request_send(req)) {
+               smbcli_request_destroy(req);
+               goto failed;
+       }
+
+       talloc_free(tmp_ctx);
+       return req;
+
+failed:
+       talloc_free(tmp_ctx);
+       return NULL;
+}
+
+/*
+  map a session request error to a NTSTATUS
+ */
+static NTSTATUS map_session_refused_error(uint8_t error)
+{
+       switch (error) {
+       case 0x80:
+       case 0x81:
+               return NT_STATUS_REMOTE_NOT_LISTENING;
+       case 0x82:
+               return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
+       case 0x83:
+               return NT_STATUS_REMOTE_RESOURCES;
+       }
+       return NT_STATUS_UNEXPECTED_IO_ERROR;
+}
+
+
+/*
+  finish a smbcli_transport_connect()
+*/
+NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
+{
+       NTSTATUS status;
+
+       if (!smbcli_request_receive(req)) {
+               smbcli_request_destroy(req);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       switch (CVAL(req->in.buffer,0)) {
+       case 0x82:
+               status = NT_STATUS_OK;
+               break;
+       case 0x83:
+               status = map_session_refused_error(CVAL(req->in.buffer,4));
+               break;
+       case 0x84:
+               DEBUG(1,("Warning: session retarget not supported\n"));
+               status = NT_STATUS_NOT_SUPPORTED;
+               break;
+       default:
+               status = NT_STATUS_UNEXPECTED_IO_ERROR;
+               break;
+       }
+
+       smbcli_request_destroy(req);
+       return status;
+}
+
+
+/*
+  send a session request (if needed)
+*/
+bool smbcli_transport_connect(struct smbcli_transport *transport,
+                             struct nbt_name *calling, 
+                             struct nbt_name *called)
+{
+       struct smbcli_request *req;
+       NTSTATUS status;
+
+       if (transport->socket->port == 445) {
+               return true;
+       }
+
+       req = smbcli_transport_connect_send(transport, 
+                                           calling, called);
+       status = smbcli_transport_connect_recv(req);
+       return NT_STATUS_IS_OK(status);
+}
 
 struct sock_connect_state {
        struct composite_context *ctx;
        const char *host_name;
        int num_ports;
        uint16_t *ports;
+       const char *socket_options;
        struct smbcli_socket *result;
 };
 
@@ -48,7 +173,8 @@ struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
                                                   const char **ports,
                                                   const char *host_name,
                                                   struct resolve_context *resolve_ctx,
-                                                  struct event_context *event_ctx)
+                                                  struct tevent_context *event_ctx,
+                                                  const char *socket_options)
 {
        struct composite_context *result, *ctx;
        struct sock_connect_state *state;
@@ -58,12 +184,7 @@ struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
        if (result == NULL) goto failed;
        result->state = COMPOSITE_STATE_IN_PROGRESS;
 
-       if (event_ctx != NULL) {
-               result->event_ctx = talloc_reference(result, event_ctx);
-       } else {
-               result->event_ctx = event_context_init(result);
-       }
-
+       result->event_ctx = event_ctx;
        if (result->event_ctx == NULL) goto failed;
 
        state = talloc(result, struct sock_connect_state);
@@ -80,6 +201,11 @@ struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
        for (i=0;ports[i];i++) {
                state->ports[i] = atoi(ports[i]);
        }
+       state->socket_options = talloc_reference(state, socket_options);
+
+       if (!host_addr) {
+               host_addr = host_name;
+       }
 
        ctx = socket_connect_multi_send(state, host_addr,
                                        state->num_ports, state->ports,
@@ -108,7 +234,7 @@ static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
        if (!composite_is_ok(state->ctx)) return;
 
        state->ctx->status =
-               socket_set_option(sock, lp_socket_options(global_loadparm), NULL);
+               socket_set_option(sock, state->socket_options, NULL);
        if (!composite_is_ok(state->ctx)) return;
 
 
@@ -119,8 +245,7 @@ static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
        state->result->port = port;
        state->result->hostname = talloc_steal(sock, state->host_name);
 
-       state->result->event.ctx =
-               talloc_reference(state->result, state->ctx->event_ctx);
+       state->result->event.ctx = state->ctx->event_ctx;
        if (composite_nomem(state->result->event.ctx, state->ctx)) return;
 
        composite_done(state->ctx);
@@ -154,13 +279,14 @@ NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
                             const char *host_addr, const char **ports,
                             const char *host_name,
                             struct resolve_context *resolve_ctx,
-                            struct event_context *event_ctx,
+                            struct tevent_context *event_ctx,
+                                const char *socket_options,
                             struct smbcli_socket **result)
 {
        struct composite_context *c =
                smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
                                         resolve_ctx,
-                                        event_ctx);
+                                        event_ctx, socket_options);
        return smbcli_sock_connect_recv(c, mem_ctx, result);
 }
 
@@ -168,7 +294,7 @@ NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
 /****************************************************************************
  mark the socket as dead
 ****************************************************************************/
-void smbcli_sock_dead(struct smbcli_socket *sock)
+_PUBLIC_ void smbcli_sock_dead(struct smbcli_socket *sock)
 {
        talloc_free(sock->event.fde);
        sock->event.fde = NULL;
@@ -187,10 +313,11 @@ void smbcli_sock_set_options(struct smbcli_socket *sock, const char *options)
 /****************************************************************************
 resolve a hostname and connect 
 ****************************************************************************/
-struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **ports,
+_PUBLIC_ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **ports,
                                                 TALLOC_CTX *mem_ctx,
                                                 struct resolve_context *resolve_ctx,
-                                                struct event_context *event_ctx)
+                                                struct tevent_context *event_ctx,
+                                                const char *socket_options)
 {
        int name_type = NBT_NAME_SERVER;
        const char *address;
@@ -200,6 +327,11 @@ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        struct smbcli_socket *result;
 
+       if (event_ctx == NULL) {
+               DEBUG(0, ("Invalid NULL event context passed in as parameter\n"));
+               return NULL;
+       }
+
        if (tmp_ctx == NULL) {
                DEBUG(0, ("talloc_new failed\n"));
                return NULL;
@@ -212,16 +344,6 @@ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **
                return NULL;
        }
 
-       if (event_ctx == NULL) {
-               event_ctx = event_context_init(mem_ctx);
-       }
-
-       if (event_ctx == NULL) {
-               DEBUG(0, ("event_context_init failed\n"));
-               talloc_free(tmp_ctx);
-               return NULL;
-       }
-
        /* allow hostnames of the form NAME#xx and do a netbios lookup */
        if ((p = strchr(name, '#'))) {
                name_type = strtol(p+1, NULL, 16);
@@ -230,14 +352,15 @@ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, const char **
 
        make_nbt_name(&nbt_name, host, name_type);
        
-       status = resolve_name(resolve_ctx, &nbt_name, tmp_ctx, &address, event_ctx);
+       status = resolve_name_ex(resolve_ctx, 0, 0, &nbt_name, tmp_ctx, &address, event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
                return NULL;
        }
 
        status = smbcli_sock_connect(mem_ctx, address, ports, name, resolve_ctx,
-                                    event_ctx, &result);
+                                    event_ctx, 
+                                        socket_options, &result);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(9, ("smbcli_sock_connect failed: %s\n",