ncacn_http: DCERPC pipe open using http transport
authorSamuel Cabrero <samuelcabrero@kernevil.me>
Tue, 16 Sep 2014 15:01:02 +0000 (17:01 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 22 Sep 2014 21:09:08 +0000 (23:09 +0200)
Signed-off-by: Samuel Cabrero <samuelcabrero@kernevil.me>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/librpc/rpc/dcerpc_connect.c

index ecb531503884b2c6a494be21161bbf4ebb20c82a..fe3a0c8a6227943dc74c98f502879bc1673b7e7d 100644 (file)
@@ -403,6 +403,177 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp_recv(struct composite_context *
 }
 
 
+struct pipe_http_state {
+       struct dcerpc_pipe_connect io;
+       const char *localaddr;
+       const char *rpc_server;
+       uint32_t rpc_server_port;
+       char *rpc_proxy;
+       uint32_t rpc_proxy_port;
+       char *http_proxy;
+       uint32_t http_proxy_port;
+       bool use_tls;
+       bool use_proxy;
+       bool use_ntlm;
+       struct loadparm_context *lp_ctx;
+};
+
+/*
+  Stage 2 of ncacn_http: rpc pipe opened (or not)
+ */
+static void continue_pipe_open_ncacn_http(struct tevent_req *subreq)
+{
+       struct composite_context *c = NULL;
+       struct pipe_http_state *s = NULL;
+       struct tstream_context *stream = NULL;
+       struct tevent_queue *queue = NULL;
+
+       c = tevent_req_callback_data(subreq, struct composite_context);
+       s = talloc_get_type(c->private_data, struct pipe_http_state);
+
+       /* receive result of RoH connect request */
+       c->status = dcerpc_pipe_open_roh_recv(subreq, s->io.conn,
+                                             &stream, &queue);
+       TALLOC_FREE(subreq);
+       if (!composite_is_ok(c)) return;
+
+       s->io.conn->transport.transport = NCACN_HTTP;
+       s->io.conn->transport.stream = stream;
+       s->io.conn->transport.write_queue = queue;
+       s->io.conn->transport.pending_reads = 0;
+
+       composite_done(c);
+}
+
+/*
+  Initiate async open of a rpc connection to a rpc pipe using HTTP transport,
+  and using the binding structure to determine the endpoint and options
+*/
+static struct composite_context* dcerpc_pipe_connect_ncacn_http_send(
+               TALLOC_CTX *mem_ctx, struct dcerpc_pipe_connect *io,
+               struct loadparm_context *lp_ctx)
+{
+       struct composite_context *c;
+       struct pipe_http_state *s;
+       struct tevent_req *subreq;
+       const char *endpoint;
+       const char *use_proxy;
+       char *proxy;
+       char *port;
+       const char *opt;
+
+       /* composite context allocation and setup */
+       c = composite_create(mem_ctx, io->conn->event_ctx);
+       if (c == NULL) return NULL;
+
+       s = talloc_zero(c, struct pipe_http_state);
+       if (composite_nomem(s, c)) return c;
+       c->private_data = s;
+
+       /* store input parameters in state structure */
+       s->lp_ctx       = lp_ctx;
+       s->io           = *io;
+       s->localaddr    = dcerpc_binding_get_string_option(io->binding,
+                                                       "localaddress");
+       /* RPC server and port (the endpoint) */
+       s->rpc_server = dcerpc_binding_get_string_option(io->binding, "host");
+       endpoint = dcerpc_binding_get_string_option(io->binding, "endpoint");
+       if (endpoint == NULL) {
+               composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+               return c;
+       }
+       s->rpc_server_port = atoi(endpoint);
+       if (s->rpc_server_port == 0) {
+               composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+               return c;
+       }
+
+       /* Use TLS */
+       opt = dcerpc_binding_get_string_option(io->binding, "HttpUseTls");
+       if (opt) {
+               if (strcasecmp(opt, "true") == 0) {
+                       s->use_tls = true;
+               } else if (strcasecmp(opt, "false") == 0) {
+                       s->use_tls = false;
+               } else {
+                       composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+                       return c;
+               }
+       } else {
+               s->use_tls = true;
+       }
+
+       /* RPC Proxy */
+       proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
+                       io->binding, "RpcProxy"));
+       s->rpc_proxy  = strsep(&port, ":");
+       if (proxy && port) {
+               s->rpc_proxy_port = atoi(port);
+       } else {
+               s->rpc_proxy_port = s->use_tls ? 443 : 80;
+       }
+       if (s->rpc_proxy == NULL) {
+               s->rpc_proxy = talloc_strdup(s, s->rpc_server);
+               if (composite_nomem(s->rpc_proxy, c)) return c;
+       }
+
+       /* HTTP Proxy */
+       proxy = port = talloc_strdup(s, dcerpc_binding_get_string_option(
+                       io->binding, "HttpProxy"));
+       s->http_proxy = strsep(&port, ":");
+       if (proxy && port) {
+               s->http_proxy_port = atoi(port);
+       } else {
+               s->http_proxy_port = s->use_tls ? 443 : 80;
+       }
+
+       /* Use local proxy */
+       use_proxy = dcerpc_binding_get_string_option(io->binding,
+                                                "HttpConnectOption");
+       if (use_proxy && strcasecmp(use_proxy, "UseHttpProxy")) {
+               s->use_proxy = true;
+       }
+
+       /* If use local proxy set, the http proxy should be provided */
+       if (s->use_proxy && !s->http_proxy) {
+               composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+               return c;
+       }
+
+       /* Check which HTTP authentication method to use */
+       opt = dcerpc_binding_get_string_option(io->binding, "HttpAuthOption");
+       if (opt) {
+               if (strcasecmp(opt, "basic") == 0) {
+                       s->use_ntlm = false;
+               } else if (strcasecmp(opt, "ntlm") == 0) {
+                       s->use_ntlm = true;
+               } else {
+                       composite_error(c, NT_STATUS_INVALID_PARAMETER_MIX);
+                       return c;
+               }
+       } else {
+               s->use_ntlm = true;
+       }
+
+       subreq = dcerpc_pipe_open_roh_send(s->io.conn, s->localaddr,
+                                          s->rpc_server, s->rpc_server_port,
+                                          s->rpc_proxy, s->rpc_proxy_port,
+                                          s->http_proxy, s->http_proxy_port,
+                                          s->use_tls, s->use_proxy,
+                                          s->io.creds, io->resolve_ctx,
+                                          s->lp_ctx, s->use_ntlm);
+       if (composite_nomem(subreq, c)) return c;
+
+       tevent_req_set_callback(subreq, continue_pipe_open_ncacn_http, c);
+       return c;
+}
+
+static NTSTATUS dcerpc_pipe_connect_ncacn_http_recv(struct composite_context *c)
+{
+       return composite_wait_free(c);
+}
+
+
 struct pipe_unix_state {
        struct dcerpc_pipe_connect io;
        const char *path;
@@ -559,6 +730,7 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
 static void continue_pipe_connect_ncacn_np_smb2(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_np_smb(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx);
+static void continue_pipe_connect_ncacn_http(struct composite_context *ctx);
 static void continue_pipe_connect_ncacn_unix(struct composite_context *ctx);
 static void continue_pipe_connect_ncalrpc(struct composite_context *ctx);
 static void continue_pipe_connect(struct composite_context *c, struct pipe_connect_state *s);
@@ -597,6 +769,7 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
        struct composite_context *ncacn_np_smb2_req;
        struct composite_context *ncacn_np_smb_req;
        struct composite_context *ncacn_ip_tcp_req;
+       struct composite_context *ncacn_http_req;
        struct composite_context *ncacn_unix_req;
        struct composite_context *ncalrpc_req;
        enum dcerpc_transport_t transport;
@@ -635,6 +808,11 @@ static void continue_connect(struct composite_context *c, struct pipe_connect_st
                composite_continue(c, ncacn_ip_tcp_req, continue_pipe_connect_ncacn_ip_tcp, c);
                return;
 
+       case NCACN_HTTP:
+               ncacn_http_req = dcerpc_pipe_connect_ncacn_http_send(c, &pc, s->lp_ctx);
+               composite_continue(c, ncacn_http_req, continue_pipe_connect_ncacn_http, c);
+               return;
+
        case NCACN_UNIX_STREAM:
                ncacn_unix_req = dcerpc_pipe_connect_ncacn_unix_stream_send(c, &pc);
                composite_continue(c, ncacn_unix_req, continue_pipe_connect_ncacn_unix, c);
@@ -709,6 +887,23 @@ static void continue_pipe_connect_ncacn_ip_tcp(struct composite_context *ctx)
 }
 
 
+/*
+  Stage 3 of pipe_connect_b: Receive result of pipe connect request on http
+*/
+static void continue_pipe_connect_ncacn_http(struct composite_context *ctx)
+{
+       struct composite_context *c = talloc_get_type(ctx->async.private_data,
+                                                     struct composite_context);
+       struct pipe_connect_state *s = talloc_get_type(c->private_data,
+                                                      struct pipe_connect_state);
+
+       c->status = dcerpc_pipe_connect_ncacn_http_recv(ctx);
+       if (!composite_is_ok(c)) return;
+
+       continue_pipe_connect(c, s);
+}
+
+
 /*
   Stage 3 of pipe_connect_b: Receive result of pipe connect request on unix socket
 */
@@ -847,6 +1042,7 @@ _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent
        switch (transport) {
        case NCACN_NP:
        case NCACN_IP_TCP:
+       case NCACN_HTTP:
        case NCALRPC:
                endpoint = dcerpc_binding_get_string_option(s->binding, "endpoint");
                break;