4bedbbf119fa28d3eed557ae0025e939e2ef2671
[kamenim/samba.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    Copyright (C) Volker Lendecke 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25
26 #include "includes.h"
27 #include "libnet/libnet.h"
28 #include "libcli/ldap/ldap.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "auth/auth.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32
33 struct samsync_ldb_secret {
34         struct samsync_ldb_secret *prev, *next;
35         DATA_BLOB secret;
36         char *name;
37         NTTIME mtime;
38 };
39
40 struct samsync_ldb_trusted_domain {
41         struct samsync_ldb_trusted_domain *prev, *next;
42         struct dom_sid *sid;
43         char *name;
44 };
45
46 struct samsync_ldb_state {
47         /* Values from the LSA lookup */
48         const struct libnet_SamSync_state *samsync_state;
49
50         struct dom_sid *dom_sid[3];
51         struct ldb_context *sam_ldb, *remote_ldb;
52         struct ldb_dn *base_dn[3];
53         struct samsync_ldb_secret *secrets;
54         struct samsync_ldb_trusted_domain *trusted_domains;
55 };
56
57 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
58                                                          struct samsync_ldb_state *state,
59                                                          struct dom_sid *sid,
60                                                          struct ldb_dn **fsp_dn,
61                                                          char **error_string)
62 {
63         const char *sidstr = dom_sid_string(mem_ctx, sid);
64         /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
65         struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,
66                                                 state->base_dn[SAM_DATABASE_DOMAIN],
67                                                 "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
68         struct ldb_message *msg;
69         int ret;
70
71         if (!sidstr) {
72                 return NT_STATUS_NO_MEMORY;
73         }
74
75         if (basedn == NULL) {
76                 *error_string = talloc_asprintf(mem_ctx, 
77                                                 "Failed to find DN for "
78                                                 "ForeignSecurityPrincipal container under %s",
79                                                 ldb_dn_linearize(mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN]));
80                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
81         }
82         
83         msg = ldb_msg_new(mem_ctx);
84         if (msg == NULL) {
85                 return NT_STATUS_NO_MEMORY;
86         }
87
88         /* add core elements to the ldb_message for the alias */
89         msg->dn = ldb_dn_build_child(mem_ctx, "CN", sidstr, basedn);
90         if (msg->dn == NULL)
91                 return NT_STATUS_NO_MEMORY;
92         
93         samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
94                              "objectClass",
95                              "foreignSecurityPrincipal");
96
97         *fsp_dn = msg->dn;
98
99         /* create the alias */
100         ret = samdb_add(state->sam_ldb, mem_ctx, msg);
101         if (ret != 0) {
102                 *error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "
103                                                 "record %s: %s",
104                                                 ldb_dn_linearize(mem_ctx, msg->dn),
105                                                 ldb_errstring(state->sam_ldb));
106                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
107         }
108         return NT_STATUS_OK;
109 }
110
111 static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,
112                                           struct samsync_ldb_state *state,
113                                           enum netr_SamDatabaseID database,
114                                           struct netr_DELTA_ENUM *delta,
115                                           char **error_string) 
116 {
117         struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;
118         const char *domain_name = domain->domain_name.string;
119         struct ldb_message *msg;
120         int ret;
121         
122         msg = ldb_msg_new(mem_ctx);
123         if (msg == NULL) {
124                 return NT_STATUS_NO_MEMORY;
125         }
126
127         if (database == SAM_DATABASE_DOMAIN) {
128                 const char *domain_attrs[] =  {"nETBIOSName", "nCName", NULL};
129                 struct ldb_message **msgs_domain;
130                 int ret_domain;
131
132                 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
133                                           "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
134                                           domain_name);
135                 if (ret_domain == -1) {
136                         *error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));
137                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
138                 }
139                 
140                 if (ret_domain != 1) {
141                         *error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,
142                                                         ret_domain);
143                         return NT_STATUS_NO_SUCH_DOMAIN;                
144                 }
145
146                 state->base_dn[database] = samdb_result_dn(state, msgs_domain[0], "nCName", NULL);
147
148                 if (state->dom_sid[database]) {
149                         /* Update the domain sid with the incoming
150                          * domain (found on LSA pipe, database sid may
151                          * be random) */
152                         samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, 
153                                               msg, "objectSid", state->dom_sid[database]);
154                 } else {
155                         /* Well, we will have to use the one from the database */
156                         state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,
157                                                                         state->base_dn[database], 
158                                                                         "objectSid", NULL);
159                 }
160
161                 if (state->samsync_state->domain_guid) {
162                         NTSTATUS nt_status;
163                         struct ldb_val v;
164                         nt_status = ndr_push_struct_blob(&v, msg, state->samsync_state->domain_guid,
165                                                          (ndr_push_flags_fn_t)ndr_push_GUID);
166                         if (!NT_STATUS_IS_OK(nt_status)) {
167                                 *error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");
168                                 return nt_status;
169                         }
170                         
171                         ldb_msg_add_value(msg, "objectGUID", &v);
172                 }
173         } else if (database == SAM_DATABASE_BUILTIN) {
174                 /* work out the builtin_dn - useful for so many calls its worth
175                    fetching here */
176                 const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,
177                                                            "distinguishedName", "objectClass=builtinDomain");
178                 state->base_dn[database] = ldb_dn_explode(state, dnstring);
179         } else {
180                 /* PRIVs DB */
181                 return NT_STATUS_INVALID_PARAMETER;
182         }
183
184         msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
185         if (!msg->dn) {
186                 return NT_STATUS_NO_MEMORY;
187         }
188
189         samdb_msg_add_string(state->sam_ldb, mem_ctx, 
190                              msg, "oEMInformation", domain->comment.string);
191
192         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
193                             msg, "forceLogoff", domain->force_logoff_time);
194
195         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
196                            msg, "minPwdLen", domain->min_password_length);
197
198         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
199                             msg, "maxPwdAge", domain->max_password_age);
200
201         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
202                             msg, "minPwdAge", domain->min_password_age);
203
204         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
205                            msg, "pwdHistoryLength", domain->password_history_length);
206
207         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
208                              msg, "modifiedCount", 
209                              domain->sequence_num);
210
211         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
212                              msg, "creationTime", domain->domain_create_time);
213
214         /* TODO: Account lockout, password properties */
215         
216         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
217
218         if (ret) {
219                 return NT_STATUS_INTERNAL_ERROR;
220         }
221         return NT_STATUS_OK;
222 }
223
224 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
225                                         struct samsync_ldb_state *state,
226                                         enum netr_SamDatabaseID database,
227                                         struct netr_DELTA_ENUM *delta,
228                                         char **error_string) 
229 {
230         uint32_t rid = delta->delta_id_union.rid;
231         struct netr_DELTA_USER *user = delta->delta_union.user;
232         const char *container, *obj_class;
233         char *cn_name;
234         int cn_name_len;
235         const struct dom_sid *user_sid;
236         struct ldb_message *msg;
237         struct ldb_message **msgs;
238         struct ldb_message **remote_msgs;
239         int ret, i;
240         uint32_t acb;
241         BOOL add = False;
242         const char *attrs[] = { NULL };
243         /* we may change this to a global search, then fill in only the things not in ldap later */
244         const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName", 
245                                        "msDS-KeyVersionNumber", "objectGUID", NULL};
246
247         user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);
248         if (!user_sid) {
249                 return NT_STATUS_NO_MEMORY;
250         }
251
252         msg = ldb_msg_new(mem_ctx);
253         if (msg == NULL) {
254                 return NT_STATUS_NO_MEMORY;
255         }
256
257         msg->dn = NULL;
258         /* search for the user, by rid */
259         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
260                            &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 
261                            ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
262
263         if (ret == -1) {
264                 *error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s", 
265                                                 dom_sid_string(mem_ctx, user_sid),
266                                                 ldb_errstring(state->sam_ldb));
267                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
268         } else if (ret == 0) {
269                 add = True;
270         } else if (ret > 1) {
271                 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB", 
272                                                 dom_sid_string(mem_ctx, user_sid));
273                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
274         } else {
275                 msg->dn = msgs[0]->dn;
276                 talloc_steal(msg, msgs[0]->dn);
277         }
278
279         /* and do the same on the remote database */
280         if (state->remote_ldb) {
281                 ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],
282                                    &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))", 
283                                    ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
284                 
285                 if (ret == -1) {
286                         *error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s", 
287                                                         dom_sid_string(mem_ctx, user_sid),
288                                                         ldb_errstring(state->remote_ldb));
289                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
290                 } else if (ret == 0) {
291                         *error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)", 
292                                                         ldb_dn_linearize(mem_ctx, state->base_dn[database]),
293                                                         dom_sid_string(mem_ctx, user_sid));
294                         return NT_STATUS_NO_SUCH_USER;
295                 } else if (ret > 1) {
296                         *error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s", 
297                                                         dom_sid_string(mem_ctx, user_sid));
298                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
299                         
300                         /* Try to put things in the same location as the remote server */
301                 } else if (add) {
302                         msg->dn = remote_msgs[0]->dn;
303                         talloc_steal(msg, remote_msgs[0]->dn);
304                 }
305         }
306
307         cn_name   = talloc_strdup(mem_ctx, user->account_name.string);
308         NT_STATUS_HAVE_NO_MEMORY(cn_name);
309         cn_name_len = strlen(cn_name);
310
311 #define ADD_OR_DEL(type, attrib, field) do {                            \
312                 if (user->field) {                                      \
313                         samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
314                                                attrib, user->field);    \
315                 } else if (!add) {                                      \
316                         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
317                                              attrib);                   \
318                 }                                                       \
319         } while (0);
320
321         ADD_OR_DEL(string, "samAccountName", account_name.string);
322         ADD_OR_DEL(string, "displayName", full_name.string);
323
324         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
325                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
326                 return NT_STATUS_NO_MEMORY; 
327         }
328
329         ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
330         ADD_OR_DEL(string, "homeDirectory", home_directory.string);
331         ADD_OR_DEL(string, "homeDrive", home_drive.string);
332         ADD_OR_DEL(string, "scriptPath", logon_script.string);
333         ADD_OR_DEL(string, "description", description.string);
334         ADD_OR_DEL(string, "userWorkstations", workstations.string);
335
336         ADD_OR_DEL(uint64, "lastLogon", last_logon);
337         ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
338
339         if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) { 
340                 return NT_STATUS_NO_MEMORY; 
341         }
342
343         ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
344         ADD_OR_DEL(uint, "logonCount", logon_count);
345
346         ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
347         ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
348         
349         if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg, 
350                                      "userAccountControl", user->acct_flags) != 0) { 
351                 return NT_STATUS_NO_MEMORY; 
352         } 
353         
354         /* Passwords.  Ensure there is no plaintext stored against
355          * this entry, as we only have hashes */
356         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
357                              "sambaPassword"); 
358         if (user->lm_password_present) {
359                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
360                                    "lmPwdHash", &user->lmpassword);
361         } else {
362                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
363                                      "lmPwdHash"); 
364         }
365         if (user->nt_password_present) {
366                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
367                                    "ntPwdHash", &user->ntpassword);
368         } else {
369                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
370                                      "ntPwdHash"); 
371         }
372             
373         ADD_OR_DEL(string, "comment", comment.string);
374         ADD_OR_DEL(string, "userParameters", parameters.string);
375         ADD_OR_DEL(uint, "countryCode", country_code);
376         ADD_OR_DEL(uint, "codePage", code_page);
377
378         ADD_OR_DEL(string, "profilePath", profile_path.string);
379
380 #undef ADD_OR_DEL
381
382         for (i=0; remote_attrs[i]; i++) {
383                 struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);
384                 if (!el) {
385                         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
386                                              remote_attrs[i]); 
387                 } else {
388                         ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);
389                 }
390         }
391
392         acb = user->acct_flags;
393         if (acb & (ACB_WSTRUST)) {
394                 cn_name[cn_name_len - 1] = '\0';
395                 container = "Computers";
396                 obj_class = "computer";
397                 
398         } else if (acb & ACB_SVRTRUST) {
399                 if (cn_name[cn_name_len - 1] != '$') {
400                         return NT_STATUS_FOOBAR;                
401                 }
402                 cn_name[cn_name_len - 1] = '\0';
403                 container = "Domain Controllers";
404                 obj_class = "computer";
405         } else {
406                 container = "Users";
407                 obj_class = "user";
408         }
409         if (add) {
410                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
411                                      "objectClass", obj_class);
412                 if (!msg->dn) {
413                         msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
414                                                         "CN=%s, CN=%s", cn_name, container);
415                         if (!msg->dn) {
416                                 return NT_STATUS_NO_MEMORY;             
417                         }
418                 }
419
420                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
421                 if (ret != 0) {
422                         struct ldb_dn *first_try_dn = msg->dn;
423                         /* Try again with the default DN */
424                         msg->dn = talloc_steal(msg, msgs[0]->dn);
425                         ret = samdb_add(state->sam_ldb, mem_ctx, msg);
426                         if (ret != 0) {
427                                 *error_string = talloc_asprintf(mem_ctx, "Failed to create user record.  Tried both %s and %s: %s",
428                                                                 ldb_dn_linearize(mem_ctx, first_try_dn),
429                                                                 ldb_dn_linearize(mem_ctx, msg->dn),
430                                                                 ldb_errstring(state->sam_ldb));
431                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
432                         }
433                 }
434         } else {
435                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
436                 if (ret != 0) {
437                         *error_string = talloc_asprintf(mem_ctx, "Failed to modify user record %s: %s",
438                                                         ldb_dn_linearize(mem_ctx, msg->dn),
439                                                         ldb_errstring(state->sam_ldb));
440                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
441                 }
442         }
443
444         return NT_STATUS_OK;
445 }
446
447 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
448                                         struct samsync_ldb_state *state,
449                                         enum netr_SamDatabaseID database,
450                                         struct netr_DELTA_ENUM *delta,
451                                         char **error_string) 
452 {
453         uint32_t rid = delta->delta_id_union.rid;
454         struct ldb_message **msgs;
455         int ret;
456         const char *attrs[] = { NULL };
457
458         /* search for the user, by rid */
459         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],
460                            &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 
461                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
462
463         if (ret == -1) {
464                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
465                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
466         } else if (ret == 0) {
467                 return NT_STATUS_NO_SUCH_USER;
468         } else if (ret > 1) {
469                 *error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s", 
470                                                 dom_sid_string(mem_ctx, 
471                                                                dom_sid_add_rid(mem_ctx, 
472                                                                                state->dom_sid[database], 
473                                                                                rid)));
474                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
475         }
476
477         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
478         if (ret != 0) {
479                 *error_string = talloc_asprintf(mem_ctx, "Failed to delete user record %s: %s",
480                                                 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
481                                                 ldb_errstring(state->sam_ldb));
482                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
483         }
484
485         return NT_STATUS_OK;
486 }
487
488 static NTSTATUS samsync_ldb_handle_group(TALLOC_CTX *mem_ctx,
489                                          struct samsync_ldb_state *state,
490                                          enum netr_SamDatabaseID database,
491                                          struct netr_DELTA_ENUM *delta,
492                                          char **error_string) 
493 {
494         uint32_t rid = delta->delta_id_union.rid;
495         struct netr_DELTA_GROUP *group = delta->delta_union.group;
496         const char *container, *obj_class;
497         const char *cn_name;
498
499         struct ldb_message *msg;
500         struct ldb_message **msgs;
501         int ret;
502         BOOL add = False;
503         const char *attrs[] = { NULL };
504
505         msg = ldb_msg_new(mem_ctx);
506         if (msg == NULL) {
507                 return NT_STATUS_NO_MEMORY;
508         }
509
510         /* search for the group, by rid */
511         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
512                            "(&(objectClass=group)(objectSid=%s))", 
513                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
514
515         if (ret == -1) {
516                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
517                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
518         } else if (ret == 0) {
519                 add = True;
520         } else if (ret > 1) {
521                 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
522                                                 dom_sid_string(mem_ctx, 
523                                                                dom_sid_add_rid(mem_ctx, 
524                                                                                state->dom_sid[database], 
525                                                                                rid)));
526                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
527         } else {
528                 msg->dn = talloc_steal(msg, msgs[0]->dn);
529         }
530
531         cn_name   = group->group_name.string;
532
533 #define ADD_OR_DEL(type, attrib, field) do {                            \
534                 if (group->field) {                                     \
535                         samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
536                                                attrib, group->field);   \
537                 } else if (!add) {                                      \
538                         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
539                                              attrib);                   \
540                 }                                                       \
541         } while (0);
542
543         ADD_OR_DEL(string, "samAccountName", group_name.string);
544
545         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
546                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
547                 return NT_STATUS_NO_MEMORY; 
548         }
549
550         ADD_OR_DEL(string, "description", description.string);
551
552 #undef ADD_OR_DEL
553
554         container = "Users";
555         obj_class = "group";
556
557         if (add) {
558                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
559                                      "objectClass", obj_class);
560                 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
561                                                 "CN=%s, CN=%s", cn_name, container);
562                 if (!msg->dn) {
563                         return NT_STATUS_NO_MEMORY;             
564                 }
565
566                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
567                 if (ret != 0) {
568                         *error_string = talloc_asprintf(mem_ctx, "Failed to create group record %s: %s",
569                                                         ldb_dn_linearize(mem_ctx, msg->dn),
570                                                         ldb_errstring(state->sam_ldb));
571                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
572                 }
573         } else {
574                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
575                 if (ret != 0) {
576                         *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
577                                                         ldb_dn_linearize(mem_ctx, msg->dn),
578                                                         ldb_errstring(state->sam_ldb));
579                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
580                 }
581         }
582
583         return NT_STATUS_OK;
584 }
585
586 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
587                                          struct samsync_ldb_state *state,
588                                          enum netr_SamDatabaseID database,
589                                          struct netr_DELTA_ENUM *delta,
590                                          char **error_string) 
591 {
592         uint32_t rid = delta->delta_id_union.rid;
593         struct ldb_message **msgs;
594         int ret;
595         const char *attrs[] = { NULL };
596
597         /* search for the group, by rid */
598         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
599                            "(&(objectClass=group)(objectSid=%s))", 
600                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
601
602         if (ret == -1) {
603                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
604                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
605         } else if (ret == 0) {
606                 return NT_STATUS_NO_SUCH_GROUP;
607         } else if (ret > 1) {
608                 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
609                                                 dom_sid_string(mem_ctx, 
610                                                                dom_sid_add_rid(mem_ctx, 
611                                                                                state->dom_sid[database], 
612                                                                                rid)));
613                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
614         }
615         
616         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
617         if (ret != 0) {
618                 *error_string = talloc_asprintf(mem_ctx, "Failed to delete group record %s: %s",
619                                                 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
620                                                 ldb_errstring(state->sam_ldb));
621                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
622         }
623
624         return NT_STATUS_OK;
625 }
626
627 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
628                                                 struct samsync_ldb_state *state,
629                                                 enum netr_SamDatabaseID database,
630                                                 struct netr_DELTA_ENUM *delta,
631                                                 char **error_string) 
632 {
633         uint32_t rid = delta->delta_id_union.rid;
634         struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
635         struct ldb_message *msg;
636         struct ldb_message **msgs;
637         int ret;
638         const char *attrs[] = { NULL };
639         int i;
640
641         msg = ldb_msg_new(mem_ctx);
642         if (msg == NULL) {
643                 return NT_STATUS_NO_MEMORY;
644         }
645
646         /* search for the group, by rid */
647         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
648                            "(&(objectClass=group)(objectSid=%s))", 
649                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
650
651         if (ret == -1) {
652                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
653                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
654         } else if (ret == 0) {
655                 return NT_STATUS_NO_SUCH_GROUP;
656         } else if (ret > 1) {
657                 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
658                                                 dom_sid_string(mem_ctx, 
659                                                                dom_sid_add_rid(mem_ctx, 
660                                                                                state->dom_sid[database], 
661                                                                                rid)));
662                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
663         } else {
664                 msg->dn = talloc_steal(msg, msgs[0]->dn);
665         }
666         
667         talloc_free(msgs);
668
669         for (i=0; i<group_member->num_rids; i++) {
670                 /* search for the group, by rid */
671                 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
672                                    "(&(objectClass=user)(objectSid=%s))", 
673                                    ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i]))); 
674                 
675                 if (ret == -1) {
676                         *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
677                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
678                 } else if (ret == 0) {
679                         return NT_STATUS_NO_SUCH_USER;
680                 } else if (ret > 1) {
681                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
682                 } else {
683                         samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, msgs[0]->dn));
684                 }
685                 
686                 talloc_free(msgs);
687         }
688         
689         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
690         if (ret != 0) {
691                 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
692                                                 ldb_dn_linearize(mem_ctx, msg->dn),
693                                                 ldb_errstring(state->sam_ldb));
694                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
695         }
696
697         return NT_STATUS_OK;
698 }
699
700 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
701                                          struct samsync_ldb_state *state,
702                                          enum netr_SamDatabaseID database,
703                                          struct netr_DELTA_ENUM *delta,
704                                          char **error_string) 
705 {
706         uint32_t rid = delta->delta_id_union.rid;
707         struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
708         const char *container, *obj_class;
709         const char *cn_name;
710
711         struct ldb_message *msg;
712         struct ldb_message **msgs;
713         int ret;
714         BOOL add = False;
715         const char *attrs[] = { NULL };
716
717         msg = ldb_msg_new(mem_ctx);
718         if (msg == NULL) {
719                 return NT_STATUS_NO_MEMORY;
720         }
721
722         /* search for the alias, by rid */
723         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
724                            "(&(objectClass=group)(objectSid=%s))", 
725                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
726
727         if (ret == -1) {
728                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
729                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
730         } else if (ret == 0) {
731                 add = True;
732         } else if (ret > 1) {
733                 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
734                                                 dom_sid_string(mem_ctx, 
735                                                                dom_sid_add_rid(mem_ctx, 
736                                                                                state->dom_sid[database], 
737                                                                                rid)));
738                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
739         } else {
740                 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
741         }
742
743         cn_name   = alias->alias_name.string;
744
745 #define ADD_OR_DEL(type, attrib, field) do {                            \
746                 if (alias->field) {                                     \
747                         samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
748                                                attrib, alias->field);   \
749                 } else if (!add) {                                      \
750                         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \
751                                              attrib);                   \
752                 }                                                       \
753         } while (0);
754
755         ADD_OR_DEL(string, "samAccountName", alias_name.string);
756
757         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
758                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
759                 return NT_STATUS_NO_MEMORY; 
760         }
761
762         ADD_OR_DEL(string, "description", description.string);
763
764 #undef ADD_OR_DEL
765
766         samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
767
768         container = "Users";
769         obj_class = "group";
770
771         if (add) {
772                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
773                                      "objectClass", obj_class);
774                 msg->dn = ldb_dn_string_compose(mem_ctx, state->base_dn[database],
775                                                 "CN=%s, CN=%s", cn_name, container);
776                 if (!msg->dn) {
777                         return NT_STATUS_NO_MEMORY;             
778                 }
779
780                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
781                 if (ret != 0) {
782                         *error_string = talloc_asprintf(mem_ctx, "Failed to create alias record %s: %s",
783                                                         ldb_dn_linearize(mem_ctx, msg->dn),
784                                                         ldb_errstring(state->sam_ldb));
785                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
786                 }
787         } else {
788                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
789                 if (ret != 0) {
790                         *error_string = talloc_asprintf(mem_ctx, "Failed to modify alias record %s: %s",
791                                                         ldb_dn_linearize(mem_ctx, msg->dn),
792                                                         ldb_errstring(state->sam_ldb));
793                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
794                 }
795         }
796
797         return NT_STATUS_OK;
798 }
799
800 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
801                                          struct samsync_ldb_state *state,
802                                          enum netr_SamDatabaseID database,
803                                          struct netr_DELTA_ENUM *delta,
804                                          char **error_string) 
805 {
806         uint32_t rid = delta->delta_id_union.rid;
807         struct ldb_message **msgs;
808         int ret;
809         const char *attrs[] = { NULL };
810
811         /* search for the alias, by rid */
812         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
813                            "(&(objectClass=group)(objectSid=%s))", 
814                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
815
816         if (ret == -1) {
817                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
818                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
819         } else if (ret == 0) {
820                 return NT_STATUS_NO_SUCH_ALIAS;
821         } else if (ret > 1) {
822                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
823         }
824
825         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
826         if (ret != 0) {
827                 *error_string = talloc_asprintf(mem_ctx, "Failed to delete alias record %s: %s",
828                                                 ldb_dn_linearize(mem_ctx, msgs[0]->dn),
829                                                 ldb_errstring(state->sam_ldb));
830                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
831         }
832
833         return NT_STATUS_OK;
834 }
835
836 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
837                                                 struct samsync_ldb_state *state,
838                                                 enum netr_SamDatabaseID database,
839                                                 struct netr_DELTA_ENUM *delta,
840                                                 char **error_string) 
841 {
842         uint32_t rid = delta->delta_id_union.rid;
843         struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
844         struct ldb_message *msg;
845         struct ldb_message **msgs;
846         int ret;
847         const char *attrs[] = { NULL };
848         int i;
849
850         msg = ldb_msg_new(mem_ctx);
851         if (msg == NULL) {
852                 return NT_STATUS_NO_MEMORY;
853         }
854
855         /* search for the alias, by rid */
856         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
857                            "(&(objectClass=group)(objectSid=%s))", 
858                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
859                 
860         if (ret == -1) {
861                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
862                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
863         } else if (ret == 0) {
864                 return NT_STATUS_NO_SUCH_GROUP;
865         } else if (ret > 1) {
866                 *error_string = talloc_asprintf(mem_ctx, "More than one group/alias with SID: %s", 
867                                                 dom_sid_string(mem_ctx, 
868                                                                dom_sid_add_rid(mem_ctx, 
869                                                                                state->dom_sid[database], 
870                                                                                rid)));
871                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
872         } else {
873                 msg->dn = talloc_steal(msg, msgs[0]->dn);
874         }
875         
876         talloc_free(msgs);
877
878         for (i=0; i<alias_member->sids.num_sids; i++) {
879                 struct ldb_dn *alias_member_dn;
880                 /* search for members, in the top basedn (normal users are builtin aliases) */
881                 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
882                                    "(objectSid=%s)", 
883                                    ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid)); 
884
885                 if (ret == -1) {
886                         *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
887                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
888                 } else if (ret == 0) {
889                         NTSTATUS nt_status;
890                         nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
891                                                                              alias_member->sids.sids[i].sid, 
892                                                                              &alias_member_dn, 
893                                                                              error_string);
894                         if (!NT_STATUS_IS_OK(nt_status)) {
895                                 return nt_status;
896                         }
897                 } else if (ret > 1) {
898                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
899                 } else {
900                         alias_member_dn = msgs[0]->dn;
901                 }
902                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", ldb_dn_linearize(mem_ctx, alias_member_dn));
903         
904                 talloc_free(msgs);
905         }
906
907         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
908         if (ret != 0) {
909                 *error_string = talloc_asprintf(mem_ctx, "Failed to modify group record %s: %s",
910                                                 ldb_dn_linearize(mem_ctx, msg->dn),
911                                                 ldb_errstring(state->sam_ldb));
912                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
913         }
914
915         return NT_STATUS_OK;
916 }
917
918 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
919                                            struct samsync_ldb_state *state,
920                                            enum netr_SamDatabaseID database,
921                                            struct netr_DELTA_ENUM *delta,
922                                            char **error_string) 
923 {
924         struct dom_sid *sid = delta->delta_id_union.sid;
925         struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
926
927         struct ldb_message *msg;
928         struct ldb_message **msgs;
929         struct ldb_dn *privilege_dn;
930         int ret;
931         const char *attrs[] = { NULL };
932         int i;
933
934         msg = ldb_msg_new(mem_ctx);
935         if (msg == NULL) {
936                 return NT_STATUS_NO_MEMORY;
937         }
938
939         /* search for the account, by sid, in the top basedn */
940         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
941                            "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
942
943         if (ret == -1) {
944                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
945                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
946         } else if (ret == 0) {
947                 NTSTATUS nt_status;
948                 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
949                                                                      sid,
950                                                                      &privilege_dn,
951                                                                      error_string);
952                 privilege_dn = talloc_steal(msg, privilege_dn);
953                 if (!NT_STATUS_IS_OK(nt_status)) {
954                         return nt_status;
955                 }
956         } else if (ret > 1) {
957                 *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
958                                                 dom_sid_string(mem_ctx, sid));
959                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
960         } else {
961                 privilege_dn = talloc_steal(msg, msgs[0]->dn);
962         }
963
964         msg->dn = privilege_dn;
965
966         for (i=0; i< account->privilege_entries; i++) {
967                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilege",
968                                      account->privilege_name[i].string);
969         }
970
971         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
972         if (ret != 0) {
973                 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
974                                                 ldb_dn_linearize(mem_ctx, msg->dn));
975                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
976         }
977
978         return NT_STATUS_OK;
979 }
980
981 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
982                                            struct samsync_ldb_state *state,
983                                            enum netr_SamDatabaseID database,
984                                            struct netr_DELTA_ENUM *delta,
985                                            char **error_string) 
986 {
987         struct dom_sid *sid = delta->delta_id_union.sid;
988
989         struct ldb_message *msg;
990         struct ldb_message **msgs;
991         int ret;
992         const char *attrs[] = { NULL };
993
994         msg = ldb_msg_new(mem_ctx);
995         if (msg == NULL) {
996                 return NT_STATUS_NO_MEMORY;
997         }
998
999         /* search for the account, by sid, in the top basedn */
1000         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
1001                            "(objectSid=%s)", 
1002                            ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
1003
1004         if (ret == -1) {
1005                 *error_string = talloc_asprintf(mem_ctx, "gendb_search failed: %s", ldb_errstring(state->sam_ldb));
1006                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1007         } else if (ret == 0) {
1008                 return NT_STATUS_NO_SUCH_USER;
1009         } else if (ret > 1) {
1010                 *error_string = talloc_asprintf(mem_ctx, "More than one account with SID: %s", 
1011                                                 dom_sid_string(mem_ctx, sid));
1012                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1013         } else {
1014                 msg->dn = talloc_steal(msg, msgs[0]->dn);
1015         }
1016
1017         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
1018                              "privilage"); 
1019
1020         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
1021         if (ret != 0) {
1022                 *error_string = talloc_asprintf(mem_ctx, "Failed to modify privilege record %s",
1023                                                 ldb_dn_linearize(mem_ctx, msg->dn));
1024                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1025         }
1026
1027         return NT_STATUS_OK;
1028 }
1029
1030 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,              
1031                                       void *private,                    
1032                                       enum netr_SamDatabaseID database,
1033                                       struct netr_DELTA_ENUM *delta,
1034                                       char **error_string)
1035 {
1036         NTSTATUS nt_status = NT_STATUS_OK;
1037         struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state);
1038
1039         *error_string = NULL;
1040         switch (delta->delta_type) {
1041         case NETR_DELTA_DOMAIN:
1042         {
1043                 nt_status = samsync_ldb_handle_domain(mem_ctx, 
1044                                                       state,
1045                                                       database,
1046                                                       delta,
1047                                                       error_string);
1048                 break;
1049         }
1050         case NETR_DELTA_USER:
1051         {
1052                 nt_status = samsync_ldb_handle_user(mem_ctx, 
1053                                                     state,
1054                                                     database,
1055                                                     delta,
1056                                                     error_string);
1057                 break;
1058         }
1059         case NETR_DELTA_DELETE_USER:
1060         {
1061                 nt_status = samsync_ldb_delete_user(mem_ctx, 
1062                                                     state,
1063                                                     database,
1064                                                     delta,
1065                                                     error_string);
1066                 break;
1067         }
1068         case NETR_DELTA_GROUP:
1069         {
1070                 nt_status = samsync_ldb_handle_group(mem_ctx, 
1071                                                      state,
1072                                                      database,
1073                                                      delta,
1074                                                      error_string);
1075                 break;
1076         }
1077         case NETR_DELTA_DELETE_GROUP:
1078         {
1079                 nt_status = samsync_ldb_delete_group(mem_ctx, 
1080                                                      state,
1081                                                      database,
1082                                                      delta,
1083                                                      error_string);
1084                 break;
1085         }
1086         case NETR_DELTA_GROUP_MEMBER:
1087         {
1088                 nt_status = samsync_ldb_handle_group_member(mem_ctx, 
1089                                                             state,
1090                                                             database,
1091                                                             delta,
1092                                                             error_string);
1093                 break;
1094         }
1095         case NETR_DELTA_ALIAS:
1096         {
1097                 nt_status = samsync_ldb_handle_alias(mem_ctx, 
1098                                                      state,
1099                                                      database,
1100                                                      delta,
1101                                                      error_string);
1102                 break;
1103         }
1104         case NETR_DELTA_DELETE_ALIAS:
1105         {
1106                 nt_status = samsync_ldb_delete_alias(mem_ctx, 
1107                                                      state,
1108                                                      database,
1109                                                      delta,
1110                                                      error_string);
1111                 break;
1112         }
1113         case NETR_DELTA_ALIAS_MEMBER:
1114         {
1115                 nt_status = samsync_ldb_handle_alias_member(mem_ctx, 
1116                                                             state,
1117                                                             database,
1118                                                             delta,
1119                                                             error_string);
1120                 break;
1121         }
1122         case NETR_DELTA_ACCOUNT:
1123         {
1124                 nt_status = samsync_ldb_handle_account(mem_ctx, 
1125                                                        state,
1126                                                        database,
1127                                                        delta,
1128                                                        error_string);
1129                 break;
1130         }
1131         case NETR_DELTA_DELETE_ACCOUNT:
1132         {
1133                 nt_status = samsync_ldb_delete_account(mem_ctx, 
1134                                                        state,
1135                                                        database,
1136                                                        delta,
1137                                                        error_string);
1138                 break;
1139         }
1140         default:
1141                 /* Can't dump them all right now */
1142                 break;
1143         }
1144         if (!NT_STATUS_IS_OK(nt_status) && !*error_string) {
1145                 *error_string = talloc_asprintf(mem_ctx, "Failed to handle samsync delta: %s", nt_errstr(nt_status));
1146         }
1147         return nt_status;
1148 }
1149
1150 static NTSTATUS libnet_samsync_ldb_init(TALLOC_CTX *mem_ctx,            
1151                                         void *private,
1152                                         struct libnet_SamSync_state *samsync_state,
1153                                         char **error_string)
1154 {
1155         struct samsync_ldb_state *state = talloc_get_type(private, struct samsync_ldb_state);
1156         const char *server = dcerpc_server_name(samsync_state->netlogon_pipe);
1157         char *ldap_url;
1158
1159         state->samsync_state = samsync_state;
1160
1161         ZERO_STRUCT(state->dom_sid);
1162         if (state->samsync_state->domain_sid) {
1163                 state->dom_sid[SAM_DATABASE_DOMAIN] = dom_sid_dup(state, state->samsync_state->domain_sid);
1164         }
1165
1166         state->dom_sid[SAM_DATABASE_BUILTIN] = dom_sid_parse_talloc(state, SID_BUILTIN);
1167
1168         if (state->samsync_state->realm) {
1169                 if (!server || !*server) {
1170                         /* huh?  how do we not have a server name?  */
1171                         *error_string = talloc_strdup(mem_ctx, "No DCE/RPC server name available.  How did we connect?");
1172                         return NT_STATUS_INVALID_PARAMETER;
1173                 }
1174                 ldap_url = talloc_asprintf(state, "ldap://%s", server);
1175                 
1176                 state->remote_ldb = ldb_wrap_connect(mem_ctx, ldap_url, 
1177                                                      NULL, state->samsync_state->machine_net_ctx->cred,
1178                                                      0, NULL);
1179                 if (!state->remote_ldb) {
1180                         *error_string = talloc_asprintf(mem_ctx, "Failed to connect to remote LDAP server at %s (used to extract additional data in SamSync replication)", ldap_url);
1181                         return NT_STATUS_NO_LOGON_SERVERS;
1182                 }
1183         } else {
1184                 state->remote_ldb = NULL;
1185         }
1186         return NT_STATUS_OK;
1187 }
1188
1189 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1190 {
1191         NTSTATUS nt_status;
1192         struct libnet_SamSync r2;
1193         struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1194
1195         if (!state) {
1196                 return NT_STATUS_NO_MEMORY;
1197         }
1198
1199         state->secrets         = NULL;
1200         state->trusted_domains = NULL;
1201
1202         state->sam_ldb         = ldb_wrap_connect(mem_ctx, lp_sam_url(), r->in.session_info,
1203                                                   ctx->cred, 0, NULL);
1204
1205         r2.out.error_string    = NULL;
1206         r2.in.binding_string   = r->in.binding_string;
1207         r2.in.init_fn          = libnet_samsync_ldb_init;
1208         r2.in.delta_fn         = libnet_samsync_ldb_fn;
1209         r2.in.fn_ctx           = state;
1210         r2.in.machine_account  = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
1211         nt_status              = libnet_SamSync_netlogon(ctx, state, &r2);
1212         r->out.error_string    = r2.out.error_string;
1213         talloc_steal(mem_ctx, r->out.error_string);
1214
1215         if (!NT_STATUS_IS_OK(nt_status)) {
1216                 talloc_free(state);
1217                 return nt_status;
1218         }
1219         talloc_free(state);
1220         return nt_status;
1221 }