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

Samba Server: update vendor to 3.6.0

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  
    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};
  • vendor/current/source4/kdc/kdc.c

    r414 r740  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33
     
    1212   the Free Software Foundation; either version 3 of the License, or
    1313   (at your option) any later version.
    14    
     14
    1515   This program is distributed in the hope that it will be useful,
    1616   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1717   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1818   GNU General Public License for more details.
    19    
     19
    2020   You should have received a copy of the GNU General Public License
    2121   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    2323
    2424#include "includes.h"
    25 #include "smbd/service_task.h"
    26 #include "smbd/service.h"
    27 #include "smbd/service_stream.h"
    2825#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"
    3328#include "lib/messaging/irpc.h"
    34 #include "lib/stream/packet.h"
    35 #include "librpc/gen_ndr/samr.h"
    3629#include "librpc/gen_ndr/ndr_irpc.h"
    3730#include "librpc/gen_ndr/ndr_krb5pac.h"
     31#include "lib/stream/packet.h"
    3832#include "lib/socket/netif.h"
    3933#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
     38extern struct krb5plugin_windc_ftable windc_plugin_table;
     39extern struct hdb_method hdb_samba4;
     40
     41static 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
     65typedef 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);
    6472
    6573/* hold information about one kdc socket */
    6674struct kdc_socket {
    67         struct socket_context *sock;
    6875        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;
    7477        kdc_process_fn_t process;
    7578};
     79
     80struct 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
    7688/*
    7789  state of an open tcp connection
     
    8294
    8395        /* the kdc_server the connection belongs to */
    84         struct kdc_server *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;
    89101};
    90102
    91 /*
    92   handle fd send events on a KDC socket
    93 */
    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 socket
    122 */
    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 socket
    201 */
    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 }
    213103
    214104static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason)
     
    217107}
    218108
    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)
     109static void kdc_tcp_recv(struct stream_connection *conn, uint16_t flags)
    287110{
    288111        struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
    289112                                                             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
    306117static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
    307118{
    308119        struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
    309120                                                             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");
    311123}
    312124
     
    316128*/
    317129
    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;       
     130static 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;
    327141        krb5_data k5_reply;
    328142        krb5_data_zero(&k5_reply);
     
    330144        krb5_kdc_update_time(NULL);
    331145
    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,
    336160                                            kdc->config,
    337161                                            input->data, input->length,
    338162                                            &k5_reply,
    339                                             peer_addr->addr,
    340                                             peer_addr->sockaddr,
     163                                            pa,
     164                                            (struct sockaddr *) &ss,
    341165                                            datagram_reply);
    342166        if (ret == -1) {
    343167                *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
    346176        if (k5_reply.length) {
    347177                *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
    348178                krb5_data_free(&k5_reply);
    349179        } 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
     185static void kdc_tcp_call_proxy_done(struct tevent_req *subreq);
     186static void kdc_tcp_call_writev_done(struct tevent_req *subreq);
     187
     188static 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
     306static 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
     373static 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);
    353399}
    354400
     
    356402  called when we get a new connection
    357403*/
    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 
    388404static void kdc_tcp_accept(struct stream_connection *conn)
    389405{
    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);
    391458}
    392459
     
    394461        .name                   = "kdc_tcp",
    395462        .accept_connection      = kdc_tcp_accept,
    396         .recv_handler           = kdc_tcp_recv_handler,
     463        .recv_handler           = kdc_tcp_recv,
    397464        .send_handler           = kdc_tcp_send
    398465};
    399466
    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 */
     468struct kdc_udp_socket {
     469        struct kdc_socket *kdc_socket;
     470        struct tdgram_context *dgram;
     471        struct tevent_queue *send_queue;
    410472};
     473
     474struct kdc_udp_call {
     475        struct kdc_udp_socket *sock;
     476        struct tsocket_address *src;
     477        DATA_BLOB in;
     478        DATA_BLOB out;
     479};
     480
     481static void kdc_udp_call_proxy_done(struct tevent_req *subreq);
     482static void kdc_udp_call_sendto_done(struct tevent_req *subreq);
     483
     484static 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
     566done:
     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
     579static 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
     614static 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}
    411627
    412628/*
    413629  start listening on the given address
    414630*/
    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;
     631static 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;
    422642        NTSTATUS status;
     643        int ret;
    423644
    424645        kdc_socket = talloc(kdc, struct kdc_socket);
    425646        NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
    426647
    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);
    433656                return status;
    434657        }
    435658
    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)));
    439689                return status;
    440690        }
    441691
    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);
    523701
    524702        return NT_STATUS_OK;
     
    532710                                       struct interface *ifaces)
    533711{
     712        const struct model_ops *model_ops;
    534713        int num_interfaces;
    535714        TALLOC_CTX *tmp_ctx = talloc_new(kdc);
    536715        NTSTATUS status;
    537716        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        }
    538729
    539730        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
    541751        for (i=0; i<num_interfaces; i++) {
    542752                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                }
    546767        }
    547768
     
    552773
    553774
    554 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 
     775static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg,
    555776                                 struct kdc_check_generic_kerberos *r)
    556777{
     
    570791        r->out.generic_reply = data_blob(NULL, 0);
    571792
    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,
    575794                                       (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
    576795        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    577796                return NT_STATUS_INVALID_PARAMETER;
    578797        }
    579        
     798
    580799        if (pac_validate.MessageType != 3) {
    581800                /* We don't implement any other message types - such as certificate validation - yet */
     
    588807                return NT_STATUS_INVALID_PARAMETER;
    589808        }
    590        
    591         srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, 
     809
     810        srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data,
    592811                                  pac_validate.ChecksumLength);
    593        
     812
    594813        if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) {
    595814                etype = ETYPE_ARCFOUR_HMAC_MD5;
     
    602821        }
    603822
    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),
    607826                                  NULL);
    608827
     
    611830        }
    612831
    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       
    619839        if (ret != 0) {
    620840                hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
    621841                krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
    622        
     842
    623843                return NT_STATUS_LOGON_FAILURE;
    624844        }
    625        
     845
    626846        ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key);
    627847
     
    633853
    634854        keyblock = key->key;
    635        
     855
    636856        kdc_sig.type = pac_validate.SignatureType;
    637857        kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
    638858                                            pac_validate.SignatureLength);
    639         ret = check_pac_checksum(msg, srv_sig, &kdc_sig, 
     859        ret = check_pac_checksum(msg, srv_sig, &kdc_sig,
    640860                           kdc->smb_krb5_context->krb5_context, &keyblock);
    641861
     
    646866                return NT_STATUS_LOGON_FAILURE;
    647867        }
    648        
     868
    649869        return NT_STATUS_OK;
    650870}
     
    660880        krb5_error_code ret;
    661881        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)) {
    664885        case ROLE_STANDALONE:
    665886                task_server_terminate(task, "kdc: no KDC required in standalone configuration", false);
     
    673894        }
    674895
    675         load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
     896        load_interfaces(task, lpcfg_interfaces(task->lp_ctx), &ifaces);
    676897
    677898        if (iface_count(ifaces) == 0) {
     
    682903        task_server_set_title(task, "task[kdc]");
    683904
    684         kdc = talloc(task, struct kdc_server);
     905        kdc = talloc_zero(task, struct kdc_server);
    685906        if (kdc == NULL) {
    686907                task_server_terminate(task, "kdc: out of memory", true);
     
    690911        kdc->task = task;
    691912
     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
    692933        initialize_krb5_error_table();
    693934
    694935        ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
    695936        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",
    697938                         error_message(ret)));
    698939                task_server_terminate(task, "kdc: krb5_init_context failed", true);
    699                 return; 
     940                return;
    700941        }
    701942
    702943        krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
    703944
    704         ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 
     945        ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
    705946                                  &kdc->config);
    706947        if(ret) {
     
    708949                return;
    709950        }
    710  
     951
    711952        kdc->config->logf = kdc->smb_krb5_context->logf;
    712953        kdc->config->db = talloc(kdc, struct HDB *);
     
    716957        }
    717958        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,
    721973                                       &kdc->config->db[0]);
    722974        if (!NT_STATUS_IS_OK(status)) {
    723975                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,
    739980                                   PLUGIN_TYPE_DATA, "hdb",
    740981                                   &hdb_samba4);
    741982        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);
    743984                return;
    744985        }
     
    746987        ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
    747988        if(ret) {
    748                 task_server_terminate(task, "kdc: failed to register hdb keytab", true);
    749                 return;
    750         }
    751 
    752         /* Registar 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,
    754995                                   PLUGIN_TYPE_DATA, "windc",
    755996                                   &windc_plugin_table);
    756997        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        }
    7621015
    7631016        /* start listening on the configured network interfaces */
     
    7681021        }
    7691022
    770         status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, 
     1023        status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS,
    7711024                               kdc_check_generic_kerberos, kdc);
    7721025        if (!NT_STATUS_IS_OK(status)) {
    773                 task_server_terminate(task, "nbtd failed to setup monitoring", true);
     1026                task_server_terminate(task, "kdc failed to setup monitoring", true);
    7741027                return;
    7751028        }
  • vendor/current/source4/kdc/kpasswdd.c

    r414 r740  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33
     
    1111   the Free Software Foundation; either version 3 of the License, or
    1212   (at your option) any later version.
    13    
     13
    1414   This program is distributed in the hope that it will be useful,
    1515   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1616   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1717   GNU General Public License for more details.
    18    
     18
    1919   You should have received a copy of the GNU General Public License
    2020   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    2323#include "includes.h"
    2424#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"
    3025#include "auth/gensec/gensec.h"
    3126#include "auth/credentials/credentials.h"
    32 #include "auth/credentials/credentials_krb5.h"
    3327#include "auth/auth.h"
    3428#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"
    3730#include "libcli/security/security.h"
    3831#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"
    5533
    5634/* 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) 
     35static 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)
    6240{
    6341        char *error_string_utf8;
    6442        size_t len;
    65        
     43
    6644        DEBUG(result_code ? 3 : 10, ("kpasswdd: %s\n", error_string));
    6745
     
    8058
    8159/* 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) 
     60static 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)
    8765{
    8866        bool ret;
     
    9068        DATA_BLOB error_bytes;
    9169        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,
    9371                                       &error_bytes);
    9472        if (!ret) {
     
    9876        k5_error_bytes.length = error_bytes.length;
    9977        kret = krb5_mk_error(kdc->smb_krb5_context->krb5_context,
    100                              result_code, NULL, &k5_error_bytes, 
     78                             result_code, NULL, &k5_error_bytes,
    10179                             NULL, NULL, NULL, NULL, &k5_error_blob);
    10280        if (kret) {
     
    11189}
    11290
    113 static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc, 
    114                                         TALLOC_CTX *mem_ctx, 
    115                                         NTSTATUS status, 
    116                                         enum samr_RejectReason reject_reason,
     91static bool kpasswd_make_pwchange_reply(struct kdc_server *kdc,
     92                                        TALLOC_CTX *mem_ctx,
     93                                        NTSTATUS status,
     94                                        enum samPwdChangeReason reject_reason,
    11795                                        struct samr_DomInfo1 *dominfo,
    118                                         DATA_BLOB *error_blob) 
     96                                        DATA_BLOB *error_blob)
    11997{
    12098        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,
    122100                                                KRB5_KPASSWD_ACCESSDENIED,
    123101                                                "No such user when changing password",
     
    125103        }
    126104        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,
    128106                                                KRB5_KPASSWD_ACCESSDENIED,
    129107                                                "Not permitted to change password",
     
    133111                const char *reject_string;
    134112                switch (reject_reason) {
    135                 case SAMR_REJECT_TOO_SHORT:
     113                case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
    136114                        reject_string = talloc_asprintf(mem_ctx, "Password too short, password must be at least %d characters long",
    137115                                                        dominfo->min_password_length);
    138116                        break;
    139                 case SAMR_REJECT_COMPLEXITY:
     117                case SAM_PWD_CHANGE_NOT_COMPLEX:
    140118                        reject_string = "Password does not meet complexity requirements";
    141119                        break;
    142                 case SAMR_REJECT_IN_HISTORY:
     120                case SAM_PWD_CHANGE_PWD_IN_HISTORY:
    143121                        reject_string = "Password is already in password history";
    144122                        break;
    145                 case SAMR_REJECT_OTHER:
    146123                default:
    147124                        reject_string = talloc_asprintf(mem_ctx, "Password must be at least %d characters long, and cannot match any of your %d previous passwords",
     
    149126                        break;
    150127                }
    151                 return kpasswdd_make_error_reply(kdc, mem_ctx, 
     128                return kpasswdd_make_error_reply(kdc, mem_ctx,
    152129                                                KRB5_KPASSWD_SOFTERROR,
    153130                                                reject_string,
     
    155132        }
    156133        if (!NT_STATUS_IS_OK(status)) {
    157                 return kpasswdd_make_error_reply(kdc, mem_ctx, 
     134                return kpasswdd_make_error_reply(kdc, mem_ctx,
    158135                                                 KRB5_KPASSWD_HARDERROR,
    159136                                                 talloc_asprintf(mem_ctx, "failed to set password: %s", nt_errstr(status)),
    160137                                                 error_blob);
    161                
     138
    162139        }
    163140        return kpasswdd_make_error_reply(kdc, mem_ctx, KRB5_KPASSWD_SUCCESS,
     
    166143}
    167144
    168 /* 
     145/*
    169146   A user password change
    170    
    171    Return true if there is a valid error packet (or sucess) formed in
     147
     148   Return true if there is a valid error packet (or success) formed in
    172149   the error_blob
    173150*/
    174151static bool kpasswdd_change_password(struct kdc_server *kdc,
    175                                      TALLOC_CTX *mem_ctx, 
     152                                     TALLOC_CTX *mem_ctx,
    176153                                     struct auth_session_info *session_info,
    177154                                     const DATA_BLOB *password,
     
    179156{
    180157        NTSTATUS status;
    181         enum samr_RejectReason reject_reason;
     158        enum samPwdChangeReason reject_reason;
    182159        struct samr_DomInfo1 *dominfo;
     160        struct samr_Password *oldLmHash, *oldNtHash;
    183161        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);
    186192        if (!samdb) {
    187                 return kpasswdd_make_error_reply(kdc, mem_ctx, 
     193                return kpasswdd_make_error_reply(kdc, mem_ctx,
    188194                                                KRB5_KPASSWD_HARDERROR,
    189195                                                "Failed to open samdb",
    190196                                                reply);
    191197        }
    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         /* User password 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 */
    203209                                        &reject_reason,
    204210                                        &dominfo);
    205         return kpasswd_make_pwchange_reply(kdc, mem_ctx, 
    206                                            status, 
     211        return kpasswd_make_pwchange_reply(kdc, mem_ctx,
     212                                           status,
    207213                                           reject_reason,
    208                                            dominfo, 
     214                                           dominfo,
    209215                                           reply);
    210216
     
    212218
    213219static bool kpasswd_process_request(struct kdc_server *kdc,
    214                                     TALLOC_CTX *mem_ctx, 
     220                                    TALLOC_CTX *mem_ctx,
    215221                                    struct gensec_security *gensec_security,
    216222                                    uint16_t version,
    217                                     DATA_BLOB *input, 
     223                                    DATA_BLOB *input,
    218224                                    DATA_BLOB *reply)
    219225{
     
    221227        size_t pw_len;
    222228
    223         if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security, 
     229        if (!NT_STATUS_IS_OK(gensec_session_info(gensec_security,
    224230                                                 &session_info))) {
    225                 return kpasswdd_make_error_reply(kdc, mem_ctx, 
     231                return kpasswdd_make_error_reply(kdc, mem_ctx,
    226232                                                KRB5_KPASSWD_HARDERROR,
    227233                                                "gensec_session_info failed!",
     
    233239        {
    234240                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,
    238244                                               input->length,
    239245                                               (void **)&password.data, &pw_len, false)) {
     
    241247                }
    242248                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,
    245251                                                &password, reply);
    246                 break;
    247252        }
    248253        case KRB5_KPASSWD_VERS_SETPW:
    249254        {
    250255                NTSTATUS status;
    251                 enum samr_RejectReason reject_reason = SAMR_REJECT_OTHER;
     256                enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    252257                struct samr_DomInfo1 *dominfo = NULL;
    253258                struct ldb_context *samdb;
    254                 struct ldb_message *msg;
    255259                krb5_context context = kdc->smb_krb5_context->krb5_context;
    256260
     
    261265                char *set_password_on_princ;
    262266                struct ldb_dn *set_password_on_dn;
     267                bool service_principal_name = false;
    263268
    264269                size_t len;
    265270                int ret;
    266 
    267                 msg = ldb_msg_new(mem_ctx);
    268                 if (!msg) {
    269                         return false;
    270                 }
    271271
    272272                ret = decode_ChangePasswdDataMS(input->data, input->length,
    273273                                                &chpw, &len);
    274274                if (ret) {
    275                         return kpasswdd_make_error_reply(kdc, mem_ctx, 
     275                        return kpasswdd_make_error_reply(kdc, mem_ctx,
    276276                                                        KRB5_KPASSWD_MALFORMED,
    277277                                                        "failed to decode password change structure",
    278278                                                        reply);
    279279                }
    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,
    284284                                               chpw.newpasswd.length,
    285285                                               (void **)&password.data, &pw_len, false)) {
     
    287287                        return false;
    288288                }
    289                
     289
    290290                password.length = pw_len;
    291        
    292                 if ((chpw.targname && !chpw.targrealm) 
     291
     292                if ((chpw.targname && !chpw.targrealm)
    293293                    || (!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,
    295296                                                        KRB5_KPASSWD_MALFORMED,
    296297                                                        "Realm and principal must be both present, or neither present",
     
    298299                }
    299300                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) {
    304306                                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,
    306316                                                                KRB5_KPASSWD_MALFORMED,
    307317                                                                "failed to extract principal to set",
    308318                                                                reply);
    309                                
    310319                        }
    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 */
    317320                } else {
    318321                        free_ChangePasswdDataMS(&chpw);
    319                         return kpasswdd_change_password(kdc, mem_ctx, session_info, 
     322                        return kpasswdd_change_password(kdc, mem_ctx, session_info,
    320323                                                        &password, reply);
    321324                }
    322325                free_ChangePasswdDataMS(&chpw);
    323326
    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                }
    332350                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);
    335353                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,
    337356                                                         KRB5_KPASSWD_HARDERROR,
    338357                                                         "Unable to open database!",
     
    340359                }
    341360
    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]),
    346365                          set_password_on_princ));
    347366                ret = ldb_transaction_start(samdb);
    348                 if (ret) {
     367                if (ret != LDB_SUCCESS) {
     368                        free(set_password_on_princ);
    349369                        status = NT_STATUS_TRANSACTION_ABORTED;
    350                         return kpasswd_make_pwchange_reply(kdc, mem_ctx, 
     370                        return kpasswd_make_pwchange_reply(kdc, mem_ctx,
    351371                                                           status,
    352                                                            SAMR_REJECT_OTHER,
    353                                                            NULL, 
     372                                                           SAM_PWD_CHANGE_NO_ERROR,
     373                                                           NULL,
    354374                                                           reply);
    355375                }
    356376
    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                }
    360386                free(set_password_on_princ);
    361387                if (!NT_STATUS_IS_OK(status)) {
    362388                        ldb_transaction_cancel(samdb);
    363                         return kpasswd_make_pwchange_reply(kdc, mem_ctx, 
     389                        return kpasswd_make_pwchange_reply(kdc, mem_ctx,
    364390                                                           status,
    365                                                            SAMR_REJECT_OTHER,
    366                                                            NULL, 
     391                                                           SAM_PWD_CHANGE_NO_ERROR,
     392                                                           NULL,
    367393                                                           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                         }
    379394                }
    380395
     
    383398                        status = samdb_set_password(samdb, mem_ctx,
    384399                                                    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 */
    387402                                                    &reject_reason, &dominfo);
    388403                }
    389404
    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                 }
    400405                if (NT_STATUS_IS_OK(status)) {
    401406                        ret = ldb_transaction_commit(samdb);
    402                         if (ret != 0) {
     407                        if (ret != LDB_SUCCESS) {
    403408                                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),
    405410                                         ldb_errstring(samdb)));
    406411                                status = NT_STATUS_TRANSACTION_ABORTED;
     
    409414                        ldb_transaction_cancel(samdb);
    410415                }
    411                 return kpasswd_make_pwchange_reply(kdc, mem_ctx, 
     416                return kpasswd_make_pwchange_reply(kdc, mem_ctx,
    412417                                                   status,
    413                                                    reject_reason, 
    414                                                    dominfo, 
     418                                                   reject_reason,
     419                                                   dominfo,
    415420                                                   reply);
    416421        }
    417422        default:
    418                 return kpasswdd_make_error_reply(kdc, mem_ctx, 
     423                return kpasswdd_make_error_reply(kdc, mem_ctx,
    419424                                                 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",
    422427                                                                 version),
    423428                                                 reply);
    424429        }
    425         return true;
    426430}
    427431
    428 bool kpasswdd_process(struct kdc_server *kdc,
    429                       TALLOC_CTX *mem_ctx,
    430                       DATA_BLOB *input,
    431                       DATA_BLOB *reply,
    432                       struct socket_address *peer_addr,
    433                       struct socket_address *my_addr,
    434                       int datagram_reply)
     432enum 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)
    435439{
    436440        bool ret;
     
    452456
    453457        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;
    455464        }
    456465
     
    459468        if (input->length <= header_len) {
    460469                talloc_free(tmp_ctx);
    461                 return false;
     470                return KDC_PROCESS_FAILED;
    462471        }
    463472
     
    465474        if (input->length != len) {
    466475                talloc_free(tmp_ctx);
    467                 return false;
     476                return KDC_PROCESS_FAILED;
    468477        }
    469478
     
    475484        if ((ap_req_len >= len) || (ap_req_len + header_len) >= len) {
    476485                talloc_free(tmp_ctx);
    477                 return false;
    478         }
    479        
     486                return KDC_PROCESS_FAILED;
     487        }
     488
    480489        krb_priv_len = len - ap_req_len;
    481490        ap_req = data_blob_const(&input->data[header_len], ap_req_len);
    482491        krb_priv_req = data_blob_const(&input->data[header_len + ap_req_len], krb_priv_len);
    483        
     492
    484493        server_credentials = cli_credentials_init(tmp_ctx);
    485494        if (!server_credentials) {
    486495                DEBUG(1, ("Failed to init server credentials\n"));
    487                 return false;
     496                talloc_free(tmp_ctx);
     497                return KDC_PROCESS_FAILED;
    488498        }
    489499
    490500        /* 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 */
    492502        cli_credentials_set_krb5_context(server_credentials, kdc->smb_krb5_context);
    493503        cli_credentials_set_conf(server_credentials, kdc->task->lp_ctx);
    494504
    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);
    496506
    497507        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);
    499509        if (ret != 0) {
    500                 ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx, 
     510                ret = kpasswdd_make_unauth_error_reply(kdc, mem_ctx,
    501511                                                       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!"),
    505514                                                       &krb_priv_rep);
    506515                ap_rep.length = 0;
     
    511520                return ret;
    512521        }
    513        
     522
    514523        /* We don't strictly need to call this wrapper, and could call
    515524         * gensec_server_start directly, as we have no need for NTLM
    516525         * and we have a PAC, but this ensures that the wrapper can be
    517526         * 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,
    519528                                              kdc->task->msg_ctx,
    520529                                              kdc->task->lp_ctx,
    521530                                              server_credentials,
    522                                               "kpasswd", 
     531                                              "kpasswd",
    523532                                              &gensec_security);
    524533        if (!NT_STATUS_IS_OK(nt_status)) {
    525534                talloc_free(tmp_ctx);
    526                 return false;
     535                return KDC_PROCESS_FAILED;
    527536        }
    528537
     
    535544         * complex code */
    536545
    537         nt_status = gensec_set_peer_addr(gensec_security, peer_addr);
     546        nt_status = gensec_set_local_address(gensec_security, peer_addr);
    538547        if (!NT_STATUS_IS_OK(nt_status)) {
    539548                talloc_free(tmp_ctx);
    540                 return false;
     549                return KDC_PROCESS_FAILED;
    541550        }
    542551#endif
    543552
    544         nt_status = gensec_set_my_addr(gensec_security, my_addr);
     553        nt_status = gensec_set_local_address(gensec_security, my_addr);
    545554        if (!NT_STATUS_IS_OK(nt_status)) {
    546555                talloc_free(tmp_ctx);
    547                 return false;
     556                return KDC_PROCESS_FAILED;
    548557        }
    549558
     
    554563        if (!NT_STATUS_IS_OK(nt_status)) {
    555564                talloc_free(tmp_ctx);
    556                 return false;
     565                return KDC_PROCESS_FAILED;
    557566        }
    558567
     
    560569        nt_status = gensec_update(gensec_security, tmp_ctx, ap_req, &ap_rep);
    561570        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,
    564573                                                       KRB5_KPASSWD_HARDERROR,
    565                                                        talloc_asprintf(mem_ctx, 
    566                                                                        "gensec_update failed: %s", 
     574                                                       talloc_asprintf(mem_ctx,
     575                                                                       "gensec_update failed: %s",
    567576                                                                       nt_errstr(nt_status)),
    568577                                                       &krb_priv_rep);
     
    572581                }
    573582                talloc_free(tmp_ctx);
    574                 return ret;
     583                return KDC_PROCESS_FAILED;
    575584        }
    576585
     
    578587        nt_status = gensec_unwrap(gensec_security, tmp_ctx, &krb_priv_req, &kpasswd_req);
    579588        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,
    581590                                                       KRB5_KPASSWD_HARDERROR,
    582                                                        talloc_asprintf(mem_ctx, 
    583                                                                        "gensec_unwrap failed: %s", 
     591                                                       talloc_asprintf(mem_ctx,
     592                                                                       "gensec_unwrap failed: %s",
    584593                                                                       nt_errstr(nt_status)),
    585594                                                       &krb_priv_rep);
     
    589598                }
    590599                talloc_free(tmp_ctx);
    591                 return ret;
     600                return KDC_PROCESS_FAILED;
    592601        }
    593602
    594603        /* 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);
    599608        if (!ret) {
    600609                /* Argh! */
    601                 return false;
     610                talloc_free(tmp_ctx);
     611                return KDC_PROCESS_FAILED;
    602612        }
    603613
    604614        /* And wrap up the reply: This ensures that the error message
    605615         * 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,
    607617                                &kpasswd_rep, &krb_priv_rep);
    608618        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,
    610620                                                       KRB5_KPASSWD_HARDERROR,
    611                                                        talloc_asprintf(mem_ctx, 
    612                                                                        "gensec_wrap failed: %s", 
     621                                                       talloc_asprintf(mem_ctx,
     622                                                                       "gensec_wrap failed: %s",
    613623                                                                       nt_errstr(nt_status)),
    614624                                                       &krb_priv_rep);
     
    618628                }
    619629                talloc_free(tmp_ctx);
    620                 return ret;
    621         }
    622        
     630                return KDC_PROCESS_FAILED;
     631        }
     632
    623633reply:
    624634        *reply = data_blob_talloc(mem_ctx, NULL, krb_priv_rep.length + ap_rep.length + header_len);
    625635        if (!reply->data) {
    626                 return false;
     636                talloc_free(tmp_ctx);
     637                return KDC_PROCESS_FAILED;
    627638        }
    628639
     
    630641        RSSVAL(reply->data, 2, 1); /* This is a version 1 reply, MS change/set or otherwise */
    631642        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,
    634645               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,
    637648               krb_priv_rep.length);
    638649
    639650        talloc_free(tmp_ctx);
    640         return ret;
     651        return KDC_PROCESS_OK;
    641652}
    642653
  • vendor/current/source4/kdc/pac-glue.c

    r414 r740  
    1 /* 
     1/*
    22   Unix SMB/CIFS implementation.
    33
    44   PAC Glue between Samba and the KDC
    5    
     5
    66   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
     7   Copyright (C) Simo Sorce <idra@samba.org> 2010
    78
    89   This program is free software; you can redistribute it and/or modify
     
    1011   the Free Software Foundation; either version 3 of the License, or
    1112   (at your option) any later version.
    12    
     13
    1314   This program is distributed in the hope that it will be useful,
    1415   but WITHOUT ANY WARRANTY; without even the implied warranty of
     
    1617   GNU General Public License for more details.
    1718
    18    
     19
    1920   You should have received a copy of the GNU General Public License
    2021   along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
    2324#include "includes.h"
    2425#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"
    2631#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
     33static
     34NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
     35                                       struct auth_user_info_dc *info,
     36                                       DATA_BLOB *pac_data)
     37{
    5538        struct netr_SamInfo3 *info3;
    56         krb5_data pac_data;
    57         NTSTATUS nt_status;
     39        union PAC_INFO pac_info;
    5840        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);
    6546        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);
    7153        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,
    7860                                      PAC_TYPE_LOGON_INFO,
    7961                                      (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
    8062        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    8163                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
     72krb5_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);
    8785        if (ret != 0) {
    8886                return ret;
     
    104102}
    105103
    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 */
     104bool 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 */
    124112        userAccountControl = ldb_msg_find_attr_as_uint(p->msg, "userAccountControl", 0);
    125113        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) */
     121bool 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
     138NTSTATUS 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),
    133161                                             p->realm_dn,
    134162                                             p->msg,
    135163                                             data_blob(NULL, 0),
    136164                                             data_blob(NULL, 0),
    137                                              &server_info);
     165                                             &user_info_dc);
    138166        if (!NT_STATUS_IS_OK(nt_status)) {
    139167                DEBUG(0, ("Getting user info for PAC failed: %s\n",
    140168                          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
     183NTSTATUS 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;
    157188        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);
    185193        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 */
     205void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
    198206{
    199207        PA_DATA pa;
     
    227235}
    228236
    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 */
     238krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
    240239{
    241240        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 */
     264NTSTATUS 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{
    243269        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");
    253273        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        }
    277276
    278277        /* 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/*
    22   Unix SMB/CIFS implementation.
    33
    4    KDC Server startup
     4   PAC Glue between Samba and the KDC
    55
    66   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
     7   Copyright (C) Simo Sorce <idra@samba.org> 2010
    78
    89   This program is free software; you can redistribute it and/or modify
     
    1011   the Free Software Foundation; either version 3 of the License, or
    1112   (at your option) any later version.
    12    
     13
    1314   This program is distributed in the hope that it will be useful,
    1415   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1516   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1617   GNU General Public License for more details.
    17    
     18
     19
    1820   You should have received a copy of the GNU General Public License
    1921   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    2022*/
    2123
    22 #ifndef __KDC_PAC_GLUE_H__
    23 #define __KDC_PAC_GLUE_H__
     24krb5_error_code samba_make_krb5_pac(krb5_context context,
     25                                    DATA_BLOB *pac_blob,
     26                                    krb5_pac *pac);
    2427
    25 #include "kdc/pac-glue_proto.h"
     28bool samba_princ_needs_pac(struct hdb_entry_ex *princ);
    2629
    27 extern struct krb5plugin_windc_ftable windc_plugin_table;
     30bool samba_krbtgt_was_untrusted_rodc(struct hdb_entry_ex *princ);
    2831
    29 #endif /* __KDC_PAC_GLUE_H__ */
     32NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
     33                                struct hdb_entry_ex *client,
     34                                DATA_BLOB **_pac_blob);
    3035
     36NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
     37                                   krb5_context context,
     38                                   krb5_pac *pac, DATA_BLOB *pac_blob);
     39
     40void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data);
     41
     42krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status);
     43
     44NTSTATUS 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.