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