s4-samba-tool: switched over to python version of samba-tool drs
[Samba/gebeck_regimport.git] / source4 / samba_tool / drs / drs.c
blob78f8c144c288d931f0095592f8c8550e1dd07b27
1 /*
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/>.
22 #include "includes.h"
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"
27 #include "ldb_wrap.h"
28 #include "system/filesys.h"
31 /**
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 },
42 { NULL, NULL }
45 /**
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);
53 /**
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");
59 d_printf("\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");
65 return 0;
68 /**
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)
74 NTSTATUS status;
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,
83 &conn->drs_pipe,
84 conn->binding,
85 &ndr_table_drsuapi,
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));
91 return false;
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);
107 return false;
108 } else if (!W_ERROR_IS_OK(req.out.result)) {
109 d_printf("DsBind failed - %s\n", win_errstr(req.out.result));
110 return false;
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) {
118 case 48:
119 conn->info48.supported_extensions_ext = bind_info->info48.supported_extensions_ext;
120 conn->info48.config_dn_guid = bind_info->info48.config_dn_guid;
121 case 28:
122 conn->info48.repl_epoch = bind_info->info28.repl_epoch;
123 case 24:
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;
127 break;
128 default:
129 d_printf("Error: server returned BindInfo length %d", req.out.bind_info->length);
130 return false;
133 return true;
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);
146 ZERO_STRUCT(r);
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;
157 return true;
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);
168 return 0;
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);
182 /* init binding */
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)) {
190 goto failed;
193 talloc_set_destructor(conn, net_drs_connection_destructor);
195 return conn;
197 failed:
198 talloc_free(conn);
199 return NULL;
203 * Open secured LDAP connection to remote DC
205 static bool net_drs_ldap_connect(struct net_drs_context *drs_ctx)
207 char *url;
208 bool bret = true;
210 url = talloc_asprintf(drs_ctx, "ldap://%s/", drs_ctx->dc_name);
211 if (!url) {
212 d_printf(__location__ ": Have no memory");
213 return false;
216 drs_ctx->ldap.ldb = ldb_wrap_connect(drs_ctx,
217 drs_ctx->net_ctx->event_ctx, drs_ctx->net_ctx->lp_ctx,
218 url,
219 NULL,
220 drs_ctx->net_ctx->credentials,
222 if (drs_ctx->ldap.ldb == NULL) {
223 d_printf("Unable to connect to LDAP %s", url);
224 bret = false;
227 talloc_free(url);
229 return bret;
233 * fetch RootDSE record
235 static bool net_drs_ldap_rootdse(struct net_drs_context *drs_ctx)
237 int ret;
238 struct ldb_result *r;
239 struct ldb_dn *basedn;
240 static const char *attrs[] = {
241 "*",
242 NULL
245 SMB_ASSERT(drs_ctx->ldap.ldb != NULL);
247 basedn = ldb_dn_new(drs_ctx, drs_ctx->ldap.ldb, NULL);
248 if (!basedn) {
249 d_printf(__location__ ": No memory");
250 return false;
253 ret = ldb_search(drs_ctx->ldap.ldb, drs_ctx, &r,
254 basedn, LDB_SCOPE_BASE, attrs,
255 "(objectClass=*)");
256 talloc_free(basedn);
257 if (ret != LDB_SUCCESS) {
258 d_printf("RootDSE search failed: %s", ldb_errstring(drs_ctx->ldap.ldb));
259 talloc_free(r);
260 return false;
261 } else if (r->count != 1) {
262 d_printf("RootDSE search returned more than one record!");
263 talloc_free(r);
264 return false;
267 drs_ctx->ldap.rootdse = r->msgs[0];
269 return true;
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)
278 NTSTATUS status;
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);
284 return false;
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;
295 return true;
299 * Free DRSUAPI connection upon net_drs_context
300 * destruction
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);
307 return 0;
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);
321 if (!drs_ctx) {
322 d_printf(__location__ ": No memory");
323 return false;
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");
329 return false;
332 drs_ctx->net_ctx = net_ctx;
334 if (!net_drs_parse_binding(drs_ctx, dc_binding)) {
335 goto failed;
338 /* LDAP connect */
339 if (!net_drs_ldap_connect(drs_ctx)) {
340 goto failed;
342 /* fetch RootDSE */
343 if (!net_drs_ldap_rootdse(drs_ctx)) {
344 goto failed;
347 /* DRSUAPI connection */
348 if (!net_drs_DsBind(drs_ctx, drs_ctx->drs_conn)) {
349 goto failed;
352 /* set destructor to free any open connections */
353 talloc_set_destructor(drs_ctx, net_drs_context_destructor);
355 *_drs_ctx = drs_ctx;
356 return true;
358 failed:
359 talloc_free(drs_ctx);
360 return false;