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