s3-net-vampire: add support for partial replication (individual deltas).
[samba.git] / source3 / utils / net_rpc_samsync.c
1 /*
2    Unix SMB/CIFS implementation.
3    dump the remote SAM using rpc samsync operations
4
5    Copyright (C) Andrew Tridgell 2002
6    Copyright (C) Tim Potter 2001,2002
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
8    Modified by Volker Lendecke 2002
9    Copyright (C) Jeremy Allison 2005.
10    Copyright (C) Guenther Deschner 2008.
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "utils/net.h"
28
29 static void parse_samsync_partial_replication_objects(TALLOC_CTX *mem_ctx,
30                                                       int argc,
31                                                       const char **argv,
32                                                       bool *do_single_object_replication,
33                                                       struct samsync_object **objects,
34                                                       uint32_t *num_objects)
35 {
36         int i;
37
38         if (argc > 0) {
39                 *do_single_object_replication = true;
40         }
41
42         for (i=0; i<argc; i++) {
43
44                 struct samsync_object o;
45
46                 ZERO_STRUCT(o);
47
48                 if (!StrnCaseCmp(argv[i], "user_rid=", strlen("user_rid="))) {
49                         o.object_identifier.rid         = get_int_param(argv[i]);
50                         o.object_type                   = NETR_DELTA_USER;
51                         o.database_id                   = SAM_DATABASE_DOMAIN;
52                 }
53                 if (!StrnCaseCmp(argv[i], "group_rid=", strlen("group_rid="))) {
54                         o.object_identifier.rid         = get_int_param(argv[i]);
55                         o.object_type                   = NETR_DELTA_GROUP;
56                         o.database_id                   = SAM_DATABASE_DOMAIN;
57                 }
58                 if (!StrnCaseCmp(argv[i], "group_member_rid=", strlen("group_member_rid="))) {
59                         o.object_identifier.rid         = get_int_param(argv[i]);
60                         o.object_type                   = NETR_DELTA_GROUP_MEMBER;
61                         o.database_id                   = SAM_DATABASE_DOMAIN;
62                 }
63                 if (!StrnCaseCmp(argv[i], "alias_rid=", strlen("alias_rid="))) {
64                         o.object_identifier.rid         = get_int_param(argv[i]);
65                         o.object_type                   = NETR_DELTA_ALIAS;
66                         o.database_id                   = SAM_DATABASE_BUILTIN;
67                 }
68                 if (!StrnCaseCmp(argv[i], "alias_member_rid=", strlen("alias_member_rid="))) {
69                         o.object_identifier.rid         = get_int_param(argv[i]);
70                         o.object_type                   = NETR_DELTA_ALIAS_MEMBER;
71                         o.database_id                   = SAM_DATABASE_BUILTIN;
72                 }
73                 if (!StrnCaseCmp(argv[i], "account_sid=", strlen("account_sid="))) {
74                         const char *sid_str = get_string_param(argv[i]);
75                         string_to_sid(&o.object_identifier.sid, sid_str);
76                         o.object_type                   = NETR_DELTA_ACCOUNT;
77                         o.database_id                   = SAM_DATABASE_PRIVS;
78                 }
79                 if (!StrnCaseCmp(argv[i], "policy_sid=", strlen("policy_sid="))) {
80                         const char *sid_str = get_string_param(argv[i]);
81                         string_to_sid(&o.object_identifier.sid, sid_str);
82                         o.object_type                   = NETR_DELTA_POLICY;
83                         o.database_id                   = SAM_DATABASE_PRIVS;
84                 }
85                 if (!StrnCaseCmp(argv[i], "trustdom_sid=", strlen("trustdom_sid="))) {
86                         const char *sid_str = get_string_param(argv[i]);
87                         string_to_sid(&o.object_identifier.sid, sid_str);
88                         o.object_type                   = NETR_DELTA_TRUSTED_DOMAIN;
89                         o.database_id                   = SAM_DATABASE_PRIVS;
90                 }
91                 if (!StrnCaseCmp(argv[i], "secret_name=", strlen("secret_name="))) {
92                         o.object_identifier.name        = get_string_param(argv[i]);
93                         o.object_type                   = NETR_DELTA_SECRET;
94                         o.database_id                   = SAM_DATABASE_PRIVS;
95                 }
96
97                 if (o.object_type > 0) {
98                         ADD_TO_ARRAY(mem_ctx, struct samsync_object, o,
99                                      objects, num_objects);
100                 }
101         }
102 }
103
104 /* dump sam database via samsync rpc calls */
105 NTSTATUS rpc_samdump_internals(struct net_context *c,
106                                 const DOM_SID *domain_sid,
107                                 const char *domain_name,
108                                 struct cli_state *cli,
109                                 struct rpc_pipe_client *pipe_hnd,
110                                 TALLOC_CTX *mem_ctx,
111                                 int argc,
112                                 const char **argv)
113 {
114         struct samsync_context *ctx = NULL;
115         NTSTATUS status;
116
117         status = libnet_samsync_init_context(mem_ctx,
118                                              domain_sid,
119                                              &ctx);
120         if (!NT_STATUS_IS_OK(status)) {
121                 return status;
122         }
123
124         ctx->mode               = NET_SAMSYNC_MODE_DUMP;
125         ctx->cli                = pipe_hnd;
126         ctx->delta_fn           = display_sam_entries;
127         ctx->domain_name        = domain_name;
128
129         ctx->force_full_replication = c->opt_force_full_repl ? true : false;
130         ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
131
132         parse_samsync_partial_replication_objects(ctx, argc, argv,
133                                                   &ctx->single_object_replication,
134                                                   &ctx->objects,
135                                                   &ctx->num_objects);
136
137         libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
138
139         libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
140
141         libnet_samsync(SAM_DATABASE_PRIVS, ctx);
142
143         TALLOC_FREE(ctx);
144
145         return NT_STATUS_OK;
146 }
147
148 /**
149  * Basic usage function for 'net rpc vampire'
150  *
151  * @param c     A net_context structure
152  * @param argc  Standard main() style argc
153  * @param argc  Standard main() style argv.  Initial components are already
154  *              stripped
155  **/
156
157 int rpc_vampire_usage(struct net_context *c, int argc, const char **argv)
158 {
159         d_printf("net rpc vampire ([ldif [<ldif-filename>] | [keytab] [<keytab-filename]) [options]\n"
160                  "\t to pull accounts from a remote PDC where we are a BDC\n"
161                  "\t\t no args puts accounts in local passdb from smb.conf\n"
162                  "\t\t ldif - put accounts in ldif format (file defaults to "
163                  "/tmp/tmp.ldif)\n"
164                  "\t\t keytab - put account passwords in krb5 keytab (defaults "
165                  "to system keytab)\n");
166
167         net_common_flags_usage(c, argc, argv);
168         return -1;
169 }
170
171
172 /* dump sam database via samsync rpc calls */
173 NTSTATUS rpc_vampire_internals(struct net_context *c,
174                                 const DOM_SID *domain_sid,
175                                 const char *domain_name,
176                                 struct cli_state *cli,
177                                 struct rpc_pipe_client *pipe_hnd,
178                                 TALLOC_CTX *mem_ctx,
179                                 int argc,
180                                 const char **argv)
181 {
182         NTSTATUS result;
183         struct samsync_context *ctx = NULL;
184
185         if (!sid_equal(domain_sid, get_global_sam_sid())) {
186                 d_printf("Cannot import users from %s at this time, "
187                          "as the current domain:\n\t%s: %s\nconflicts "
188                          "with the remote domain\n\t%s: %s\n"
189                          "Perhaps you need to set: \n\n\tsecurity=user\n\t"
190                          "workgroup=%s\n\n in your smb.conf?\n",
191                          domain_name,
192                          get_global_sam_name(),
193                          sid_string_dbg(get_global_sam_sid()),
194                          domain_name,
195                          sid_string_dbg(domain_sid),
196                          domain_name);
197                 return NT_STATUS_UNSUCCESSFUL;
198         }
199
200         result = libnet_samsync_init_context(mem_ctx,
201                                              domain_sid,
202                                              &ctx);
203         if (!NT_STATUS_IS_OK(result)) {
204                 return result;
205         }
206
207         ctx->mode               = NET_SAMSYNC_MODE_FETCH_PASSDB;
208         ctx->cli                = pipe_hnd;
209         ctx->delta_fn           = fetch_sam_entries;
210         ctx->domain_name        = domain_name;
211
212         ctx->force_full_replication = c->opt_force_full_repl ? true : false;
213         ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
214
215         parse_samsync_partial_replication_objects(ctx, argc, argv,
216                                                   &ctx->single_object_replication,
217                                                   &ctx->objects,
218                                                   &ctx->num_objects);
219
220         /* fetch domain */
221         result = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
222
223         if (!NT_STATUS_IS_OK(result) && ctx->error_message) {
224                 d_fprintf(stderr, "%s\n", ctx->error_message);
225                 goto fail;
226         }
227
228         if (ctx->result_message) {
229                 d_fprintf(stdout, "%s\n", ctx->result_message);
230         }
231
232         /* fetch builtin */
233         ctx->domain_sid = sid_dup_talloc(mem_ctx, &global_sid_Builtin);
234         ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
235         result = libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
236
237         if (!NT_STATUS_IS_OK(result) && ctx->error_message) {
238                 d_fprintf(stderr, "%s\n", ctx->error_message);
239                 goto fail;
240         }
241
242         if (ctx->result_message) {
243                 d_fprintf(stdout, "%s\n", ctx->result_message);
244         }
245
246  fail:
247         TALLOC_FREE(ctx);
248         return result;
249 }
250
251 NTSTATUS rpc_vampire_ldif_internals(struct net_context *c,
252                                     const DOM_SID *domain_sid,
253                                     const char *domain_name,
254                                     struct cli_state *cli,
255                                     struct rpc_pipe_client *pipe_hnd,
256                                     TALLOC_CTX *mem_ctx,
257                                     int argc,
258                                     const char **argv)
259 {
260         NTSTATUS status;
261         struct samsync_context *ctx = NULL;
262
263         status = libnet_samsync_init_context(mem_ctx,
264                                              domain_sid,
265                                              &ctx);
266         if (!NT_STATUS_IS_OK(status)) {
267                 return status;
268         }
269
270         if (argc >= 1) {
271                 ctx->output_filename = argv[0];
272         }
273         if (argc >= 2) {
274                 parse_samsync_partial_replication_objects(ctx, argc-1, argv+1,
275                                                           &ctx->single_object_replication,
276                                                           &ctx->objects,
277                                                           &ctx->num_objects);
278         }
279
280         ctx->mode               = NET_SAMSYNC_MODE_FETCH_LDIF;
281         ctx->cli                = pipe_hnd;
282         ctx->delta_fn           = fetch_sam_entries_ldif;
283         ctx->domain_name        = domain_name;
284
285         ctx->force_full_replication = c->opt_force_full_repl ? true : false;
286         ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
287
288         /* fetch domain */
289         status = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
290
291         if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
292                 d_fprintf(stderr, "%s\n", ctx->error_message);
293                 goto fail;
294         }
295
296         if (ctx->result_message) {
297                 d_fprintf(stdout, "%s\n", ctx->result_message);
298         }
299
300         /* fetch builtin */
301         ctx->domain_sid = sid_dup_talloc(mem_ctx, &global_sid_Builtin);
302         ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
303         status = libnet_samsync(SAM_DATABASE_BUILTIN, ctx);
304
305         if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
306                 d_fprintf(stderr, "%s\n", ctx->error_message);
307                 goto fail;
308         }
309
310         if (ctx->result_message) {
311                 d_fprintf(stdout, "%s\n", ctx->result_message);
312         }
313
314  fail:
315         TALLOC_FREE(ctx);
316         return status;
317 }
318
319 int rpc_vampire_ldif(struct net_context *c, int argc, const char **argv)
320 {
321         if (c->display_usage) {
322                 d_printf("Usage:\n"
323                          "net rpc vampire ldif\n"
324                          "    Dump remote SAM database to LDIF file or stdout\n");
325                 return 0;
326         }
327
328         return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id, 0,
329                                rpc_vampire_ldif_internals, argc, argv);
330 }
331
332
333 NTSTATUS rpc_vampire_keytab_internals(struct net_context *c,
334                                       const DOM_SID *domain_sid,
335                                       const char *domain_name,
336                                       struct cli_state *cli,
337                                       struct rpc_pipe_client *pipe_hnd,
338                                       TALLOC_CTX *mem_ctx,
339                                       int argc,
340                                       const char **argv)
341 {
342         NTSTATUS status;
343         struct samsync_context *ctx = NULL;
344
345         status = libnet_samsync_init_context(mem_ctx,
346                                              domain_sid,
347                                              &ctx);
348         if (!NT_STATUS_IS_OK(status)) {
349                 return status;
350         }
351
352         if (argc < 1) {
353                 /* the caller should ensure that a filename is provided */
354                 return NT_STATUS_INVALID_PARAMETER;
355         } else {
356                 ctx->output_filename = argv[0];
357         }
358         if (argc >= 2) {
359                 parse_samsync_partial_replication_objects(ctx, argc-1, argv+1,
360                                                           &ctx->single_object_replication,
361                                                           &ctx->objects,
362                                                           &ctx->num_objects);
363         }
364
365         ctx->mode               = NET_SAMSYNC_MODE_FETCH_KEYTAB;
366         ctx->cli                = pipe_hnd;
367         ctx->delta_fn           = fetch_sam_entries_keytab;
368         ctx->domain_name        = domain_name;
369         ctx->username           = c->opt_user_name;
370         ctx->password           = c->opt_password;
371
372         ctx->force_full_replication = c->opt_force_full_repl ? true : false;
373         ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
374
375         /* fetch domain */
376         status = libnet_samsync(SAM_DATABASE_DOMAIN, ctx);
377
378         if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
379                 d_fprintf(stderr, "%s\n", ctx->error_message);
380                 goto out;
381         }
382
383         if (ctx->result_message) {
384                 d_fprintf(stdout, "%s\n", ctx->result_message);
385         }
386
387  out:
388         TALLOC_FREE(ctx);
389
390         return status;
391 }
392
393 static NTSTATUS rpc_vampire_keytab_ds_internals(struct net_context *c,
394                                                 const DOM_SID *domain_sid,
395                                                 const char *domain_name,
396                                                 struct cli_state *cli,
397                                                 struct rpc_pipe_client *pipe_hnd,
398                                                 TALLOC_CTX *mem_ctx,
399                                                 int argc,
400                                                 const char **argv)
401 {
402         NTSTATUS status;
403         struct dssync_context *ctx = NULL;
404
405         status = libnet_dssync_init_context(mem_ctx,
406                                             &ctx);
407         if (!NT_STATUS_IS_OK(status)) {
408                 return status;
409         }
410
411         ctx->force_full_replication = c->opt_force_full_repl ? true : false;
412         ctx->clean_old_entries = c->opt_clean_old_entries ? true : false;
413
414         if (argc < 1) {
415                 /* the caller should ensure that a filename is provided */
416                 return NT_STATUS_INVALID_PARAMETER;
417         } else {
418                 ctx->output_filename = argv[0];
419         }
420
421         if (argc >= 2) {
422                 ctx->object_dns = &argv[1];
423                 ctx->object_count = argc - 1;
424                 ctx->single_object_replication = c->opt_single_obj_repl ? true
425                                                                         : false;
426         }
427
428         ctx->cli                = pipe_hnd;
429         ctx->domain_name        = domain_name;
430         ctx->ops                = &libnet_dssync_keytab_ops;
431
432         status = libnet_dssync(mem_ctx, ctx);
433         if (!NT_STATUS_IS_OK(status) && ctx->error_message) {
434                 d_fprintf(stderr, "%s\n", ctx->error_message);
435                 goto out;
436         }
437
438         if (ctx->result_message) {
439                 d_fprintf(stdout, "%s\n", ctx->result_message);
440         }
441
442  out:
443         TALLOC_FREE(ctx);
444
445         return status;
446 }
447
448 /**
449  * Basic function for 'net rpc vampire keytab'
450  *
451  * @param c     A net_context structure
452  * @param argc  Standard main() style argc
453  * @param argc  Standard main() style argv.  Initial components are already
454  *              stripped
455  **/
456
457 int rpc_vampire_keytab(struct net_context *c, int argc, const char **argv)
458 {
459         int ret = 0;
460
461         if (c->display_usage || (argc < 1)) {
462                 d_printf("Usage:\n"
463                          "net rpc vampire keytab <keytabfile>\n"
464                          "    Dump remote SAM database to Kerberos keytab file\n");
465                 return 0;
466         }
467
468         ret = run_rpc_command(c, NULL, &ndr_table_drsuapi.syntax_id,
469                               NET_FLAGS_SEAL,
470                               rpc_vampire_keytab_ds_internals, argc, argv);
471         if (ret == 0) {
472                 return 0;
473         }
474
475         return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id, 0,
476                                rpc_vampire_keytab_internals,
477                                argc, argv);
478 }