root/source3/libnet/libnet_dssync_keytab.c

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

DEFINITIONS

This source file includes following definitions.
  1. keytab_startup
  2. keytab_finish
  3. parse_supplemental_credentials
  4. parse_object
  5. dn_is_in_object_list
  6. keytab_process_objects
  7. keytab_startup
  8. keytab_finish
  9. keytab_process_objects

   1 /*
   2    Unix SMB/CIFS implementation.
   3 
   4    Copyright (C) Guenther Deschner <gd@samba.org> 2008
   5    Copyright (C) Michael Adam 2008
   6 
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11 
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16 
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 #include "libnet/libnet.h"
  23 #include "librpc/gen_ndr/ndr_drsblobs.h"
  24 
  25 #if defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC)
  26 
  27 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  28                                struct replUpToDateVectorBlob **pold_utdv)
  29 {
  30         krb5_error_code ret = 0;
  31         struct libnet_keytab_context *keytab_ctx;
  32         struct libnet_keytab_entry *entry;
  33         struct replUpToDateVectorBlob *old_utdv = NULL;
  34         char *principal;
  35 
  36         ret = libnet_keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
  37         if (ret) {
  38                 return krb5_to_nt_status(ret);
  39         }
  40 
  41         keytab_ctx->dns_domain_name = ctx->dns_domain_name;
  42         keytab_ctx->clean_old_entries = ctx->clean_old_entries;
  43         ctx->private_data = keytab_ctx;
  44 
  45         principal = talloc_asprintf(mem_ctx, "UTDV/%s@%s",
  46                                     ctx->nc_dn, ctx->dns_domain_name);
  47         NT_STATUS_HAVE_NO_MEMORY(principal);
  48 
  49         entry = libnet_keytab_search(keytab_ctx, principal, 0, ENCTYPE_NULL,
  50                                      mem_ctx);
  51         if (entry) {
  52                 enum ndr_err_code ndr_err;
  53                 old_utdv = talloc(mem_ctx, struct replUpToDateVectorBlob);
  54 
  55                 ndr_err = ndr_pull_struct_blob(&entry->password, old_utdv,
  56                                 NULL, old_utdv,
  57                                 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
  58                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  59                         NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
  60                         ctx->error_message = talloc_asprintf(ctx,
  61                                         "Failed to pull UpToDateVector: %s",
  62                                         nt_errstr(status));
  63                         return status;
  64                 }
  65 
  66                 if (DEBUGLEVEL >= 10) {
  67                         NDR_PRINT_DEBUG(replUpToDateVectorBlob, old_utdv);
  68                 }
  69         }
  70 
  71         if (pold_utdv) {
  72                 *pold_utdv = old_utdv;
  73         }
  74 
  75         return NT_STATUS_OK;
  76 }
  77 
  78 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  79                               struct replUpToDateVectorBlob *new_utdv)
  80 {
  81         NTSTATUS status = NT_STATUS_OK;
  82         krb5_error_code ret = 0;
  83         struct libnet_keytab_context *keytab_ctx =
  84                 (struct libnet_keytab_context *)ctx->private_data;
  85 
  86         if (new_utdv) {
  87                 enum ndr_err_code ndr_err;
  88                 DATA_BLOB blob;
  89 
  90                 if (DEBUGLEVEL >= 10) {
  91                         NDR_PRINT_DEBUG(replUpToDateVectorBlob, new_utdv);
  92                 }
  93 
  94                 ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, new_utdv,
  95                                 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
  96                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
  97                         status = ndr_map_error2ntstatus(ndr_err);
  98                         ctx->error_message = talloc_asprintf(ctx,
  99                                         "Failed to push UpToDateVector: %s",
 100                                         nt_errstr(status));
 101                         goto done;
 102                 }
 103 
 104                 status = libnet_keytab_add_to_keytab_entries(mem_ctx, keytab_ctx, 0,
 105                                                              ctx->nc_dn, "UTDV",
 106                                                              ENCTYPE_NULL,
 107                                                              blob);
 108                 if (!NT_STATUS_IS_OK(status)) {
 109                         goto done;
 110                 }
 111         }
 112 
 113         ret = libnet_keytab_add(keytab_ctx);
 114         if (ret) {
 115                 status = krb5_to_nt_status(ret);
 116                 ctx->error_message = talloc_asprintf(ctx,
 117                         "Failed to add entries to keytab %s: %s",
 118                         keytab_ctx->keytab_name, error_message(ret));
 119                 goto done;
 120         }
 121 
 122         ctx->result_message = talloc_asprintf(ctx,
 123                 "Vampired %d accounts to keytab %s",
 124                 keytab_ctx->count,
 125                 keytab_ctx->keytab_name);
 126 
 127 done:
 128         TALLOC_FREE(keytab_ctx);
 129         return status;
 130 }
 131 
 132 /****************************************************************
 133 ****************************************************************/
 134 
 135 static  NTSTATUS parse_supplemental_credentials(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 136                         const DATA_BLOB *blob,
 137                         struct package_PrimaryKerberosCtr3 **pkb3,
 138                         struct package_PrimaryKerberosCtr4 **pkb4)
 139 {
 140         NTSTATUS status;
 141         enum ndr_err_code ndr_err;
 142         struct supplementalCredentialsBlob scb;
 143         struct supplementalCredentialsPackage *scpk = NULL;
 144         DATA_BLOB scpk_blob;
 145         struct package_PrimaryKerberosBlob *pkb;
 146         bool newer_keys = false;
 147         uint32_t j;
 148 
 149         ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, NULL, &scb,
 150                         (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
 151         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 152                 status = ndr_map_error2ntstatus(ndr_err);
 153                 goto done;
 154         }
 155         if (scb.sub.signature !=
 156             SUPPLEMENTAL_CREDENTIALS_SIGNATURE)
 157         {
 158                 if (DEBUGLEVEL >= 10) {
 159                         NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
 160                 }
 161                 status = NT_STATUS_INVALID_PARAMETER;
 162                 goto done;
 163         }
 164         for (j=0; j < scb.sub.num_packages; j++) {
 165                 if (strcmp("Primary:Kerberos-Newer-Keys",
 166                     scb.sub.packages[j].name) == 0)
 167                 {
 168                         scpk = &scb.sub.packages[j];
 169                         if (!scpk->data || !scpk->data[0]) {
 170                                 scpk = NULL;
 171                                 continue;
 172                         }
 173                         newer_keys = true;
 174                         break;
 175                 } else  if (strcmp("Primary:Kerberos",
 176                                    scb.sub.packages[j].name) == 0)
 177                 {
 178                         /*
 179                          * grab this but don't break here:
 180                          * there might still be newer-keys ...
 181                          */
 182                         scpk = &scb.sub.packages[j];
 183                         if (!scpk->data || !scpk->data[0]) {
 184                                 scpk = NULL;
 185                         }
 186                 }
 187         }
 188 
 189         if (!scpk) {
 190                 /* no data */
 191                 status = NT_STATUS_OK;
 192                 goto done;
 193         }
 194 
 195         scpk_blob = strhex_to_data_blob(mem_ctx, scpk->data);
 196         if (!scpk_blob.data) {
 197                 status = NT_STATUS_NO_MEMORY;
 198                 goto done;
 199         }
 200 
 201         pkb = TALLOC_ZERO_P(mem_ctx, struct package_PrimaryKerberosBlob);
 202         if (!pkb) {
 203                 status = NT_STATUS_NO_MEMORY;
 204                 goto done;
 205         }
 206         ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, NULL, pkb,
 207                         (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
 208         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 209                 status = ndr_map_error2ntstatus(ndr_err);
 210                 goto done;
 211         }
 212 
 213         if (!newer_keys && pkb->version != 3) {
 214                 status = NT_STATUS_INVALID_PARAMETER;
 215                 goto done;
 216         }
 217 
 218         if (newer_keys && pkb->version != 4) {
 219                 status = NT_STATUS_INVALID_PARAMETER;
 220                 goto done;
 221         }
 222 
 223         if (pkb->version == 4 && pkb4) {
 224                 *pkb4 = &pkb->ctr.ctr4;
 225         } else if (pkb->version == 3 && pkb3) {
 226                 *pkb3 = &pkb->ctr.ctr3;
 227         }
 228 
 229         status = NT_STATUS_OK;
 230 
 231 done:
 232         return status;
 233 }
 234 
 235 static NTSTATUS parse_object(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 236                              struct libnet_keytab_context *ctx,
 237                              struct drsuapi_DsReplicaObjectListItemEx *cur)
 238 {
 239         NTSTATUS status = NT_STATUS_OK;
 240         uchar nt_passwd[16];
 241         DATA_BLOB *blob;
 242         int i = 0;
 243         struct drsuapi_DsReplicaAttribute *attr;
 244         bool got_pwd = false;
 245 
 246         struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
 247         struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
 248 
 249         char *object_dn = NULL;
 250         char *upn = NULL;
 251         char **spn = NULL;
 252         uint32_t num_spns = 0;
 253         char *name = NULL;
 254         uint32_t kvno = 0;
 255         uint32_t uacc = 0;
 256         uint32_t sam_type = 0;
 257 
 258         uint32_t pwd_history_len = 0;
 259         uint8_t *pwd_history = NULL;
 260 
 261         ZERO_STRUCT(nt_passwd);
 262 
 263         object_dn = talloc_strdup(mem_ctx, cur->object.identifier->dn);
 264         if (!object_dn) {
 265                 return NT_STATUS_NO_MEMORY;
 266         }
 267 
 268         DEBUG(3, ("parsing object '%s'\n", object_dn));
 269 
 270         for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
 271 
 272                 attr = &cur->object.attribute_ctr.attributes[i];
 273 
 274                 if (attr->attid == DRSUAPI_ATTRIBUTE_servicePrincipalName) {
 275                         uint32_t count;
 276                         num_spns = attr->value_ctr.num_values;
 277                         spn = TALLOC_ARRAY(mem_ctx, char *, num_spns);
 278                         for (count = 0; count < num_spns; count++) {
 279                                 blob = attr->value_ctr.values[count].blob;
 280                                 pull_string_talloc(spn, NULL, 0,
 281                                                    &spn[count],
 282                                                    blob->data, blob->length,
 283                                                    STR_UNICODE);
 284                         }
 285                 }
 286 
 287                 if (attr->value_ctr.num_values != 1) {
 288                         continue;
 289                 }
 290 
 291                 if (!attr->value_ctr.values[0].blob) {
 292                         continue;
 293                 }
 294 
 295                 blob = attr->value_ctr.values[0].blob;
 296 
 297                 switch (attr->attid) {
 298                         case DRSUAPI_ATTRIBUTE_unicodePwd:
 299 
 300                                 if (blob->length != 16) {
 301                                         break;
 302                                 }
 303 
 304                                 memcpy(&nt_passwd, blob->data, 16);
 305                                 got_pwd = true;
 306 
 307                                 /* pick the kvno from the meta_data version,
 308                                  * thanks, metze, for explaining this */
 309 
 310                                 if (!cur->meta_data_ctr) {
 311                                         break;
 312                                 }
 313                                 if (cur->meta_data_ctr->count !=
 314                                     cur->object.attribute_ctr.num_attributes) {
 315                                         break;
 316                                 }
 317                                 kvno = cur->meta_data_ctr->meta_data[i].version;
 318                                 break;
 319                         case DRSUAPI_ATTRIBUTE_ntPwdHistory:
 320                                 pwd_history_len = blob->length / 16;
 321                                 pwd_history = blob->data;
 322                                 break;
 323                         case DRSUAPI_ATTRIBUTE_userPrincipalName:
 324                                 pull_string_talloc(mem_ctx, NULL, 0, &upn,
 325                                                    blob->data, blob->length,
 326                                                    STR_UNICODE);
 327                                 break;
 328                         case DRSUAPI_ATTRIBUTE_sAMAccountName:
 329                                 pull_string_talloc(mem_ctx, NULL, 0, &name,
 330                                                    blob->data, blob->length,
 331                                                    STR_UNICODE);
 332                                 break;
 333                         case DRSUAPI_ATTRIBUTE_sAMAccountType:
 334                                 sam_type = IVAL(blob->data, 0);
 335                                 break;
 336                         case DRSUAPI_ATTRIBUTE_userAccountControl:
 337                                 uacc = IVAL(blob->data, 0);
 338                                 break;
 339                         case DRSUAPI_ATTRIBUTE_supplementalCredentials:
 340                                 status = parse_supplemental_credentials(mem_ctx,
 341                                                                         blob,
 342                                                                         &pkb3,
 343                                                                         &pkb4);
 344                                 if (!NT_STATUS_IS_OK(status)) {
 345                                         DEBUG(2, ("parsing of supplemental "
 346                                                   "credentials failed: %s\n",
 347                                                   nt_errstr(status)));
 348                                 }
 349                                 break;
 350                         default:
 351                                 break;
 352                 }
 353         }
 354 
 355         if (!got_pwd) {
 356                 DEBUG(10, ("no password (unicodePwd) found - skipping.\n"));
 357                 return NT_STATUS_OK;
 358         }
 359 
 360         if (name) {
 361                 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, 0, object_dn,
 362                                                              "SAMACCOUNTNAME",
 363                                                              ENCTYPE_NULL,
 364                                                              data_blob_talloc(mem_ctx, name,
 365                                                              strlen(name) + 1));
 366                 if (!NT_STATUS_IS_OK(status)) {
 367                         return status;
 368                 }
 369         } else {
 370                 /* look into keytab ... */
 371                 struct libnet_keytab_entry *entry = NULL;
 372                 char *principal = NULL;
 373 
 374                 DEBUG(10, ("looking for SAMACCOUNTNAME/%s@%s in keytayb...\n",
 375                            object_dn, ctx->dns_domain_name));
 376 
 377                 principal = talloc_asprintf(mem_ctx, "%s/%s@%s",
 378                                             "SAMACCOUNTNAME",
 379                                             object_dn,
 380                                             ctx->dns_domain_name);
 381                 if (!principal) {
 382                         DEBUG(1, ("talloc failed\n"));
 383                         return NT_STATUS_NO_MEMORY;
 384                 }
 385                 entry = libnet_keytab_search(ctx, principal, 0, ENCTYPE_NULL,
 386                                              mem_ctx);
 387                 if (entry) {
 388                         name = (char *)TALLOC_MEMDUP(mem_ctx,
 389                                                      entry->password.data,
 390                                                      entry->password.length);
 391                         if (!name) {
 392                                 DEBUG(1, ("talloc failed!"));
 393                                 return NT_STATUS_NO_MEMORY;
 394                         } else {
 395                                 DEBUG(10, ("found name %s\n", name));
 396                         }
 397                         TALLOC_FREE(entry);
 398                 } else {
 399                         DEBUG(10, ("entry not found\n"));
 400                 }
 401                 TALLOC_FREE(principal);
 402         }
 403 
 404         if (!name) {
 405                 DEBUG(10, ("no name (sAMAccountName) found - skipping.\n"));
 406                 return NT_STATUS_OK;
 407         }
 408 
 409         DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno));
 410         DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x",
 411                 sam_type, uacc));
 412         if (upn) {
 413                 DEBUGADD(1,(", upn: %s", upn));
 414         }
 415         if (num_spns > 0) {
 416                 DEBUGADD(1, (", spns: ["));
 417                 for (i = 0; i < num_spns; i++) {
 418                         DEBUGADD(1, ("%s%s", spn[i],
 419                                      (i+1 == num_spns)?"]":", "));
 420                 }
 421         }
 422         DEBUGADD(1,("\n"));
 423 
 424         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL,
 425                                                      ENCTYPE_ARCFOUR_HMAC,
 426                                                      data_blob_talloc(mem_ctx, nt_passwd, 16));
 427 
 428         if (!NT_STATUS_IS_OK(status)) {
 429                 return status;
 430         }
 431 
 432         /* add kerberos keys (if any) */
 433 
 434         if (pkb4) {
 435                 for (i=0; i < pkb4->num_keys; i++) {
 436                         if (!pkb4->keys[i].value) {
 437                                 continue;
 438                         }
 439                         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno,
 440                                                                      name,
 441                                                                      NULL,
 442                                                                      pkb4->keys[i].keytype,
 443                                                                      *pkb4->keys[i].value);
 444                         if (!NT_STATUS_IS_OK(status)) {
 445                                 return status;
 446                         }
 447                 }
 448                 for (i=0; i < pkb4->num_old_keys; i++) {
 449                         if (!pkb4->old_keys[i].value) {
 450                                 continue;
 451                         }
 452                         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
 453                                                                      name,
 454                                                                      NULL,
 455                                                                      pkb4->old_keys[i].keytype,
 456                                                                      *pkb4->old_keys[i].value);
 457                         if (!NT_STATUS_IS_OK(status)) {
 458                                 return status;
 459                         }
 460                 }
 461                 for (i=0; i < pkb4->num_older_keys; i++) {
 462                         if (!pkb4->older_keys[i].value) {
 463                                 continue;
 464                         }
 465                         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 2,
 466                                                                      name,
 467                                                                      NULL,
 468                                                                      pkb4->older_keys[i].keytype,
 469                                                                      *pkb4->older_keys[i].value);
 470                         if (!NT_STATUS_IS_OK(status)) {
 471                                 return status;
 472                         }
 473                 }
 474         }
 475 
 476         if (pkb3) {
 477                 for (i=0; i < pkb3->num_keys; i++) {
 478                         if (!pkb3->keys[i].value) {
 479                                 continue;
 480                         }
 481                         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name,
 482                                                                      NULL,
 483                                                                      pkb3->keys[i].keytype,
 484                                                                      *pkb3->keys[i].value);
 485                         if (!NT_STATUS_IS_OK(status)) {
 486                                 return status;
 487                         }
 488                 }
 489                 for (i=0; i < pkb3->num_old_keys; i++) {
 490                         if (!pkb3->old_keys[i].value) {
 491                                 continue;
 492                         }
 493                         status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
 494                                                                      name,
 495                                                                      NULL,
 496                                                                      pkb3->old_keys[i].keytype,
 497                                                                      *pkb3->old_keys[i].value);
 498                         if (!NT_STATUS_IS_OK(status)) {
 499                                 return status;
 500                         }
 501                 }
 502         }
 503 
 504         if ((kvno < 0) && (kvno < pwd_history_len)) {
 505                 return status;
 506         }
 507 
 508         /* add password history */
 509 
 510         /* skip first entry */
 511         if (got_pwd) {
 512                 kvno--;
 513                 i = 1;
 514         } else {
 515                 i = 0;
 516         }
 517 
 518         for (; i<pwd_history_len; i++) {
 519                 status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno--, name, NULL,
 520                                                              ENCTYPE_ARCFOUR_HMAC,
 521                                                              data_blob_talloc(mem_ctx, &pwd_history[i*16], 16));
 522                 if (!NT_STATUS_IS_OK(status)) {
 523                         break;
 524                 }
 525         }
 526 
 527         return status;
 528 }
 529 
 530 static bool dn_is_in_object_list(struct dssync_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 531                                  const char *dn)
 532 {
 533         uint32_t count;
 534 
 535         if (ctx->object_count == 0) {
 536                 return true;
 537         }
 538 
 539         for (count = 0; count < ctx->object_count; count++) {
 540                 if (strequal(ctx->object_dns[count], dn)) {
 541                         return true;
 542                 }
 543         }
 544 
 545         return false;
 546 }
 547 
 548 /****************************************************************
 549 ****************************************************************/
 550 
 551 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 552                                        TALLOC_CTX *mem_ctx,
 553                                        struct drsuapi_DsReplicaObjectListItemEx *cur,
 554                                        struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
 555 {
 556         NTSTATUS status = NT_STATUS_OK;
 557         struct libnet_keytab_context *keytab_ctx =
 558                 (struct libnet_keytab_context *)ctx->private_data;
 559 
 560         for (; cur; cur = cur->next_object) {
 561                 /*
 562                  * When not in single object replication mode,
 563                  * the object_dn list is used as a positive write filter.
 564                  */
 565                 if (!ctx->single_object_replication &&
 566                     !dn_is_in_object_list(ctx, cur->object.identifier->dn))
 567                 {
 568                         continue;
 569                 }
 570 
 571                 status = parse_object(mem_ctx, keytab_ctx, cur);
 572                 if (!NT_STATUS_IS_OK(status)) {
 573                         goto out;
 574                 }
 575         }
 576 
 577  out:
 578         return status;
 579 }
 580 
 581 #else
 582 
 583 static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 584                                struct replUpToDateVectorBlob **pold_utdv)
 585 {
 586         return NT_STATUS_NOT_SUPPORTED;
 587 }
 588 
 589 static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 590                               struct replUpToDateVectorBlob *new_utdv)
 591 {
 592         return NT_STATUS_NOT_SUPPORTED;
 593 }
 594 
 595 static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 596                                        TALLOC_CTX *mem_ctx,
 597                                        struct drsuapi_DsReplicaObjectListItemEx *cur,
 598                                        struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
 599 {
 600         return NT_STATUS_NOT_SUPPORTED;
 601 }
 602 #endif /* defined(HAVE_ADS) && defined(ENCTYPE_ARCFOUR_HMAC) */
 603 
 604 const struct dssync_ops libnet_dssync_keytab_ops = {
 605         .startup                = keytab_startup,
 606         .process_objects        = keytab_process_objects,
 607         .finish                 = keytab_finish,
 608 };

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