[PATCH] drsuapi.idl: Manage all possible lengths of DsBindInfo

Samuel Cabrero scabrero at zentyal.com
Fri Jul 4 09:08:45 MDT 2014


Hello,

we have reports about samba not able to join to domain and crashing with 
the following exception:

'drsuapi.DsBindInfoFallBack' object has no attribute 'supported_extensions'

Digging into the problem it seems to be in the drsuapi IDL. The 
DsBindInfo blob returned by the server is decoded in the IDL, based on 
the blob length. For some reason, some servers are returning a 32 bytes 
length blob, which is not decoded, so it falls into the default case and 
python bindings crash.

Reviewing the documentation [MS-DRSR], it is possible the server not to 
push the object GUID of the configuration NC, so I have added that case 
and also the one to decode the blob returned by W2K12 R2 which is 52 bytes.

Cheers.

-- 
Samuel Cabrero - Developer
scabrero at zentyal.com

Zentyal - Active Exchange
www.zentyal.com
-------------- next part --------------
>From f272d62415eec04128c3820de33187fe241a9f75 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero at zentyal.com>
Date: Fri, 4 Jul 2014 12:45:59 +0200
Subject: [PATCH] idl:drsuapi: Manage all possible lengths of
 drsuapi_DsBindInfo

Signed-off-by: Samuel Cabrero <scabrero at zentyal.com>
Reviewed-by: Kamen Mazdrashki <kamenim at samba.org>
---
 librpc/idl/drsuapi.idl                | 21 +++++++++++++++++++++
 source3/libnet/libnet_dssync.c        | 21 ++++++++++++++++++++-
 source3/rpcclient/cmd_drsuapi.c       |  4 ++++
 source4/dsdb/repl/drepl_out_helpers.c | 27 ++++++++++++++++++++++++++-
 source4/libnet/libnet_become_dc.c     | 25 ++++++++++++++++++++++++-
 source4/libnet/libnet_unbecome_dc.c   | 25 ++++++++++++++++++++++++-
 source4/torture/drs/rpc/dssync.c      | 21 ++++++++++++++++++++-
 source4/torture/drs/rpc/msds_intid.c  | 21 ++++++++++++++++++++-
 source4/torture/rpc/dsgetinfo.c       | 21 ++++++++++++++++++++-
 9 files changed, 179 insertions(+), 7 deletions(-)

diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl
index f1c6cd6..b78a865 100644
--- a/librpc/idl/drsuapi.idl
+++ b/librpc/idl/drsuapi.idl
@@ -129,6 +129,14 @@ interface drsuapi
 		uint32 repl_epoch;
 	} drsuapi_DsBindInfo28;
 
+	typedef [public] struct {
+		drsuapi_SupportedExtensions supported_extensions;
+		GUID site_guid;
+		uint32 pid;
+		uint32 repl_epoch;
+		drsuapi_SupportedExtensionsExt supported_extensions_ext;
+	} drsuapi_DsBindInfo32;
+
 	/* this is used by w2k8 */
 	typedef [public] struct {
 		drsuapi_SupportedExtensions supported_extensions;
@@ -139,6 +147,17 @@ interface drsuapi
 		GUID config_dn_guid;
 	} drsuapi_DsBindInfo48;
 
+	/* this is used by w2k12 R2 [MS-DRSR] Section 5.39 */
+	typedef [public] struct {
+		drsuapi_SupportedExtensions supported_extensions;
+		GUID site_guid;
+		uint32 pid;
+		uint32 repl_epoch;
+		drsuapi_SupportedExtensionsExt supported_extensions_ext;
+		GUID config_dn_guid;
+		drsuapi_SupportedExtensionsExt supported_capabilities_ext;
+	} drsuapi_DsBindInfo52;
+
 	typedef [public] struct {
 		[flag(NDR_REMAINING)] DATA_BLOB info;
 	} drsuapi_DsBindInfoFallBack;
@@ -146,7 +165,9 @@ interface drsuapi
 	typedef [nopull, nopush, noprint] [nodiscriminant] union {
 		[case(24)][subcontext(0), subcontext_size(24)] drsuapi_DsBindInfo24 info24;
 		[case(28)][subcontext(0), subcontext_size(28)] drsuapi_DsBindInfo28 info28;
+		[case(32)][subcontext(0), subcontext_size(32)] drsuapi_DsBindInfo32 info32;
 		[case(48)][subcontext(0), subcontext_size(48)] drsuapi_DsBindInfo48 info48;
+		[case(52)][subcontext(0), subcontext_size(52)] drsuapi_DsBindInfo52 info52;
 		/*
 		 * The size for the defaut case is a bit arbitrary it in fact the value
 		 * of the switch but we can't reference it.
diff --git a/source3/libnet/libnet_dssync.c b/source3/libnet/libnet_dssync.c
index a843106..94f0628 100644
--- a/source3/libnet/libnet_dssync.c
+++ b/source3/libnet/libnet_dssync.c
@@ -195,9 +195,19 @@ static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx,
 		ctx->remote_info28.repl_epoch		= 0;
 		break;
 	}
-	case 28:
+	case 28: {
 		ctx->remote_info28 = bind_info.info.info28;
 		break;
+	}
+	case 32: {
+		struct drsuapi_DsBindInfo32 *info32;
+		info32 = &bind_info.info.info32;
+		ctx->remote_info28.site_guid		= info32->site_guid;
+		ctx->remote_info28.supported_extensions	= info32->supported_extensions;
+		ctx->remote_info28.pid			= info32->pid;
+		ctx->remote_info28.repl_epoch		= info32->repl_epoch;
+		break;
+	}
 	case 48: {
 		struct drsuapi_DsBindInfo48 *info48;
 		info48 = &bind_info.info.info48;
@@ -207,6 +217,15 @@ static NTSTATUS libnet_dssync_bind(TALLOC_CTX *mem_ctx,
 		ctx->remote_info28.repl_epoch		= info48->repl_epoch;
 		break;
 	}
+	case 52: {
+		struct drsuapi_DsBindInfo52 *info52;
+		info52 = &bind_info.info.info52;
+		ctx->remote_info28.site_guid		= info52->site_guid;
+		ctx->remote_info28.supported_extensions	= info52->supported_extensions;
+		ctx->remote_info28.pid			= info52->pid;
+		ctx->remote_info28.repl_epoch		= info52->repl_epoch;
+		break;
+	}
 	default:
 		DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
 			  bind_info.length));
diff --git a/source3/rpcclient/cmd_drsuapi.c b/source3/rpcclient/cmd_drsuapi.c
index 0c281cf..6a1fac7 100644
--- a/source3/rpcclient/cmd_drsuapi.c
+++ b/source3/rpcclient/cmd_drsuapi.c
@@ -420,8 +420,12 @@ static WERROR cmd_drsuapi_getncchanges(struct rpc_pipe_client *cli,
 		supported_extensions = bind_info.info.info24.supported_extensions;
 	} else if (bind_info.length == 28) {
 		supported_extensions = bind_info.info.info28.supported_extensions;
+	} else if (bind_info.length == 32) {
+		supported_extensions = bind_info.info.info32.supported_extensions;
 	} else if (bind_info.length == 48) {
 		supported_extensions = bind_info.info.info48.supported_extensions;
+	} else if (bind_info.length == 52) {
+		supported_extensions = bind_info.info.info52.supported_extensions;
 	}
 
 	if (!nc_dn) {
diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c
index 2339027..22d44f0 100644
--- a/source4/dsdb/repl/drepl_out_helpers.c
+++ b/source4/dsdb/repl/drepl_out_helpers.c
@@ -186,10 +186,35 @@ static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
 			info28->repl_epoch		= info48->repl_epoch;
 			break;
 		}
-		case 28:
+		case 28: {
 			*info28 = state->bind_r.out.bind_info->info.info28;
 			break;
 		}
+		case 32: {
+			struct drsuapi_DsBindInfo32 *info32;
+			info32 = &state->bind_r.out.bind_info->info.info32;
+
+			info28->supported_extensions	= info32->supported_extensions;
+			info28->site_guid		= info32->site_guid;
+			info28->pid			= info32->pid;
+			info28->repl_epoch		= info32->repl_epoch;
+			break;
+		}
+		case 52: {
+			struct drsuapi_DsBindInfo52 *info52;
+			info52 = &state->bind_r.out.bind_info->info.info52;
+
+			info28->supported_extensions	= info52->supported_extensions;
+			info28->site_guid		= info52->site_guid;
+			info28->pid			= info52->pid;
+			info28->repl_epoch		= info52->repl_epoch;
+			break;
+		}
+		default:
+			DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+				state->bind_r.out.bind_info->length));
+			break;
+		}
 	}
 
 	tevent_req_done(req);
diff --git a/source4/libnet/libnet_become_dc.c b/source4/libnet/libnet_become_dc.c
index 6d00fcc..55ac48c 100644
--- a/source4/libnet/libnet_become_dc.c
+++ b/source4/libnet/libnet_become_dc.c
@@ -1712,10 +1712,33 @@ static WERROR becomeDC_drsuapi_bind_recv(struct libnet_BecomeDC_state *s,
 			drsuapi->remote_info28.repl_epoch		= info48->repl_epoch;
 			break;
 		}
-		case 28:
+		case 28: {
 			drsuapi->remote_info28 = drsuapi->bind_r.out.bind_info->info.info28;
 			break;
 		}
+		case 32: {
+			struct drsuapi_DsBindInfo32 *info32;
+			info32 = &drsuapi->bind_r.out.bind_info->info.info32;
+			drsuapi->remote_info28.supported_extensions	= info32->supported_extensions;
+			drsuapi->remote_info28.site_guid		= info32->site_guid;
+			drsuapi->remote_info28.pid			= info32->pid;
+			drsuapi->remote_info28.repl_epoch		= info32->repl_epoch;
+			break;
+		}
+		case 52: {
+			struct drsuapi_DsBindInfo52 *info52;
+			info52 = &drsuapi->bind_r.out.bind_info->info.info52;
+			drsuapi->remote_info28.supported_extensions	= info52->supported_extensions;
+			drsuapi->remote_info28.site_guid		= info52->site_guid;
+			drsuapi->remote_info28.pid			= info52->pid;
+			drsuapi->remote_info28.repl_epoch		= info52->repl_epoch;
+			break;
+		}
+		default:
+			DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+					drsuapi->bind_r.out.bind_info->length));
+			break;
+		}
 	}
 
 	return WERR_OK;
diff --git a/source4/libnet/libnet_unbecome_dc.c b/source4/libnet/libnet_unbecome_dc.c
index f575eb1..2ff7b1c 100644
--- a/source4/libnet/libnet_unbecome_dc.c
+++ b/source4/libnet/libnet_unbecome_dc.c
@@ -649,10 +649,33 @@ static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq)
 			s->drsuapi.remote_info28.repl_epoch		= info48->repl_epoch;
 			break;
 		}
-		case 28:
+		case 28: {
 			s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
 			break;
 		}
+		case 32: {
+			struct drsuapi_DsBindInfo32 *info32;
+			info32 = &s->drsuapi.bind_r.out.bind_info->info.info32;
+			s->drsuapi.remote_info28.supported_extensions	= info32->supported_extensions;
+			s->drsuapi.remote_info28.site_guid		= info32->site_guid;
+			s->drsuapi.remote_info28.pid			= info32->pid;
+			s->drsuapi.remote_info28.repl_epoch		= info32->repl_epoch;
+			break;
+		}
+		case 52: {
+			struct drsuapi_DsBindInfo52 *info52;
+			info52 = &s->drsuapi.bind_r.out.bind_info->info.info52;
+			s->drsuapi.remote_info28.supported_extensions	= info52->supported_extensions;
+			s->drsuapi.remote_info28.site_guid		= info52->site_guid;
+			s->drsuapi.remote_info28.pid			= info52->pid;
+			s->drsuapi.remote_info28.repl_epoch		= info52->repl_epoch;
+			break;
+		}
+		default:
+			DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
+				s->drsuapi.bind_r.out.bind_info->length));
+			break;
+		}
 	}
 
 	unbecomeDC_drsuapi_remove_ds_server_send(s);
diff --git a/source4/torture/drs/rpc/dssync.c b/source4/torture/drs/rpc/dssync.c
index 813f136..0f13ea5 100644
--- a/source4/torture/drs/rpc/dssync.c
+++ b/source4/torture/drs/rpc/dssync.c
@@ -246,9 +246,28 @@ static bool _test_DsBind(struct torture_context *tctx,
 			b->peer_bind_info28.repl_epoch		= info48->repl_epoch;
 			break;
 		}
-		case 28:
+		case 28: {
 			b->peer_bind_info28 = b->req.out.bind_info->info.info28;
 			break;
+		}
+		case 32: {
+			struct drsuapi_DsBindInfo32 *info32;
+			info32 = &b->req.out.bind_info->info.info32;
+			b->peer_bind_info28.supported_extensions= info32->supported_extensions;
+			b->peer_bind_info28.site_guid		= info32->site_guid;
+			b->peer_bind_info28.pid			= info32->pid;
+			b->peer_bind_info28.repl_epoch		= info32->repl_epoch;
+			break;
+		}
+		case 52: {
+			struct drsuapi_DsBindInfo52 *info52;
+			info52 = &b->req.out.bind_info->info.info52;
+			b->peer_bind_info28.supported_extensions= info52->supported_extensions;
+			b->peer_bind_info28.site_guid		= info52->site_guid;
+			b->peer_bind_info28.pid			= info52->pid;
+			b->peer_bind_info28.repl_epoch		= info52->repl_epoch;
+			break;
+		}
 		default:
 			printf("DsBind - warning: unknown BindInfo length: %u\n",
 			       b->req.out.bind_info->length);
diff --git a/source4/torture/drs/rpc/msds_intid.c b/source4/torture/drs/rpc/msds_intid.c
index a02acd8..b93f70a 100644
--- a/source4/torture/drs/rpc/msds_intid.c
+++ b/source4/torture/drs/rpc/msds_intid.c
@@ -244,9 +244,28 @@ static bool _test_DsaBind(struct torture_context *tctx,
 		bi->srv_info48.repl_epoch		= info28->repl_epoch;
 		break;
 	}
-	case 48:
+	case 48: {
 		bi->srv_info48 = r.out.bind_info->info.info48;
 		break;
+	}
+	case 32: {
+		struct drsuapi_DsBindInfo32 *info32;
+		info32 = &r.out.bind_info->info.info32;
+		bi->srv_info48.supported_extensions	= info32->supported_extensions;
+		bi->srv_info48.site_guid		= info32->site_guid;
+		bi->srv_info48.pid			= info32->pid;
+		bi->srv_info48.repl_epoch		= info32->repl_epoch;
+		break;
+	}
+	case 52: {
+		struct drsuapi_DsBindInfo52 *info52;
+		info52 = &r.out.bind_info->info.info52;
+		bi->srv_info48.supported_extensions	= info52->supported_extensions;
+		bi->srv_info48.site_guid		= info52->site_guid;
+		bi->srv_info48.pid			= info52->pid;
+		bi->srv_info48.repl_epoch		= info52->repl_epoch;
+		break;
+	}
 	default:
 		torture_result(tctx, TORTURE_FAIL,
 		               "DsBind: unknown BindInfo length: %u",
diff --git a/source4/torture/rpc/dsgetinfo.c b/source4/torture/rpc/dsgetinfo.c
index 7d6b01f..93c8b2d 100644
--- a/source4/torture/rpc/dsgetinfo.c
+++ b/source4/torture/rpc/dsgetinfo.c
@@ -204,9 +204,28 @@ static bool _test_DsBind(struct torture_context *tctx,
 			b->peer_bind_info28.repl_epoch		= info48->repl_epoch;
 			break;
 		}
-		case 28:
+		case 28: {
 			b->peer_bind_info28 = b->req.out.bind_info->info.info28;
 			break;
+		}
+		case 32: {
+			struct drsuapi_DsBindInfo32 *info32;
+			info32 = &b->req.out.bind_info->info.info32;
+			b->peer_bind_info28.supported_extensions= info32->supported_extensions;
+			b->peer_bind_info28.site_guid		= info32->site_guid;
+			b->peer_bind_info28.pid			= info32->pid;
+			b->peer_bind_info28.repl_epoch		= info32->repl_epoch;
+			break;
+		}
+		case 52: {
+			struct drsuapi_DsBindInfo52 *info52;
+			info52 = &b->req.out.bind_info->info.info52;
+			b->peer_bind_info28.supported_extensions= info52->supported_extensions;
+			b->peer_bind_info28.site_guid		= info52->site_guid;
+			b->peer_bind_info28.pid			= info52->pid;
+			b->peer_bind_info28.repl_epoch		= info52->repl_epoch;
+			break;
+		}
 		default:
 			printf("DsBind - warning: unknown BindInfo length: %u\n",
 			       b->req.out.bind_info->length);
-- 
1.9.1



More information about the samba-technical mailing list