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