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 "utils/net/net.h"
24 #include "librpc/gen_ndr/ndr_drsuapi_c.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb_wrap.h"
33 * 'net drs' supported sub-commands
35 static const struct net_functable net_drs_functable[] = {
36 { "bind", "Display replication features for a domain controller\n", net_drs_bind_cmd, net_drs_bind_usage },
41 * 'net drs' entry point
43 int net_drs(struct net_context *ctx, int argc, const char **argv)
45 return net_run_function(ctx, argc, argv, net_drs_functable, net_drs_usage);
49 * 'net drs' usage message
51 int net_drs_usage(struct net_context *ctx, int argc, const char **argv)
53 d_printf("net drs <command> [options]\n");
55 d_printf("Currently implemented commands:\n");
56 d_printf(" bind - Display DC replication features");
61 * Create drsuapi connection to remote DC
62 * and fill-in DC capabilities
64 static bool net_drs_DsBind(struct net_drs_context *drs_ctx)
67 struct GUID bind_guid;
68 struct drsuapi_DsBind req;
69 struct drsuapi_DsBindInfoCtr in_bind_ctr;
70 union drsuapi_DsBindInfo *bind_info;
72 SMB_ASSERT(drs_ctx->binding != NULL);
74 status = dcerpc_pipe_connect_b(drs_ctx,
78 drs_ctx->net_ctx->credentials,
79 drs_ctx->net_ctx->event_ctx,
80 drs_ctx->net_ctx->lp_ctx);
81 if (!NT_STATUS_IS_OK(status)) {
82 d_printf("Failed to connect to server: %s\n", nt_errstr(status));
86 ZERO_STRUCT(in_bind_ctr);
87 in_bind_ctr.length = 48;
88 in_bind_ctr.info.info48.pid = (uint32_t)getpid();
89 GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
90 req.in.bind_guid = &bind_guid;
91 req.in.bind_info = &in_bind_ctr;
92 req.out.bind_handle = &drs_ctx->bind_handle;
94 status = dcerpc_drsuapi_DsBind(drs_ctx->drs_pipe, drs_ctx, &req);
95 if (!NT_STATUS_IS_OK(status)) {
96 const char *errstr = nt_errstr(status);
97 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
98 errstr = dcerpc_errstr(drs_ctx, drs_ctx->drs_pipe->last_fault_code);
100 d_printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
102 } else if (!W_ERROR_IS_OK(req.out.result)) {
103 d_printf("DsBind failed - %s\n", win_errstr(req.out.result));
107 /* fill-in remote DC capabilities */
108 ZERO_STRUCT(drs_ctx->info48);
109 bind_info = &req.out.bind_info->info;
110 drs_ctx->bind_info_len = req.out.bind_info->length;
111 switch (drs_ctx->bind_info_len) {
113 drs_ctx->info48.supported_extensions_ext = bind_info->info48.supported_extensions_ext;
114 drs_ctx->info48.config_dn_guid = bind_info->info48.config_dn_guid;
116 drs_ctx->info48.repl_epoch = bind_info->info28.repl_epoch;
118 drs_ctx->info48.supported_extensions = bind_info->info24.supported_extensions;
119 drs_ctx->info48.site_guid = bind_info->info24.site_guid;
120 drs_ctx->info48.pid = bind_info->info24.pid;
123 d_printf("Error: server returned BindInfo length %d", req.out.bind_info->length);
131 * Close DRSUAPI connection to remote DC
133 static bool net_drs_DsUnbind(struct net_drs_context *drs_ctx)
135 struct drsuapi_DsUnbind r;
136 struct policy_handle bind_handle;
139 r.out.bind_handle = &bind_handle;
141 r.in.bind_handle = &drs_ctx->bind_handle;
142 dcerpc_drsuapi_DsUnbind(drs_ctx->drs_pipe, drs_ctx, &r);
149 * Open secured LDAP connection to remote DC
151 static bool net_drs_ldap_connect(struct net_drs_context *drs_ctx)
156 url = talloc_asprintf(drs_ctx, "ldap://%s/", drs_ctx->dc_name);
158 d_printf(__location__ ": Have no memory");
162 drs_ctx->ldap.ldb = ldb_wrap_connect(drs_ctx,
163 drs_ctx->net_ctx->event_ctx, drs_ctx->net_ctx->lp_ctx,
166 drs_ctx->net_ctx->credentials,
168 if (drs_ctx->ldap.ldb == NULL) {
169 d_printf("Unable to connect to LDAP %s", url);
179 * fetch RootDSE record
181 static bool net_drs_ldap_rootdse(struct net_drs_context *drs_ctx)
184 struct ldb_result *r;
185 struct ldb_dn *basedn;
186 static const char *attrs[] = {
191 SMB_ASSERT(drs_ctx->ldap.ldb != NULL);
193 basedn = ldb_dn_new(drs_ctx, drs_ctx->ldap.ldb, NULL);
195 d_printf(__location__ ": No memory");
199 ret = ldb_search(drs_ctx->ldap.ldb, drs_ctx, &r,
200 basedn, LDB_SCOPE_BASE, attrs,
203 if (ret != LDB_SUCCESS) {
204 d_printf("RootDSE search failed: %s", ldb_errstring(drs_ctx->ldap.ldb));
207 } else if (r->count != 1) {
208 d_printf("RootDSE search returned more than one record!");
213 drs_ctx->ldap.rootdse = r->msgs[0];
219 * parses binding from command line
220 * and gets target DC name
222 static bool net_drs_parse_binding(struct net_drs_context *drs_ctx, const char *dc_binding)
226 status = dcerpc_parse_binding(drs_ctx, dc_binding, &drs_ctx->binding);
227 if (!NT_STATUS_IS_OK(status)) {
228 d_printf("Bad binding supplied %s\n", dc_binding);
232 drs_ctx->binding->transport = NCACN_IP_TCP;
233 drs_ctx->binding->flags |= DCERPC_SIGN | DCERPC_SEAL;
235 /* cache target DC name */
236 drs_ctx->dc_name = drs_ctx->binding->target_hostname;
242 * Free DRSUAPI connection upon net_drs_context
245 static int net_drs_context_destructor(struct net_drs_context *drs_ctx)
247 if (drs_ctx->drs_pipe) {
248 net_drs_DsUnbind(drs_ctx);
254 * Create net_drs_context context to be used
255 * by 'net drs' sub-commands
257 bool net_drs_create_context(struct net_context *net_ctx,
258 const char *dc_binding,
259 struct net_drs_context **_drs_ctx)
261 struct net_drs_context *drs_ctx;
263 drs_ctx = talloc_zero(net_ctx, struct net_drs_context);
265 d_printf(__location__ ": No memory");
269 drs_ctx->net_ctx = net_ctx;
271 if (!net_drs_parse_binding(drs_ctx, dc_binding)) {
276 if (!net_drs_ldap_connect(drs_ctx)) {
280 if (!net_drs_ldap_rootdse(drs_ctx)) {
284 /* DRSUAPI connection */
285 if (!net_drs_DsBind(drs_ctx)) {
289 /* set destructor to free any open connections */
290 talloc_set_destructor(drs_ctx, net_drs_context_destructor);
296 talloc_free(drs_ctx);