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