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