librpc/rpc: add dcerpc_sec_verification_trailer_check()
authorGregor Beck <gbeck@sernet.de>
Wed, 8 Jan 2014 08:50:33 +0000 (09:50 +0100)
committerStefan Metzmacher <metze@samba.org>
Mon, 10 Feb 2014 07:57:35 +0000 (08:57 +0100)
Signed-off-by: Gregor Beck <gbeck@sernet.de>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
librpc/rpc/dcerpc_util.c
librpc/rpc/rpc_common.h

index 425e748116a91aada48857e770ba8c1b70bd1c10..56eff034b37771a901c73fbb3979500521025fc0 100644 (file)
@@ -27,6 +27,7 @@
 #include "librpc/rpc/dcerpc.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "rpc_common.h"
+#include "lib/util/bitmap.h"
 
 /* we need to be able to get/set the fragment length without doing a full
    decode */
@@ -449,3 +450,138 @@ bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
 
        return true;
 }
+
+static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
+{
+       bool ret = false;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct bitmap *commands_seen;
+       int i;
+
+       if (r->count.count == 0) {
+               ret = true;
+               goto done;
+       }
+
+       if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
+               goto done;
+       }
+
+       commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
+       if (commands_seen == NULL) {
+               goto done;
+       }
+
+       for (i=0; i < r->count.count; i++) {
+               enum dcerpc_sec_vt_command_enum cmd =
+                       r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
+
+               if (bitmap_query(commands_seen, cmd)) {
+                       /* Each command must appear at most once. */
+                       goto done;
+               }
+               bitmap_set(commands_seen, cmd);
+
+               switch (cmd) {
+               case DCERPC_SEC_VT_COMMAND_BITMASK1:
+               case DCERPC_SEC_VT_COMMAND_PCONTEXT:
+               case DCERPC_SEC_VT_COMMAND_HEADER2:
+                       break;
+               default:
+                       if ((r->commands[i].u._unknown.length % 4) != 0) {
+                               goto done;
+                       }
+                       break;
+               }
+       }
+       ret = true;
+done:
+       TALLOC_FREE(frame);
+       return ret;
+}
+
+#define CHECK(msg, ok)                                         \
+do {                                                           \
+       if (!ok) {                                              \
+               DEBUG(10, ("SEC_VT check %s failed\n", msg));   \
+               return false;                                   \
+       }                                                       \
+} while(0)
+
+#define CHECK_SYNTAX(msg, s1, s2)                                      \
+do {                                                           \
+       if (!ndr_syntax_id_equal(&s1, &s2)) {                           \
+               TALLOC_CTX *frame = talloc_stackframe();                \
+               DEBUG(10, ("SEC_VT check %s failed: %s vs. %s\n", msg,  \
+                          ndr_syntax_id_to_string(frame, &s1),         \
+                          ndr_syntax_id_to_string(frame, &s1)));       \
+               TALLOC_FREE(frame);                                     \
+               return false;                                           \
+       }                                                               \
+} while(0)
+
+
+bool dcerpc_sec_verification_trailer_check(
+               const struct dcerpc_sec_verification_trailer *vt,
+               const uint32_t *bitmask1,
+               const struct dcerpc_sec_vt_pcontext *pcontext,
+               const struct dcerpc_sec_vt_header2 *header2)
+{
+       size_t i;
+
+       if (!dcerpc_sec_vt_is_valid(vt)) {
+               return false;
+       }
+
+       for (i=0; i < vt->count.count; i++) {
+               struct dcerpc_sec_vt *c = &vt->commands[i];
+
+               switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
+               case DCERPC_SEC_VT_COMMAND_BITMASK1:
+                       if (bitmask1 == NULL) {
+                               CHECK("Bitmask1 must_process_command",
+                                     !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
+                               break;
+                       }
+
+                       if (c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING) {
+                               CHECK("Bitmask1 client_header_signing",
+                                     *bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING);
+                       }
+                       break;
+
+               case DCERPC_SEC_VT_COMMAND_PCONTEXT:
+                       if (pcontext == NULL) {
+                               CHECK("Pcontext must_process_command",
+                                     !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
+                               break;
+                       }
+
+                       CHECK_SYNTAX("Pcontect abstract_syntax",
+                                    pcontext->abstract_syntax,
+                                    c->u.pcontext.abstract_syntax);
+                       CHECK_SYNTAX("Pcontext transfer_syntax",
+                                    pcontext->transfer_syntax,
+                                    c->u.pcontext.transfer_syntax);
+                       break;
+
+               case DCERPC_SEC_VT_COMMAND_HEADER2: {
+                       if (header2 == NULL) {
+                               CHECK("Header2 must_process_command",
+                                     !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
+                               break;
+                       }
+
+                       CHECK("Header2", dcerpc_sec_vt_header2_equal(header2, &c->u.header2));
+                       break;
+               }
+
+               default:
+                       CHECK("Unknown must_process_command",
+                             !(c->command & DCERPC_SEC_VT_MUST_PROCESS));
+                       break;
+               }
+       }
+
+       return true;
+}
index aab7c1001d2994c769af61a9822fb59a0d2a36ed..257b1a2dd25a2346fb48114ad9b181acd195f0b2 100644 (file)
@@ -338,4 +338,22 @@ struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struc
 bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
                                 const struct dcerpc_sec_vt_header2 *v2);
 
+/**
+ * Check for consistency of the security verification trailer with the PDU header.
+ * See <a href="http://msdn.microsoft.com/en-us/library/cc243559.aspx">MS-RPCE 2.2.2.13</a>.
+ * A check with an empty trailer succeeds.
+ *
+ * @param[in] vt a pointer to the security verification trailer.
+ * @param[in] bitmask1 which flags were negotiated on the connection.
+ * @param[in] pcontext the syntaxes negotiatied for the presentation context.
+ * @param[in] header2 some fields from the PDU header.
+ *
+ * @retval true on success.
+ */
+bool dcerpc_sec_verification_trailer_check(
+               const struct dcerpc_sec_verification_trailer *vt,
+               const uint32_t *bitmask1,
+               const struct dcerpc_sec_vt_pcontext *pcontext,
+               const struct dcerpc_sec_vt_header2 *header2);
+
 #endif /* __DEFAULT_LIBRPC_RPCCOMMON_H__ */