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 (1972)
Showing
with 1332 additions and 939 deletions
......@@ -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: b078783e082ead539940faaa644567bf4ed67f67
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
......@@ -185,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
......@@ -268,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
......@@ -322,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
......@@ -392,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
......@@ -663,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,8 +26,8 @@ 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_RELEASE=4
SAMBA_VERSION_MINOR=21
SAMBA_VERSION_RELEASE=0
########################################################
# If a official release has a serious bug #
......
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"
......@@ -175,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.
......@@ -272,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
......@@ -457,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.
*
......@@ -511,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),
......@@ -646,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);
......@@ -670,6 +765,7 @@ return_hash:
if (nt_hash == NULL) {
return NULL;
}
talloc_keep_secret(nt_hash);
*nt_hash = *cred->nt_hash;
......@@ -695,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;
......@@ -707,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,7 +271,7 @@ 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);
......@@ -281,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
......@@ -349,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
*/
......@@ -367,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__ */
......@@ -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)
......
......@@ -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',
......
......@@ -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"
......@@ -301,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,
......
......@@ -198,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__ */
......@@ -43,7 +43,8 @@
static const struct gensec_security_ops **generic_security_ops;
static int gensec_num_backends;
bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct gensec_security *security)
static bool gensec_security_ops_enabled(const struct gensec_security_ops *ops,
struct gensec_security *security)
{
bool ok = lpcfg_parm_bool(security->settings->lp_ctx,
NULL,
......@@ -79,72 +80,66 @@ bool gensec_security_ops_enabled(const struct gensec_security_ops *ops, struct g
* more complex.
*/
static const struct gensec_security_ops **gensec_use_kerberos_mechs(
TALLOC_CTX *mem_ctx,
const struct gensec_security_ops * const *old_gensec_list,
enum credentials_use_kerberos use_kerberos,
bool keep_schannel)
static bool gensec_offer_mech(struct gensec_security *gensec_security,
const struct gensec_security_ops *mech)
{
const struct gensec_security_ops **new_gensec_list;
int i, j, num_mechs_in;
struct cli_credentials *creds = NULL;
enum credentials_use_kerberos use_kerberos;
bool offer;
for (num_mechs_in=0; old_gensec_list && old_gensec_list[num_mechs_in]; num_mechs_in++) {
/* noop */
}
/*
* We want to always offer SPNEGO and other backends
*/
offer = mech->glue;
new_gensec_list = talloc_array(mem_ctx,
const struct gensec_security_ops *,
num_mechs_in + 1);
if (!new_gensec_list) {
return NULL;
if (gensec_security != NULL) {
creds = gensec_get_credentials(gensec_security);
}
j = 0;
for (i=0; old_gensec_list && old_gensec_list[i]; i++) {
bool keep = false;
if ((mech->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) && (creds != NULL))
{
if (cli_credentials_get_netlogon_creds(creds) != NULL) {
offer = true;
}
/*
* We want to keep SPNEGO and other backends
* Even if Kerberos is set to REQUIRED, offer the
* schannel auth mechanism so that machine accounts are
* able to authenticate via netlogon.
*/
keep = old_gensec_list[i]->glue;
if (old_gensec_list[i]->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
keep = keep_schannel;
if (gensec_security->gensec_role == GENSEC_SERVER) {
offer = true;
}
}
switch (use_kerberos) {
case CRED_USE_KERBEROS_DESIRED:
keep = true;
break;
case CRED_USE_KERBEROS_DISABLED:
if (old_gensec_list[i]->kerberos == false) {
keep = true;
}
break;
case CRED_USE_KERBEROS_REQUIRED:
if (old_gensec_list[i]->kerberos == true) {
keep = true;
}
use_kerberos = CRED_USE_KERBEROS_DESIRED;
if (creds != NULL) {
use_kerberos = cli_credentials_get_kerberos_state(creds);
}
break;
default:
/* Can't happen or invalid parameter */
return NULL;
switch (use_kerberos) {
case CRED_USE_KERBEROS_DESIRED:
offer = true;
break;
case CRED_USE_KERBEROS_DISABLED:
if (!mech->kerberos) {
offer = true;
}
if (!keep) {
continue;
break;
case CRED_USE_KERBEROS_REQUIRED:
if (mech->kerberos) {
offer = true;
}
break;
default:
/* Can't happen or invalid parameter */
offer = false;
}
new_gensec_list[j] = old_gensec_list[i];
j++;
if (offer && (gensec_security != NULL)) {
offer = gensec_security_ops_enabled(mech, gensec_security);
}
new_gensec_list[j] = NULL;
return new_gensec_list;
return offer;
}
_PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
......@@ -153,159 +148,147 @@ _PUBLIC_ const struct gensec_security_ops **gensec_security_mechs(
{
const struct gensec_security_ops * const *backends =
generic_security_ops;
enum credentials_use_kerberos use_kerberos = CRED_USE_KERBEROS_DESIRED;
bool keep_schannel = false;
if (gensec_security != NULL) {
struct cli_credentials *creds = NULL;
creds = gensec_get_credentials(gensec_security);
if (creds != NULL) {
use_kerberos = cli_credentials_get_kerberos_state(creds);
if (cli_credentials_get_netlogon_creds(creds) != NULL) {
keep_schannel = true;
}
/*
* Even if Kerberos is set to REQUIRED, keep the
* schannel auth mechanism so that machine accounts are
* able to authenticate via netlogon.
*/
if (gensec_security->gensec_role == GENSEC_SERVER) {
keep_schannel = true;
}
}
const struct gensec_security_ops **result = NULL;
size_t i, j, num_backends;
if (gensec_security->settings->backends) {
backends = gensec_security->settings->backends;
}
if ((gensec_security != NULL) &&
(gensec_security->settings->backends != NULL)) {
backends = gensec_security->settings->backends;
}
return gensec_use_kerberos_mechs(mem_ctx, backends,
use_kerberos, keep_schannel);
if (backends == NULL) {
/* Just return the NULL terminator */
return talloc_zero(mem_ctx,
const struct gensec_security_ops *);
}
}
for (num_backends = 0; backends[num_backends]; num_backends++) {
/* noop */
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
struct gensec_security *gensec_security,
const char *oid_string)
{
int i, j;
const struct gensec_security_ops **backends;
const struct gensec_security_ops *backend;
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
result = talloc_array(
mem_ctx, const struct gensec_security_ops *, num_backends + 1);
if (result == NULL) {
return NULL;
}
backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i],
gensec_security))
continue;
if (backends[i]->oid) {
for (j=0; backends[i]->oid[j]; j++) {
if (backends[i]->oid[j] &&
(strcmp(backends[i]->oid[j], oid_string) == 0)) {
backend = backends[i];
talloc_free(mem_ctx);
return backend;
}
}
j = 0;
for (i = 0; backends[i]; i++) {
bool offer = gensec_offer_mech(gensec_security, backends[i]);
if (offer) {
result[j++] = backends[i];
}
}
talloc_free(mem_ctx);
return NULL;
result[j] = NULL;
return result;
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
struct gensec_security *gensec_security,
const char *sasl_name)
static const struct gensec_security_ops *gensec_security_by_fn(
struct gensec_security *gensec_security,
bool (*fn)(const struct gensec_security_ops *backend,
const void *private_data),
const void *private_data)
{
int i;
const struct gensec_security_ops **backends;
const struct gensec_security_ops *backend;
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
size_t i;
const struct gensec_security_ops **backends = NULL;
backends = gensec_security_mechs(gensec_security, gensec_security);
if (backends == NULL) {
return NULL;
}
backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i], gensec_security)) {
continue;
}
if (backends[i]->sasl_name
&& (strcmp(backends[i]->sasl_name, sasl_name) == 0)) {
backend = backends[i];
talloc_free(mem_ctx);
for (i = 0; backends[i] != NULL; i++) {
const struct gensec_security_ops *backend = backends[i];
bool ok;
ok = fn(backend, private_data);
if (ok) {
TALLOC_FREE(backends);
return backend;
}
}
talloc_free(mem_ctx);
TALLOC_FREE(backends);
return NULL;
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
struct gensec_security *gensec_security,
uint32_t auth_type)
static bool by_oid_fn(const struct gensec_security_ops *backend,
const void *private_data)
{
const char *oid = private_data;
int i;
const struct gensec_security_ops **backends;
const struct gensec_security_ops *backend;
TALLOC_CTX *mem_ctx;
if (auth_type == DCERPC_AUTH_TYPE_NONE) {
return NULL;
if (backend->oid == NULL) {
return false;
}
mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
return NULL;
}
backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i], gensec_security)) {
continue;
}
if (backends[i]->auth_type == auth_type) {
backend = backends[i];
talloc_free(mem_ctx);
return backend;
for (i = 0; backend->oid[i] != NULL; i++) {
if (strcmp(backend->oid[i], oid) == 0) {
return true;
}
}
talloc_free(mem_ctx);
return false;
}
return NULL;
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_oid(
struct gensec_security *gensec_security,
const char *oid_string)
{
return gensec_security_by_fn(gensec_security, by_oid_fn, oid_string);
}
const struct gensec_security_ops *gensec_security_by_name(struct gensec_security *gensec_security,
const char *name)
static bool by_sasl_name_fn(const struct gensec_security_ops *backend,
const void *private_data)
{
int i;
const struct gensec_security_ops **backends;
const struct gensec_security_ops *backend;
TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
if (!mem_ctx) {
const char *sasl_name = private_data;
if (backend->sasl_name == NULL) {
return false;
}
return (strcmp(backend->sasl_name, sasl_name) == 0);
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_sasl_name(
struct gensec_security *gensec_security,
const char *sasl_name)
{
return gensec_security_by_fn(
gensec_security, by_sasl_name_fn, sasl_name);
}
static bool by_auth_type_fn(const struct gensec_security_ops *backend,
const void *private_data)
{
uint32_t auth_type = *((const uint32_t *)private_data);
return (backend->auth_type == auth_type);
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_auth_type(
struct gensec_security *gensec_security,
uint32_t auth_type)
{
if (auth_type == DCERPC_AUTH_TYPE_NONE) {
return NULL;
}
backends = gensec_security_mechs(gensec_security, mem_ctx);
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i], gensec_security))
continue;
if (backends[i]->name
&& (strcmp(backends[i]->name, name) == 0)) {
backend = backends[i];
talloc_free(mem_ctx);
return backend;
}
return gensec_security_by_fn(
gensec_security, by_auth_type_fn, &auth_type);
}
static bool by_name_fn(const struct gensec_security_ops *backend,
const void *private_data)
{
const char *name = private_data;
if (backend->name == NULL) {
return false;
}
talloc_free(mem_ctx);
return NULL;
return (strcmp(backend->name, name) == 0);
}
_PUBLIC_ const struct gensec_security_ops *gensec_security_by_name(
struct gensec_security *gensec_security,
const char *name)
{
return gensec_security_by_fn(gensec_security, by_name_fn, name);
}
static const char **gensec_security_sasl_names_from_ops(
......@@ -334,11 +317,6 @@ static const char **gensec_security_sasl_names_from_ops(
}
if (gensec_security != NULL) {
if (!gensec_security_ops_enabled(ops[i],
gensec_security)) {
continue;
}
role = gensec_security->gensec_role;
}
......@@ -428,9 +406,6 @@ static const struct gensec_security_ops **gensec_security_by_sasl_list(
/* Find backends in our preferred order, by walking our list,
* then looking in the supplied list */
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i], gensec_security))
continue;
for (sasl_idx = 0; sasl_names[sasl_idx]; sasl_idx++) {
if (!backends[i]->sasl_name ||
!(strcmp(backends[i]->sasl_name,
......@@ -500,9 +475,6 @@ _PUBLIC_ const struct gensec_security_ops_wrapper *gensec_security_by_oid_list(
/* Find backends in our preferred order, by walking our list,
* then looking in the supplied list */
for (i=0; backends && backends[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(backends[i], gensec_security))
continue;
if (!backends[i]->oid) {
continue;
}
......@@ -570,10 +542,6 @@ static const char **gensec_security_oids_from_ops(
}
for (i=0; ops && ops[i]; i++) {
if (gensec_security != NULL &&
!gensec_security_ops_enabled(ops[i], gensec_security)) {
continue;
}
if (!ops[i]->oid) {
continue;
}
......
......@@ -23,10 +23,14 @@
#include "includes.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h"
#include "auth/credentials/credentials.h"
#include "auth/common_auth.h"
#include "../lib/util/asn1.h"
#include "param/param.h"
#include "libds/common/roles.h"
#include "lib/util/util_net.h"
#undef strcasecmp
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
......@@ -336,3 +340,80 @@ const char *gensec_child_final_auth_type(struct gensec_security *gensec_security
return gensec_final_auth_type(gensec_security->child_security);
}
char *gensec_get_unparsed_target_principal(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx)
{
const char *target_principal = gensec_get_target_principal(gensec_security);
const char *service = gensec_get_target_service(gensec_security);
const char *hostname = gensec_get_target_hostname(gensec_security);
if (target_principal != NULL) {
return talloc_strdup(mem_ctx, target_principal);
} else if (service != NULL && hostname != NULL) {
return talloc_asprintf(mem_ctx, "%s/%s", service, hostname);
} else if (hostname != NULL) {
return talloc_strdup(mem_ctx, target_principal);
}
return NULL;
}
NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security)
{
struct cli_credentials *creds = gensec_get_credentials(gensec_security);
bool auth_requested = cli_credentials_authentication_requested(creds);
enum credentials_use_kerberos krb5_state =
cli_credentials_get_kerberos_state(creds);
char *user_principal = NULL;
const char *client_realm = cli_credentials_get_realm(creds);
const char *target_principal = gensec_get_target_principal(gensec_security);
const char *hostname = gensec_get_target_hostname(gensec_security);
if (!auth_requested) {
return NT_STATUS_INVALID_PARAMETER;
}
if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
return NT_STATUS_INVALID_PARAMETER;
}
errno = 0;
user_principal = cli_credentials_get_principal(creds, gensec_security);
if (errno != 0) {
TALLOC_FREE(user_principal);
return NT_STATUS_NO_MEMORY;
}
if (user_principal == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
TALLOC_FREE(user_principal);
if (target_principal != NULL) {
return NT_STATUS_OK;
}
if (client_realm == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
if (hostname == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
if (strcasecmp(hostname, "localhost") == 0) {
return NT_STATUS_INVALID_PARAMETER;
}
#define STAR_SMBSERVER "*SMBSERVER"
if (strcmp(hostname, STAR_SMBSERVER) == 0) {
return NT_STATUS_INVALID_PARAMETER;
}
if (is_ipaddress(hostname)) {
return NT_STATUS_INVALID_PARAMETER;
}
return NT_STATUS_OK;
}
/*
/*
Unix SMB/CIFS implementation.
RFC2478 Compliant SPNEGO implementation
......@@ -66,11 +66,11 @@ struct spnego_neg_ops {
const char *name;
/*
* The start hook does the initial processing on the incoming packet and
* may starts the first possible subcontext. It indicates that
* may start the first possible subcontext. It indicates that
* gensec_update() is required on the subcontext by returning
* NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
* 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
* caller should treat 'in_next' as const and don't attempt to free the
* caller should treat 'in_next' as const and not attempt to free the
* content. NT_STATUS_OK indicates the finish hook should be invoked
* directly within the need of gensec_update() on the subcontext.
* Every other error indicates an error that's returned to the caller.
......@@ -88,7 +88,7 @@ struct spnego_neg_ops {
* gensec_update() is required on the subcontext by returning
* NT_STATUS_MORE_PROCESSING_REQUIRED and return something useful in
* 'in_next'. Note that 'in_mem_ctx' is just passed as a hint, the
* caller should treat 'in_next' as const and don't attempt to free the
* caller should treat 'in_next' as const and not attempt to free the
* content. NT_STATUS_OK indicates the finish hook should be invoked
* directly within the need of gensec_update() on the subcontext.
* Every other error indicates an error that's returned to the caller.
......@@ -221,14 +221,14 @@ static NTSTATUS gensec_spnego_server_start(struct gensec_security *gensec_securi
return NT_STATUS_OK;
}
/** Fallback to another GENSEC mechanism, based on magic strings
/** Fallback to another GENSEC mechanism, based on magic strings
*
* This is the 'fallback' case, where we don't get SPNEGO, and have to
* try all the other options (and hope they all have a magic string
* they check)
*/
static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security,
static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec_security,
struct spnego_state *spnego_state,
TALLOC_CTX *mem_ctx,
const DATA_BLOB in)
......@@ -242,12 +242,6 @@ static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec
bool is_spnego;
NTSTATUS nt_status;
if (gensec_security != NULL &&
!gensec_security_ops_enabled(all_ops[i], gensec_security))
{
continue;
}
if (!all_ops[i]->oid) {
continue;
}
......@@ -273,8 +267,8 @@ static NTSTATUS gensec_spnego_server_try_fallback(struct gensec_security *gensec
spnego_state->state_position = SPNEGO_FALLBACK;
nt_status = gensec_subcontext_start(spnego_state,
gensec_security,
nt_status = gensec_subcontext_start(spnego_state,
gensec_security,
&spnego_state->sub_sec_security);
if (!NT_STATUS_IS_OK(nt_status)) {
......@@ -503,18 +497,8 @@ static NTSTATUS gensec_spnego_client_negTokenInit_start(
TALLOC_CTX *in_mem_ctx,
DATA_BLOB *in_next)
{
const char *tp = NULL;
/* The server offers a list of mechanisms */
tp = spnego_in->negTokenInit.targetPrincipal;
if (tp != NULL && strcmp(tp, ADS_IGNORE_PRINCIPAL) != 0) {
DBG_INFO("Server claims it's principal name is %s\n", tp);
if (lpcfg_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
gensec_set_target_principal(gensec_security, tp);
}
}
n->mech_idx = 0;
/* Do not use server mech list as it isn't protected. Instead, get all
......@@ -1114,7 +1098,7 @@ static const struct spnego_neg_ops gensec_spnego_client_negTokenTarg_ops = {
.finish_fn = gensec_spnego_client_negTokenTarg_finish,
};
/** create a server negTokenTarg
/** create a server negTokenTarg
*
* This is the case, where the client is the first one who sends data
*/
......@@ -1126,15 +1110,14 @@ static NTSTATUS gensec_spnego_server_response(struct spnego_state *spnego_state,
DATA_BLOB mech_list_mic,
DATA_BLOB *out)
{
struct spnego_data spnego_out;
/* compose reply */
spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
spnego_out.negTokenTarg.responseToken = unwrapped_out;
spnego_out.negTokenTarg.mechListMIC = mech_list_mic;
spnego_out.negTokenTarg.supportedMech = NULL;
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
struct spnego_data spnego_out = {
.type = SPNEGO_NEG_TOKEN_TARG,
.negTokenTarg.responseToken = unwrapped_out,
.negTokenTarg.mechListMIC = mech_list_mic,
.negTokenTarg.supportedMech = NULL,
};
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
spnego_out.negTokenTarg.supportedMech = spnego_state->neg_oid;
if (spnego_state->mic_requested) {
spnego_out.negTokenTarg.negResult = SPNEGO_REQUEST_MIC;
......@@ -2201,9 +2184,9 @@ static NTSTATUS gensec_spnego_update_recv(struct tevent_req *req,
return status;
}
static const char *gensec_spnego_oids[] = {
static const char *gensec_spnego_oids[] = {
GENSEC_OID_SPNEGO,
NULL
NULL
};
static const struct gensec_security_ops gensec_spnego_security_ops = {
......
......@@ -68,7 +68,7 @@ NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
session_info_flags |= AUTH_SESSION_INFO_NTLM;
if (gensec_security->auth_context && gensec_security->auth_context->generate_session_info) {
nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx,
nt_status = gensec_security->auth_context->generate_session_info(gensec_security->auth_context, mem_ctx,
gensec_ntlmssp->server_returned_info,
gensec_ntlmssp->ntlmssp_state->user,
session_info_flags,
......@@ -201,22 +201,7 @@ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
if (gensec_security->settings->server_dns_name) {
dns_name = gensec_security->settings->server_dns_name;
} else {
const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx);
char *lower_netbiosname;
lower_netbiosname = strlower_talloc(ntlmssp_state, netbios_name);
NT_STATUS_HAVE_NO_MEMORY(lower_netbiosname);
/* Find out the DNS host name */
if (dnsdomain && dnsdomain[0] != '\0') {
dns_name = talloc_asprintf(ntlmssp_state, "%s.%s",
lower_netbiosname,
dnsdomain);
talloc_free(lower_netbiosname);
NT_STATUS_HAVE_NO_MEMORY(dns_name);
} else {
dns_name = lower_netbiosname;
}
dns_name = lpcfg_dns_hostname(gensec_security->settings->lp_ctx);
}
if (gensec_security->settings->server_dns_domain) {
......