root/source4/libnet/libnet_samsync_ldb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. samsync_ldb_add_foreignSecurityPrincipal
  2. samsync_ldb_handle_domain
  3. samsync_ldb_handle_user
  4. samsync_ldb_delete_user
  5. samsync_ldb_handle_group
  6. samsync_ldb_delete_group
  7. samsync_ldb_handle_group_member
  8. samsync_ldb_handle_alias
  9. samsync_ldb_delete_alias
  10. samsync_ldb_handle_alias_member
  11. samsync_ldb_handle_account
  12. samsync_ldb_delete_account
  13. libnet_samsync_ldb_fn
  14. libnet_samsync_ldb_init
  15. libnet_samsync_ldb

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

/* [<][>][^][v][top][bottom][index][help] */