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