s3-libnet: better separate headers.
[samba.git] / source3 / libnet / libnet_samsync.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Extract the user/system database from a remote SamSync server
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
7    Copyright (C) Guenther Deschner <gd@samba.org> 2008
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23
24 #include "includes.h"
25 #include "libnet/libnet_samsync.h"
26 #include "../lib/crypto/crypto.h"
27 #include "../libcli/samsync/samsync.h"
28 #include "../libcli/auth/libcli_auth.h"
29 #include "../librpc/gen_ndr/cli_netlogon.h"
30
31 /**
32  * Fix up the delta, dealing with encryption issues so that the final
33  * callback need only do the printing or application logic
34  */
35
36 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
37                                         struct netlogon_creds_CredentialState *creds,
38                                         enum netr_SamDatabaseID database_id,
39                                         struct netr_DELTA_ENUM_ARRAY *r)
40 {
41         NTSTATUS status;
42         int i;
43
44         for (i = 0; i < r->num_deltas; i++) {
45
46                 status = samsync_fix_delta(mem_ctx,
47                                            creds,
48                                            database_id,
49                                            &r->delta_enum[i]);
50                 if (!NT_STATUS_IS_OK(status)) {
51                         return status;
52                 }
53         }
54
55         return NT_STATUS_OK;
56 }
57
58 /**
59  * libnet_samsync_init_context
60  */
61
62 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
63                                      const struct dom_sid *domain_sid,
64                                      struct samsync_context **ctx_p)
65 {
66         struct samsync_context *ctx;
67
68         *ctx_p = NULL;
69
70         ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
71         NT_STATUS_HAVE_NO_MEMORY(ctx);
72
73         if (domain_sid) {
74                 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
75                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
76
77                 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
78                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
79         }
80
81         *ctx_p = ctx;
82
83         return NT_STATUS_OK;
84 }
85
86 /**
87  * samsync_database_str
88  */
89
90 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
91 {
92
93         switch (database_id) {
94                 case SAM_DATABASE_DOMAIN:
95                         return "DOMAIN";
96                 case SAM_DATABASE_BUILTIN:
97                         return "BUILTIN";
98                 case SAM_DATABASE_PRIVS:
99                         return "PRIVS";
100                 default:
101                         return "unknown";
102         }
103 }
104
105 /**
106  * samsync_debug_str
107  */
108
109 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
110                                      enum net_samsync_mode mode,
111                                      enum netr_SamDatabaseID database_id)
112 {
113         const char *action = NULL;
114
115         switch (mode) {
116                 case NET_SAMSYNC_MODE_DUMP:
117                         action = "Dumping (to stdout)";
118                         break;
119                 case NET_SAMSYNC_MODE_FETCH_PASSDB:
120                         action = "Fetching (to passdb)";
121                         break;
122                 case NET_SAMSYNC_MODE_FETCH_LDIF:
123                         action = "Fetching (to ldif)";
124                         break;
125                 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
126                         action = "Fetching (to keytab)";
127                         break;
128                 default:
129                         action = "Unknown";
130                         break;
131         }
132
133         return talloc_asprintf(mem_ctx, "%s %s database",
134                                 action, samsync_database_str(database_id));
135 }
136
137 /**
138  * libnet_samsync
139  */
140
141 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
142                                             struct netr_ChangeLogEntry *e)
143 {
144         ZERO_STRUCTP(e);
145
146         e->db_index             = o->database_id;
147         e->delta_type           = o->object_type;
148
149         switch (e->delta_type) {
150                 case NETR_DELTA_DOMAIN:
151                 case NETR_DELTA_DELETE_GROUP:
152                 case NETR_DELTA_RENAME_GROUP:
153                 case NETR_DELTA_DELETE_USER:
154                 case NETR_DELTA_RENAME_USER:
155                 case NETR_DELTA_DELETE_ALIAS:
156                 case NETR_DELTA_RENAME_ALIAS:
157                 case NETR_DELTA_DELETE_TRUST:
158                 case NETR_DELTA_DELETE_ACCOUNT:
159                 case NETR_DELTA_DELETE_SECRET:
160                 case NETR_DELTA_DELETE_GROUP2:
161                 case NETR_DELTA_DELETE_USER2:
162                 case NETR_DELTA_MODIFY_COUNT:
163                         break;
164                 case NETR_DELTA_USER:
165                 case NETR_DELTA_GROUP:
166                 case NETR_DELTA_GROUP_MEMBER:
167                 case NETR_DELTA_ALIAS:
168                 case NETR_DELTA_ALIAS_MEMBER:
169                         e->object_rid = o->object_identifier.rid;
170                         break;
171                 case NETR_DELTA_SECRET:
172                         e->object.object_name = o->object_identifier.name;
173                         e->flags = NETR_CHANGELOG_NAME_INCLUDED;
174                         break;
175                 case NETR_DELTA_TRUSTED_DOMAIN:
176                 case NETR_DELTA_ACCOUNT:
177                 case NETR_DELTA_POLICY:
178                         e->object.object_sid = o->object_identifier.sid;
179                         e->flags = NETR_CHANGELOG_SID_INCLUDED;
180                         break;
181                 default:
182                         break;
183         }
184 }
185
186 /**
187  * libnet_samsync_delta
188  */
189
190 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
191                                      enum netr_SamDatabaseID database_id,
192                                      uint64_t *sequence_num,
193                                      struct samsync_context *ctx,
194                                      struct netr_ChangeLogEntry *e)
195 {
196         NTSTATUS result;
197         NTSTATUS callback_status;
198         const char *logon_server = ctx->cli->desthost;
199         const char *computername = global_myname();
200         struct netr_Authenticator credential;
201         struct netr_Authenticator return_authenticator;
202         uint16_t restart_state = 0;
203         uint32_t sync_context = 0;
204
205         ZERO_STRUCT(return_authenticator);
206
207         do {
208                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
209
210                 netlogon_creds_client_authenticator(ctx->cli->dc, &credential);
211
212                 if (ctx->single_object_replication &&
213                     !ctx->force_full_replication) {
214                         result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
215                                                           logon_server,
216                                                           computername,
217                                                           &credential,
218                                                           &return_authenticator,
219                                                           *e,
220                                                           0,
221                                                           &delta_enum_array);
222                 } else if (!ctx->force_full_replication &&
223                            sequence_num && (*sequence_num > 0)) {
224                         result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
225                                                             logon_server,
226                                                             computername,
227                                                             &credential,
228                                                             &return_authenticator,
229                                                             database_id,
230                                                             sequence_num,
231                                                             &delta_enum_array,
232                                                             0xffff);
233                 } else {
234                         result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
235                                                            logon_server,
236                                                            computername,
237                                                            &credential,
238                                                            &return_authenticator,
239                                                            database_id,
240                                                            restart_state,
241                                                            &sync_context,
242                                                            &delta_enum_array,
243                                                            0xffff);
244                 }
245
246                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
247                         return result;
248                 }
249
250                 /* Check returned credentials. */
251                 if (!netlogon_creds_client_check(ctx->cli->dc,
252                                                  &return_authenticator.cred)) {
253                         DEBUG(0,("credentials chain check failed\n"));
254                         return NT_STATUS_ACCESS_DENIED;
255                 }
256
257                 if (NT_STATUS_IS_ERR(result)) {
258                         break;
259                 }
260
261                 samsync_fix_delta_array(mem_ctx,
262                                         ctx->cli->dc,
263                                         database_id,
264                                         delta_enum_array);
265
266                 /* Process results */
267                 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
268                                                             delta_enum_array,
269                                                             sequence_num,
270                                                             ctx);
271                 if (!NT_STATUS_IS_OK(callback_status)) {
272                         result = callback_status;
273                         goto out;
274                 }
275
276                 TALLOC_FREE(delta_enum_array);
277
278         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
279
280  out:
281
282         return result;
283 }
284
285 /**
286  * libnet_samsync
287  */
288
289 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
290                         struct samsync_context *ctx)
291 {
292         NTSTATUS status = NT_STATUS_OK;
293         NTSTATUS callback_status;
294         TALLOC_CTX *mem_ctx;
295         const char *debug_str;
296         uint64_t sequence_num = 0;
297         int i = 0;
298
299         if (!(mem_ctx = talloc_new(ctx))) {
300                 return NT_STATUS_NO_MEMORY;
301         }
302
303         if (!ctx->ops) {
304                 return NT_STATUS_INVALID_PARAMETER;
305         }
306
307         if (ctx->ops->startup) {
308                 status = ctx->ops->startup(mem_ctx, ctx,
309                                            database_id, &sequence_num);
310                 if (!NT_STATUS_IS_OK(status)) {
311                         goto done;
312                 }
313         }
314
315         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
316         if (debug_str) {
317                 d_fprintf(stderr, "%s\n", debug_str);
318         }
319
320         if (!ctx->single_object_replication) {
321                 status = libnet_samsync_delta(mem_ctx, database_id,
322                                               &sequence_num, ctx, NULL);
323                 goto done;
324         }
325
326         for (i=0; i<ctx->num_objects; i++) {
327
328                 struct netr_ChangeLogEntry e;
329
330                 if (ctx->objects[i].database_id != database_id) {
331                         continue;
332                 }
333
334                 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
335
336                 status = libnet_samsync_delta(mem_ctx, database_id,
337                                               &sequence_num, ctx, &e);
338                 if (!NT_STATUS_IS_OK(status)) {
339                         goto done;
340                 }
341         }
342
343  done:
344
345         if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
346                 callback_status = ctx->ops->finish(mem_ctx, ctx,
347                                                    database_id, sequence_num);
348                 if (!NT_STATUS_IS_OK(callback_status)) {
349                         status = callback_status;
350                 }
351         }
352
353         if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
354
355                 ctx->error_message = talloc_asprintf(ctx,
356                         "Failed to fetch %s database: %s",
357                         samsync_database_str(database_id),
358                         nt_errstr(status));
359
360                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
361
362                         ctx->error_message =
363                                 talloc_asprintf_append(ctx->error_message,
364                                         "\nPerhaps %s is a Windows native mode domain?",
365                                         ctx->domain_name);
366                 }
367         }
368
369         talloc_destroy(mem_ctx);
370
371         return status;
372 }
373
374 /**
375  * pull_netr_AcctLockStr
376  */
377
378 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
379                                struct lsa_BinaryString *r,
380                                struct netr_AcctLockStr **str_p)
381 {
382         struct netr_AcctLockStr *str;
383         enum ndr_err_code ndr_err;
384         DATA_BLOB blob;
385
386         if (!mem_ctx || !r || !str_p) {
387                 return NT_STATUS_INVALID_PARAMETER;
388         }
389
390         *str_p = NULL;
391
392         str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
393         if (!str) {
394                 return NT_STATUS_NO_MEMORY;
395         }
396
397         blob = data_blob_const(r->array, r->length);
398
399         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, str,
400                        (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
401
402         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
403                 return ndr_map_error2ntstatus(ndr_err);
404         }
405
406         *str_p = str;
407
408         return NT_STATUS_OK;
409 }
410