38d6d267b83eea034c6444b7b27e7bc30585202a
[kai/samba.git] / source / 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 "librpc/gen_ndr/ndr_netlogon.h"
29 #include "librpc/gen_ndr/ndr_samr.h"
30 #include "dlinklist.h"
31 #include "lib/ldb/include/ldb.h"
32
33 struct samsync_ldb_secret {
34         struct samsync_ldb_secret *prev, *next;
35         DATA_BLOB secret;
36         char *name;
37         NTTIME mtime;
38 };
39
40 struct samsync_ldb_trusted_domain {
41         struct samsync_ldb_trusted_domain *prev, *next;
42         struct dom_sid *sid;
43         char *name;
44 };
45
46 struct samsync_ldb_state {
47         struct dom_sid *dom_sid[3];
48         struct ldb_context *sam_ldb;
49         char *base_dn[3];
50         struct samsync_ldb_secret *secrets;
51         struct samsync_ldb_trusted_domain *trusted_domains;
52 };
53
54 static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,
55                                                          struct samsync_ldb_state *state,
56                                                          struct dom_sid *sid,
57                                                          char **fsp_dn)
58 {
59         const char *sidstr = dom_sid_string(mem_ctx, sid);
60         /* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */
61         const char *basedn = samdb_search_string(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN],
62                                                  "dn",
63                                                  "(&(objectClass=container)"
64                                                  "(cn=ForeignSecurityPrincipals))");
65         struct ldb_message *msg;
66         int ret;
67
68         if (!sidstr) {
69                 return NT_STATUS_NO_MEMORY;
70         }
71
72         if (basedn == NULL) {
73                 DEBUG(0, ("Failed to find DN for "
74                           "ForeignSecurityPrincipal container\n"));
75                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
76         }
77         
78         msg = ldb_msg_new(mem_ctx);
79         if (msg == NULL) {
80                 return NT_STATUS_NO_MEMORY;
81         }
82
83         /* add core elements to the ldb_message for the alias */
84         msg->dn = talloc_asprintf(mem_ctx, "CN=%s,%s", sidstr, basedn);
85         if (msg->dn == NULL)
86                 return NT_STATUS_NO_MEMORY;
87         
88         samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,
89                              "objectClass",
90                              "foreignSecurityPrincipal");
91
92         *fsp_dn = msg->dn;
93
94         /* create the alias */
95         ret = samdb_add(state->sam_ldb, mem_ctx, msg);
96         if (ret != 0) {
97                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
98                          "record %s: %s\n", msg->dn, 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                 ret_domain = gendb_search(state->sam_ldb, mem_ctx, NULL, &msgs_domain, domain_attrs,
120                                           "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 
121                                           domain_name);
122                 if (ret_domain == -1) {
123                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
124                 }
125                 
126                 if (ret_domain != 1) {
127                         return NT_STATUS_NO_SUCH_DOMAIN;                
128                 }
129
130                 state->base_dn[database]
131                         = talloc_steal(state, samdb_result_string(msgs_domain[0], 
132                                                                   "nCName", NULL));
133                 
134                 state->dom_sid[database]
135                         = talloc_steal(state, 
136                                        samdb_search_dom_sid(state->sam_ldb, state,
137                                                             state->base_dn[database], "objectSid", 
138                                                             "dn=%s", state->base_dn[database]));
139         } else if (database == SAM_DATABASE_BUILTIN) {
140                         /* work out the builtin_dn - useful for so many calls its worth
141                            fetching here */
142                 state->base_dn[database]
143                         = talloc_steal(state, 
144                                        samdb_search_string(state->sam_ldb, mem_ctx, NULL,
145                                                            "dn", "objectClass=builtinDomain"));
146                 state->dom_sid[database]
147                         = dom_sid_parse_talloc(state, SID_BUILTIN);
148         } else {
149                 /* PRIVs DB */
150                 return NT_STATUS_INVALID_PARAMETER;
151         }
152
153         msg = ldb_msg_new(mem_ctx);
154         if (msg == NULL) {
155                 return NT_STATUS_NO_MEMORY;
156         }
157
158         msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);
159         if (!msg->dn) {
160                 return NT_STATUS_NO_MEMORY;
161         }
162
163         samdb_msg_add_string(state->sam_ldb, mem_ctx, 
164                              msg, "oEMInformation", domain->comment.string);
165
166         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
167                              msg, "forceLogff", domain->force_logoff_time);
168
169         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
170                           msg, "minPwdLen", domain->min_password_length);
171
172         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
173                           msg, "maxPwdAge", domain->max_password_age);
174
175         samdb_msg_add_int64(state->sam_ldb, mem_ctx, 
176                           msg, "minPwdAge", domain->min_password_age);
177
178         samdb_msg_add_uint(state->sam_ldb, mem_ctx, 
179                           msg, "pwdHistoryLength", domain->password_history_length);
180
181         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
182                              msg, "modifiedCountAtLastProm", 
183                              domain->sequence_num);
184
185         samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 
186                              msg, "creationTime", domain->domain_create_time);
187
188         /* TODO: Account lockout, password properties */
189         
190         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
191
192         if (ret) {
193                 return NT_STATUS_INTERNAL_ERROR;
194         }
195         return NT_STATUS_OK;
196 }
197
198 static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,
199                                         struct samsync_ldb_state *state,
200                                         struct creds_CredentialState *creds,
201                                         enum netr_SamDatabaseID database,
202                                         struct netr_DELTA_ENUM *delta) 
203 {
204         uint32_t rid = delta->delta_id_union.rid;
205         struct netr_DELTA_USER *user = delta->delta_union.user;
206         const char *container, *obj_class;
207         char *cn_name;
208         int cn_name_len;
209
210         struct ldb_message *msg;
211         struct ldb_message **msgs;
212         int ret;
213         uint32_t acb;
214         BOOL add = False;
215         const char *attrs[] = { NULL };
216
217         msg = ldb_msg_new(mem_ctx);
218         if (msg == NULL) {
219                 return NT_STATUS_NO_MEMORY;
220         }
221
222         /* search for the user, by rid */
223         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
224                            "(&(objectClass=user)(objectSid=%s))", 
225                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
226
227         if (ret == -1) {
228                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
229         } else if (ret == 0) {
230                 add = True;
231         } else if (ret > 1) {
232                 DEBUG(0, ("More than one user with SID: %s\n", 
233                           dom_sid_string(mem_ctx, 
234                                          dom_sid_add_rid(mem_ctx, 
235                                                          state->dom_sid[database], 
236                                                          rid))));
237                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
238         } else {
239                 msg->dn = talloc_steal(msg, msgs[0]->dn);
240         }
241
242
243         cn_name   = talloc_strdup(mem_ctx, user->account_name.string);
244         NT_STATUS_HAVE_NO_MEMORY(cn_name);
245         cn_name_len = strlen(cn_name);
246
247 #define ADD_OR_DEL(type, attrib, field) do {\
248         if (user->field) { \
249                 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
250                                      attrib, user->field); \
251         } else if (!add) { \
252                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
253                                      attrib); \
254         } \
255         } while (0);
256
257         ADD_OR_DEL(string, "samAccountName", account_name.string);
258         ADD_OR_DEL(string, "displayName", full_name.string);
259
260         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
261                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
262                 return NT_STATUS_NO_MEMORY; 
263         }
264
265         ADD_OR_DEL(uint, "primaryGroupID", primary_gid);
266         ADD_OR_DEL(string, "homeDirectory", home_directory.string);
267         ADD_OR_DEL(string, "homeDrive", home_drive.string);
268         ADD_OR_DEL(string, "scriptPath", logon_script.string);
269         ADD_OR_DEL(string, "description", description.string);
270         ADD_OR_DEL(string, "userWorkstations", workstations.string);
271
272         ADD_OR_DEL(uint64, "lastLogon", last_logon);
273         ADD_OR_DEL(uint64, "lastLogoff", last_logoff);
274
275         if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) { 
276                 return NT_STATUS_NO_MEMORY; 
277         }
278
279         ADD_OR_DEL(uint, "badPwdCount", bad_password_count);
280         ADD_OR_DEL(uint, "logonCount", logon_count);
281
282         ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);
283         ADD_OR_DEL(uint64, "accountExpires", acct_expiry);
284         
285         if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg, 
286                                      "userAccountConrol", user->acct_flags) != 0) { 
287                 return NT_STATUS_NO_MEMORY; 
288         } 
289         
290         /* Passwords */
291         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
292                                 "unicodePwd"); 
293         if (user->lm_password_present) {
294                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
295                                    "lmPwdHash", &user->lmpassword);
296         } else {
297                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
298                                      "lmPwdHash"); 
299         }
300         if (user->nt_password_present) {
301                 samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  
302                                    "ntPwdHash", &user->ntpassword);
303         } else {
304                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
305                                      "ntPwdHash"); 
306         }
307             
308         ADD_OR_DEL(string, "comment", comment.string);
309         ADD_OR_DEL(string, "userParameters", parameters.string);
310         ADD_OR_DEL(uint, "countryCode", country_code);
311         ADD_OR_DEL(uint, "codePage", code_page);
312
313         ADD_OR_DEL(string, "profilePath", profile_path.string);
314
315 #undef ADD_OR_DEL
316
317         acb = user->acct_flags;
318         if (acb & (ACB_WSTRUST)) {
319                 cn_name[cn_name_len - 1] = '\0';
320                 container = "Computers";
321                 obj_class = "computer";
322                 
323         } else if (acb & ACB_SVRTRUST) {
324                 if (cn_name[cn_name_len - 1] != '$') {
325                         return NT_STATUS_FOOBAR;                
326                 }
327                 cn_name[cn_name_len - 1] = '\0';
328                 container = "Domain Controllers";
329                 obj_class = "computer";
330         } else {
331                 container = "Users";
332                 obj_class = "user";
333         }
334         if (add) {
335                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
336                                      "objectClass", obj_class);
337                 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
338                                           cn_name, container, state->base_dn[database]);
339                 if (!msg->dn) {
340                         return NT_STATUS_NO_MEMORY;             
341                 }
342
343                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
344                 if (ret != 0) {
345                         DEBUG(0,("Failed to create user record %s\n", msg->dn));
346                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
347                 }
348         } else {
349                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
350                 if (ret != 0) {
351                         DEBUG(0,("Failed to modify user record %s\n", msg->dn));
352                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
353                 }
354         }
355
356         return NT_STATUS_OK;
357 }
358
359 static NTSTATUS samsync_ldb_delete_user(TALLOC_CTX *mem_ctx,
360                                         struct samsync_ldb_state *state,
361                                         struct creds_CredentialState *creds,
362                                         enum netr_SamDatabaseID database,
363                                         struct netr_DELTA_ENUM *delta) 
364 {
365         uint32_t rid = delta->delta_id_union.rid;
366         struct ldb_message **msgs;
367         int ret;
368         const char *attrs[] = { NULL };
369
370         /* search for the user, by rid */
371         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
372                            "(&(objectClass=user)(objectSid=%s))", 
373                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
374
375         if (ret == -1) {
376                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
377                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
378         } else if (ret == 0) {
379                 return NT_STATUS_NO_SUCH_USER;
380         } else if (ret > 1) {
381                 DEBUG(0, ("More than one user with SID: %s\n", 
382                           dom_sid_string(mem_ctx, 
383                                          dom_sid_add_rid(mem_ctx, 
384                                                          state->dom_sid[database], 
385                                                          rid))));
386                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
387         }
388
389         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
390         if (ret != 0) {
391                 DEBUG(0,("Failed to delete user record %s: %s\n", msgs[0]->dn, 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 = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
471                                           cn_name, container, state->base_dn[database]);
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", msg->dn, ldb_errstring(state->sam_ldb)));
479                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
480                 }
481         } else {
482                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
483                 if (ret != 0) {
484                         DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
485                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
486                 }
487         }
488
489         return NT_STATUS_OK;
490 }
491
492 static NTSTATUS samsync_ldb_delete_group(TALLOC_CTX *mem_ctx,
493                                         struct samsync_ldb_state *state,
494                                         struct creds_CredentialState *creds,
495                                         enum netr_SamDatabaseID database,
496                                         struct netr_DELTA_ENUM *delta) 
497 {
498         uint32_t rid = delta->delta_id_union.rid;
499         struct ldb_message **msgs;
500         int ret;
501         const char *attrs[] = { NULL };
502
503         /* search for the group, by rid */
504         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
505                            "(&(objectClass=group)(objectSid=%s))", 
506                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
507
508         if (ret == -1) {
509                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
510                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
511         } else if (ret == 0) {
512                 return NT_STATUS_NO_SUCH_GROUP;
513         } else if (ret > 1) {
514                 DEBUG(0, ("More than one group/alias with SID: %s\n", 
515                           dom_sid_string(mem_ctx, 
516                                          dom_sid_add_rid(mem_ctx, 
517                                                          state->dom_sid[database], 
518                                                          rid))));
519                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
520         }
521         
522         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
523         if (ret != 0) {
524                 DEBUG(0,("Failed to delete group record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
525                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
526         }
527
528         return NT_STATUS_OK;
529 }
530
531 static NTSTATUS samsync_ldb_handle_group_member(TALLOC_CTX *mem_ctx,
532                                                 struct samsync_ldb_state *state,
533                                                 struct creds_CredentialState *creds,
534                                                 enum netr_SamDatabaseID database,
535                                                 struct netr_DELTA_ENUM *delta) 
536 {
537         uint32_t rid = delta->delta_id_union.rid;
538         struct netr_DELTA_GROUP_MEMBER *group_member = delta->delta_union.group_member;
539         struct ldb_message *msg;
540         struct ldb_message **msgs;
541         int ret;
542         const char *attrs[] = { NULL };
543         int i;
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                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
557                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
558         } else if (ret == 0) {
559                 return NT_STATUS_NO_SUCH_GROUP;
560         } else if (ret > 1) {
561                 DEBUG(0, ("More than one group/alias with SID: %s\n", 
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         talloc_free(msgs);
572
573         for (i=0; i<group_member->num_rids; i++) {
574                 /* search for the group, by rid */
575                 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
576                                    "(&(objectClass=user)(objectSid=%s))", 
577                                    ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], group_member->rids[i]))); 
578
579                 if (ret == -1) {
580                         DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
581                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
582                 } else if (ret == 0) {
583                         return NT_STATUS_NO_SUCH_USER;
584                 } else if (ret > 1) {
585                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
586                 } else {
587                         samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", msgs[0]->dn);
588                 }
589         
590                 talloc_free(msgs);
591         }
592
593         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
594         if (ret != 0) {
595                 DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
596                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
597         }
598
599         return NT_STATUS_OK;
600 }
601
602 static NTSTATUS samsync_ldb_handle_alias(TALLOC_CTX *mem_ctx,
603                                          struct samsync_ldb_state *state,
604                                          struct creds_CredentialState *creds,
605                                          enum netr_SamDatabaseID database,
606                                          struct netr_DELTA_ENUM *delta) 
607 {
608         uint32_t rid = delta->delta_id_union.rid;
609         struct netr_DELTA_ALIAS *alias = delta->delta_union.alias;
610         const char *container, *obj_class;
611         const char *cn_name;
612
613         struct ldb_message *msg;
614         struct ldb_message **msgs;
615         int ret;
616         BOOL add = False;
617         const char *attrs[] = { NULL };
618
619         msg = ldb_msg_new(mem_ctx);
620         if (msg == NULL) {
621                 return NT_STATUS_NO_MEMORY;
622         }
623
624         /* search for the alias, by rid */
625         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
626                            "(&(objectClass=group)(objectSid=%s))", 
627                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
628
629         if (ret == -1) {
630                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
631                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
632         } else if (ret == 0) {
633                 add = True;
634         } else if (ret > 1) {
635                 DEBUG(0, ("More than one group/alias with SID: %s\n", 
636                           dom_sid_string(mem_ctx, 
637                                          dom_sid_add_rid(mem_ctx, 
638                                                          state->dom_sid[database], 
639                                                          rid))));
640                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
641         } else {
642                 msg->dn = talloc_steal(mem_ctx, msgs[0]->dn);
643         }
644
645         cn_name   = alias->alias_name.string;
646
647 #define ADD_OR_DEL(type, attrib, field) do {\
648         if (alias->field) { \
649                 samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \
650                                      attrib, alias->field); \
651         } else if (!add) { \
652                 samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  \
653                                      attrib); \
654         } \
655         } while (0);
656
657         ADD_OR_DEL(string, "samAccountName", alias_name.string);
658
659         if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 
660                                   "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {
661                 return NT_STATUS_NO_MEMORY; 
662         }
663
664         ADD_OR_DEL(string, "description", description.string);
665
666 #undef ADD_OR_DEL
667
668         samdb_msg_add_uint(state->sam_ldb, mem_ctx, msg, "groupType", 0x80000004);
669
670         container = "Users";
671         obj_class = "group";
672
673         if (add) {
674                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, 
675                                      "objectClass", obj_class);
676                 msg->dn = talloc_asprintf(mem_ctx, "CN=%s,CN=%s,%s",
677                                           cn_name, container, state->base_dn[database]);
678                 if (!msg->dn) {
679                         return NT_STATUS_NO_MEMORY;             
680                 }
681
682                 ret = samdb_add(state->sam_ldb, mem_ctx, msg);
683                 if (ret != 0) {
684                         DEBUG(0,("Failed to create alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
685                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
686                 }
687         } else {
688                 ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
689                 if (ret != 0) {
690                         DEBUG(0,("Failed to modify alias record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
691                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
692                 }
693         }
694
695         return NT_STATUS_OK;
696 }
697
698 static NTSTATUS samsync_ldb_delete_alias(TALLOC_CTX *mem_ctx,
699                                         struct samsync_ldb_state *state,
700                                         struct creds_CredentialState *creds,
701                                         enum netr_SamDatabaseID database,
702                                         struct netr_DELTA_ENUM *delta) 
703 {
704         uint32_t rid = delta->delta_id_union.rid;
705         struct ldb_message **msgs;
706         int ret;
707         const char *attrs[] = { NULL };
708
709         /* search for the alias, by rid */
710         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
711                            "(&(objectClass=group)(objectSid=%s))", 
712                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
713
714         if (ret == -1) {
715                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
716                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
717         } else if (ret == 0) {
718                 return NT_STATUS_NO_SUCH_ALIAS;
719         } else if (ret > 1) {
720                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
721         }
722
723         ret = samdb_delete(state->sam_ldb, mem_ctx, msgs[0]->dn);
724         if (ret != 0) {
725                 DEBUG(0,("Failed to delete alias record %s: %s\n", msgs[0]->dn, ldb_errstring(state->sam_ldb)));
726                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
727         }
728
729         return NT_STATUS_OK;
730 }
731
732 static NTSTATUS samsync_ldb_handle_alias_member(TALLOC_CTX *mem_ctx,
733                                                 struct samsync_ldb_state *state,
734                                                 struct creds_CredentialState *creds,
735                                                 enum netr_SamDatabaseID database,
736                                                 struct netr_DELTA_ENUM *delta) 
737 {
738         uint32_t rid = delta->delta_id_union.rid;
739         struct netr_DELTA_ALIAS_MEMBER *alias_member = delta->delta_union.alias_member;
740         struct ldb_message *msg;
741         struct ldb_message **msgs;
742         int ret;
743         const char *attrs[] = { NULL };
744         int i;
745
746         msg = ldb_msg_new(mem_ctx);
747         if (msg == NULL) {
748                 return NT_STATUS_NO_MEMORY;
749         }
750
751         /* search for the alias, by rid */
752         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database], &msgs, attrs,
753                            "(&(objectClass=group)(objectSid=%s))", 
754                            ldap_encode_ndr_dom_sid(mem_ctx, dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))); 
755
756         if (ret == -1) {
757                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
758                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
759         } else if (ret == 0) {
760                 return NT_STATUS_NO_SUCH_GROUP;
761         } else if (ret > 1) {
762                 DEBUG(0, ("More than one group/alias with SID: %s\n", 
763                           dom_sid_string(mem_ctx, 
764                                          dom_sid_add_rid(mem_ctx, 
765                                                          state->dom_sid[database], 
766                                                          rid))));
767                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
768         } else {
769                 msg->dn = talloc_steal(msg, msgs[0]->dn);
770         }
771         
772         talloc_free(msgs);
773
774         for (i=0; i<alias_member->sids.num_sids; i++) {
775                 char *alias_member_dn;
776                 /* search for members, in the top basedn (normal users are builtin aliases) */
777                 ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
778                                    "(objectSid=%s)", 
779                                    ldap_encode_ndr_dom_sid(mem_ctx, alias_member->sids.sids[i].sid)); 
780
781                 if (ret == -1) {
782                         DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
783                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
784                 } else if (ret == 0) {
785                         NTSTATUS nt_status;
786                         nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
787                                                                              alias_member->sids.sids[i].sid, 
788                                                                              &alias_member_dn);
789                         if (!NT_STATUS_IS_OK(nt_status)) {
790                                 return nt_status;
791                         }
792                 } else if (ret > 1) {
793                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
794                 } else {
795                         alias_member_dn = msgs[0]->dn;
796                 }
797                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "member", alias_member_dn);
798         
799                 talloc_free(msgs);
800         }
801
802         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
803         if (ret != 0) {
804                 DEBUG(0,("Failed to modify group record %s: %s\n", msg->dn, ldb_errstring(state->sam_ldb)));
805                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
806         }
807
808         return NT_STATUS_OK;
809 }
810
811 static NTSTATUS samsync_ldb_handle_account(TALLOC_CTX *mem_ctx,
812                                         struct samsync_ldb_state *state,
813                                         struct creds_CredentialState *creds,
814                                         enum netr_SamDatabaseID database,
815                                         struct netr_DELTA_ENUM *delta) 
816 {
817         struct dom_sid *sid = delta->delta_id_union.sid;
818         struct netr_DELTA_ACCOUNT *account = delta->delta_union.account;
819
820         struct ldb_message *msg;
821         struct ldb_message **msgs;
822         char *privilage_dn;
823         int ret;
824         const char *attrs[] = { NULL };
825         int i;
826
827         msg = ldb_msg_new(mem_ctx);
828         if (msg == NULL) {
829                 return NT_STATUS_NO_MEMORY;
830         }
831
832         /* search for the account, by sid, in the top basedn */
833         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
834                            "(objectSid=%s)", ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
835
836         if (ret == -1) {
837                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
838                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
839         } else if (ret == 0) {
840                 NTSTATUS nt_status;
841                 nt_status = samsync_ldb_add_foreignSecurityPrincipal(mem_ctx, state,
842                                                                      sid,
843                                                                      &privilage_dn);
844                 privilage_dn = talloc_steal(msg, privilage_dn);
845                 if (!NT_STATUS_IS_OK(nt_status)) {
846                         return nt_status;
847                 }
848         } else if (ret > 1) {
849                 DEBUG(0, ("More than one account with SID: %s\n", 
850                           dom_sid_string(mem_ctx, sid)));
851                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
852         } else {
853                 privilage_dn = talloc_steal(msg, msgs[0]->dn);
854         }
855
856         msg->dn = privilage_dn;
857
858         for (i=0; i< account->privilege_entries; i++) {
859                 samdb_msg_add_string(state->sam_ldb, mem_ctx, msg, "privilage",
860                                      account->privilege_name[i].string);
861         }
862
863         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
864         if (ret != 0) {
865                 DEBUG(0,("Failed to modify privilage record %s\n", msg->dn));
866                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
867         }
868
869         return NT_STATUS_OK;
870 }
871
872 static NTSTATUS samsync_ldb_delete_account(TALLOC_CTX *mem_ctx,
873                                         struct samsync_ldb_state *state,
874                                         struct creds_CredentialState *creds,
875                                         enum netr_SamDatabaseID database,
876                                         struct netr_DELTA_ENUM *delta) 
877 {
878         struct dom_sid *sid = delta->delta_id_union.sid;
879
880         struct ldb_message *msg;
881         struct ldb_message **msgs;
882         int ret;
883         const char *attrs[] = { NULL };
884
885         msg = ldb_msg_new(mem_ctx);
886         if (msg == NULL) {
887                 return NT_STATUS_NO_MEMORY;
888         }
889
890         /* search for the account, by sid, in the top basedn */
891         ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[SAM_DATABASE_DOMAIN], &msgs, attrs,
892                            "(objectSid=%s)", 
893                            ldap_encode_ndr_dom_sid(mem_ctx, sid)); 
894
895         if (ret == -1) {
896                 DEBUG(0, ("gendb_search failed: %s\n", ldb_errstring(state->sam_ldb)));
897                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
898         } else if (ret == 0) {
899                 return NT_STATUS_NO_SUCH_USER;
900         } else if (ret > 1) {
901                 DEBUG(0, ("More than one account with SID: %s\n", 
902                           dom_sid_string(mem_ctx, sid)));
903                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
904         } else {
905                 msg->dn = talloc_steal(msg, msgs[0]->dn);
906         }
907
908         samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  
909                              "privilage"); 
910
911         ret = samdb_replace(state->sam_ldb, mem_ctx, msg);
912         if (ret != 0) {
913                 DEBUG(0,("Failed to modify privilage record %s\n", msg->dn));
914                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
915         }
916
917         return NT_STATUS_OK;
918 }
919
920 static NTSTATUS libnet_samsync_ldb_fn(TALLOC_CTX *mem_ctx,              
921                                   void *private,                        
922                                   struct creds_CredentialState *creds,
923                                   enum netr_SamDatabaseID database,
924                                   struct netr_DELTA_ENUM *delta,
925                                   char **error_string)
926 {
927         NTSTATUS nt_status = NT_STATUS_OK;
928         struct samsync_ldb_state *state = private;
929
930         *error_string = NULL;
931         switch (delta->delta_type) {
932         case NETR_DELTA_DOMAIN:
933         {
934                 nt_status = samsync_ldb_handle_domain(mem_ctx, 
935                                                       state,
936                                                       creds,
937                                                       database,
938                                                       delta);
939                 break;
940         }
941         case NETR_DELTA_USER:
942         {
943                 nt_status = samsync_ldb_handle_user(mem_ctx, 
944                                                     state,
945                                                     creds,
946                                                     database,
947                                                     delta);
948                 break;
949         }
950         case NETR_DELTA_DELETE_USER:
951         {
952                 nt_status = samsync_ldb_delete_user(mem_ctx, 
953                                                     state,
954                                                     creds,
955                                                     database,
956                                                     delta);
957                 break;
958         }
959         case NETR_DELTA_GROUP:
960         {
961                 nt_status = samsync_ldb_handle_group(mem_ctx, 
962                                                      state,
963                                                      creds,
964                                                      database,
965                                                      delta);
966                 break;
967         }
968         case NETR_DELTA_DELETE_GROUP:
969         {
970                 nt_status = samsync_ldb_delete_group(mem_ctx, 
971                                                     state,
972                                                     creds,
973                                                     database,
974                                                     delta);
975                 break;
976         }
977         case NETR_DELTA_GROUP_MEMBER:
978         {
979                 nt_status = samsync_ldb_handle_group_member(mem_ctx, 
980                                                             state,
981                                                             creds,
982                                                             database,
983                                                             delta);
984                 break;
985         }
986         case NETR_DELTA_ALIAS:
987         {
988                 nt_status = samsync_ldb_handle_alias(mem_ctx, 
989                                                      state,
990                                                      creds,
991                                                      database,
992                                                      delta);
993                 break;
994         }
995         case NETR_DELTA_DELETE_ALIAS:
996         {
997                 nt_status = samsync_ldb_delete_alias(mem_ctx, 
998                                                     state,
999                                                     creds,
1000                                                     database,
1001                                                     delta);
1002                 break;
1003         }
1004         case NETR_DELTA_ALIAS_MEMBER:
1005         {
1006                 nt_status = samsync_ldb_handle_alias_member(mem_ctx, 
1007                                                             state,
1008                                                             creds,
1009                                                             database,
1010                                                             delta);
1011                 break;
1012         }
1013         case NETR_DELTA_ACCOUNT:
1014         {
1015                 nt_status = samsync_ldb_handle_account(mem_ctx, 
1016                                                      state,
1017                                                      creds,
1018                                                      database,
1019                                                      delta);
1020                 break;
1021         }
1022         case NETR_DELTA_DELETE_ACCOUNT:
1023         {
1024                 nt_status = samsync_ldb_delete_account(mem_ctx, 
1025                                                     state,
1026                                                     creds,
1027                                                     database,
1028                                                     delta);
1029                 break;
1030         }
1031         default:
1032                 /* Can't dump them all right now */
1033                 break;
1034         }
1035         return nt_status;
1036 }
1037
1038 static NTSTATUS libnet_samsync_ldb_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1039 {
1040         NTSTATUS nt_status;
1041         struct libnet_SamSync r2;
1042         struct samsync_ldb_state *state = talloc(mem_ctx, struct samsync_ldb_state);
1043
1044         if (!state) {
1045                 return NT_STATUS_NO_MEMORY;
1046         }
1047
1048         state->secrets = NULL;
1049         state->trusted_domains = NULL;
1050
1051         state->sam_ldb = samdb_connect(state);
1052
1053         
1054
1055         r2.error_string = NULL;
1056         r2.delta_fn = libnet_samsync_ldb_fn;
1057         r2.fn_ctx = state;
1058         r2.machine_account = NULL; /* TODO:  Create a machine account, fill this in, and the delete it */
1059         nt_status = libnet_SamSync_netlogon(ctx, state, &r2);
1060         r->error_string = r2.error_string;
1061
1062         if (!NT_STATUS_IS_OK(nt_status)) {
1063                 talloc_free(state);
1064                 return nt_status;
1065         }
1066         talloc_free(state);
1067         return nt_status;
1068 }
1069
1070
1071
1072 static NTSTATUS libnet_samsync_ldb_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1073 {
1074         NTSTATUS nt_status;
1075         struct libnet_samsync_ldb r2;
1076         r2.level = LIBNET_SAMSYNC_LDB_NETLOGON;
1077         r2.error_string = NULL;
1078         nt_status = libnet_samsync_ldb(ctx, mem_ctx, &r2);
1079         r->error_string = r2.error_string;
1080         
1081         return nt_status;
1082 }
1083
1084 NTSTATUS libnet_samsync_ldb(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_samsync_ldb *r)
1085 {
1086         switch (r->level) {
1087         case LIBNET_SAMSYNC_LDB_GENERIC:
1088                 return libnet_samsync_ldb_generic(ctx, mem_ctx, r);
1089         case LIBNET_SAMSYNC_LDB_NETLOGON:
1090                 return libnet_samsync_ldb_netlogon(ctx, mem_ctx, r);
1091         }
1092
1093         return NT_STATUS_INVALID_LEVEL;
1094 }