s4-rpc: paranoid check for auth_length
[abartlet/samba.git/.git] / source4 / librpc / rpc / dcerpc_util.c
index 1847b20ee7304042f4c59ad2963de74631d0f00b..9dabb54ca5046c15dc604b9bb48583262e22af11 100644 (file)
@@ -52,8 +52,8 @@ const struct ndr_interface_call *dcerpc_iface_find_call(const struct ndr_interfa
 */
 NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
                         struct smb_iconv_convenience *iconv_convenience,
-                         struct ncacn_packet *pkt,
-                         struct dcerpc_auth *auth_info)
+                        struct ncacn_packet *pkt,
+                        struct dcerpc_auth *auth_info)
 {
        struct ndr_push *ndr;
        enum ndr_err_code ndr_err;
@@ -83,6 +83,19 @@ NTSTATUS ncacn_push_auth(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
        }
 
        if (auth_info) {
+#if 0
+               /* the s3 rpc server doesn't handle auth padding in
+                  bind requests. Use zero auth padding to keep us
+                  working with old servers */
+               uint32_t offset = ndr->offset;
+               ndr_err = ndr_push_align(ndr, 16);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       return ndr_map_error2ntstatus(ndr_err);
+               }
+               auth_info->auth_pad_length = ndr->offset - offset;
+#else
+               auth_info->auth_pad_length = 0;
+#endif
                ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth_info);
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        return ndr_map_error2ntstatus(ndr_err);
@@ -202,7 +215,7 @@ static void continue_epm_map(struct rpc_request *req)
 struct composite_context *dcerpc_epm_map_binding_send(TALLOC_CTX *mem_ctx,
                                                      struct dcerpc_binding *binding,
                                                      const struct ndr_interface_table *table,
-                                                     struct event_context *ev,
+                                                     struct tevent_context *ev,
                                                      struct loadparm_context *lp_ctx)
 {
        struct composite_context *c;
@@ -303,7 +316,7 @@ NTSTATUS dcerpc_epm_map_binding_recv(struct composite_context *c)
   Get endpoint mapping for rpc connection
 */
 _PUBLIC_ NTSTATUS dcerpc_epm_map_binding(TALLOC_CTX *mem_ctx, struct dcerpc_binding *binding,
-                               const struct ndr_interface_table *table, struct event_context *ev,
+                               const struct ndr_interface_table *table, struct tevent_context *ev,
                                struct loadparm_context *lp_ctx)
 {
        struct composite_context *c;
@@ -513,6 +526,10 @@ struct composite_context *dcerpc_pipe_auth_send(struct dcerpc_pipe *p,
 
        conn = s->pipe->conn;
        conn->flags = binding->flags;
+
+       if (DEBUGLVL(100)) {
+               conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
+       }
        
        /* remember the binding string for possible secondary connections */
        conn->binding_string = dcerpc_binding_string(p, binding);
@@ -732,7 +749,7 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
 
        p2->syntax = table->syntax_id;
 
-       p2->transfer_syntax = ndr_transfer_syntax;
+       p2->transfer_syntax = p->transfer_syntax;
 
        p2->binding = talloc_reference(p2, p->binding);
 
@@ -746,3 +763,70 @@ _PUBLIC_ NTSTATUS dcerpc_secondary_context(struct dcerpc_pipe *p,
 
        return NT_STATUS_OK;
 }
+
+
+/*
+  pull an dcerpc_auth structure, taking account of any auth padding in
+  the blob at the end of the structure
+ */
+NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
+                                 TALLOC_CTX *mem_ctx,
+                                 DATA_BLOB *pkt_auth_blob,
+                                 struct dcerpc_auth *auth,
+                                 uint32_t *auth_length,
+                                 bool check_pad)
+{
+       struct ndr_pull *ndr;
+       enum ndr_err_code ndr_err;
+       uint32_t pad;
+
+       pad = pkt_auth_blob->length - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
+
+       /* paranoia check for pad size. This would be caught anyway by
+          the ndr_pull_advance() a few lines down, but it scared
+          Jeremy enough for him to call me, so we might as well check
+          it now, just to prevent someone posting a bogus YouTube
+          video in the future.
+       */
+       if (pad > pkt_auth_blob->length) {
+               return NT_STATUS_INFO_LENGTH_MISMATCH;
+       }
+
+       *auth_length = pkt_auth_blob->length - pad;
+
+       ndr = ndr_pull_init_blob(pkt_auth_blob, mem_ctx, NULL);
+       if (!ndr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
+               ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
+       }
+
+       ndr_err = ndr_pull_advance(ndr, pad);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               talloc_free(ndr);
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+
+       ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               talloc_free(ndr);
+               return ndr_map_error2ntstatus(ndr_err);
+       }
+
+       if (check_pad && pad != auth->auth_pad_length) {
+               DEBUG(1,(__location__ ": WARNING: pad length mismatch. Calculated %u  got %u\n",
+                        (unsigned)pad, (unsigned)auth->auth_pad_length));
+       }
+
+       DEBUG(6,(__location__ ": auth_pad_length %u\n",
+                (unsigned)auth->auth_pad_length));
+
+       talloc_steal(mem_ctx, auth->credentials.data);
+       talloc_free(ndr);
+
+       return NT_STATUS_OK;
+}
+
+