librpc: Added a dcerpc_binding_dup() function.
[nivanova/samba-autobuild/.git] / librpc / rpc / binding.c
index 5e9bef8e7c370d464aa75ff82f4342cc8415104a..cc0aed931a18f9ca19bee698471ff46d92c15266 100644 (file)
 #include "librpc/gen_ndr/ndr_epmapper.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "librpc/rpc/dcerpc.h"
+#include "rpc_common.h"
+
 #undef strcasecmp
+#undef strncasecmp
 
 #define MAX_PROTSEQ            10
 
@@ -86,7 +89,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)
@@ -220,7 +224,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;
                }
        }
@@ -240,7 +249,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;
        }
@@ -313,6 +322,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;
@@ -339,8 +349,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];
@@ -634,7 +653,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);
@@ -668,14 +687,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;
        }
@@ -683,6 +702,86 @@ _PUBLIC_ NTSTATUS dcerpc_binding_from_tower(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
+_PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
+                                                  const struct dcerpc_binding *b)
+{
+       struct dcerpc_binding *n;
+       uint32_t count;
+
+       n = talloc_zero(mem_ctx, struct dcerpc_binding);
+       if (n == NULL) {
+               return NULL;
+       }
+
+       n->transport = b->transport;
+       n->object = b->object;
+       n->flags = b->flags;
+       n->assoc_group_id = b->assoc_group_id;
+
+       if (b->host != NULL) {
+               n->host = talloc_strdup(n, b->host);
+               if (n->host == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
+       if (b->target_hostname != NULL) {
+               n->target_hostname = talloc_strdup(n, b->target_hostname);
+               if (n->target_hostname == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
+       if (b->target_principal != NULL) {
+               n->target_principal = talloc_strdup(n, b->target_principal);
+               if (n->target_principal == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
+       if (b->localaddress != NULL) {
+               n->localaddress = talloc_strdup(n, b->localaddress);
+               if (n->localaddress == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
+       if (b->endpoint != NULL) {
+               n->endpoint = talloc_strdup(n, b->endpoint);
+               if (n->endpoint == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
+       for (count = 0; b->options && b->options[count]; count++);
+
+       if (count > 0) {
+               uint32_t i;
+
+               n->options = talloc_array(n, const char *, count + 1);
+               if (n->options == NULL) {
+                       talloc_free(n);
+                       return NULL;
+               }
+
+               for (i = 0; i < count; i++) {
+                       n->options[i] = talloc_strdup(n->options, b->options[i]);
+                       if (n->options[i] == NULL) {
+                               talloc_free(n);
+                               return NULL;
+                       }
+               }
+               n->options[count] = NULL;
+       }
+
+       return n;
+}
+
 _PUBLIC_ NTSTATUS dcerpc_binding_build_tower(TALLOC_CTX *mem_ctx,
                                             const struct dcerpc_binding *binding,
                                             struct epm_tower *tower)
@@ -741,7 +840,8 @@ _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)) {
+               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 {