Changeset 740 for vendor/current/source4/kdc
- Timestamp:
- Nov 14, 2012, 12:59:34 PM (13 years ago)
- Location:
- vendor/current/source4/kdc
- Files:
-
- 11 added
- 4 deleted
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source4/kdc/hdb-samba4.c
r414 r740 34 34 35 35 #include "includes.h" 36 #include "system/time.h" 37 #include "../libds/common/flags.h" 38 #include "lib/ldb/include/ldb.h" 39 #include "lib/ldb/include/ldb_errors.h" 40 #include "librpc/gen_ndr/netlogon.h" 41 #include "libcli/security/security.h" 42 #include "auth/auth.h" 43 #include "auth/credentials/credentials.h" 44 #include "auth/auth_sam.h" 45 #include "../lib/util/util_ldb.h" 46 #include "dsdb/samdb/samdb.h" 47 #include "librpc/ndr/libndr.h" 48 #include "librpc/gen_ndr/ndr_drsblobs.h" 49 #include "librpc/gen_ndr/lsa.h" 50 #include "libcli/auth/libcli_auth.h" 51 #include "param/param.h" 52 #include "events/events.h" 53 #include "kdc/kdc.h" 54 #include "../lib/crypto/md4.h" 55 56 enum hdb_samba4_ent_type 57 { HDB_SAMBA4_ENT_TYPE_CLIENT, HDB_SAMBA4_ENT_TYPE_SERVER, 58 HDB_SAMBA4_ENT_TYPE_KRBTGT, HDB_SAMBA4_ENT_TYPE_TRUST, HDB_SAMBA4_ENT_TYPE_ANY }; 59 60 enum trust_direction { 61 UNKNOWN = 0, 62 INBOUND = LSA_TRUST_DIRECTION_INBOUND, 63 OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND 64 }; 65 66 static const char *trust_attrs[] = { 67 "trustPartner", 68 "trustAuthIncoming", 69 "trustAuthOutgoing", 70 "whenCreated", 71 "msDS-SupportedEncryptionTypes", 72 "trustAttributes", 73 "trustDirection", 74 "trustType", 75 NULL 76 }; 77 78 static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val) 79 { 80 const char *tmp; 81 const char *gentime; 82 struct tm tm; 83 84 gentime = ldb_msg_find_attr_as_string(msg, attr, NULL); 85 if (!gentime) 86 return default_val; 87 88 tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm); 89 if (tmp == NULL) { 90 return default_val; 91 } 92 93 return timegm(&tm); 94 } 95 96 static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum hdb_samba4_ent_type ent_type) 97 { 98 HDBFlags flags = int2HDBFlags(0); 99 100 /* we don't allow kadmin deletes */ 101 flags.immutable = 1; 102 103 /* mark the principal as invalid to start with */ 104 flags.invalid = 1; 105 106 flags.renewable = 1; 107 108 /* All accounts are servers, but this may be disabled again in the caller */ 109 flags.server = 1; 110 111 /* Account types - clear the invalid bit if it turns out to be valid */ 112 if (userAccountControl & UF_NORMAL_ACCOUNT) { 113 if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) { 114 flags.client = 1; 115 } 116 flags.invalid = 0; 117 } 118 119 if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) { 120 if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) { 121 flags.client = 1; 122 } 123 flags.invalid = 0; 124 } 125 if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) { 126 if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) { 127 flags.client = 1; 128 } 129 flags.invalid = 0; 130 } 131 if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) { 132 if (ent_type == HDB_SAMBA4_ENT_TYPE_CLIENT || ent_type == HDB_SAMBA4_ENT_TYPE_ANY) { 133 flags.client = 1; 134 } 135 flags.invalid = 0; 136 } 137 138 /* Not permitted to act as a client if disabled */ 139 if (userAccountControl & UF_ACCOUNTDISABLE) { 140 flags.client = 0; 141 } 142 if (userAccountControl & UF_LOCKOUT) { 143 flags.invalid = 1; 144 } 145 /* 146 if (userAccountControl & UF_PASSWORD_NOTREQD) { 147 flags.invalid = 1; 148 } 149 */ 150 /* 151 UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent 152 */ 153 if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) { 154 flags.invalid = 1; 155 } 156 157 /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in hdb_samba4_message2entry() */ 158 159 /* 160 if (userAccountControl & UF_MNS_LOGON_ACCOUNT) { 161 flags.invalid = 1; 162 } 163 */ 164 if (userAccountControl & UF_SMARTCARD_REQUIRED) { 165 flags.require_hwauth = 1; 166 } 167 if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) { 168 flags.ok_as_delegate = 1; 169 } 170 if (!(userAccountControl & UF_NOT_DELEGATED)) { 171 flags.forwardable = 1; 172 flags.proxiable = 1; 173 } 174 175 if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) { 176 flags.require_preauth = 0; 177 } else { 178 flags.require_preauth = 1; 179 180 } 181 return flags; 182 } 183 184 static int hdb_samba4_destructor(struct hdb_samba4_private *p) 185 { 186 hdb_entry_ex *entry_ex = p->entry_ex; 187 free_hdb_entry(&entry_ex->entry); 188 return 0; 189 } 190 191 static void hdb_samba4_free_entry(krb5_context context, hdb_entry_ex *entry_ex) 192 { 193 talloc_free(entry_ex->ctx); 194 } 195 196 static krb5_error_code hdb_samba4_message2entry_keys(krb5_context context, 197 struct smb_iconv_convenience *iconv_convenience, 198 TALLOC_CTX *mem_ctx, 199 struct ldb_message *msg, 200 unsigned int userAccountControl, 201 hdb_entry_ex *entry_ex) 202 { 203 krb5_error_code ret = 0; 204 enum ndr_err_code ndr_err; 205 struct samr_Password *hash; 206 const struct ldb_val *sc_val; 207 struct supplementalCredentialsBlob scb; 208 struct supplementalCredentialsPackage *scpk = NULL; 209 bool newer_keys = false; 210 struct package_PrimaryKerberosBlob _pkb; 211 struct package_PrimaryKerberosCtr3 *pkb3 = NULL; 212 struct package_PrimaryKerberosCtr4 *pkb4 = NULL; 213 uint32_t i; 214 uint32_t allocated_keys = 0; 215 216 entry_ex->entry.keys.val = NULL; 217 entry_ex->entry.keys.len = 0; 218 219 entry_ex->entry.kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0); 220 221 /* Get keys from the db */ 222 223 hash = samdb_result_hash(mem_ctx, msg, "unicodePwd"); 224 sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials"); 225 226 /* unicodePwd for enctype 0x17 (23) if present */ 227 if (hash) { 228 allocated_keys++; 229 } 230 231 /* supplementalCredentials if present */ 232 if (sc_val) { 233 ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, iconv_convenience, &scb, 234 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob); 235 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 236 dump_data(0, sc_val->data, sc_val->length); 237 ret = EINVAL; 238 goto out; 239 } 240 241 if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) { 242 NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb); 243 ret = EINVAL; 244 goto out; 245 } 246 247 for (i=0; i < scb.sub.num_packages; i++) { 248 if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) { 249 scpk = &scb.sub.packages[i]; 250 if (!scpk->data || !scpk->data[0]) { 251 scpk = NULL; 252 continue; 253 } 254 newer_keys = true; 255 break; 256 } else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) { 257 scpk = &scb.sub.packages[i]; 258 if (!scpk->data || !scpk->data[0]) { 259 scpk = NULL; 260 } 261 /* 262 * we don't break here in hope to find 263 * a Kerberos-Newer-Keys package 264 */ 265 } 266 } 267 } 268 /* 269 * Primary:Kerberos-Newer-Keys or Primary:Kerberos element 270 * of supplementalCredentials 271 */ 272 if (scpk) { 273 DATA_BLOB blob; 274 275 blob = strhex_to_data_blob(mem_ctx, scpk->data); 276 if (!blob.data) { 277 ret = ENOMEM; 278 goto out; 279 } 280 281 /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */ 282 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, iconv_convenience, &_pkb, 283 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob); 284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 285 ret = EINVAL; 286 krb5_set_error_message(context, ret, "hdb_samba4_message2entry_keys: could not parse package_PrimaryKerberosBlob"); 287 krb5_warnx(context, "hdb_samba4_message2entry_keys: could not parse package_PrimaryKerberosBlob"); 288 goto out; 289 } 290 291 if (newer_keys && _pkb.version != 4) { 292 ret = EINVAL; 293 krb5_set_error_message(context, ret, "hdb_samba4_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4"); 294 krb5_warnx(context, "hdb_samba4_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4"); 295 goto out; 296 } 297 298 if (!newer_keys && _pkb.version != 3) { 299 ret = EINVAL; 300 krb5_set_error_message(context, ret, "hdb_samba4_message2entry_keys: could not parse Primary:Kerberos not version 3"); 301 krb5_warnx(context, "hdb_samba4_message2entry_keys: could not parse Primary:Kerberos not version 3"); 302 goto out; 303 } 304 305 if (_pkb.version == 4) { 306 pkb4 = &_pkb.ctr.ctr4; 307 allocated_keys += pkb4->num_keys; 308 } else if (_pkb.version == 3) { 309 pkb3 = &_pkb.ctr.ctr3; 310 allocated_keys += pkb3->num_keys; 311 } 312 } 313 314 if (allocated_keys == 0) { 315 /* oh, no password. Apparently (comment in 316 * hdb-ldap.c) this violates the ASN.1, but this 317 * allows an entry with no keys (yet). */ 318 return 0; 319 } 320 321 /* allocate space to decode into */ 322 entry_ex->entry.keys.len = 0; 323 entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(Key)); 324 if (entry_ex->entry.keys.val == NULL) { 325 ret = ENOMEM; 326 goto out; 327 } 328 329 if (hash && !(userAccountControl & UF_USE_DES_KEY_ONLY)) { 330 Key key; 331 332 key.mkvno = 0; 333 key.salt = NULL; /* No salt for this enc type */ 334 335 ret = krb5_keyblock_init(context, 336 ENCTYPE_ARCFOUR_HMAC, 337 hash->hash, sizeof(hash->hash), 338 &key.key); 339 if (ret) { 340 goto out; 341 } 342 343 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; 344 entry_ex->entry.keys.len++; 345 } 346 347 if (pkb4) { 348 for (i=0; i < pkb4->num_keys; i++) { 349 bool use = true; 350 Key key; 351 352 if (!pkb4->keys[i].value) continue; 353 354 if (userAccountControl & UF_USE_DES_KEY_ONLY) { 355 switch (pkb4->keys[i].keytype) { 356 case ENCTYPE_DES_CBC_CRC: 357 case ENCTYPE_DES_CBC_MD5: 358 break; 359 default: 360 use = false; 361 break; 362 } 363 } 364 365 if (!use) continue; 366 367 key.mkvno = 0; 368 key.salt = NULL; 369 370 if (pkb4->salt.string) { 371 DATA_BLOB salt; 372 373 salt = data_blob_string_const(pkb4->salt.string); 374 375 key.salt = calloc(1, sizeof(*key.salt)); 376 if (key.salt == NULL) { 377 ret = ENOMEM; 378 goto out; 379 } 380 381 key.salt->type = hdb_pw_salt; 382 383 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length); 384 if (ret) { 385 free(key.salt); 386 key.salt = NULL; 387 goto out; 388 } 389 } 390 391 /* TODO: maybe pass the iteration_count somehow... */ 392 393 ret = krb5_keyblock_init(context, 394 pkb4->keys[i].keytype, 395 pkb4->keys[i].value->data, 396 pkb4->keys[i].value->length, 397 &key.key); 398 if (ret == KRB5_PROG_ETYPE_NOSUPP) { 399 DEBUG(2,("Unsupported keytype ignored - type %u\n", 400 pkb4->keys[i].keytype)); 401 ret = 0; 402 continue; 403 } 404 if (ret) { 405 if (key.salt) { 406 free_Salt(key.salt); 407 free(key.salt); 408 key.salt = NULL; 409 } 410 goto out; 411 } 412 413 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; 414 entry_ex->entry.keys.len++; 415 } 416 } else if (pkb3) { 417 for (i=0; i < pkb3->num_keys; i++) { 418 bool use = true; 419 Key key; 420 421 if (!pkb3->keys[i].value) continue; 422 423 if (userAccountControl & UF_USE_DES_KEY_ONLY) { 424 switch (pkb3->keys[i].keytype) { 425 case ENCTYPE_DES_CBC_CRC: 426 case ENCTYPE_DES_CBC_MD5: 427 break; 428 default: 429 use = false; 430 break; 431 } 432 } 433 434 if (!use) continue; 435 436 key.mkvno = 0; 437 key.salt = NULL; 438 439 if (pkb3->salt.string) { 440 DATA_BLOB salt; 441 442 salt = data_blob_string_const(pkb3->salt.string); 443 444 key.salt = calloc(1, sizeof(*key.salt)); 445 if (key.salt == NULL) { 446 ret = ENOMEM; 447 goto out; 448 } 449 450 key.salt->type = hdb_pw_salt; 451 452 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length); 453 if (ret) { 454 free(key.salt); 455 key.salt = NULL; 456 goto out; 457 } 458 } 459 460 ret = krb5_keyblock_init(context, 461 pkb3->keys[i].keytype, 462 pkb3->keys[i].value->data, 463 pkb3->keys[i].value->length, 464 &key.key); 465 if (ret) { 466 if (key.salt) { 467 free_Salt(key.salt); 468 free(key.salt); 469 key.salt = NULL; 470 } 471 goto out; 472 } 473 474 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; 475 entry_ex->entry.keys.len++; 476 } 477 } 478 479 out: 480 if (ret != 0) { 481 entry_ex->entry.keys.len = 0; 482 } 483 if (entry_ex->entry.keys.len == 0 && entry_ex->entry.keys.val) { 484 free(entry_ex->entry.keys.val); 485 entry_ex->entry.keys.val = NULL; 486 } 487 return ret; 488 } 489 490 /* 491 * Construct an hdb_entry from a directory entry. 492 */ 493 static krb5_error_code hdb_samba4_message2entry(krb5_context context, HDB *db, 494 struct loadparm_context *lp_ctx, 495 TALLOC_CTX *mem_ctx, krb5_const_principal principal, 496 enum hdb_samba4_ent_type ent_type, 497 struct ldb_dn *realm_dn, 498 struct ldb_message *msg, 499 hdb_entry_ex *entry_ex) 500 { 501 unsigned int userAccountControl; 502 int i; 503 krb5_error_code ret = 0; 504 krb5_boolean is_computer = FALSE; 505 char *realm = strupper_talloc(mem_ctx, lp_realm(lp_ctx)); 506 507 struct hdb_samba4_private *p; 508 NTTIME acct_expiry; 509 NTSTATUS status; 510 511 uint32_t rid; 512 struct ldb_message_element *objectclasses; 513 struct ldb_val computer_val; 514 const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); 515 computer_val.data = discard_const_p(uint8_t,"computer"); 516 computer_val.length = strlen((const char *)computer_val.data); 517 518 if (!samAccountName) { 519 ret = ENOENT; 520 krb5_set_error_message(context, ret, "hdb_samba4_message2entry: no samAccountName present"); 521 goto out; 522 } 523 524 objectclasses = ldb_msg_find_element(msg, "objectClass"); 525 526 if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) { 527 is_computer = TRUE; 528 } 529 530 memset(entry_ex, 0, sizeof(*entry_ex)); 531 532 if (!realm) { 533 ret = ENOMEM; 534 krb5_set_error_message(context, ret, "talloc_strdup: out of memory"); 535 goto out; 536 } 537 538 p = talloc(mem_ctx, struct hdb_samba4_private); 539 if (!p) { 540 ret = ENOMEM; 541 goto out; 542 } 543 544 p->entry_ex = entry_ex; 545 p->iconv_convenience = lp_iconv_convenience(lp_ctx); 546 p->lp_ctx = lp_ctx; 547 p->realm_dn = talloc_reference(p, realm_dn); 548 if (!p->realm_dn) { 549 ret = ENOMEM; 550 goto out; 551 } 552 553 talloc_set_destructor(p, hdb_samba4_destructor); 554 555 entry_ex->ctx = p; 556 entry_ex->free_entry = hdb_samba4_free_entry; 557 558 userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0); 559 560 561 entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal))); 562 if (ent_type == HDB_SAMBA4_ENT_TYPE_ANY && principal == NULL) { 563 krb5_make_principal(context, &entry_ex->entry.principal, realm, samAccountName, NULL); 564 } else { 565 ret = copy_Principal(principal, entry_ex->entry.principal); 566 if (ret) { 567 krb5_clear_error_message(context); 568 goto out; 569 } 570 571 /* While we have copied the client principal, tests 572 * show that Win2k3 returns the 'corrected' realm, not 573 * the client-specified realm. This code attempts to 574 * replace the client principal's realm with the one 575 * we determine from our records */ 576 577 /* this has to be with malloc() */ 578 krb5_principal_set_realm(context, entry_ex->entry.principal, realm); 579 } 580 581 /* First try and figure out the flags based on the userAccountControl */ 582 entry_ex->entry.flags = uf2HDBFlags(context, userAccountControl, ent_type); 583 584 /* Windows 2008 seems to enforce this (very sensible) rule by 585 * default - don't allow offline attacks on a user's password 586 * by asking for a ticket to them as a service (encrypted with 587 * their probably patheticly insecure password) */ 588 589 if (entry_ex->entry.flags.server 590 && lp_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) { 591 if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) { 592 entry_ex->entry.flags.server = 0; 593 } 594 } 595 596 { 597 /* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use 598 * of the Heimdal KDC. They are stored in a the traditional 599 * DB for audit purposes, and still form part of the structure 600 * we must return */ 601 602 /* use 'whenCreated' */ 603 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0); 604 /* use '???' */ 605 entry_ex->entry.created_by.principal = NULL; 606 607 entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event)); 608 if (entry_ex->entry.modified_by == NULL) { 609 ret = ENOMEM; 610 krb5_set_error_message(context, ret, "malloc: out of memory"); 611 goto out; 612 } 613 614 /* use 'whenChanged' */ 615 entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0); 616 /* use '???' */ 617 entry_ex->entry.modified_by->principal = NULL; 618 } 619 620 621 /* The lack of password controls etc applies to krbtgt by 622 * virtue of being that particular RID */ 623 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, msg, "objectSid"), NULL, &rid); 624 625 if (!NT_STATUS_IS_OK(status)) { 626 ret = EINVAL; 627 goto out; 628 } 629 630 if (rid == DOMAIN_RID_KRBTGT) { 631 entry_ex->entry.valid_end = NULL; 632 entry_ex->entry.pw_end = NULL; 633 634 entry_ex->entry.flags.invalid = 0; 635 entry_ex->entry.flags.server = 1; 636 637 /* Don't mark all requests for the krbtgt/realm as 638 * 'change password', as otherwise we could get into 639 * trouble, and not enforce the password expirty. 640 * Instead, only do it when request is for the kpasswd service */ 641 if (ent_type == HDB_SAMBA4_ENT_TYPE_SERVER 642 && principal->name.name_string.len == 2 643 && (strcmp(principal->name.name_string.val[0], "kadmin") == 0) 644 && (strcmp(principal->name.name_string.val[1], "changepw") == 0) 645 && lp_is_my_domain_or_realm(lp_ctx, principal->realm)) { 646 entry_ex->entry.flags.change_pw = 1; 647 } 648 entry_ex->entry.flags.client = 0; 649 entry_ex->entry.flags.forwardable = 1; 650 entry_ex->entry.flags.ok_as_delegate = 1; 651 } else if (entry_ex->entry.flags.server && ent_type == HDB_SAMBA4_ENT_TYPE_SERVER) { 652 /* The account/password expiry only applies when the account is used as a 653 * client (ie password login), not when used as a server */ 654 655 /* Make very well sure we don't use this for a client, 656 * it could bypass the password restrictions */ 657 entry_ex->entry.flags.client = 0; 658 659 entry_ex->entry.valid_end = NULL; 660 entry_ex->entry.pw_end = NULL; 661 662 } else { 663 NTTIME must_change_time 664 = samdb_result_force_password_change((struct ldb_context *)db->hdb_db, mem_ctx, 665 realm_dn, msg); 666 if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) { 667 entry_ex->entry.pw_end = NULL; 668 } else { 669 entry_ex->entry.pw_end = malloc(sizeof(*entry_ex->entry.pw_end)); 670 if (entry_ex->entry.pw_end == NULL) { 671 ret = ENOMEM; 672 goto out; 673 } 674 *entry_ex->entry.pw_end = nt_time_to_unix(must_change_time); 675 } 676 677 acct_expiry = samdb_result_account_expires(msg); 678 if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) { 679 entry_ex->entry.valid_end = NULL; 680 } else { 681 entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end)); 682 if (entry_ex->entry.valid_end == NULL) { 683 ret = ENOMEM; 684 goto out; 685 } 686 *entry_ex->entry.valid_end = nt_time_to_unix(acct_expiry); 687 } 688 } 689 690 entry_ex->entry.valid_start = NULL; 691 692 entry_ex->entry.max_life = NULL; 693 694 entry_ex->entry.max_renew = NULL; 695 696 entry_ex->entry.generation = NULL; 697 698 /* Get keys from the db */ 699 ret = hdb_samba4_message2entry_keys(context, p->iconv_convenience, p, msg, userAccountControl, entry_ex); 700 if (ret) { 701 /* Could be bougus data in the entry, or out of memory */ 702 goto out; 703 } 704 705 entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes))); 706 if (entry_ex->entry.etypes == NULL) { 707 krb5_clear_error_message(context); 708 ret = ENOMEM; 709 goto out; 710 } 711 entry_ex->entry.etypes->len = entry_ex->entry.keys.len; 712 entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int)); 713 if (entry_ex->entry.etypes->val == NULL) { 714 krb5_clear_error_message(context); 715 ret = ENOMEM; 716 goto out; 717 } 718 for (i=0; i < entry_ex->entry.etypes->len; i++) { 719 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype; 720 } 721 722 723 p->msg = talloc_steal(p, msg); 724 p->samdb = (struct ldb_context *)db->hdb_db; 725 726 out: 727 if (ret != 0) { 728 /* This doesn't free ent itself, that is for the eventual caller to do */ 729 hdb_free_entry(context, entry_ex); 730 } else { 731 talloc_steal(db, entry_ex->ctx); 732 } 733 734 return ret; 735 } 736 737 /* 738 * Construct an hdb_entry from a directory entry. 739 */ 740 static krb5_error_code hdb_samba4_trust_message2entry(krb5_context context, HDB *db, 741 struct loadparm_context *lp_ctx, 742 TALLOC_CTX *mem_ctx, krb5_const_principal principal, 743 enum trust_direction direction, 744 struct ldb_dn *realm_dn, 745 struct ldb_message *msg, 746 hdb_entry_ex *entry_ex) 747 { 748 749 const char *dnsdomain; 750 char *realm; 751 DATA_BLOB password_utf16; 752 struct samr_Password password_hash; 753 const struct ldb_val *password_val; 754 struct trustAuthInOutBlob password_blob; 755 struct hdb_samba4_private *p; 756 757 enum ndr_err_code ndr_err; 758 int i, ret, trust_direction_flags; 759 760 p = talloc(mem_ctx, struct hdb_samba4_private); 761 if (!p) { 762 ret = ENOMEM; 763 goto out; 764 } 765 766 p->entry_ex = entry_ex; 767 p->iconv_convenience = lp_iconv_convenience(lp_ctx); 768 p->lp_ctx = lp_ctx; 769 p->realm_dn = realm_dn; 770 771 talloc_set_destructor(p, hdb_samba4_destructor); 772 773 entry_ex->ctx = p; 774 entry_ex->free_entry = hdb_samba4_free_entry; 775 776 /* use 'whenCreated' */ 777 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0); 778 /* use '???' */ 779 entry_ex->entry.created_by.principal = NULL; 780 781 entry_ex->entry.valid_start = NULL; 782 783 trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0); 784 785 if (direction == INBOUND) { 786 realm = strupper_talloc(mem_ctx, lp_realm(lp_ctx)); 787 password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming"); 788 789 } else { /* OUTBOUND */ 790 dnsdomain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL); 791 realm = strupper_talloc(mem_ctx, dnsdomain); 792 password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing"); 793 } 794 795 if (!password_val || !(trust_direction_flags & direction)) { 796 ret = ENOENT; 797 goto out; 798 } 799 800 ndr_err = ndr_pull_struct_blob(password_val, mem_ctx, p->iconv_convenience, &password_blob, 801 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob); 802 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 803 ret = EINVAL; 804 goto out; 805 } 806 807 entry_ex->entry.kvno = -1; 808 for (i=0; i < password_blob.count; i++) { 809 if (password_blob.current->array[i].AuthType == TRUST_AUTH_TYPE_VERSION) { 810 entry_ex->entry.kvno = password_blob.current->array[i].AuthInfo.version.version; 811 } 812 } 813 814 for (i=0; i < password_blob.count; i++) { 815 if (password_blob.current->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) { 816 password_utf16 = data_blob_const(password_blob.current->array[i].AuthInfo.clear.password, 817 password_blob.current->array[i].AuthInfo.clear.size); 818 /* In the future, generate all sorts of 819 * hashes, but for now we can't safely convert 820 * the random strings windows uses into 821 * utf8 */ 822 823 /* but as it is utf16 already, we can get the NT password/arcfour-hmac-md5 key */ 824 mdfour(password_hash.hash, password_utf16.data, password_utf16.length); 825 break; 826 } else if (password_blob.current->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) { 827 password_hash = password_blob.current->array[i].AuthInfo.nt4owf.password; 828 break; 829 } 830 } 831 entry_ex->entry.keys.len = 0; 832 entry_ex->entry.keys.val = NULL; 833 834 if (i < password_blob.count) { 835 Key key; 836 /* Must have found a cleartext or MD4 password */ 837 entry_ex->entry.keys.val = calloc(1, sizeof(Key)); 838 839 key.mkvno = 0; 840 key.salt = NULL; /* No salt for this enc type */ 841 842 if (entry_ex->entry.keys.val == NULL) { 843 ret = ENOMEM; 844 goto out; 845 } 846 847 ret = krb5_keyblock_init(context, 848 ENCTYPE_ARCFOUR_HMAC, 849 password_hash.hash, sizeof(password_hash.hash), 850 &key.key); 851 852 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key; 853 entry_ex->entry.keys.len++; 854 } 855 856 entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal))); 857 858 ret = copy_Principal(principal, entry_ex->entry.principal); 859 if (ret) { 860 krb5_clear_error_message(context); 861 goto out; 862 } 863 864 /* While we have copied the client principal, tests 865 * show that Win2k3 returns the 'corrected' realm, not 866 * the client-specified realm. This code attempts to 867 * replace the client principal's realm with the one 868 * we determine from our records */ 869 870 krb5_principal_set_realm(context, entry_ex->entry.principal, realm); 871 entry_ex->entry.flags = int2HDBFlags(0); 872 entry_ex->entry.flags.immutable = 1; 873 entry_ex->entry.flags.invalid = 0; 874 entry_ex->entry.flags.server = 1; 875 entry_ex->entry.flags.require_preauth = 1; 876 877 entry_ex->entry.pw_end = NULL; 878 879 entry_ex->entry.max_life = NULL; 880 881 entry_ex->entry.max_renew = NULL; 882 883 entry_ex->entry.generation = NULL; 884 885 entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes))); 886 if (entry_ex->entry.etypes == NULL) { 887 krb5_clear_error_message(context); 888 ret = ENOMEM; 889 goto out; 890 } 891 entry_ex->entry.etypes->len = entry_ex->entry.keys.len; 892 entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int)); 893 if (entry_ex->entry.etypes->val == NULL) { 894 krb5_clear_error_message(context); 895 ret = ENOMEM; 896 goto out; 897 } 898 for (i=0; i < entry_ex->entry.etypes->len; i++) { 899 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype; 900 } 901 902 903 p->msg = talloc_steal(p, msg); 904 p->samdb = (struct ldb_context *)db->hdb_db; 905 906 out: 907 if (ret != 0) { 908 /* This doesn't free ent itself, that is for the eventual caller to do */ 909 hdb_free_entry(context, entry_ex); 910 } else { 911 talloc_steal(db, entry_ex->ctx); 912 } 913 914 return ret; 915 916 } 917 918 static krb5_error_code hdb_samba4_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx, 919 TALLOC_CTX *mem_ctx, 920 const char *realm, 921 struct ldb_dn *realm_dn, 922 struct ldb_message **pmsg) 923 { 924 int lret; 925 krb5_error_code ret; 926 char *filter = NULL; 927 const char * const *attrs = trust_attrs; 928 929 struct ldb_result *res = NULL; 930 filter = talloc_asprintf(mem_ctx, "(&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s)))", realm, realm); 931 932 if (!filter) { 933 ret = ENOMEM; 934 krb5_set_error_message(context, ret, "talloc_asprintf: out of memory"); 935 return ret; 936 } 937 938 lret = ldb_search(ldb_ctx, mem_ctx, &res, 939 ldb_get_default_basedn(ldb_ctx), 940 LDB_SCOPE_SUBTREE, attrs, "%s", filter); 941 if (lret != LDB_SUCCESS) { 942 DEBUG(3, ("Failed to search for %s: %s\n", filter, ldb_errstring(ldb_ctx))); 943 return HDB_ERR_NOENTRY; 944 } else if (res->count == 0 || res->count > 1) { 945 DEBUG(3, ("Failed find a single entry for %s: got %d\n", filter, res->count)); 946 talloc_free(res); 947 return HDB_ERR_NOENTRY; 948 } 949 talloc_steal(mem_ctx, res->msgs); 950 *pmsg = res->msgs[0]; 951 talloc_free(res); 952 return 0; 953 } 36 #include "kdc/kdc-glue.h" 37 #include "kdc/db-glue.h" 954 38 955 39 static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode) … … 960 44 krb5_set_error_message(context, ret, "hdb_samba4_open: use of a master key incompatible with LDB\n"); 961 45 return ret; 962 } 46 } 963 47 964 48 return 0; … … 985 69 } 986 70 987 static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db,988 struct loadparm_context *lp_ctx,989 TALLOC_CTX *mem_ctx,990 krb5_const_principal principal,991 const char **attrs,992 struct ldb_dn **realm_dn,993 struct ldb_message **msg) {994 NTSTATUS nt_status;995 char *principal_string;996 krb5_error_code ret;997 998 ret = krb5_unparse_name(context, principal, &principal_string);999 1000 if (ret != 0) {1001 return ret;1002 }1003 1004 nt_status = sam_get_results_principal((struct ldb_context *)db->hdb_db,1005 mem_ctx, principal_string, attrs,1006 realm_dn, msg);1007 free(principal_string);1008 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {1009 return HDB_ERR_NOENTRY;1010 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {1011 return ENOMEM;1012 } else if (!NT_STATUS_IS_OK(nt_status)) {1013 return EINVAL;1014 }1015 1016 return ret;1017 }1018 1019 static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,1020 struct loadparm_context *lp_ctx,1021 TALLOC_CTX *mem_ctx,1022 krb5_const_principal principal,1023 unsigned flags,1024 hdb_entry_ex *entry_ex) {1025 struct ldb_dn *realm_dn;1026 krb5_error_code ret;1027 struct ldb_message *msg = NULL;1028 1029 ret = hdb_samba4_lookup_client(context, db, lp_ctx,1030 mem_ctx, principal, user_attrs,1031 &realm_dn, &msg);1032 if (ret != 0) {1033 return ret;1034 }1035 1036 ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,1037 principal, HDB_SAMBA4_ENT_TYPE_CLIENT,1038 realm_dn, msg, entry_ex);1039 return ret;1040 }1041 1042 static krb5_error_code hdb_samba4_fetch_krbtgt(krb5_context context, HDB *db,1043 struct loadparm_context *lp_ctx,1044 TALLOC_CTX *mem_ctx,1045 krb5_const_principal principal,1046 unsigned flags,1047 hdb_entry_ex *entry_ex)1048 {1049 krb5_error_code ret;1050 struct ldb_message *msg = NULL;1051 struct ldb_dn *realm_dn = ldb_get_default_basedn(db->hdb_db);1052 const char *realm;1053 1054 krb5_principal alloc_principal = NULL;1055 if (principal->name.name_string.len != 21056 || (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) != 0)) {1057 /* Not a krbtgt */1058 return HDB_ERR_NOENTRY;1059 }1060 1061 /* krbtgt case. Either us or a trusted realm */1062 1063 if (lp_is_my_domain_or_realm(lp_ctx, principal->realm)1064 && lp_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) {1065 /* us */1066 /* Cludge, cludge cludge. If the realm part of krbtgt/realm,1067 * is in our db, then direct the caller at our primary1068 * krbtgt */1069 1070 int lret;1071 char *realm_fixed;1072 1073 lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,1074 realm_dn, LDB_SCOPE_SUBTREE,1075 &msg, krbtgt_attrs,1076 "(&(objectClass=user)(samAccountName=krbtgt))");1077 if (lret == LDB_ERR_NO_SUCH_OBJECT) {1078 krb5_warnx(context, "hdb_samba4_fetch: could not find own KRBTGT in DB!");1079 krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB!");1080 return HDB_ERR_NOENTRY;1081 } else if (lret != LDB_SUCCESS) {1082 krb5_warnx(context, "hdb_samba4_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(db->hdb_db));1083 krb5_set_error_message(context, HDB_ERR_NOENTRY, "hdb_samba4_fetch: could not find own KRBTGT in DB: %s", ldb_errstring(db->hdb_db));1084 return HDB_ERR_NOENTRY;1085 }1086 1087 realm_fixed = strupper_talloc(mem_ctx, lp_realm(lp_ctx));1088 if (!realm_fixed) {1089 ret = ENOMEM;1090 krb5_set_error_message(context, ret, "strupper_talloc: out of memory");1091 return ret;1092 }1093 1094 ret = krb5_copy_principal(context, principal, &alloc_principal);1095 if (ret) {1096 return ret;1097 }1098 1099 free(alloc_principal->name.name_string.val[1]);1100 alloc_principal->name.name_string.val[1] = strdup(realm_fixed);1101 talloc_free(realm_fixed);1102 if (!alloc_principal->name.name_string.val[1]) {1103 ret = ENOMEM;1104 krb5_set_error_message(context, ret, "hdb_samba4_fetch: strdup() failed!");1105 return ret;1106 }1107 principal = alloc_principal;1108 1109 ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,1110 principal, HDB_SAMBA4_ENT_TYPE_KRBTGT,1111 realm_dn, msg, entry_ex);1112 if (ret != 0) {1113 krb5_warnx(context, "hdb_samba4_fetch: self krbtgt message2entry failed");1114 }1115 return ret;1116 1117 } else {1118 enum trust_direction direction = UNKNOWN;1119 1120 /* Either an inbound or outbound trust */1121 1122 if (strcasecmp(lp_realm(lp_ctx), principal->realm) == 0) {1123 /* look for inbound trust */1124 direction = INBOUND;1125 realm = principal->name.name_string.val[1];1126 }1127 1128 if (strcasecmp(lp_realm(lp_ctx), principal->name.name_string.val[1]) == 0) {1129 /* look for outbound trust */1130 direction = OUTBOUND;1131 realm = principal->realm;1132 }1133 1134 /* Trusted domains are under CN=system */1135 1136 ret = hdb_samba4_lookup_trust(context, (struct ldb_context *)db->hdb_db,1137 mem_ctx,1138 realm, realm_dn, &msg);1139 1140 if (ret != 0) {1141 krb5_warnx(context, "hdb_samba4_fetch: could not find principal in DB");1142 krb5_set_error_message(context, ret, "hdb_samba4_fetch: could not find principal in DB");1143 return ret;1144 }1145 1146 ret = hdb_samba4_trust_message2entry(context, db, lp_ctx, mem_ctx,1147 principal, direction,1148 realm_dn, msg, entry_ex);1149 if (ret != 0) {1150 krb5_warnx(context, "hdb_samba4_fetch: trust_message2entry failed");1151 }1152 return ret;1153 1154 1155 /* we should lookup trusted domains */1156 return HDB_ERR_NOENTRY;1157 }1158 1159 }1160 1161 static krb5_error_code hdb_samba4_lookup_server(krb5_context context, HDB *db,1162 struct loadparm_context *lp_ctx,1163 TALLOC_CTX *mem_ctx,1164 krb5_const_principal principal,1165 const char **attrs,1166 struct ldb_dn **realm_dn,1167 struct ldb_message **msg)1168 {1169 krb5_error_code ret;1170 const char *realm;1171 if (principal->name.name_string.len >= 2) {1172 /* 'normal server' case */1173 int ldb_ret;1174 NTSTATUS nt_status;1175 struct ldb_dn *user_dn;1176 char *principal_string;1177 1178 ret = krb5_unparse_name_flags(context, principal,1179 KRB5_PRINCIPAL_UNPARSE_NO_REALM,1180 &principal_string);1181 if (ret != 0) {1182 return ret;1183 }1184 1185 /* At this point we may find the host is known to be1186 * in a different realm, so we should generate a1187 * referral instead */1188 nt_status = crack_service_principal_name((struct ldb_context *)db->hdb_db,1189 mem_ctx, principal_string,1190 &user_dn, realm_dn);1191 free(principal_string);1192 1193 if (!NT_STATUS_IS_OK(nt_status)) {1194 return HDB_ERR_NOENTRY;1195 }1196 1197 ldb_ret = gendb_search_single_extended_dn((struct ldb_context *)db->hdb_db,1198 mem_ctx,1199 user_dn, LDB_SCOPE_BASE,1200 msg, attrs,1201 "(objectClass=*)");1202 if (ldb_ret != LDB_SUCCESS) {1203 return HDB_ERR_NOENTRY;1204 }1205 1206 } else {1207 int lret;1208 char *filter = NULL;1209 char *short_princ;1210 /* server as client principal case, but we must not lookup userPrincipalNames */1211 *realm_dn = ldb_get_default_basedn(db->hdb_db);1212 realm = krb5_principal_get_realm(context, principal);1213 1214 /* TODO: Check if it is our realm, otherwise give referall */1215 1216 ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);1217 1218 if (ret != 0) {1219 krb5_set_error_message(context, ret, "hdb_samba4_lookup_principal: could not parse principal");1220 krb5_warnx(context, "hdb_samba4_lookup_principal: could not parse principal");1221 return ret;1222 }1223 1224 lret = gendb_search_single_extended_dn(db->hdb_db, mem_ctx,1225 *realm_dn, LDB_SCOPE_SUBTREE,1226 msg, attrs, "(&(objectClass=user)(samAccountName=%s))",1227 ldb_binary_encode_string(mem_ctx, short_princ));1228 free(short_princ);1229 if (lret == LDB_ERR_NO_SUCH_OBJECT) {1230 DEBUG(3, ("Failed find a entry for %s\n", filter));1231 return HDB_ERR_NOENTRY;1232 }1233 if (lret != LDB_SUCCESS) {1234 DEBUG(3, ("Failed single search for for %s - %s\n",1235 filter, ldb_errstring(db->hdb_db)));1236 return HDB_ERR_NOENTRY;1237 }1238 }1239 1240 return 0;1241 }1242 1243 static krb5_error_code hdb_samba4_fetch_server(krb5_context context, HDB *db,1244 struct loadparm_context *lp_ctx,1245 TALLOC_CTX *mem_ctx,1246 krb5_const_principal principal,1247 unsigned flags,1248 hdb_entry_ex *entry_ex)1249 {1250 krb5_error_code ret;1251 struct ldb_dn *realm_dn;1252 struct ldb_message *msg;1253 1254 ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, principal,1255 server_attrs, &realm_dn, &msg);1256 if (ret != 0) {1257 return ret;1258 }1259 1260 ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,1261 principal, HDB_SAMBA4_ENT_TYPE_SERVER,1262 realm_dn, msg, entry_ex);1263 if (ret != 0) {1264 krb5_warnx(context, "hdb_samba4_fetch: message2entry failed");1265 }1266 1267 return ret;1268 }1269 1270 static krb5_error_code hdb_samba4_fetch(krb5_context context, HDB *db,1271 krb5_const_principal principal,1272 unsigned flags,1273 hdb_entry_ex *entry_ex)1274 {1275 krb5_error_code ret = HDB_ERR_NOENTRY;1276 TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_fetch context");1277 struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(db->hdb_db, "loadparm"), struct loadparm_context);1278 1279 if (!mem_ctx) {1280 ret = ENOMEM;1281 krb5_set_error_message(context, ret, "hdb_samba4_fetch: talloc_named() failed!");1282 return ret;1283 }1284 1285 if (flags & HDB_F_GET_CLIENT) {1286 ret = hdb_samba4_fetch_client(context, db, lp_ctx, mem_ctx, principal, flags, entry_ex);1287 if (ret != HDB_ERR_NOENTRY) goto done;1288 }1289 if (flags & HDB_F_GET_SERVER) {1290 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */1291 ret = hdb_samba4_fetch_krbtgt(context, db, lp_ctx, mem_ctx, principal, flags, entry_ex);1292 if (ret != HDB_ERR_NOENTRY) goto done;1293 1294 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */1295 ret = hdb_samba4_fetch_server(context, db, lp_ctx, mem_ctx, principal, flags, entry_ex);1296 if (ret != HDB_ERR_NOENTRY) goto done;1297 }1298 if (flags & HDB_F_GET_KRBTGT) {1299 ret = hdb_samba4_fetch_krbtgt(context, db, lp_ctx, mem_ctx, principal, flags, entry_ex);1300 if (ret != HDB_ERR_NOENTRY) goto done;1301 }1302 1303 done:1304 talloc_free(mem_ctx);1305 return ret;1306 }1307 1308 71 static krb5_error_code hdb_samba4_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 1309 72 { … … 1316 79 } 1317 80 1318 struct hdb_samba4_seq { 1319 struct ldb_context *ctx; 1320 struct loadparm_context *lp_ctx; 1321 int index; 1322 int count; 1323 struct ldb_message **msgs; 1324 struct ldb_dn *realm_dn; 1325 }; 1326 1327 static krb5_error_code hdb_samba4_seq(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry) 1328 { 1329 krb5_error_code ret; 1330 struct hdb_samba4_seq *priv = (struct hdb_samba4_seq *)db->hdb_dbc; 1331 TALLOC_CTX *mem_ctx; 1332 hdb_entry_ex entry_ex; 1333 memset(&entry_ex, '\0', sizeof(entry_ex)); 1334 1335 if (!priv) { 1336 return HDB_ERR_NOENTRY; 1337 } 1338 1339 mem_ctx = talloc_named(priv, 0, "hdb_samba4_seq context"); 1340 1341 if (!mem_ctx) { 1342 ret = ENOMEM; 1343 krb5_set_error_message(context, ret, "hdb_samba4_seq: talloc_named() failed!"); 1344 return ret; 1345 } 1346 1347 if (priv->index < priv->count) { 1348 ret = hdb_samba4_message2entry(context, db, priv->lp_ctx, 1349 mem_ctx, 1350 NULL, HDB_SAMBA4_ENT_TYPE_ANY, 1351 priv->realm_dn, priv->msgs[priv->index++], entry); 1352 } else { 1353 ret = HDB_ERR_NOENTRY; 1354 } 1355 1356 if (ret != 0) { 1357 db->hdb_dbc = NULL; 1358 } else { 1359 talloc_free(mem_ctx); 1360 } 1361 1362 return ret; 81 static krb5_error_code hdb_samba4_fetch_kvno(krb5_context context, HDB *db, 82 krb5_const_principal principal, 83 unsigned flags, 84 krb5_kvno kvno, 85 hdb_entry_ex *entry_ex) 86 { 87 struct samba_kdc_db_context *kdc_db_ctx; 88 89 kdc_db_ctx = talloc_get_type_abort(db->hdb_db, 90 struct samba_kdc_db_context); 91 92 return samba_kdc_fetch(context, kdc_db_ctx, principal, flags, kvno, entry_ex); 1363 93 } 1364 94 … … 1366 96 hdb_entry_ex *entry) 1367 97 { 1368 struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; 1369 struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), 1370 struct loadparm_context); 1371 struct hdb_samba4_seq *priv = (struct hdb_samba4_seq *)db->hdb_dbc; 1372 char *realm; 1373 struct ldb_result *res = NULL; 1374 krb5_error_code ret; 1375 TALLOC_CTX *mem_ctx; 1376 int lret; 1377 1378 if (priv) { 1379 talloc_free(priv); 1380 db->hdb_dbc = NULL; 1381 } 1382 1383 priv = (struct hdb_samba4_seq *) talloc(db, struct hdb_samba4_seq); 1384 if (!priv) { 1385 ret = ENOMEM; 1386 krb5_set_error_message(context, ret, "talloc: out of memory"); 1387 return ret; 1388 } 1389 1390 priv->ctx = ldb_ctx; 1391 priv->lp_ctx = lp_ctx; 1392 priv->index = 0; 1393 priv->msgs = NULL; 1394 priv->realm_dn = ldb_get_default_basedn(ldb_ctx); 1395 priv->count = 0; 1396 1397 mem_ctx = talloc_named(priv, 0, "hdb_samba4_firstkey context"); 1398 1399 if (!mem_ctx) { 1400 ret = ENOMEM; 1401 krb5_set_error_message(context, ret, "hdb_samba4_firstkey: talloc_named() failed!"); 1402 return ret; 1403 } 1404 1405 ret = krb5_get_default_realm(context, &realm); 1406 if (ret != 0) { 1407 talloc_free(priv); 1408 return ret; 1409 } 1410 1411 lret = ldb_search(ldb_ctx, priv, &res, 1412 priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs, 1413 "(objectClass=user)"); 1414 1415 if (lret != LDB_SUCCESS) { 1416 talloc_free(priv); 1417 return HDB_ERR_NOENTRY; 1418 } 1419 1420 priv->count = res->count; 1421 priv->msgs = talloc_steal(priv, res->msgs); 1422 talloc_free(res); 1423 1424 db->hdb_dbc = priv; 1425 1426 ret = hdb_samba4_seq(context, db, flags, entry); 1427 1428 if (ret != 0) { 1429 talloc_free(priv); 1430 db->hdb_dbc = NULL; 1431 } else { 1432 talloc_free(mem_ctx); 1433 } 1434 return ret; 98 struct samba_kdc_db_context *kdc_db_ctx; 99 100 kdc_db_ctx = talloc_get_type_abort(db->hdb_db, 101 struct samba_kdc_db_context); 102 103 return samba_kdc_firstkey(context, kdc_db_ctx, entry); 1435 104 } 1436 105 … … 1438 107 hdb_entry_ex *entry) 1439 108 { 1440 return hdb_samba4_seq(context, db, flags, entry); 109 struct samba_kdc_db_context *kdc_db_ctx; 110 111 kdc_db_ctx = talloc_get_type_abort(db->hdb_db, 112 struct samba_kdc_db_context); 113 114 return samba_kdc_nextkey(context, kdc_db_ctx, entry); 1441 115 } 1442 116 … … 1447 121 } 1448 122 1449 1450 /* Check if a given entry may delegate to this target principal 1451 * 1452 * This is currently a very nasty hack - allowing only delegation to itself. 1453 */ 1454 krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db, 1455 hdb_entry_ex *entry, 1456 krb5_const_principal target_principal) 1457 { 1458 struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; 1459 struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), 1460 struct loadparm_context); 1461 krb5_error_code ret; 1462 krb5_principal enterprise_prinicpal = NULL; 1463 struct ldb_dn *realm_dn; 1464 struct ldb_message *msg; 1465 struct dom_sid *orig_sid; 1466 struct dom_sid *target_sid; 1467 struct hdb_samba4_private *p = talloc_get_type(entry->ctx, struct hdb_samba4_private); 1468 const char *delegation_check_attrs[] = { 1469 "objectSid", NULL 1470 }; 1471 1472 TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation"); 1473 1474 if (!mem_ctx) { 1475 ret = ENOMEM; 1476 krb5_set_error_message(context, ret, "hdb_samba4_fetch: talloc_named() failed!"); 1477 return ret; 1478 } 1479 1480 if (target_principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) { 1481 /* Need to reparse the enterprise principal to find the real target */ 1482 if (target_principal->name.name_string.len != 1) { 1483 ret = KRB5_PARSE_MALFORMED; 1484 krb5_set_error_message(context, ret, "hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components", 1485 target_principal->name.name_string.len); 1486 talloc_free(mem_ctx); 1487 return ret; 1488 } 1489 ret = krb5_parse_name(context, target_principal->name.name_string.val[0], 1490 &enterprise_prinicpal); 1491 if (ret) { 1492 talloc_free(mem_ctx); 1493 return ret; 1494 } 1495 target_principal = enterprise_prinicpal; 1496 } 1497 1498 ret = hdb_samba4_lookup_server(context, db, lp_ctx, mem_ctx, target_principal, 1499 delegation_check_attrs, &realm_dn, &msg); 1500 1501 krb5_free_principal(context, enterprise_prinicpal); 1502 1503 if (ret != 0) { 1504 talloc_free(mem_ctx); 1505 return ret; 1506 } 1507 1508 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"); 1509 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid"); 1510 1511 /* Allow delegation to the same principal, even if by a different 1512 * name. The easy and safe way to prove this is by SID 1513 * comparison */ 1514 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) { 1515 talloc_free(mem_ctx); 1516 return KRB5KDC_ERR_BADOPTION; 1517 } 1518 1519 talloc_free(mem_ctx); 1520 return ret; 1521 } 1522 1523 /* Certificates printed by a the Certificate Authority might have a 1524 * slightly different form of the user principal name to that in the 1525 * database. Allow a mismatch where they both refer to the same 1526 * SID */ 1527 1528 krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, 1529 hdb_entry_ex *entry, 1530 krb5_const_principal certificate_principal) 1531 { 1532 struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db; 1533 struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"), 1534 struct loadparm_context); 1535 krb5_error_code ret; 1536 struct ldb_dn *realm_dn; 1537 struct ldb_message *msg; 1538 struct dom_sid *orig_sid; 1539 struct dom_sid *target_sid; 1540 struct hdb_samba4_private *p = talloc_get_type(entry->ctx, struct hdb_samba4_private); 1541 const char *ms_upn_check_attrs[] = { 1542 "objectSid", NULL 1543 }; 1544 1545 TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation"); 1546 1547 if (!mem_ctx) { 1548 ret = ENOMEM; 1549 krb5_set_error_message(context, ret, "hdb_samba4_fetch: talloc_named() failed!"); 1550 return ret; 1551 } 1552 1553 ret = hdb_samba4_lookup_client(context, db, lp_ctx, 1554 mem_ctx, certificate_principal, 1555 ms_upn_check_attrs, &realm_dn, &msg); 1556 1557 if (ret != 0) { 1558 talloc_free(mem_ctx); 1559 return ret; 1560 } 1561 1562 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"); 1563 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid"); 1564 1565 /* Consider these to be the same principal, even if by a different 1566 * name. The easy and safe way to prove this is by SID 1567 * comparison */ 1568 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) { 1569 talloc_free(mem_ctx); 1570 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; 1571 } 1572 1573 talloc_free(mem_ctx); 1574 return ret; 1575 } 1576 1577 /* This interface is to be called by the KDC and libnet_keytab_dump, which is expecting Samba 1578 * calling conventions. It is also called by a wrapper 1579 * (hdb_samba4_create) from the kpasswdd -> krb5 -> keytab_hdb -> hdb 1580 * code */ 1581 1582 NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx, 1583 struct tevent_context *ev_ctx, 1584 struct loadparm_context *lp_ctx, 1585 krb5_context context, struct HDB **db) 1586 { 123 static krb5_error_code 124 hdb_samba4_check_identical_client_and_server(krb5_context context, HDB *db, 125 hdb_entry_ex *entry, 126 krb5_const_principal target_principal) 127 { 128 struct samba_kdc_db_context *kdc_db_ctx; 129 130 kdc_db_ctx = talloc_get_type_abort(db->hdb_db, 131 struct samba_kdc_db_context); 132 133 return samba_kdc_check_identical_client_and_server(context, kdc_db_ctx, 134 entry, 135 target_principal); 136 } 137 138 static krb5_error_code 139 hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db, 140 hdb_entry_ex *entry, 141 krb5_const_principal certificate_principal) 142 { 143 struct samba_kdc_db_context *kdc_db_ctx; 144 145 kdc_db_ctx = talloc_get_type_abort(db->hdb_db, 146 struct samba_kdc_db_context); 147 148 return samba_kdc_check_pkinit_ms_upn_match(context, kdc_db_ctx, 149 entry, 150 certificate_principal); 151 } 152 153 /* This interface is to be called by the KDC and libnet_keytab_dump, 154 * which is expecting Samba calling conventions. 155 * It is also called by a wrapper (hdb_samba4_create) from the 156 * kpasswdd -> krb5 -> keytab_hdb -> hdb code */ 157 158 NTSTATUS hdb_samba4_create_kdc(struct samba_kdc_base_context *base_ctx, 159 krb5_context context, struct HDB **db) 160 { 161 struct samba_kdc_db_context *kdc_db_ctx; 1587 162 NTSTATUS nt_status; 1588 struct auth_session_info *session_info; 1589 *db = talloc( mem_ctx, HDB);163 164 *db = talloc(base_ctx, HDB); 1590 165 if (!*db) { 1591 166 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); … … 1597 172 (*db)->hdb_capability_flags = 0; 1598 173 1599 nt_status = auth_system_session_info(*db, lp_ctx, &session_info);174 nt_status = samba_kdc_setup_db_ctx(*db, base_ctx, &kdc_db_ctx); 1600 175 if (!NT_STATUS_IS_OK(nt_status)) { 176 talloc_free(*db); 1601 177 return nt_status; 1602 178 } 1603 1604 /* The idea here is very simple. Using Kerberos to 1605 * authenticate the KDC to the LDAP server is higly likely to 1606 * be circular. 1607 * 1608 * In future we may set this up to use EXERNAL and SSL 1609 * certificates, for now it will almost certainly be NTLMSSP 1610 */ 1611 1612 cli_credentials_set_kerberos_state(session_info->credentials, 1613 CRED_DONT_USE_KERBEROS); 1614 1615 /* Setup the link to LDB */ 1616 (*db)->hdb_db = samdb_connect(*db, ev_ctx, lp_ctx, session_info); 1617 if ((*db)->hdb_db == NULL) { 1618 DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!")); 1619 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; 1620 } 179 (*db)->hdb_db = kdc_db_ctx; 1621 180 1622 181 (*db)->hdb_dbc = NULL; 1623 182 (*db)->hdb_open = hdb_samba4_open; 1624 183 (*db)->hdb_close = hdb_samba4_close; 1625 (*db)->hdb_fetch = hdb_samba4_fetch;184 (*db)->hdb_fetch_kvno = hdb_samba4_fetch_kvno; 1626 185 (*db)->hdb_store = hdb_samba4_store; 1627 186 (*db)->hdb_remove = hdb_samba4_remove; … … 1639 198 1640 199 (*db)->hdb_auth_status = NULL; 1641 (*db)->hdb_check_constrained_delegation = hdb_samba4_check_ constrained_delegation;200 (*db)->hdb_check_constrained_delegation = hdb_samba4_check_identical_client_and_server; 1642 201 (*db)->hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match; 202 (*db)->hdb_check_s4u2self = hdb_samba4_check_identical_client_and_server; 1643 203 1644 204 return NT_STATUS_OK; … … 1649 209 NTSTATUS nt_status; 1650 210 void *ptr; 1651 struct hdb_samba4_context *hdb_samba4_context; 211 struct samba_kdc_base_context *base_ctx; 212 1652 213 if (sscanf(arg, "&%p", &ptr) != 1) { 1653 214 return EINVAL; 1654 215 } 1655 hdb_samba4_context = talloc_get_type_abort(ptr, struct hdb_samba4_context);216 base_ctx = talloc_get_type_abort(ptr, struct samba_kdc_base_context); 1656 217 /* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */ 1657 nt_status = hdb_samba4_create_kdc(hdb_samba4_context, hdb_samba4_context->ev_ctx, hdb_samba4_context->lp_ctx, 1658 context, db); 218 nt_status = hdb_samba4_create_kdc(base_ctx, context, db); 1659 219 1660 220 if (NT_STATUS_IS_OK(nt_status)) { … … 1673 233 struct hdb_method hdb_samba4 = { 1674 234 .interface_version = HDB_INTERFACE_VERSION, 1675 .prefix = "samba4", 235 .prefix = "samba4", 1676 236 .create = hdb_samba4_create 1677 237 }; -
vendor/current/source4/kdc/kdc.c
r414 r740 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 … … 12 12 the Free Software Foundation; either version 3 of the License, or 13 13 (at your option) any later version. 14 14 15 15 This program is distributed in the hope that it will be useful, 16 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 18 GNU General Public License for more details. 19 19 20 20 You should have received a copy of the GNU General Public License 21 21 along with this program. If not, see <http://www.gnu.org/licenses/>. … … 23 23 24 24 #include "includes.h" 25 #include "smbd/service_task.h"26 #include "smbd/service.h"27 #include "smbd/service_stream.h"28 25 #include "smbd/process_model.h" 29 #include "lib/events/events.h" 30 #include "lib/socket/socket.h" 31 #include "system/network.h" 32 #include "../lib/util/dlinklist.h" 26 #include "lib/tsocket/tsocket.h" 27 #include "libcli/util/tstream.h" 33 28 #include "lib/messaging/irpc.h" 34 #include "lib/stream/packet.h"35 #include "librpc/gen_ndr/samr.h"36 29 #include "librpc/gen_ndr/ndr_irpc.h" 37 30 #include "librpc/gen_ndr/ndr_krb5pac.h" 31 #include "lib/stream/packet.h" 38 32 #include "lib/socket/netif.h" 39 33 #include "param/param.h" 40 #include "kdc/kdc.h" 41 #include "librpc/gen_ndr/ndr_misc.h" 42 43 44 /* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when 45 * used as a keytab */ 46 TALLOC_CTX *hdb_samba4_mem_ctx; 47 struct tevent_context *hdb_samba4_ev_ctx; 48 struct loadparm_context *hdb_samba4_lp_ctx; 49 50 /* hold all the info needed to send a reply */ 51 struct kdc_reply { 52 struct kdc_reply *next, *prev; 53 struct socket_address *dest; 54 DATA_BLOB packet; 55 }; 56 57 typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc, 58 TALLOC_CTX *mem_ctx, 59 DATA_BLOB *input, 60 DATA_BLOB *reply, 61 struct socket_address *peer_addr, 62 struct socket_address *my_addr, 63 int datagram); 34 #include "kdc/kdc-glue.h" 35 #include "dsdb/samdb/samdb.h" 36 #include "auth/session.h" 37 38 extern struct krb5plugin_windc_ftable windc_plugin_table; 39 extern struct hdb_method hdb_samba4; 40 41 static NTSTATUS kdc_proxy_unavailable_error(struct kdc_server *kdc, 42 TALLOC_CTX *mem_ctx, 43 DATA_BLOB *out) 44 { 45 int kret; 46 krb5_data k5_error_blob; 47 48 kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context, 49 KRB5KDC_ERR_SVC_UNAVAILABLE, NULL, NULL, 50 NULL, NULL, NULL, NULL, &k5_error_blob); 51 if (kret != 0) { 52 DEBUG(2,(__location__ ": Unable to form krb5 error reply\n")); 53 return NT_STATUS_INTERNAL_ERROR; 54 } 55 56 *out = data_blob_talloc(mem_ctx, k5_error_blob.data, k5_error_blob.length); 57 krb5_data_free(&k5_error_blob); 58 if (!out->data) { 59 return NT_STATUS_NO_MEMORY; 60 } 61 62 return NT_STATUS_OK; 63 } 64 65 typedef enum kdc_process_ret (*kdc_process_fn_t)(struct kdc_server *kdc, 66 TALLOC_CTX *mem_ctx, 67 DATA_BLOB *input, 68 DATA_BLOB *reply, 69 struct tsocket_address *peer_addr, 70 struct tsocket_address *my_addr, 71 int datagram); 64 72 65 73 /* hold information about one kdc socket */ 66 74 struct kdc_socket { 67 struct socket_context *sock;68 75 struct kdc_server *kdc; 69 struct tevent_fd *fde; 70 71 /* a queue of outgoing replies that have been deferred */ 72 struct kdc_reply *send_queue; 73 76 struct tsocket_address *local_address; 74 77 kdc_process_fn_t process; 75 78 }; 79 80 struct kdc_tcp_call { 81 struct kdc_tcp_connection *kdc_conn; 82 DATA_BLOB in; 83 DATA_BLOB out; 84 uint8_t out_hdr[4]; 85 struct iovec out_iov[2]; 86 }; 87 76 88 /* 77 89 state of an open tcp connection … … 82 94 83 95 /* the kdc_server the connection belongs to */ 84 struct kdc_s erver *kdc;85 86 struct packet_context *packet;87 88 kdc_process_fn_t process;96 struct kdc_socket *kdc_socket; 97 98 struct tstream_context *tstream; 99 100 struct tevent_queue *send_queue; 89 101 }; 90 102 91 /*92 handle fd send events on a KDC socket93 */94 static void kdc_send_handler(struct kdc_socket *kdc_socket)95 {96 while (kdc_socket->send_queue) {97 struct kdc_reply *rep = kdc_socket->send_queue;98 NTSTATUS status;99 size_t sendlen;100 101 status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,102 rep->dest);103 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {104 break;105 }106 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_BUFFER_SIZE)) {107 /* Replace with a krb err, response to big */108 }109 110 DLIST_REMOVE(kdc_socket->send_queue, rep);111 talloc_free(rep);112 }113 114 if (kdc_socket->send_queue == NULL) {115 EVENT_FD_NOT_WRITEABLE(kdc_socket->fde);116 }117 }118 119 120 /*121 handle fd recv events on a KDC socket122 */123 static void kdc_recv_handler(struct kdc_socket *kdc_socket)124 {125 NTSTATUS status;126 TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket);127 DATA_BLOB blob;128 struct kdc_reply *rep;129 DATA_BLOB reply;130 size_t nread, dsize;131 struct socket_address *src;132 struct socket_address *my_addr;133 int ret;134 135 status = socket_pending(kdc_socket->sock, &dsize);136 if (!NT_STATUS_IS_OK(status)) {137 talloc_free(tmp_ctx);138 return;139 }140 141 blob = data_blob_talloc(tmp_ctx, NULL, dsize);142 if (blob.data == NULL) {143 /* hope this is a temporary low memory condition */144 talloc_free(tmp_ctx);145 return;146 }147 148 status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,149 tmp_ctx, &src);150 if (!NT_STATUS_IS_OK(status)) {151 talloc_free(tmp_ctx);152 return;153 }154 blob.length = nread;155 156 DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n",157 (long)blob.length, src->addr, (uint16_t)src->port));158 159 my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx);160 if (!my_addr) {161 talloc_free(tmp_ctx);162 return;163 }164 165 166 /* Call krb5 */167 ret = kdc_socket->process(kdc_socket->kdc,168 tmp_ctx,169 &blob,170 &reply,171 src, my_addr,172 1 /* Datagram */);173 if (!ret) {174 talloc_free(tmp_ctx);175 return;176 }177 178 /* queue a pending reply */179 rep = talloc(kdc_socket, struct kdc_reply);180 if (rep == NULL) {181 talloc_free(tmp_ctx);182 return;183 }184 rep->dest = talloc_steal(rep, src);185 rep->packet = reply;186 talloc_steal(rep, reply.data);187 188 if (rep->packet.data == NULL) {189 talloc_free(rep);190 talloc_free(tmp_ctx);191 return;192 }193 194 DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *);195 EVENT_FD_WRITEABLE(kdc_socket->fde);196 talloc_free(tmp_ctx);197 }198 199 /*200 handle fd events on a KDC socket201 */202 static void kdc_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,203 uint16_t flags, void *private_data)204 {205 struct kdc_socket *kdc_socket = talloc_get_type(private_data, struct kdc_socket);206 if (flags & EVENT_FD_WRITE) {207 kdc_send_handler(kdc_socket);208 }209 if (flags & EVENT_FD_READ) {210 kdc_recv_handler(kdc_socket);211 }212 }213 103 214 104 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason) … … 217 107 } 218 108 219 /* 220 receive a full packet on a KDC connection 221 */ 222 static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob) 223 { 224 struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data, 225 struct kdc_tcp_connection); 226 NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 227 TALLOC_CTX *tmp_ctx = talloc_new(kdcconn); 228 int ret; 229 DATA_BLOB input, reply; 230 struct socket_address *src_addr; 231 struct socket_address *my_addr; 232 233 talloc_steal(tmp_ctx, blob.data); 234 235 src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx); 236 if (!src_addr) { 237 talloc_free(tmp_ctx); 238 return NT_STATUS_NO_MEMORY; 239 } 240 241 my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx); 242 if (!my_addr) { 243 talloc_free(tmp_ctx); 244 return NT_STATUS_NO_MEMORY; 245 } 246 247 /* Call krb5 */ 248 input = data_blob_const(blob.data + 4, blob.length - 4); 249 250 ret = kdcconn->process(kdcconn->kdc, 251 tmp_ctx, 252 &input, 253 &reply, 254 src_addr, 255 my_addr, 256 0 /* Not datagram */); 257 if (!ret) { 258 talloc_free(tmp_ctx); 259 return NT_STATUS_INTERNAL_ERROR; 260 } 261 262 /* and now encode the reply */ 263 blob = data_blob_talloc(kdcconn, NULL, reply.length + 4); 264 if (!blob.data) { 265 talloc_free(tmp_ctx); 266 return NT_STATUS_NO_MEMORY; 267 } 268 269 RSIVAL(blob.data, 0, reply.length); 270 memcpy(blob.data + 4, reply.data, reply.length); 271 272 status = packet_send(kdcconn->packet, blob); 273 if (!NT_STATUS_IS_OK(status)) { 274 talloc_free(tmp_ctx); 275 return status; 276 } 277 278 /* the call isn't needed any more */ 279 talloc_free(tmp_ctx); 280 return NT_STATUS_OK; 281 } 282 283 /* 284 receive some data on a KDC connection 285 */ 286 static void kdc_tcp_recv_handler(struct stream_connection *conn, uint16_t flags) 109 static void kdc_tcp_recv(struct stream_connection *conn, uint16_t flags) 287 110 { 288 111 struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data, 289 112 struct kdc_tcp_connection); 290 packet_recv(kdcconn->packet); 291 } 292 293 /* 294 called on a tcp recv error 295 */ 296 static void kdc_tcp_recv_error(void *private_data, NTSTATUS status) 297 { 298 struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data, 299 struct kdc_tcp_connection); 300 kdc_tcp_terminate_connection(kdcconn, nt_errstr(status)); 301 } 302 303 /* 304 called when we can write to a connection 305 */ 113 /* this should never be triggered! */ 114 kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_recv: called"); 115 } 116 306 117 static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags) 307 118 { 308 119 struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data, 309 120 struct kdc_tcp_connection); 310 packet_queue_run(kdcconn->packet); 121 /* this should never be triggered! */ 122 kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_send: called"); 311 123 } 312 124 … … 316 128 */ 317 129 318 static bool kdc_process(struct kdc_server *kdc, 319 TALLOC_CTX *mem_ctx, 320 DATA_BLOB *input, 321 DATA_BLOB *reply, 322 struct socket_address *peer_addr, 323 struct socket_address *my_addr, 324 int datagram_reply) 325 { 326 int ret; 130 static enum kdc_process_ret kdc_process(struct kdc_server *kdc, 131 TALLOC_CTX *mem_ctx, 132 DATA_BLOB *input, 133 DATA_BLOB *reply, 134 struct tsocket_address *peer_addr, 135 struct tsocket_address *my_addr, 136 int datagram_reply) 137 { 138 int ret; 139 char *pa; 140 struct sockaddr_storage ss; 327 141 krb5_data k5_reply; 328 142 krb5_data_zero(&k5_reply); … … 330 144 krb5_kdc_update_time(NULL); 331 145 332 DEBUG(10,("Received KDC packet of length %lu from %s:%d\n", 333 (long)input->length - 4, peer_addr->addr, peer_addr->port)); 334 335 ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, 146 ret = tsocket_address_bsd_sockaddr(peer_addr, (struct sockaddr *) &ss, 147 sizeof(struct sockaddr_storage)); 148 if (ret < 0) { 149 return KDC_PROCESS_FAILED; 150 } 151 pa = tsocket_address_string(peer_addr, mem_ctx); 152 if (pa == NULL) { 153 return KDC_PROCESS_FAILED; 154 } 155 156 DEBUG(10,("Received KDC packet of length %lu from %s\n", 157 (long)input->length - 4, pa)); 158 159 ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, 336 160 kdc->config, 337 161 input->data, input->length, 338 162 &k5_reply, 339 p eer_addr->addr,340 peer_addr->sockaddr,163 pa, 164 (struct sockaddr *) &ss, 341 165 datagram_reply); 342 166 if (ret == -1) { 343 167 *reply = data_blob(NULL, 0); 344 return false; 345 } 168 return KDC_PROCESS_FAILED; 169 } 170 171 if (ret == HDB_ERR_NOT_FOUND_HERE) { 172 *reply = data_blob(NULL, 0); 173 return KDC_PROCESS_PROXY; 174 } 175 346 176 if (k5_reply.length) { 347 177 *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length); 348 178 krb5_data_free(&k5_reply); 349 179 } else { 350 *reply = data_blob(NULL, 0); 351 } 352 return true; 180 *reply = data_blob(NULL, 0); 181 } 182 return KDC_PROCESS_OK; 183 } 184 185 static void kdc_tcp_call_proxy_done(struct tevent_req *subreq); 186 static void kdc_tcp_call_writev_done(struct tevent_req *subreq); 187 188 static void kdc_tcp_call_loop(struct tevent_req *subreq) 189 { 190 struct kdc_tcp_connection *kdc_conn = tevent_req_callback_data(subreq, 191 struct kdc_tcp_connection); 192 struct kdc_tcp_call *call; 193 NTSTATUS status; 194 enum kdc_process_ret ret; 195 196 call = talloc(kdc_conn, struct kdc_tcp_call); 197 if (call == NULL) { 198 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " 199 "no memory for kdc_tcp_call"); 200 return; 201 } 202 call->kdc_conn = kdc_conn; 203 204 status = tstream_read_pdu_blob_recv(subreq, 205 call, 206 &call->in); 207 TALLOC_FREE(subreq); 208 if (!NT_STATUS_IS_OK(status)) { 209 const char *reason; 210 211 reason = talloc_asprintf(call, "kdc_tcp_call_loop: " 212 "tstream_read_pdu_blob_recv() - %s", 213 nt_errstr(status)); 214 if (!reason) { 215 reason = nt_errstr(status); 216 } 217 218 kdc_tcp_terminate_connection(kdc_conn, reason); 219 return; 220 } 221 222 DEBUG(10,("Received krb5 TCP packet of length %lu from %s\n", 223 (long) call->in.length, 224 tsocket_address_string(kdc_conn->conn->remote_address, call))); 225 226 /* skip length header */ 227 call->in.data +=4; 228 call->in.length -= 4; 229 230 /* Call krb5 */ 231 ret = kdc_conn->kdc_socket->process(kdc_conn->kdc_socket->kdc, 232 call, 233 &call->in, 234 &call->out, 235 kdc_conn->conn->remote_address, 236 kdc_conn->conn->local_address, 237 0 /* Stream */); 238 if (ret == KDC_PROCESS_FAILED) { 239 kdc_tcp_terminate_connection(kdc_conn, 240 "kdc_tcp_call_loop: process function failed"); 241 return; 242 } 243 244 if (ret == KDC_PROCESS_PROXY) { 245 uint16_t port; 246 247 if (!kdc_conn->kdc_socket->kdc->am_rodc) { 248 kdc_tcp_terminate_connection(kdc_conn, 249 "kdc_tcp_call_loop: proxying requested when not RODC"); 250 return; 251 } 252 port = tsocket_address_inet_port(kdc_conn->conn->local_address); 253 254 subreq = kdc_tcp_proxy_send(call, 255 kdc_conn->conn->event.ctx, 256 kdc_conn->kdc_socket->kdc, 257 port, 258 call->in); 259 if (subreq == NULL) { 260 kdc_tcp_terminate_connection(kdc_conn, 261 "kdc_tcp_call_loop: kdc_tcp_proxy_send failed"); 262 return; 263 } 264 tevent_req_set_callback(subreq, kdc_tcp_call_proxy_done, call); 265 return; 266 } 267 268 /* First add the length of the out buffer */ 269 RSIVAL(call->out_hdr, 0, call->out.length); 270 call->out_iov[0].iov_base = (char *) call->out_hdr; 271 call->out_iov[0].iov_len = 4; 272 273 call->out_iov[1].iov_base = (char *) call->out.data; 274 call->out_iov[1].iov_len = call->out.length; 275 276 subreq = tstream_writev_queue_send(call, 277 kdc_conn->conn->event.ctx, 278 kdc_conn->tstream, 279 kdc_conn->send_queue, 280 call->out_iov, 2); 281 if (subreq == NULL) { 282 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " 283 "no memory for tstream_writev_queue_send"); 284 return; 285 } 286 tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call); 287 288 /* 289 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), 290 * packet_full_request_u32 provides the pdu length then. 291 */ 292 subreq = tstream_read_pdu_blob_send(kdc_conn, 293 kdc_conn->conn->event.ctx, 294 kdc_conn->tstream, 295 4, /* initial_read_size */ 296 packet_full_request_u32, 297 kdc_conn); 298 if (subreq == NULL) { 299 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " 300 "no memory for tstream_read_pdu_blob_send"); 301 return; 302 } 303 tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); 304 } 305 306 static void kdc_tcp_call_proxy_done(struct tevent_req *subreq) 307 { 308 struct kdc_tcp_call *call = tevent_req_callback_data(subreq, 309 struct kdc_tcp_call); 310 struct kdc_tcp_connection *kdc_conn = call->kdc_conn; 311 NTSTATUS status; 312 313 status = kdc_tcp_proxy_recv(subreq, call, &call->out); 314 TALLOC_FREE(subreq); 315 if (!NT_STATUS_IS_OK(status)) { 316 /* generate an error packet */ 317 status = kdc_proxy_unavailable_error(kdc_conn->kdc_socket->kdc, 318 call, &call->out); 319 } 320 321 if (!NT_STATUS_IS_OK(status)) { 322 const char *reason; 323 324 reason = talloc_asprintf(call, "kdc_tcp_call_proxy_done: " 325 "kdc_proxy_unavailable_error - %s", 326 nt_errstr(status)); 327 if (!reason) { 328 reason = "kdc_tcp_call_proxy_done: kdc_proxy_unavailable_error() failed"; 329 } 330 331 kdc_tcp_terminate_connection(call->kdc_conn, reason); 332 return; 333 } 334 335 /* First add the length of the out buffer */ 336 RSIVAL(call->out_hdr, 0, call->out.length); 337 call->out_iov[0].iov_base = (char *) call->out_hdr; 338 call->out_iov[0].iov_len = 4; 339 340 call->out_iov[1].iov_base = (char *) call->out.data; 341 call->out_iov[1].iov_len = call->out.length; 342 343 subreq = tstream_writev_queue_send(call, 344 kdc_conn->conn->event.ctx, 345 kdc_conn->tstream, 346 kdc_conn->send_queue, 347 call->out_iov, 2); 348 if (subreq == NULL) { 349 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " 350 "no memory for tstream_writev_queue_send"); 351 return; 352 } 353 tevent_req_set_callback(subreq, kdc_tcp_call_writev_done, call); 354 355 /* 356 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), 357 * packet_full_request_u32 provides the pdu length then. 358 */ 359 subreq = tstream_read_pdu_blob_send(kdc_conn, 360 kdc_conn->conn->event.ctx, 361 kdc_conn->tstream, 362 4, /* initial_read_size */ 363 packet_full_request_u32, 364 kdc_conn); 365 if (subreq == NULL) { 366 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_call_loop: " 367 "no memory for tstream_read_pdu_blob_send"); 368 return; 369 } 370 tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); 371 } 372 373 static void kdc_tcp_call_writev_done(struct tevent_req *subreq) 374 { 375 struct kdc_tcp_call *call = tevent_req_callback_data(subreq, 376 struct kdc_tcp_call); 377 int sys_errno; 378 int rc; 379 380 rc = tstream_writev_queue_recv(subreq, &sys_errno); 381 TALLOC_FREE(subreq); 382 if (rc == -1) { 383 const char *reason; 384 385 reason = talloc_asprintf(call, "kdc_tcp_call_writev_done: " 386 "tstream_writev_queue_recv() - %d:%s", 387 sys_errno, strerror(sys_errno)); 388 if (!reason) { 389 reason = "kdc_tcp_call_writev_done: tstream_writev_queue_recv() failed"; 390 } 391 392 kdc_tcp_terminate_connection(call->kdc_conn, reason); 393 return; 394 } 395 396 /* We don't care about errors */ 397 398 talloc_free(call); 353 399 } 354 400 … … 356 402 called when we get a new connection 357 403 */ 358 static void kdc_tcp_generic_accept(struct stream_connection *conn, kdc_process_fn_t process_fn)359 {360 struct kdc_server *kdc = talloc_get_type(conn->private_data, struct kdc_server);361 struct kdc_tcp_connection *kdcconn;362 363 kdcconn = talloc_zero(conn, struct kdc_tcp_connection);364 if (!kdcconn) {365 stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");366 return;367 }368 kdcconn->conn = conn;369 kdcconn->kdc = kdc;370 kdcconn->process = process_fn;371 conn->private_data = kdcconn;372 373 kdcconn->packet = packet_init(kdcconn);374 if (kdcconn->packet == NULL) {375 kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory");376 return;377 }378 packet_set_private(kdcconn->packet, kdcconn);379 packet_set_socket(kdcconn->packet, conn->socket);380 packet_set_callback(kdcconn->packet, kdc_tcp_recv);381 packet_set_full_request(kdcconn->packet, packet_full_request_u32);382 packet_set_error_handler(kdcconn->packet, kdc_tcp_recv_error);383 packet_set_event_context(kdcconn->packet, conn->event.ctx);384 packet_set_fde(kdcconn->packet, conn->event.fde);385 packet_set_serialise(kdcconn->packet);386 }387 388 404 static void kdc_tcp_accept(struct stream_connection *conn) 389 405 { 390 kdc_tcp_generic_accept(conn, kdc_process); 406 struct kdc_socket *kdc_socket; 407 struct kdc_tcp_connection *kdc_conn; 408 struct tevent_req *subreq; 409 int rc; 410 411 kdc_conn = talloc_zero(conn, struct kdc_tcp_connection); 412 if (kdc_conn == NULL) { 413 stream_terminate_connection(conn, 414 "kdc_tcp_accept: out of memory"); 415 return; 416 } 417 418 kdc_conn->send_queue = tevent_queue_create(conn, "kdc_tcp_accept"); 419 if (kdc_conn->send_queue == NULL) { 420 stream_terminate_connection(conn, 421 "kdc_tcp_accept: out of memory"); 422 return; 423 } 424 425 kdc_socket = talloc_get_type(conn->private_data, struct kdc_socket); 426 427 TALLOC_FREE(conn->event.fde); 428 429 rc = tstream_bsd_existing_socket(kdc_conn, 430 socket_get_fd(conn->socket), 431 &kdc_conn->tstream); 432 if (rc < 0) { 433 stream_terminate_connection(conn, 434 "kdc_tcp_accept: out of memory"); 435 return; 436 } 437 438 kdc_conn->conn = conn; 439 kdc_conn->kdc_socket = kdc_socket; 440 conn->private_data = kdc_conn; 441 442 /* 443 * The krb5 tcp pdu's has the length as 4 byte (initial_read_size), 444 * packet_full_request_u32 provides the pdu length then. 445 */ 446 subreq = tstream_read_pdu_blob_send(kdc_conn, 447 kdc_conn->conn->event.ctx, 448 kdc_conn->tstream, 449 4, /* initial_read_size */ 450 packet_full_request_u32, 451 kdc_conn); 452 if (subreq == NULL) { 453 kdc_tcp_terminate_connection(kdc_conn, "kdc_tcp_accept: " 454 "no memory for tstream_read_pdu_blob_send"); 455 return; 456 } 457 tevent_req_set_callback(subreq, kdc_tcp_call_loop, kdc_conn); 391 458 } 392 459 … … 394 461 .name = "kdc_tcp", 395 462 .accept_connection = kdc_tcp_accept, 396 .recv_handler = kdc_tcp_recv _handler,463 .recv_handler = kdc_tcp_recv, 397 464 .send_handler = kdc_tcp_send 398 465 }; 399 466 400 static void kpasswdd_tcp_accept(struct stream_connection *conn) 401 { 402 kdc_tcp_generic_accept(conn, kpasswdd_process); 403 } 404 405 static const struct stream_server_ops kpasswdd_tcp_stream_ops = { 406 .name = "kpasswdd_tcp", 407 .accept_connection = kpasswdd_tcp_accept, 408 .recv_handler = kdc_tcp_recv_handler, 409 .send_handler = kdc_tcp_send 467 /* hold information about one kdc/kpasswd udp socket */ 468 struct kdc_udp_socket { 469 struct kdc_socket *kdc_socket; 470 struct tdgram_context *dgram; 471 struct tevent_queue *send_queue; 410 472 }; 473 474 struct kdc_udp_call { 475 struct kdc_udp_socket *sock; 476 struct tsocket_address *src; 477 DATA_BLOB in; 478 DATA_BLOB out; 479 }; 480 481 static void kdc_udp_call_proxy_done(struct tevent_req *subreq); 482 static void kdc_udp_call_sendto_done(struct tevent_req *subreq); 483 484 static void kdc_udp_call_loop(struct tevent_req *subreq) 485 { 486 struct kdc_udp_socket *sock = tevent_req_callback_data(subreq, 487 struct kdc_udp_socket); 488 struct kdc_udp_call *call; 489 uint8_t *buf; 490 ssize_t len; 491 int sys_errno; 492 enum kdc_process_ret ret; 493 494 call = talloc(sock, struct kdc_udp_call); 495 if (call == NULL) { 496 talloc_free(call); 497 goto done; 498 } 499 call->sock = sock; 500 501 len = tdgram_recvfrom_recv(subreq, &sys_errno, 502 call, &buf, &call->src); 503 TALLOC_FREE(subreq); 504 if (len == -1) { 505 talloc_free(call); 506 goto done; 507 } 508 509 call->in.data = buf; 510 call->in.length = len; 511 512 DEBUG(10,("Received krb5 UDP packet of length %lu from %s\n", 513 (long)call->in.length, 514 tsocket_address_string(call->src, call))); 515 516 /* Call krb5 */ 517 ret = sock->kdc_socket->process(sock->kdc_socket->kdc, 518 call, 519 &call->in, 520 &call->out, 521 call->src, 522 sock->kdc_socket->local_address, 523 1 /* Datagram */); 524 if (ret == KDC_PROCESS_FAILED) { 525 talloc_free(call); 526 goto done; 527 } 528 529 if (ret == KDC_PROCESS_PROXY) { 530 uint16_t port; 531 532 if (!sock->kdc_socket->kdc->am_rodc) { 533 DEBUG(0,("kdc_udp_call_loop: proxying requested when not RODC")); 534 talloc_free(call); 535 goto done; 536 } 537 538 port = tsocket_address_inet_port(sock->kdc_socket->local_address); 539 540 subreq = kdc_udp_proxy_send(call, 541 sock->kdc_socket->kdc->task->event_ctx, 542 sock->kdc_socket->kdc, 543 port, 544 call->in); 545 if (subreq == NULL) { 546 talloc_free(call); 547 goto done; 548 } 549 tevent_req_set_callback(subreq, kdc_udp_call_proxy_done, call); 550 goto done; 551 } 552 553 subreq = tdgram_sendto_queue_send(call, 554 sock->kdc_socket->kdc->task->event_ctx, 555 sock->dgram, 556 sock->send_queue, 557 call->out.data, 558 call->out.length, 559 call->src); 560 if (subreq == NULL) { 561 talloc_free(call); 562 goto done; 563 } 564 tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call); 565 566 done: 567 subreq = tdgram_recvfrom_send(sock, 568 sock->kdc_socket->kdc->task->event_ctx, 569 sock->dgram); 570 if (subreq == NULL) { 571 task_server_terminate(sock->kdc_socket->kdc->task, 572 "no memory for tdgram_recvfrom_send", 573 true); 574 return; 575 } 576 tevent_req_set_callback(subreq, kdc_udp_call_loop, sock); 577 } 578 579 static void kdc_udp_call_proxy_done(struct tevent_req *subreq) 580 { 581 struct kdc_udp_call *call = 582 tevent_req_callback_data(subreq, 583 struct kdc_udp_call); 584 NTSTATUS status; 585 586 status = kdc_udp_proxy_recv(subreq, call, &call->out); 587 TALLOC_FREE(subreq); 588 if (!NT_STATUS_IS_OK(status)) { 589 /* generate an error packet */ 590 status = kdc_proxy_unavailable_error(call->sock->kdc_socket->kdc, 591 call, &call->out); 592 } 593 594 if (!NT_STATUS_IS_OK(status)) { 595 talloc_free(call); 596 return; 597 } 598 599 subreq = tdgram_sendto_queue_send(call, 600 call->sock->kdc_socket->kdc->task->event_ctx, 601 call->sock->dgram, 602 call->sock->send_queue, 603 call->out.data, 604 call->out.length, 605 call->src); 606 if (subreq == NULL) { 607 talloc_free(call); 608 return; 609 } 610 611 tevent_req_set_callback(subreq, kdc_udp_call_sendto_done, call); 612 } 613 614 static void kdc_udp_call_sendto_done(struct tevent_req *subreq) 615 { 616 struct kdc_udp_call *call = tevent_req_callback_data(subreq, 617 struct kdc_udp_call); 618 ssize_t ret; 619 int sys_errno; 620 621 ret = tdgram_sendto_queue_recv(subreq, &sys_errno); 622 623 /* We don't care about errors */ 624 625 talloc_free(call); 626 } 411 627 412 628 /* 413 629 start listening on the given address 414 630 */ 415 static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address, 416 uint16_t kdc_port, uint16_t kpasswd_port) 417 { 418 const struct model_ops *model_ops; 419 struct kdc_socket *kdc_socket; 420 struct kdc_socket *kpasswd_socket; 421 struct socket_address *kdc_address, *kpasswd_address; 631 static NTSTATUS kdc_add_socket(struct kdc_server *kdc, 632 const struct model_ops *model_ops, 633 const char *name, 634 const char *address, 635 uint16_t port, 636 kdc_process_fn_t process, 637 bool udp_only) 638 { 639 struct kdc_socket *kdc_socket; 640 struct kdc_udp_socket *kdc_udp_socket; 641 struct tevent_req *udpsubreq; 422 642 NTSTATUS status; 643 int ret; 423 644 424 645 kdc_socket = talloc(kdc, struct kdc_socket); 425 646 NT_STATUS_HAVE_NO_MEMORY(kdc_socket); 426 647 427 kpasswd_socket = talloc(kdc, struct kdc_socket); 428 NT_STATUS_HAVE_NO_MEMORY(kpasswd_socket); 429 430 status = socket_create("ip", SOCKET_TYPE_DGRAM, &kdc_socket->sock, 0); 431 if (!NT_STATUS_IS_OK(status)) { 432 talloc_free(kdc_socket); 648 kdc_socket->kdc = kdc; 649 kdc_socket->process = process; 650 651 ret = tsocket_address_inet_from_strings(kdc_socket, "ip", 652 address, port, 653 &kdc_socket->local_address); 654 if (ret != 0) { 655 status = map_nt_error_from_unix(errno); 433 656 return status; 434 657 } 435 658 436 status = socket_create("ip", SOCKET_TYPE_DGRAM, &kpasswd_socket->sock, 0); 437 if (!NT_STATUS_IS_OK(status)) { 438 talloc_free(kpasswd_socket); 659 if (!udp_only) { 660 status = stream_setup_socket(kdc->task, 661 kdc->task->event_ctx, 662 kdc->task->lp_ctx, 663 model_ops, 664 &kdc_tcp_stream_ops, 665 "ip", address, &port, 666 lpcfg_socket_options(kdc->task->lp_ctx), 667 kdc_socket); 668 if (!NT_STATUS_IS_OK(status)) { 669 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", 670 address, port, nt_errstr(status))); 671 talloc_free(kdc_socket); 672 return status; 673 } 674 } 675 676 kdc_udp_socket = talloc(kdc_socket, struct kdc_udp_socket); 677 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket); 678 679 kdc_udp_socket->kdc_socket = kdc_socket; 680 681 ret = tdgram_inet_udp_socket(kdc_socket->local_address, 682 NULL, 683 kdc_udp_socket, 684 &kdc_udp_socket->dgram); 685 if (ret != 0) { 686 status = map_nt_error_from_unix(errno); 687 DEBUG(0,("Failed to bind to %s:%u UDP - %s\n", 688 address, port, nt_errstr(status))); 439 689 return status; 440 690 } 441 691 442 kdc_socket->kdc = kdc; 443 kdc_socket->send_queue = NULL; 444 kdc_socket->process = kdc_process; 445 446 talloc_steal(kdc_socket, kdc_socket->sock); 447 448 kdc_socket->fde = event_add_fd(kdc->task->event_ctx, kdc, 449 socket_get_fd(kdc_socket->sock), EVENT_FD_READ, 450 kdc_socket_handler, kdc_socket); 451 452 kdc_address = socket_address_from_strings(kdc_socket, kdc_socket->sock->backend_name, 453 address, kdc_port); 454 NT_STATUS_HAVE_NO_MEMORY(kdc_address); 455 456 status = socket_listen(kdc_socket->sock, kdc_address, 0, 0); 457 if (!NT_STATUS_IS_OK(status)) { 458 DEBUG(0,("Failed to bind to %s:%d UDP for kdc - %s\n", 459 address, kdc_port, nt_errstr(status))); 460 talloc_free(kdc_socket); 461 return status; 462 } 463 464 kpasswd_socket->kdc = kdc; 465 kpasswd_socket->send_queue = NULL; 466 kpasswd_socket->process = kpasswdd_process; 467 468 talloc_steal(kpasswd_socket, kpasswd_socket->sock); 469 470 kpasswd_socket->fde = event_add_fd(kdc->task->event_ctx, kdc, 471 socket_get_fd(kpasswd_socket->sock), EVENT_FD_READ, 472 kdc_socket_handler, kpasswd_socket); 473 474 kpasswd_address = socket_address_from_strings(kpasswd_socket, kpasswd_socket->sock->backend_name, 475 address, kpasswd_port); 476 NT_STATUS_HAVE_NO_MEMORY(kpasswd_address); 477 478 status = socket_listen(kpasswd_socket->sock, kpasswd_address, 0, 0); 479 if (!NT_STATUS_IS_OK(status)) { 480 DEBUG(0,("Failed to bind to %s:%d UDP for kpasswd - %s\n", 481 address, kpasswd_port, nt_errstr(status))); 482 talloc_free(kpasswd_socket); 483 return status; 484 } 485 486 /* within the kdc task we want to be a single process, so 487 ask for the single process model ops and pass these to the 488 stream_setup_socket() call. */ 489 model_ops = process_model_startup(kdc->task->event_ctx, "single"); 490 if (!model_ops) { 491 DEBUG(0,("Can't find 'single' process model_ops\n")); 492 talloc_free(kdc_socket); 493 return NT_STATUS_INTERNAL_ERROR; 494 } 495 496 status = stream_setup_socket(kdc->task->event_ctx, 497 kdc->task->lp_ctx, 498 model_ops, 499 &kdc_tcp_stream_ops, 500 "ip", address, &kdc_port, 501 lp_socket_options(kdc->task->lp_ctx), 502 kdc); 503 if (!NT_STATUS_IS_OK(status)) { 504 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", 505 address, kdc_port, nt_errstr(status))); 506 talloc_free(kdc_socket); 507 return status; 508 } 509 510 status = stream_setup_socket(kdc->task->event_ctx, 511 kdc->task->lp_ctx, 512 model_ops, 513 &kpasswdd_tcp_stream_ops, 514 "ip", address, &kpasswd_port, 515 lp_socket_options(kdc->task->lp_ctx), 516 kdc); 517 if (!NT_STATUS_IS_OK(status)) { 518 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n", 519 address, kpasswd_port, nt_errstr(status))); 520 talloc_free(kdc_socket); 521 return status; 522 } 692 kdc_udp_socket->send_queue = tevent_queue_create(kdc_udp_socket, 693 "kdc_udp_send_queue"); 694 NT_STATUS_HAVE_NO_MEMORY(kdc_udp_socket->send_queue); 695 696 udpsubreq = tdgram_recvfrom_send(kdc_udp_socket, 697 kdc->task->event_ctx, 698 kdc_udp_socket->dgram); 699 NT_STATUS_HAVE_NO_MEMORY(udpsubreq); 700 tevent_req_set_callback(udpsubreq, kdc_udp_call_loop, kdc_udp_socket); 523 701 524 702 return NT_STATUS_OK; … … 532 710 struct interface *ifaces) 533 711 { 712 const struct model_ops *model_ops; 534 713 int num_interfaces; 535 714 TALLOC_CTX *tmp_ctx = talloc_new(kdc); 536 715 NTSTATUS status; 537 716 int i; 717 uint16_t kdc_port = lpcfg_krb5_port(lp_ctx); 718 uint16_t kpasswd_port = lpcfg_kpasswd_port(lp_ctx); 719 bool done_wildcard = false; 720 721 /* within the kdc task we want to be a single process, so 722 ask for the single process model ops and pass these to the 723 stream_setup_socket() call. */ 724 model_ops = process_model_startup("single"); 725 if (!model_ops) { 726 DEBUG(0,("Can't find 'single' process model_ops\n")); 727 return NT_STATUS_INTERNAL_ERROR; 728 } 538 729 539 730 num_interfaces = iface_count(ifaces); 540 731 732 /* if we are allowing incoming packets from any address, then 733 we need to bind to the wildcard address */ 734 if (!lpcfg_bind_interfaces_only(lp_ctx)) { 735 if (kdc_port) { 736 status = kdc_add_socket(kdc, model_ops, 737 "kdc", "0.0.0.0", kdc_port, 738 kdc_process, false); 739 NT_STATUS_NOT_OK_RETURN(status); 740 } 741 742 if (kpasswd_port) { 743 status = kdc_add_socket(kdc, model_ops, 744 "kpasswd", "0.0.0.0", kpasswd_port, 745 kpasswdd_process, false); 746 NT_STATUS_NOT_OK_RETURN(status); 747 } 748 done_wildcard = true; 749 } 750 541 751 for (i=0; i<num_interfaces; i++) { 542 752 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i)); 543 status = kdc_add_socket(kdc, address, lp_krb5_port(lp_ctx), 544 lp_kpasswd_port(lp_ctx)); 545 NT_STATUS_NOT_OK_RETURN(status); 753 754 if (kdc_port) { 755 status = kdc_add_socket(kdc, model_ops, 756 "kdc", address, kdc_port, 757 kdc_process, done_wildcard); 758 NT_STATUS_NOT_OK_RETURN(status); 759 } 760 761 if (kpasswd_port) { 762 status = kdc_add_socket(kdc, model_ops, 763 "kpasswd", address, kpasswd_port, 764 kpasswdd_process, done_wildcard); 765 NT_STATUS_NOT_OK_RETURN(status); 766 } 546 767 } 547 768 … … 552 773 553 774 554 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 775 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 555 776 struct kdc_check_generic_kerberos *r) 556 777 { … … 570 791 r->out.generic_reply = data_blob(NULL, 0); 571 792 572 ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, 573 lp_iconv_convenience(kdc->task->lp_ctx), 574 &pac_validate, 793 ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, &pac_validate, 575 794 (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate); 576 795 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 577 796 return NT_STATUS_INVALID_PARAMETER; 578 797 } 579 798 580 799 if (pac_validate.MessageType != 3) { 581 800 /* We don't implement any other message types - such as certificate validation - yet */ … … 588 807 return NT_STATUS_INVALID_PARAMETER; 589 808 } 590 591 srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, 809 810 srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, 592 811 pac_validate.ChecksumLength); 593 812 594 813 if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) { 595 814 etype = ETYPE_ARCFOUR_HMAC_MD5; … … 602 821 } 603 822 604 ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, 605 lp _realm(kdc->task->lp_ctx),606 "krbtgt", lp _realm(kdc->task->lp_ctx),823 ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, 824 lpcfg_realm(kdc->task->lp_ctx), 825 "krbtgt", lpcfg_realm(kdc->task->lp_ctx), 607 826 NULL); 608 827 … … 611 830 } 612 831 613 ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, 614 kdc->config->db[0], 615 principal, 616 HDB_F_GET_KRBTGT | HDB_F_DECRYPT, 617 &ent); 618 832 ret = kdc->config->db[0]->hdb_fetch_kvno(kdc->smb_krb5_context->krb5_context, 833 kdc->config->db[0], 834 principal, 835 HDB_F_GET_KRBTGT | HDB_F_DECRYPT, 836 0, 837 &ent); 838 619 839 if (ret != 0) { 620 840 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent); 621 841 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal); 622 842 623 843 return NT_STATUS_LOGON_FAILURE; 624 844 } 625 845 626 846 ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key); 627 847 … … 633 853 634 854 keyblock = key->key; 635 855 636 856 kdc_sig.type = pac_validate.SignatureType; 637 857 kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength], 638 858 pac_validate.SignatureLength); 639 ret = check_pac_checksum(msg, srv_sig, &kdc_sig, 859 ret = check_pac_checksum(msg, srv_sig, &kdc_sig, 640 860 kdc->smb_krb5_context->krb5_context, &keyblock); 641 861 … … 646 866 return NT_STATUS_LOGON_FAILURE; 647 867 } 648 868 649 869 return NT_STATUS_OK; 650 870 } … … 660 880 krb5_error_code ret; 661 881 struct interface *ifaces; 662 663 switch (lp_server_role(task->lp_ctx)) { 882 int ldb_ret; 883 884 switch (lpcfg_server_role(task->lp_ctx)) { 664 885 case ROLE_STANDALONE: 665 886 task_server_terminate(task, "kdc: no KDC required in standalone configuration", false); … … 673 894 } 674 895 675 load_interfaces(task, lp _interfaces(task->lp_ctx), &ifaces);896 load_interfaces(task, lpcfg_interfaces(task->lp_ctx), &ifaces); 676 897 677 898 if (iface_count(ifaces) == 0) { … … 682 903 task_server_set_title(task, "task[kdc]"); 683 904 684 kdc = talloc (task, struct kdc_server);905 kdc = talloc_zero(task, struct kdc_server); 685 906 if (kdc == NULL) { 686 907 task_server_terminate(task, "kdc: out of memory", true); … … 690 911 kdc->task = task; 691 912 913 914 /* get a samdb connection */ 915 kdc->samdb = samdb_connect(kdc, kdc->task->event_ctx, kdc->task->lp_ctx, 916 system_session(kdc->task->lp_ctx), 0); 917 if (!kdc->samdb) { 918 DEBUG(1,("kdc_task_init: unable to connect to samdb\n")); 919 task_server_terminate(task, "kdc: krb5_init_context samdb connect failed", true); 920 return; 921 } 922 923 ldb_ret = samdb_rodc(kdc->samdb, &kdc->am_rodc); 924 if (ldb_ret != LDB_SUCCESS) { 925 DEBUG(1, ("kdc_task_init: Cannot determine if we are an RODC: %s\n", 926 ldb_errstring(kdc->samdb))); 927 task_server_terminate(task, "kdc: krb5_init_context samdb RODC connect failed", true); 928 return; 929 } 930 931 kdc->proxy_timeout = lpcfg_parm_int(kdc->task->lp_ctx, NULL, "kdc", "proxy timeout", 5); 932 692 933 initialize_krb5_error_table(); 693 934 694 935 ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context); 695 936 if (ret) { 696 DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", 937 DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", 697 938 error_message(ret))); 698 939 task_server_terminate(task, "kdc: krb5_init_context failed", true); 699 return; 940 return; 700 941 } 701 942 702 943 krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r); 703 944 704 ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 945 ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 705 946 &kdc->config); 706 947 if(ret) { … … 708 949 return; 709 950 } 710 951 711 952 kdc->config->logf = kdc->smb_krb5_context->logf; 712 953 kdc->config->db = talloc(kdc, struct HDB *); … … 716 957 } 717 958 kdc->config->num_db = 1; 718 719 status = hdb_samba4_create_kdc(kdc, task->event_ctx, task->lp_ctx, 720 kdc->smb_krb5_context->krb5_context, 959 960 /* Register hdb-samba4 hooks for use as a keytab */ 961 962 kdc->base_ctx = talloc_zero(kdc, struct samba_kdc_base_context); 963 if (!kdc->base_ctx) { 964 task_server_terminate(task, "kdc: out of memory", true); 965 return; 966 } 967 968 kdc->base_ctx->ev_ctx = task->event_ctx; 969 kdc->base_ctx->lp_ctx = task->lp_ctx; 970 971 status = hdb_samba4_create_kdc(kdc->base_ctx, 972 kdc->smb_krb5_context->krb5_context, 721 973 &kdc->config->db[0]); 722 974 if (!NT_STATUS_IS_OK(status)) { 723 975 task_server_terminate(task, "kdc: hdb_samba4_create_kdc (setup KDC database) failed", true); 724 return; 725 } 726 727 /* Register hdb-samba4 hooks for use as a keytab */ 728 729 kdc->hdb_samba4_context = talloc(kdc, struct hdb_samba4_context); 730 if (!kdc->hdb_samba4_context) { 731 task_server_terminate(task, "kdc: out of memory", true); 732 return; 733 } 734 735 kdc->hdb_samba4_context->ev_ctx = task->event_ctx; 736 kdc->hdb_samba4_context->lp_ctx = task->lp_ctx; 737 738 ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 976 return; 977 } 978 979 ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 739 980 PLUGIN_TYPE_DATA, "hdb", 740 981 &hdb_samba4); 741 982 if(ret) { 742 task_server_terminate(task, "kdc: failed to register hdb keytab", true);983 task_server_terminate(task, "kdc: failed to register hdb plugin", true); 743 984 return; 744 985 } … … 746 987 ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops); 747 988 if(ret) { 748 task_server_terminate(task, "kdc: failed to register hdb keytab", true);749 return; 750 } 751 752 /* Regist ar WinDC hooks */753 ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 989 task_server_terminate(task, "kdc: failed to register keytab plugin", true); 990 return; 991 } 992 993 /* Register WinDC hooks */ 994 ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 754 995 PLUGIN_TYPE_DATA, "windc", 755 996 &windc_plugin_table); 756 997 if(ret) { 757 task_server_terminate(task, "kdc: failed to register hdb keytab", true); 758 return; 759 } 760 761 krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context); 998 task_server_terminate(task, "kdc: failed to register windc plugin", true); 999 return; 1000 } 1001 1002 ret = krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context); 1003 1004 if(ret) { 1005 task_server_terminate(task, "kdc: failed to init windc plugin", true); 1006 return; 1007 } 1008 1009 ret = krb5_kdc_pkinit_config(kdc->smb_krb5_context->krb5_context, kdc->config); 1010 1011 if(ret) { 1012 task_server_terminate(task, "kdc: failed to init kdc pkinit subsystem", true); 1013 return; 1014 } 762 1015 763 1016 /* start listening on the configured network interfaces */ … … 768 1021 } 769 1022 770 status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, 1023 status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, 771 1024 kdc_check_generic_kerberos, kdc); 772 1025 if (!NT_STATUS_IS_OK(status)) { 773 task_server_terminate(task, " nbtdfailed to setup monitoring", true);1026 task_server_terminate(task, "kdc failed to setup monitoring", true); 774 1027 return; 775 1028 } -
vendor/current/source4/kdc/kpasswdd.c
r414 r740 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 … … 11 11 the Free Software Foundation; either version 3 of the License, or 12 12 (at your option) any later version. 13 13 14 14 This program is distributed in the hope that it will be useful, 15 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 17 GNU General Public License for more details. 18 18 19 19 You should have received a copy of the GNU General Public License 20 20 along with this program. If not, see <http://www.gnu.org/licenses/>. … … 23 23 #include "includes.h" 24 24 #include "smbd/service_task.h" 25 #include "lib/events/events.h"26 #include "lib/socket/socket.h"27 #include "system/network.h"28 #include "../lib/util/dlinklist.h"29 #include "lib/ldb/include/ldb.h"30 25 #include "auth/gensec/gensec.h" 31 26 #include "auth/credentials/credentials.h" 32 #include "auth/credentials/credentials_krb5.h"33 27 #include "auth/auth.h" 34 28 #include "dsdb/samdb/samdb.h" 35 #include "rpc_server/dcerpc_server.h" 36 #include "rpc_server/samr/proto.h" 29 #include "../lib/util/util_ldb.h" 37 30 #include "libcli/security/security.h" 38 31 #include "param/param.h" 39 #include "kdc/kdc.h" 40 41 /* TODO: remove all SAMBA4_INTERNAL_HEIMDAL stuff from this file */ 42 #ifdef SAMBA4_INTERNAL_HEIMDAL 43 #include "heimdal_build/kpasswdd-glue.h" 44 #endif 45 46 /* hold information about one kdc socket */ 47 struct kpasswd_socket { 48 struct socket_context *sock; 49 struct kdc_server *kdc; 50 struct tevent_fd *fde; 51 52 /* a queue of outgoing replies that have been deferred */ 53 struct kdc_reply *send_queue; 54 }; 32 #include "kdc/kdc-glue.h" 55 33 56 34 /* Return true if there is a valid error packet formed in the error_blob */ 57 static bool kpasswdd_make_error_reply(struct kdc_server *kdc, 58 TALLOC_CTX *mem_ctx, 59 uint16_t result_code, 60 const char *error_string, 61 DATA_BLOB *error_blob) 35 static bool kpasswdd_make_error_reply(struct kdc_server *kdc, 36 TALLOC_CTX *mem_ctx, 37 uint16_t result_code, 38 const char *error_string, 39 DATA_BLOB *error_blob) 62 40 { 63 41 char *error_string_utf8; 64 42 size_t len; 65 43 66 44 DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string)); 67 45 … … 80 58 81 59 /* Return true if there is a valid error packet formed in the error_blob */ 82 static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, 83 TALLOC_CTX *mem_ctx, 84 uint16_t result_code, 85 const char *error_string, 86 DATA_BLOB *error_blob) 60 static bool kpasswdd_make_unauth_error_reply(struct kdc_server *kdc, 61 TALLOC_CTX *mem_ctx, 62 uint16_t result_code, 63 const char *error_string, 64 DATA_BLOB *error_blob) 87 65 { 88 66 bool ret; … … 90 68 DATA_BLOB error_bytes; 91 69 krb5_data k5_error_bytes, k5_error_blob; 92 ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string, 70 ret = kpasswdd_make_error_reply(kdc, mem_ctx, result_code, error_string, 93 71 &error_bytes); 94 72 if (!ret) { … … 98 76 k5_error_bytes.length = error_bytes.length; 99 77 kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context, 100 result_code, NULL, &k5_error_bytes, 78 result_code, NULL, &k5_error_bytes, 101 79 NULL, NULL, NULL, NULL, &k5_error_blob); 102 80 if (kret) { … … 111 89 } 112 90 113 static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, 114 TALLOC_CTX *mem_ctx, 115 NTSTATUS status, 116 enum sam r_RejectReason reject_reason,91 static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, 92 TALLOC_CTX *mem_ctx, 93 NTSTATUS status, 94 enum samPwdChangeReason reject_reason, 117 95 struct samr_DomInfo1 *dominfo, 118 DATA_BLOB *error_blob) 96 DATA_BLOB *error_blob) 119 97 { 120 98 if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { 121 return kpasswdd_make_error_reply(kdc, mem_ctx, 99 return kpasswdd_make_error_reply(kdc, mem_ctx, 122 100 KRB5_KPASSWD_ACCESSDENIED, 123 101 "No such user when changing password", … … 125 103 } 126 104 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { 127 return kpasswdd_make_error_reply(kdc, mem_ctx, 105 return kpasswdd_make_error_reply(kdc, mem_ctx, 128 106 KRB5_KPASSWD_ACCESSDENIED, 129 107 "Not permitted to change password", … … 133 111 const char *reject_string; 134 112 switch (reject_reason) { 135 case SAM R_REJECT_TOO_SHORT:113 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT: 136 114 reject_string = talloc_asprintf(mem_ctx, "Password too short, password must be at least %d characters long", 137 115 dominfo->min_password_length); 138 116 break; 139 case SAM R_REJECT_COMPLEXITY:117 case SAM_PWD_CHANGE_NOT_COMPLEX: 140 118 reject_string = "Password does not meet complexity requirements"; 141 119 break; 142 case SAM R_REJECT_IN_HISTORY:120 case SAM_PWD_CHANGE_PWD_IN_HISTORY: 143 121 reject_string = "Password is already in password history"; 144 122 break; 145 case SAMR_REJECT_OTHER:146 123 default: 147 124 reject_string = talloc_asprintf(mem_ctx, "Password must be at least %d characters long, and cannot match any of your %d previous passwords", … … 149 126 break; 150 127 } 151 return kpasswdd_make_error_reply(kdc, mem_ctx, 128 return kpasswdd_make_error_reply(kdc, mem_ctx, 152 129 KRB5_KPASSWD_SOFTERROR, 153 130 reject_string, … … 155 132 } 156 133 if (!NT_STATUS_IS_OK(status)) { 157 return kpasswdd_make_error_reply(kdc, mem_ctx, 134 return kpasswdd_make_error_reply(kdc, mem_ctx, 158 135 KRB5_KPASSWD_HARDERROR, 159 136 talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)), 160 137 error_blob); 161 138 162 139 } 163 140 return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS, … … 166 143 } 167 144 168 /* 145 /* 169 146 A user password change 170 171 Return true if there is a valid error packet (or suc ess) formed in147 148 Return true if there is a valid error packet (or success) formed in 172 149 the error_blob 173 150 */ 174 151 static bool kpasswdd_change_password(struct kdc_server *kdc, 175 TALLOC_CTX *mem_ctx, 152 TALLOC_CTX *mem_ctx, 176 153 struct auth_session_info *session_info, 177 154 const DATA_BLOB *password, … … 179 156 { 180 157 NTSTATUS status; 181 enum sam r_RejectReason reject_reason;158 enum samPwdChangeReason reject_reason; 182 159 struct samr_DomInfo1 *dominfo; 160 struct samr_Password *oldLmHash, *oldNtHash; 183 161 struct ldb_context *samdb; 184 185 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, system_session(mem_ctx, kdc->task->lp_ctx)); 162 const char * const attrs[] = { "dBCSPwd", "unicodePwd", NULL }; 163 struct ldb_message **res; 164 int ret; 165 166 /* Fetch the old hashes to get the old password in order to perform 167 * the password change operation. Naturally it would be much better to 168 * have a password hash from an authentication around but this doesn't 169 * seem to be the case here. */ 170 ret = gendb_search(kdc->samdb, mem_ctx, NULL, &res, attrs, 171 "(&(objectClass=user)(sAMAccountName=%s))", 172 session_info->info->account_name); 173 if (ret != 1) { 174 return kpasswdd_make_error_reply(kdc, mem_ctx, 175 KRB5_KPASSWD_ACCESSDENIED, 176 "No such user when changing password", 177 reply); 178 } 179 180 status = samdb_result_passwords(mem_ctx, kdc->task->lp_ctx, res[0], 181 &oldLmHash, &oldNtHash); 182 if (!NT_STATUS_IS_OK(status)) { 183 return kpasswdd_make_error_reply(kdc, mem_ctx, 184 KRB5_KPASSWD_ACCESSDENIED, 185 "Not permitted to change password", 186 reply); 187 } 188 189 /* Start a SAM with user privileges for the password change */ 190 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, 191 session_info, 0); 186 192 if (!samdb) { 187 return kpasswdd_make_error_reply(kdc, mem_ctx, 193 return kpasswdd_make_error_reply(kdc, mem_ctx, 188 194 KRB5_KPASSWD_HARDERROR, 189 195 "Failed to open samdb", 190 196 reply); 191 197 } 192 193 DEBUG(3, ("Changing password of %s\\%s (%s)\n", 194 session_info-> server_info->domain_name,195 session_info-> server_info->account_name,196 dom_sid_string(mem_ctx, session_info->security_token->user_sid)));197 198 /* Userpassword change */199 status = samdb_set_password_sid(samdb, mem_ctx, 200 session_info->security_token->user_sid,201 password, NULL, NULL, 202 true, /* this is a user password change */198 199 DEBUG(3, ("Changing password of %s\\%s (%s)\n", 200 session_info->info->domain_name, 201 session_info->info->account_name, 202 dom_sid_string(mem_ctx, &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]))); 203 204 /* Performs the password change */ 205 status = samdb_set_password_sid(samdb, mem_ctx, 206 &session_info->security_token->sids[PRIMARY_USER_SID_INDEX], 207 password, NULL, NULL, 208 oldLmHash, oldNtHash, /* this is a user password change */ 203 209 &reject_reason, 204 210 &dominfo); 205 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 206 status, 211 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 212 status, 207 213 reject_reason, 208 dominfo, 214 dominfo, 209 215 reply); 210 216 … … 212 218 213 219 static bool kpasswd_process_request(struct kdc_server *kdc, 214 TALLOC_CTX *mem_ctx, 220 TALLOC_CTX *mem_ctx, 215 221 struct gensec_security *gensec_security, 216 222 uint16_t version, 217 DATA_BLOB *input, 223 DATA_BLOB *input, 218 224 DATA_BLOB *reply) 219 225 { … … 221 227 size_t pw_len; 222 228 223 if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, 229 if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, 224 230 &session_info))) { 225 return kpasswdd_make_error_reply(kdc, mem_ctx, 231 return kpasswdd_make_error_reply(kdc, mem_ctx, 226 232 KRB5_KPASSWD_HARDERROR, 227 233 "gensec_session_info failed!", … … 233 239 { 234 240 DATA_BLOB password; 235 if (!convert_string_talloc_convenience(mem_ctx, lp _iconv_convenience(kdc->task->lp_ctx),236 CH_UTF8, CH_UTF16, 237 (const char *)input->data, 241 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(kdc->task->lp_ctx), 242 CH_UTF8, CH_UTF16, 243 (const char *)input->data, 238 244 input->length, 239 245 (void **)&password.data, &pw_len, false)) { … … 241 247 } 242 248 password.length = pw_len; 243 244 return kpasswdd_change_password(kdc, mem_ctx, session_info, 249 250 return kpasswdd_change_password(kdc, mem_ctx, session_info, 245 251 &password, reply); 246 break;247 252 } 248 253 case KRB5_KPASSWD_VERS_SETPW: 249 254 { 250 255 NTSTATUS status; 251 enum sam r_RejectReason reject_reason = SAMR_REJECT_OTHER;256 enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR; 252 257 struct samr_DomInfo1 *dominfo = NULL; 253 258 struct ldb_context *samdb; 254 struct ldb_message *msg;255 259 krb5_context context = kdc->smb_krb5_context->krb5_context; 256 260 … … 261 265 char *set_password_on_princ; 262 266 struct ldb_dn *set_password_on_dn; 267 bool service_principal_name = false; 263 268 264 269 size_t len; 265 270 int ret; 266 267 msg = ldb_msg_new(mem_ctx);268 if (!msg) {269 return false;270 }271 271 272 272 ret = decode_ChangePasswdDataMS(input->data, input->length, 273 273 &chpw, &len); 274 274 if (ret) { 275 return kpasswdd_make_error_reply(kdc, mem_ctx, 275 return kpasswdd_make_error_reply(kdc, mem_ctx, 276 276 KRB5_KPASSWD_MALFORMED, 277 277 "failed to decode password change structure", 278 278 reply); 279 279 } 280 281 if (!convert_string_talloc_convenience(mem_ctx, lp _iconv_convenience(kdc->task->lp_ctx),282 CH_UTF8, CH_UTF16, 283 (const char *)chpw.newpasswd.data, 280 281 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(kdc->task->lp_ctx), 282 CH_UTF8, CH_UTF16, 283 (const char *)chpw.newpasswd.data, 284 284 chpw.newpasswd.length, 285 285 (void **)&password.data, &pw_len, false)) { … … 287 287 return false; 288 288 } 289 289 290 290 password.length = pw_len; 291 292 if ((chpw.targname && !chpw.targrealm) 291 292 if ((chpw.targname && !chpw.targrealm) 293 293 || (!chpw.targname && chpw.targrealm)) { 294 return kpasswdd_make_error_reply(kdc, mem_ctx, 294 free_ChangePasswdDataMS(&chpw); 295 return kpasswdd_make_error_reply(kdc, mem_ctx, 295 296 KRB5_KPASSWD_MALFORMED, 296 297 "Realm and principal must be both present, or neither present", … … 298 299 } 299 300 if (chpw.targname && chpw.targrealm) { 300 #ifdef SAMBA4_INTERNAL_HEIMDAL 301 if (_krb5_principalname2krb5_principal(kdc->smb_krb5_context->krb5_context, 302 &principal, *chpw.targname, 303 *chpw.targrealm) != 0) { 301 ret = krb5_build_principal_ext(kdc->smb_krb5_context->krb5_context, 302 &principal, 303 strlen(*chpw.targrealm), 304 *chpw.targrealm, 0); 305 if (ret) { 304 306 free_ChangePasswdDataMS(&chpw); 305 return kpasswdd_make_error_reply(kdc, mem_ctx, 307 return kpasswdd_make_error_reply(kdc, mem_ctx, 308 KRB5_KPASSWD_MALFORMED, 309 "failed to get principal", 310 reply); 311 } 312 if (copy_PrincipalName(chpw.targname, &principal->name)) { 313 free_ChangePasswdDataMS(&chpw); 314 krb5_free_principal(context, principal); 315 return kpasswdd_make_error_reply(kdc, mem_ctx, 306 316 KRB5_KPASSWD_MALFORMED, 307 317 "failed to extract principal to set", 308 318 reply); 309 310 319 } 311 #else /* SAMBA4_INTERNAL_HEIMDAL */312 return kpasswdd_make_error_reply(kdc, mem_ctx,313 KRB5_KPASSWD_BAD_VERSION,314 "Operation Not Implemented",315 reply);316 #endif /* SAMBA4_INTERNAL_HEIMDAL */317 320 } else { 318 321 free_ChangePasswdDataMS(&chpw); 319 return kpasswdd_change_password(kdc, mem_ctx, session_info, 322 return kpasswdd_change_password(kdc, mem_ctx, session_info, 320 323 &password, reply); 321 324 } 322 325 free_ChangePasswdDataMS(&chpw); 323 326 324 if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) { 325 krb5_free_principal(context, principal); 326 return kpasswdd_make_error_reply(kdc, mem_ctx, 327 KRB5_KPASSWD_MALFORMED, 328 "krb5_unparse_name failed!", 329 reply); 330 } 331 327 if (principal->name.name_string.len >= 2) { 328 service_principal_name = true; 329 330 /* We use this, rather than 'no realm' flag, 331 * as we don't want to accept a password 332 * change on a principal from another realm */ 333 334 if (krb5_unparse_name_short(context, principal, &set_password_on_princ) != 0) { 335 krb5_free_principal(context, principal); 336 return kpasswdd_make_error_reply(kdc, mem_ctx, 337 KRB5_KPASSWD_MALFORMED, 338 "krb5_unparse_name failed!", 339 reply); 340 } 341 } else { 342 if (krb5_unparse_name(context, principal, &set_password_on_princ) != 0) { 343 krb5_free_principal(context, principal); 344 return kpasswdd_make_error_reply(kdc, mem_ctx, 345 KRB5_KPASSWD_MALFORMED, 346 "krb5_unparse_name failed!", 347 reply); 348 } 349 } 332 350 krb5_free_principal(context, principal); 333 334 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info );351 352 samdb = samdb_connect(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info, 0); 335 353 if (!samdb) { 336 return kpasswdd_make_error_reply(kdc, mem_ctx, 354 free(set_password_on_princ); 355 return kpasswdd_make_error_reply(kdc, mem_ctx, 337 356 KRB5_KPASSWD_HARDERROR, 338 357 "Unable to open database!", … … 340 359 } 341 360 342 DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", 343 session_info-> server_info->domain_name,344 session_info-> server_info->account_name,345 dom_sid_string(mem_ctx, session_info->security_token->user_sid),361 DEBUG(3, ("%s\\%s (%s) is changing password of %s\n", 362 session_info->info->domain_name, 363 session_info->info->account_name, 364 dom_sid_string(mem_ctx, &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]), 346 365 set_password_on_princ)); 347 366 ret = ldb_transaction_start(samdb); 348 if (ret) { 367 if (ret != LDB_SUCCESS) { 368 free(set_password_on_princ); 349 369 status = NT_STATUS_TRANSACTION_ABORTED; 350 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 370 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 351 371 status, 352 SAM R_REJECT_OTHER,353 NULL, 372 SAM_PWD_CHANGE_NO_ERROR, 373 NULL, 354 374 reply); 355 375 } 356 376 357 status = crack_user_principal_name(samdb, mem_ctx, 358 set_password_on_princ, 359 &set_password_on_dn, NULL); 377 if (service_principal_name) { 378 status = crack_service_principal_name(samdb, mem_ctx, 379 set_password_on_princ, 380 &set_password_on_dn, NULL); 381 } else { 382 status = crack_user_principal_name(samdb, mem_ctx, 383 set_password_on_princ, 384 &set_password_on_dn, NULL); 385 } 360 386 free(set_password_on_princ); 361 387 if (!NT_STATUS_IS_OK(status)) { 362 388 ldb_transaction_cancel(samdb); 363 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 389 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 364 390 status, 365 SAM R_REJECT_OTHER,366 NULL, 391 SAM_PWD_CHANGE_NO_ERROR, 392 NULL, 367 393 reply); 368 }369 370 msg = ldb_msg_new(mem_ctx);371 if (msg == NULL) {372 ldb_transaction_cancel(samdb);373 status = NT_STATUS_NO_MEMORY;374 } else {375 msg->dn = ldb_dn_copy(msg, set_password_on_dn);376 if (!msg->dn) {377 status = NT_STATUS_NO_MEMORY;378 }379 394 } 380 395 … … 383 398 status = samdb_set_password(samdb, mem_ctx, 384 399 set_password_on_dn, NULL, 385 msg, &password, NULL, NULL,386 false, /* this is not a user password change */400 &password, NULL, NULL, 401 NULL, NULL, /* this is not a user password change */ 387 402 &reject_reason, &dominfo); 388 403 } 389 404 390 if (NT_STATUS_IS_OK(status)) {391 /* modify the samdb record */392 ret = samdb_replace(samdb, mem_ctx, msg);393 if (ret != 0) {394 DEBUG(2,("Failed to modify record to set password on %s: %s\n",395 ldb_dn_get_linearized(msg->dn),396 ldb_errstring(samdb)));397 status = NT_STATUS_ACCESS_DENIED;398 }399 }400 405 if (NT_STATUS_IS_OK(status)) { 401 406 ret = ldb_transaction_commit(samdb); 402 if (ret != 0) {407 if (ret != LDB_SUCCESS) { 403 408 DEBUG(1,("Failed to commit transaction to set password on %s: %s\n", 404 ldb_dn_get_linearized( msg->dn),409 ldb_dn_get_linearized(set_password_on_dn), 405 410 ldb_errstring(samdb))); 406 411 status = NT_STATUS_TRANSACTION_ABORTED; … … 409 414 ldb_transaction_cancel(samdb); 410 415 } 411 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 416 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 412 417 status, 413 reject_reason, 414 dominfo, 418 reject_reason, 419 dominfo, 415 420 reply); 416 421 } 417 422 default: 418 return kpasswdd_make_error_reply(kdc, mem_ctx, 423 return kpasswdd_make_error_reply(kdc, mem_ctx, 419 424 KRB5_KPASSWD_BAD_VERSION, 420 talloc_asprintf(mem_ctx, 421 "Protocol version %u not supported", 425 talloc_asprintf(mem_ctx, 426 "Protocol version %u not supported", 422 427 version), 423 428 reply); 424 429 } 425 return true;426 430 } 427 431 428 boolkpasswdd_process(struct kdc_server *kdc,429 TALLOC_CTX *mem_ctx,430 DATA_BLOB *input,431 DATA_BLOB *reply,432 structsocket_address *peer_addr,433 structsocket_address *my_addr,434 int datagram_reply)432 enum kdc_process_ret kpasswdd_process(struct kdc_server *kdc, 433 TALLOC_CTX *mem_ctx, 434 DATA_BLOB *input, 435 DATA_BLOB *reply, 436 struct tsocket_address *peer_addr, 437 struct tsocket_address *my_addr, 438 int datagram_reply) 435 439 { 436 440 bool ret; … … 452 456 453 457 if (!tmp_ctx) { 454 return false; 458 return KDC_PROCESS_FAILED; 459 } 460 461 if (kdc->am_rodc) { 462 talloc_free(tmp_ctx); 463 return KDC_PROCESS_PROXY; 455 464 } 456 465 … … 459 468 if (input->length <= header_len) { 460 469 talloc_free(tmp_ctx); 461 return false;470 return KDC_PROCESS_FAILED; 462 471 } 463 472 … … 465 474 if (input->length != len) { 466 475 talloc_free(tmp_ctx); 467 return false;476 return KDC_PROCESS_FAILED; 468 477 } 469 478 … … 475 484 if ((ap_req_len >= len) || (ap_req_len + header_len) >= len) { 476 485 talloc_free(tmp_ctx); 477 return false;478 } 479 486 return KDC_PROCESS_FAILED; 487 } 488 480 489 krb_priv_len = len - ap_req_len; 481 490 ap_req = data_blob_const(&input->data[header_len], ap_req_len); 482 491 krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len); 483 492 484 493 server_credentials = cli_credentials_init(tmp_ctx); 485 494 if (!server_credentials) { 486 495 DEBUG(1, ("Failed to init server credentials\n")); 487 return false; 496 talloc_free(tmp_ctx); 497 return KDC_PROCESS_FAILED; 488 498 } 489 499 490 500 /* We want the credentials subsystem to use the krb5 context 491 * we already have, rather than a new context */ 501 * we already have, rather than a new context */ 492 502 cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context); 493 503 cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx); 494 504 495 keytab_name = talloc_asprintf(server_credentials, "HDB:samba4&%p", kdc-> hdb_samba4_context);505 keytab_name = talloc_asprintf(server_credentials, "HDB:samba4&%p", kdc->base_ctx); 496 506 497 507 cli_credentials_set_username(server_credentials, "kadmin/changepw", CRED_SPECIFIED); 498 ret = cli_credentials_set_keytab_name(server_credentials, kdc->task-> event_ctx, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED);508 ret = cli_credentials_set_keytab_name(server_credentials, kdc->task->lp_ctx, keytab_name, CRED_SPECIFIED); 499 509 if (ret != 0) { 500 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 510 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 501 511 KRB5_KPASSWD_HARDERROR, 502 talloc_asprintf(mem_ctx, 503 "Failed to obtain server credentials for kadmin/changepw: %s\n", 504 nt_errstr(nt_status)), 512 talloc_asprintf(mem_ctx, 513 "Failed to obtain server credentials for kadmin/changepw!"), 505 514 &krb_priv_rep); 506 515 ap_rep.length = 0; … … 511 520 return ret; 512 521 } 513 522 514 523 /* We don't strictly need to call this wrapper, and could call 515 524 * gensec_server_start directly, as we have no need for NTLM 516 525 * and we have a PAC, but this ensures that the wrapper can be 517 526 * safely extended for other helpful things in future */ 518 nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, 527 nt_status = samba_server_gensec_start(tmp_ctx, kdc->task->event_ctx, 519 528 kdc->task->msg_ctx, 520 529 kdc->task->lp_ctx, 521 530 server_credentials, 522 "kpasswd", 531 "kpasswd", 523 532 &gensec_security); 524 533 if (!NT_STATUS_IS_OK(nt_status)) { 525 534 talloc_free(tmp_ctx); 526 return false;535 return KDC_PROCESS_FAILED; 527 536 } 528 537 … … 535 544 * complex code */ 536 545 537 nt_status = gensec_set_ peer_addr(gensec_security, peer_addr);546 nt_status = gensec_set_local_address(gensec_security, peer_addr); 538 547 if (!NT_STATUS_IS_OK(nt_status)) { 539 548 talloc_free(tmp_ctx); 540 return false;549 return KDC_PROCESS_FAILED; 541 550 } 542 551 #endif 543 552 544 nt_status = gensec_set_ my_addr(gensec_security, my_addr);553 nt_status = gensec_set_local_address(gensec_security, my_addr); 545 554 if (!NT_STATUS_IS_OK(nt_status)) { 546 555 talloc_free(tmp_ctx); 547 return false;556 return KDC_PROCESS_FAILED; 548 557 } 549 558 … … 554 563 if (!NT_STATUS_IS_OK(nt_status)) { 555 564 talloc_free(tmp_ctx); 556 return false;565 return KDC_PROCESS_FAILED; 557 566 } 558 567 … … 560 569 nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep); 561 570 if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 562 563 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 571 572 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 564 573 KRB5_KPASSWD_HARDERROR, 565 talloc_asprintf(mem_ctx, 566 "gensec_update failed: %s", 574 talloc_asprintf(mem_ctx, 575 "gensec_update failed: %s", 567 576 nt_errstr(nt_status)), 568 577 &krb_priv_rep); … … 572 581 } 573 582 talloc_free(tmp_ctx); 574 return ret;583 return KDC_PROCESS_FAILED; 575 584 } 576 585 … … 578 587 nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req); 579 588 if (!NT_STATUS_IS_OK(nt_status)) { 580 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 589 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 581 590 KRB5_KPASSWD_HARDERROR, 582 talloc_asprintf(mem_ctx, 583 "gensec_unwrap failed: %s", 591 talloc_asprintf(mem_ctx, 592 "gensec_unwrap failed: %s", 584 593 nt_errstr(nt_status)), 585 594 &krb_priv_rep); … … 589 598 } 590 599 talloc_free(tmp_ctx); 591 return ret;600 return KDC_PROCESS_FAILED; 592 601 } 593 602 594 603 /* Figure out something to do with it (probably changing a password...) */ 595 ret = kpasswd_process_request(kdc, tmp_ctx, 596 gensec_security, 597 version, 598 &kpasswd_req, &kpasswd_rep); 604 ret = kpasswd_process_request(kdc, tmp_ctx, 605 gensec_security, 606 version, 607 &kpasswd_req, &kpasswd_rep); 599 608 if (!ret) { 600 609 /* Argh! */ 601 return false; 610 talloc_free(tmp_ctx); 611 return KDC_PROCESS_FAILED; 602 612 } 603 613 604 614 /* And wrap up the reply: This ensures that the error message 605 615 * or success can be verified by the client */ 606 nt_status = gensec_wrap(gensec_security, tmp_ctx, 616 nt_status = gensec_wrap(gensec_security, tmp_ctx, 607 617 &kpasswd_rep, &krb_priv_rep); 608 618 if (!NT_STATUS_IS_OK(nt_status)) { 609 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 619 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 610 620 KRB5_KPASSWD_HARDERROR, 611 talloc_asprintf(mem_ctx, 612 "gensec_wrap failed: %s", 621 talloc_asprintf(mem_ctx, 622 "gensec_wrap failed: %s", 613 623 nt_errstr(nt_status)), 614 624 &krb_priv_rep); … … 618 628 } 619 629 talloc_free(tmp_ctx); 620 return ret;621 } 622 630 return KDC_PROCESS_FAILED; 631 } 632 623 633 reply: 624 634 *reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len); 625 635 if (!reply->data) { 626 return false; 636 talloc_free(tmp_ctx); 637 return KDC_PROCESS_FAILED; 627 638 } 628 639 … … 630 641 RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */ 631 642 RSSVAL(reply->data, 4, ap_rep.length); 632 memcpy(reply->data + header_len, 633 ap_rep.data, 643 memcpy(reply->data + header_len, 644 ap_rep.data, 634 645 ap_rep.length); 635 memcpy(reply->data + header_len + ap_rep.length, 636 krb_priv_rep.data, 646 memcpy(reply->data + header_len + ap_rep.length, 647 krb_priv_rep.data, 637 648 krb_priv_rep.length); 638 649 639 650 talloc_free(tmp_ctx); 640 return ret;651 return KDC_PROCESS_OK; 641 652 } 642 653 -
vendor/current/source4/kdc/pac-glue.c
r414 r740 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 4 4 PAC Glue between Samba and the KDC 5 5 6 6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009 7 Copyright (C) Simo Sorce <idra@samba.org> 2010 7 8 8 9 This program is free software; you can redistribute it and/or modify … … 10 11 the Free Software Foundation; either version 3 of the License, or 11 12 (at your option) any later version. 12 13 13 14 This program is distributed in the hope that it will be useful, 14 15 but WITHOUT ANY WARRANTY; without even the implied warranty of … … 16 17 GNU General Public License for more details. 17 18 18 19 19 20 You should have received a copy of the GNU General Public License 20 21 along with this program. If not, see <http://www.gnu.org/licenses/>. … … 23 24 #include "includes.h" 24 25 #include "../libds/common/flags.h" 25 #include "lib/ldb/include/ldb.h" 26 #include <ldb.h> 27 #include "auth/auth.h" 28 #include "auth/auth_sam_reply.h" 29 #include "kdc/kdc-glue.h" 30 #include "param/param.h" 26 31 #include "librpc/gen_ndr/ndr_krb5pac.h" 27 #include "librpc/gen_ndr/krb5pac.h" 28 #include "auth/auth.h" 29 #include "auth/auth_sam.h" 30 #include "auth/auth_sam_reply.h" 31 #include "kdc/kdc.h" 32 #include "param/param.h" 33 34 struct krb5_dh_moduli; 35 struct _krb5_krb_auth_data; 36 37 static krb5_error_code samba_kdc_plugin_init(krb5_context context, void **ptr) 38 { 39 *ptr = NULL; 40 return 0; 41 } 42 43 static void samba_kdc_plugin_fini(void *ptr) 44 { 45 return; 46 } 47 48 static krb5_error_code make_pac(krb5_context context, 49 TALLOC_CTX *mem_ctx, 50 struct smb_iconv_convenience *iconv_convenience, 51 struct auth_serversupplied_info *server_info, 52 krb5_pac *pac) 53 { 54 union PAC_INFO info; 32 33 static 34 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx, 35 struct auth_user_info_dc *info, 36 DATA_BLOB *pac_data) 37 { 55 38 struct netr_SamInfo3 *info3; 56 krb5_data pac_data; 57 NTSTATUS nt_status; 39 union PAC_INFO pac_info; 58 40 enum ndr_err_code ndr_err; 59 DATA_BLOB pac_out; 60 krb5_error_code ret; 61 62 ZERO_STRUCT(info); 63 64 nt_status = auth_convert_server_info_saminfo3(mem_ctx, server_info, &info3); 41 NTSTATUS nt_status; 42 43 ZERO_STRUCT(pac_info); 44 45 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3); 65 46 if (!NT_STATUS_IS_OK(nt_status)) { 66 DEBUG(1, ("Getting Samba info failed: %s\n", nt_errstr(nt_status))); 67 return EINVAL; 68 } 69 70 info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO); 47 DEBUG(1, ("Getting Samba info failed: %s\n", 48 nt_errstr(nt_status))); 49 return nt_status; 50 } 51 52 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO); 71 53 if (!mem_ctx) { 72 return ENOMEM;73 } 74 75 info.logon_info.info->info3 = *info3;76 77 ndr_err = ndr_push_union_blob( &pac_out, mem_ctx, iconv_convenience, &info,54 return NT_STATUS_NO_MEMORY; 55 } 56 57 pac_info.logon_info.info->info3 = *info3; 58 59 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info, 78 60 PAC_TYPE_LOGON_INFO, 79 61 (ndr_push_flags_fn_t)ndr_push_PAC_INFO); 80 62 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 81 63 nt_status = ndr_map_error2ntstatus(ndr_err); 82 DEBUG(1, ("PAC (presig) push failed: %s\n", nt_errstr(nt_status))); 83 return EINVAL; 84 } 85 86 ret = krb5_data_copy(&pac_data, pac_out.data, pac_out.length); 64 DEBUG(1, ("PAC (presig) push failed: %s\n", 65 nt_errstr(nt_status))); 66 return nt_status; 67 } 68 69 return NT_STATUS_OK; 70 } 71 72 krb5_error_code samba_make_krb5_pac(krb5_context context, 73 DATA_BLOB *pac_blob, 74 krb5_pac *pac) 75 { 76 krb5_data pac_data; 77 krb5_error_code ret; 78 79 /* The user account may be set not to want the PAC */ 80 if (!pac_blob) { 81 return 0; 82 } 83 84 ret = krb5_data_copy(&pac_data, pac_blob->data, pac_blob->length); 87 85 if (ret != 0) { 88 86 return ret; … … 104 102 } 105 103 106 /* Given the right private pointer from hdb_samba4, get a PAC from the attached ldb messages */ 107 static krb5_error_code samba_kdc_get_pac(void *priv, 108 krb5_context context, 109 struct hdb_entry_ex *client, 110 krb5_pac *pac) 111 { 112 krb5_error_code ret; 113 NTSTATUS nt_status; 114 struct auth_serversupplied_info *server_info; 115 struct hdb_samba4_private *p = talloc_get_type(client->ctx, struct hdb_samba4_private); 116 TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context"); 117 unsigned int userAccountControl; 118 119 if (!mem_ctx) { 120 return ENOMEM; 121 } 122 123 /* The user account may be set not to want the PAC */ 104 bool samba_princ_needs_pac(struct hdb_entry_ex *princ) 105 { 106 107 struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry); 108 uint32_t userAccountControl; 109 110 111 /* The service account may be set not to want the PAC */ 124 112 userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0); 125 113 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { 126 *pac = NULL; 127 return 0; 128 } 129 130 nt_status = authsam_make_server_info(mem_ctx, p->samdb, 131 lp_netbios_name(p->lp_ctx), 132 lp_sam_name(p->lp_ctx), 114 return false; 115 } 116 117 return true; 118 } 119 120 /* Was the krbtgt an RODC (and we are not) */ 121 bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ) 122 { 123 124 struct samba_kdc_entry *p = talloc_get_type(princ->ctx, struct samba_kdc_entry); 125 int rodc_krbtgt_number; 126 127 /* Determine if this was printed by an RODC */ 128 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1); 129 if (rodc_krbtgt_number == -1) { 130 return false; 131 } else if (rodc_krbtgt_number != p->kdc_db_ctx->my_krbtgt_number) { 132 return true; 133 } 134 135 return false; 136 } 137 138 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, 139 struct hdb_entry_ex *client, 140 DATA_BLOB **_pac_blob) 141 { 142 struct samba_kdc_entry *p = talloc_get_type(client->ctx, struct samba_kdc_entry); 143 struct auth_user_info_dc *user_info_dc; 144 DATA_BLOB *pac_blob; 145 NTSTATUS nt_status; 146 147 /* The user account may be set not to want the PAC */ 148 if ( ! samba_princ_needs_pac(client)) { 149 *_pac_blob = NULL; 150 return NT_STATUS_OK; 151 } 152 153 pac_blob = talloc_zero(mem_ctx, DATA_BLOB); 154 if (!pac_blob) { 155 return NT_STATUS_NO_MEMORY; 156 } 157 158 nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb, 159 lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx), 160 lpcfg_sam_name(p->kdc_db_ctx->lp_ctx), 133 161 p->realm_dn, 134 162 p->msg, 135 163 data_blob(NULL, 0), 136 164 data_blob(NULL, 0), 137 & server_info);165 &user_info_dc); 138 166 if (!NT_STATUS_IS_OK(nt_status)) { 139 167 DEBUG(0, ("Getting user info for PAC failed: %s\n", 140 168 nt_errstr(nt_status))); 141 return ENOMEM; 142 } 143 144 ret = make_pac(context, mem_ctx, p->iconv_convenience, server_info, pac); 145 146 talloc_free(mem_ctx); 147 return ret; 148 } 149 150 /* Resign (and reform, including possibly new groups) a PAC */ 151 152 static krb5_error_code samba_kdc_reget_pac(void *priv, krb5_context context, 153 const krb5_principal client_principal, 154 struct hdb_entry_ex *client, 155 struct hdb_entry_ex *server, krb5_pac *pac) 156 { 169 return nt_status; 170 } 171 172 nt_status = samba_get_logon_info_pac_blob(mem_ctx, user_info_dc, pac_blob); 173 if (!NT_STATUS_IS_OK(nt_status)) { 174 DEBUG(0, ("Building PAC failed: %s\n", 175 nt_errstr(nt_status))); 176 return nt_status; 177 } 178 179 *_pac_blob = pac_blob; 180 return NT_STATUS_OK; 181 } 182 183 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, 184 krb5_context context, 185 krb5_pac *pac, DATA_BLOB *pac_blob) 186 { 187 struct auth_user_info_dc *user_info_dc; 157 188 krb5_error_code ret; 158 159 unsigned int userAccountControl; 160 161 struct hdb_samba4_private *p = talloc_get_type(server->ctx, struct hdb_samba4_private); 162 163 struct auth_serversupplied_info *server_info_out; 164 165 TALLOC_CTX *mem_ctx = talloc_named(p, 0, "samba_get_pac context"); 166 167 if (!mem_ctx) { 168 return ENOMEM; 169 } 170 171 /* The service account may be set not to want the PAC */ 172 userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0); 173 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) { 174 talloc_free(mem_ctx); 175 *pac = NULL; 176 return 0; 177 } 178 179 ret = kerberos_pac_to_server_info(mem_ctx, p->iconv_convenience, 180 *pac, context, &server_info_out); 181 182 /* We will compleatly regenerate this pac */ 183 krb5_pac_free(context, *pac); 184 189 NTSTATUS nt_status; 190 191 ret = kerberos_pac_to_user_info_dc(mem_ctx, *pac, 192 context, &user_info_dc, NULL, NULL); 185 193 if (ret) { 186 talloc_free(mem_ctx);187 return ret;188 } 189 190 ret = make_pac(context, mem_ctx, p->iconv_convenience, server_info_out, pac);191 192 talloc_free(mem_ctx);193 return ret; 194 } 195 196 static void samba_kdc_build_edata_reply(TALLOC_CTX *tmp_ctx, krb5_data *e_data, 197 NTSTATUS nt_status)194 return NT_STATUS_UNSUCCESSFUL; 195 } 196 197 nt_status = samba_get_logon_info_pac_blob(mem_ctx, 198 user_info_dc, pac_blob); 199 200 return nt_status; 201 } 202 203 /* this function allocates 'data' using malloc. 204 * The caller is responsible for freeing it */ 205 void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data) 198 206 { 199 207 PA_DATA pa; … … 227 235 } 228 236 229 /* Given an hdb entry (and in particular it's private member), consult 230 * the account_ok routine in auth/auth_sam.c for consistancy */ 231 232 233 static krb5_error_code samba_kdc_check_client_access(void *priv, 234 krb5_context context, 235 krb5_kdc_configuration *config, 236 hdb_entry_ex *client_ex, const char *client_name, 237 hdb_entry_ex *server_ex, const char *server_name, 238 KDC_REQ *req, 239 krb5_data *e_data) 237 /* function to map policy errors */ 238 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status) 240 239 { 241 240 krb5_error_code ret; 242 NTSTATUS nt_status; 241 242 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) 243 ret = KRB5KDC_ERR_KEY_EXPIRED; 244 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) 245 ret = KRB5KDC_ERR_KEY_EXPIRED; 246 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) 247 ret = KRB5KDC_ERR_CLIENT_REVOKED; 248 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) 249 ret = KRB5KDC_ERR_CLIENT_REVOKED; 250 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) 251 ret = KRB5KDC_ERR_CLIENT_REVOKED; 252 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) 253 ret = KRB5KDC_ERR_CLIENT_REVOKED; 254 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) 255 ret = KRB5KDC_ERR_POLICY; 256 else 257 ret = KRB5KDC_ERR_POLICY; 258 259 return ret; 260 } 261 262 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c 263 * for consistency */ 264 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry, 265 const char *client_name, 266 const char *workstation, 267 bool password_change) 268 { 243 269 TALLOC_CTX *tmp_ctx; 244 struct hdb_samba4_private *p; 245 char *workstation = NULL; 246 HostAddresses *addresses = req->req_body.addresses; 247 int i; 248 bool password_change; 249 250 tmp_ctx = talloc_new(client_ex->ctx); 251 p = talloc_get_type(client_ex->ctx, struct hdb_samba4_private); 252 270 NTSTATUS nt_status; 271 272 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access"); 253 273 if (!tmp_ctx) { 254 return ENOMEM; 255 } 256 257 if (addresses) { 258 for (i=0; i < addresses->len; i++) { 259 if (addresses->val->addr_type == KRB5_ADDRESS_NETBIOS) { 260 workstation = talloc_strndup(tmp_ctx, addresses->val->address.data, MIN(addresses->val->address.length, 15)); 261 if (workstation) { 262 break; 263 } 264 } 265 } 266 } 267 268 /* Strip space padding */ 269 if (workstation) { 270 i = MIN(strlen(workstation), 15); 271 for (; i > 0 && workstation[i - 1] == ' '; i--) { 272 workstation[i - 1] = '\0'; 273 } 274 } 275 276 password_change = (server_ex && server_ex->entry.flags.change_pw); 274 return NT_STATUS_NO_MEMORY; 275 } 277 276 278 277 /* we allow all kinds of trusts here */ 279 nt_status = authsam_account_ok(tmp_ctx, 280 p->samdb, 281 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, 282 p->realm_dn, 283 p->msg, 284 workstation, 285 client_name, true, password_change); 286 287 if (NT_STATUS_IS_OK(nt_status)) { 288 /* Now do the standard Heimdal check */ 289 ret = kdc_check_flags(context, config, 290 client_ex, client_name, 291 server_ex, server_name, 292 req->msg_type == krb_as_req); 293 } else { 294 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE)) 295 ret = KRB5KDC_ERR_KEY_EXPIRED; 296 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED)) 297 ret = KRB5KDC_ERR_KEY_EXPIRED; 298 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED)) 299 ret = KRB5KDC_ERR_CLIENT_REVOKED; 300 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED)) 301 ret = KRB5KDC_ERR_CLIENT_REVOKED; 302 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS)) 303 ret = KRB5KDC_ERR_CLIENT_REVOKED; 304 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT)) 305 ret = KRB5KDC_ERR_CLIENT_REVOKED; 306 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION)) 307 ret = KRB5KDC_ERR_POLICY; 308 else 309 ret = KRB5KDC_ERR_POLICY; 310 311 samba_kdc_build_edata_reply(tmp_ctx, e_data, nt_status); 312 } 313 314 return ret; 315 } 316 317 struct krb5plugin_windc_ftable windc_plugin_table = { 318 .minor_version = KRB5_WINDC_PLUGING_MINOR, 319 .init = samba_kdc_plugin_init, 320 .fini = samba_kdc_plugin_fini, 321 .pac_generate = samba_kdc_get_pac, 322 .pac_verify = samba_kdc_reget_pac, 323 .client_access = samba_kdc_check_client_access, 324 }; 325 278 nt_status = authsam_account_ok(tmp_ctx, 279 kdc_entry->kdc_db_ctx->samdb, 280 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | 281 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, 282 kdc_entry->realm_dn, kdc_entry->msg, 283 workstation, client_name, 284 true, password_change); 285 286 talloc_free(tmp_ctx); 287 return nt_status; 288 } 289 -
vendor/current/source4/kdc/pac-glue.h
r414 r740 1 /* 1 /* 2 2 Unix SMB/CIFS implementation. 3 3 4 KDC Server startup4 PAC Glue between Samba and the KDC 5 5 6 6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009 7 Copyright (C) Simo Sorce <idra@samba.org> 2010 7 8 8 9 This program is free software; you can redistribute it and/or modify … … 10 11 the Free Software Foundation; either version 3 of the License, or 11 12 (at your option) any later version. 12 13 13 14 This program is distributed in the hope that it will be useful, 14 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 17 GNU General Public License for more details. 17 18 19 18 20 You should have received a copy of the GNU General Public License 19 21 along with this program. If not, see <http://www.gnu.org/licenses/>. 20 22 */ 21 23 22 #ifndef __KDC_PAC_GLUE_H__ 23 #define __KDC_PAC_GLUE_H__ 24 krb5_error_code samba_make_krb5_pac(krb5_context context, 25 DATA_BLOB *pac_blob, 26 krb5_pac *pac); 24 27 25 #include "kdc/pac-glue_proto.h" 28 bool samba_princ_needs_pac(struct hdb_entry_ex *princ); 26 29 27 extern struct krb5plugin_windc_ftable windc_plugin_table;30 bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ); 28 31 29 #endif /* __KDC_PAC_GLUE_H__ */ 32 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx, 33 struct hdb_entry_ex *client, 34 DATA_BLOB **_pac_blob); 30 35 36 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx, 37 krb5_context context, 38 krb5_pac *pac, DATA_BLOB *pac_blob); 39 40 void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data); 41 42 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status); 43 44 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry, 45 const char *client_name, 46 const char *workstation, 47 bool password_change);
Note:
See TracChangeset
for help on using the changeset viewer.