2005-06-03 18:32:10 +04:00
/*
* Copyright ( c ) 1999 - 2001 , 2003 , PADL Software Pty Ltd .
2009-05-26 06:31:39 +04:00
* Copyright ( c ) 2004 - 2009 , Andrew Bartlett < abartlet @ samba . org > .
2005-06-03 18:32:10 +04:00
* Copyright ( c ) 2004 , Stefan Metzmacher < metze @ samba . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* 3. Neither the name of PADL Software nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
# include "includes.h"
2006-05-25 19:12:23 +04:00
# include "system/time.h"
2009-06-12 16:27:19 +04:00
# include "../libds/common/flags.h"
2005-06-04 09:35:27 +04:00
# include "lib/ldb/include/ldb.h"
2005-11-08 03:11:45 +03:00
# include "lib/ldb/include/ldb_errors.h"
2005-11-06 17:15:34 +03:00
# include "librpc/gen_ndr/netlogon.h"
2009-05-26 07:09:57 +04:00
# include "libcli/security/security.h"
2005-12-11 11:31:46 +03:00
# include "auth/auth.h"
2006-11-07 03:48:36 +03:00
# include "auth/credentials/credentials.h"
2006-03-07 14:07:23 +03:00
# include "auth/auth_sam.h"
2008-10-11 23:31:42 +04:00
# include "../lib/util/util_ldb.h"
2005-12-28 18:38:36 +03:00
# include "dsdb/samdb/samdb.h"
2007-02-19 01:01:02 +03:00
# include "librpc/ndr/libndr.h"
# include "librpc/gen_ndr/ndr_drsblobs.h"
2008-08-26 04:27:00 +04:00
# include "librpc/gen_ndr/lsa.h"
2007-02-19 01:01:02 +03:00
# include "libcli/auth/libcli_auth.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2008-04-17 14:23:44 +04:00
# include "events/events.h"
2008-06-04 17:39:17 +04:00
# include "kdc/kdc.h"
2008-09-24 17:30:23 +04:00
# include "../lib/crypto/md4.h"
2005-06-03 18:32:10 +04:00
2009-12-23 23:08:02 +03:00
enum hdb_samba4_ent_type
{ HDB_SAMBA4_ENT_TYPE_CLIENT , HDB_SAMBA4_ENT_TYPE_SERVER ,
2008-09-24 23:53:10 +04:00
HDB_SAMBA4_ENT_TYPE_KRBTGT , HDB_SAMBA4_ENT_TYPE_TRUST , HDB_SAMBA4_ENT_TYPE_ANY } ;
2005-06-03 18:32:10 +04:00
2008-08-15 15:16:20 +04:00
enum trust_direction {
2008-08-26 04:27:00 +04:00
UNKNOWN = 0 ,
2009-12-23 23:08:02 +03:00
INBOUND = LSA_TRUST_DIRECTION_INBOUND ,
2008-08-26 04:27:00 +04:00
OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
2008-08-15 15:16:20 +04:00
} ;
2008-08-08 04:35:57 +04:00
static const char * trust_attrs [ ] = {
" trustPartner " ,
" trustAuthIncoming " ,
" trustAuthOutgoing " ,
" whenCreated " ,
2008-08-15 15:16:20 +04:00
" msDS-SupportedEncryptionTypes " ,
" trustAttributes " ,
" trustDirection " ,
" trustType " ,
2008-08-08 04:35:57 +04:00
NULL
} ;
2005-06-03 18:32:10 +04:00
static KerberosTime ldb_msg_find_krb5time_ldap_time ( struct ldb_message * msg , const char * attr , KerberosTime default_val )
{
const char * tmp ;
const char * gentime ;
struct tm tm ;
2006-08-13 12:00:36 +04:00
gentime = ldb_msg_find_attr_as_string ( msg , attr , NULL ) ;
2005-06-03 18:32:10 +04:00
if ( ! gentime )
return default_val ;
tmp = strptime ( gentime , " %Y%m%d%H%M%SZ " , & tm ) ;
if ( tmp = = NULL ) {
return default_val ;
}
return timegm ( & tm ) ;
}
2009-12-23 23:08:02 +03:00
static HDBFlags uf2HDBFlags ( krb5_context context , int userAccountControl , enum hdb_samba4_ent_type ent_type )
2005-06-03 18:32:10 +04:00
{
HDBFlags flags = int2HDBFlags ( 0 ) ;
/* we don't allow kadmin deletes */
flags . immutable = 1 ;
/* mark the principal as invalid to start with */
flags . invalid = 1 ;
2005-06-28 04:56:39 +04:00
flags . renewable = 1 ;
2005-11-05 14:29:34 +03:00
/* All accounts are servers, but this may be disabled again in the caller */
flags . server = 1 ;
2005-06-03 18:32:10 +04:00
/* Account types - clear the invalid bit if it turns out to be valid */
if ( userAccountControl & UF_NORMAL_ACCOUNT ) {
2008-09-24 23:53:10 +04:00
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_CLIENT | | ent_type = = HDB_SAMBA4_ENT_TYPE_ANY ) {
2005-06-03 18:32:10 +04:00
flags . client = 1 ;
}
flags . invalid = 0 ;
}
2009-12-23 23:08:02 +03:00
2005-06-03 18:32:10 +04:00
if ( userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT ) {
2008-09-24 23:53:10 +04:00
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_CLIENT | | ent_type = = HDB_SAMBA4_ENT_TYPE_ANY ) {
2005-06-03 18:32:10 +04:00
flags . client = 1 ;
}
flags . invalid = 0 ;
}
if ( userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT ) {
2008-09-24 23:53:10 +04:00
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_CLIENT | | ent_type = = HDB_SAMBA4_ENT_TYPE_ANY ) {
2005-06-03 18:32:10 +04:00
flags . client = 1 ;
}
flags . invalid = 0 ;
}
if ( userAccountControl & UF_SERVER_TRUST_ACCOUNT ) {
2008-09-24 23:53:10 +04:00
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_CLIENT | | ent_type = = HDB_SAMBA4_ENT_TYPE_ANY ) {
2005-06-03 18:32:10 +04:00
flags . client = 1 ;
}
flags . invalid = 0 ;
}
2005-10-20 08:56:47 +04:00
/* Not permitted to act as a client if disabled */
2005-06-03 18:32:10 +04:00
if ( userAccountControl & UF_ACCOUNTDISABLE ) {
2005-10-20 08:56:47 +04:00
flags . client = 0 ;
2005-06-03 18:32:10 +04:00
}
if ( userAccountControl & UF_LOCKOUT ) {
flags . invalid = 1 ;
}
/*
if ( userAccountControl & UF_PASSWORD_NOTREQD ) {
flags . invalid = 1 ;
}
*/
/*
2006-07-12 04:56:27 +04:00
UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent
2005-06-03 18:32:10 +04:00
*/
if ( userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT ) {
flags . invalid = 1 ;
}
2009-07-16 06:47:57 +04:00
/* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in hdb_samba4_message2entry() */
2005-06-03 18:32:10 +04:00
/*
if ( userAccountControl & UF_MNS_LOGON_ACCOUNT ) {
flags . invalid = 1 ;
}
*/
if ( userAccountControl & UF_SMARTCARD_REQUIRED ) {
flags . require_hwauth = 1 ;
}
2005-11-07 05:29:37 +03:00
if ( userAccountControl & UF_TRUSTED_FOR_DELEGATION ) {
flags . ok_as_delegate = 1 ;
2009-12-23 23:08:02 +03:00
}
2005-11-07 05:29:37 +03:00
if ( ! ( userAccountControl & UF_NOT_DELEGATED ) ) {
2005-06-03 18:32:10 +04:00
flags . forwardable = 1 ;
flags . proxiable = 1 ;
}
if ( userAccountControl & UF_DONT_REQUIRE_PREAUTH ) {
flags . require_preauth = 0 ;
} else {
flags . require_preauth = 1 ;
}
return flags ;
}
2009-07-27 07:48:45 +04:00
static int hdb_samba4_destructor ( struct hdb_samba4_private * p )
2005-11-07 05:29:37 +03:00
{
2009-02-01 01:43:43 +03:00
hdb_entry_ex * entry_ex = p - > entry_ex ;
2005-12-15 23:38:24 +03:00
free_hdb_entry ( & entry_ex - > entry ) ;
return 0 ;
}
2009-07-27 07:48:45 +04:00
static void hdb_samba4_free_entry ( krb5_context context , hdb_entry_ex * entry_ex )
2005-12-15 23:38:24 +03:00
{
talloc_free ( entry_ex - > ctx ) ;
2005-11-07 05:29:37 +03:00
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_message2entry_keys ( krb5_context context ,
2008-02-21 16:16:02 +03:00
struct smb_iconv_convenience * iconv_convenience ,
2007-02-15 15:56:46 +03:00
TALLOC_CTX * mem_ctx ,
2007-02-14 14:47:17 +03:00
struct ldb_message * msg ,
unsigned int userAccountControl ,
hdb_entry_ex * entry_ex )
{
krb5_error_code ret = 0 ;
2007-11-09 21:24:51 +03:00
enum ndr_err_code ndr_err ;
2007-02-15 15:56:46 +03:00
struct samr_Password * hash ;
2007-02-19 01:01:02 +03:00
const struct ldb_val * sc_val ;
struct supplementalCredentialsBlob scb ;
2008-07-22 20:47:27 +04:00
struct supplementalCredentialsPackage * scpk = NULL ;
2008-07-24 10:23:15 +04:00
bool newer_keys = false ;
2007-02-19 01:01:02 +03:00
struct package_PrimaryKerberosBlob _pkb ;
2007-02-19 03:28:11 +03:00
struct package_PrimaryKerberosCtr3 * pkb3 = NULL ;
2008-07-24 10:23:15 +04:00
struct package_PrimaryKerberosCtr4 * pkb4 = NULL ;
2007-02-19 01:01:02 +03:00
uint32_t i ;
2007-02-15 15:56:46 +03:00
uint32_t allocated_keys = 0 ;
entry_ex - > entry . keys . val = NULL ;
entry_ex - > entry . keys . len = 0 ;
2007-02-14 14:47:17 +03:00
2007-02-16 18:56:24 +03:00
entry_ex - > entry . kvno = ldb_msg_find_attr_as_int ( msg , " msDS-KeyVersionNumber " , 0 ) ;
2007-02-19 01:01:02 +03:00
/* Get keys from the db */
2007-02-14 14:47:17 +03:00
2007-02-15 15:56:46 +03:00
hash = samdb_result_hash ( mem_ctx , msg , " unicodePwd " ) ;
2007-02-19 01:01:02 +03:00
sc_val = ldb_msg_find_ldb_val ( msg , " supplementalCredentials " ) ;
2007-02-15 15:56:46 +03:00
2007-02-19 01:01:02 +03:00
/* unicodePwd for enctype 0x17 (23) if present */
2007-02-15 15:56:46 +03:00
if ( hash ) {
allocated_keys + + ;
}
2007-02-14 14:47:17 +03:00
2007-02-19 01:01:02 +03:00
/* supplementalCredentials if present */
if ( sc_val ) {
2008-02-21 16:16:02 +03:00
ndr_err = ndr_pull_struct_blob_all ( sc_val , mem_ctx , iconv_convenience , & scb ,
2007-11-09 21:24:51 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_supplementalCredentialsBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2007-02-19 01:01:02 +03:00
dump_data ( 0 , sc_val - > data , sc_val - > length ) ;
ret = EINVAL ;
goto out ;
}
2008-07-23 15:41:51 +04:00
if ( scb . sub . signature ! = SUPPLEMENTAL_CREDENTIALS_SIGNATURE ) {
NDR_PRINT_DEBUG ( supplementalCredentialsBlob , & scb ) ;
ret = EINVAL ;
goto out ;
}
2007-02-19 01:01:02 +03:00
for ( i = 0 ; i < scb . sub . num_packages ; i + + ) {
2008-07-22 20:47:27 +04:00
if ( strcmp ( " Primary:Kerberos-Newer-Keys " , scb . sub . packages [ i ] . name ) = = 0 ) {
2008-07-24 10:23:15 +04:00
scpk = & scb . sub . packages [ i ] ;
if ( ! scpk - > data | | ! scpk - > data [ 0 ] ) {
scpk = NULL ;
2008-07-22 20:47:27 +04:00
continue ;
}
2008-07-24 10:23:15 +04:00
newer_keys = true ;
2008-07-22 20:47:27 +04:00
break ;
} else if ( strcmp ( " Primary:Kerberos " , scb . sub . packages [ i ] . name ) = = 0 ) {
scpk = & scb . sub . packages [ i ] ;
if ( ! scpk - > data | | ! scpk - > data [ 0 ] ) {
scpk = NULL ;
}
/*
* we don ' t break here in hope to find
* a Kerberos - Newer - Keys package
*/
2007-02-19 01:01:02 +03:00
}
2008-07-22 20:47:27 +04:00
}
}
2008-07-24 10:23:15 +04:00
/*
* Primary : Kerberos - Newer - Keys or Primary : Kerberos element
* of supplementalCredentials
*/
if ( scpk ) {
2007-02-19 01:01:02 +03:00
DATA_BLOB blob ;
2008-10-18 20:09:04 +04:00
blob = strhex_to_data_blob ( mem_ctx , scpk - > data ) ;
2007-02-19 01:01:02 +03:00
if ( ! blob . data ) {
ret = ENOMEM ;
goto out ;
}
2008-07-22 20:46:24 +04:00
/* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
2008-02-21 16:16:02 +03:00
ndr_err = ndr_pull_struct_blob ( & blob , mem_ctx , iconv_convenience , & _pkb ,
2007-11-09 21:24:51 +03:00
( ndr_pull_flags_fn_t ) ndr_pull_package_PrimaryKerberosBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
2007-02-19 01:01:02 +03:00
ret = EINVAL ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_message2entry_keys: could not parse package_PrimaryKerberosBlob " ) ;
krb5_warnx ( context , " hdb_samba4_message2entry_keys: could not parse package_PrimaryKerberosBlob " ) ;
2007-02-19 01:01:02 +03:00
goto out ;
}
2008-07-24 10:23:15 +04:00
if ( newer_keys & & _pkb . version ! = 4 ) {
2007-02-19 03:28:11 +03:00
ret = EINVAL ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4 " ) ;
krb5_warnx ( context , " hdb_samba4_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4 " ) ;
2007-02-19 03:28:11 +03:00
goto out ;
}
2008-07-24 10:23:15 +04:00
if ( ! newer_keys & & _pkb . version ! = 3 ) {
ret = EINVAL ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_message2entry_keys: could not parse Primary:Kerberos not version 3 " ) ;
krb5_warnx ( context , " hdb_samba4_message2entry_keys: could not parse Primary:Kerberos not version 3 " ) ;
2008-07-24 10:23:15 +04:00
goto out ;
}
if ( _pkb . version = = 4 ) {
pkb4 = & _pkb . ctr . ctr4 ;
allocated_keys + = pkb4 - > num_keys ;
} else if ( _pkb . version = = 3 ) {
pkb3 = & _pkb . ctr . ctr3 ;
allocated_keys + = pkb3 - > num_keys ;
}
2007-02-19 01:01:02 +03:00
}
2007-02-15 15:56:46 +03:00
if ( allocated_keys = = 0 ) {
2007-02-14 14:47:17 +03:00
/* oh, no password. Apparently (comment in
* hdb - ldap . c ) this violates the ASN .1 , but this
* allows an entry with no keys ( yet ) . */
2007-02-15 15:56:46 +03:00
return 0 ;
}
2007-02-14 14:47:17 +03:00
2007-02-15 15:56:46 +03:00
/* allocate space to decode into */
entry_ex - > entry . keys . len = 0 ;
entry_ex - > entry . keys . val = calloc ( allocated_keys , sizeof ( Key ) ) ;
if ( entry_ex - > entry . keys . val = = NULL ) {
ret = ENOMEM ;
goto out ;
}
2007-02-14 14:47:17 +03:00
2007-02-19 01:01:02 +03:00
if ( hash & & ! ( userAccountControl & UF_USE_DES_KEY_ONLY ) ) {
2007-02-15 15:56:46 +03:00
Key key ;
key . mkvno = 0 ;
key . salt = NULL ; /* No salt for this enc type */
ret = krb5_keyblock_init ( context ,
2009-08-18 06:08:37 +04:00
ENCTYPE_ARCFOUR_HMAC ,
2009-12-23 23:08:02 +03:00
hash - > hash , sizeof ( hash - > hash ) ,
2007-02-15 15:56:46 +03:00
& key . key ) ;
if ( ret ) {
goto out ;
2007-02-14 14:47:17 +03:00
}
2007-02-15 15:56:46 +03:00
entry_ex - > entry . keys . val [ entry_ex - > entry . keys . len ] = key ;
entry_ex - > entry . keys . len + + ;
}
2007-02-14 14:47:17 +03:00
2008-07-22 20:47:27 +04:00
if ( pkb4 ) {
for ( i = 0 ; i < pkb4 - > num_keys ; i + + ) {
bool use = true ;
Key key ;
if ( ! pkb4 - > keys [ i ] . value ) continue ;
if ( userAccountControl & UF_USE_DES_KEY_ONLY ) {
switch ( pkb4 - > keys [ i ] . keytype ) {
case ENCTYPE_DES_CBC_CRC :
case ENCTYPE_DES_CBC_MD5 :
break ;
default :
use = false ;
break ;
}
}
if ( ! use ) continue ;
key . mkvno = 0 ;
key . salt = NULL ;
if ( pkb4 - > salt . string ) {
DATA_BLOB salt ;
salt = data_blob_string_const ( pkb4 - > salt . string ) ;
key . salt = calloc ( 1 , sizeof ( * key . salt ) ) ;
if ( key . salt = = NULL ) {
ret = ENOMEM ;
goto out ;
}
key . salt - > type = hdb_pw_salt ;
ret = krb5_data_copy ( & key . salt - > salt , salt . data , salt . length ) ;
if ( ret ) {
free ( key . salt ) ;
key . salt = NULL ;
goto out ;
}
}
2008-07-24 10:23:15 +04:00
/* TODO: maybe pass the iteration_count somehow... */
2008-07-22 20:47:27 +04:00
ret = krb5_keyblock_init ( context ,
pkb4 - > keys [ i ] . keytype ,
pkb4 - > keys [ i ] . value - > data ,
pkb4 - > keys [ i ] . value - > length ,
& key . key ) ;
2009-09-19 05:04:15 +04:00
if ( ret = = KRB5_PROG_ETYPE_NOSUPP ) {
DEBUG ( 2 , ( " Unsupported keytype ignored - type %u \n " ,
pkb4 - > keys [ i ] . keytype ) ) ;
ret = 0 ;
continue ;
}
2008-07-22 20:47:27 +04:00
if ( ret ) {
if ( key . salt ) {
free_Salt ( key . salt ) ;
free ( key . salt ) ;
key . salt = NULL ;
}
goto out ;
}
entry_ex - > entry . keys . val [ entry_ex - > entry . keys . len ] = key ;
entry_ex - > entry . keys . len + + ;
}
} else if ( pkb3 ) {
2007-02-19 03:28:11 +03:00
for ( i = 0 ; i < pkb3 - > num_keys ; i + + ) {
2007-02-19 01:01:02 +03:00
bool use = true ;
Key key ;
2007-02-19 03:28:11 +03:00
if ( ! pkb3 - > keys [ i ] . value ) continue ;
2007-02-19 01:01:02 +03:00
if ( userAccountControl & UF_USE_DES_KEY_ONLY ) {
2007-02-19 03:28:11 +03:00
switch ( pkb3 - > keys [ i ] . keytype ) {
2007-02-19 01:01:02 +03:00
case ENCTYPE_DES_CBC_CRC :
case ENCTYPE_DES_CBC_MD5 :
break ;
default :
use = false ;
break ;
}
}
if ( ! use ) continue ;
key . mkvno = 0 ;
2008-07-22 20:34:14 +04:00
key . salt = NULL ;
2007-02-19 01:01:02 +03:00
2007-02-19 03:28:11 +03:00
if ( pkb3 - > salt . string ) {
2007-02-19 01:01:02 +03:00
DATA_BLOB salt ;
2007-02-19 03:28:11 +03:00
salt = data_blob_string_const ( pkb3 - > salt . string ) ;
2007-02-19 01:01:02 +03:00
key . salt = calloc ( 1 , sizeof ( * key . salt ) ) ;
if ( key . salt = = NULL ) {
ret = ENOMEM ;
goto out ;
}
key . salt - > type = hdb_pw_salt ;
ret = krb5_data_copy ( & key . salt - > salt , salt . data , salt . length ) ;
if ( ret ) {
free ( key . salt ) ;
key . salt = NULL ;
goto out ;
}
}
ret = krb5_keyblock_init ( context ,
2007-02-19 03:28:11 +03:00
pkb3 - > keys [ i ] . keytype ,
pkb3 - > keys [ i ] . value - > data ,
pkb3 - > keys [ i ] . value - > length ,
2007-02-19 01:01:02 +03:00
& key . key ) ;
if ( ret ) {
if ( key . salt ) {
free_Salt ( key . salt ) ;
free ( key . salt ) ;
key . salt = NULL ;
}
goto out ;
}
entry_ex - > entry . keys . val [ entry_ex - > entry . keys . len ] = key ;
entry_ex - > entry . keys . len + + ;
}
}
2007-02-14 14:47:17 +03:00
out :
2007-02-19 01:01:02 +03:00
if ( ret ! = 0 ) {
2007-02-19 03:28:11 +03:00
entry_ex - > entry . keys . len = 0 ;
2007-02-19 01:01:02 +03:00
}
if ( entry_ex - > entry . keys . len = = 0 & & entry_ex - > entry . keys . val ) {
2007-02-15 15:56:46 +03:00
free ( entry_ex - > entry . keys . val ) ;
entry_ex - > entry . keys . val = NULL ;
}
2007-02-14 14:47:17 +03:00
return ret ;
}
2005-06-03 18:32:10 +04:00
/*
* Construct an hdb_entry from a directory entry .
*/
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_message2entry ( krb5_context context , HDB * db ,
struct loadparm_context * lp_ctx ,
2005-06-03 18:32:10 +04:00
TALLOC_CTX * mem_ctx , krb5_const_principal principal ,
2009-07-27 07:48:45 +04:00
enum hdb_samba4_ent_type ent_type ,
2009-05-26 06:31:39 +04:00
struct ldb_dn * realm_dn ,
2005-06-03 18:32:10 +04:00
struct ldb_message * msg ,
2005-11-07 05:29:37 +03:00
hdb_entry_ex * entry_ex )
2005-06-03 18:32:10 +04:00
{
2005-11-07 05:29:37 +03:00
unsigned int userAccountControl ;
2005-06-03 18:32:10 +04:00
int i ;
krb5_error_code ret = 0 ;
2005-12-19 10:11:58 +03:00
krb5_boolean is_computer = FALSE ;
2009-05-26 06:31:39 +04:00
char * realm = strupper_talloc ( mem_ctx , lp_realm ( lp_ctx ) ) ;
2005-06-03 18:32:10 +04:00
2009-07-27 07:48:45 +04:00
struct hdb_samba4_private * p ;
2005-11-08 05:30:42 +03:00
NTTIME acct_expiry ;
2009-05-26 07:09:57 +04:00
NTSTATUS status ;
2005-11-06 00:26:28 +03:00
2009-05-26 07:09:57 +04:00
uint32_t rid ;
2005-12-19 10:11:58 +03:00
struct ldb_message_element * objectclasses ;
struct ldb_val computer_val ;
2009-05-26 06:31:39 +04:00
const char * samAccountName = ldb_msg_find_attr_as_string ( msg , " samAccountName " , NULL ) ;
2005-12-19 10:11:58 +03:00
computer_val . data = discard_const_p ( uint8_t , " computer " ) ;
computer_val . length = strlen ( ( const char * ) computer_val . data ) ;
2009-12-23 23:08:02 +03:00
2009-05-26 06:31:39 +04:00
if ( ! samAccountName ) {
ret = ENOENT ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_message2entry: no samAccountName present " ) ;
2009-05-26 06:31:39 +04:00
goto out ;
}
2005-12-19 10:11:58 +03:00
objectclasses = ldb_msg_find_element ( msg , " objectClass " ) ;
2009-12-23 23:08:02 +03:00
2005-12-19 10:11:58 +03:00
if ( objectclasses & & ldb_msg_find_val ( objectclasses , & computer_val ) ) {
is_computer = TRUE ;
}
2005-12-15 23:38:24 +03:00
memset ( entry_ex , 0 , sizeof ( * entry_ex ) ) ;
2005-11-06 00:26:28 +03:00
2005-06-03 18:32:10 +04:00
if ( ! realm ) {
ret = ENOMEM ;
2009-06-08 13:06:16 +04:00
krb5_set_error_message ( context , ret , " talloc_strdup: out of memory " ) ;
2005-06-03 18:32:10 +04:00
goto out ;
}
2009-12-23 23:08:02 +03:00
2009-07-27 07:48:45 +04:00
p = talloc ( mem_ctx , struct hdb_samba4_private ) ;
2009-02-01 01:43:43 +03:00
if ( ! p ) {
2005-12-15 23:38:24 +03:00
ret = ENOMEM ;
goto out ;
}
2009-02-01 01:43:43 +03:00
p - > entry_ex = entry_ex ;
p - > iconv_convenience = lp_iconv_convenience ( lp_ctx ) ;
2009-05-26 06:31:39 +04:00
p - > lp_ctx = lp_ctx ;
p - > realm_dn = talloc_reference ( p , realm_dn ) ;
if ( ! p - > realm_dn ) {
ret = ENOMEM ;
goto out ;
}
2005-12-15 23:38:24 +03:00
2009-07-27 07:48:45 +04:00
talloc_set_destructor ( p , hdb_samba4_destructor ) ;
2005-12-15 23:38:24 +03:00
2009-02-01 01:43:43 +03:00
entry_ex - > ctx = p ;
2009-07-27 07:48:45 +04:00
entry_ex - > free_entry = hdb_samba4_free_entry ;
2005-12-15 23:38:24 +03:00
2006-08-13 12:00:36 +04:00
userAccountControl = ldb_msg_find_attr_as_uint ( msg , " userAccountControl " , 0 ) ;
2005-12-19 10:11:58 +03:00
2009-12-23 23:08:02 +03:00
2005-12-15 23:38:24 +03:00
entry_ex - > entry . principal = malloc ( sizeof ( * ( entry_ex - > entry . principal ) ) ) ;
2008-09-24 23:53:10 +04:00
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_ANY & & principal = = NULL ) {
2005-12-15 23:38:24 +03:00
krb5_make_principal ( context , & entry_ex - > entry . principal , realm , samAccountName , NULL ) ;
2005-06-03 18:32:10 +04:00
} else {
2005-12-15 23:38:24 +03:00
ret = copy_Principal ( principal , entry_ex - > entry . principal ) ;
2005-06-03 18:32:10 +04:00
if ( ret ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2005-06-03 18:32:10 +04:00
goto out ;
}
/* While we have copied the client principal, tests
* show that Win2k3 returns the ' corrected ' realm , not
* the client - specified realm . This code attempts to
* replace the client principal ' s realm with the one
* we determine from our records */
2009-12-23 23:08:02 +03:00
2005-06-03 18:32:10 +04:00
/* this has to be with malloc() */
2009-06-08 13:06:16 +04:00
krb5_principal_set_realm ( context , entry_ex - > entry . principal , realm ) ;
2005-06-03 18:32:10 +04:00
}
2009-05-26 06:31:39 +04:00
/* First try and figure out the flags based on the userAccountControl */
2005-12-15 23:38:24 +03:00
entry_ex - > entry . flags = uf2HDBFlags ( context , userAccountControl , ent_type ) ;
2005-06-03 18:32:10 +04:00
2009-05-26 06:31:39 +04:00
/* Windows 2008 seems to enforce this (very sensible) rule by
* default - don ' t allow offline attacks on a user ' s password
* by asking for a ticket to them as a service ( encrypted with
* their probably patheticly insecure password ) */
2009-05-26 07:09:57 +04:00
if ( entry_ex - > entry . flags . server
& & lp_parm_bool ( lp_ctx , NULL , " kdc " , " require spn for service " , true ) ) {
2006-08-13 12:00:36 +04:00
if ( ! is_computer & & ! ldb_msg_find_attr_as_string ( msg , " servicePrincipalName " , NULL ) ) {
2005-12-15 23:38:24 +03:00
entry_ex - > entry . flags . server = 0 ;
2005-11-05 14:29:34 +03:00
}
}
2009-05-26 07:09:57 +04:00
{
/* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
* of the Heimdal KDC . They are stored in a the traditional
* DB for audit purposes , and still form part of the structure
* we must return */
2009-12-23 23:08:02 +03:00
2009-05-26 07:09:57 +04:00
/* use 'whenCreated' */
entry_ex - > entry . created_by . time = ldb_msg_find_krb5time_ldap_time ( msg , " whenCreated " , 0 ) ;
/* use '???' */
entry_ex - > entry . created_by . principal = NULL ;
2009-12-23 23:08:02 +03:00
2009-05-26 07:09:57 +04:00
entry_ex - > entry . modified_by = ( Event * ) malloc ( sizeof ( Event ) ) ;
if ( entry_ex - > entry . modified_by = = NULL ) {
ret = ENOMEM ;
2009-06-08 13:06:16 +04:00
krb5_set_error_message ( context , ret , " malloc: out of memory " ) ;
2009-05-26 07:09:57 +04:00
goto out ;
}
2009-12-23 23:08:02 +03:00
2009-05-26 07:09:57 +04:00
/* use 'whenChanged' */
entry_ex - > entry . modified_by - > time = ldb_msg_find_krb5time_ldap_time ( msg , " whenChanged " , 0 ) ;
/* use '???' */
entry_ex - > entry . modified_by - > principal = NULL ;
}
2005-06-03 18:32:10 +04:00
2009-05-26 07:09:57 +04:00
/* The lack of password controls etc applies to krbtgt by
* virtue of being that particular RID */
status = dom_sid_split_rid ( NULL , samdb_result_dom_sid ( mem_ctx , msg , " objectSid " ) , NULL , & rid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
ret = EINVAL ;
2005-06-03 18:32:10 +04:00
goto out ;
}
2009-05-26 07:09:57 +04:00
if ( rid = = DOMAIN_RID_KRBTGT ) {
entry_ex - > entry . valid_end = NULL ;
entry_ex - > entry . pw_end = NULL ;
2005-06-03 18:32:10 +04:00
2009-05-26 07:09:57 +04:00
entry_ex - > entry . flags . invalid = 0 ;
entry_ex - > entry . flags . server = 1 ;
2009-06-18 05:08:46 +04:00
/* Don't mark all requests for the krbtgt/realm as
* ' change password ' , as otherwise we could get into
* trouble , and not enforce the password expirty .
* Instead , only do it when request is for the kpasswd service */
if ( ent_type = = HDB_SAMBA4_ENT_TYPE_SERVER
& & principal - > name . name_string . len = = 2
& & ( strcmp ( principal - > name . name_string . val [ 0 ] , " kadmin " ) = = 0 )
& & ( strcmp ( principal - > name . name_string . val [ 1 ] , " changepw " ) = = 0 )
& & lp_is_my_domain_or_realm ( lp_ctx , principal - > realm ) ) {
entry_ex - > entry . flags . change_pw = 1 ;
}
2009-05-26 07:09:57 +04:00
entry_ex - > entry . flags . client = 0 ;
entry_ex - > entry . flags . forwardable = 1 ;
entry_ex - > entry . flags . ok_as_delegate = 1 ;
} else if ( entry_ex - > entry . flags . server & & ent_type = = HDB_SAMBA4_ENT_TYPE_SERVER ) {
/* The account/password expiry only applies when the account is used as a
* client ( ie password login ) , not when used as a server */
2005-06-03 18:32:10 +04:00
2009-05-26 06:31:39 +04:00
/* Make very well sure we don't use this for a client,
2009-05-26 07:09:57 +04:00
* it could bypass the password restrictions */
2009-05-26 06:31:39 +04:00
entry_ex - > entry . flags . client = 0 ;
2009-05-26 07:09:57 +04:00
2005-12-15 23:38:24 +03:00
entry_ex - > entry . valid_end = NULL ;
2009-05-26 06:31:39 +04:00
entry_ex - > entry . pw_end = NULL ;
2005-06-03 18:32:10 +04:00
2009-05-26 06:31:39 +04:00
} else {
2005-11-08 05:30:42 +03:00
NTTIME must_change_time
2009-12-23 23:08:02 +03:00
= samdb_result_force_password_change ( ( struct ldb_context * ) db - > hdb_db , mem_ctx ,
2009-05-26 06:31:39 +04:00
realm_dn , msg ) ;
2006-03-07 06:33:26 +03:00
if ( must_change_time = = 0x7FFFFFFFFFFFFFFFULL ) {
entry_ex - > entry . pw_end = NULL ;
} else {
2005-12-15 23:38:24 +03:00
entry_ex - > entry . pw_end = malloc ( sizeof ( * entry_ex - > entry . pw_end ) ) ;
if ( entry_ex - > entry . pw_end = = NULL ) {
2005-11-08 05:30:42 +03:00
ret = ENOMEM ;
goto out ;
}
2005-12-15 23:38:24 +03:00
* entry_ex - > entry . pw_end = nt_time_to_unix ( must_change_time ) ;
2005-11-08 05:30:42 +03:00
}
2009-05-26 06:31:39 +04:00
acct_expiry = samdb_result_account_expires ( msg ) ;
if ( acct_expiry = = 0x7FFFFFFFFFFFFFFFULL ) {
entry_ex - > entry . valid_end = NULL ;
} else {
entry_ex - > entry . valid_end = malloc ( sizeof ( * entry_ex - > entry . valid_end ) ) ;
if ( entry_ex - > entry . valid_end = = NULL ) {
ret = ENOMEM ;
goto out ;
}
* entry_ex - > entry . valid_end = nt_time_to_unix ( acct_expiry ) ;
}
2005-11-08 05:30:42 +03:00
}
2009-05-26 07:09:57 +04:00
entry_ex - > entry . valid_start = NULL ;
2005-12-15 23:38:24 +03:00
entry_ex - > entry . max_life = NULL ;
2005-06-03 18:32:10 +04:00
2005-12-15 23:38:24 +03:00
entry_ex - > entry . max_renew = NULL ;
2005-06-03 18:32:10 +04:00
2005-12-15 23:38:24 +03:00
entry_ex - > entry . generation = NULL ;
2005-06-03 18:32:10 +04:00
2007-02-14 14:47:17 +03:00
/* Get keys from the db */
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_message2entry_keys ( context , p - > iconv_convenience , p , msg , userAccountControl , entry_ex ) ;
2007-02-14 14:47:17 +03:00
if ( ret ) {
/* Could be bougus data in the entry, or out of memory */
goto out ;
}
2005-06-03 18:32:10 +04:00
2005-12-15 23:38:24 +03:00
entry_ex - > entry . etypes = malloc ( sizeof ( * ( entry_ex - > entry . etypes ) ) ) ;
if ( entry_ex - > entry . etypes = = NULL ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2005-06-03 18:32:10 +04:00
ret = ENOMEM ;
goto out ;
}
2005-12-15 23:38:24 +03:00
entry_ex - > entry . etypes - > len = entry_ex - > entry . keys . len ;
entry_ex - > entry . etypes - > val = calloc ( entry_ex - > entry . etypes - > len , sizeof ( int ) ) ;
if ( entry_ex - > entry . etypes - > val = = NULL ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2005-06-03 18:32:10 +04:00
ret = ENOMEM ;
goto out ;
}
2005-12-15 23:38:24 +03:00
for ( i = 0 ; i < entry_ex - > entry . etypes - > len ; i + + ) {
entry_ex - > entry . etypes - > val [ i ] = entry_ex - > entry . keys . val [ i ] . key . keytype ;
2005-06-03 18:32:10 +04:00
}
2005-11-07 05:29:37 +03:00
2009-02-01 01:43:43 +03:00
p - > msg = talloc_steal ( p , msg ) ;
p - > samdb = ( struct ldb_context * ) db - > hdb_db ;
2009-12-23 23:08:02 +03:00
2005-06-03 18:32:10 +04:00
out :
if ( ret ! = 0 ) {
2005-11-07 05:29:37 +03:00
/* This doesn't free ent itself, that is for the eventual caller to do */
2005-12-15 23:38:24 +03:00
hdb_free_entry ( context , entry_ex ) ;
} else {
talloc_steal ( db , entry_ex - > ctx ) ;
2005-06-03 18:32:10 +04:00
}
return ret ;
}
2008-08-15 15:16:20 +04:00
/*
* Construct an hdb_entry from a directory entry .
*/
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_trust_message2entry ( krb5_context context , HDB * db ,
2008-08-15 15:16:20 +04:00
struct loadparm_context * lp_ctx ,
TALLOC_CTX * mem_ctx , krb5_const_principal principal ,
enum trust_direction direction ,
2009-05-26 06:31:39 +04:00
struct ldb_dn * realm_dn ,
2008-08-15 15:16:20 +04:00
struct ldb_message * msg ,
hdb_entry_ex * entry_ex )
{
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
const char * dnsdomain ;
char * realm ;
DATA_BLOB password_utf16 ;
struct samr_Password password_hash ;
const struct ldb_val * password_val ;
struct trustAuthInOutBlob password_blob ;
2009-07-27 07:48:45 +04:00
struct hdb_samba4_private * p ;
2008-08-15 15:16:20 +04:00
enum ndr_err_code ndr_err ;
int i , ret , trust_direction_flags ;
2009-07-27 07:48:45 +04:00
p = talloc ( mem_ctx , struct hdb_samba4_private ) ;
2009-02-01 01:43:43 +03:00
if ( ! p ) {
2008-08-15 15:16:20 +04:00
ret = ENOMEM ;
goto out ;
}
2009-02-01 01:43:43 +03:00
p - > entry_ex = entry_ex ;
p - > iconv_convenience = lp_iconv_convenience ( lp_ctx ) ;
2009-05-26 06:31:39 +04:00
p - > lp_ctx = lp_ctx ;
p - > realm_dn = realm_dn ;
2008-08-15 15:16:20 +04:00
2009-07-27 07:48:45 +04:00
talloc_set_destructor ( p , hdb_samba4_destructor ) ;
2008-08-15 15:16:20 +04:00
2009-02-01 01:43:43 +03:00
entry_ex - > ctx = p ;
2009-07-27 07:48:45 +04:00
entry_ex - > free_entry = hdb_samba4_free_entry ;
2008-08-15 15:16:20 +04:00
/* use 'whenCreated' */
entry_ex - > entry . created_by . time = ldb_msg_find_krb5time_ldap_time ( msg , " whenCreated " , 0 ) ;
/* use '???' */
entry_ex - > entry . created_by . principal = NULL ;
entry_ex - > entry . valid_start = NULL ;
trust_direction_flags = ldb_msg_find_attr_as_int ( msg , " trustDirection " , 0 ) ;
if ( direction = = INBOUND ) {
realm = strupper_talloc ( mem_ctx , lp_realm ( lp_ctx ) ) ;
password_val = ldb_msg_find_ldb_val ( msg , " trustAuthIncoming " ) ;
} else { /* OUTBOUND */
dnsdomain = ldb_msg_find_attr_as_string ( msg , " trustPartner " , NULL ) ;
realm = strupper_talloc ( mem_ctx , dnsdomain ) ;
password_val = ldb_msg_find_ldb_val ( msg , " trustAuthOutgoing " ) ;
}
2008-08-26 04:27:00 +04:00
if ( ! password_val | | ! ( trust_direction_flags & direction ) ) {
ret = ENOENT ;
goto out ;
}
2009-02-01 01:43:43 +03:00
ndr_err = ndr_pull_struct_blob ( password_val , mem_ctx , p - > iconv_convenience , & password_blob ,
2008-08-15 15:16:20 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_trustAuthInOutBlob ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
ret = EINVAL ;
goto out ;
}
2008-10-04 03:36:49 +04:00
entry_ex - > entry . kvno = - 1 ;
2008-10-02 03:00:33 +04:00
for ( i = 0 ; i < password_blob . count ; i + + ) {
if ( password_blob . current - > array [ i ] . AuthType = = TRUST_AUTH_TYPE_VERSION ) {
entry_ex - > entry . kvno = password_blob . current - > array [ i ] . AuthInfo . version . version ;
}
}
2008-08-15 15:16:20 +04:00
for ( i = 0 ; i < password_blob . count ; i + + ) {
if ( password_blob . current - > array [ i ] . AuthType = = TRUST_AUTH_TYPE_CLEAR ) {
password_utf16 = data_blob_const ( password_blob . current - > array [ i ] . AuthInfo . clear . password ,
password_blob . current - > array [ i ] . AuthInfo . clear . size ) ;
/* In the future, generate all sorts of
* hashes , but for now we can ' t safely convert
* the random strings windows uses into
* utf8 */
/* but as it is utf16 already, we can get the NT password/arcfour-hmac-md5 key */
mdfour ( password_hash . hash , password_utf16 . data , password_utf16 . length ) ;
break ;
} else if ( password_blob . current - > array [ i ] . AuthType = = TRUST_AUTH_TYPE_NT4OWF ) {
password_hash = password_blob . current - > array [ i ] . AuthInfo . nt4owf . password ;
break ;
}
}
entry_ex - > entry . keys . len = 0 ;
entry_ex - > entry . keys . val = NULL ;
if ( i < password_blob . count ) {
Key key ;
/* Must have found a cleartext or MD4 password */
entry_ex - > entry . keys . val = calloc ( 1 , sizeof ( Key ) ) ;
key . mkvno = 0 ;
key . salt = NULL ; /* No salt for this enc type */
if ( entry_ex - > entry . keys . val = = NULL ) {
ret = ENOMEM ;
goto out ;
}
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
ret = krb5_keyblock_init ( context ,
2009-08-18 06:08:37 +04:00
ENCTYPE_ARCFOUR_HMAC ,
2009-12-23 23:08:02 +03:00
password_hash . hash , sizeof ( password_hash . hash ) ,
2008-08-15 15:16:20 +04:00
& key . key ) ;
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
entry_ex - > entry . keys . val [ entry_ex - > entry . keys . len ] = key ;
entry_ex - > entry . keys . len + + ;
}
2009-12-23 23:08:02 +03:00
2008-10-02 22:30:14 +04:00
entry_ex - > entry . principal = malloc ( sizeof ( * ( entry_ex - > entry . principal ) ) ) ;
2008-08-15 15:16:20 +04:00
ret = copy_Principal ( principal , entry_ex - > entry . principal ) ;
if ( ret ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2008-08-15 15:16:20 +04:00
goto out ;
}
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
/* While we have copied the client principal, tests
* show that Win2k3 returns the ' corrected ' realm , not
* the client - specified realm . This code attempts to
* replace the client principal ' s realm with the one
* we determine from our records */
2009-12-23 23:08:02 +03:00
2009-06-08 13:06:16 +04:00
krb5_principal_set_realm ( context , entry_ex - > entry . principal , realm ) ;
2008-08-15 15:16:20 +04:00
entry_ex - > entry . flags = int2HDBFlags ( 0 ) ;
entry_ex - > entry . flags . immutable = 1 ;
entry_ex - > entry . flags . invalid = 0 ;
entry_ex - > entry . flags . server = 1 ;
entry_ex - > entry . flags . require_preauth = 1 ;
entry_ex - > entry . pw_end = NULL ;
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
entry_ex - > entry . max_life = NULL ;
entry_ex - > entry . max_renew = NULL ;
entry_ex - > entry . generation = NULL ;
entry_ex - > entry . etypes = malloc ( sizeof ( * ( entry_ex - > entry . etypes ) ) ) ;
if ( entry_ex - > entry . etypes = = NULL ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2008-08-15 15:16:20 +04:00
ret = ENOMEM ;
goto out ;
}
entry_ex - > entry . etypes - > len = entry_ex - > entry . keys . len ;
entry_ex - > entry . etypes - > val = calloc ( entry_ex - > entry . etypes - > len , sizeof ( int ) ) ;
if ( entry_ex - > entry . etypes - > val = = NULL ) {
2009-06-08 13:06:16 +04:00
krb5_clear_error_message ( context ) ;
2008-08-15 15:16:20 +04:00
ret = ENOMEM ;
goto out ;
}
for ( i = 0 ; i < entry_ex - > entry . etypes - > len ; i + + ) {
entry_ex - > entry . etypes - > val [ i ] = entry_ex - > entry . keys . val [ i ] . key . keytype ;
}
2009-02-01 01:43:43 +03:00
p - > msg = talloc_steal ( p , msg ) ;
p - > samdb = ( struct ldb_context * ) db - > hdb_db ;
2009-12-23 23:08:02 +03:00
2008-08-15 15:16:20 +04:00
out :
if ( ret ! = 0 ) {
/* This doesn't free ent itself, that is for the eventual caller to do */
hdb_free_entry ( context , entry_ex ) ;
} else {
talloc_steal ( db , entry_ex - > ctx ) ;
}
return ret ;
}
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_lookup_trust ( krb5_context context , struct ldb_context * ldb_ctx ,
2008-08-08 04:35:57 +04:00
TALLOC_CTX * mem_ctx ,
const char * realm ,
struct ldb_dn * realm_dn ,
2009-06-04 08:07:35 +04:00
struct ldb_message * * pmsg )
2008-08-08 04:35:57 +04:00
{
int lret ;
2009-06-08 13:06:16 +04:00
krb5_error_code ret ;
2008-08-08 04:35:57 +04:00
char * filter = NULL ;
const char * const * attrs = trust_attrs ;
struct ldb_result * res = NULL ;
filter = talloc_asprintf ( mem_ctx , " (&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s))) " , realm , realm ) ;
if ( ! filter ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
krb5_set_error_message ( context , ret , " talloc_asprintf: out of memory " ) ;
return ret ;
2008-08-08 04:35:57 +04:00
}
2008-09-23 22:30:06 +04:00
lret = ldb_search ( ldb_ctx , mem_ctx , & res ,
ldb_get_default_basedn ( ldb_ctx ) ,
LDB_SCOPE_SUBTREE , attrs , " %s " , filter ) ;
2008-08-08 04:35:57 +04:00
if ( lret ! = LDB_SUCCESS ) {
DEBUG ( 3 , ( " Failed to search for %s: %s \n " , filter , ldb_errstring ( ldb_ctx ) ) ) ;
return HDB_ERR_NOENTRY ;
} else if ( res - > count = = 0 | | res - > count > 1 ) {
DEBUG ( 3 , ( " Failed find a single entry for %s: got %d \n " , filter , res - > count ) ) ;
talloc_free ( res ) ;
return HDB_ERR_NOENTRY ;
}
talloc_steal ( mem_ctx , res - > msgs ) ;
2009-06-04 08:07:35 +04:00
* pmsg = res - > msgs [ 0 ] ;
2008-08-08 04:35:57 +04:00
talloc_free ( res ) ;
return 0 ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_open ( krb5_context context , HDB * db , int flags , mode_t mode )
2005-06-03 18:32:10 +04:00
{
if ( db - > hdb_master_key_set ) {
2009-06-08 13:06:16 +04:00
krb5_error_code ret = HDB_ERR_NOENTRY ;
2009-07-16 06:47:57 +04:00
krb5_warnx ( context , " hdb_samba4_open: use of a master key incompatible with LDB \n " ) ;
krb5_set_error_message ( context , ret , " hdb_samba4_open: use of a master key incompatible with LDB \n " ) ;
2009-06-08 13:06:16 +04:00
return ret ;
2009-12-23 23:08:02 +03:00
}
2005-06-03 18:32:10 +04:00
return 0 ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_close ( krb5_context context , HDB * db )
2005-06-03 18:32:10 +04:00
{
return 0 ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_lock ( krb5_context context , HDB * db , int operation )
2005-06-03 18:32:10 +04:00
{
return 0 ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_unlock ( krb5_context context , HDB * db )
2005-06-03 18:32:10 +04:00
{
return 0 ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_rename ( krb5_context context , HDB * db , const char * new_name )
2005-06-03 18:32:10 +04:00
{
return HDB_ERR_DB_INUSE ;
}
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_lookup_client ( krb5_context context , HDB * db ,
struct loadparm_context * lp_ctx ,
TALLOC_CTX * mem_ctx ,
2009-07-28 08:05:19 +04:00
krb5_const_principal principal ,
const char * * attrs ,
2009-12-23 23:08:02 +03:00
struct ldb_dn * * realm_dn ,
2009-07-28 08:05:19 +04:00
struct ldb_message * * msg ) {
2006-05-07 08:51:30 +04:00
NTSTATUS nt_status ;
char * principal_string ;
krb5_error_code ret ;
2005-06-03 18:32:10 +04:00
2006-05-07 08:51:30 +04:00
ret = krb5_unparse_name ( context , principal , & principal_string ) ;
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
if ( ret ! = 0 ) {
return ret ;
}
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
nt_status = sam_get_results_principal ( ( struct ldb_context * ) db - > hdb_db ,
2009-12-23 23:08:02 +03:00
mem_ctx , principal_string , attrs ,
2009-07-28 08:05:19 +04:00
realm_dn , msg ) ;
2006-05-07 08:51:30 +04:00
free ( principal_string ) ;
if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NO_SUCH_USER ) ) {
return HDB_ERR_NOENTRY ;
} else if ( NT_STATUS_EQUAL ( nt_status , NT_STATUS_NO_MEMORY ) ) {
2005-06-03 18:32:10 +04:00
return ENOMEM ;
2006-05-07 08:51:30 +04:00
} else if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return EINVAL ;
2005-06-03 18:32:10 +04:00
}
2009-12-23 23:08:02 +03:00
2009-07-28 08:05:19 +04:00
return ret ;
}
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_fetch_client ( krb5_context context , HDB * db ,
struct loadparm_context * lp_ctx ,
TALLOC_CTX * mem_ctx ,
2009-07-28 08:05:19 +04:00
krb5_const_principal principal ,
unsigned flags ,
hdb_entry_ex * entry_ex ) {
struct ldb_dn * realm_dn ;
krb5_error_code ret ;
struct ldb_message * msg = NULL ;
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_lookup_client ( context , db , lp_ctx ,
mem_ctx , principal , user_attrs ,
2009-07-28 08:05:19 +04:00
& realm_dn , & msg ) ;
if ( ret ! = 0 ) {
return ret ;
}
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_message2entry ( context , db , lp_ctx , mem_ctx ,
2009-07-28 08:05:19 +04:00
principal , HDB_SAMBA4_ENT_TYPE_CLIENT ,
realm_dn , msg , entry_ex ) ;
2006-05-07 08:51:30 +04:00
return ret ;
}
2005-06-03 18:32:10 +04:00
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_fetch_krbtgt ( krb5_context context , HDB * db ,
struct loadparm_context * lp_ctx ,
TALLOC_CTX * mem_ctx ,
2006-05-07 08:51:30 +04:00
krb5_const_principal principal ,
unsigned flags ,
hdb_entry_ex * entry_ex )
{
krb5_error_code ret ;
2009-06-04 08:07:35 +04:00
struct ldb_message * msg = NULL ;
2009-05-26 06:31:39 +04:00
struct ldb_dn * realm_dn = ldb_get_default_basedn ( db - > hdb_db ) ;
2008-08-08 04:35:57 +04:00
const char * realm ;
2006-05-07 08:51:30 +04:00
2006-12-29 14:01:37 +03:00
krb5_principal alloc_principal = NULL ;
2006-05-07 08:51:30 +04:00
if ( principal - > name . name_string . len ! = 2
| | ( strcmp ( principal - > name . name_string . val [ 0 ] , KRB5_TGS_NAME ) ! = 0 ) ) {
/* Not a krbtgt */
return HDB_ERR_NOENTRY ;
}
2005-10-27 14:45:16 +04:00
2006-05-07 08:51:30 +04:00
/* krbtgt case. Either us or a trusted realm */
2008-07-31 01:47:01 +04:00
2009-05-26 06:31:39 +04:00
if ( lp_is_my_domain_or_realm ( lp_ctx , principal - > realm )
& & lp_is_my_domain_or_realm ( lp_ctx , principal - > name . name_string . val [ 1 ] ) ) {
2009-12-23 23:08:02 +03:00
/* us */
2006-12-29 14:01:37 +03:00
/* Cludge, cludge cludge. If the realm part of krbtgt/realm,
* is in our db , then direct the caller at our primary
2008-07-31 01:47:01 +04:00
* krbtgt */
2009-06-30 04:29:30 +04:00
int lret ;
char * realm_fixed ;
2009-12-23 23:08:02 +03:00
lret = gendb_search_single_extended_dn ( db - > hdb_db , mem_ctx ,
2009-06-30 04:29:30 +04:00
realm_dn , LDB_SCOPE_SUBTREE ,
2009-12-23 23:08:02 +03:00
& msg , krbtgt_attrs ,
" (&(objectClass=user)(samAccountName=krbtgt)) " ) ;
2009-06-30 04:29:30 +04:00
if ( lret = = LDB_ERR_NO_SUCH_OBJECT ) {
2009-07-16 06:47:57 +04:00
krb5_warnx ( context , " hdb_samba4_fetch: could not find own KRBTGT in DB! " ) ;
krb5_set_error_message ( context , HDB_ERR_NOENTRY , " hdb_samba4_fetch: could not find own KRBTGT in DB! " ) ;
2009-06-30 04:29:30 +04:00
return HDB_ERR_NOENTRY ;
} else if ( lret ! = LDB_SUCCESS ) {
2009-07-16 06:47:57 +04:00
krb5_warnx ( context , " hdb_samba4_fetch: could not find own KRBTGT in DB: %s " , ldb_errstring ( db - > hdb_db ) ) ;
krb5_set_error_message ( context , HDB_ERR_NOENTRY , " hdb_samba4_fetch: could not find own KRBTGT in DB: %s " , ldb_errstring ( db - > hdb_db ) ) ;
2009-06-30 04:29:30 +04:00
return HDB_ERR_NOENTRY ;
}
2009-12-23 23:08:02 +03:00
2009-06-30 04:29:30 +04:00
realm_fixed = strupper_talloc ( mem_ctx , lp_realm ( lp_ctx ) ) ;
2006-12-29 14:01:37 +03:00
if ( ! realm_fixed ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
krb5_set_error_message ( context , ret , " strupper_talloc: out of memory " ) ;
return ret ;
2006-12-29 14:01:37 +03:00
}
2009-12-23 23:08:02 +03:00
2006-12-29 14:01:37 +03:00
ret = krb5_copy_principal ( context , principal , & alloc_principal ) ;
if ( ret ) {
return ret ;
}
2009-12-23 23:08:02 +03:00
2006-12-29 14:01:37 +03:00
free ( alloc_principal - > name . name_string . val [ 1 ] ) ;
alloc_principal - > name . name_string . val [ 1 ] = strdup ( realm_fixed ) ;
talloc_free ( realm_fixed ) ;
if ( ! alloc_principal - > name . name_string . val [ 1 ] ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_fetch: strdup() failed! " ) ;
2009-06-08 13:06:16 +04:00
return ret ;
2006-12-29 14:01:37 +03:00
}
principal = alloc_principal ;
2009-05-26 06:31:39 +04:00
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_message2entry ( context , db , lp_ctx , mem_ctx ,
principal , HDB_SAMBA4_ENT_TYPE_KRBTGT ,
2009-06-04 08:07:35 +04:00
realm_dn , msg , entry_ex ) ;
2008-08-08 04:35:57 +04:00
if ( ret ! = 0 ) {
2009-12-23 23:08:02 +03:00
krb5_warnx ( context , " hdb_samba4_fetch: self krbtgt message2entry failed " ) ;
2008-08-08 04:35:57 +04:00
}
return ret ;
2006-05-07 08:51:30 +04:00
} else {
2008-08-15 15:16:20 +04:00
enum trust_direction direction = UNKNOWN ;
2008-07-31 01:47:01 +04:00
/* Either an inbound or outbound trust */
if ( strcasecmp ( lp_realm ( lp_ctx ) , principal - > realm ) = = 0 ) {
/* look for inbound trust */
2008-08-08 04:35:57 +04:00
direction = INBOUND ;
realm = principal - > name . name_string . val [ 1 ] ;
2008-07-31 01:47:01 +04:00
}
if ( strcasecmp ( lp_realm ( lp_ctx ) , principal - > name . name_string . val [ 1 ] ) = = 0 ) {
/* look for outbound trust */
2008-08-08 04:35:57 +04:00
direction = OUTBOUND ;
realm = principal - > realm ;
2008-07-31 01:47:01 +04:00
}
/* Trusted domains are under CN=system */
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_lookup_trust ( context , ( struct ldb_context * ) db - > hdb_db ,
mem_ctx ,
2008-08-15 15:16:20 +04:00
realm , realm_dn , & msg ) ;
2009-12-23 23:08:02 +03:00
2008-08-08 04:35:57 +04:00
if ( ret ! = 0 ) {
2009-07-16 06:47:57 +04:00
krb5_warnx ( context , " hdb_samba4_fetch: could not find principal in DB " ) ;
krb5_set_error_message ( context , ret , " hdb_samba4_fetch: could not find principal in DB " ) ;
2008-08-08 04:35:57 +04:00
return ret ;
}
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_trust_message2entry ( context , db , lp_ctx , mem_ctx ,
principal , direction ,
2009-06-04 08:07:35 +04:00
realm_dn , msg , entry_ex ) ;
2008-08-08 04:35:57 +04:00
if ( ret ! = 0 ) {
2009-12-23 23:08:02 +03:00
krb5_warnx ( context , " hdb_samba4_fetch: trust_message2entry failed " ) ;
2008-08-08 04:35:57 +04:00
}
return ret ;
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
/* we should lookup trusted domains */
return HDB_ERR_NOENTRY ;
}
2005-10-27 14:45:16 +04:00
2006-05-07 08:51:30 +04:00
}
2005-11-05 14:29:34 +03:00
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_lookup_server ( krb5_context context , HDB * db ,
2009-07-16 11:37:36 +04:00
struct loadparm_context * lp_ctx ,
2009-12-23 23:08:02 +03:00
TALLOC_CTX * mem_ctx ,
2009-07-16 11:37:36 +04:00
krb5_const_principal principal ,
const char * * attrs ,
struct ldb_dn * * realm_dn ,
struct ldb_message * * msg )
2006-05-07 08:51:30 +04:00
{
krb5_error_code ret ;
const char * realm ;
if ( principal - > name . name_string . len > = 2 ) {
/* 'normal server' case */
int ldb_ret ;
NTSTATUS nt_status ;
2009-05-26 06:31:39 +04:00
struct ldb_dn * user_dn ;
2006-05-07 08:51:30 +04:00
char * principal_string ;
2009-12-23 23:08:02 +03:00
ret = krb5_unparse_name_flags ( context , principal ,
KRB5_PRINCIPAL_UNPARSE_NO_REALM ,
2006-11-07 09:59:56 +03:00
& principal_string ) ;
2006-05-07 08:51:30 +04:00
if ( ret ! = 0 ) {
2005-10-27 17:54:30 +04:00
return ret ;
}
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
/* At this point we may find the host is known to be
* in a different realm , so we should generate a
* referral instead */
nt_status = crack_service_principal_name ( ( struct ldb_context * ) db - > hdb_db ,
2009-12-23 23:08:02 +03:00
mem_ctx , principal_string ,
2009-07-16 11:37:36 +04:00
& user_dn , realm_dn ) ;
2006-05-07 08:51:30 +04:00
free ( principal_string ) ;
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return HDB_ERR_NOENTRY ;
}
2009-12-23 23:08:02 +03:00
2009-06-04 08:07:35 +04:00
ldb_ret = gendb_search_single_extended_dn ( ( struct ldb_context * ) db - > hdb_db ,
2009-12-23 23:08:02 +03:00
mem_ctx ,
2009-06-04 08:07:35 +04:00
user_dn , LDB_SCOPE_BASE ,
2009-07-16 11:37:36 +04:00
msg , attrs ,
2009-06-04 08:07:35 +04:00
" (objectClass=*) " ) ;
if ( ldb_ret ! = LDB_SUCCESS ) {
2006-05-07 08:51:30 +04:00
return HDB_ERR_NOENTRY ;
}
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
} else {
2009-06-30 04:29:30 +04:00
int lret ;
char * filter = NULL ;
char * short_princ ;
2006-05-07 08:51:30 +04:00
/* server as client principal case, but we must not lookup userPrincipalNames */
2009-07-16 11:37:36 +04:00
* realm_dn = ldb_get_default_basedn ( db - > hdb_db ) ;
2006-05-07 08:51:30 +04:00
realm = krb5_principal_get_realm ( context , principal ) ;
2009-12-23 23:08:02 +03:00
2009-06-30 04:29:30 +04:00
/* TODO: Check if it is our realm, otherwise give referall */
2009-12-23 23:08:02 +03:00
2009-06-30 04:29:30 +04:00
ret = krb5_unparse_name_flags ( context , principal , KRB5_PRINCIPAL_UNPARSE_NO_REALM , & short_princ ) ;
2009-12-23 23:08:02 +03:00
2006-05-07 08:51:30 +04:00
if ( ret ! = 0 ) {
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_lookup_principal: could not parse principal " ) ;
krb5_warnx ( context , " hdb_samba4_lookup_principal: could not parse principal " ) ;
2006-05-07 08:51:30 +04:00
return ret ;
}
2009-12-23 23:08:02 +03:00
lret = gendb_search_single_extended_dn ( db - > hdb_db , mem_ctx ,
2009-07-16 11:37:36 +04:00
* realm_dn , LDB_SCOPE_SUBTREE ,
2009-12-23 23:08:02 +03:00
msg , attrs , " (&(objectClass=user)(samAccountName=%s)) " ,
2009-06-30 04:29:30 +04:00
ldb_binary_encode_string ( mem_ctx , short_princ ) ) ;
free ( short_princ ) ;
if ( lret = = LDB_ERR_NO_SUCH_OBJECT ) {
DEBUG ( 3 , ( " Failed find a entry for %s \n " , filter ) ) ;
return HDB_ERR_NOENTRY ;
}
if ( lret ! = LDB_SUCCESS ) {
2009-12-23 23:08:02 +03:00
DEBUG ( 3 , ( " Failed single search for for %s - %s \n " ,
2009-06-30 04:29:30 +04:00
filter , ldb_errstring ( db - > hdb_db ) ) ) ;
return HDB_ERR_NOENTRY ;
}
2006-05-07 08:51:30 +04:00
}
2005-10-27 14:45:16 +04:00
2009-07-16 11:37:36 +04:00
return 0 ;
}
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_fetch_server ( krb5_context context , HDB * db ,
2009-07-16 11:37:36 +04:00
struct loadparm_context * lp_ctx ,
2009-12-23 23:08:02 +03:00
TALLOC_CTX * mem_ctx ,
2009-07-16 11:37:36 +04:00
krb5_const_principal principal ,
unsigned flags ,
hdb_entry_ex * entry_ex )
{
krb5_error_code ret ;
struct ldb_dn * realm_dn ;
struct ldb_message * msg ;
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_lookup_server ( context , db , lp_ctx , mem_ctx , principal ,
2009-07-16 11:37:36 +04:00
server_attrs , & realm_dn , & msg ) ;
if ( ret ! = 0 ) {
return ret ;
}
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_message2entry ( context , db , lp_ctx , mem_ctx ,
2008-09-24 23:53:10 +04:00
principal , HDB_SAMBA4_ENT_TYPE_SERVER ,
2009-06-04 08:07:35 +04:00
realm_dn , msg , entry_ex ) ;
2005-10-27 14:45:16 +04:00
if ( ret ! = 0 ) {
2009-12-23 23:08:02 +03:00
krb5_warnx ( context , " hdb_samba4_fetch: message2entry failed " ) ;
2005-10-27 14:45:16 +04:00
}
2006-05-07 08:51:30 +04:00
return ret ;
}
2009-12-23 23:08:02 +03:00
static krb5_error_code hdb_samba4_fetch ( krb5_context context , HDB * db ,
2006-05-07 08:51:30 +04:00
krb5_const_principal principal ,
unsigned flags ,
hdb_entry_ex * entry_ex )
{
2006-06-06 08:50:14 +04:00
krb5_error_code ret = HDB_ERR_NOENTRY ;
2009-07-16 06:47:57 +04:00
TALLOC_CTX * mem_ctx = talloc_named ( db , 0 , " hdb_samba4_fetch context " ) ;
2009-06-30 06:06:38 +04:00
struct loadparm_context * lp_ctx = talloc_get_type ( ldb_get_opaque ( db - > hdb_db , " loadparm " ) , struct loadparm_context ) ;
2005-06-03 18:32:10 +04:00
2006-05-07 08:51:30 +04:00
if ( ! mem_ctx ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_fetch: talloc_named() failed! " ) ;
2009-06-08 13:06:16 +04:00
return ret ;
2005-06-03 18:32:10 +04:00
}
2006-05-07 08:51:30 +04:00
if ( flags & HDB_F_GET_CLIENT ) {
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_fetch_client ( context , db , lp_ctx , mem_ctx , principal , flags , entry_ex ) ;
2006-05-23 09:14:06 +04:00
if ( ret ! = HDB_ERR_NOENTRY ) goto done ;
2006-05-07 08:51:30 +04:00
}
if ( flags & HDB_F_GET_SERVER ) {
2008-07-31 01:47:01 +04:00
/* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_fetch_krbtgt ( context , db , lp_ctx , mem_ctx , principal , flags , entry_ex ) ;
2006-05-23 09:14:06 +04:00
if ( ret ! = HDB_ERR_NOENTRY ) goto done ;
2008-07-31 01:47:01 +04:00
/* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_fetch_server ( context , db , lp_ctx , mem_ctx , principal , flags , entry_ex ) ;
2008-07-31 01:47:01 +04:00
if ( ret ! = HDB_ERR_NOENTRY ) goto done ;
2006-05-07 08:51:30 +04:00
}
if ( flags & HDB_F_GET_KRBTGT ) {
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_fetch_krbtgt ( context , db , lp_ctx , mem_ctx , principal , flags , entry_ex ) ;
2006-05-23 09:14:06 +04:00
if ( ret ! = HDB_ERR_NOENTRY ) goto done ;
2006-05-07 08:51:30 +04:00
}
2006-05-23 09:14:06 +04:00
done :
talloc_free ( mem_ctx ) ;
2005-06-03 18:32:10 +04:00
return ret ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_store ( krb5_context context , HDB * db , unsigned flags , hdb_entry_ex * entry )
2005-06-03 18:32:10 +04:00
{
return HDB_ERR_DB_INUSE ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_remove ( krb5_context context , HDB * db , krb5_const_principal principal )
2005-06-03 18:32:10 +04:00
{
return HDB_ERR_DB_INUSE ;
}
2009-07-27 07:48:45 +04:00
struct hdb_samba4_seq {
2005-06-03 18:32:10 +04:00
struct ldb_context * ctx ;
2009-06-30 06:06:38 +04:00
struct loadparm_context * lp_ctx ;
2005-06-03 18:32:10 +04:00
int index ;
int count ;
struct ldb_message * * msgs ;
2009-05-26 06:31:39 +04:00
struct ldb_dn * realm_dn ;
2005-06-03 18:32:10 +04:00
} ;
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_seq ( krb5_context context , HDB * db , unsigned flags , hdb_entry_ex * entry )
2005-06-03 18:32:10 +04:00
{
krb5_error_code ret ;
2009-07-27 07:48:45 +04:00
struct hdb_samba4_seq * priv = ( struct hdb_samba4_seq * ) db - > hdb_dbc ;
2005-06-03 18:32:10 +04:00
TALLOC_CTX * mem_ctx ;
2005-11-07 05:29:37 +03:00
hdb_entry_ex entry_ex ;
memset ( & entry_ex , ' \0 ' , sizeof ( entry_ex ) ) ;
2005-06-03 18:32:10 +04:00
if ( ! priv ) {
return HDB_ERR_NOENTRY ;
}
2009-07-16 06:47:57 +04:00
mem_ctx = talloc_named ( priv , 0 , " hdb_samba4_seq context " ) ;
2005-06-03 18:32:10 +04:00
if ( ! mem_ctx ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_seq: talloc_named() failed! " ) ;
2009-06-08 13:06:16 +04:00
return ret ;
2005-06-03 18:32:10 +04:00
}
if ( priv - > index < priv - > count ) {
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_message2entry ( context , db , priv - > lp_ctx ,
mem_ctx ,
NULL , HDB_SAMBA4_ENT_TYPE_ANY ,
2009-05-26 06:31:39 +04:00
priv - > realm_dn , priv - > msgs [ priv - > index + + ] , entry ) ;
2005-06-03 18:32:10 +04:00
} else {
ret = HDB_ERR_NOENTRY ;
}
if ( ret ! = 0 ) {
2007-06-15 04:14:11 +04:00
db - > hdb_dbc = NULL ;
2005-06-03 18:32:10 +04:00
} else {
talloc_free ( mem_ctx ) ;
}
return ret ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_firstkey ( krb5_context context , HDB * db , unsigned flags ,
2005-12-15 23:38:24 +03:00
hdb_entry_ex * entry )
2005-06-03 18:32:10 +04:00
{
struct ldb_context * ldb_ctx = ( struct ldb_context * ) db - > hdb_db ;
2009-12-23 23:08:02 +03:00
struct loadparm_context * lp_ctx = talloc_get_type ( ldb_get_opaque ( ldb_ctx , " loadparm " ) ,
2009-06-30 06:06:38 +04:00
struct loadparm_context ) ;
2009-07-27 07:48:45 +04:00
struct hdb_samba4_seq * priv = ( struct hdb_samba4_seq * ) db - > hdb_dbc ;
2005-06-03 18:32:10 +04:00
char * realm ;
2005-11-08 03:11:45 +03:00
struct ldb_result * res = NULL ;
2005-06-03 18:32:10 +04:00
krb5_error_code ret ;
TALLOC_CTX * mem_ctx ;
2005-11-08 03:11:45 +03:00
int lret ;
2005-06-03 18:32:10 +04:00
if ( priv ) {
talloc_free ( priv ) ;
2007-06-15 04:14:11 +04:00
db - > hdb_dbc = NULL ;
2005-06-03 18:32:10 +04:00
}
2009-07-27 07:48:45 +04:00
priv = ( struct hdb_samba4_seq * ) talloc ( db , struct hdb_samba4_seq ) ;
2005-06-03 18:32:10 +04:00
if ( ! priv ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
krb5_set_error_message ( context , ret , " talloc: out of memory " ) ;
return ret ;
2005-06-03 18:32:10 +04:00
}
priv - > ctx = ldb_ctx ;
2009-06-30 06:06:38 +04:00
priv - > lp_ctx = lp_ctx ;
2005-06-03 18:32:10 +04:00
priv - > index = 0 ;
priv - > msgs = NULL ;
2009-05-26 06:31:39 +04:00
priv - > realm_dn = ldb_get_default_basedn ( ldb_ctx ) ;
2005-06-03 18:32:10 +04:00
priv - > count = 0 ;
2009-07-16 06:47:57 +04:00
mem_ctx = talloc_named ( priv , 0 , " hdb_samba4_firstkey context " ) ;
2005-06-03 18:32:10 +04:00
if ( ! mem_ctx ) {
2009-06-08 13:06:16 +04:00
ret = ENOMEM ;
2009-07-16 06:47:57 +04:00
krb5_set_error_message ( context , ret , " hdb_samba4_firstkey: talloc_named() failed! " ) ;
2009-06-08 13:06:16 +04:00
return ret ;
2005-06-03 18:32:10 +04:00
}
ret = krb5_get_default_realm ( context , & realm ) ;
if ( ret ! = 0 ) {
talloc_free ( priv ) ;
return ret ;
}
2009-12-23 23:08:02 +03:00
2008-09-23 22:30:06 +04:00
lret = ldb_search ( ldb_ctx , priv , & res ,
2009-05-26 06:31:39 +04:00
priv - > realm_dn , LDB_SCOPE_SUBTREE , user_attrs ,
2008-09-23 22:30:06 +04:00
" (objectClass=user) " ) ;
2005-06-03 18:32:10 +04:00
2005-11-08 03:11:45 +03:00
if ( lret ! = LDB_SUCCESS ) {
2005-06-03 18:32:10 +04:00
talloc_free ( priv ) ;
return HDB_ERR_NOENTRY ;
}
2005-11-08 03:11:45 +03:00
priv - > count = res - > count ;
priv - > msgs = talloc_steal ( priv , res - > msgs ) ;
2006-01-31 06:15:16 +03:00
talloc_free ( res ) ;
2005-11-08 03:11:45 +03:00
2007-06-15 04:14:11 +04:00
db - > hdb_dbc = priv ;
2005-06-03 18:32:10 +04:00
2009-07-16 06:47:57 +04:00
ret = hdb_samba4_seq ( context , db , flags , entry ) ;
2007-06-14 16:19:53 +04:00
2005-06-03 18:32:10 +04:00
if ( ret ! = 0 ) {
talloc_free ( priv ) ;
2007-06-15 04:14:11 +04:00
db - > hdb_dbc = NULL ;
2005-06-03 18:32:10 +04:00
} else {
talloc_free ( mem_ctx ) ;
}
return ret ;
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_nextkey ( krb5_context context , HDB * db , unsigned flags ,
2005-12-15 23:38:24 +03:00
hdb_entry_ex * entry )
2005-06-03 18:32:10 +04:00
{
2009-07-16 06:47:57 +04:00
return hdb_samba4_seq ( context , db , flags , entry ) ;
2005-06-03 18:32:10 +04:00
}
2009-07-16 06:47:57 +04:00
static krb5_error_code hdb_samba4_destroy ( krb5_context context , HDB * db )
2005-06-03 18:32:10 +04:00
{
talloc_free ( db ) ;
return 0 ;
}
2009-07-28 08:05:19 +04:00
/* Check if a given entry may delegate to this target principal
*
2009-12-23 23:08:02 +03:00
* This is currently a very nasty hack - allowing only delegation to itself .
2009-07-28 08:05:19 +04:00
*/
2010-01-21 17:57:41 +03:00
static krb5_error_code
hdb_samba4_check_constrained_delegation ( krb5_context context , HDB * db ,
hdb_entry_ex * entry ,
krb5_const_principal target_principal )
2009-07-18 04:15:55 +04:00
{
struct ldb_context * ldb_ctx = ( struct ldb_context * ) db - > hdb_db ;
2009-12-23 23:08:02 +03:00
struct loadparm_context * lp_ctx = talloc_get_type ( ldb_get_opaque ( ldb_ctx , " loadparm " ) ,
2009-07-18 04:15:55 +04:00
struct loadparm_context ) ;
krb5_error_code ret ;
krb5_principal enterprise_prinicpal = NULL ;
struct ldb_dn * realm_dn ;
struct ldb_message * msg ;
struct dom_sid * orig_sid ;
struct dom_sid * target_sid ;
2009-07-27 07:48:45 +04:00
struct hdb_samba4_private * p = talloc_get_type ( entry - > ctx , struct hdb_samba4_private ) ;
2009-07-18 04:15:55 +04:00
const char * delegation_check_attrs [ ] = {
" objectSid " , NULL
} ;
2009-12-23 23:08:02 +03:00
2009-07-18 04:15:55 +04:00
TALLOC_CTX * mem_ctx = talloc_named ( db , 0 , " hdb_samba4_check_constrained_delegation " ) ;
if ( ! mem_ctx ) {
ret = ENOMEM ;
krb5_set_error_message ( context , ret , " hdb_samba4_fetch: talloc_named() failed! " ) ;
return ret ;
}
if ( target_principal - > name . name_type = = KRB5_NT_ENTERPRISE_PRINCIPAL ) {
/* Need to reparse the enterprise principal to find the real target */
if ( target_principal - > name . name_string . len ! = 1 ) {
ret = KRB5_PARSE_MALFORMED ;
2009-12-23 23:08:02 +03:00
krb5_set_error_message ( context , ret , " hdb_samba4_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components " ,
target_principal - > name . name_string . len ) ;
2009-07-18 04:15:55 +04:00
talloc_free ( mem_ctx ) ;
return ret ;
}
2009-12-23 23:08:02 +03:00
ret = krb5_parse_name ( context , target_principal - > name . name_string . val [ 0 ] ,
2009-07-18 04:15:55 +04:00
& enterprise_prinicpal ) ;
if ( ret ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
target_principal = enterprise_prinicpal ;
}
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_lookup_server ( context , db , lp_ctx , mem_ctx , target_principal ,
2009-07-18 04:15:55 +04:00
delegation_check_attrs , & realm_dn , & msg ) ;
krb5_free_principal ( context , enterprise_prinicpal ) ;
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
orig_sid = samdb_result_dom_sid ( mem_ctx , p - > msg , " objectSid " ) ;
target_sid = samdb_result_dom_sid ( mem_ctx , msg , " objectSid " ) ;
/* Allow delegation to the same principal, even if by a different
* name . The easy and safe way to prove this is by SID
* comparison */
if ( ! ( orig_sid & & target_sid & & dom_sid_equal ( orig_sid , target_sid ) ) ) {
talloc_free ( mem_ctx ) ;
return KRB5KDC_ERR_BADOPTION ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2009-07-28 08:05:19 +04:00
/* Certificates printed by a the Certificate Authority might have a
* slightly different form of the user principal name to that in the
* database . Allow a mismatch where they both refer to the same
* SID */
2010-01-21 17:57:41 +03:00
static krb5_error_code
hdb_samba4_check_pkinit_ms_upn_match ( krb5_context context , HDB * db ,
hdb_entry_ex * entry ,
krb5_const_principal certificate_principal )
2009-07-28 08:05:19 +04:00
{
struct ldb_context * ldb_ctx = ( struct ldb_context * ) db - > hdb_db ;
2009-12-23 23:08:02 +03:00
struct loadparm_context * lp_ctx = talloc_get_type ( ldb_get_opaque ( ldb_ctx , " loadparm " ) ,
2009-07-28 08:05:19 +04:00
struct loadparm_context ) ;
krb5_error_code ret ;
struct ldb_dn * realm_dn ;
struct ldb_message * msg ;
struct dom_sid * orig_sid ;
struct dom_sid * target_sid ;
struct hdb_samba4_private * p = talloc_get_type ( entry - > ctx , struct hdb_samba4_private ) ;
const char * ms_upn_check_attrs [ ] = {
" objectSid " , NULL
} ;
2009-12-23 23:08:02 +03:00
2010-01-09 00:53:30 +03:00
TALLOC_CTX * mem_ctx = talloc_named ( db , 0 , " hdb_samba4_check_pkinit_ms_upn_match " ) ;
2009-07-28 08:05:19 +04:00
if ( ! mem_ctx ) {
ret = ENOMEM ;
krb5_set_error_message ( context , ret , " hdb_samba4_fetch: talloc_named() failed! " ) ;
return ret ;
}
2009-12-23 23:08:02 +03:00
ret = hdb_samba4_lookup_client ( context , db , lp_ctx ,
2009-07-28 08:05:19 +04:00
mem_ctx , certificate_principal ,
ms_upn_check_attrs , & realm_dn , & msg ) ;
2009-12-23 23:08:02 +03:00
2009-07-28 08:05:19 +04:00
if ( ret ! = 0 ) {
talloc_free ( mem_ctx ) ;
return ret ;
}
orig_sid = samdb_result_dom_sid ( mem_ctx , p - > msg , " objectSid " ) ;
target_sid = samdb_result_dom_sid ( mem_ctx , msg , " objectSid " ) ;
/* Consider these to be the same principal, even if by a different
* name . The easy and safe way to prove this is by SID
* comparison */
if ( ! ( orig_sid & & target_sid & & dom_sid_equal ( orig_sid , target_sid ) ) ) {
talloc_free ( mem_ctx ) ;
return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH ;
}
talloc_free ( mem_ctx ) ;
return ret ;
}
2009-07-27 07:48:45 +04:00
/* This interface is to be called by the KDC and libnet_keytab_dump, which is expecting Samba
2006-01-24 08:31:08 +03:00
* calling conventions . It is also called by a wrapper
2009-07-27 07:48:45 +04:00
* ( hdb_samba4_create ) from the kpasswdd - > krb5 - > keytab_hdb - > hdb
2006-01-24 08:31:08 +03:00
* code */
2009-12-23 23:08:02 +03:00
NTSTATUS hdb_samba4_create_kdc ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev_ctx ,
2009-07-27 07:48:45 +04:00
struct loadparm_context * lp_ctx ,
krb5_context context , struct HDB * * db )
2005-06-03 18:32:10 +04:00
{
2005-12-11 11:31:46 +03:00
struct auth_session_info * session_info ;
2009-11-09 13:38:49 +03:00
NTSTATUS nt_status ;
2005-06-29 17:55:09 +04:00
* db = talloc ( mem_ctx , HDB ) ;
2005-06-03 18:32:10 +04:00
if ( ! * db ) {
2009-06-08 13:06:16 +04:00
krb5_set_error_message ( context , ENOMEM , " malloc: out of memory " ) ;
2005-12-11 11:31:46 +03:00
return NT_STATUS_NO_MEMORY ;
2005-06-03 18:32:10 +04:00
}
( * db ) - > hdb_master_key_set = 0 ;
( * db ) - > hdb_db = NULL ;
2009-06-30 06:11:14 +04:00
( * db ) - > hdb_capability_flags = 0 ;
2005-06-05 17:11:42 +04:00
2009-11-09 13:38:49 +03:00
# if 1
/* we would prefer to use system_session(), as that would
* allow us to share the samdb backend context with other parts of the
* system . For now we can ' t as we need to override the
* credentials to set CRED_DONT_USE_KERBEROS , which would
2009-12-23 23:08:02 +03:00
* break other users of the system_session */
2009-11-09 13:38:49 +03:00
DEBUG ( 0 , ( " FIXME: Using new system session for hdb \n " ) ) ;
nt_status = auth_system_session_info ( * db , lp_ctx , & session_info ) ;
if ( ! NT_STATUS_IS_OK ( nt_status ) ) {
return nt_status ;
}
# else
2009-10-25 09:19:03 +03:00
session_info = system_session ( lp_ctx ) ;
if ( session_info = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
2005-12-11 11:31:46 +03:00
}
2009-11-09 13:38:49 +03:00
# endif
2009-12-23 23:08:02 +03:00
2005-12-11 11:31:46 +03:00
/* The idea here is very simple. Using Kerberos to
* authenticate the KDC to the LDAP server is higly likely to
* be circular .
*
* In future we may set this up to use EXERNAL and SSL
2009-11-09 13:38:49 +03:00
* certificates , for now it will almost certainly be NTLMSSP_SET_USERNAME
2005-12-11 11:31:46 +03:00
*/
2009-12-23 23:08:02 +03:00
cli_credentials_set_kerberos_state ( session_info - > credentials ,
2006-01-28 15:19:20 +03:00
CRED_DONT_USE_KERBEROS ) ;
2005-12-11 11:31:46 +03:00
2005-06-29 17:55:09 +04:00
/* Setup the link to LDB */
2008-04-17 14:23:44 +04:00
( * db ) - > hdb_db = samdb_connect ( * db , ev_ctx , lp_ctx , session_info ) ;
2005-06-05 17:11:42 +04:00
if ( ( * db ) - > hdb_db = = NULL ) {
2009-07-27 07:48:45 +04:00
DEBUG ( 1 , ( " hdb_samba4_create: Cannot open samdb for KDC backend! " ) ) ;
2005-12-11 11:31:46 +03:00
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO ;
2005-06-03 18:32:10 +04:00
}
2007-06-15 04:14:11 +04:00
( * db ) - > hdb_dbc = NULL ;
2009-07-16 06:47:57 +04:00
( * db ) - > hdb_open = hdb_samba4_open ;
( * db ) - > hdb_close = hdb_samba4_close ;
( * db ) - > hdb_fetch = hdb_samba4_fetch ;
( * db ) - > hdb_store = hdb_samba4_store ;
( * db ) - > hdb_remove = hdb_samba4_remove ;
( * db ) - > hdb_firstkey = hdb_samba4_firstkey ;
( * db ) - > hdb_nextkey = hdb_samba4_nextkey ;
( * db ) - > hdb_lock = hdb_samba4_lock ;
( * db ) - > hdb_unlock = hdb_samba4_unlock ;
( * db ) - > hdb_rename = hdb_samba4_rename ;
2005-06-03 18:32:10 +04:00
/* we don't implement these, as we are not a lockable database */
( * db ) - > hdb__get = NULL ;
( * db ) - > hdb__put = NULL ;
/* kadmin should not be used for deletes - use other tools instead */
( * db ) - > hdb__del = NULL ;
2009-07-16 06:47:57 +04:00
( * db ) - > hdb_destroy = hdb_samba4_destroy ;
2005-06-03 18:32:10 +04:00
2009-07-07 06:34:55 +04:00
( * db ) - > hdb_auth_status = NULL ;
2009-07-18 04:15:55 +04:00
( * db ) - > hdb_check_constrained_delegation = hdb_samba4_check_constrained_delegation ;
2009-07-28 08:05:19 +04:00
( * db ) - > hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match ;
2009-07-07 06:34:55 +04:00
2005-12-11 11:31:46 +03:00
return NT_STATUS_OK ;
2005-06-03 18:32:10 +04:00
}
2006-01-24 08:31:08 +03:00
2009-07-27 07:48:45 +04:00
static krb5_error_code hdb_samba4_create ( krb5_context context , struct HDB * * db , const char * arg )
2006-01-24 08:31:08 +03:00
{
NTSTATUS nt_status ;
2009-07-27 10:09:25 +04:00
void * ptr ;
struct hdb_samba4_context * hdb_samba4_context ;
2009-12-23 23:08:02 +03:00
2009-07-27 10:09:25 +04:00
if ( sscanf ( arg , " &%p " , & ptr ) ! = 1 ) {
return EINVAL ;
}
hdb_samba4_context = talloc_get_type_abort ( ptr , struct hdb_samba4_context ) ;
2008-02-21 19:17:37 +03:00
/* The global kdc_mem_ctx and kdc_lp_ctx, Disgusting, ugly hack, but it means one less private hook */
2009-07-27 10:09:25 +04:00
nt_status = hdb_samba4_create_kdc ( hdb_samba4_context , hdb_samba4_context - > ev_ctx , hdb_samba4_context - > lp_ctx ,
2009-07-27 07:48:45 +04:00
context , db ) ;
2006-01-24 08:31:08 +03:00
if ( NT_STATUS_IS_OK ( nt_status ) ) {
return 0 ;
}
return EINVAL ;
}
2009-07-27 07:48:45 +04:00
/* Only used in the hdb-backed keytab code
2009-07-27 10:09:25 +04:00
* for a keytab of ' samba4 & < address > ' , to find
2009-07-27 07:48:45 +04:00
* kpasswd ' s key in the main DB , and to
2009-07-27 10:09:25 +04:00
* copy all the keys into a file ( libnet_keytab_export )
*
* The < address > is the string form of a pointer to a talloced struct hdb_samba_context
*/
2009-07-27 07:48:45 +04:00
struct hdb_method hdb_samba4 = {
. interface_version = HDB_INTERFACE_VERSION ,
2009-12-23 23:08:02 +03:00
. prefix = " samba4 " ,
2009-07-27 07:48:45 +04:00
. create = hdb_samba4_create
} ;