s4:libcli/raw: copy smbcli_transport_connect_* to clisocket.c
[kai/samba.git] / source4 / libcli / raw / clisocket.c
index d51ffbaa746b8ee90a97077e59f9243c9cb2b602..70a83a493f03c8d317e885766f3282b872438e04 100644 (file)
 #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;
@@ -50,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;
@@ -60,7 +184,7 @@ struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
        if (result == NULL) goto failed;
        result->state = COMPOSITE_STATE_IN_PROGRESS;
 
-       result->event_ctx = talloc_reference(result, event_ctx);
+       result->event_ctx = event_ctx;
        if (result->event_ctx == NULL) goto failed;
 
        state = talloc(result, struct sock_connect_state);
@@ -77,7 +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 = lp_socket_options(global_loadparm);
+       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,
@@ -117,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);
@@ -152,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);
 }
 
@@ -188,7 +316,8 @@ resolve a hostname and connect
 _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;
@@ -223,14 +352,15 @@ _PUBLIC_ struct smbcli_socket *smbcli_sock_connect_byname(const char *host, cons
 
        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",