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