root/source3/libnet/libnet_samsync.c

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

DEFINITIONS

This source file includes following definitions.
  1. fix_user
  2. fix_secret
  3. samsync_fix_delta
  4. samsync_fix_delta_array
  5. libnet_samsync_init_context
  6. samsync_database_str
  7. samsync_debug_str
  8. libnet_init_netr_ChangeLogEntry
  9. libnet_samsync_delta
  10. libnet_samsync
  11. pull_netr_AcctLockStr

   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) Guenther Deschner <gd@samba.org> 2008
   8 
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13 
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18 
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 
  24 #include "includes.h"
  25 #include "libnet/libnet.h"
  26 
  27 /**
  28  * Decrypt and extract the user's passwords.
  29  *
  30  * The writes decrypted (no longer 'RID encrypted' or arcfour encrypted)
  31  * passwords back into the structure
  32  */
  33 
  34 static NTSTATUS fix_user(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  35                          DATA_BLOB *session_key,
  36                          enum netr_SamDatabaseID database_id,
  37                          struct netr_DELTA_ENUM *delta)
  38 {
  39 
  40         uint32_t rid = delta->delta_id_union.rid;
  41         struct netr_DELTA_USER *user = delta->delta_union.user;
  42         struct samr_Password lm_hash;
  43         struct samr_Password nt_hash;
  44         unsigned char zero_buf[16];
  45 
  46         memset(zero_buf, '\0', sizeof(zero_buf));
  47 
  48         /* Note that win2000 may send us all zeros
  49          * for the hashes if it doesn't
  50          * think this channel is secure enough. */
  51         if (user->lm_password_present) {
  52                 if (memcmp(user->lmpassword.hash, zero_buf, 16) != 0) {
  53                         sam_pwd_hash(rid, user->lmpassword.hash, lm_hash.hash, 0);
  54                 } else {
  55                         memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
  56                 }
  57                 user->lmpassword = lm_hash;
  58         }
  59 
  60         if (user->nt_password_present) {
  61                 if (memcmp(user->ntpassword.hash, zero_buf, 16) != 0) {
  62                         sam_pwd_hash(rid, user->ntpassword.hash, nt_hash.hash, 0);
  63                 } else {
  64                         memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
  65                 }
  66                 user->ntpassword = nt_hash;
  67         }
  68 
  69         if (user->user_private_info.SensitiveData) {
  70                 DATA_BLOB data;
  71                 struct netr_USER_KEYS keys;
  72                 enum ndr_err_code ndr_err;
  73                 data.data = user->user_private_info.SensitiveData;
  74                 data.length = user->user_private_info.DataLength;
  75                 SamOEMhashBlob(data.data, data.length, session_key);
  76                 user->user_private_info.SensitiveData = data.data;
  77                 user->user_private_info.DataLength = data.length;
  78 
  79                 ndr_err = ndr_pull_struct_blob(&data, mem_ctx, NULL, &keys,
  80                         (ndr_pull_flags_fn_t)ndr_pull_netr_USER_KEYS);
  81                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  82                         dump_data(10, data.data, data.length);
  83                         return ndr_map_error2ntstatus(ndr_err);
  84                 }
  85 
  86                 /* Note that win2000 may send us all zeros
  87                  * for the hashes if it doesn't
  88                  * think this channel is secure enough. */
  89                 if (keys.keys.keys2.lmpassword.length == 16) {
  90                         if (memcmp(keys.keys.keys2.lmpassword.pwd.hash,
  91                                         zero_buf, 16) != 0) {
  92                                 sam_pwd_hash(rid,
  93                                         keys.keys.keys2.lmpassword.pwd.hash,
  94                                         lm_hash.hash, 0);
  95                         } else {
  96                                 memset(lm_hash.hash, '\0', sizeof(lm_hash.hash));
  97                         }
  98                         user->lmpassword = lm_hash;
  99                         user->lm_password_present = true;
 100                 }
 101                 if (keys.keys.keys2.ntpassword.length == 16) {
 102                         if (memcmp(keys.keys.keys2.ntpassword.pwd.hash,
 103                                                 zero_buf, 16) != 0) {
 104                                 sam_pwd_hash(rid,
 105                                         keys.keys.keys2.ntpassword.pwd.hash,
 106                                         nt_hash.hash, 0);
 107                         } else {
 108                                 memset(nt_hash.hash, '\0', sizeof(nt_hash.hash));
 109                         }
 110                         user->ntpassword = nt_hash;
 111                         user->nt_password_present = true;
 112                 }
 113                 /* TODO: rid decrypt history fields */
 114         }
 115         return NT_STATUS_OK;
 116 }
 117 
 118 /**
 119  * Decrypt and extract the secrets
 120  *
 121  * The writes decrypted secrets back into the structure
 122  */
 123 static NTSTATUS fix_secret(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 124                            DATA_BLOB *session_key,
 125                            enum netr_SamDatabaseID database_id,
 126                            struct netr_DELTA_ENUM *delta)
 127 {
 128         struct netr_DELTA_SECRET *secret = delta->delta_union.secret;
 129 
 130         SamOEMhashBlob(secret->current_cipher.cipher_data,
 131                        secret->current_cipher.maxlen,
 132                        session_key);
 133 
 134         SamOEMhashBlob(secret->old_cipher.cipher_data,
 135                        secret->old_cipher.maxlen,
 136                        session_key);
 137 
 138         return NT_STATUS_OK;
 139 }
 140 
 141 /**
 142  * Fix up the delta, dealing with encryption issues so that the final
 143  * callback need only do the printing or application logic
 144  */
 145 
 146 static NTSTATUS samsync_fix_delta(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 147                                   DATA_BLOB *session_key,
 148                                   enum netr_SamDatabaseID database_id,
 149                                   struct netr_DELTA_ENUM *delta)
 150 {
 151         NTSTATUS status = NT_STATUS_OK;
 152 
 153         switch (delta->delta_type) {
 154                 case NETR_DELTA_USER:
 155 
 156                         status = fix_user(mem_ctx,
 157                                           session_key,
 158                                           database_id,
 159                                           delta);
 160                         break;
 161                 case NETR_DELTA_SECRET:
 162 
 163                         status = fix_secret(mem_ctx,
 164                                             session_key,
 165                                             database_id,
 166                                             delta);
 167                         break;
 168                 default:
 169                         break;
 170         }
 171 
 172         return status;
 173 }
 174 
 175 /**
 176  * Fix up the delta, dealing with encryption issues so that the final
 177  * callback need only do the printing or application logic
 178  */
 179 
 180 static NTSTATUS samsync_fix_delta_array(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 181                                         DATA_BLOB *session_key,
 182                                         enum netr_SamDatabaseID database_id,
 183                                         struct netr_DELTA_ENUM_ARRAY *r)
 184 {
 185         NTSTATUS status;
 186         int i;
 187 
 188         for (i = 0; i < r->num_deltas; i++) {
 189 
 190                 status = samsync_fix_delta(mem_ctx,
 191                                            session_key,
 192                                            database_id,
 193                                            &r->delta_enum[i]);
 194                 if (!NT_STATUS_IS_OK(status)) {
 195                         return status;
 196                 }
 197         }
 198 
 199         return NT_STATUS_OK;
 200 }
 201 
 202 /**
 203  * libnet_samsync_init_context
 204  */
 205 
 206 NTSTATUS libnet_samsync_init_context(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 207                                      const struct dom_sid *domain_sid,
 208                                      struct samsync_context **ctx_p)
 209 {
 210         struct samsync_context *ctx;
 211 
 212         *ctx_p = NULL;
 213 
 214         ctx = TALLOC_ZERO_P(mem_ctx, struct samsync_context);
 215         NT_STATUS_HAVE_NO_MEMORY(ctx);
 216 
 217         if (domain_sid) {
 218                 ctx->domain_sid = sid_dup_talloc(mem_ctx, domain_sid);
 219                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid);
 220 
 221                 ctx->domain_sid_str = sid_string_talloc(mem_ctx, ctx->domain_sid);
 222                 NT_STATUS_HAVE_NO_MEMORY(ctx->domain_sid_str);
 223         }
 224 
 225         *ctx_p = ctx;
 226 
 227         return NT_STATUS_OK;
 228 }
 229 
 230 /**
 231  * samsync_database_str
 232  */
 233 
 234 static const char *samsync_database_str(enum netr_SamDatabaseID database_id)
     /* [<][>][^][v][top][bottom][index][help] */
 235 {
 236 
 237         switch (database_id) {
 238                 case SAM_DATABASE_DOMAIN:
 239                         return "DOMAIN";
 240                 case SAM_DATABASE_BUILTIN:
 241                         return "BUILTIN";
 242                 case SAM_DATABASE_PRIVS:
 243                         return "PRIVS";
 244                 default:
 245                         return "unknown";
 246         }
 247 }
 248 
 249 /**
 250  * samsync_debug_str
 251  */
 252 
 253 static const char *samsync_debug_str(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 254                                      enum net_samsync_mode mode,
 255                                      enum netr_SamDatabaseID database_id)
 256 {
 257         const char *action = NULL;
 258 
 259         switch (mode) {
 260                 case NET_SAMSYNC_MODE_DUMP:
 261                         action = "Dumping (to stdout)";
 262                         break;
 263                 case NET_SAMSYNC_MODE_FETCH_PASSDB:
 264                         action = "Fetching (to passdb)";
 265                         break;
 266                 case NET_SAMSYNC_MODE_FETCH_LDIF:
 267                         action = "Fetching (to ldif)";
 268                         break;
 269                 case NET_SAMSYNC_MODE_FETCH_KEYTAB:
 270                         action = "Fetching (to keytab)";
 271                         break;
 272                 default:
 273                         action = "Unknown";
 274                         break;
 275         }
 276 
 277         return talloc_asprintf(mem_ctx, "%s %s database",
 278                                 action, samsync_database_str(database_id));
 279 }
 280 
 281 /**
 282  * libnet_samsync
 283  */
 284 
 285 static void libnet_init_netr_ChangeLogEntry(struct samsync_object *o,
     /* [<][>][^][v][top][bottom][index][help] */
 286                                             struct netr_ChangeLogEntry *e)
 287 {
 288         ZERO_STRUCTP(e);
 289 
 290         e->db_index             = o->database_id;
 291         e->delta_type           = o->object_type;
 292 
 293         switch (e->delta_type) {
 294                 case NETR_DELTA_DOMAIN:
 295                 case NETR_DELTA_DELETE_GROUP:
 296                 case NETR_DELTA_RENAME_GROUP:
 297                 case NETR_DELTA_DELETE_USER:
 298                 case NETR_DELTA_RENAME_USER:
 299                 case NETR_DELTA_DELETE_ALIAS:
 300                 case NETR_DELTA_RENAME_ALIAS:
 301                 case NETR_DELTA_DELETE_TRUST:
 302                 case NETR_DELTA_DELETE_ACCOUNT:
 303                 case NETR_DELTA_DELETE_SECRET:
 304                 case NETR_DELTA_DELETE_GROUP2:
 305                 case NETR_DELTA_DELETE_USER2:
 306                 case NETR_DELTA_MODIFY_COUNT:
 307                         break;
 308                 case NETR_DELTA_USER:
 309                 case NETR_DELTA_GROUP:
 310                 case NETR_DELTA_GROUP_MEMBER:
 311                 case NETR_DELTA_ALIAS:
 312                 case NETR_DELTA_ALIAS_MEMBER:
 313                         e->object_rid = o->object_identifier.rid;
 314                         break;
 315                 case NETR_DELTA_SECRET:
 316                         e->object.object_name = o->object_identifier.name;
 317                         e->flags = NETR_CHANGELOG_NAME_INCLUDED;
 318                         break;
 319                 case NETR_DELTA_TRUSTED_DOMAIN:
 320                 case NETR_DELTA_ACCOUNT:
 321                 case NETR_DELTA_POLICY:
 322                         e->object.object_sid = o->object_identifier.sid;
 323                         e->flags = NETR_CHANGELOG_SID_INCLUDED;
 324                         break;
 325                 default:
 326                         break;
 327         }
 328 }
 329 
 330 /**
 331  * libnet_samsync_delta
 332  */
 333 
 334 static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 335                                      enum netr_SamDatabaseID database_id,
 336                                      uint64_t *sequence_num,
 337                                      struct samsync_context *ctx,
 338                                      struct netr_ChangeLogEntry *e)
 339 {
 340         NTSTATUS result;
 341         NTSTATUS callback_status;
 342         const char *logon_server = ctx->cli->desthost;
 343         const char *computername = global_myname();
 344         struct netr_Authenticator credential;
 345         struct netr_Authenticator return_authenticator;
 346         uint16_t restart_state = 0;
 347         uint32_t sync_context = 0;
 348         DATA_BLOB session_key;
 349 
 350         ZERO_STRUCT(return_authenticator);
 351 
 352         do {
 353                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
 354 
 355                 netlogon_creds_client_step(ctx->cli->dc, &credential);
 356 
 357                 if (ctx->single_object_replication &&
 358                     !ctx->force_full_replication) {
 359                         result = rpccli_netr_DatabaseRedo(ctx->cli, mem_ctx,
 360                                                           logon_server,
 361                                                           computername,
 362                                                           &credential,
 363                                                           &return_authenticator,
 364                                                           *e,
 365                                                           0,
 366                                                           &delta_enum_array);
 367                 } else if (!ctx->force_full_replication &&
 368                            sequence_num && (*sequence_num > 0)) {
 369                         result = rpccli_netr_DatabaseDeltas(ctx->cli, mem_ctx,
 370                                                             logon_server,
 371                                                             computername,
 372                                                             &credential,
 373                                                             &return_authenticator,
 374                                                             database_id,
 375                                                             sequence_num,
 376                                                             &delta_enum_array,
 377                                                             0xffff);
 378                 } else {
 379                         result = rpccli_netr_DatabaseSync2(ctx->cli, mem_ctx,
 380                                                            logon_server,
 381                                                            computername,
 382                                                            &credential,
 383                                                            &return_authenticator,
 384                                                            database_id,
 385                                                            restart_state,
 386                                                            &sync_context,
 387                                                            &delta_enum_array,
 388                                                            0xffff);
 389                 }
 390 
 391                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) {
 392                         return result;
 393                 }
 394 
 395                 /* Check returned credentials. */
 396                 if (!netlogon_creds_client_check(ctx->cli->dc,
 397                                                  &return_authenticator.cred)) {
 398                         DEBUG(0,("credentials chain check failed\n"));
 399                         return NT_STATUS_ACCESS_DENIED;
 400                 }
 401 
 402                 if (NT_STATUS_IS_ERR(result)) {
 403                         break;
 404                 }
 405 
 406                 session_key = data_blob_const(ctx->cli->dc->sess_key, 16);
 407 
 408                 samsync_fix_delta_array(mem_ctx,
 409                                         &session_key,
 410                                         database_id,
 411                                         delta_enum_array);
 412 
 413                 /* Process results */
 414                 callback_status = ctx->ops->process_objects(mem_ctx, database_id,
 415                                                             delta_enum_array,
 416                                                             sequence_num,
 417                                                             ctx);
 418                 if (!NT_STATUS_IS_OK(callback_status)) {
 419                         result = callback_status;
 420                         goto out;
 421                 }
 422 
 423                 TALLOC_FREE(delta_enum_array);
 424 
 425         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 426 
 427  out:
 428 
 429         return result;
 430 }
 431 
 432 /**
 433  * libnet_samsync
 434  */
 435 
 436 NTSTATUS libnet_samsync(enum netr_SamDatabaseID database_id,
     /* [<][>][^][v][top][bottom][index][help] */
 437                         struct samsync_context *ctx)
 438 {
 439         NTSTATUS status = NT_STATUS_OK;
 440         NTSTATUS callback_status;
 441         TALLOC_CTX *mem_ctx;
 442         const char *debug_str;
 443         uint64_t sequence_num = 0;
 444         int i = 0;
 445 
 446         if (!(mem_ctx = talloc_new(ctx))) {
 447                 return NT_STATUS_NO_MEMORY;
 448         }
 449 
 450         if (!ctx->ops) {
 451                 return NT_STATUS_INVALID_PARAMETER;
 452         }
 453 
 454         if (ctx->ops->startup) {
 455                 status = ctx->ops->startup(mem_ctx, ctx,
 456                                            database_id, &sequence_num);
 457                 if (!NT_STATUS_IS_OK(status)) {
 458                         goto done;
 459                 }
 460         }
 461 
 462         debug_str = samsync_debug_str(mem_ctx, ctx->mode, database_id);
 463         if (debug_str) {
 464                 d_fprintf(stderr, "%s\n", debug_str);
 465         }
 466 
 467         if (!ctx->single_object_replication) {
 468                 status = libnet_samsync_delta(mem_ctx, database_id,
 469                                               &sequence_num, ctx, NULL);
 470                 goto done;
 471         }
 472 
 473         for (i=0; i<ctx->num_objects; i++) {
 474 
 475                 struct netr_ChangeLogEntry e;
 476 
 477                 if (ctx->objects[i].database_id != database_id) {
 478                         continue;
 479                 }
 480 
 481                 libnet_init_netr_ChangeLogEntry(&ctx->objects[i], &e);
 482 
 483                 status = libnet_samsync_delta(mem_ctx, database_id,
 484                                               &sequence_num, ctx, &e);
 485                 if (!NT_STATUS_IS_OK(status)) {
 486                         goto done;
 487                 }
 488         }
 489 
 490  done:
 491 
 492         if (NT_STATUS_IS_OK(status) && ctx->ops->finish) {
 493                 callback_status = ctx->ops->finish(mem_ctx, ctx,
 494                                                    database_id, sequence_num);
 495                 if (!NT_STATUS_IS_OK(callback_status)) {
 496                         status = callback_status;
 497                 }
 498         }
 499 
 500         if (NT_STATUS_IS_ERR(status) && !ctx->error_message) {
 501 
 502                 ctx->error_message = talloc_asprintf(ctx,
 503                         "Failed to fetch %s database: %s",
 504                         samsync_database_str(database_id),
 505                         nt_errstr(status));
 506 
 507                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
 508 
 509                         ctx->error_message =
 510                                 talloc_asprintf_append(ctx->error_message,
 511                                         "\nPerhaps %s is a Windows native mode domain?",
 512                                         ctx->domain_name);
 513                 }
 514         }
 515 
 516         talloc_destroy(mem_ctx);
 517 
 518         return status;
 519 }
 520 
 521 /**
 522  * pull_netr_AcctLockStr
 523  */
 524 
 525 NTSTATUS pull_netr_AcctLockStr(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 526                                struct lsa_BinaryString *r,
 527                                struct netr_AcctLockStr **str_p)
 528 {
 529         struct netr_AcctLockStr *str;
 530         enum ndr_err_code ndr_err;
 531         DATA_BLOB blob;
 532 
 533         if (!mem_ctx || !r || !str_p) {
 534                 return NT_STATUS_INVALID_PARAMETER;
 535         }
 536 
 537         *str_p = NULL;
 538 
 539         str = TALLOC_ZERO_P(mem_ctx, struct netr_AcctLockStr);
 540         if (!str) {
 541                 return NT_STATUS_NO_MEMORY;
 542         }
 543 
 544         blob = data_blob_const(r->array, r->length);
 545 
 546         ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, NULL, str,
 547                        (ndr_pull_flags_fn_t)ndr_pull_netr_AcctLockStr);
 548 
 549         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 550                 return ndr_map_error2ntstatus(ndr_err);
 551         }
 552 
 553         *str_p = str;
 554 
 555         return NT_STATUS_OK;
 556 }
 557 

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