r8771: Extend the SamSync code out to groups and aliases, as well as deleting.
[bbaumbach/samba-autobuild/.git] / source4 / libnet / libnet_samsync_ldb.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) Andrew Tridgell 2004
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 2 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, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24
25 #include "includes.h"
26 #include "libnet/libnet.h"
27 #include "librpc/gen_ndr/ndr_netlogon.h"
28 #include "librpc/gen_ndr/ndr_samr.h"
29 #include "dlinklist.h"
30 #include "lib/ldb/include/ldb.h"
31
32 struct samsync_ldb_secret {
33         struct samsync_ldb_secret *prev, *next;
34         DATA_BLOB secret;
35         char *name;
36         NTTIME mtime;
37 };
38
39 struct samsync_ldb_trusted_domain {
40         struct samsync_ldb_trusted_domain *prev, *next;
41         struct dom_sid *sid;
42         char *name;
43 };
44
45 struct samsync_ldb_state {
46         struct dom_sid *dom_sid[3];
47         struct ldb_context *sam_ldb;
48         char *base_dn[3];
49         struct samsync_ldb_secret *secrets;
50         struct samsync_ldb_trusted_domain *trusted_domains;
51 };
52
53 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
54                                           struct samsync_ldb_state *state,
55                                           struct creds_CredentialState *creds,
56                                           enum netr_SamDatabaseID database,
57                                           struct netr_DELTA_ENUM *delta) 
58 {
59         struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
60         const char *domain_name = domain->domain_name.string;
61         struct ldb_message *msg;
62         int ret;
63         
64         if (database == SAM_DATABASE_DOMAIN) {
65                 const char *domain_attrs[] =  {"nETBIOSName", "nCName", NULL};
66                 struct ldb_message **msgs_domain;
67                 int ret_domain;
68                 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
69                                           "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
70                                           domain_name);
71                 if (ret_domain == -1) {
72                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
73                 }
74                 
75                 if (ret_domain != 1) {
76                         return NT_STATUS_NO_SUCH_DOMAIN;                
77                 }
78
79                 state->base_dn[database]
80                         = talloc_steal(state, samdb_result_string(msgs_domain[0], 
81                                                                   "nCName", NULL));
82                 
83                 state->dom_sid[database]
84                         = talloc_steal(state, 
85                                        samdb_search_dom_sid(state->sam_ldb, state,
86                                                             state->base_dn[database], "objectSid", 
87                                                             "dn=%s", state->base_dn[database]));
88         } else if (database == SAM_DATABASE_BUILTIN) {
89                         /* work out the builtin_dn - useful for so many calls its worth
90                            fetching here */
91                 state->base_dn[database]
92                         = talloc_steal(state, 
93                                        samdb_search_string(state->sam_ldb, mem_ctx, NULL,
94                                                            "dn", "objectClass=builtinDomain"));
95                 state->dom_sid[database]
96                         = dom_sid_parse_talloc(state, SID_BUILTIN);
97         } else {
98                 /* PRIVs DB */
99                 return NT_STATUS_INVALID_PARAMETER;
100         }
101
102         msg = ldb_msg_new(mem_ctx);
103         if (msg == NULL) {
104                 return NT_STATUS_NO_MEMORY;
105         }
106
107         msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
108         if (!msg->dn) {
109                 return NT_STATUS_NO_MEMORY;
110         }
111
112         samdb_msg_add_string(state->sam_ldb, mem_ctx, 
113                              msg, "oEMInformation", domain->comment.string);
114
115         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
116                              msg, "forceLogff", domain->force_logoff_time);
117
118         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
119                           msg, "minPwdLen", domain->min_password_length);
120
121         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
122                           msg, "maxPwdAge", domain->max_password_age);
123
124         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
125                           msg, "minPwdAge", domain->min_password_age);
126
127         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
128                           msg, "pwdHistoryLength", domain->password_history_length);
129
130         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
131                              msg, "modifiedCountAtLastProm", 
132                              domain->sequence_num);
133
134         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
135                              msg, "creationTime", domain->domain_create_time);
136
137         /* TODO: Account lockout, password properties */
138         
139         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
140
141         if (ret) {
142                 return NT_STATUS_INTERNAL_ERROR;
143         }
144         return NT_STATUS_OK;
145 }
146
147 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
148                                         struct samsync_ldb_state *state,
149                                         struct creds_CredentialState *creds,
150                                         enum netr_SamDatabaseID database,
151                                         struct netr_DELTA_ENUM *delta) 
152 {
153         uint32_t rid = delta->delta_id_union.rid;
154         struct netr_DELTA_USER *user = delta->delta_union.user;
155         const char *container, *obj_class;
156         char *cn_name;
157         int cn_name_len;
158
159         struct ldb_message *msg;
160         struct ldb_message **msgs;
161         int ret;
162         uint32_t acb;
163         BOOL add = False;
164         const char *attrs[] = { NULL };
165
166         msg = ldb_msg_new(mem_ctx);
167         if (msg == NULL) {
168                 return NT_STATUS_NO_MEMORY;
169         }
170
171         /* search for the user, by rid */
172         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
173                            "(&(objectClass=user)(objectSid=%s))", 
174                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
175
176         if (ret == -1) {
177                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
178         } else if (ret == 0) {
179                 add = True;
180         } else if (ret > 1) {
181                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
182         } else {
183                 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
184         }
185
186
187         cn_name   = talloc_strdup(mem_ctx, user->account_name.string);
188         NT_STATUS_HAVE_NO_MEMORY(cn_name);
189         cn_name_len = strlen(cn_name);
190
191 #define ADD_OR_DEL(type, attrib, field) do {\
192         if (user->field) { \
193                 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
194                                      attrib, user->field); \
195         } else if (!add) { \
196                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
197                                      attrib); \
198         } \
199         } while (0);
200
201         ADD_OR_DEL(string, "samAccountName", account_name.string);
202         ADD_OR_DEL(string, "displayName", full_name.string);
203
204         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
205                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
206                 return NT_STATUS_NO_MEMORY; 
207         }
208
209         ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
210         ADD_OR_DEL(string, "homeDirectory", home_directory.string);
211         ADD_OR_DEL(string, "homeDrive", home_drive.string);
212         ADD_OR_DEL(string, "scriptPath", logon_script.string);
213         ADD_OR_DEL(string, "description", description.string);
214         ADD_OR_DEL(string, "userWorkstations", workstations.string);
215
216         ADD_OR_DEL(uint64, "lastLogon", last_logon);
217         ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
218
219         /* TODO: Logon hours */
220
221         ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
222         ADD_OR_DEL(uint, "logonCount", logon_count);
223
224         ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
225         ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
226         
227         if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg, 
228                                      "userAccountConrol", user->acct_flags) != 0) { 
229                 return NT_STATUS_NO_MEMORY; 
230         } 
231         
232         /* Passwords */
233         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
234                                 "unicodePwd"); 
235         if (user->lm_password_present) {
236                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
237                                    "lmPwdHash", &user->lmpassword);
238         } else {
239                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
240                                      "lmPwdHash"); 
241         }
242         if (user->nt_password_present) {
243                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
244                                    "ntPwdHash", &user->ntpassword);
245         } else {
246                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
247                                      "ntPwdHash"); 
248         }
249             
250         ADD_OR_DEL(string, "comment", comment.string);
251         ADD_OR_DEL(string, "userParameters", parameters.string);
252         ADD_OR_DEL(uint, "countryCode", country_code);
253         ADD_OR_DEL(uint, "codePage", code_page);
254
255         ADD_OR_DEL(string, "profilePath", profile_path.string);
256
257 #undef ADD_OR_DEL
258
259         acb = user->acct_flags;
260         if (acb & (ACB_WSTRUST)) {
261                 cn_name[cn_name_len - 1] = '\0';
262                 container = "Computers";
263                 obj_class = "computer";
264                 
265         } else if (acb & ACB_SVRTRUST) {
266                 if (cn_name[cn_name_len - 1] != '$') {
267                         return NT_STATUS_FOOBAR;                
268                 }
269                 cn_name[cn_name_len - 1] = '\0';
270                 container = "Domain Controllers";
271                 obj_class = "computer";
272         } else {
273                 container = "Users";
274                 obj_class = "user";
275         }
276         if (add) {
277                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
278                                      "objectClass", obj_class);
279                 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
280                                           cn_name, container, state->base_dn[database]);
281                 if (!msg->dn) {
282                         return NT_STATUS_NO_MEMORY;             
283                 }
284
285                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
286                 if (ret != 0) {
287                         DEBUG(0,("Failed to create user record %s\n", msg->dn));
288                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
289                 }
290         } else {
291                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
292                 if (ret != 0) {
293                         DEBUG(0,("Failed to modify user record %s\n", msg->dn));
294                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
295                 }
296         }
297
298         return NT_STATUS_OK;
299 }
300
301 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
302                                         struct samsync_ldb_state *state,
303                                         struct creds_CredentialState *creds,
304                                         enum netr_SamDatabaseID database,
305                                         struct netr_DELTA_ENUM *delta) 
306 {
307         uint32_t rid = delta->delta_id_union.rid;
308         struct ldb_message **msgs;
309         int ret;
310         const char *attrs[] = { NULL };
311
312         /* search for the user, by rid */
313         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
314                            "(&(objectClass=user)(objectSid=%s))", 
315                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
316
317         if (ret == -1) {
318                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
319         } else if (ret == 0) {
320                 return NT_STATUS_NO_SUCH_USER;
321         } else if (ret > 1) {
322                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
323         }
324
325         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
326         if (ret != 0) {
327                 DEBUG(0,("Failed to delete user record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
328                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
329         }
330
331         return NT_STATUS_OK;
332 }
333
334 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
335                                          struct samsync_ldb_state *state,
336                                          struct creds_CredentialState *creds,
337                                          enum netr_SamDatabaseID database,
338                                          struct netr_DELTA_ENUM *delta) 
339 {
340         uint32_t rid = delta->delta_id_union.rid;
341         struct netr_DELTA_GROUP *group = delta->delta_union.group;
342         const char *container, *obj_class;
343         const char *cn_name;
344
345         struct ldb_message *msg;
346         struct ldb_message **msgs;
347         int ret;
348         BOOL add = False;
349         const char *attrs[] = { NULL };
350
351         msg = ldb_msg_new(mem_ctx);
352         if (msg == NULL) {
353                 return NT_STATUS_NO_MEMORY;
354         }
355
356         /* search for the group, by rid */
357         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
358                            "(&(objectClass=group)(objectSid=%s))", 
359                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
360
361         if (ret == -1) {
362                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
363         } else if (ret == 0) {
364                 add = True;
365         } else if (ret > 1) {
366                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
367         } else {
368                 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
369         }
370
371         cn_name   = group->group_name.string;
372
373 #define ADD_OR_DEL(type, attrib, field) do {\
374         if (group->field) { \
375                 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
376                                      attrib, group->field); \
377         } else if (!add) { \
378                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
379                                      attrib); \
380         } \
381         } while (0);
382
383         ADD_OR_DEL(string, "samAccountName", group_name.string);
384
385         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
386                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
387                 return NT_STATUS_NO_MEMORY; 
388         }
389
390         ADD_OR_DEL(string, "description", description.string);
391
392 #undef ADD_OR_DEL
393
394         container = "Users";
395         obj_class = "group";
396
397         if (add) {
398                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
399                                      "objectClass", obj_class);
400                 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
401                                           cn_name, container, state->base_dn[database]);
402                 if (!msg->dn) {
403                         return NT_STATUS_NO_MEMORY;             
404                 }
405
406                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
407                 if (ret != 0) {
408                         DEBUG(0,("Failed to create group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
409                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
410                 }
411         } else {
412                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
413                 if (ret != 0) {
414                         DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
415                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
416                 }
417         }
418
419         return NT_STATUS_OK;
420 }
421
422 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
423                                         struct samsync_ldb_state *state,
424                                         struct creds_CredentialState *creds,
425                                         enum netr_SamDatabaseID database,
426                                         struct netr_DELTA_ENUM *delta) 
427 {
428         uint32_t rid = delta->delta_id_union.rid;
429         struct ldb_message **msgs;
430         int ret;
431         const char *attrs[] = { NULL };
432
433         /* search for the group, by rid */
434         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
435                            "(&(objectClass=group)(objectSid=%s))", 
436                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
437
438         if (ret == -1) {
439                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
440         } else if (ret == 0) {
441                 return NT_STATUS_NO_SUCH_GROUP;
442         } else if (ret > 1) {
443                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
444         }
445
446         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
447         if (ret != 0) {
448                 DEBUG(0,("Failed to delete group record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
449                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
450         }
451
452         return NT_STATUS_OK;
453 }
454
455 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
456                                          struct samsync_ldb_state *state,
457                                          struct creds_CredentialState *creds,
458                                          enum netr_SamDatabaseID database,
459                                          struct netr_DELTA_ENUM *delta) 
460 {
461         uint32_t rid = delta->delta_id_union.rid;
462         struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
463         const char *container, *obj_class;
464         const char *cn_name;
465
466         struct ldb_message *msg;
467         struct ldb_message **msgs;
468         int ret;
469         BOOL add = False;
470         const char *attrs[] = { NULL };
471
472         msg = ldb_msg_new(mem_ctx);
473         if (msg == NULL) {
474                 return NT_STATUS_NO_MEMORY;
475         }
476
477         /* search for the alias, by rid */
478         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
479                            "(&(objectClass=group)(objectSid=%s))", 
480                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
481
482         if (ret == -1) {
483                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
484         } else if (ret == 0) {
485                 add = True;
486         } else if (ret > 1) {
487                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
488         } else {
489                 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
490         }
491
492         cn_name   = alias->alias_name.string;
493
494 #define ADD_OR_DEL(type, attrib, field) do {\
495         if (alias->field) { \
496                 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
497                                      attrib, alias->field); \
498         } else if (!add) { \
499                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
500                                      attrib); \
501         } \
502         } while (0);
503
504         ADD_OR_DEL(string, "samAccountName", alias_name.string);
505
506         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
507                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
508                 return NT_STATUS_NO_MEMORY; 
509         }
510
511         ADD_OR_DEL(string, "description", description.string);
512
513 #undef ADD_OR_DEL
514
515         samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "groupType", "0x80000004");
516
517         container = "Users";
518         obj_class = "group";
519
520         if (add) {
521                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
522                                      "objectClass", obj_class);
523                 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
524                                           cn_name, container, state->base_dn[database]);
525                 if (!msg->dn) {
526                         return NT_STATUS_NO_MEMORY;             
527                 }
528
529                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
530                 if (ret != 0) {
531                         DEBUG(0,("Failed to create alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
532                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
533                 }
534         } else {
535                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
536                 if (ret != 0) {
537                         DEBUG(0,("Failed to modify alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
538                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
539                 }
540         }
541
542         return NT_STATUS_OK;
543 }
544
545 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
546                                         struct samsync_ldb_state *state,
547                                         struct creds_CredentialState *creds,
548                                         enum netr_SamDatabaseID database,
549                                         struct netr_DELTA_ENUM *delta) 
550 {
551         uint32_t rid = delta->delta_id_union.rid;
552         struct ldb_message **msgs;
553         int ret;
554         const char *attrs[] = { NULL };
555
556         /* search for the alias, by rid */
557         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
558                            "(&(objectClass=group)(objectSid=%s))", 
559                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
560
561         if (ret == -1) {
562                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
563         } else if (ret == 0) {
564                 return NT_STATUS_NO_SUCH_ALIAS;
565         } else if (ret > 1) {
566                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
567         }
568
569         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
570         if (ret != 0) {
571                 DEBUG(0,("Failed to delete alias record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
572                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
573         }
574
575         return NT_STATUS_OK;
576 }
577
578 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,              
579                                   void *private,                        
580                                   struct creds_CredentialState *creds,
581                                   enum netr_SamDatabaseID database,
582                                   struct netr_DELTA_ENUM *delta,
583                                   char **error_string)
584 {
585         NTSTATUS nt_status = NT_STATUS_OK;
586         struct samsync_ldb_state *state = private;
587
588         *error_string = NULL;
589         switch (delta->delta_type) {
590         case NETR_DELTA_DOMAIN:
591         {
592                 nt_status = samsync_ldb_handle_domain(mem_ctx, 
593                                                       state,
594                                                       creds,
595                                                       database,
596                                                       delta);
597                 break;
598         }
599         case NETR_DELTA_USER:
600         {
601                 nt_status = samsync_ldb_handle_user(mem_ctx, 
602                                                     state,
603                                                     creds,
604                                                     database,
605                                                     delta);
606                 break;
607         }
608         case NETR_DELTA_DELETE_USER:
609         {
610                 nt_status = samsync_ldb_delete_user(mem_ctx, 
611                                                     state,
612                                                     creds,
613                                                     database,
614                                                     delta);
615                 break;
616         }
617         case NETR_DELTA_GROUP:
618         {
619                 nt_status = samsync_ldb_handle_group(mem_ctx, 
620                                                      state,
621                                                      creds,
622                                                      database,
623                                                      delta);
624                 break;
625         }
626         case NETR_DELTA_DELETE_GROUP:
627         {
628                 nt_status = samsync_ldb_delete_group(mem_ctx, 
629                                                     state,
630                                                     creds,
631                                                     database,
632                                                     delta);
633                 break;
634         }
635         case NETR_DELTA_ALIAS:
636         {
637                 nt_status = samsync_ldb_handle_alias(mem_ctx, 
638                                                      state,
639                                                      creds,
640                                                      database,
641                                                      delta);
642                 break;
643         }
644         case NETR_DELTA_DELETE_ALIAS:
645         {
646                 nt_status = samsync_ldb_delete_alias(mem_ctx, 
647                                                     state,
648                                                     creds,
649                                                     database,
650                                                     delta);
651                 break;
652         }
653         default:
654                 /* Can't dump them all right now */
655                 break;
656         }
657         return nt_status;
658 }
659
660 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
661 {
662         NTSTATUS nt_status;
663         struct libnet_SamSync r2;
664         struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
665
666         if (!state) {
667                 return NT_STATUS_NO_MEMORY;
668         }
669
670         state->secrets = NULL;
671         state->trusted_domains = NULL;
672
673         state->sam_ldb = samdb_connect(state);
674
675         
676
677         r2.error_string = NULL;
678         r2.delta_fn = libnet_samsync_ldb_fn;
679         r2.fn_ctx = state;
680         r2.machine_account = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
681         nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
682         r->error_string = r2.error_string;
683
684         if (!NT_STATUS_IS_OK(nt_status)) {
685                 talloc_free(state);
686                 return nt_status;
687         }
688         talloc_free(state);
689         return nt_status;
690 }
691
692
693
694 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
695 {
696         NTSTATUS nt_status;
697         struct libnet_samsync_ldb r2;
698         r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
699         r2.error_string = NULL;
700         nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
701         r->error_string = r2.error_string;
702         
703         return nt_status;
704 }
705
706 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
707 {
708         switch (r->level) {
709         case LIBNET_SAMSYNC_LDB_GENERIC:
710                 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
711         case LIBNET_SAMSYNC_LDB_NETLOGON:
712                 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
713         }
714
715         return NT_STATUS_INVALID_LEVEL;
716 }