2 Samba Unix/Linux SMB client library
4 Implements functions offered by repadmin.exe tool under Windows
6 Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "samba_tool/samba_tool.h"
24 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
25 #include "samba_tool/drs/drs.h"
26 #include "lib/ldb/include/ldb.h"
28 #include "system/filesys.h"
32 * 'samba-tool drs' supported sub-commands
34 static const struct net_functable net_drs_functable
[] = {
35 { "bind", "Display replication features for a domain controller\n", net_drs_bind_cmd
, net_drs_bind_usage
},
36 { "kcc", "Forces the KCC to recalculate replication topology for a specified domain controller\n",
37 net_drs_kcc_cmd
, net_drs_kcc_usage
},
38 { "replicate", "Triggers replication event for the specified naming context between the source and destination domain controllers.\n",
39 net_drs_replicate_cmd
, net_drs_replicate_usage
},
40 { "showrepl", "Displays the replication partners for each directory partition on the specified domain controller.\n",
41 net_drs_showrepl_cmd
, net_drs_showrepl_usage
},
46 * 'samba-tool drs' entry point
48 int net_drs(struct net_context
*ctx
, int argc
, const char **argv
)
50 return net_run_function(ctx
, argc
, argv
, net_drs_functable
, net_drs_usage
);
54 * 'samba-tool drs' usage message
56 int net_drs_usage(struct net_context
*ctx
, int argc
, const char **argv
)
58 d_printf("samba-tool drs <command> [options]\n");
60 d_printf("Currently implemented commands:\n");
61 d_printf(" bind - Display DC replication features\n");
62 d_printf(" kcc - Forces the KCC to recalculate replication topology for a specified domain controller\n");
63 d_printf(" replicate - Triggers replication event for the specified naming context between the source and destination domain controllers.\n");
64 d_printf(" showrepl - Displays the replication partners for each directory partition on the specified domain controller.\n");
69 * Create drsuapi connection to remote DC
70 * and fill-in DC capabilities
72 static bool net_drs_DsBind(struct net_drs_context
*drs_ctx
, struct net_drs_connection
*conn
)
75 struct GUID bind_guid
;
76 struct drsuapi_DsBind req
;
77 struct drsuapi_DsBindInfoCtr in_bind_ctr
;
78 union drsuapi_DsBindInfo
*bind_info
;
80 SMB_ASSERT(conn
->binding
!= NULL
);
82 status
= dcerpc_pipe_connect_b(conn
,
86 drs_ctx
->net_ctx
->credentials
,
87 drs_ctx
->net_ctx
->event_ctx
,
88 drs_ctx
->net_ctx
->lp_ctx
);
89 if (!NT_STATUS_IS_OK(status
)) {
90 d_printf("Failed to connect to server: %s\n", nt_errstr(status
));
93 conn
->drs_handle
= conn
->drs_pipe
->binding_handle
;
95 ZERO_STRUCT(in_bind_ctr
);
96 in_bind_ctr
.length
= 48;
97 in_bind_ctr
.info
.info48
.pid
= (uint32_t)getpid();
98 GUID_from_string(DRSUAPI_DS_BIND_GUID
, &bind_guid
);
99 req
.in
.bind_guid
= &bind_guid
;
100 req
.in
.bind_info
= &in_bind_ctr
;
101 req
.out
.bind_handle
= &conn
->bind_handle
;
103 status
= dcerpc_drsuapi_DsBind_r(conn
->drs_handle
, conn
, &req
);
104 if (!NT_STATUS_IS_OK(status
)) {
105 const char *errstr
= nt_errstr(status
);
106 d_printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr
);
108 } else if (!W_ERROR_IS_OK(req
.out
.result
)) {
109 d_printf("DsBind failed - %s\n", win_errstr(req
.out
.result
));
113 /* fill-in remote DC capabilities */
114 ZERO_STRUCT(conn
->info48
);
115 bind_info
= &req
.out
.bind_info
->info
;
116 conn
->bind_info_len
= req
.out
.bind_info
->length
;
117 switch (conn
->bind_info_len
) {
119 conn
->info48
.supported_extensions_ext
= bind_info
->info48
.supported_extensions_ext
;
120 conn
->info48
.config_dn_guid
= bind_info
->info48
.config_dn_guid
;
122 conn
->info48
.repl_epoch
= bind_info
->info28
.repl_epoch
;
124 conn
->info48
.supported_extensions
= bind_info
->info24
.supported_extensions
;
125 conn
->info48
.site_guid
= bind_info
->info24
.site_guid
;
126 conn
->info48
.pid
= bind_info
->info24
.pid
;
129 d_printf("Error: server returned BindInfo length %d", req
.out
.bind_info
->length
);
137 * Close DRSUAPI connection to remote DC
139 static bool net_drs_DsUnbind(struct net_drs_connection
*conn
)
141 struct drsuapi_DsUnbind r
;
142 struct policy_handle bind_handle
;
144 SMB_ASSERT(conn
->drs_pipe
);
147 r
.out
.bind_handle
= &bind_handle
;
149 r
.in
.bind_handle
= &conn
->bind_handle
;
150 dcerpc_drsuapi_DsUnbind_r(conn
->drs_handle
, conn
, &r
);
152 /* free dcerpc pipe in case we get called more than once */
153 talloc_free(conn
->drs_pipe
);
154 conn
->drs_pipe
= NULL
;
155 conn
->drs_handle
= NULL
;
161 * Destroy drsuapi connection
163 static int net_drs_connection_destructor(struct net_drs_connection
*conn
)
165 if (conn
->drs_pipe
) {
166 net_drs_DsUnbind(conn
);
172 * Create DRSUAPI connection to target DC
173 * @return ptr to net_drs_connection or NULL on failure
175 struct net_drs_connection
* net_drs_connect_dc(struct net_drs_context
*drs_ctx
, const char *dc_name
)
177 struct net_drs_connection
*conn
= NULL
;
179 conn
= talloc_zero(drs_ctx
, struct net_drs_connection
);
180 NET_DRS_NOMEM_GOTO(conn
, failed
);
183 conn
->binding
= talloc_zero(conn
, struct dcerpc_binding
);
184 conn
->binding
->transport
= NCACN_IP_TCP
;
185 conn
->binding
->flags
= drs_ctx
->drs_conn
->binding
->flags
;
186 conn
->binding
->host
= talloc_strdup(conn
, dc_name
);
187 conn
->binding
->target_hostname
= conn
->binding
->host
;
189 if (!net_drs_DsBind(drs_ctx
, conn
)) {
193 talloc_set_destructor(conn
, net_drs_connection_destructor
);
203 * Open secured LDAP connection to remote DC
205 static bool net_drs_ldap_connect(struct net_drs_context
*drs_ctx
)
210 url
= talloc_asprintf(drs_ctx
, "ldap://%s/", drs_ctx
->dc_name
);
212 d_printf(__location__
": Have no memory");
216 drs_ctx
->ldap
.ldb
= ldb_wrap_connect(drs_ctx
,
217 drs_ctx
->net_ctx
->event_ctx
, drs_ctx
->net_ctx
->lp_ctx
,
220 drs_ctx
->net_ctx
->credentials
,
222 if (drs_ctx
->ldap
.ldb
== NULL
) {
223 d_printf("Unable to connect to LDAP %s", url
);
233 * fetch RootDSE record
235 static bool net_drs_ldap_rootdse(struct net_drs_context
*drs_ctx
)
238 struct ldb_result
*r
;
239 struct ldb_dn
*basedn
;
240 static const char *attrs
[] = {
245 SMB_ASSERT(drs_ctx
->ldap
.ldb
!= NULL
);
247 basedn
= ldb_dn_new(drs_ctx
, drs_ctx
->ldap
.ldb
, NULL
);
249 d_printf(__location__
": No memory");
253 ret
= ldb_search(drs_ctx
->ldap
.ldb
, drs_ctx
, &r
,
254 basedn
, LDB_SCOPE_BASE
, attrs
,
257 if (ret
!= LDB_SUCCESS
) {
258 d_printf("RootDSE search failed: %s", ldb_errstring(drs_ctx
->ldap
.ldb
));
261 } else if (r
->count
!= 1) {
262 d_printf("RootDSE search returned more than one record!");
267 drs_ctx
->ldap
.rootdse
= r
->msgs
[0];
273 * parses binding from command line
274 * and gets target DC name
276 static bool net_drs_parse_binding(struct net_drs_context
*drs_ctx
, const char *dc_binding
)
279 struct dcerpc_binding
*b
;
281 status
= dcerpc_parse_binding(drs_ctx
->drs_conn
, dc_binding
, &b
);
282 if (!NT_STATUS_IS_OK(status
)) {
283 d_printf("Bad binding supplied %s\n", dc_binding
);
287 b
->transport
= NCACN_IP_TCP
;
288 b
->flags
|= DCERPC_SIGN
| DCERPC_SEAL
;
290 /* cache target DC name */
291 drs_ctx
->dc_name
= b
->target_hostname
;
293 drs_ctx
->drs_conn
->binding
= b
;
299 * Free DRSUAPI connection upon net_drs_context
302 static int net_drs_context_destructor(struct net_drs_context
*drs_ctx
)
304 if (drs_ctx
->drs_conn
&& drs_ctx
->drs_conn
->drs_pipe
) {
305 net_drs_DsUnbind(drs_ctx
->drs_conn
);
311 * Create net_drs_context context to be used
312 * by 'samba-tool drs' sub-commands
314 bool net_drs_create_context(struct net_context
*net_ctx
,
315 const char *dc_binding
,
316 struct net_drs_context
**_drs_ctx
)
318 struct net_drs_context
*drs_ctx
;
320 drs_ctx
= talloc_zero(net_ctx
, struct net_drs_context
);
322 d_printf(__location__
": No memory");
326 drs_ctx
->drs_conn
= talloc_zero(drs_ctx
, struct net_drs_connection
);
327 if (!drs_ctx
->drs_conn
) {
328 d_printf(__location__
": No memory");
332 drs_ctx
->net_ctx
= net_ctx
;
334 if (!net_drs_parse_binding(drs_ctx
, dc_binding
)) {
339 if (!net_drs_ldap_connect(drs_ctx
)) {
343 if (!net_drs_ldap_rootdse(drs_ctx
)) {
347 /* DRSUAPI connection */
348 if (!net_drs_DsBind(drs_ctx
, drs_ctx
->drs_conn
)) {
352 /* set destructor to free any open connections */
353 talloc_set_destructor(drs_ctx
, net_drs_context_destructor
);
359 talloc_free(drs_ctx
);