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