TODO _dcerpc_binding_set_pointer_option
authorStefan Metzmacher <metze@samba.org>
Fri, 17 Oct 2014 11:11:32 +0000 (13:11 +0200)
committerStefan Metzmacher <metze@samba.org>
Tue, 4 Jun 2019 10:43:20 +0000 (12:43 +0200)
librpc/rpc/binding.c

index 5027dacc9c331aeb5663ea4c0729c0d77d224606..4b3beaecba56a68169199414cd6dc932f3fe6383 100644 (file)
 
 #define MAX_PROTSEQ            10
 
+struct dcerpc_binding_pointer_ref;
+
+struct dcerpc_binding_pointer {
+       struct dcerpc_binding *b;
+       struct dcerpc_binding_pointer_ref *r;
+       const char *name;
+       const char *type;
+       const void *pointer;
+};
+
+struct dcerpc_binding_pointer_ref {
+       struct dcerpc_binding_pointer *p;
+};
+
 struct dcerpc_binding {
        enum dcerpc_transport_t transport;
        struct GUID object;
@@ -50,6 +64,8 @@ struct dcerpc_binding {
        uint32_t flags;
        uint32_t assoc_group_id;
        char assoc_group_string[11]; /* 0x3456789a + '\0' */
+       uint8_t num_pointers;
+       struct dcerpc_binding_pointer **pointers;
 };
 
 static const struct {
@@ -211,8 +227,11 @@ const char *epm_floor_string(TALLOC_CTX *mem_ctx, struct epm_floor *epm_floor)
 
 /*
   form a binding string from a binding structure
+  TODO
 */
-_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
+static char *dcerpc_binding_string_ex(TALLOC_CTX *mem_ctx,
+                                       const struct dcerpc_binding *b,
+                                       uint64_t flags)
 {
        char *s = talloc_strdup(mem_ctx, "");
        char *o = s;
@@ -274,6 +293,8 @@ _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bi
                option_section = true;
        } else if (b->options) {
                option_section = true;
+       } else if (b->num_pointers != 0) {
+               option_section = true;
        } else if (b->flags) {
                option_section = true;
        }
@@ -350,6 +371,23 @@ _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bi
                }
        }
 
+       for (i=0; b->num_pointers; i++) {
+               struct dcerpc_binding_pointer *p = b->pointers[i];
+               char tsbuf[512];
+
+               snprintf(tsbuf, sizeof(tsbuf),
+                        "pointer(%d:%p):%s=(%s *)%p",
+                        getpid(), p->pointer,
+                        p->name, p->type, p->pointer);
+
+               o = s;
+               s = talloc_asprintf_append_buffer(s, ",%s", tsbuf);
+               if (s == NULL) {
+                       talloc_free(o);
+                       return NULL;
+               }
+       }
+
        o = s;
        s = talloc_asprintf_append_buffer(s, "]");
        if (s == NULL) {
@@ -360,6 +398,14 @@ _PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_bi
        return s;
 }
 
+/*
+  form a binding string from a binding structure
+*/
+_PUBLIC_ char *dcerpc_binding_string(TALLOC_CTX *mem_ctx, const struct dcerpc_binding *b)
+{
+       return dcerpc_binding_string_ex(mem_ctx, b, 0);
+}
+
 /*
   parse a binding string into a dcerpc_binding structure
 */
@@ -809,6 +855,11 @@ _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
         * value != NULL means add or reset.
         */
 
+       ret = strncmp(name, "pointer(", 8);
+       if (ret == 0) {
+               return NT_STATUS_INVALID_PARAMETER_MIX;
+       }
+
        ret = strcmp(name, "transport");
        if (ret == 0) {
                enum dcerpc_transport_t t = dcerpc_transport_by_name(value);
@@ -953,58 +1004,137 @@ _PUBLIC_ NTSTATUS dcerpc_binding_set_string_option(struct dcerpc_binding *b,
        return NT_STATUS_OK;
 }
 
-_PUBLIC_ void *_dcerpc_binding_get_pointer_option(const struct dcerpc_binding *b,
-                                                 const char *name, const char *type)
+static uint8_t dcerpc_binding_find_pointer_idx(const struct dcerpc_binding *b,
+                                             const char *name,
+                                             const char *type)
 {
-       char tsbuf[256];
-       const char *vs;
-       char *end = NULL;
-       unsigned long long vl;
-       uintptr_t vp;
+       uint8_t i;
 
-       if (strlen(name) > 100) {
-               return NULL;
+       for (i = 0; i < b->num_pointers; i++) {
+               struct dcerpc_binding_pointer *p = b->pointers[i];
+               int ret;
+
+               ret = strcmp(p->name, name);
+               if (ret != 0) {
+                       continue;
+               }
+
+               ret = strcmp(p->type, type);
+               if (ret != 0) {
+                       continue;
+               }
+
+               return i;
        }
 
-       if (strlen(type) > 100) {
-               return NULL;
+       return UINT8_MAX;
+}
+
+static int dcerpc_binding_pointer_destructor(struct dcerpc_binding_pointer *p)
+{
+       struct dcerpc_binding *b = p->b;
+       uint8_t i;
+       uint8_t idx = UINT8_MAX;
+
+       if (p->r != NULL) {
+               p->r->p = NULL;
+               TALLOC_FREE(p->r);
        }
 
-       snprintf(tsbuf, sizeof(tsbuf), "%s:pointer:%d:%s", name, getpid(), type);
+       for (i = 0; i < b->num_pointers; i++) {
+               if (p != b->pointers[i]) {
+                       continue;
+               }
 
-       vs = dcerpc_binding_get_string_option(b, tsbuf);
-       if (vs == NULL) {
-               return NULL;
+               idx = i;
+               break;
        }
 
-       errno = 0;
-       vl = strtoull(vs, &end, 16);
-       if (errno != 0) {
-               return NULL;
+       if (idx == UINT8_MAX) {
+               return 0;
        }
-       if (end == NULL) {
-               return NULL;
+
+       for (i = idx + 1; i < b->num_pointers; i++) {
+               b->pointers[i - 1] = b->pointers[i];
        }
-       if (end[0] != '\0') {
-               return NULL;
+
+       b->num_pointers -= 1;
+       b->pointers = talloc_realloc(b, b->pointers,
+                                    struct dcerpc_binding_pointer *,
+                                    b->num_pointers);
+
+       return 0;
+}
+
+static int dcerpc_binding_pointer_ref_destructor(struct dcerpc_binding_pointer_ref *r)
+{
+       if (r->p == NULL) {
+               return 0;
        }
 
-       vp = vl;
-       if (vp != vl) {
+       r->p->r = NULL;
+       TALLOC_FREE(r->p);
+       return 0;
+}
+
+_PUBLIC_ void *_dcerpc_binding_get_pointer_option(const struct dcerpc_binding *b,
+                                                 const char *name, const char *type)
+{
+       struct dcerpc_binding_pointer *p;
+       uint8_t idx;
+
+       idx = dcerpc_binding_find_pointer_idx(b, name, type);
+       if (idx == UINT8_MAX) {
                return NULL;
        }
 
-       return (void *)vp;
+       p = b->pointers[idx];
+
+       return discard_const(p->pointer);
+}
+
+#if 0
+_PUBLIC_ void dcerpc_binding_clear_pointer_options(struct dcerpc_binding *b,
+                                                  const char *name,
+                                                  const char *type)
+{
+       uint8_t i;
+
+       for (i = 0; i < b->num_pointers; ) {
+               struct dcerpc_binding_pointer *p = b->pointers[i];
+               int ret;
+
+               if (name != NULL) {
+                       ret = strcmp(p->name, name);
+                       if (ret != 0) {
+                               i++;
+                               continue;
+                       }
+               }
+
+               if (type != NULL) {
+                       ret = strcmp(p->type, type);
+                       if (ret != 0) {
+                               i++;
+                               continue;
+                       }
+               }
+
+               /*
+                * This removes the element at index 'i'
+                */
+               talloc_free(b->pointers[i]);
+       }
 }
+#endif
 
 _PUBLIC_ NTSTATUS _dcerpc_binding_set_pointer_option(struct dcerpc_binding *b,
                                                     const char *name,
                                                     const char *type,
-                                                    const void *vp)
+                                                    const void *pointer)
 {
-       char tsbuf[256];
-       char vsbuf[20];
-       const char *vs = NULL;
+       struct dcerpc_binding_pointer *p = NULL;
+       uint8_t idx;
 
        if (strlen(name) > 100) {
                return NT_STATUS_INVALID_PARAMETER_MIX;
@@ -1014,14 +1144,78 @@ _PUBLIC_ NTSTATUS _dcerpc_binding_set_pointer_option(struct dcerpc_binding *b,
                return NT_STATUS_INVALID_PARAMETER_MIX;
        }
 
-       snprintf(tsbuf, sizeof(tsbuf), "%s:pointer:%d:%s", name, getpid(), type);
+       if (pointer != NULL) {
+               const void *pv = talloc_check_name(pointer, type);
 
-       if (vp != NULL) {
-               snprintf(vsbuf, sizeof(vsbuf), "%p", vp);
-               vs = vsbuf;
+               if (pv == NULL) {
+                       return NT_STATUS_INVALID_PARAMETER_MIX;
+               }
        }
 
-       return dcerpc_binding_set_string_option(b, tsbuf, vs);
+       if (b->num_pointers >= INT8_MAX) {
+               return NT_STATUS_TOO_MANY_ADDRESSES;
+       }
+
+       idx = dcerpc_binding_find_pointer_idx(b, name, type);
+       if (idx == UINT8_MAX) {
+               struct dcerpc_binding_pointer **r = NULL;
+
+               if (pointer == NULL) {
+                       return NT_STATUS_OK;
+               }
+
+               r = talloc_realloc(b, b->pointers,
+                                  struct dcerpc_binding_pointer *,
+                                  b->num_pointers + 1);
+               if (r == NULL) {
+                       goto nomem;
+               }
+               b->pointers = r;
+
+               idx = b->num_pointers;
+               b->pointers[idx] = NULL;
+               b->num_pointers += 1;
+       }
+
+       if (pointer == NULL) {
+               talloc_free(b->pointers[idx]);
+               return NT_STATUS_OK;
+       }
+
+       p = talloc_zero(b->pointers, struct dcerpc_binding_pointer);
+       if (p == NULL) {
+               goto nomem;
+       }
+       p->b = b;
+       p->name = talloc_strdup(p, name);
+       if (p->name == NULL) {
+               goto nomem;
+       }
+       p->type = talloc_strdup(p, type);
+       if (p->name == NULL) {
+               goto nomem;
+       }
+       p->pointer = pointer;
+
+       p->r = talloc_zero(pointer, struct dcerpc_binding_pointer_ref);
+       if (p->r == NULL) {
+               goto nomem;
+       }
+       p->r->p = p;
+       talloc_set_destructor(p->r, dcerpc_binding_pointer_ref_destructor);
+
+       TALLOC_FREE(b->pointers[idx]);
+       b->pointers[idx] = p;
+       talloc_set_destructor(p, dcerpc_binding_pointer_destructor);
+
+       return NT_STATUS_OK;
+
+ nomem:
+       TALLOC_FREE(p);
+       b->pointers = talloc_realloc(b, b->pointers,
+                                    struct dcerpc_binding_pointer *,
+                                    b->num_pointers);
+       return NT_STATUS_NO_MEMORY;
 }
 
 _PUBLIC_ uint32_t dcerpc_binding_get_flags(const struct dcerpc_binding *b)
@@ -1449,7 +1643,7 @@ _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
                                                   const struct dcerpc_binding *b)
 {
        struct dcerpc_binding *n;
-       uint32_t count;
+       size_t i, count;
 
        n = talloc_zero(mem_ctx, struct dcerpc_binding);
        if (n == NULL) {
@@ -1503,8 +1697,6 @@ _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
        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);
@@ -1521,6 +1713,20 @@ _PUBLIC_ struct dcerpc_binding *dcerpc_binding_dup(TALLOC_CTX *mem_ctx,
                n->options[count] = NULL;
        }
 
+       for (i=0; i < b->num_pointers; i++) {
+               struct dcerpc_binding_pointer *p = b->pointers[i];
+               NTSTATUS status;
+
+               status = _dcerpc_binding_set_pointer_option(n,
+                                                           p->name,
+                                                           p->type,
+                                                           p->pointer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(n);
+                       return NULL;
+               }
+       }
+
        return n;
 }