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