s4-net-drs: fix some coding style issues
[kai/samba-autobuild/.git] / source4 / utils / net / drs / net_drs.c
1 /*
2    Samba Unix/Linux SMB client library
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 "librpc/gen_ndr/ndr_drsuapi_c.h"
25 #include "net_drs.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb_wrap.h"
28 #include "system/filesys.h"
29
30
31 /**
32  * 'net drs' supported sub-commands
33  */
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         { NULL, NULL }
39 };
40
41 /**
42  * 'net drs' entry point
43  */
44 int net_drs(struct net_context *ctx, int argc, const char **argv)
45 {
46         return net_run_function(ctx, argc, argv, net_drs_functable, net_drs_usage);
47 }
48
49 /**
50  * 'net drs' usage message
51  */
52 int net_drs_usage(struct net_context *ctx, int argc, const char **argv)
53 {
54         d_printf("net drs <command> [options]\n");
55         d_printf("\n");
56         d_printf("Currently implemented commands:\n");
57         d_printf("  bind - Display DC replication features\n");
58         d_printf("  kcc - Forces the KCC to recalculate replication topology for a specified domain controller\n");
59         return 0;
60 }
61
62 /**
63  * Create drsuapi connection to remote DC
64  * and fill-in DC capabilities
65  */
66 static bool net_drs_DsBind(struct net_drs_context *drs_ctx)
67 {
68         NTSTATUS status;
69         struct GUID bind_guid;
70         struct drsuapi_DsBind req;
71         struct drsuapi_DsBindInfoCtr in_bind_ctr;
72         union drsuapi_DsBindInfo *bind_info;
73
74         SMB_ASSERT(drs_ctx->binding != NULL);
75
76         status = dcerpc_pipe_connect_b(drs_ctx,
77                                        &drs_ctx->drs_pipe,
78                                        drs_ctx->binding,
79                                        &ndr_table_drsuapi,
80                                        drs_ctx->net_ctx->credentials,
81                                        drs_ctx->net_ctx->event_ctx,
82                                        drs_ctx->net_ctx->lp_ctx);
83         if (!NT_STATUS_IS_OK(status)) {
84                 d_printf("Failed to connect to server: %s\n", nt_errstr(status));
85                 return false;
86         }
87
88         ZERO_STRUCT(in_bind_ctr);
89         in_bind_ctr.length = 48;
90         in_bind_ctr.info.info48.pid = (uint32_t)getpid();
91         GUID_from_string(DRSUAPI_DS_BIND_GUID, &bind_guid);
92         req.in.bind_guid = &bind_guid;
93         req.in.bind_info = &in_bind_ctr;
94         req.out.bind_handle = &drs_ctx->bind_handle;
95
96         status = dcerpc_drsuapi_DsBind(drs_ctx->drs_pipe, drs_ctx, &req);
97         if (!NT_STATUS_IS_OK(status)) {
98                 const char *errstr = nt_errstr(status);
99                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
100                         errstr = dcerpc_errstr(drs_ctx, drs_ctx->drs_pipe->last_fault_code);
101                 }
102                 d_printf("dcerpc_drsuapi_DsBind failed - %s\n", errstr);
103                 return false;
104         } else if (!W_ERROR_IS_OK(req.out.result)) {
105                 d_printf("DsBind failed - %s\n", win_errstr(req.out.result));
106                 return false;
107         }
108
109         /* fill-in remote DC capabilities */
110         ZERO_STRUCT(drs_ctx->info48);
111         bind_info = &req.out.bind_info->info;
112         drs_ctx->bind_info_len = req.out.bind_info->length;
113         switch (drs_ctx->bind_info_len) {
114         case 48:
115                 drs_ctx->info48.supported_extensions_ext = bind_info->info48.supported_extensions_ext;
116                 drs_ctx->info48.config_dn_guid = bind_info->info48.config_dn_guid;
117         case 28:
118                 drs_ctx->info48.repl_epoch = bind_info->info28.repl_epoch;
119         case 24:
120                 drs_ctx->info48.supported_extensions = bind_info->info24.supported_extensions;
121                 drs_ctx->info48.site_guid = bind_info->info24.site_guid;
122                 drs_ctx->info48.pid = bind_info->info24.pid;
123                 break;
124         default:
125                 d_printf("Error: server returned BindInfo length %d", req.out.bind_info->length);
126                 return false;
127         }
128
129         return true;
130 }
131
132 /**
133  * Close DRSUAPI connection to remote DC
134  */
135 static bool net_drs_DsUnbind(struct net_drs_context *drs_ctx)
136 {
137         struct drsuapi_DsUnbind r;
138         struct policy_handle bind_handle;
139
140         ZERO_STRUCT(r);
141         r.out.bind_handle = &bind_handle;
142
143         r.in.bind_handle = &drs_ctx->bind_handle;
144         dcerpc_drsuapi_DsUnbind(drs_ctx->drs_pipe, drs_ctx, &r);
145
146         return true;
147 }
148
149
150 /**
151  * Open secured LDAP connection to remote DC
152  */
153 static bool net_drs_ldap_connect(struct net_drs_context *drs_ctx)
154 {
155         char *url;
156         bool bret = true;
157
158         url = talloc_asprintf(drs_ctx, "ldap://%s/", drs_ctx->dc_name);
159         if (!url) {
160                 d_printf(__location__ ": Have no memory");
161                 return false;
162         }
163
164         drs_ctx->ldap.ldb = ldb_wrap_connect(drs_ctx,
165                                              drs_ctx->net_ctx->event_ctx, drs_ctx->net_ctx->lp_ctx,
166                                              url,
167                                              NULL,
168                                              drs_ctx->net_ctx->credentials,
169                                              0);
170         if (drs_ctx->ldap.ldb == NULL) {
171                 d_printf("Unable to connect to LDAP %s", url);
172                 bret = false;
173         }
174
175         talloc_free(url);
176
177         return bret;
178 }
179
180 /**
181  * fetch RootDSE record
182  */
183 static bool net_drs_ldap_rootdse(struct net_drs_context *drs_ctx)
184 {
185         int ret;
186         struct ldb_result *r;
187         struct ldb_dn *basedn;
188         static const char *attrs[] = {
189                 "*",
190                 NULL
191         };
192
193         SMB_ASSERT(drs_ctx->ldap.ldb != NULL);
194
195         basedn = ldb_dn_new(drs_ctx, drs_ctx->ldap.ldb, NULL);
196         if (!basedn) {
197                 d_printf(__location__ ": No memory");
198                 return false;
199         }
200
201         ret = ldb_search(drs_ctx->ldap.ldb, drs_ctx, &r,
202                          basedn, LDB_SCOPE_BASE, attrs,
203                          "(objectClass=*)");
204         talloc_free(basedn);
205         if (ret != LDB_SUCCESS) {
206                 d_printf("RootDSE search failed: %s", ldb_errstring(drs_ctx->ldap.ldb));
207                 talloc_free(r);
208                 return false;
209         } else if (r->count != 1) {
210                 d_printf("RootDSE search returned more than one record!");
211                 talloc_free(r);
212                 return false;
213         }
214
215         drs_ctx->ldap.rootdse = r->msgs[0];
216
217         return true;
218 }
219
220 /**
221  * parses binding from command line
222  * and gets target DC name
223  */
224 static bool net_drs_parse_binding(struct net_drs_context *drs_ctx, const char *dc_binding)
225 {
226         NTSTATUS status;
227
228         status = dcerpc_parse_binding(drs_ctx, dc_binding, &drs_ctx->binding);
229         if (!NT_STATUS_IS_OK(status)) {
230                 d_printf("Bad binding supplied %s\n", dc_binding);
231                 return false;
232         }
233
234         drs_ctx->binding->transport = NCACN_IP_TCP;
235         drs_ctx->binding->flags |= DCERPC_SIGN | DCERPC_SEAL;
236
237         /* cache target DC name */
238         drs_ctx->dc_name = drs_ctx->binding->target_hostname;
239
240         return true;
241 }
242
243 /**
244  * Free DRSUAPI connection upon net_drs_context
245  * destruction
246  */
247 static int net_drs_context_destructor(struct net_drs_context *drs_ctx)
248 {
249         if (drs_ctx->drs_pipe) {
250                 net_drs_DsUnbind(drs_ctx);
251         }
252         return 0;
253 }
254
255 /**
256  * Create net_drs_context context to be used
257  * by 'net drs' sub-commands
258  */
259 bool net_drs_create_context(struct net_context *net_ctx,
260                             const char *dc_binding,
261                             struct net_drs_context **_drs_ctx)
262 {
263         struct net_drs_context *drs_ctx;
264
265         drs_ctx = talloc_zero(net_ctx, struct net_drs_context);
266         if (!drs_ctx) {
267                 d_printf(__location__ ": No memory");
268                 return false;
269         }
270
271         drs_ctx->net_ctx = net_ctx;
272
273         if (!net_drs_parse_binding(drs_ctx, dc_binding)) {
274                 goto failed;
275         }
276
277         /* LDAP connect */
278         if (!net_drs_ldap_connect(drs_ctx)) {
279                 goto failed;
280         }
281         /* fetch RootDSE */
282         if (!net_drs_ldap_rootdse(drs_ctx)) {
283                 goto failed;
284         }
285
286         /* DRSUAPI connection */
287         if (!net_drs_DsBind(drs_ctx)) {
288                 goto failed;
289         }
290
291         /* set destructor to free any open connections */
292         talloc_set_destructor(drs_ctx, net_drs_context_destructor);
293
294         *_drs_ctx = drs_ctx;
295         return true;
296
297 failed:
298         talloc_free(drs_ctx);
299         return false;
300 }