Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • lts-team/packages/samba
  • thctlo/samba-lintianfix
  • arnaudr/samba
  • jrwren/samba
  • paride/samba
  • athos/samba
  • henrich/samba
  • cnotin/samba
  • mimi89999/samba
  • samba-team/samba
  • ahasenack/samba
  • jrtc27/samba
  • noel/samba
13 results
Show changes
Commits on Source (2185)
Showing
with 1019 additions and 508 deletions
include:
- /.gitlab-ci-default-runners.yml
.shared_runner_test:
# We need the more powerful n1-standard-2 runners
# in order to handle the lcov overhead.
#
# See .gitlab-ci-default-runners.yml for more details
tags:
- gitlab-org-docker
# Currently we're happy with the defaults
# From https://docs.gitlab.com/ee/user/gitlab_com/#shared-runners:
# From https://docs.gitlab.com/ee/ci/runners/hosted_runners/linux.html
#
# ...
#
# All your CI/CD jobs run on n1-standard-1 instances with 3.75GB of RAM, CoreOS
# and the latest Docker Engine installed. Instances provide 1 vCPU and 25GB of
# HDD disk space. The default region of the VMs is US East1. Each instance is
# used only for one job, this ensures any sensitive data left on the system can’t
# be accessed by other people their CI jobs.
#
# The gitlab-shared-runners-manager-X.gitlab.com fleet of runners are dedicated
# for GitLab projects as well as community forks of them. They use a slightly
# larger machine type (n1-standard-2) and have a bigger SSD disk size. They don’t
# run untagged jobs and unlike the general fleet of shared runners, the instances
# are re-used up to 40 times.
#
# ...
#
# The n1-standard-1 runners seem to be tagged with 'docker' together with 'gce'.
#
# The more powerful n1-standard-2 runners seem to be tagged with
# 'gitlab-org-docker' or some with just 'gitlab-org'.
#
# Runner Tag vCPUs Memory Storage
# saas-linux-small-amd64 2 8 GB 25 GB
#
# Our current private runner 'docker', 'samba-ci-private', 'shared' and
# 'ubuntu2204'. It runs with an ubuntu2204 kernel (5.15) and provides an
# ext4 filesystem and similar RAM as the n1-standard-2 runners.
# ext4 filesystem, 2 CPU and 4 GB (shared tag) 8G (samba-ci-private tag) RAM.
#
.shared_runner_build:
# We use n1-standard-1 shared runners by default.
#
# There are currently 5 shared runners with 'docker' and 'gce',
# while there are only 2 provising 'docker' together with 'shared'.
# We use saas-linux-small-amd64 shared runners by default.
# We avoid adding explicit tags for them in order
# to work with potential changes in future
#
# We used to fallback to our private runner if the docker+shared runners
# were busy, but now that we use the 5 docker+gce runners, we try to only
# use shared runners without a fallback to our private runner!
# Lets see how that will work out.
tags:
- docker
- gce
# In order to generate valid yaml, we define a dummy variable...
variables:
SAMBA_SHARED_RUNNER_BUILD_DUMMY_VARIABLE: shared_runner_build
.shared_runner_test:
# Currently we're fine using the n1-standard-1 runners also for testing
# We use saas-linux-small-amd64 shared runners by default.
extends: .shared_runner_build
.private_runner_test:
......
......@@ -47,7 +47,7 @@ variables:
# Set this to the contents of bootstrap/sha1sum.txt
# which is generated by bootstrap/template.py --render
#
SAMBA_CI_CONTAINER_TAG: 9a406973474a7903fe7fd6215226660911ed73c0
SAMBA_CI_CONTAINER_TAG: d7e721bceae90834dfe04e8a9ba864a55d1c49e1
#
# We use the ubuntu2204 image as default as
# it matches what we have on atb-devel-224
......@@ -64,9 +64,9 @@ variables:
SAMBA_CI_CONTAINER_IMAGE_debian11_32bit: debian11-32bit
SAMBA_CI_CONTAINER_IMAGE_debian12: debian12
SAMBA_CI_CONTAINER_IMAGE_opensuse155: opensuse155
SAMBA_CI_CONTAINER_IMAGE_fedora39: fedora39
SAMBA_CI_CONTAINER_IMAGE_centos7: centos7
SAMBA_CI_CONTAINER_IMAGE_centos8s: centos8s
SAMBA_CI_CONTAINER_IMAGE_centos9s: centos9s
SAMBA_CI_CONTAINER_IMAGE_fedora40: fedora40
include:
# The image creation details are specified in a separate file
......@@ -112,8 +112,14 @@ include:
before_script:
- uname -a
- ls -l /sys/module/
- ls -l /sys/kernel/security/
- if [ -e /sys/kernel/security/lsm ]; then cat /sys/kernel/security/lsm ; echo; fi
- if [ -e /proc/config.gz ]; then sudo zcat /proc/config.gz; echo; fi
- lsb_release -a
- cat /etc/os-release
- id
- cat /proc/self/status
- lscpu
- cat /proc/cpuinfo
- mount
......@@ -140,7 +146,7 @@ include:
- ccache -z -M 500M
- ccache -s
# We are already running .gitlab-ci directives from this repo, remove additional checks that break our CI
- git config --global --add safe.directory `pwd`
- git config --global --add safe.directory '*'
after_script:
- mount
- df -h
......@@ -179,7 +185,6 @@ include:
others:
extends: .shared_template
script:
- script/autobuild.py ldb $SAMBA_CI_AUTOBUILD_ENABLE_COVERAGE --verbose --nocleanup --keeplogs --tail --full-testbase /builds/samba-testbase/ldb
- script/autobuild.py pidl $SAMBA_CI_AUTOBUILD_ENABLE_COVERAGE --verbose --nocleanup --keeplogs --tail --full-testbase /builds/samba-testbase/pidl
- script/autobuild.py replace $SAMBA_CI_AUTOBUILD_ENABLE_COVERAGE --verbose --nocleanup --keeplogs --tail --full-testbase /builds/samba-testbase/replace
- script/autobuild.py talloc $SAMBA_CI_AUTOBUILD_ENABLE_COVERAGE --verbose --nocleanup --keeplogs --tail --full-testbase /builds/samba-testbase/talloc
......@@ -262,13 +267,13 @@ samba-def-build:
samba-mit-build:
extends: .shared_template_build_only
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora39}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora40}
stage: build_first
.needs_samba-mit-build:
extends: .shared_template_test_only
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora39}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora40}
needs:
- job: samba-mit-build
artifacts: true
......@@ -316,7 +321,7 @@ samba:
samba-mitkrb5:
extends: .shared_template
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora39}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora40}
samba-minimal-smbd:
extends: .shared_template
......@@ -386,7 +391,7 @@ samba-addc-mit-4b:
samba-fips:
extends: .shared_template
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora39}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora40}
samba-codecheck:
extends: .shared_template
......@@ -657,24 +662,20 @@ opensuse155-samba-o3:
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_opensuse155}
centos7-samba-o3:
centos8s-samba-o3:
extends: .samba-o3-template
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos7}
# Git on CentOS doesn't support shallow git cloning
GIT_DEPTH: ""
# We need a newer GnuTLS version on CentOS7
PKG_CONFIG_PATH: "/usr/lib64/compat-gnutls37/pkgconfig:/usr/lib64/compat-nettle32/pkgconfig"
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos8s}
centos8s-samba-o3:
centos9s-samba-o3:
extends: .samba-o3-template
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos8s}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_centos9s}
fedora39-samba-o3:
fedora40-samba-o3:
extends: .samba-o3-template
variables:
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora39}
SAMBA_CI_JOB_IMAGE: ${SAMBA_CI_CONTAINER_IMAGE_fedora40}
#
# Keep the samba-o3 sections at the end ...
......
Jo Sutton <josutton@catalyst.net.nz> <josephsutton@catalyst.net.nz>
......@@ -390,6 +390,48 @@ Bad Example:
pointer1 = some_func1();
```
### Initialize structs
All structures MUST be at least initialised to 0/NULL.
Current recommended initialization:
```c
struct somestruct {
int ival;
bool bval;
double dval;
char *sval;
};
struct somestruct var1 = {};
```
avoid:
```c
struct somestruct var1 = {0};
```
as it can be less portable, in particular if the first element of the struct in question is a nested struct.
Of course if specific members need non-zero initialization then use something like:
```c
struct bar {
int inner;
};
struct foo {
int outer;
struct bar nested;
};
struct foo var2 = {
.outer = 5,
.nested = {
.inner = 3,
},
};
```
### Make use of helper variables
......
......@@ -26,7 +26,7 @@ SAMBA_COPYRIGHT_STRING="Copyright Andrew Tridgell and the Samba Team 1992-2024"
# -> "3.0.0" #
########################################################
SAMBA_VERSION_MAJOR=4
SAMBA_VERSION_MINOR=20
SAMBA_VERSION_MINOR=21
SAMBA_VERSION_RELEASE=0
########################################################
......@@ -89,7 +89,7 @@ SAMBA_VERSION_PRE_RELEASE=
# e.g. SAMBA_VERSION_RC_RELEASE=1 #
# -> "3.0.0rc1" #
########################################################
SAMBA_VERSION_RC_RELEASE=
SAMBA_VERSION_RC_RELEASE=1
########################################################
# To mark SVN snapshots this should be set to 'yes' #
......
This diff is collapsed.
......@@ -22,6 +22,7 @@
*/
#include "includes.h"
#include "lib/util/util_file.h"
#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
#include "auth/credentials/credentials.h"
#include "auth/credentials/credentials_internal.h"
......@@ -146,6 +147,11 @@ _PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct
return creds->kerberos_state;
}
_PUBLIC_ enum credentials_obtained cli_credentials_get_kerberos_state_obtained(struct cli_credentials *creds)
{
return creds->kerberos_state_obtained;
}
_PUBLIC_ const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *creds)
{
return creds->forced_sasl_mech;
......@@ -170,11 +176,32 @@ _PUBLIC_ bool cli_credentials_set_gensec_features(struct cli_credentials *creds,
return false;
}
_PUBLIC_ bool cli_credentials_add_gensec_features(
struct cli_credentials *creds,
uint32_t gensec_features,
enum credentials_obtained obtained)
{
return cli_credentials_set_gensec_features(
creds, creds->gensec_features | gensec_features, obtained);
}
_PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds)
{
return creds->gensec_features;
}
/**
* @brief Find out how the username was obtained.
*
* @param cred A credentials context.
*
* @return The obtained information for the username.
*/
_PUBLIC_ enum credentials_obtained
cli_credentials_get_username_obtained(struct cli_credentials *cred)
{
return cred->username_obtained;
}
/**
* Obtain the username for this credentials context.
......@@ -267,6 +294,64 @@ _PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred)
}
/**
* @brief Find out how the principal was obtained.
*
* @param cred A credentials context.
*
* @return The obtained information for the principal.
*/
_PUBLIC_ enum credentials_obtained
cli_credentials_get_principal_obtained(struct cli_credentials *cred)
{
if (cred->machine_account_pending) {
cli_credentials_set_machine_account(cred,
cred->machine_account_pending_lp_ctx);
}
if (cred->principal_obtained < cred->username_obtained
|| cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) {
const char *effective_username = NULL;
const char *effective_realm = NULL;
enum credentials_obtained effective_obtained;
/*
* We don't want to trigger a callbacks in
* cli_credentials_get_username()
* cli_credentials_get_domain()
* nor
* cli_credentials_get_realm()
*/
effective_username = cred->username;
if (effective_username == NULL || strlen(effective_username) == 0) {
return cred->username_obtained;
}
if (cred->domain_obtained > cred->realm_obtained) {
effective_realm = cred->domain;
effective_obtained = MIN(cred->domain_obtained,
cred->username_obtained);
} else {
effective_realm = cred->realm;
effective_obtained = MIN(cred->realm_obtained,
cred->username_obtained);
}
if (effective_realm == NULL || strlen(effective_realm) == 0) {
effective_realm = cred->domain;
effective_obtained = MIN(cred->domain_obtained,
cred->username_obtained);
}
if (effective_realm != NULL && strlen(effective_realm) != 0) {
return effective_obtained;
}
}
return cred->principal_obtained;
}
/**
* Obtain the client principal for this credentials context.
* @param cred credentials context
......@@ -452,6 +537,19 @@ _PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred)
return cred->password;
}
/**
* @brief Find out how the password was obtained.
*
* @param cred A credentials context.
*
* @return The obtained information for the password.
*/
_PUBLIC_ enum credentials_obtained
cli_credentials_get_password_obtained(struct cli_credentials *cred)
{
return cred->password_obtained;
}
/**
* @brief Obtain the password for this credentials context.
*
......@@ -506,6 +604,7 @@ _PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred,
if (nt_hash == NULL) {
return false;
}
talloc_keep_secret(nt_hash);
converted = strhex_to_str((char *)nt_hash->hash,
sizeof(nt_hash->hash),
......@@ -641,6 +740,7 @@ _PUBLIC_ struct samr_Password *cli_credentials_get_nt_hash(struct cli_credential
if (nt_hash == NULL) {
return NULL;
}
talloc_keep_secret(nt_hash);
if (password_is_nt_hash) {
size_t password_len = strlen(password);
......@@ -665,6 +765,7 @@ return_hash:
if (nt_hash == NULL) {
return NULL;
}
talloc_keep_secret(nt_hash);
*nt_hash = *cred->nt_hash;
......@@ -690,6 +791,7 @@ _PUBLIC_ struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_creden
if (!nt_hash) {
return NULL;
}
talloc_keep_secret(nt_hash);
*nt_hash = *cred->old_nt_hash;
......@@ -702,6 +804,7 @@ _PUBLIC_ struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_creden
if (!nt_hash) {
return NULL;
}
talloc_keep_secret(nt_hash);
E_md4hash(old_password, nt_hash->hash);
......
......@@ -91,6 +91,7 @@ struct cli_credentials *cli_credentials_init_server(TALLOC_CTX *mem_ctx,
void cli_credentials_set_anonymous(struct cli_credentials *cred);
bool cli_credentials_wrong_password(struct cli_credentials *cred);
const char *cli_credentials_get_password(struct cli_credentials *cred);
enum credentials_obtained cli_credentials_get_password_obtained(struct cli_credentials *cred);
const char *cli_credentials_get_password_and_obtained(struct cli_credentials *cred,
enum credentials_obtained *obtained);
void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx,
......@@ -105,6 +106,7 @@ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_
DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key);
const char *cli_credentials_get_realm(struct cli_credentials *cred);
const char *cli_credentials_get_username(struct cli_credentials *cred);
enum credentials_obtained cli_credentials_get_username_obtained(struct cli_credentials *cred);
const char *cli_credentials_get_username_and_obtained(struct cli_credentials *cred,
enum credentials_obtained *obtained);
int cli_credentials_get_krb5_context(struct cli_credentials *cred,
......@@ -120,6 +122,10 @@ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
struct loadparm_context *lp_ctx,
char *ccache_name,
struct ccache_container **ccc, const char **error_string);
bool cli_credentials_get_ccache_name_obtained(struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
char **ccache_name,
enum credentials_obtained *obtained);
bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
const char *principal,
unsigned int *count);
......@@ -247,6 +253,9 @@ bool cli_credentials_set_gensec_features(struct cli_credentials *creds,
uint32_t gensec_features,
enum credentials_obtained obtained);
uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds);
bool cli_credentials_add_gensec_features(struct cli_credentials *creds,
uint32_t gensec_features,
enum credentials_obtained obtained);
int cli_credentials_set_ccache(struct cli_credentials *cred,
struct loadparm_context *lp_ctx,
const char *name,
......@@ -262,11 +271,12 @@ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
const char *principal,
const char *self_service);
void cli_credentials_set_target_service(struct cli_credentials *cred, const char *principal);
const char *cli_credentials_get_salt_principal(struct cli_credentials *cred);
char *cli_credentials_get_salt_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx);
const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred);
const char *cli_credentials_get_self_service(struct cli_credentials *cred);
const char *cli_credentials_get_target_service(struct cli_credentials *cred);
enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds);
enum credentials_obtained cli_credentials_get_kerberos_state_obtained(struct cli_credentials *creds);
const char *cli_credentials_get_forced_sasl_mech(struct cli_credentials *cred);
enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds);
NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
......@@ -280,6 +290,8 @@ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
bool cli_credentials_set_username_callback(struct cli_credentials *cred,
const char *(*username_cb) (struct cli_credentials *));
enum credentials_obtained cli_credentials_get_principal_obtained(struct cli_credentials *cred);
/**
* Obtain the client principal for this credentials context.
* @param cred credentials context
......@@ -348,12 +360,6 @@ NTSTATUS netlogon_creds_session_encrypt(
struct netlogon_creds_CredentialState *state,
DATA_BLOB data);
int cli_credentials_get_aes256_key(struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
const char *salt,
DATA_BLOB *aes_256);
/**
* Kerberos FAST handling
*/
......@@ -366,4 +372,18 @@ struct cli_credentials *cli_credentials_get_krb5_fast_armor_credentials(struct c
bool cli_credentials_get_krb5_require_fast_armor(struct cli_credentials *creds);
/**
* Group Managed Service Account helper
*/
/*
* All current callers set "for_keytab = true", but if we start using
* this for getting a TGT we need the logic to ignore a very new
* key
*/
NTSTATUS cli_credentials_set_gmsa_passwords(struct cli_credentials *creds,
const DATA_BLOB *managed_password_blob,
bool for_keytab,
const char **error_string);
#endif /* __CREDENTIALS_H__ */
/*
Unix SMB/CIFS implementation.
User credentials handling for Group Managed Service Accounts
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2023
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "librpc/gen_ndr/ndr_gmsa.h" /* for struct MANAGEDPASSWORD_BLOB */
#include "auth/credentials/credentials.h"
#include "auth/credentials/credentials_internal.h"
#include "lib/util/charset/charset.h"
#include "lib/crypto/gkdi.h"
/*
* All current callers set "for_keytab = true", but if we start using
* this for getting a TGT we need the logic to ignore a very new
* key
*/
NTSTATUS cli_credentials_set_gmsa_passwords(struct cli_credentials *creds,
const DATA_BLOB *managed_password_blob,
bool for_keytab,
const char **error_string)
{
struct MANAGEDPASSWORD_BLOB managed_password;
DATA_BLOB managed_pw_utf16;
DATA_BLOB previous_managed_pw_utf16;
enum ndr_err_code ndr_err;
TALLOC_CTX *frame = talloc_stackframe();
bool only_use_previous_pw;
/*
* Group Managed Service Accounts are type
* UF_WORKSTATION_TRUST_ACCOUNT and will follow those salting
* rules
*/
cli_credentials_set_secure_channel_type(creds, SEC_CHAN_WKSTA);
ndr_err = ndr_pull_struct_blob_all(managed_password_blob,
frame,
&managed_password,
(ndr_pull_flags_fn_t)ndr_pull_MANAGEDPASSWORD_BLOB);
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
*error_string = talloc_asprintf(creds,
"Failed to parse msDS-ManagedPassword "
"as MANAGEDPASSWORD_BLOB");
TALLOC_FREE(frame);
return NT_STATUS_ILL_FORMED_PASSWORD;
}
/*
* We check if this is 'for keytab' as a keytab wants to know
* about a near-future password as it will be on disk for some
* time
*/
only_use_previous_pw =
managed_password.passwords.query_interval != NULL
&& *managed_password.passwords.query_interval <= gkdi_max_clock_skew
&& for_keytab == false;
/*
* We look at the old password first as we might bail out
* early if the new password is "too fresh"
*/
if (managed_password.passwords.previous) {
previous_managed_pw_utf16
= data_blob_const(managed_password.passwords.previous,
utf16_len(managed_password.passwords.previous));
cli_credentials_set_old_utf16_password(creds, &previous_managed_pw_utf16);
if (only_use_previous_pw) {
/* We are in the 5 mins where we know the next
* password, but it will not be available yet, just
* use the old password for now.
*/
cli_credentials_set_utf16_password(creds, &previous_managed_pw_utf16,
CRED_SPECIFIED);
/*
* We are done, the new password is of no
* interest to us
*/
TALLOC_FREE(frame);
return NT_STATUS_OK;
}
}
if (only_use_previous_pw) {
*error_string = talloc_asprintf(creds,
"No old password but new password is too new "
"(< 5min) in msDS-ManagedPassword "
"MANAGEDPASSWORD_BLOB");
TALLOC_FREE(frame);
return NT_STATUS_ILL_FORMED_PASSWORD;
}
if (managed_password.passwords.current == NULL) {
*error_string = talloc_asprintf(creds,
"Failed to find new password in msDS-ManagedPassword "
"MANAGEDPASSWORD_BLOB");
TALLOC_FREE(frame);
return NT_STATUS_ILL_FORMED_PASSWORD;
}
managed_pw_utf16
= data_blob_const(managed_password.passwords.current,
utf16_len(managed_password.passwords.current));
cli_credentials_set_utf16_password(creds, &managed_pw_utf16,
CRED_SPECIFIED);
TALLOC_FREE(frame);
return NT_STATUS_OK;
}
......@@ -79,25 +79,15 @@ static uint32_t smb_gss_krb5_copy_ccache(uint32_t *min_stat,
krb5_cc_cursor cursor = NULL;
krb5_principal princ = NULL;
krb5_error_code code;
char *dummy_name;
uint32_t maj_stat = GSS_S_FAILURE;
dummy_name = talloc_asprintf(ccc,
"MEMORY:gss_krb5_copy_ccache-%p",
&ccc->ccache);
if (dummy_name == NULL) {
*min_stat = ENOMEM;
return GSS_S_FAILURE;
}
/*
* Create a dummy ccache, so we can iterate over the credentials
* and find the default principal for the ccache we want to
* copy. The new ccache needs to be initialized with this
* principal.
*/
code = krb5_cc_resolve(context, dummy_name, &dummy_ccache);
TALLOC_FREE(dummy_name);
code = smb_krb5_cc_new_unique_memory(context, NULL, NULL, &dummy_ccache);
if (code != 0) {
*min_stat = code;
return GSS_S_FAILURE;
......@@ -109,13 +99,13 @@ static uint32_t smb_gss_krb5_copy_ccache(uint32_t *min_stat,
*/
maj_stat = gss_krb5_copy_ccache(min_stat, cred, dummy_ccache);
if (maj_stat != 0) {
krb5_cc_close(context, dummy_ccache);
krb5_cc_destroy(context, dummy_ccache);
return maj_stat;
}
code = krb5_cc_start_seq_get(context, dummy_ccache, &cursor);
if (code != 0) {
krb5_cc_close(context, dummy_ccache);
krb5_cc_destroy(context, dummy_ccache);
*min_stat = EINVAL;
return GSS_S_FAILURE;
}
......@@ -125,7 +115,7 @@ static uint32_t smb_gss_krb5_copy_ccache(uint32_t *min_stat,
&cursor,
&creds);
if (code != 0) {
krb5_cc_close(context, dummy_ccache);
krb5_cc_destroy(context, dummy_ccache);
*min_stat = EINVAL;
return GSS_S_FAILURE;
}
......@@ -163,7 +153,7 @@ static uint32_t smb_gss_krb5_copy_ccache(uint32_t *min_stat,
krb5_cc_end_seq_get(context, dummy_ccache, &cursor);
code = 0;
}
krb5_cc_close(context, dummy_ccache);
krb5_cc_destroy(context, dummy_ccache);
if (code != 0 || princ == NULL) {
krb5_free_cred_contents(context, &creds);
......@@ -333,7 +323,11 @@ _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
return ret;
}
} else {
ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
/*
* This is where the caller really wants to use
* the default krb5 ccache.
*/
ret = smb_force_krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
if (ret) {
(*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
......@@ -382,29 +376,18 @@ static krb5_error_code krb5_cc_remove_cred_wrap(struct ccache_container *ccc,
krb5_creds cached_creds = {0};
krb5_cc_cursor cursor = NULL;
krb5_error_code code;
char *dummy_name;
dummy_name = talloc_asprintf(ccc,
"MEMORY:copy_ccache-%p",
&ccc->ccache);
if (dummy_name == NULL) {
return KRB5_CC_NOMEM;
}
code = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context,
dummy_name,
&dummy_ccache);
code = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
NULL, NULL,
&dummy_ccache);
if (code != 0) {
DBG_ERR("krb5_cc_resolve failed: %s\n",
smb_get_krb5_error_message(
ccc->smb_krb5_context->krb5_context,
code, ccc));
TALLOC_FREE(dummy_name);
return code;
}
TALLOC_FREE(dummy_name);
code = krb5_cc_start_seq_get(ccc->smb_krb5_context->krb5_context,
ccc->ccache,
&cursor);
......@@ -597,10 +580,11 @@ _PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred
static int cli_credentials_new_ccache(struct cli_credentials *cred,
struct loadparm_context *lp_ctx,
char *ccache_name,
char *given_ccache_name,
struct ccache_container **_ccc,
const char **error_string)
{
char *ccache_name = given_ccache_name;
bool must_free_cc_name = false;
krb5_error_code ret;
struct ccache_container *ccc = talloc(cred, struct ccache_container);
......@@ -623,31 +607,32 @@ static int cli_credentials_new_ccache(struct cli_credentials *cred,
}
if (!ccache_name) {
must_free_cc_name = true;
if (lpcfg_parm_bool(lp_ctx, NULL, "credentials", "krb5_cc_file", false)) {
ccache_name = talloc_asprintf(ccc, "FILE:/tmp/krb5_cc_samba_%u_%p",
(unsigned int)getpid(), ccc);
} else {
ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
ccc);
}
if (!ccache_name) {
talloc_free(ccc);
(*error_string) = strerror(ENOMEM);
return ENOMEM;
if (ccache_name == NULL) {
talloc_free(ccc);
(*error_string) = strerror(ENOMEM);
return ENOMEM;
}
must_free_cc_name = true;
}
}
ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
&ccc->ccache);
if (ccache_name != NULL) {
ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
&ccc->ccache);
} else {
ret = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
ccc, &ccache_name,
&ccc->ccache);
must_free_cc_name = true;
}
if (ret) {
(*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
ccache_name,
smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
ret, ccc));
talloc_free(ccache_name);
talloc_free(ccc);
return ret;
}
......@@ -759,6 +744,95 @@ _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
}
/**
* @brief Check if a valid Kerberos credential cache is attached.
*
* This will not ask for a password nor do a kinit.
*
* @param cred The credentials context.
*
* @param mem_ctx A memory context to allocate the ccache_name.
*
* @param ccache_name A pointer to a string to store the ccache name.
*
* @param obtained A pointer to store the information how the ccache was
* obtained.
*
* @return True if a credential cache is attached, false if not or an error
* occurred.
*/
_PUBLIC_ bool cli_credentials_get_ccache_name_obtained(
struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
char **ccache_name,
enum credentials_obtained *obtained)
{
if (ccache_name != NULL) {
*ccache_name = NULL;
}
if (obtained != NULL) {
*obtained = CRED_UNINITIALISED;
}
if (cred->machine_account_pending) {
return false;
}
if (cred->ccache_obtained == CRED_UNINITIALISED) {
return false;
}
if (cred->ccache_obtained >= cred->ccache_threshold) {
krb5_context k5ctx = cred->ccache->smb_krb5_context->krb5_context;
krb5_ccache k5ccache = cred->ccache->ccache;
krb5_error_code ret;
time_t lifetime = 0;
ret = smb_krb5_cc_get_lifetime(k5ctx, k5ccache, &lifetime);
if (ret == KRB5_CC_END || ret == ENOENT) {
return false;
}
if (ret != 0) {
return false;
}
if (lifetime == 0) {
return false;
} else if (lifetime < 300) {
if (cred->password_obtained >= cred->ccache_obtained) {
/*
* we have a password to re-kinit
* so let the caller try that.
*/
return false;
}
}
if (ccache_name != NULL) {
char *name = NULL;
ret = krb5_cc_get_full_name(k5ctx, k5ccache, &name);
if (ret != 0) {
return false;
}
*ccache_name = talloc_strdup(mem_ctx, name);
SAFE_FREE(name);
if (*ccache_name == NULL) {
return false;
}
}
if (obtained != NULL) {
*obtained = cred->ccache_obtained;
}
return true;
}
return false;
}
/* We have good reason to think the ccache in these credentials is invalid - blow it away */
static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
{
......@@ -1071,7 +1145,6 @@ static int cli_credentials_shallow_ccache(struct cli_credentials *cred)
const struct ccache_container *old_ccc = NULL;
enum credentials_obtained old_obtained;
struct ccache_container *ccc = NULL;
char *ccache_name = NULL;
krb5_principal princ;
old_obtained = cred->ccache_obtained;
......@@ -1104,10 +1177,10 @@ static int cli_credentials_shallow_ccache(struct cli_credentials *cred)
*ccc = *old_ccc;
ccc->ccache = NULL;
ccache_name = talloc_asprintf(ccc, "MEMORY:%p", ccc);
ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context,
ccache_name, &ccc->ccache);
ret = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
NULL,
NULL,
&ccc->ccache);
if (ret != 0) {
TALLOC_FREE(ccc);
return ret;
......@@ -1115,8 +1188,6 @@ static int cli_credentials_shallow_ccache(struct cli_credentials *cred)
talloc_set_destructor(ccc, free_mccache);
TALLOC_FREE(ccache_name);
ret = smb_krb5_cc_copy_creds(ccc->smb_krb5_context->krb5_context,
old_ccc->ccache, ccc->ccache);
if (ret != 0) {
......@@ -1174,10 +1245,8 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
krb5_keytab keytab;
TALLOC_CTX *mem_ctx;
const char *username = cli_credentials_get_username(cred);
const char *upn = NULL;
const char *realm = cli_credentials_get_realm(cred);
char *salt_principal = NULL;
uint32_t uac_flags = 0;
if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
cred->username_obtained))) {
......@@ -1200,37 +1269,10 @@ _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
return ENOMEM;
}
switch (cred->secure_channel_type) {
case SEC_CHAN_WKSTA:
case SEC_CHAN_RODC:
uac_flags = UF_WORKSTATION_TRUST_ACCOUNT;
break;
case SEC_CHAN_BDC:
uac_flags = UF_SERVER_TRUST_ACCOUNT;
break;
case SEC_CHAN_DOMAIN:
case SEC_CHAN_DNS_DOMAIN:
uac_flags = UF_INTERDOMAIN_TRUST_ACCOUNT;
break;
default:
upn = cli_credentials_get_principal(cred, mem_ctx);
if (upn == NULL) {
TALLOC_FREE(mem_ctx);
return ENOMEM;
}
uac_flags = UF_NORMAL_ACCOUNT;
break;
}
ret = smb_krb5_salt_principal_str(realm,
username, /* sAMAccountName */
upn, /* userPrincipalName */
uac_flags,
mem_ctx,
&salt_principal);
if (ret) {
salt_principal = cli_credentials_get_salt_principal(cred, mem_ctx);
if (salt_principal == NULL) {
talloc_free(mem_ctx);
return ret;
return ENOMEM;
}
ret = smb_krb5_create_memory_keytab(mem_ctx,
......@@ -1412,9 +1454,61 @@ _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
}
const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
char *cli_credentials_get_salt_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
{
return cred->salt_principal;
TALLOC_CTX *frame = NULL;
const char *realm = NULL;
const char *username = NULL;
uint32_t uac_flags = 0;
char *salt_principal = NULL;
const char *upn = NULL;
int ret;
/* If specified, use the specified value */
if (cred->salt_principal != NULL) {
return talloc_strdup(mem_ctx, cred->salt_principal);
}
frame = talloc_stackframe();
switch (cred->secure_channel_type) {
case SEC_CHAN_WKSTA:
case SEC_CHAN_RODC:
uac_flags = UF_WORKSTATION_TRUST_ACCOUNT;
break;
case SEC_CHAN_BDC:
uac_flags = UF_SERVER_TRUST_ACCOUNT;
break;
case SEC_CHAN_DOMAIN:
case SEC_CHAN_DNS_DOMAIN:
uac_flags = UF_INTERDOMAIN_TRUST_ACCOUNT;
break;
default:
upn = cli_credentials_get_principal(cred, frame);
if (upn == NULL) {
TALLOC_FREE(frame);
return NULL;
}
uac_flags = UF_NORMAL_ACCOUNT;
break;
}
realm = cli_credentials_get_realm(cred);
username = cli_credentials_get_username(cred);
ret = smb_krb5_salt_principal_str(realm,
username, /* sAMAccountName */
upn, /* userPrincipalName */
uac_flags,
mem_ctx,
&salt_principal);
if (ret) {
TALLOC_FREE(frame);
return NULL;
}
TALLOC_FREE(frame);
return salt_principal;
}
_PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
......@@ -1481,29 +1575,69 @@ _PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, c
cred->target_service = talloc_strdup(cred, target_service);
}
_PUBLIC_ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
const char *salt,
DATA_BLOB *aes_256)
_PUBLIC_ int cli_credentials_get_kerberos_key(struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
krb5_enctype enctype,
bool previous,
DATA_BLOB *key_blob)
{
struct smb_krb5_context *smb_krb5_context = NULL;
krb5_error_code krb5_ret;
int ret;
const char *password = NULL;
const char *salt = NULL;
krb5_data cleartext_data;
krb5_data salt_data = {
.length = 0,
};
krb5_keyblock key;
TALLOC_CTX *frame = talloc_stackframe();
if ((int)enctype == (int)ENCTYPE_ARCFOUR_HMAC) {
struct samr_Password *nt_hash;
if (previous) {
nt_hash = cli_credentials_get_old_nt_hash(cred, frame);
} else {
nt_hash = cli_credentials_get_nt_hash(cred, frame);
}
if (nt_hash == NULL) {
TALLOC_FREE(frame);
return EINVAL;
}
*key_blob = data_blob_talloc(mem_ctx,
nt_hash->hash,
sizeof(nt_hash->hash));
if (key_blob->data == NULL) {
TALLOC_FREE(frame);
return ENOMEM;
}
TALLOC_FREE(frame);
return 0;
}
if (cred->password_will_be_nt_hash) {
DEBUG(1,("cli_credentials_get_aes256_key: cannot generate AES256 key using NT hash\n"));
DEBUG(1,("cli_credentials_get_kerberos_key: cannot generate Kerberos key using NT hash\n"));
TALLOC_FREE(frame);
return EINVAL;
}
password = cli_credentials_get_password(cred);
salt = cli_credentials_get_salt_principal(cred, frame);
if (salt == NULL) {
TALLOC_FREE(frame);
return EINVAL;
}
if (previous) {
password = cli_credentials_get_old_password(cred);
} else {
password = cli_credentials_get_password(cred);
}
if (password == NULL) {
TALLOC_FREE(frame);
return EINVAL;
}
......@@ -1513,6 +1647,7 @@ _PUBLIC_ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
ret = cli_credentials_get_krb5_context(cred, lp_ctx,
&smb_krb5_context);
if (ret != 0) {
TALLOC_FREE(frame);
return ret;
}
......@@ -1520,31 +1655,34 @@ _PUBLIC_ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
salt_data.length = strlen(salt);
/*
* create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
* create Kerberos key out of
* the salt and the cleartext password
*/
krb5_ret = smb_krb5_create_key_from_string(smb_krb5_context->krb5_context,
NULL,
&salt_data,
&cleartext_data,
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
enctype,
&key);
if (krb5_ret != 0) {
DEBUG(1,("cli_credentials_get_aes256_key: "
"generation of a aes256-cts-hmac-sha1-96 key failed: %s\n",
smb_get_krb5_error_message(smb_krb5_context->krb5_context,
krb5_ret, mem_ctx)));
TALLOC_FREE(frame);
return EINVAL;
}
*aes_256 = data_blob_talloc(mem_ctx,
*key_blob = data_blob_talloc(mem_ctx,
KRB5_KEY_DATA(&key),
KRB5_KEY_LENGTH(&key));
krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &key);
if (aes_256->data == NULL) {
if (key_blob->data == NULL) {
TALLOC_FREE(frame);
return ENOMEM;
}
talloc_keep_secret(aes_256->data);
talloc_keep_secret(key_blob->data);
TALLOC_FREE(frame);
return 0;
}
......
......@@ -23,9 +23,8 @@
#ifndef __CREDENTIALS_KRB5_H__
#define __CREDENTIALS_KRB5_H__
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_krb5.h>
#include <krb5.h>
#include "system/gssapi.h"
#include "system/kerberos.h"
struct gssapi_creds_container {
gss_cred_id_t creds;
......@@ -41,5 +40,12 @@ int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
struct cli_credentials *cli_credentials_shallow_copy(TALLOC_CTX *mem_ctx,
struct cli_credentials *src);
int cli_credentials_get_kerberos_key(struct cli_credentials *cred,
TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
krb5_enctype enctype,
bool previous,
DATA_BLOB *key_blob);
#endif /* __CREDENTIALS_KRB5_H__ */
......@@ -370,13 +370,17 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credenti
}
if (secrets_tdb_password_more_recent) {
enum credentials_use_kerberos use_kerberos =
CRED_USE_KERBEROS_DISABLED;
char *machine_account = talloc_asprintf(tmp_ctx, "%s$", lpcfg_netbios_name(lp_ctx));
cli_credentials_set_password(cred, secrets_tdb_password, CRED_SPECIFIED);
cli_credentials_set_old_password(cred, secrets_tdb_old_password, CRED_SPECIFIED);
cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
if (strequal(domain, lpcfg_workgroup(lp_ctx))) {
enum credentials_use_kerberos use_kerberos =
cli_credentials_get_kerberos_state(cred);
enum credentials_obtained use_kerberos_obtained =
cli_credentials_get_kerberos_state_obtained(cred);
bool is_ad = false;
cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_SPECIFIED);
switch (server_role) {
......@@ -388,13 +392,28 @@ _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credenti
FALL_THROUGH;
case ROLE_ACTIVE_DIRECTORY_DC:
case ROLE_IPA_DC:
use_kerberos = CRED_USE_KERBEROS_DESIRED;
is_ad = true;
break;
}
if (use_kerberos != CRED_USE_KERBEROS_DESIRED || is_ad) {
/*
* Keep an explicit selection
*
* For AD domains we also keep
* CRED_USE_KERBEROS_DESIRED
*/
} else if (use_kerberos_obtained <= CRED_SMB_CONF) {
/*
* Disable kerberos by default within
* an NT4 domain.
*/
cli_credentials_set_kerberos_state(cred,
CRED_USE_KERBEROS_DISABLED,
CRED_SMB_CONF);
}
}
cli_credentials_set_kerberos_state(cred,
use_kerberos,
CRED_SPECIFIED);
cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
cli_credentials_set_password_last_changed_time(cred, secrets_tdb_lct);
cli_credentials_set_secure_channel_type(cred, secrets_tdb_secure_channel_type);
......
......@@ -23,6 +23,7 @@
#include "pycredentials.h"
#include "param/param.h"
#include "auth/credentials/credentials_internal.h"
#include "auth/credentials/credentials_krb5.h"
#include "librpc/gen_ndr/samr.h" /* for struct samr_Password */
#include "librpc/gen_ndr/netlogon.h"
#include "libcli/util/pyerrors.h"
......@@ -34,8 +35,6 @@
#include "auth/kerberos/kerberos.h"
#include "libcli/smb/smb_constants.h"
void initcredentials(void);
static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
return pytalloc_steal(type, cli_credentials_init(NULL));
......@@ -545,6 +544,9 @@ static PyObject *py_creds_get_nt_hash(PyObject *self, PyObject *unused)
return NULL;
}
ntpw = cli_credentials_get_nt_hash(creds, creds);
if (ntpw == NULL) {
Py_RETURN_NONE;
}
ret = PyBytes_FromStringAndSize(discard_const_p(char, ntpw->hash), 16);
TALLOC_FREE(ntpw);
......@@ -573,11 +575,7 @@ static PyObject *py_creds_set_nt_hash(PyObject *self, PyObject *args)
return NULL;
}
pwd = pytalloc_get_type(py_cp, struct samr_Password);
if (pwd == NULL) {
/* pytalloc_get_type sets TypeError */
return NULL;
}
pwd = pytalloc_get_ptr(py_cp);
return PyBool_FromLong(cli_credentials_set_nt_hash(creds, pwd, obt));
}
......@@ -973,14 +971,55 @@ static PyObject *py_creds_get_secure_channel_type(PyObject *self, PyObject *args
return PyLong_FromLong(channel_type);
}
static PyObject *py_creds_get_aes256_key(PyObject *self, PyObject *args)
static PyObject *py_creds_set_kerberos_salt_principal(PyObject *self, PyObject *args)
{
char *salt_principal = NULL;
struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
if (creds == NULL) {
PyErr_Format(PyExc_TypeError, "Credentials expected");
return NULL;
}
if (!PyArg_ParseTuple(args, "s", &salt_principal))
return NULL;
cli_credentials_set_salt_principal(
creds,
salt_principal);
Py_RETURN_NONE;
}
static PyObject *py_creds_get_kerberos_salt_principal(PyObject *self, PyObject *unused)
{
TALLOC_CTX *mem_ctx;
PyObject *ret = NULL;
struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
if (creds == NULL) {
PyErr_Format(PyExc_TypeError, "Credentials expected");
return NULL;
}
mem_ctx = talloc_new(NULL);
if (mem_ctx == NULL) {
PyErr_NoMemory();
return NULL;
}
ret = PyString_FromStringOrNULL(cli_credentials_get_salt_principal(creds, mem_ctx));
TALLOC_FREE(mem_ctx);
return ret;
}
static PyObject *py_creds_get_kerberos_key_current_or_old(PyObject *self, PyObject *args, bool old)
{
struct loadparm_context *lp_ctx = NULL;
TALLOC_CTX *mem_ctx = NULL;
PyObject *py_lp_ctx = Py_None;
const char *salt = NULL;
DATA_BLOB aes_256;
DATA_BLOB key;
int code;
int enctype;
PyObject *ret = NULL;
struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
if (creds == NULL) {
......@@ -988,7 +1027,7 @@ static PyObject *py_creds_get_aes256_key(PyObject *self, PyObject *args)
return NULL;
}
if (!PyArg_ParseTuple(args, "s|O", &salt, &py_lp_ctx))
if (!PyArg_ParseTuple(args, "i|O", &enctype, &py_lp_ctx))
return NULL;
mem_ctx = talloc_new(NULL);
......@@ -1003,24 +1042,35 @@ static PyObject *py_creds_get_aes256_key(PyObject *self, PyObject *args)
return NULL;
}
code = cli_credentials_get_aes256_key(creds,
mem_ctx,
lp_ctx,
salt,
&aes_256);
code = cli_credentials_get_kerberos_key(creds,
mem_ctx,
lp_ctx,
enctype,
old,
&key);
if (code != 0) {
PyErr_SetString(PyExc_RuntimeError,
"Failed to generate AES256 key");
"Failed to generate Kerberos key");
talloc_free(mem_ctx);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)aes_256.data,
aes_256.length);
ret = PyBytes_FromStringAndSize((const char *)key.data,
key.length);
talloc_free(mem_ctx);
return ret;
}
static PyObject *py_creds_get_kerberos_key(PyObject *self, PyObject *args)
{
return py_creds_get_kerberos_key_current_or_old(self, args, false);
}
static PyObject *py_creds_get_old_kerberos_key(PyObject *self, PyObject *args)
{
return py_creds_get_kerberos_key_current_or_old(self, args, true);
}
static PyObject *py_creds_encrypt_netr_crypt_password(PyObject *self,
PyObject *args)
{
......@@ -1040,7 +1090,12 @@ static PyObject *py_creds_encrypt_netr_crypt_password(PyObject *self,
return NULL;
}
pwd = pytalloc_get_type(py_cp, struct netr_CryptPassword);
if (!py_check_dcerpc_type(py_cp, "samba.dcerpc.netlogon", "netr_CryptPassword")) {
/* py_check_dcerpc_type sets TypeError */
return NULL;
}
pwd = pytalloc_get_ptr(py_cp);
if (pwd == NULL) {
/* pytalloc_get_type sets TypeError */
return NULL;
......@@ -1587,12 +1642,30 @@ static PyMethodDef py_creds_methods[] = {
.ml_flags = METH_VARARGS,
},
{
.ml_name = "get_aes256_key",
.ml_meth = py_creds_get_aes256_key,
.ml_name = "set_kerberos_salt_principal",
.ml_meth = py_creds_set_kerberos_salt_principal,
.ml_flags = METH_VARARGS,
},
{
.ml_name = "get_kerberos_salt_principal",
.ml_meth = py_creds_get_kerberos_salt_principal,
.ml_flags = METH_VARARGS,
.ml_doc = "S.get_aes256_key(salt[, lp]) -> bytes\n"
"Generate an AES256 key using the current password and\n"
"the specified salt",
},
{
.ml_name = "get_kerberos_key",
.ml_meth = py_creds_get_kerberos_key,
.ml_flags = METH_VARARGS,
.ml_doc = "S.get_kerberos_key(enctype, [lp]) -> bytes\n"
"Generate a Kerberos key using the current password and\n"
"the salt on this credentials object",
},
{
.ml_name = "get_old_kerberos_key",
.ml_meth = py_creds_get_old_kerberos_key,
.ml_flags = METH_VARARGS,
.ml_doc = "S.get_old_kerberos_key(enctype, [lp]) -> bytes\n"
"Generate a Kerberos key using the old (previous) password and\n"
"the salt on this credentials object",
},
{
.ml_name = "encrypt_netr_crypt_password",
......@@ -1760,6 +1833,10 @@ MODULE_INIT_FUNC(credentials)
PyModule_AddObject(m, "SMB_ENCRYPTION_DESIRED", PyLong_FromLong(SMB_ENCRYPTION_DESIRED));
PyModule_AddObject(m, "SMB_ENCRYPTION_REQUIRED", PyLong_FromLong(SMB_ENCRYPTION_REQUIRED));
PyModule_AddObject(m, "ENCTYPE_ARCFOUR_HMAC", PyLong_FromLong(ENCTYPE_ARCFOUR_HMAC));
PyModule_AddObject(m, "ENCTYPE_AES128_CTS_HMAC_SHA1_96", PyLong_FromLong(ENCTYPE_AES128_CTS_HMAC_SHA1_96));
PyModule_AddObject(m, "ENCTYPE_AES256_CTS_HMAC_SHA1_96", PyLong_FromLong(ENCTYPE_AES256_CTS_HMAC_SHA1_96));
Py_INCREF(&PyCredentials);
PyModule_AddObject(m, "Credentials", (PyObject *)&PyCredentials);
Py_INCREF(&PyCredentialCacheContainer);
......
......@@ -140,7 +140,7 @@ unicodePwd:: """ + base64.b64encode(u"\"P@ssw0rd\"".encode('utf-16-le')).decode(
res = ldb_virtual.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
def test_computer_account_bind(self):
# create a computer acocount for the test
# create a computer account for the test
delete_force(self.ldb, self.computer_dn)
self.ldb.add_ldif("""
dn: """ + self.computer_dn + """
......
......@@ -166,6 +166,9 @@ static void torture_creds_parse_string(void **state)
{
TALLOC_CTX *mem_ctx = *state;
struct cli_credentials *creds = NULL;
enum credentials_obtained princ_obtained = CRED_UNINITIALISED;
enum credentials_obtained usr_obtained = CRED_UNINITIALISED;
enum credentials_obtained pwd_obtained = CRED_UNINITIALISED;
creds = cli_credentials_init(mem_ctx);
assert_non_null(creds);
......@@ -213,13 +216,17 @@ static void torture_creds_parse_string(void **state)
assert_int_equal(creds->domain_obtained, CRED_SPECIFIED);
assert_string_equal(creds->username, "wurst@brot.realm");
assert_int_equal(creds->username_obtained, CRED_SPECIFIED);
usr_obtained = cli_credentials_get_username_obtained(creds);
assert_int_equal(usr_obtained, CRED_SPECIFIED);
assert_string_equal(creds->principal, "wurst@brot.realm");
assert_int_equal(creds->principal_obtained, CRED_SPECIFIED);
princ_obtained = cli_credentials_get_principal_obtained(creds);
assert_int_equal(princ_obtained, CRED_SPECIFIED);
assert_string_equal(creds->password, "BROT");
assert_int_equal(creds->password_obtained, CRED_SPECIFIED);
pwd_obtained = cli_credentials_get_password_obtained(creds);
assert_int_equal(pwd_obtained, CRED_SPECIFIED);
}
static void torture_creds_krb5_state(void **state)
......@@ -227,6 +234,8 @@ static void torture_creds_krb5_state(void **state)
TALLOC_CTX *mem_ctx = *state;
struct cli_credentials *creds = NULL;
struct loadparm_context *lp_ctx = NULL;
enum credentials_obtained kerberos_state_obtained;
enum credentials_use_kerberos kerberos_state;
bool ok;
lp_ctx = loadparm_init_global(true);
......@@ -234,18 +243,27 @@ static void torture_creds_krb5_state(void **state)
creds = cli_credentials_init(mem_ctx);
assert_non_null(creds);
assert_int_equal(creds->kerberos_state_obtained, CRED_UNINITIALISED);
assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
kerberos_state_obtained =
cli_credentials_get_kerberos_state_obtained(creds);
kerberos_state = cli_credentials_get_kerberos_state(creds);
assert_int_equal(kerberos_state_obtained, CRED_UNINITIALISED);
assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
ok = cli_credentials_set_conf(creds, lp_ctx);
assert_true(ok);
assert_int_equal(creds->kerberos_state_obtained, CRED_SMB_CONF);
assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
kerberos_state_obtained =
cli_credentials_get_kerberos_state_obtained(creds);
kerberos_state = cli_credentials_get_kerberos_state(creds);
assert_int_equal(kerberos_state_obtained, CRED_SMB_CONF);
assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
ok = cli_credentials_guess(creds, lp_ctx);
assert_true(ok);
assert_int_equal(creds->kerberos_state_obtained, CRED_SMB_CONF);
assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_DESIRED);
kerberos_state_obtained =
cli_credentials_get_kerberos_state_obtained(creds);
kerberos_state = cli_credentials_get_kerberos_state(creds);
assert_int_equal(kerberos_state_obtained, CRED_SMB_CONF);
assert_int_equal(kerberos_state, CRED_USE_KERBEROS_DESIRED);
assert_int_equal(creds->ccache_obtained, CRED_GUESS_FILE);
assert_non_null(creds->ccache);
......@@ -253,15 +271,21 @@ static void torture_creds_krb5_state(void **state)
CRED_USE_KERBEROS_REQUIRED,
CRED_SPECIFIED);
assert_true(ok);
assert_int_equal(creds->kerberos_state_obtained, CRED_SPECIFIED);
assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_REQUIRED);
kerberos_state_obtained =
cli_credentials_get_kerberos_state_obtained(creds);
kerberos_state = cli_credentials_get_kerberos_state(creds);
assert_int_equal(kerberos_state_obtained, CRED_SPECIFIED);
assert_int_equal(kerberos_state, CRED_USE_KERBEROS_REQUIRED);
ok = cli_credentials_set_kerberos_state(creds,
CRED_USE_KERBEROS_DISABLED,
CRED_SMB_CONF);
assert_false(ok);
assert_int_equal(creds->kerberos_state_obtained, CRED_SPECIFIED);
assert_int_equal(creds->kerberos_state, CRED_USE_KERBEROS_REQUIRED);
kerberos_state_obtained =
cli_credentials_get_kerberos_state_obtained(creds);
kerberos_state = cli_credentials_get_kerberos_state(creds);
assert_int_equal(kerberos_state_obtained, CRED_SPECIFIED);
assert_int_equal(kerberos_state, CRED_USE_KERBEROS_REQUIRED);
}
......
......@@ -4,7 +4,7 @@ bld.SAMBA_LIBRARY('samba-credentials',
source='credentials.c',
public_headers='credentials.h',
pc_files='samba-credentials.pc',
deps='LIBCRYPTO samba-errors events LIBCLI_AUTH samba-security CREDENTIALS_SECRETS CREDENTIALS_KRB5',
deps='LIBCRYPTO samba-errors events LIBCLI_AUTH samba-security CREDENTIALS_SECRETS CREDENTIALS_KRB5 CREDENTIALS_GMSA',
vnum='1.0.0'
)
......@@ -14,6 +14,11 @@ bld.SAMBA_SUBSYSTEM('CREDENTIALS_KRB5',
public_deps='com_err authkrb5',
)
bld.SAMBA_SUBSYSTEM('CREDENTIALS_GMSA',
source='credentials_gmsa.c',
deps='samba-credentials CREDENTIALS_NTLM NDR_GMSA ldb gkdi',
)
bld.SAMBA_SUBSYSTEM('CREDENTIALS_SECRETS',
source='credentials_secrets.c',
deps='CREDENTIALS_KRB5 CREDENTIALS_NTLM ldb SECRETS samdb-common dbwrap',
......
......@@ -854,3 +854,66 @@ _PUBLIC_ const char *gensec_get_target_principal(struct gensec_security *gensec_
return NULL;
}
static int gensec_channel_bindings_destructor(struct gensec_channel_bindings *cb)
{
data_blob_clear_free(&cb->initiator_address);
data_blob_clear_free(&cb->acceptor_address);
data_blob_clear_free(&cb->application_data);
*cb = (struct gensec_channel_bindings) { .initiator_addrtype = 0, };
return 0;
}
_PUBLIC_ NTSTATUS gensec_set_channel_bindings(struct gensec_security *gensec_security,
uint32_t initiator_addrtype,
const DATA_BLOB *initiator_address,
uint32_t acceptor_addrtype,
const DATA_BLOB *acceptor_address,
const DATA_BLOB *application_data)
{
struct gensec_channel_bindings *cb = NULL;
if (gensec_security->subcontext) {
return NT_STATUS_INTERNAL_ERROR;
}
if (gensec_security->channel_bindings != NULL) {
return NT_STATUS_ALREADY_REGISTERED;
}
cb = talloc_zero(gensec_security, struct gensec_channel_bindings);
if (cb == NULL) {
return NT_STATUS_NO_MEMORY;
}
talloc_set_destructor(cb, gensec_channel_bindings_destructor);
cb->initiator_addrtype = initiator_addrtype;
if (initiator_address != NULL) {
cb->initiator_address = data_blob_dup_talloc(cb,
*initiator_address);
if (cb->initiator_address.length != initiator_address->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
cb->acceptor_addrtype = acceptor_addrtype;
if (acceptor_address != NULL) {
cb->acceptor_address = data_blob_dup_talloc(cb,
*acceptor_address);
if (cb->acceptor_address.length != acceptor_address->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
if (application_data != NULL) {
cb->application_data = data_blob_dup_talloc(cb,
*application_data);
if (cb->application_data.length != application_data->length) {
TALLOC_FREE(cb);
return NT_STATUS_NO_MEMORY;
}
}
gensec_security->channel_bindings = cb;
return NT_STATUS_OK;
}
......@@ -25,6 +25,7 @@
#include "../lib/util/data_blob.h"
#include "libcli/util/ntstatus.h"
#include "lib/util/time.h"
#define GENSEC_SASL_NAME_NTLMSSP "NTLM"
......@@ -70,6 +71,7 @@ struct gensec_target {
#define GENSEC_FEATURE_NO_AUTHZ_LOG 0x00000800
#define GENSEC_FEATURE_SMB_TRANSPORT 0x00001000
#define GENSEC_FEATURE_LDAPS_TRANSPORT 0x00002000
#define GENSEC_FEATURE_CB_OPTIONAL 0x00004000
#define GENSEC_EXPIRE_TIME_INFINITY (NTTIME)0x8000000000000000LL
......@@ -300,8 +302,6 @@ NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
const DATA_BLOB *in,
DATA_BLOB *out);
bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security);
NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
const char *sasl_name);
const char **gensec_security_sasl_names(struct gensec_security *gensec_security,
......@@ -313,6 +313,13 @@ bool gensec_setting_bool(struct gensec_settings *settings, const char *mechanism
NTSTATUS gensec_set_target_principal(struct gensec_security *gensec_security, const char *principal);
const char *gensec_get_target_principal(struct gensec_security *gensec_security);
NTSTATUS gensec_set_channel_bindings(struct gensec_security *gensec_security,
uint32_t initiator_addrtype,
const DATA_BLOB *initiator_address,
uint32_t acceptor_addrtype,
const DATA_BLOB *acceptor_address,
const DATA_BLOB *application_data);
NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
struct gensec_security *gensec_security,
struct smb_krb5_context *smb_krb5_context,
......
......@@ -95,6 +95,23 @@ struct gensec_security_ops_wrapper {
const char *oid;
};
/*
* typedef struct gss_channel_bindings_struct {
* OM_uint32 initiator_addrtype;
* gss_buffer_desc initiator_address;
* OM_uint32 acceptor_addrtype;
* gss_buffer_desc acceptor_address;
* gss_buffer_desc application_data;
* } *gss_channel_bindings_t;
*/
struct gensec_channel_bindings {
uint32_t initiator_addrtype;
DATA_BLOB initiator_address;
uint32_t acceptor_addrtype;
DATA_BLOB acceptor_address;
DATA_BLOB application_data;
};
struct gensec_security {
const struct gensec_security_ops *ops;
void *private_data;
......@@ -106,6 +123,7 @@ struct gensec_security {
uint32_t max_update_size;
uint8_t dcerpc_auth_level;
struct tsocket_address *local_addr, *remote_addr;
struct gensec_channel_bindings *channel_bindings;
struct gensec_settings *settings;
/* When we are a server, this may be filled in to provide an
......@@ -180,4 +198,8 @@ NTSTATUS gensec_child_session_info(struct gensec_security *gensec_security,
NTTIME gensec_child_expire_time(struct gensec_security *gensec_security);
const char *gensec_child_final_auth_type(struct gensec_security *gensec_security);
char *gensec_get_unparsed_target_principal(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx);
NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security);
#endif /* __GENSEC_H__ */