Ignore:
Timestamp:
Nov 14, 2012, 12:59:34 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to 3.6.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source4/kdc/hdb-samba4.c

    r414 r740  
    3434
    3535#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"
    95438
    95539static krb5_error_code hdb_samba4_open(krb5_context context, HDB *db, int flags, mode_t mode)
     
    96044                krb5_set_error_message(context, ret, "hdb_samba4_open: use of a master key incompatible with LDB\n");
    96145                return ret;
    962         }               
     46        }
    96347
    96448        return 0;
     
    98569}
    98670
    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 != 2
    1056             || (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 primary
    1068                  * 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 be
    1186                  * in a different realm, so we should generate a
    1187                  * 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 
    130871static krb5_error_code hdb_samba4_store(krb5_context context, HDB *db, unsigned flags, hdb_entry_ex *entry)
    130972{
     
    131679}
    131780
    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;
     81static 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);
    136393}
    136494
     
    136696                                        hdb_entry_ex *entry)
    136797{
    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);
    1435104}
    1436105
     
    1438107                                   hdb_entry_ex *entry)
    1439108{
    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);
    1441115}
    1442116
     
    1447121}
    1448122
    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 {
     123static krb5_error_code
     124hdb_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
     138static krb5_error_code
     139hdb_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
     158NTSTATUS 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;
    1587162        NTSTATUS nt_status;
    1588         struct auth_session_info *session_info;
    1589         *db = talloc(mem_ctx, HDB);
     163
     164        *db = talloc(base_ctx, HDB);
    1590165        if (!*db) {
    1591166                krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
     
    1597172        (*db)->hdb_capability_flags = 0;
    1598173
    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);
    1600175        if (!NT_STATUS_IS_OK(nt_status)) {
     176                talloc_free(*db);
    1601177                return nt_status;
    1602178        }
    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;
    1621180
    1622181        (*db)->hdb_dbc = NULL;
    1623182        (*db)->hdb_open = hdb_samba4_open;
    1624183        (*db)->hdb_close = hdb_samba4_close;
    1625         (*db)->hdb_fetch = hdb_samba4_fetch;
     184        (*db)->hdb_fetch_kvno = hdb_samba4_fetch_kvno;
    1626185        (*db)->hdb_store = hdb_samba4_store;
    1627186        (*db)->hdb_remove = hdb_samba4_remove;
     
    1639198
    1640199        (*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;
    1642201        (*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;
    1643203
    1644204        return NT_STATUS_OK;
     
    1649209        NTSTATUS nt_status;
    1650210        void *ptr;
    1651         struct hdb_samba4_context *hdb_samba4_context;
     211        struct samba_kdc_base_context *base_ctx;
     212
    1652213        if (sscanf(arg, "&%p", &ptr) != 1) {
    1653214                return EINVAL;
    1654215        }
    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);
    1656217        /* 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);
    1659219
    1660220        if (NT_STATUS_IS_OK(nt_status)) {
     
    1673233struct hdb_method hdb_samba4 = {
    1674234        .interface_version = HDB_INTERFACE_VERSION,
    1675         .prefix = "samba4", 
     235        .prefix = "samba4",
    1676236        .create = hdb_samba4_create
    1677237};
Note: See TracChangeset for help on using the changeset viewer.