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