1e28c73db5ce855d320a55ab2223f859828e715f
[bbaumbach/samba-autobuild/.git] / source4 / utils / net / drs / net_drs_replicate.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Implements functions offered by repadmin.exe tool under Windows
5
6    Copyright (C) Kamen Mazdrashki <kamen.mazdrashki@postpath.com> 2010
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
23 #include "utils/net/net.h"
24 #include "net_drs.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "dsdb/samdb/samdb.h"
27
28
29 /**
30  * Figure out what is the NDTS Settings objectGUID
31  * when DC_NAME is given
32  */
33 static struct ldb_dn *
34 net_drs_server_dn_from_dc_name(struct net_drs_context *drs_ctx,
35                                const char *dc_name)
36 {
37         int ldb_err;
38         struct ldb_dn *dn;
39         struct ldb_dn *server_dn = NULL;
40         struct ldb_result *ldb_res;
41         static const char *attrs[] = {
42                 "objectGUID",
43                 "name",
44                 "dNSHostName",
45                 NULL
46         };
47         TALLOC_CTX *mem_ctx;
48
49         mem_ctx = talloc_new(drs_ctx);
50
51         /* Make DN for Sites container */
52         dn = ldb_msg_find_attr_as_dn(drs_ctx->ldap.ldb, mem_ctx, drs_ctx->ldap.rootdse, "dsServiceName");
53         NET_DRS_CHECK_GOTO(dn != NULL, failed, "RootDSE doesn't have dsServiceName!?\n");
54         if (!ldb_dn_remove_child_components(dn, 4)) {
55                 d_printf("Failed to make DN for Sites container.\n");
56                 goto failed;
57         }
58
59         /* search for Server in Sites container */
60         ldb_err = ldb_search(drs_ctx->ldap.ldb, mem_ctx, &ldb_res,
61                              dn, LDB_SCOPE_SUBTREE, attrs,
62                              "(&(objectCategory=server)(|(name=%1$s)(dNSHostName=%1$s)))",
63                              dc_name);
64         if (ldb_err != LDB_SUCCESS) {
65                 d_printf("ldb_seach() failed with err: %d (%s).\n",
66                          ldb_err, ldb_errstring(drs_ctx->ldap.ldb));
67                 goto failed;
68         }
69         if (ldb_res->count != 1) {
70                 d_printf("ldb_search() should return exactly one record!\n");
71                 goto failed;
72         }
73
74         server_dn = talloc_steal(drs_ctx, ldb_res->msgs[0]->dn);
75
76 failed:
77         talloc_free(mem_ctx);
78         return server_dn;
79 }
80
81
82 /**
83  * Figure out what is the NDTS Settings objectGUID
84  * when DC_NAME is given
85  */
86 static bool net_drs_ntds_guid_from_dc_name(struct net_drs_context *drs_ctx,
87                                            const char *dc_name,
88                                            struct GUID *_ntds_guid)
89 {
90         int ldb_err;
91         struct ldb_dn *server_dn;
92         struct ldb_result *ldb_res;
93         static const char *attrs[] = {
94                 "objectGUID",
95                 "msDS-portLDAP",
96                 "name",
97                 "objectCategory",
98                 NULL
99         };
100         TALLOC_CTX *mem_ctx;
101
102         mem_ctx = talloc_new(drs_ctx);
103
104         /* resolve Server_DN for dc_name */
105         server_dn = net_drs_server_dn_from_dc_name(drs_ctx, dc_name);
106         if (!server_dn) {
107                 d_printf("DSA object for %s could not be found.\n", dc_name);
108                 goto failed;
109         }
110
111         /* move server_dn mem to local context */
112         server_dn = talloc_steal(mem_ctx, server_dn);
113
114         /* search ntdsDsa object under Server container */
115         ldb_err = ldb_search(drs_ctx->ldap.ldb, mem_ctx, &ldb_res,
116                              server_dn, LDB_SCOPE_ONELEVEL, attrs,
117                              "%s", "(|(objectCategory=nTDSDSA)(objectCategory=nTDSDSARO))");
118         if (ldb_err != LDB_SUCCESS) {
119                 d_printf("ldb_seach() failed with err: %d (%s).\n",
120                          ldb_err, ldb_errstring(drs_ctx->ldap.ldb));
121                 goto failed;
122         }
123         if (ldb_res->count != 1) {
124                 d_printf("ldb_search() should return exactly one record!\n");
125                 goto failed;
126         }
127
128         *_ntds_guid =  samdb_result_guid(ldb_res->msgs[0], "objectGUID");
129
130         talloc_free(mem_ctx);
131         return true;
132
133 failed:
134         talloc_free(mem_ctx);
135         return false;
136 }
137
138 /**
139  * Sends DsReplicaSync to dc_name_dest to
140  * replicate naming context nc_dn_str from
141  * server with ntds_guid_src GUID
142  */
143 static bool net_drs_replicate_sync_nc(struct net_drs_context *drs_ctx,
144                                       struct GUID ntds_guid_src,
145                                       const char *nc_dn_str,
146                                       uint32_t options)
147 {
148         NTSTATUS status;
149         struct net_drs_connection *drs_conn;
150         struct drsuapi_DsReplicaSync req;
151         union drsuapi_DsReplicaSyncRequest sync_req;
152         struct drsuapi_DsReplicaObjectIdentifier nc;
153
154         /* use already opened connection */
155         drs_conn = drs_ctx->drs_conn;
156
157         /* construct naming context object */
158         ZERO_STRUCT(nc);
159         nc.dn = nc_dn_str;
160
161         /* construct request object for DsReplicaSync */
162         req.in.bind_handle                      = &drs_conn->bind_handle;
163         req.in.level                            = 1;
164         req.in.req                              = &sync_req;
165         req.in.req->req1.naming_context         = &nc;
166         req.in.req->req1.options                = options;
167         req.in.req->req1.source_dsa_dns         = NULL;
168         req.in.req->req1.source_dsa_guid        = ntds_guid_src;
169
170         /* send DsReplicaSync request */
171         status = dcerpc_drsuapi_DsReplicaSync_r(drs_conn->drs_handle, drs_ctx, &req);
172         if (!NT_STATUS_IS_OK(status)) {
173                 const char *errstr = nt_errstr(status);
174                 d_printf("DsReplicaSync RPC failed - %s.\n", errstr);
175                 return false;
176         } else if (!W_ERROR_IS_OK(req.out.result)) {
177                 d_printf("DsReplicaSync failed - %s (nc=[%s], dsa_guid=[%s]).\n",
178                          win_errstr(req.out.result),
179                          nc.dn, GUID_string(drs_ctx, &ntds_guid_src));
180                 return false;
181         }
182
183         return true;
184 }
185
186 /**
187  * 'net drs replicate' command entry point
188  */
189 int net_drs_replicate_cmd(struct net_context *ctx, int argc, const char **argv)
190 {
191         bool bret;
192         struct net_drs_context *drs_ctx;
193         struct GUID ntds_guid_src;
194         const char *dc_name_dest;
195         const char *dc_name_src;
196         const char *nc_dn_str;
197
198         /* only one arg expected */
199         if (argc != 3) {
200                 return net_drs_replicate_usage(ctx, argc, argv);
201         }
202
203         dc_name_dest = argv[0];
204         dc_name_src = argv[1];
205         nc_dn_str = argv[2];
206
207         if (!net_drs_create_context(ctx, dc_name_dest, &drs_ctx)) {
208                 return -1;
209         }
210
211         /* Resolve source DC_NAME to its NDTS Settings GUID */
212         if (!net_drs_ntds_guid_from_dc_name(drs_ctx, dc_name_src, &ntds_guid_src)) {
213                 d_printf("Error: DSA object for %s could not be found.\n", dc_name_src);
214                 goto failed;
215         }
216
217         /* Synchronize given Naming Context */
218         bret = net_drs_replicate_sync_nc(drs_ctx,
219                                          ntds_guid_src, nc_dn_str,
220                                          DRSUAPI_DRS_WRIT_REP);
221         if (!bret) {
222                 goto failed;
223         }
224
225         d_printf("Replicate from %s to %s was successful.\n", dc_name_src, drs_ctx->dc_name);
226
227         talloc_free(drs_ctx);
228         return 0;
229
230 failed:
231         d_printf("Replicate terminated with errors.\n");
232         talloc_free(drs_ctx);
233         return -1;
234 }
235
236 /**
237  * 'net drs replicate' usage
238  */
239 int net_drs_replicate_usage(struct net_context *ctx, int argc, const char **argv)
240 {
241         d_printf("net drs replicate <Dest_DC_NAME> <Src_DC_NAME> <Naming Context>\n");
242         return 0;
243 }