waf: added top level build rules
[samba.git] / librpc / rpc / binding.c
index d773b8b59134ee6692eb05f9722355059e7a3531..b7c3a40a0d14763d950adc9a8acace91bb48a9f7 100644 (file)
 */
 
 #include "includes.h"
+#include "../../lib/util/util_net.h"
 #include "librpc/gen_ndr/ndr_epmapper.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/rpc/dcerpc.h"
 #undef strcasecmp
+#undef strncasecmp
 
 #define MAX_PROTSEQ            10
 
@@ -85,7 +87,8 @@ static const struct {
        {"bigendian", DCERPC_PUSH_BIGENDIAN},
        {"smb2", DCERPC_SMB2},
        {"hdrsign", DCERPC_HEADER_SIGNING},
-       {"ndr64", DCERPC_NDR64}
+       {"ndr64", DCERPC_NDR64},
+       {"localaddress", DCERPC_LOCALADDRESS}
 };
 
 const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
@@ -113,7 +116,7 @@ const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
                                return talloc_asprintf(mem_ctx, " uuid %s/0x%02x", uuidstr, syntax.if_version);
                        } else { /* IPX */
                                return talloc_asprintf(mem_ctx, "IPX:%s", 
-                                               data_blob_hex_string(mem_ctx, &epm_floor->rhs.uuid.unknown));
+                                               data_blob_hex_string_upper(mem_ctx, &epm_floor->rhs.uuid.unknown));
                        }
 
                case EPM_PROTOCOL_NCACN:
@@ -219,7 +222,12 @@ _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bi
 
        for (i=0;i<ARRAY_SIZE(ncacn_options);i++) {
                if (b->flags & ncacn_options[i].flag) {
-                       s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+                       if (ncacn_options[i].flag == DCERPC_LOCALADDRESS && b->localaddress) {
+                               s = talloc_asprintf_append_buffer(s, ",%s=%s", ncacn_options[i].name,
+                                                                 b->localaddress);
+                       } else {
+                               s = talloc_asprintf_append_buffer(s, ",%s", ncacn_options[i].name);
+                       }
                        if (!s) return NULL;
                }
        }
@@ -239,7 +247,7 @@ _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struc
        char *p;
        int i, j, comma_count;
 
-       b = talloc(mem_ctx, struct dcerpc_binding);
+       b = talloc_zero(mem_ctx, struct dcerpc_binding);
        if (!b) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -312,6 +320,7 @@ _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struc
        b->flags = 0;
        b->assoc_group_id = 0;
        b->endpoint = NULL;
+       b->localaddress = NULL;
 
        if (!options) {
                *b_out = b;
@@ -338,8 +347,17 @@ _PUBLIC_ NTSTATUS dcerpc_parse_binding(TALLOC_CTX *mem_ctx, const char *s, struc
        /* some options are pre-parsed for convenience */
        for (i=0;b->options[i];i++) {
                for (j=0;j<ARRAY_SIZE(ncacn_options);j++) {
-                       if (strcasecmp(ncacn_options[j].name, b->options[i]) == 0) {
+                       size_t opt_len = strlen(ncacn_options[j].name);
+                       if (strncasecmp(ncacn_options[j].name, b->options[i], opt_len) == 0) {
                                int k;
+                               char c = b->options[i][opt_len];
+
+                               if (ncacn_options[j].flag == DCERPC_LOCALADDRESS && c == '=') {
+                                       b->localaddress = talloc_strdup(b, &b->options[i][opt_len+1]);
+                               } else if (c != 0) {
+                                       continue;
+                               }
+
                                b->flags |= ncacn_options[j].flag;
                                for (k=i;b->options[k];k++) {
                                        b->options[k] = b->options[k+1];
@@ -375,7 +393,7 @@ _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
        enum ndr_err_code ndr_err;
        uint16_t if_version=0;
 
-       ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx, NULL);
+       ndr = ndr_pull_init_blob(&epm_floor->lhs.lhs_data, mem_ctx);
        if (ndr == NULL) {
                talloc_free(mem_ctx);
                return NT_STATUS_NO_MEMORY;
@@ -403,14 +421,33 @@ _PUBLIC_ NTSTATUS dcerpc_floor_get_lhs_data(const struct epm_floor *epm_floor,
 
 static DATA_BLOB dcerpc_floor_pack_lhs_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
 {
-       struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx, NULL);
+       DATA_BLOB blob;
+       struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
 
        ndr->flags |= LIBNDR_FLAG_NOALIGN;
 
        ndr_push_GUID(ndr, NDR_SCALARS | NDR_BUFFERS, &syntax->uuid);
        ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version);
 
-       return ndr_push_blob(ndr);
+       blob = ndr_push_blob(ndr);
+       talloc_steal(mem_ctx, blob.data);
+       talloc_free(ndr);
+       return blob;
+}
+
+static DATA_BLOB dcerpc_floor_pack_rhs_if_version_data(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *syntax)
+{
+       DATA_BLOB blob;
+       struct ndr_push *ndr = ndr_push_init_ctx(mem_ctx);
+
+       ndr->flags |= LIBNDR_FLAG_NOALIGN;
+
+       ndr_push_uint16(ndr, NDR_SCALARS, syntax->if_version >> 16);
+
+       blob = ndr_push_blob(ndr);
+       talloc_steal(mem_ctx, blob.data);
+       talloc_free(ndr);
+       return blob;
 }
 
 const char *dcerpc_floor_get_rhs_data(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
@@ -614,7 +651,7 @@ _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        struct dcerpc_binding *binding;
 
-       binding = talloc(mem_ctx, struct dcerpc_binding);
+       binding = talloc_zero(mem_ctx, struct dcerpc_binding);
        NT_STATUS_HAVE_NO_MEMORY(binding);
 
        ZERO_STRUCT(binding->object);
@@ -648,14 +685,14 @@ _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
 
        /* Set endpoint */
        if (tower->num_floors >= 4) {
-               binding->endpoint = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[3]);
+               binding->endpoint = dcerpc_floor_get_rhs_data(binding, &tower->floors[3]);
        } else {
                binding->endpoint = NULL;
        }
 
        /* Set network address */
        if (tower->num_floors >= 5) {
-               binding->host = dcerpc_floor_get_rhs_data(mem_ctx, &tower->floors[4]);
+               binding->host = dcerpc_floor_get_rhs_data(binding, &tower->floors[4]);
                NT_STATUS_HAVE_NO_MEMORY(binding->host);
                binding->target_hostname = binding->host;
        }
@@ -691,29 +728,29 @@ _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
        /* Floor 0 */
        tower->floors[0].lhs.protocol = EPM_PROTOCOL_UUID;
 
-       tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx, &binding->object);
+       tower->floors[0].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors, &binding->object);
 
-       tower->floors[0].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+       tower->floors[0].rhs.uuid.unknown = dcerpc_floor_pack_rhs_if_version_data(tower->floors, &binding->object);
 
        /* Floor 1 */
        tower->floors[1].lhs.protocol = EPM_PROTOCOL_UUID;
 
-       tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(mem_ctx
+       tower->floors[1].lhs.lhs_data = dcerpc_floor_pack_lhs_data(tower->floors
                                                                &ndr_transfer_syntax);
 
-       tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(mem_ctx, 2);
+       tower->floors[1].rhs.uuid.unknown = data_blob_talloc_zero(tower->floors, 2);
 
        /* Floor 2 to num_protocols */
        for (i = 0; i < num_protocols; i++) {
                tower->floors[2 + i].lhs.protocol = protseq[i];
-               tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(mem_ctx, NULL, 0);
+               tower->floors[2 + i].lhs.lhs_data = data_blob_talloc(tower->floors, NULL, 0);
                ZERO_STRUCT(tower->floors[2 + i].rhs);
-               dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[2 + i], "");
+               dcerpc_floor_set_rhs_data(tower->floors, &tower->floors[2 + i], "");
        }
 
        /* The 4th floor contains the endpoint */
        if (num_protocols >= 2 && binding->endpoint) {
-               status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[3], binding->endpoint);
+               status = dcerpc_floor_set_rhs_data(tower->floors, &tower->floors[3], binding->endpoint);
                if (NT_STATUS_IS_ERR(status)) {
                        return status;
                }
@@ -721,8 +758,9 @@ _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
 
        /* The 5th contains the network address */
        if (num_protocols >= 3 && binding->host) {
-               if (is_ipaddress(binding->host)) {
-                       status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], 
+               if (is_ipaddress(binding->host) ||
+                   (binding->host[0] == '\\' && binding->host[1] == '\\')) {
+                       status = dcerpc_floor_set_rhs_data(tower->floors, &tower->floors[4], 
                                                           binding->host);
                } else {
                        /* note that we don't attempt to resolve the
@@ -730,7 +768,7 @@ _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
                           are in the client code, and want to put in
                           a wildcard all-zeros IP for the server to
                           fill in */
-                       status = dcerpc_floor_set_rhs_data(mem_ctx, &tower->floors[4], 
+                       status = dcerpc_floor_set_rhs_data(tower->floors, &tower->floors[4], 
                                                           "0.0.0.0");
                }
                if (NT_STATUS_IS_ERR(status)) {