From 561d834123a2a8a96954f7cca556f8838ab38b72 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 7 Oct 2011 17:20:33 +1100 Subject: auth: move credentials layer to the top level This will allow gensec_start.c to move to the top level. This does not change what code uses the cli_credentials code, but allows the gensec code to be more broadly. Andrew Bartlett --- auth/credentials/credentials.c | 1002 ++++++++++++++++++++++ auth/credentials/credentials.h | 300 +++++++ auth/credentials/credentials_krb5.c | 903 +++++++++++++++++++ auth/credentials/credentials_krb5.h | 57 ++ auth/credentials/credentials_ntlm.c | 256 ++++++ auth/credentials/credentials_secrets.c | 293 +++++++ auth/credentials/pycredentials.c | 492 +++++++++++ auth/credentials/pycredentials.h | 36 + auth/credentials/samba-credentials.pc.in | 11 + auth/credentials/tests/bind.py | 154 ++++ auth/credentials/tests/simple.c | 119 +++ auth/credentials/wscript_build | 32 + auth/wscript_build | 1 + source3/auth/auth_samba4.c | 2 +- source4/auth/credentials/credentials.c | 1002 ---------------------- source4/auth/credentials/credentials.h | 300 ------- source4/auth/credentials/credentials_krb5.c | 903 ------------------- source4/auth/credentials/credentials_krb5.h | 57 -- source4/auth/credentials/credentials_ntlm.c | 256 ------ source4/auth/credentials/credentials_secrets.c | 293 ------- source4/auth/credentials/pycredentials.c | 492 ----------- source4/auth/credentials/pycredentials.h | 36 - source4/auth/credentials/samba-credentials.pc.in | 11 - source4/auth/credentials/tests/bind.py | 154 ---- source4/auth/credentials/tests/simple.c | 119 --- source4/auth/credentials/wscript_build | 32 - source4/auth/gensec/gensec_start.c | 4 + source4/auth/wscript_build | 1 - source4/selftest/tests.py | 2 +- source4/torture/local/wscript_build | 2 +- 30 files changed, 3663 insertions(+), 3659 deletions(-) create mode 100644 auth/credentials/credentials.c create mode 100644 auth/credentials/credentials.h create mode 100644 auth/credentials/credentials_krb5.c create mode 100644 auth/credentials/credentials_krb5.h create mode 100644 auth/credentials/credentials_ntlm.c create mode 100644 auth/credentials/credentials_secrets.c create mode 100644 auth/credentials/pycredentials.c create mode 100644 auth/credentials/pycredentials.h create mode 100644 auth/credentials/samba-credentials.pc.in create mode 100755 auth/credentials/tests/bind.py create mode 100644 auth/credentials/tests/simple.c create mode 100644 auth/credentials/wscript_build delete mode 100644 source4/auth/credentials/credentials.c delete mode 100644 source4/auth/credentials/credentials.h delete mode 100644 source4/auth/credentials/credentials_krb5.c delete mode 100644 source4/auth/credentials/credentials_krb5.h delete mode 100644 source4/auth/credentials/credentials_ntlm.c delete mode 100644 source4/auth/credentials/credentials_secrets.c delete mode 100644 source4/auth/credentials/pycredentials.c delete mode 100644 source4/auth/credentials/pycredentials.h delete mode 100644 source4/auth/credentials/samba-credentials.pc.in delete mode 100755 source4/auth/credentials/tests/bind.py delete mode 100644 source4/auth/credentials/tests/simple.c delete mode 100644 source4/auth/credentials/wscript_build diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c new file mode 100644 index 0000000000..83e90344bf --- /dev/null +++ b/auth/credentials/credentials.c @@ -0,0 +1,1002 @@ +/* + Unix SMB/CIFS implementation. + + User credentials handling + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Tim Potter 2001 + Copyright (C) Andrew Bartlett 2005 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ +#include "auth/credentials/credentials.h" +#include "auth/credentials/credentials_proto.h" +#include "libcli/auth/libcli_auth.h" +#include "lib/events/events.h" +#include "param/param.h" +#include "system/filesys.h" + +/** + * Create a new credentials structure + * @param mem_ctx TALLOC_CTX parent for credentials structure + */ +_PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) +{ + struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials); + if (cred == NULL) { + return cred; + } + + cred->workstation_obtained = CRED_UNINITIALISED; + cred->username_obtained = CRED_UNINITIALISED; + cred->password_obtained = CRED_UNINITIALISED; + cred->domain_obtained = CRED_UNINITIALISED; + cred->realm_obtained = CRED_UNINITIALISED; + cred->ccache_obtained = CRED_UNINITIALISED; + cred->client_gss_creds_obtained = CRED_UNINITIALISED; + cred->principal_obtained = CRED_UNINITIALISED; + cred->keytab_obtained = CRED_UNINITIALISED; + cred->server_gss_creds_obtained = CRED_UNINITIALISED; + + cred->ccache_threshold = CRED_UNINITIALISED; + cred->client_gss_creds_threshold = CRED_UNINITIALISED; + + cred->workstation = NULL; + cred->username = NULL; + cred->password = NULL; + cred->old_password = NULL; + cred->domain = NULL; + cred->realm = NULL; + cred->principal = NULL; + cred->salt_principal = NULL; + cred->impersonate_principal = NULL; + cred->self_service = NULL; + cred->target_service = NULL; + + cred->bind_dn = NULL; + + cred->nt_hash = NULL; + + cred->lm_response.data = NULL; + cred->lm_response.length = 0; + cred->nt_response.data = NULL; + cred->nt_response.length = 0; + + cred->ccache = NULL; + cred->client_gss_creds = NULL; + cred->keytab = NULL; + cred->server_gss_creds = NULL; + + cred->workstation_cb = NULL; + cred->password_cb = NULL; + cred->username_cb = NULL; + cred->domain_cb = NULL; + cred->realm_cb = NULL; + cred->principal_cb = NULL; + + cred->priv_data = NULL; + + cred->netlogon_creds = NULL; + cred->secure_channel_type = SEC_CHAN_NULL; + + cred->kvno = 0; + + cred->password_last_changed_time = 0; + + cred->smb_krb5_context = NULL; + + cred->machine_account_pending = false; + cred->machine_account_pending_lp_ctx = NULL; + + cred->machine_account = false; + + cred->tries = 3; + + cred->callback_running = false; + + cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS); + cli_credentials_set_gensec_features(cred, 0); + cli_credentials_set_krb_forwardable(cred, CRED_AUTO_KRB_FORWARDABLE); + + return cred; +} + +/** + * Create a new anonymous credential + * @param mem_ctx TALLOC_CTX parent for credentials structure + */ +_PUBLIC_ struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx) +{ + struct cli_credentials *anon_credentials; + + anon_credentials = cli_credentials_init(mem_ctx); + cli_credentials_set_anonymous(anon_credentials); + + return anon_credentials; +} + +_PUBLIC_ void cli_credentials_set_kerberos_state(struct cli_credentials *creds, + enum credentials_use_kerberos use_kerberos) +{ + creds->use_kerberos = use_kerberos; +} + +_PUBLIC_ void cli_credentials_set_krb_forwardable(struct cli_credentials *creds, + enum credentials_krb_forwardable krb_forwardable) +{ + creds->krb_forwardable = krb_forwardable; +} + +_PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds) +{ + return creds->use_kerberos; +} + +_PUBLIC_ enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds) +{ + return creds->krb_forwardable; +} + +_PUBLIC_ void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features) +{ + creds->gensec_features = gensec_features; +} + +_PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds) +{ + return creds->gensec_features; +} + + +/** + * Obtain the username for this credentials context. + * @param cred credentials context + * @retval The username set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->username_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->username = cred->username_cb(cred); + cred->callback_running = false; + cred->username_obtained = CRED_SPECIFIED; + cli_credentials_invalidate_ccache(cred, cred->username_obtained); + } + + return cred->username; +} + +_PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, + const char *val, enum credentials_obtained obtained) +{ + if (obtained >= cred->username_obtained) { + cred->username = talloc_strdup(cred, val); + cred->username_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->username_obtained); + return true; + } + + return false; +} + +bool cli_credentials_set_username_callback(struct cli_credentials *cred, + const char *(*username_cb) (struct cli_credentials *)) +{ + if (cred->username_obtained < CRED_CALLBACK) { + cred->username_cb = username_cb; + cred->username_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + +_PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, + const char *bind_dn) +{ + cred->bind_dn = talloc_strdup(cred, bind_dn); + return true; +} + +/** + * Obtain the BIND DN for this credentials context. + * @param cred credentials context + * @retval The username set on this context. + * @note Return value will be NULL if not specified explictly + */ +_PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred) +{ + return cred->bind_dn; +} + + +/** + * Obtain the client principal for this credentials context. + * @param cred credentials context + * @retval The username set on this context. + * @note Return value will never be NULL except by programmer error. + */ +const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->principal_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->principal = cred->principal_cb(cred); + cred->callback_running = false; + cred->principal_obtained = CRED_SPECIFIED; + cli_credentials_invalidate_ccache(cred, cred->principal_obtained); + } + + if (cred->principal_obtained < cred->username_obtained + || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) { + if (cred->domain_obtained > cred->realm_obtained) { + *obtained = MIN(cred->domain_obtained, cred->username_obtained); + return talloc_asprintf(mem_ctx, "%s@%s", + cli_credentials_get_username(cred), + cli_credentials_get_domain(cred)); + } else { + *obtained = MIN(cred->domain_obtained, cred->username_obtained); + return talloc_asprintf(mem_ctx, "%s@%s", + cli_credentials_get_username(cred), + cli_credentials_get_realm(cred)); + } + } + *obtained = cred->principal_obtained; + return talloc_reference(mem_ctx, cred->principal); +} + +/** + * Obtain the client principal for this credentials context. + * @param cred credentials context + * @retval The username set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx) +{ + enum credentials_obtained obtained; + return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained); +} + +bool cli_credentials_set_principal(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->principal_obtained) { + cred->principal = talloc_strdup(cred, val); + cred->principal_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->principal_obtained); + return true; + } + + return false; +} + +/* Set a callback to get the principal. This could be a popup dialog, + * a terminal prompt or similar. */ +bool cli_credentials_set_principal_callback(struct cli_credentials *cred, + const char *(*principal_cb) (struct cli_credentials *)) +{ + if (cred->principal_obtained < CRED_CALLBACK) { + cred->principal_cb = principal_cb; + cred->principal_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + +/* Some of our tools are 'anonymous by default'. This is a single + * function to determine if authentication has been explicitly + * requested */ + +_PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) +{ + if (cred->bind_dn) { + return true; + } + + if (cli_credentials_is_anonymous(cred)){ + return false; + } + + if (cred->principal_obtained >= CRED_SPECIFIED) { + return true; + } + if (cred->username_obtained >= CRED_SPECIFIED) { + return true; + } + + if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { + return true; + } + + return false; +} + +/** + * Obtain the password for this credentials context. + * @param cred credentials context + * @retval If set, the cleartext password, otherwise NULL + */ +_PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->password_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->password = cred->password_cb(cred); + cred->callback_running = false; + cred->password_obtained = CRED_CALLBACK_RESULT; + cli_credentials_invalidate_ccache(cred, cred->password_obtained); + } + + return cred->password; +} + +/* Set a password on the credentials context, including an indication + * of 'how' the password was obtained */ + +_PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cred->password = talloc_strdup(cred, val); + cred->password_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->password_obtained); + + cred->nt_hash = NULL; + cred->lm_response = data_blob(NULL, 0); + cred->nt_response = data_blob(NULL, 0); + return true; + } + + return false; +} + +_PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred, + const char *(*password_cb) (struct cli_credentials *)) +{ + if (cred->password_obtained < CRED_CALLBACK) { + cred->password_cb = password_cb; + cred->password_obtained = CRED_CALLBACK; + cli_credentials_invalidate_ccache(cred, cred->password_obtained); + return true; + } + + return false; +} + +/** + * Obtain the 'old' password for this credentials context (used for join accounts). + * @param cred credentials context + * @retval If set, the cleartext password, otherwise NULL + */ +const char *cli_credentials_get_old_password(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + return cred->old_password; +} + +bool cli_credentials_set_old_password(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + cred->old_password = talloc_strdup(cred, val); + return true; +} + +/** + * Obtain the password, in the form MD4(unicode(password)) for this credentials context. + * + * Sometimes we only have this much of the password, while the rest of + * the time this call avoids calling E_md4hash themselves. + * + * @param cred credentials context + * @retval If set, the cleartext password, otherwise NULL + */ +_PUBLIC_ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, + TALLOC_CTX *mem_ctx) +{ + const char *password = cli_credentials_get_password(cred); + + if (password) { + struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); + if (!nt_hash) { + return NULL; + } + + E_md4hash(password, nt_hash->hash); + + return nt_hash; + } else { + return cred->nt_hash; + } +} + +/** + * Obtain the 'short' or 'NetBIOS' domain for this credentials context. + * @param cred credentials context + * @retval The domain set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->domain_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->domain = cred->domain_cb(cred); + cred->callback_running = false; + cred->domain_obtained = CRED_SPECIFIED; + cli_credentials_invalidate_ccache(cred, cred->domain_obtained); + } + + return cred->domain; +} + + +_PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->domain_obtained) { + /* it is important that the domain be in upper case, + * particularly for the sensitive NTLMv2 + * calculations */ + cred->domain = strupper_talloc(cred, val); + cred->domain_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->domain_obtained); + return true; + } + + return false; +} + +bool cli_credentials_set_domain_callback(struct cli_credentials *cred, + const char *(*domain_cb) (struct cli_credentials *)) +{ + if (cred->domain_obtained < CRED_CALLBACK) { + cred->domain_cb = domain_cb; + cred->domain_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + +/** + * Obtain the Kerberos realm for this credentials context. + * @param cred credentials context + * @retval The realm set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->realm_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->realm = cred->realm_cb(cred); + cred->callback_running = false; + cred->realm_obtained = CRED_SPECIFIED; + cli_credentials_invalidate_ccache(cred, cred->realm_obtained); + } + + return cred->realm; +} + +/** + * Set the realm for this credentials context, and force it to + * uppercase for the sainity of our local kerberos libraries + */ +_PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->realm_obtained) { + cred->realm = strupper_talloc(cred, val); + cred->realm_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->realm_obtained); + return true; + } + + return false; +} + +bool cli_credentials_set_realm_callback(struct cli_credentials *cred, + const char *(*realm_cb) (struct cli_credentials *)) +{ + if (cred->realm_obtained < CRED_CALLBACK) { + cred->realm_cb = realm_cb; + cred->realm_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + +/** + * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context. + * + * @param cred credentials context + * @retval The workstation name set on this context. + * @note Return value will never be NULL except by programmer error. + */ +_PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred) +{ + if (cred->workstation_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->workstation = cred->workstation_cb(cred); + cred->callback_running = false; + cred->workstation_obtained = CRED_SPECIFIED; + } + + return cred->workstation; +} + +_PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->workstation_obtained) { + cred->workstation = talloc_strdup(cred, val); + cred->workstation_obtained = obtained; + return true; + } + + return false; +} + +bool cli_credentials_set_workstation_callback(struct cli_credentials *cred, + const char *(*workstation_cb) (struct cli_credentials *)) +{ + if (cred->workstation_obtained < CRED_CALLBACK) { + cred->workstation_cb = workstation_cb; + cred->workstation_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + +/** + * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields + * + * The format accepted is [domain\\]user[%password] or user[@realm][%password] + * + * @param credentials Credentials structure on which to set the password + * @param data the string containing the username, password etc + * @param obtained This enum describes how 'specified' this password is + */ + +_PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained) +{ + char *uname, *p; + + if (strcmp("%",data) == 0) { + cli_credentials_set_anonymous(credentials); + return; + } + + uname = talloc_strdup(credentials, data); + if ((p = strchr_m(uname,'%'))) { + *p = 0; + cli_credentials_set_password(credentials, p+1, obtained); + } + + if ((p = strchr_m(uname,'@'))) { + cli_credentials_set_principal(credentials, uname, obtained); + *p = 0; + cli_credentials_set_realm(credentials, p+1, obtained); + return; + } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) { + *p = 0; + cli_credentials_set_domain(credentials, uname, obtained); + uname = p+1; + } + cli_credentials_set_username(credentials, uname, obtained); +} + +/** + * Given a a credentials structure, print it as a string + * + * The format output is [domain\\]user[%password] or user[@realm][%password] + * + * @param credentials Credentials structure on which to set the password + * @param mem_ctx The memory context to place the result on + */ + +_PUBLIC_ const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx) +{ + const char *bind_dn = cli_credentials_get_bind_dn(credentials); + const char *domain; + const char *username; + const char *name; + + if (bind_dn) { + name = talloc_reference(mem_ctx, bind_dn); + } else { + cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain); + if (domain && domain[0]) { + name = talloc_asprintf(mem_ctx, "%s\\%s", + domain, username); + } else { + name = talloc_asprintf(mem_ctx, "%s", + username); + } + } + return name; +} + +/** + * Specifies default values for domain, workstation and realm + * from the smb.conf configuration file + * + * @param cred Credentials structure to fill in + */ +_PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, + struct loadparm_context *lp_ctx) +{ + cli_credentials_set_username(cred, "", CRED_UNINITIALISED); + cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED); + cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_UNINITIALISED); + cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_UNINITIALISED); +} + +/** + * Guess defaults for credentials from environment variables, + * and from the configuration file + * + * @param cred Credentials structure to fill in + */ +_PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred, + struct loadparm_context *lp_ctx) +{ + char *p; + const char *error_string; + + if (lp_ctx != NULL) { + cli_credentials_set_conf(cred, lp_ctx); + } + + if (getenv("LOGNAME")) { + cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV); + } + + if (getenv("USER")) { + cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV); + if ((p = strchr_m(getenv("USER"),'%'))) { + memset(p,0,strlen(cred->password)); + } + } + + if (getenv("PASSWD")) { + cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV); + } + + if (getenv("PASSWD_FD")) { + cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), + CRED_GUESS_FILE); + } + + p = getenv("PASSWD_FILE"); + if (p && p[0]) { + cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE); + } + + if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) { + cli_credentials_set_ccache(cred, lp_ctx, NULL, CRED_GUESS_FILE, + &error_string); + } +} + +/** + * Attach NETLOGON credentials for use with SCHANNEL + */ + +_PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, + struct netlogon_creds_CredentialState *netlogon_creds) +{ + cred->netlogon_creds = talloc_reference(cred, netlogon_creds); +} + +/** + * Return attached NETLOGON credentials + */ + +struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred) +{ + return cred->netlogon_creds; +} + +/** + * Set NETLOGON secure channel type + */ + +_PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred, + enum netr_SchannelType secure_channel_type) +{ + cred->secure_channel_type = secure_channel_type; +} + +/** + * Return NETLOGON secure chanel type + */ + +_PUBLIC_ time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred) +{ + return cred->password_last_changed_time; +} + +/** + * Set NETLOGON secure channel type + */ + +_PUBLIC_ void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred, + time_t last_changed_time) +{ + cred->password_last_changed_time = last_changed_time; +} + +/** + * Return NETLOGON secure chanel type + */ + +_PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred) +{ + return cred->secure_channel_type; +} + +/** + * Fill in a credentials structure as the anonymous user + */ +_PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) +{ + cli_credentials_set_username(cred, "", CRED_SPECIFIED); + cli_credentials_set_domain(cred, "", CRED_SPECIFIED); + cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); + cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED); + cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED); +} + +/** + * Describe a credentials context as anonymous or authenticated + * @retval true if anonymous, false if a username is specified + */ + +_PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred) +{ + const char *username; + + /* if bind dn is set it's not anonymous */ + if (cred->bind_dn) { + return false; + } + + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + username = cli_credentials_get_username(cred); + + /* Yes, it is deliberate that we die if we have a NULL pointer + * here - anonymous is "", not NULL, which is 'never specified, + * never guessed', ie programmer bug */ + if (!username[0]) { + return true; + } + + return false; +} + +/** + * Mark the current password for a credentials struct as wrong. This will + * cause the password to be prompted again (if a callback is set). + * + * This will decrement the number of times the password can be tried. + * + * @retval whether the credentials struct is finished + */ +_PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred) +{ + if (cred->password_obtained != CRED_CALLBACK_RESULT) { + return false; + } + + cred->password_obtained = CRED_CALLBACK; + + cred->tries--; + + return (cred->tries > 0); +} + +_PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, + const char **username, + const char **domain) +{ + if (cred->principal_obtained > cred->username_obtained) { + *domain = talloc_strdup(mem_ctx, ""); + *username = cli_credentials_get_principal(cred, mem_ctx); + } else { + *domain = cli_credentials_get_domain(cred); + *username = cli_credentials_get_username(cred); + } +} + +/** + * Read a named file, and parse it for username, domain, realm and password + * + * @param credentials Credentials structure on which to set the password + * @param file a named file to read the details from + * @param obtained This enum describes how 'specified' this password is + */ + +_PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained) +{ + uint16_t len = 0; + char *ptr, *val, *param; + char **lines; + int i, numlines; + + lines = file_lines_load(file, &numlines, 0, NULL); + + if (lines == NULL) + { + /* fail if we can't open the credentials file */ + d_printf("ERROR: Unable to open credentials file!\n"); + return false; + } + + for (i = 0; i < numlines; i++) { + len = strlen(lines[i]); + + if (len == 0) + continue; + + /* break up the line into parameter & value. + * will need to eat a little whitespace possibly */ + param = lines[i]; + if (!(ptr = strchr_m (lines[i], '='))) + continue; + + val = ptr+1; + *ptr = '\0'; + + /* eat leading white space */ + while ((*val!='\0') && ((*val==' ') || (*val=='\t'))) + val++; + + if (strwicmp("password", param) == 0) { + cli_credentials_set_password(cred, val, obtained); + } else if (strwicmp("username", param) == 0) { + cli_credentials_set_username(cred, val, obtained); + } else if (strwicmp("domain", param) == 0) { + cli_credentials_set_domain(cred, val, obtained); + } else if (strwicmp("realm", param) == 0) { + cli_credentials_set_realm(cred, val, obtained); + } + memset(lines[i], 0, len); + } + + talloc_free(lines); + + return true; +} + +/** + * Read a named file, and parse it for a password + * + * @param credentials Credentials structure on which to set the password + * @param file a named file to read the password from + * @param obtained This enum describes how 'specified' this password is + */ + +_PUBLIC_ bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained) +{ + int fd = open(file, O_RDONLY, 0); + bool ret; + + if (fd < 0) { + fprintf(stderr, "Error opening password file %s: %s\n", + file, strerror(errno)); + return false; + } + + ret = cli_credentials_parse_password_fd(credentials, fd, obtained); + + close(fd); + + return ret; +} + + +/** + * Read a file descriptor, and parse it for a password (eg from a file or stdin) + * + * @param credentials Credentials structure on which to set the password + * @param fd open file descriptor to read the password from + * @param obtained This enum describes how 'specified' this password is + */ + +_PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials, + int fd, enum credentials_obtained obtained) +{ + char *p; + char pass[128]; + + for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */ + p && p - pass < sizeof(pass);) { + switch (read(fd, p, 1)) { + case 1: + if (*p != '\n' && *p != '\0') { + *++p = '\0'; /* advance p, and null-terminate pass */ + break; + } + /* fall through */ + case 0: + if (p - pass) { + *p = '\0'; /* null-terminate it, just in case... */ + p = NULL; /* then force the loop condition to become false */ + break; + } else { + fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n"); + return false; + } + + default: + fprintf(stderr, "Error reading password from file descriptor %d: %s\n", + fd, strerror(errno)); + return false; + } + } + + cli_credentials_set_password(credentials, pass, obtained); + return true; +} + + diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h new file mode 100644 index 0000000000..f8fa2f864b --- /dev/null +++ b/auth/credentials/credentials.h @@ -0,0 +1,300 @@ +/* + samba -- Unix SMB/CIFS implementation. + + Client credentials structure + + Copyright (C) Jelmer Vernooij 2004-2006 + Copyright (C) Andrew Bartlett 2005 + + 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 . +*/ +#ifndef __CREDENTIALS_H__ +#define __CREDENTIALS_H__ + +#include "../lib/util/data_blob.h" +#include "librpc/gen_ndr/misc.h" + +struct ccache_container; +struct tevent_context; + +/* In order of priority */ +enum credentials_obtained { + CRED_UNINITIALISED = 0, /* We don't even have a guess yet */ + CRED_CALLBACK, /* Callback should be used to obtain value */ + CRED_GUESS_ENV, /* Current value should be used, which was guessed */ + CRED_GUESS_FILE, /* A guess from a file (or file pointed at in env variable) */ + CRED_CALLBACK_RESULT, /* Value was obtained from a callback */ + CRED_SPECIFIED /* Was explicitly specified on the command-line */ +}; + +enum credentials_use_kerberos { + CRED_AUTO_USE_KERBEROS = 0, /* Default, we try kerberos if available */ + CRED_DONT_USE_KERBEROS, /* Sometimes trying kerberos just does 'bad things', so don't */ + CRED_MUST_USE_KERBEROS /* Sometimes administrators are parinoid, so always do kerberos */ +}; + +enum credentials_krb_forwardable { + CRED_AUTO_KRB_FORWARDABLE = 0, /* Default, follow library defaults */ + CRED_NO_KRB_FORWARDABLE, /* not forwardable */ + CRED_FORCE_KRB_FORWARDABLE /* forwardable */ +}; + +#define CLI_CRED_NTLM2 0x01 +#define CLI_CRED_NTLMv2_AUTH 0x02 +#define CLI_CRED_LANMAN_AUTH 0x04 +#define CLI_CRED_NTLM_AUTH 0x08 +#define CLI_CRED_CLEAR_AUTH 0x10 /* TODO: Push cleartext auth with this flag */ + +struct cli_credentials { + enum credentials_obtained workstation_obtained; + enum credentials_obtained username_obtained; + enum credentials_obtained password_obtained; + enum credentials_obtained domain_obtained; + enum credentials_obtained realm_obtained; + enum credentials_obtained ccache_obtained; + enum credentials_obtained client_gss_creds_obtained; + enum credentials_obtained principal_obtained; + enum credentials_obtained keytab_obtained; + enum credentials_obtained server_gss_creds_obtained; + + /* Threshold values (essentially a MAX() over a number of the + * above) for the ccache and GSS credentials, to ensure we + * regenerate/pick correctly */ + + enum credentials_obtained ccache_threshold; + enum credentials_obtained client_gss_creds_threshold; + + const char *workstation; + const char *username; + const char *password; + const char *old_password; + const char *domain; + const char *realm; + const char *principal; + char *salt_principal; + char *impersonate_principal; + char *self_service; + char *target_service; + + const char *bind_dn; + + /* Allows authentication from a keytab or similar */ + struct samr_Password *nt_hash; + + /* Allows NTLM pass-though authentication */ + DATA_BLOB lm_response; + DATA_BLOB nt_response; + + struct ccache_container *ccache; + struct gssapi_creds_container *client_gss_creds; + struct keytab_container *keytab; + struct gssapi_creds_container *server_gss_creds; + + const char *(*workstation_cb) (struct cli_credentials *); + const char *(*password_cb) (struct cli_credentials *); + const char *(*username_cb) (struct cli_credentials *); + const char *(*domain_cb) (struct cli_credentials *); + const char *(*realm_cb) (struct cli_credentials *); + const char *(*principal_cb) (struct cli_credentials *); + + /* Private handle for the callback routines to use */ + void *priv_data; + + struct netlogon_creds_CredentialState *netlogon_creds; + enum netr_SchannelType secure_channel_type; + int kvno; + time_t password_last_changed_time; + + struct smb_krb5_context *smb_krb5_context; + + /* We are flagged to get machine account details from the + * secrets.ldb when we are asked for a username or password */ + bool machine_account_pending; + struct loadparm_context *machine_account_pending_lp_ctx; + + /* Is this a machine account? */ + bool machine_account; + + /* Should we be trying to use kerberos? */ + enum credentials_use_kerberos use_kerberos; + + /* Should we get a forwardable ticket? */ + enum credentials_krb_forwardable krb_forwardable; + + /* gensec features which should be used for connections */ + uint32_t gensec_features; + + /* Number of retries left before bailing out */ + int tries; + + /* Whether any callback is currently running */ + bool callback_running; +}; + +struct ldb_context; +struct ldb_message; +struct loadparm_context; +struct ccache_container; + +struct gssapi_creds_container; + +const char *cli_credentials_get_workstation(struct cli_credentials *cred); +bool cli_credentials_set_workstation(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +bool cli_credentials_is_anonymous(struct cli_credentials *cred); +struct cli_credentials *cli_credentials_init(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); +void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, + const char **username, + const char **domain); +NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, + int *flags, + DATA_BLOB challenge, DATA_BLOB target_info, + DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, + 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); +int cli_credentials_get_krb5_context(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct smb_krb5_context **smb_krb5_context); +int cli_credentials_get_ccache(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + struct ccache_container **ccc, + const char **error_string); +int cli_credentials_get_named_ccache(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + char *ccache_name, + struct ccache_container **ccc, const char **error_string); +int cli_credentials_get_keytab(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct keytab_container **_ktc); +const char *cli_credentials_get_domain(struct cli_credentials *cred); +struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred); +void cli_credentials_set_machine_account_pending(struct cli_credentials *cred, + struct loadparm_context *lp_ctx); +void cli_credentials_set_conf(struct cli_credentials *cred, + struct loadparm_context *lp_ctx); +const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx); +int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct gssapi_creds_container **_gcc); +int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + struct gssapi_creds_container **_gcc, + const char **error_string); +void cli_credentials_set_kerberos_state(struct cli_credentials *creds, + enum credentials_use_kerberos use_kerberos); +void cli_credentials_set_krb_forwardable(struct cli_credentials *creds, + enum credentials_krb_forwardable krb_forwardable); +bool cli_credentials_set_domain(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +bool cli_credentials_set_domain_callback(struct cli_credentials *cred, + const char *(*domain_cb) (struct cli_credentials *)); +bool cli_credentials_set_username(struct cli_credentials *cred, + const char *val, enum credentials_obtained obtained); +bool cli_credentials_set_username_callback(struct cli_credentials *cred, + const char *(*username_cb) (struct cli_credentials *)); +bool cli_credentials_set_principal(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +bool cli_credentials_set_principal_callback(struct cli_credentials *cred, + const char *(*principal_cb) (struct cli_credentials *)); +bool cli_credentials_set_password(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx); +void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained); +const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, + TALLOC_CTX *mem_ctx); +bool cli_credentials_set_realm(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +void cli_credentials_set_secure_channel_type(struct cli_credentials *cred, + enum netr_SchannelType secure_channel_type); +void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred, + time_t last_change_time); +void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, + struct netlogon_creds_CredentialState *netlogon_creds); +NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, + struct smb_krb5_context *smb_krb5_context); +NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *serviceprincipal); +NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred, + struct loadparm_context *lp_ctx); +bool cli_credentials_authentication_requested(struct cli_credentials *cred); +void cli_credentials_guess(struct cli_credentials *cred, + struct loadparm_context *lp_ctx); +bool cli_credentials_set_bind_dn(struct cli_credentials *cred, + const char *bind_dn); +const char *cli_credentials_get_bind_dn(struct cli_credentials *cred); +bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained); +const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx); +bool cli_credentials_set_password_callback(struct cli_credentials *cred, + const char *(*password_cb) (struct cli_credentials *)); +enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred); +time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred); +void cli_credentials_set_kvno(struct cli_credentials *cred, + int kvno); +bool cli_credentials_set_nt_hash(struct cli_credentials *cred, + const struct samr_Password *nt_hash, + enum credentials_obtained obtained); +bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + enum credentials_obtained obtained); +int cli_credentials_set_keytab_name(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *keytab_name, + enum credentials_obtained obtained); +void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features); +uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds); +int cli_credentials_set_ccache(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *name, + enum credentials_obtained obtained, + const char **error_string); +bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained); +bool cli_credentials_parse_password_fd(struct cli_credentials *credentials, + int fd, enum credentials_obtained obtained); +void cli_credentials_invalidate_ccache(struct cli_credentials *cred, + enum credentials_obtained obtained); +void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal); +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); +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_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds); +NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct ldb_context *ldb, + const char *base, + const char *filter, + char **error_string); + int cli_credentials_get_kvno(struct cli_credentials *cred); + + +#endif /* __CREDENTIALS_H__ */ diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c new file mode 100644 index 0000000000..7130e4164d --- /dev/null +++ b/auth/credentials/credentials_krb5.c @@ -0,0 +1,903 @@ +/* + Unix SMB/CIFS implementation. + + Handle user credentials (as regards krb5) + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Tim Potter 2001 + Copyright (C) Andrew Bartlett 2005 + + 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 . +*/ + +#include "includes.h" +#include "system/kerberos.h" +#include "auth/kerberos/kerberos.h" +#include "auth/credentials/credentials.h" +#include "auth/credentials/credentials_proto.h" +#include "auth/credentials/credentials_krb5.h" +#include "auth/kerberos/kerberos_credentials.h" +#include "auth/kerberos/kerberos_util.h" +#include "param/param.h" + +_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct smb_krb5_context **smb_krb5_context) +{ + int ret; + if (cred->smb_krb5_context) { + *smb_krb5_context = cred->smb_krb5_context; + return 0; + } + + ret = smb_krb5_init_context(cred, NULL, lp_ctx, + &cred->smb_krb5_context); + if (ret) { + cred->smb_krb5_context = NULL; + return ret; + } + *smb_krb5_context = cred->smb_krb5_context; + return 0; +} + +/* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(), + * otherwise we may still have references to the old smb_krb5_context in a credential cache etc + */ +_PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, + struct smb_krb5_context *smb_krb5_context) +{ + if (smb_krb5_context == NULL) { + talloc_unlink(cred, cred->smb_krb5_context); + cred->smb_krb5_context = NULL; + return NT_STATUS_OK; + } + + if (!talloc_reference(cred, smb_krb5_context)) { + return NT_STATUS_NO_MEMORY; + } + cred->smb_krb5_context = smb_krb5_context; + return NT_STATUS_OK; +} + +static int cli_credentials_set_from_ccache(struct cli_credentials *cred, + struct ccache_container *ccache, + enum credentials_obtained obtained, + const char **error_string) +{ + + krb5_principal princ; + krb5_error_code ret; + char *name; + + if (cred->ccache_obtained > obtained) { + return 0; + } + + ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context, + ccache->ccache, &princ); + + if (ret) { + (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n", + smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, + ret, cred)); + return ret; + } + + ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name); + if (ret) { + (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n", + smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, + ret, cred)); + return ret; + } + + cli_credentials_set_principal(cred, name, obtained); + + free(name); + + krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ); + + /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */ + cred->ccache_obtained = obtained; + + return 0; +} + +/* Free a memory ccache */ +static int free_mccache(struct ccache_container *ccc) +{ + krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache); + + return 0; +} + +/* Free a disk-based ccache */ +static int free_dccache(struct ccache_container *ccc) { + krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache); + + return 0; +} + +_PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *name, + enum credentials_obtained obtained, + const char **error_string) +{ + krb5_error_code ret; + krb5_principal princ; + struct ccache_container *ccc; + if (cred->ccache_obtained > obtained) { + return 0; + } + + ccc = talloc(cred, struct ccache_container); + if (!ccc) { + (*error_string) = error_message(ENOMEM); + return ENOMEM; + } + + ret = cli_credentials_get_krb5_context(cred, lp_ctx, + &ccc->smb_krb5_context); + if (ret) { + (*error_string) = error_message(ret); + talloc_free(ccc); + return ret; + } + if (!talloc_reference(ccc, ccc->smb_krb5_context)) { + talloc_free(ccc); + (*error_string) = error_message(ENOMEM); + return ENOMEM; + } + + if (name) { + ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache); + if (ret) { + (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n", + name, + smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, + ret, ccc)); + talloc_free(ccc); + return ret; + } + } else { + ret = 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, + ret, ccc)); + talloc_free(ccc); + return ret; + } + } + + talloc_set_destructor(ccc, free_dccache); + + ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ); + + if (ret == 0) { + krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ); + ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string); + + if (ret) { + (*error_string) = error_message(ret); + return ret; + } + + cred->ccache = ccc; + cred->ccache_obtained = obtained; + talloc_steal(cred, ccc); + + cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); + return 0; + } + return 0; +} + + +static int cli_credentials_new_ccache(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + char *ccache_name, + struct ccache_container **_ccc, + const char **error_string) +{ + bool must_free_cc_name = false; + krb5_error_code ret; + struct ccache_container *ccc = talloc(cred, struct ccache_container); + if (!ccc) { + return ENOMEM; + } + + ret = cli_credentials_get_krb5_context(cred, lp_ctx, + &ccc->smb_krb5_context); + if (ret) { + talloc_free(ccc); + (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s", + error_message(ret)); + return ret; + } + if (!talloc_reference(ccc, ccc->smb_krb5_context)) { + talloc_free(ccc); + (*error_string) = strerror(ENOMEM); + return ENOMEM; + } + + 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; + } + } + + ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, + &ccc->ccache); + 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; + } + + if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) { + talloc_set_destructor(ccc, free_mccache); + } else { + talloc_set_destructor(ccc, free_dccache); + } + + if (must_free_cc_name) { + talloc_free(ccache_name); + } + + *_ccc = ccc; + + return 0; +} + +_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + char *ccache_name, + struct ccache_container **ccc, + const char **error_string) +{ + krb5_error_code ret; + enum credentials_obtained obtained; + + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, lp_ctx); + } + + if (cred->ccache_obtained >= cred->ccache_threshold && + cred->ccache_obtained > CRED_UNINITIALISED) { + time_t lifetime; + bool expired = false; + ret = krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context, + cred->ccache->ccache, &lifetime); + if (ret == KRB5_CC_END) { + /* If we have a particular ccache set, without + * an initial ticket, then assume there is a + * good reason */ + } else if (ret == 0) { + if (lifetime == 0) { + DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n", + cli_credentials_get_principal(cred, cred))); + expired = true; + } else if (lifetime < 300) { + DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n", + cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); + expired = true; + } + } else { + (*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n", + smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, + ret, cred)); + return ret; + } + + DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n", + cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); + + if (!expired) { + *ccc = cred->ccache; + return 0; + } + } + if (cli_credentials_is_anonymous(cred)) { + (*error_string) = "Cannot get anonymous kerberos credentials"; + return EINVAL; + } + + ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string); + if (ret) { + return ret; + } + + ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string); + if (ret) { + return ret; + } + + ret = cli_credentials_set_from_ccache(cred, *ccc, + obtained, error_string); + + cred->ccache = *ccc; + cred->ccache_obtained = cred->principal_obtained; + if (ret) { + return ret; + } + cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); + return 0; +} + +_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + struct ccache_container **ccc, + const char **error_string) +{ + return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string); +} + +/* 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) +{ + if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->client_gss_creds); + cred->client_gss_creds = NULL; + } + cred->client_gss_creds_obtained = CRED_UNINITIALISED; +} + +void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, + enum credentials_obtained obtained) +{ + /* If the caller just changed the username/password etc, then + * any cached credentials are now invalid */ + if (obtained >= cred->client_gss_creds_obtained) { + if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->client_gss_creds); + cred->client_gss_creds = NULL; + } + cred->client_gss_creds_obtained = CRED_UNINITIALISED; + } + /* Now that we know that the data is 'this specified', then + * don't allow something less 'known' to be returned as a + * ccache. Ie, if the username is on the command line, we + * don't want to later guess to use a file-based ccache */ + if (obtained > cred->client_gss_creds_threshold) { + cred->client_gss_creds_threshold = obtained; + } +} + +/* We have good reason to think this CCACHE is invalid. Blow it away */ +static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred) +{ + if (cred->ccache_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->ccache); + cred->ccache = NULL; + } + cred->ccache_obtained = CRED_UNINITIALISED; + + cli_credentials_unconditionally_invalidate_client_gss_creds(cred); +} + +_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, + enum credentials_obtained obtained) +{ + /* If the caller just changed the username/password etc, then + * any cached credentials are now invalid */ + if (obtained >= cred->ccache_obtained) { + if (cred->ccache_obtained > CRED_UNINITIALISED) { + talloc_unlink(cred, cred->ccache); + cred->ccache = NULL; + } + cred->ccache_obtained = CRED_UNINITIALISED; + } + /* Now that we know that the data is 'this specified', then + * don't allow something less 'known' to be returned as a + * ccache. i.e, if the username is on the command line, we + * don't want to later guess to use a file-based ccache */ + if (obtained > cred->ccache_threshold) { + cred->ccache_threshold = obtained; + } + + cli_credentials_invalidate_client_gss_creds(cred, + obtained); +} + +static int free_gssapi_creds(struct gssapi_creds_container *gcc) +{ + OM_uint32 min_stat, maj_stat; + maj_stat = gss_release_cred(&min_stat, &gcc->creds); + return 0; +} + +_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, + struct tevent_context *event_ctx, + struct loadparm_context *lp_ctx, + struct gssapi_creds_container **_gcc, + const char **error_string) +{ + int ret = 0; + OM_uint32 maj_stat, min_stat; + struct gssapi_creds_container *gcc; + struct ccache_container *ccache; + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + krb5_enctype *etypes = NULL; + + if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && + cred->client_gss_creds_obtained > CRED_UNINITIALISED) { + bool expired = false; + OM_uint32 lifetime = 0; + gss_cred_usage_t usage = 0; + maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, + NULL, &lifetime, &usage, NULL); + if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) { + DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred))); + expired = true; + } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) { + DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime)); + expired = true; + } else if (maj_stat != GSS_S_COMPLETE) { + *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n", + gssapi_error_string(cred, maj_stat, min_stat, NULL)); + return EINVAL; + } + if (expired) { + cli_credentials_unconditionally_invalidate_client_gss_creds(cred); + } else { + DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", + cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); + + *_gcc = cred->client_gss_creds; + return 0; + } + } + + ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, + &ccache, error_string); + if (ret) { + if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { + DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", error_message(ret))); + } else { + DEBUG(4, ("Failed to get kerberos credentials: %s\n", error_message(ret))); + } + return ret; + } + + gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + (*error_string) = error_message(ENOMEM); + return ENOMEM; + } + + maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, + &gcc->creds); + if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { + /* This CCACHE is no good. Ensure we don't use it again */ + cli_credentials_unconditionally_invalidate_ccache(cred); + + /* Now try again to get a ccache */ + ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, + &ccache, error_string); + if (ret) { + DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); + return ret; + } + + maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, + &gcc->creds); + + } + + if (maj_stat) { + talloc_free(gcc); + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret)); + return ret; + } + + /* + * transfer the enctypes from the smb_krb5_context to the gssapi layer + * + * We use 'our' smb_krb5_context to do the AS-REQ and it is possible + * to configure the enctypes via the krb5.conf. + * + * And the gss_init_sec_context() creates it's own krb5_context and + * the TGS-REQ had all enctypes in it and only the ones configured + * and used for the AS-REQ, so it wasn't possible to disable the usage + * of AES keys. + */ + min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context, + KRB5_PDU_NONE, + &etypes); + if (min_stat == 0) { + OM_uint32 num_ktypes; + + for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); + + maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, + num_ktypes, + (int32_t *) etypes); + krb5_xfree (etypes); + if (maj_stat) { + talloc_free(gcc); + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret)); + return ret; + } + } + + /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ + maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, + GSS_KRB5_CRED_NO_CI_FLAGS_X, + &empty_buffer); + if (maj_stat) { + talloc_free(gcc); + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret)); + return ret; + } + + cred->client_gss_creds_obtained = cred->ccache_obtained; + talloc_set_destructor(gcc, free_gssapi_creds); + cred->client_gss_creds = gcc; + *_gcc = gcc; + return 0; +} + +/** + Set a gssapi cred_id_t into the credentials system. (Client case) + + This grabs the credentials both 'intact' and getting the krb5 + ccache out of it. This routine can be generalised in future for + the case where we deal with GSSAPI mechs other than krb5. + + On sucess, the caller must not free gssapi_cred, as it now belongs + to the credentials system. +*/ + + int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + gss_cred_id_t gssapi_cred, + enum credentials_obtained obtained, + const char **error_string) +{ + int ret; + OM_uint32 maj_stat, min_stat; + struct ccache_container *ccc; + struct gssapi_creds_container *gcc; + if (cred->client_gss_creds_obtained > obtained) { + return 0; + } + + gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + (*error_string) = error_message(ENOMEM); + return ENOMEM; + } + + ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string); + if (ret != 0) { + return ret; + } + + maj_stat = gss_krb5_copy_ccache(&min_stat, + gssapi_cred, ccc->ccache); + if (maj_stat) { + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + if (ret) { + (*error_string) = error_message(ENOMEM); + } + } + + if (ret == 0) { + ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string); + } + cred->ccache = ccc; + cred->ccache_obtained = obtained; + if (ret == 0) { + gcc->creds = gssapi_cred; + talloc_set_destructor(gcc, free_gssapi_creds); + + /* set the clinet_gss_creds_obtained here, as it just + got set to UNINITIALISED by the calls above */ + cred->client_gss_creds_obtained = obtained; + cred->client_gss_creds = gcc; + } + return ret; +} + +/* Get the keytab (actually, a container containing the krb5_keytab) + * attached to this context. If this hasn't been done or set before, + * it will be generated from the password. + */ +_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct keytab_container **_ktc) +{ + krb5_error_code ret; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; + + if (cred->keytab_obtained >= (MAX(cred->principal_obtained, + cred->username_obtained))) { + *_ktc = cred->keytab; + return 0; + } + + if (cli_credentials_is_anonymous(cred)) { + return EINVAL; + } + + ret = cli_credentials_get_krb5_context(cred, lp_ctx, + &smb_krb5_context); + if (ret) { + return ret; + } + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = smb_krb5_create_memory_keytab(mem_ctx, cred, + smb_krb5_context, &ktc); + if (ret) { + talloc_free(mem_ctx); + return ret; + } + + cred->keytab_obtained = (MAX(cred->principal_obtained, + cred->username_obtained)); + + talloc_steal(cred, ktc); + cred->keytab = ktc; + *_ktc = cred->keytab; + talloc_free(mem_ctx); + return ret; +} + +/* Given the name of a keytab (presumably in the format + * FILE:/etc/krb5.keytab), open it and attach it */ + +_PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *keytab_name, + enum credentials_obtained obtained) +{ + krb5_error_code ret; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; + + if (cred->keytab_obtained >= obtained) { + return 0; + } + + ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context); + if (ret) { + return ret; + } + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context, + keytab_name, &ktc); + if (ret) { + return ret; + } + + cred->keytab_obtained = obtained; + + talloc_steal(cred, ktc); + cred->keytab = ktc; + talloc_free(mem_ctx); + + return ret; +} + +/* Get server gss credentials (in gsskrb5, this means the keytab) */ + +_PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct gssapi_creds_container **_gcc) +{ + int ret = 0; + OM_uint32 maj_stat, min_stat; + struct gssapi_creds_container *gcc; + struct keytab_container *ktc; + struct smb_krb5_context *smb_krb5_context; + TALLOC_CTX *mem_ctx; + krb5_principal princ; + const char *error_string; + enum credentials_obtained obtained; + + mem_ctx = talloc_new(cred); + if (!mem_ctx) { + return ENOMEM; + } + + ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context); + if (ret) { + return ret; + } + + ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string); + if (ret) { + DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n", + error_string)); + talloc_free(mem_ctx); + return ret; + } + + if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) { + talloc_free(mem_ctx); + *_gcc = cred->server_gss_creds; + return 0; + } + + ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc); + if (ret) { + DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); + return ret; + } + + gcc = talloc(cred, struct gssapi_creds_container); + if (!gcc) { + talloc_free(mem_ctx); + return ENOMEM; + } + + /* This creates a GSSAPI cred_id_t with the principal and keytab set */ + maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, + &gcc->creds); + if (maj_stat) { + if (min_stat) { + ret = min_stat; + } else { + ret = EINVAL; + } + } + if (ret == 0) { + cred->server_gss_creds_obtained = cred->keytab_obtained; + talloc_set_destructor(gcc, free_gssapi_creds); + cred->server_gss_creds = gcc; + *_gcc = gcc; + } + talloc_free(mem_ctx); + return ret; +} + +/** + * Set Kerberos KVNO + */ + +_PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred, + int kvno) +{ + cred->kvno = kvno; +} + +/** + * Return Kerberos KVNO + */ + +_PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred) +{ + return cred->kvno; +} + + +const char *cli_credentials_get_salt_principal(struct cli_credentials *cred) +{ + return cred->salt_principal; +} + +_PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal) +{ + talloc_free(cred->salt_principal); + cred->salt_principal = talloc_strdup(cred, principal); +} + +/* The 'impersonate_principal' is used to allow one Kerberos principal + * (and it's associated keytab etc) to impersonate another. The + * ability to do this is controlled by the KDC, but it is generally + * permitted to impersonate anyone to yourself. This allows any + * member of the domain to get the groups of a user. This is also + * known as S4U2Self */ + +_PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred) +{ + return cred->impersonate_principal; +} + +/* + * The 'self_service' is the service principal that + * represents the same object (by its objectSid) + * as the client principal (typically our machine account). + * When trying to impersonate 'impersonate_principal' with + * S4U2Self. + */ +_PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred) +{ + return cred->self_service; +} + +_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred, + const char *principal, + const char *self_service) +{ + talloc_free(cred->impersonate_principal); + cred->impersonate_principal = talloc_strdup(cred, principal); + talloc_free(cred->self_service); + cred->self_service = talloc_strdup(cred, self_service); + cli_credentials_set_kerberos_state(cred, CRED_MUST_USE_KERBEROS); +} + +/* + * when impersonating for S4U2proxy we need to set the target principal. + * Similarly, we may only be authorized to do general impersonation to + * some particular services. + * + * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT + * + * NULL means that tickets will be obtained for the krbtgt service. +*/ + +const char *cli_credentials_get_target_service(struct cli_credentials *cred) +{ + return cred->target_service; +} + +_PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service) +{ + talloc_free(cred->target_service); + cred->target_service = talloc_strdup(cred, target_service); +} + diff --git a/auth/credentials/credentials_krb5.h b/auth/credentials/credentials_krb5.h new file mode 100644 index 0000000000..36bf03d5eb --- /dev/null +++ b/auth/credentials/credentials_krb5.h @@ -0,0 +1,57 @@ +/* + samba -- Unix SMB/CIFS implementation. + + Client credentials structure + + Copyright (C) Jelmer Vernooij 2004-2006 + Copyright (C) Andrew Bartlett 2005 + + 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 . +*/ + +#ifndef __CREDENTIALS_KRB5_H__ +#define __CREDENTIALS_KRB5_H__ + +#include +#include +#include + +struct gssapi_creds_container { + gss_cred_id_t creds; +}; + +/* Manually prototyped here to avoid needing gss headers in most callers */ +int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + gss_cred_id_t gssapi_cred, + enum credentials_obtained obtained, + const char **error_string); + +/* Manually prototyped here to avoid needing krb5 headers in most callers */ +krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *princ, + enum credentials_obtained *obtained, + const char **error_string); +krb5_error_code impersonate_principal_from_credentials(TALLOC_CTX *parent_ctx, + struct cli_credentials *credentials, + struct smb_krb5_context *smb_krb5_context, + krb5_principal *princ, + const char **error_string); + +void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, + enum credentials_obtained obtained); + +#endif /* __CREDENTIALS_KRB5_H__ */ diff --git a/auth/credentials/credentials_ntlm.c b/auth/credentials/credentials_ntlm.c new file mode 100644 index 0000000000..7f4af4f08c --- /dev/null +++ b/auth/credentials/credentials_ntlm.c @@ -0,0 +1,256 @@ +/* + Unix SMB/CIFS implementation. + + User credentials handling + + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Andrew Bartlett 2001-2005 + Copyright (C) Stefan Metzmacher 2005 + + 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 . +*/ + +#include "includes.h" +#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ +#include "../lib/crypto/crypto.h" +#include "libcli/auth/libcli_auth.h" +#include "auth/credentials/credentials.h" + +_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, + int *flags, + DATA_BLOB challenge, DATA_BLOB target_info, + DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, + DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) +{ + const char *user, *domain; + DATA_BLOB lm_response, nt_response; + DATA_BLOB lm_session_key, session_key; + const struct samr_Password *nt_hash; + lm_session_key = data_blob(NULL, 0); + + /* We may already have an NTLM response we prepared earlier. + * This is used for NTLM pass-though authentication */ + if (cred->nt_response.data || cred->lm_response.data) { + *_nt_response = cred->nt_response; + *_lm_response = cred->lm_response; + + if (!cred->lm_response.data) { + *flags = *flags & ~CLI_CRED_LANMAN_AUTH; + } + *_lm_session_key = data_blob(NULL, 0); + *_session_key = data_blob(NULL, 0); + return NT_STATUS_OK; + } + + nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx); + + cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain); + + /* If we are sending a username@realm login (see function + * above), then we will not send LM, it will not be + * accepted */ + if (cred->principal_obtained > cred->username_obtained) { + *flags = *flags & ~CLI_CRED_LANMAN_AUTH; + } + + /* Likewise if we are a machine account (avoid protocol downgrade attacks) */ + if (cred->machine_account) { + *flags = *flags & ~CLI_CRED_LANMAN_AUTH; + } + + if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) { + return NT_STATUS_ACCESS_DENIED; + } + + if (!nt_hash) { + static const uint8_t zeros[16]; + /* do nothing - blobs are zero length */ + + /* session key is all zeros */ + session_key = data_blob_talloc(mem_ctx, zeros, 16); + lm_session_key = data_blob_talloc(mem_ctx, zeros, 16); + + lm_response = data_blob(NULL, 0); + nt_response = data_blob(NULL, 0); + + /* not doing NTLM2 without a password */ + *flags &= ~CLI_CRED_NTLM2; + } else if (*flags & CLI_CRED_NTLMv2_AUTH) { + + if (!target_info.length) { + /* be lazy, match win2k - we can't do NTLMv2 without it */ + DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + /* TODO: if the remote server is standalone, then we should replace 'domain' + with the server name as supplied above */ + + if (!SMBNTLMv2encrypt_hash(mem_ctx, + user, + domain, + nt_hash->hash, &challenge, + &target_info, + &lm_response, &nt_response, + NULL, &session_key)) { + return NT_STATUS_NO_MEMORY; + } + + /* LM Key is incompatible... */ + *flags &= ~CLI_CRED_LANMAN_AUTH; + } else if (*flags & CLI_CRED_NTLM2) { + struct MD5Context md5_session_nonce_ctx; + uint8_t session_nonce[16]; + uint8_t session_nonce_hash[16]; + uint8_t user_session_key[16]; + + lm_response = data_blob_talloc(mem_ctx, NULL, 24); + generate_random_buffer(lm_response.data, 8); + memset(lm_response.data+8, 0, 16); + + memcpy(session_nonce, challenge.data, 8); + memcpy(&session_nonce[8], lm_response.data, 8); + + MD5Init(&md5_session_nonce_ctx); + MD5Update(&md5_session_nonce_ctx, challenge.data, 8); + MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); + MD5Final(session_nonce_hash, &md5_session_nonce_ctx); + + DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); + DEBUG(5, ("challenge is: \n")); + dump_data(5, session_nonce_hash, 8); + + nt_response = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(nt_hash->hash, + session_nonce_hash, + nt_response.data); + + session_key = data_blob_talloc(mem_ctx, NULL, 16); + + SMBsesskeygen_ntv1(nt_hash->hash, user_session_key); + hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); + dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); + + /* LM Key is incompatible... */ + *flags &= ~CLI_CRED_LANMAN_AUTH; + } else { + uint8_t lm_hash[16]; + nt_response = data_blob_talloc(mem_ctx, NULL, 24); + SMBOWFencrypt(nt_hash->hash, challenge.data, + nt_response.data); + + session_key = data_blob_talloc(mem_ctx, NULL, 16); + SMBsesskeygen_ntv1(nt_hash->hash, session_key.data); + dump_data_pw("NT session key:\n", session_key.data, session_key.length); + + /* lanman auth is insecure, it may be disabled. + We may also not have a password */ + if (*flags & CLI_CRED_LANMAN_AUTH) { + const char *password; + password = cli_credentials_get_password(cred); + if (!password) { + lm_response = nt_response; + } else { + lm_response = data_blob_talloc(mem_ctx, NULL, 24); + if (!SMBencrypt(password,challenge.data, + lm_response.data)) { + /* If the LM password was too long (and therefore the LM hash being + of the first 14 chars only), don't send it. + + We don't have any better options but to send the NT response + */ + data_blob_free(&lm_response); + lm_response = nt_response; + /* LM Key is incompatible with 'long' passwords */ + *flags &= ~CLI_CRED_LANMAN_AUTH; + } else { + E_deshash(password, lm_hash); + lm_session_key = data_blob_talloc(mem_ctx, NULL, 16); + memcpy(lm_session_key.data, lm_hash, 8); + memset(&lm_session_key.data[8], '\0', 8); + + if (!(*flags & CLI_CRED_NTLM_AUTH)) { + session_key = lm_session_key; + } + } + } + } else { + const char *password; + + /* LM Key is incompatible... */ + lm_response = nt_response; + *flags &= ~CLI_CRED_LANMAN_AUTH; + + password = cli_credentials_get_password(cred); + if (password) { + E_deshash(password, lm_hash); + lm_session_key = data_blob_talloc(mem_ctx, NULL, 16); + memcpy(lm_session_key.data, lm_hash, 8); + memset(&lm_session_key.data[8], '\0', 8); + } + } + } + if (_lm_response) { + *_lm_response = lm_response; + } + if (_nt_response) { + *_nt_response = nt_response; + } + if (_lm_session_key) { + *_lm_session_key = lm_session_key; + } + if (_session_key) { + *_session_key = session_key; + } + return NT_STATUS_OK; +} + +_PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, + const struct samr_Password *nt_hash, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cli_credentials_set_password(cred, NULL, obtained); + if (nt_hash) { + cred->nt_hash = talloc(cred, struct samr_Password); + *cred->nt_hash = *nt_hash; + } else { + cred->nt_hash = NULL; + } + return true; + } + + return false; +} + +_PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, + const DATA_BLOB *lm_response, + const DATA_BLOB *nt_response, + enum credentials_obtained obtained) +{ + if (obtained >= cred->password_obtained) { + cli_credentials_set_password(cred, NULL, obtained); + if (nt_response) { + cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length); + talloc_steal(cred, cred->nt_response.data); + } + if (nt_response) { + cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length); + } + return true; + } + + return false; +} + diff --git a/auth/credentials/credentials_secrets.c b/auth/credentials/credentials_secrets.c new file mode 100644 index 0000000000..d86032a564 --- /dev/null +++ b/auth/credentials/credentials_secrets.c @@ -0,0 +1,293 @@ +/* + Unix SMB/CIFS implementation. + + User credentials handling (as regards on-disk files) + + Copyright (C) Jelmer Vernooij 2005 + Copyright (C) Tim Potter 2001 + Copyright (C) Andrew Bartlett 2005 + + 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 . +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include +#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ +#include "param/secrets.h" +#include "system/filesys.h" +#include "auth/credentials/credentials.h" +#include "auth/credentials/credentials_proto.h" +#include "auth/credentials/credentials_krb5.h" +#include "auth/kerberos/kerberos_util.h" +#include "param/param.h" +#include "lib/events/events.h" +#include "dsdb/samdb/samdb.h" + +/** + * Fill in credentials for the machine trust account, from the secrets database. + * + * @param cred Credentials structure to fill in + * @retval NTSTATUS error detailing any failure + */ +_PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + struct ldb_context *ldb, + const char *base, + const char *filter, + char **error_string) +{ + TALLOC_CTX *mem_ctx; + + int ldb_ret; + struct ldb_message *msg; + + const char *machine_account; + const char *password; + const char *old_password; + const char *domain; + const char *realm; + enum netr_SchannelType sct; + const char *salt_principal; + char *keytab; + const struct ldb_val *whenChanged; + + /* ok, we are going to get it now, don't recurse back here */ + cred->machine_account_pending = false; + + /* some other parts of the system will key off this */ + cred->machine_account = true; + + mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password"); + + if (!ldb) { + /* Local secrets are stored in secrets.ldb */ + ldb = secrets_db_connect(mem_ctx, lp_ctx); + if (!ldb) { + /* set anonymous as the fallback, if the machine account won't work */ + cli_credentials_set_anonymous(cred); + *error_string = talloc_strdup(cred, "Could not open secrets.ldb"); + talloc_free(mem_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + } + + ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg, + ldb_dn_new(mem_ctx, ldb, base), + LDB_SCOPE_SUBTREE, + NULL, 0, "%s", filter); + + if (ldb_ret != LDB_SUCCESS) { + *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s\n", + filter, base ? base : "", + ldb_strerror(ldb_ret), ldb_errstring(ldb)); + /* set anonymous as the fallback, if the machine account won't work */ + cli_credentials_set_anonymous(cred); + talloc_free(mem_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + + password = ldb_msg_find_attr_as_string(msg, "secret", NULL); + old_password = ldb_msg_find_attr_as_string(msg, "priorSecret", NULL); + + machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); + + if (!machine_account) { + machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL); + + if (!machine_account) { + const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL); + if (!ldap_bind_dn) { + *error_string = talloc_asprintf(cred, + "Could not find 'samAccountName', " + "'servicePrincipalName' or " + "'ldapBindDn' in secrets record: %s", + ldb_dn_get_linearized(msg->dn)); + /* set anonymous as the fallback, if the machine account won't work */ + cli_credentials_set_anonymous(cred); + talloc_free(mem_ctx); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } else { + /* store bind dn in credentials */ + cli_credentials_set_bind_dn(cred, ldap_bind_dn); + } + } + } + + salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL); + cli_credentials_set_salt_principal(cred, salt_principal); + + sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0); + if (sct) { + cli_credentials_set_secure_channel_type(cred, sct); + } + + if (!password) { + const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd"); + struct samr_Password hash; + ZERO_STRUCT(hash); + if (nt_password_hash) { + memcpy(hash.hash, nt_password_hash->data, + MIN(nt_password_hash->length, sizeof(hash.hash))); + + cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); + } else { + cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); + } + } else { + cli_credentials_set_password(cred, password, CRED_SPECIFIED); + } + + + domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL); + if (domain) { + cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); + } + + realm = ldb_msg_find_attr_as_string(msg, "realm", NULL); + if (realm) { + cli_credentials_set_realm(cred, realm, CRED_SPECIFIED); + } + + if (machine_account) { + cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); + } + + cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0)); + + whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged"); + if (whenChanged) { + time_t lct; + if (ldb_val_to_time(whenChanged, &lct) == LDB_SUCCESS) { + cli_credentials_set_password_last_changed_time(cred, lct); + } + } + + /* If there was an external keytab specified by reference in + * the LDB, then use this. Otherwise we will make one up + * (chewing CPU time) from the password */ + keytab = keytab_name_from_msg(cred, ldb, msg); + if (keytab) { + cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED); + talloc_free(keytab); + } + talloc_free(mem_ctx); + + return NT_STATUS_OK; +} + +/** + * Fill in credentials for the machine trust account, from the secrets database. + * + * @param cred Credentials structure to fill in + * @retval NTSTATUS error detailing any failure + */ +_PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred, + struct loadparm_context *lp_ctx) +{ + NTSTATUS status; + char *filter; + char *error_string; + /* Bleh, nasty recursion issues: We are setting a machine + * account here, so we don't want the 'pending' flag around + * any more */ + cred->machine_account_pending = false; + filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER, + cli_credentials_get_domain(cred)); + status = cli_credentials_set_secrets(cred, lp_ctx, NULL, + SECRETS_PRIMARY_DOMAIN_DN, + filter, &error_string); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Could not find machine account in secrets database: %s: %s\n", nt_errstr(status), error_string)); + talloc_free(error_string); + } + return status; +} + +/** + * Fill in credentials for the machine trust account, from the secrets database. + * + * @param cred Credentials structure to fill in + * @retval NTSTATUS error detailing any failure + */ +NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred, + struct loadparm_context *lp_ctx) +{ + NTSTATUS status; + char *filter; + char *error_string; + /* Bleh, nasty recursion issues: We are setting a machine + * account here, so we don't want the 'pending' flag around + * any more */ + cred->machine_account_pending = false; + filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH, + cli_credentials_get_realm(cred), + cli_credentials_get_domain(cred)); + status = cli_credentials_set_secrets(cred, lp_ctx, NULL, + SECRETS_PRINCIPALS_DN, + filter, &error_string); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s: %s\n", nt_errstr(status), error_string)); + talloc_free(error_string); + } + return status; +} + +/** + * Fill in credentials for a particular prinicpal, from the secrets database. + * + * @param cred Credentials structure to fill in + * @retval NTSTATUS error detailing any failure + */ +_PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred, + struct loadparm_context *lp_ctx, + const char *serviceprincipal) +{ + NTSTATUS status; + char *filter; + char *error_string; + /* Bleh, nasty recursion issues: We are setting a machine + * account here, so we don't want the 'pending' flag around + * any more */ + cred->machine_account_pending = false; + filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH, + cli_credentials_get_realm(cred), + cli_credentials_get_domain(cred), + serviceprincipal); + status = cli_credentials_set_secrets(cred, lp_ctx, NULL, + SECRETS_PRINCIPALS_DN, filter, + &error_string); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Could not find %s principal in secrets database: %s: %s\n", serviceprincipal, nt_errstr(status), error_string)); + } + return status; +} + +/** + * Ask that when required, the credentials system will be filled with + * machine trust account, from the secrets database. + * + * @param cred Credentials structure to fill in + * @note This function is used to call the above function after, rather + * than during, popt processing. + * + */ +_PUBLIC_ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred, + struct loadparm_context *lp_ctx) +{ + cred->machine_account_pending = true; + cred->machine_account_pending_lp_ctx = lp_ctx; +} + + diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c new file mode 100644 index 0000000000..5d21721490 --- /dev/null +++ b/auth/credentials/pycredentials.c @@ -0,0 +1,492 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij 2007 + + 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 . +*/ + +#include +#include "includes.h" +#include "pycredentials.h" +#include "param/param.h" +#include "lib/cmdline/credentials.h" +#include "librpc/gen_ndr/samr.h" /* for struct samr_Password */ +#include "libcli/util/pyerrors.h" +#include "param/pyparam.h" +#include + +void initcredentials(void); + +static PyObject *PyString_FromStringOrNULL(const char *str) +{ + if (str == NULL) + Py_RETURN_NONE; + return PyString_FromString(str); +} + +static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + pytalloc_Object *ret = (pytalloc_Object *)type->tp_alloc(type, 0); + if (ret == NULL) { + PyErr_NoMemory(); + return NULL; + } + ret->talloc_ctx = talloc_new(NULL); + if (ret->talloc_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + ret->ptr = cli_credentials_init(ret->talloc_ctx); + return (PyObject *)ret; +} + +static PyObject *py_creds_get_username(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_username(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_username(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + return PyBool_FromLong(cli_credentials_set_username(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_get_password(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_password(PyCredentials_AsCliCredentials(self))); +} + + +static PyObject *py_creds_set_password(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + return PyBool_FromLong(cli_credentials_set_password(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_get_domain(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_domain(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_domain(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + return PyBool_FromLong(cli_credentials_set_domain(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_get_realm(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_realm(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_realm(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + return PyBool_FromLong(cli_credentials_set_realm(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_get_bind_dn(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_bind_dn(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_bind_dn(pytalloc_Object *self, PyObject *args) +{ + char *newval; + if (!PyArg_ParseTuple(args, "s", &newval)) + return NULL; + + return PyBool_FromLong(cli_credentials_set_bind_dn(PyCredentials_AsCliCredentials(self), newval)); +} + +static PyObject *py_creds_get_workstation(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_workstation(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_workstation(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + return PyBool_FromLong(cli_credentials_set_workstation(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_is_anonymous(pytalloc_Object *self) +{ + return PyBool_FromLong(cli_credentials_is_anonymous(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_anonymous(pytalloc_Object *self) +{ + cli_credentials_set_anonymous(PyCredentials_AsCliCredentials(self)); + Py_RETURN_NONE; +} + +static PyObject *py_creds_authentication_requested(pytalloc_Object *self) +{ + return PyBool_FromLong(cli_credentials_authentication_requested(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_wrong_password(pytalloc_Object *self) +{ + return PyBool_FromLong(cli_credentials_wrong_password(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_cmdline_callbacks(pytalloc_Object *self) +{ + return PyBool_FromLong(cli_credentials_set_cmdline_callbacks(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args) +{ + char *newval; + enum credentials_obtained obt = CRED_SPECIFIED; + int _obt = obt; + + if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { + return NULL; + } + obt = _obt; + + cli_credentials_parse_string(PyCredentials_AsCliCredentials(self), newval, obt); + Py_RETURN_NONE; +} + +static PyObject *py_creds_get_nt_hash(pytalloc_Object *self) +{ + const struct samr_Password *ntpw = cli_credentials_get_nt_hash(PyCredentials_AsCliCredentials(self), self->ptr); + + return PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16); +} + +static PyObject *py_creds_set_kerberos_state(pytalloc_Object *self, PyObject *args) +{ + int state; + if (!PyArg_ParseTuple(args, "i", &state)) + return NULL; + + cli_credentials_set_kerberos_state(PyCredentials_AsCliCredentials(self), state); + Py_RETURN_NONE; +} + +static PyObject *py_creds_set_krb_forwardable(pytalloc_Object *self, PyObject *args) +{ + int state; + if (!PyArg_ParseTuple(args, "i", &state)) + return NULL; + + cli_credentials_set_krb_forwardable(PyCredentials_AsCliCredentials(self), state); + Py_RETURN_NONE; +} + +static PyObject *py_creds_guess(pytalloc_Object *self, PyObject *args) +{ + PyObject *py_lp_ctx = Py_None; + struct loadparm_context *lp_ctx; + TALLOC_CTX *mem_ctx; + struct cli_credentials *creds; + + creds = PyCredentials_AsCliCredentials(self); + + if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx)) + return NULL; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); + if (lp_ctx == NULL) { + talloc_free(mem_ctx); + return NULL; + } + + cli_credentials_guess(creds, lp_ctx); + + talloc_free(mem_ctx); + + Py_RETURN_NONE; +} + +static PyObject *py_creds_set_machine_account(pytalloc_Object *self, PyObject *args) +{ + PyObject *py_lp_ctx = Py_None; + struct loadparm_context *lp_ctx; + NTSTATUS status; + struct cli_credentials *creds; + TALLOC_CTX *mem_ctx; + + creds = PyCredentials_AsCliCredentials(self); + + if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx)) + return NULL; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); + if (lp_ctx == NULL) { + talloc_free(mem_ctx); + return NULL; + } + + status = cli_credentials_set_machine_account(creds, lp_ctx); + talloc_free(mem_ctx); + + PyErr_NTSTATUS_IS_ERR_RAISE(status); + + Py_RETURN_NONE; +} + +static PyObject *PyCredentialCacheContainer_from_ccache_container(struct ccache_container *ccc) +{ + PyCredentialCacheContainerObject *py_ret; + + if (ccc == NULL) { + Py_RETURN_NONE; + } + + py_ret = (PyCredentialCacheContainerObject *)PyCredentialCacheContainer.tp_alloc(&PyCredentialCacheContainer, 0); + if (py_ret == NULL) { + PyErr_NoMemory(); + return NULL; + } + py_ret->mem_ctx = talloc_new(NULL); + py_ret->ccc = talloc_reference(py_ret->mem_ctx, ccc); + return (PyObject *)py_ret; +} + + +static PyObject *py_creds_get_named_ccache(pytalloc_Object *self, PyObject *args) +{ + PyObject *py_lp_ctx = Py_None; + char *ccache_name; + struct loadparm_context *lp_ctx; + struct ccache_container *ccc; + struct tevent_context *event_ctx; + int ret; + const char *error_string; + struct cli_credentials *creds; + TALLOC_CTX *mem_ctx; + + creds = PyCredentials_AsCliCredentials(self); + + if (!PyArg_ParseTuple(args, "|Os", &py_lp_ctx, &ccache_name)) + return NULL; + + mem_ctx = talloc_new(NULL); + if (mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } + + lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); + if (lp_ctx == NULL) { + talloc_free(mem_ctx); + return NULL; + } + + event_ctx = tevent_context_init(mem_ctx); + + ret = cli_credentials_get_named_ccache(creds, event_ctx, lp_ctx, + ccache_name, &ccc, &error_string); + talloc_unlink(mem_ctx, lp_ctx); + if (ret == 0) { + talloc_steal(ccc, event_ctx); + talloc_free(mem_ctx); + return PyCredentialCacheContainer_from_ccache_container(ccc); + } + + PyErr_SetString(PyExc_RuntimeError, error_string?error_string:"NULL"); + + talloc_free(mem_ctx); + return NULL; +} + +static PyObject *py_creds_set_gensec_features(pytalloc_Object *self, PyObject *args) +{ + unsigned int gensec_features; + + if (!PyArg_ParseTuple(args, "I", &gensec_features)) + return NULL; + + cli_credentials_set_gensec_features(PyCredentials_AsCliCredentials(self), gensec_features); + + Py_RETURN_NONE; +} + +static PyObject *py_creds_get_gensec_features(pytalloc_Object *self, PyObject *args) +{ + unsigned int gensec_features; + + gensec_features = cli_credentials_get_gensec_features(PyCredentials_AsCliCredentials(self)); + return PyInt_FromLong(gensec_features); +} + + +static PyMethodDef py_creds_methods[] = { + { "get_username", (PyCFunction)py_creds_get_username, METH_NOARGS, + "S.get_username() -> username\nObtain username." }, + { "set_username", (PyCFunction)py_creds_set_username, METH_VARARGS, + "S.set_username(name, obtained=CRED_SPECIFIED) -> None\n" + "Change username." }, + { "get_password", (PyCFunction)py_creds_get_password, METH_NOARGS, + "S.get_password() -> password\n" + "Obtain password." }, + { "set_password", (PyCFunction)py_creds_set_password, METH_VARARGS, + "S.set_password(password, obtained=CRED_SPECIFIED) -> None\n" + "Change password." }, + { "get_domain", (PyCFunction)py_creds_get_domain, METH_NOARGS, + "S.get_domain() -> domain\n" + "Obtain domain name." }, + { "set_domain", (PyCFunction)py_creds_set_domain, METH_VARARGS, + "S.set_domain(domain, obtained=CRED_SPECIFIED) -> None\n" + "Change domain name." }, + { "get_realm", (PyCFunction)py_creds_get_realm, METH_NOARGS, + "S.get_realm() -> realm\n" + "Obtain realm name." }, + { "set_realm", (PyCFunction)py_creds_set_realm, METH_VARARGS, + "S.set_realm(realm, obtained=CRED_SPECIFIED) -> None\n" + "Change realm name." }, + { "get_bind_dn", (PyCFunction)py_creds_get_bind_dn, METH_NOARGS, + "S.get_bind_dn() -> bind dn\n" + "Obtain bind DN." }, + { "set_bind_dn", (PyCFunction)py_creds_set_bind_dn, METH_VARARGS, + "S.set_bind_dn(bind_dn) -> None\n" + "Change bind DN." }, + { "is_anonymous", (PyCFunction)py_creds_is_anonymous, METH_NOARGS, + NULL }, + { "set_anonymous", (PyCFunction)py_creds_set_anonymous, METH_NOARGS, + "S.set_anonymous() -> None\n" + "Use anonymous credentials." }, + { "get_workstation", (PyCFunction)py_creds_get_workstation, METH_NOARGS, + NULL }, + { "set_workstation", (PyCFunction)py_creds_set_workstation, METH_VARARGS, + NULL }, + { "authentication_requested", (PyCFunction)py_creds_authentication_requested, METH_NOARGS, + NULL }, + { "wrong_password", (PyCFunction)py_creds_wrong_password, METH_NOARGS, + "S.wrong_password() -> bool\n" + "Indicate the returned password was incorrect." }, + { "set_cmdline_callbacks", (PyCFunction)py_creds_set_cmdline_callbacks, METH_NOARGS, + "S.set_cmdline_callbacks() -> bool\n" + "Use command-line to obtain credentials not explicitly set." }, + { "parse_string", (PyCFunction)py_creds_parse_string, METH_VARARGS, + "S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n" + "Parse credentials string." }, + { "get_nt_hash", (PyCFunction)py_creds_get_nt_hash, METH_NOARGS, + NULL }, + { "set_kerberos_state", (PyCFunction)py_creds_set_kerberos_state, METH_VARARGS, + NULL }, + { "set_krb_forwardable", (PyCFunction)py_creds_set_krb_forwardable, METH_VARARGS, + NULL }, + { "guess", (PyCFunction)py_creds_guess, METH_VARARGS, NULL }, + { "set_machine_account", (PyCFunction)py_creds_set_machine_account, METH_VARARGS, NULL }, + { "get_named_ccache", (PyCFunction)py_creds_get_named_ccache, METH_VARARGS, NULL }, + { "set_gensec_features", (PyCFunction)py_creds_set_gensec_features, METH_VARARGS, NULL }, + { "get_gensec_features", (PyCFunction)py_creds_get_gensec_features, METH_NOARGS, NULL }, + { NULL } +}; + +PyTypeObject PyCredentials = { + .tp_name = "credentials.Credentials", + .tp_basicsize = sizeof(pytalloc_Object), + .tp_new = py_creds_new, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = py_creds_methods, +}; + + +PyTypeObject PyCredentialCacheContainer = { + .tp_name = "credentials.CredentialCacheContainer", + .tp_basicsize = sizeof(pytalloc_Object), + .tp_flags = Py_TPFLAGS_DEFAULT, +}; + +void initcredentials(void) +{ + PyObject *m; + PyTypeObject *talloc_type = pytalloc_GetObjectType(); + if (talloc_type == NULL) + return; + + PyCredentials.tp_base = PyCredentialCacheContainer.tp_base = talloc_type; + + if (PyType_Ready(&PyCredentials) < 0) + return; + + if (PyType_Ready(&PyCredentialCacheContainer) < 0) + return; + + m = Py_InitModule3("credentials", NULL, "Credentials management."); + if (m == NULL) + return; + + PyModule_AddObject(m, "AUTO_USE_KERBEROS", PyInt_FromLong(CRED_AUTO_USE_KERBEROS)); + PyModule_AddObject(m, "DONT_USE_KERBEROS", PyInt_FromLong(CRED_DONT_USE_KERBEROS)); + PyModule_AddObject(m, "MUST_USE_KERBEROS", PyInt_FromLong(CRED_MUST_USE_KERBEROS)); + + PyModule_AddObject(m, "AUTO_KRB_FORWARDABLE", PyInt_FromLong(CRED_AUTO_KRB_FORWARDABLE)); + PyModule_AddObject(m, "NO_KRB_FORWARDABLE", PyInt_FromLong(CRED_NO_KRB_FORWARDABLE)); + PyModule_AddObject(m, "FORCE_KRB_FORWARDABLE", PyInt_FromLong(CRED_FORCE_KRB_FORWARDABLE)); + + Py_INCREF(&PyCredentials); + PyModule_AddObject(m, "Credentials", (PyObject *)&PyCredentials); + Py_INCREF(&PyCredentialCacheContainer); + PyModule_AddObject(m, "CredentialCacheContainer", (PyObject *)&PyCredentialCacheContainer); +} diff --git a/auth/credentials/pycredentials.h b/auth/credentials/pycredentials.h new file mode 100644 index 0000000000..3a110fb09a --- /dev/null +++ b/auth/credentials/pycredentials.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij 2008 + + 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 . +*/ +#ifndef _PYCREDENTIALS_H_ +#define _PYCREDENTIALS_H_ + +#include "auth/credentials/credentials.h" +#include + +extern PyTypeObject PyCredentials; +extern PyTypeObject PyCredentialCacheContainer; +typedef struct { + PyObject_HEAD + TALLOC_CTX *mem_ctx; + struct ccache_container *ccc; +} PyCredentialCacheContainerObject; +#define PyCredentials_Check(py_obj) PyObject_TypeCheck(py_obj, &PyCredentials) +#define PyCredentials_AsCliCredentials(py_obj) pytalloc_get_type(py_obj, struct cli_credentials) +#define cli_credentials_from_py_object(py_obj) (py_obj == Py_None)?cli_credentials_init_anon(NULL):PyCredentials_AsCliCredentials(py_obj) + +#endif /* _PYCREDENTIALS_H_ */ diff --git a/auth/credentials/samba-credentials.pc.in b/auth/credentials/samba-credentials.pc.in new file mode 100644 index 0000000000..9a0db509ee --- /dev/null +++ b/auth/credentials/samba-credentials.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +modulesdir=${prefix}/modules/gensec + +Name: samba-credentials +Description: Credentials management +Version: @PACKAGE_VERSION@ +Libs: @LIB_RPATH@ -L${libdir} -lsamba-credentials +Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/auth/credentials/tests/bind.py b/auth/credentials/tests/bind.py new file mode 100755 index 0000000000..1529a475c7 --- /dev/null +++ b/auth/credentials/tests/bind.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# This is unit with tests for LDAP access checks + +import optparse +import sys +import base64 +import re +import os +import copy +import time + +sys.path.insert(0, "bin/python") +import samba +samba.ensure_external_module("testtools", "testtools") +samba.ensure_external_module("subunit", "subunit/python") + +import samba.getopt as options + +from ldb import ( + SCOPE_BASE, SCOPE_SUBTREE, LdbError, ERR_NO_SUCH_OBJECT) +from samba.dcerpc import security + +from samba.auth import system_session +from samba import gensec +from samba.samdb import SamDB +from samba.credentials import Credentials +import samba.tests +from samba.tests import delete_force +from subunit.run import SubunitTestRunner +import unittest + +parser = optparse.OptionParser("ldap [options] ") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) + +# use command line creds if available +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) +opts, args = parser.parse_args() + +if len(args) < 1: + parser.print_usage() + sys.exit(1) + +host = args[0] +lp = sambaopts.get_loadparm() +creds = credopts.get_credentials(lp) +creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) +creds_machine = copy.deepcopy(creds) +creds_user1 = copy.deepcopy(creds) +creds_user2 = copy.deepcopy(creds) +creds_user3 = copy.deepcopy(creds) + +class BindTests(samba.tests.TestCase): + + info_dc = None + + def setUp(self): + super(BindTests, self).setUp() + # fetch rootDSEs + if self.info_dc is None: + res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + self.assertEquals(len(res), 1) + BindTests.info_dc = res[0] + # cache some of RootDSE props + self.schema_dn = self.info_dc["schemaNamingContext"][0] + self.domain_dn = self.info_dc["defaultNamingContext"][0] + self.config_dn = self.info_dc["configurationNamingContext"][0] + self.computer_dn = "CN=centos53,CN=Computers,%s" % self.domain_dn + self.password = "P@ssw0rd" + self.username = "BindTestUser_" + time.strftime("%s", time.gmtime()) + + def tearDown(self): + super(BindTests, self).tearDown() + + def test_computer_account_bind(self): + # create a computer acocount for the test + delete_force(ldb, self.computer_dn) + ldb.add_ldif(""" +dn: """ + self.computer_dn + """ +cn: CENTOS53 +displayName: CENTOS53$ +name: CENTOS53 +sAMAccountName: CENTOS53$ +countryCode: 0 +objectClass: computer +objectClass: organizationalPerson +objectClass: person +objectClass: top +objectClass: user +codePage: 0 +userAccountControl: 4096 +dNSHostName: centos53.alabala.test +operatingSystemVersion: 5.2 (3790) +operatingSystem: Windows Server 2003 +""") + ldb.modify_ldif(""" +dn: """ + self.computer_dn + """ +changetype: modify +replace: unicodePwd +unicodePwd:: """ + base64.b64encode("\"P@ssw0rd\"".encode('utf-16-le')) + """ +""") + + # do a simple bind and search with the machine account + creds_machine.set_bind_dn(self.computer_dn) + creds_machine.set_password(self.password) + print "BindTest with: " + creds_machine.get_bind_dn() + ldb_machine = samba.tests.connect_samdb(host, credentials=creds_machine, + lp=lp, ldap_only=True) + res = ldb_machine.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + + def test_user_account_bind(self): + # create user + ldb.newuser(username=self.username, password=self.password) + ldb_res = ldb.search(base=self.domain_dn, + scope=SCOPE_SUBTREE, + expression="(samAccountName=%s)" % self.username) + self.assertEquals(len(ldb_res), 1) + user_dn = ldb_res[0]["dn"] + + # do a simple bind and search with the user account in format user@realm + creds_user1.set_bind_dn(self.username + "@" + creds.get_realm()) + creds_user1.set_password(self.password) + print "BindTest with: " + creds_user1.get_bind_dn() + ldb_user1 = samba.tests.connect_samdb(host, credentials=creds_user1, + lp=lp, ldap_only=True) + res = ldb_user1.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + + # do a simple bind and search with the user account in format domain\user + creds_user2.set_bind_dn(creds.get_domain() + "\\" + self.username) + creds_user2.set_password(self.password) + print "BindTest with: " + creds_user2.get_bind_dn() + ldb_user2 = samba.tests.connect_samdb(host, credentials=creds_user2, + lp=lp, ldap_only=True) + res = ldb_user2.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + + # do a simple bind and search with the user account DN + creds_user3.set_bind_dn(str(user_dn)) + creds_user3.set_password(self.password) + print "BindTest with: " + creds_user3.get_bind_dn() + ldb_user3 = samba.tests.connect_samdb(host, credentials=creds_user3, + lp=lp, ldap_only=True) + res = ldb_user3.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) + + +ldb = samba.tests.connect_samdb(host, credentials=creds, lp=lp, ldap_only=True) + +runner = SubunitTestRunner() +rc = 0 +if not runner.run(unittest.makeSuite(BindTests)).wasSuccessful(): + rc = 1 + +sys.exit(rc) diff --git a/auth/credentials/tests/simple.c b/auth/credentials/tests/simple.c new file mode 100644 index 0000000000..6c722750d6 --- /dev/null +++ b/auth/credentials/tests/simple.c @@ -0,0 +1,119 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij 2007 + + 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 . +*/ + +#include "includes.h" +#include "auth/credentials/credentials.h" +#include "torture/torture.h" + +static bool test_init(struct torture_context *tctx) +{ + struct cli_credentials *creds = cli_credentials_init(tctx); + + cli_credentials_set_domain(creds, "bla", CRED_SPECIFIED); + + torture_assert_str_equal(tctx, "BLA", cli_credentials_get_domain(creds), + "domain"); + + cli_credentials_set_username(creds, "someuser", CRED_SPECIFIED); + + torture_assert_str_equal(tctx, "someuser", + cli_credentials_get_username(creds), + "username"); + + cli_credentials_set_password(creds, "p4ssw0rd", CRED_SPECIFIED); + + torture_assert_str_equal(tctx, "p4ssw0rd", + cli_credentials_get_password(creds), + "password"); + + return true; +} + +static bool test_init_anonymous(struct torture_context *tctx) +{ + struct cli_credentials *creds = cli_credentials_init_anon(tctx); + + torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), + "", "domain"); + + torture_assert_str_equal(tctx, cli_credentials_get_username(creds), + "", "username"); + + torture_assert(tctx, cli_credentials_get_password(creds) == NULL, + "password"); + + return true; +} + +static bool test_parse_string(struct torture_context *tctx) +{ + struct cli_credentials *creds = cli_credentials_init_anon(tctx); + + /* anonymous */ + cli_credentials_parse_string(creds, "%", CRED_SPECIFIED); + + torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), + "", "domain"); + + torture_assert_str_equal(tctx, cli_credentials_get_username(creds), + "", "username"); + + torture_assert(tctx, cli_credentials_get_password(creds) == NULL, + "password"); + + /* username + password */ + cli_credentials_parse_string(creds, "somebody%secret", + CRED_SPECIFIED); + + torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), + "", "domain"); + + torture_assert_str_equal(tctx, cli_credentials_get_username(creds), + "somebody", "username"); + + torture_assert_str_equal(tctx, cli_credentials_get_password(creds), + "secret", "password"); + + /* principal */ + cli_credentials_parse_string(creds, "prin@styx", + CRED_SPECIFIED); + + torture_assert_str_equal(tctx, cli_credentials_get_realm(creds), + "STYX", "realm"); + + torture_assert_str_equal(tctx, + cli_credentials_get_principal(creds, tctx), + "prin@styx", "principal"); + + return true; +} + +struct torture_suite *torture_local_credentials(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "credentials"); + + torture_suite_add_simple_test(suite, "init", test_init); + torture_suite_add_simple_test(suite, "init anonymous", + test_init_anonymous); + torture_suite_add_simple_test(suite, "parse_string", + test_parse_string); + + return suite; +} + diff --git a/auth/credentials/wscript_build b/auth/credentials/wscript_build new file mode 100644 index 0000000000..2c46b43b21 --- /dev/null +++ b/auth/credentials/wscript_build @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +bld.SAMBA_LIBRARY('samba-credentials', + source='credentials.c', + autoproto='credentials_proto.h', + public_headers='credentials.h', + pc_files='samba-credentials.pc', + deps='LIBCRYPTO errors events LIBCLI_AUTH security CREDENTIALS_SECRETS CREDENTIALS_KRB5', + vnum='0.0.1' + ) + +bld.SAMBA_SUBSYSTEM('CREDENTIALS_KRB5', + source='credentials_krb5.c', + deps='KERBEROS_UTIL gssapi samba-credentials', + public_deps='com_err authkrb5', + ) + +bld.SAMBA_SUBSYSTEM('CREDENTIALS_SECRETS', + source='credentials_secrets.c', + deps='CREDENTIALS_KRB5 CREDENTIALS_NTLM ldb samdb-common', + ) + +bld.SAMBA_SUBSYSTEM('CREDENTIALS_NTLM', + source='credentials_ntlm.c', + deps='samba-credentials') + +bld.SAMBA_PYTHON('pycredentials', + source='pycredentials.c', + public_deps='samba-credentials cmdline-credentials pytalloc-util pyparam_util CREDENTIALS_KRB5 CREDENTIALS_SECRETS', + realname='samba/credentials.so' + ) + diff --git a/auth/wscript_build b/auth/wscript_build index 976e8ab090..540317a401 100644 --- a/auth/wscript_build +++ b/auth/wscript_build @@ -8,3 +8,4 @@ bld.SAMBA_LIBRARY('auth_sam_reply', ) bld.RECURSE('gensec') +bld.RECURSE('credentials') diff --git a/source3/auth/auth_samba4.c b/source3/auth/auth_samba4.c index 371d4b7a33..994bde1713 100644 --- a/source3/auth/auth_samba4.c +++ b/source3/auth/auth_samba4.c @@ -26,7 +26,7 @@ #include "source4/lib/events/events.h" #include "source4/lib/messaging/messaging.h" #include "auth/gensec/gensec.h" -#include "source4/auth/credentials/credentials.h" +#include "auth/credentials/credentials.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_AUTH diff --git a/source4/auth/credentials/credentials.c b/source4/auth/credentials/credentials.c deleted file mode 100644 index 83e90344bf..0000000000 --- a/source4/auth/credentials/credentials.c +++ /dev/null @@ -1,1002 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - User credentials handling - - Copyright (C) Jelmer Vernooij 2005 - Copyright (C) Tim Potter 2001 - Copyright (C) Andrew Bartlett 2005 - - 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 . -*/ - -#include "includes.h" -#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ -#include "auth/credentials/credentials.h" -#include "auth/credentials/credentials_proto.h" -#include "libcli/auth/libcli_auth.h" -#include "lib/events/events.h" -#include "param/param.h" -#include "system/filesys.h" - -/** - * Create a new credentials structure - * @param mem_ctx TALLOC_CTX parent for credentials structure - */ -_PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) -{ - struct cli_credentials *cred = talloc(mem_ctx, struct cli_credentials); - if (cred == NULL) { - return cred; - } - - cred->workstation_obtained = CRED_UNINITIALISED; - cred->username_obtained = CRED_UNINITIALISED; - cred->password_obtained = CRED_UNINITIALISED; - cred->domain_obtained = CRED_UNINITIALISED; - cred->realm_obtained = CRED_UNINITIALISED; - cred->ccache_obtained = CRED_UNINITIALISED; - cred->client_gss_creds_obtained = CRED_UNINITIALISED; - cred->principal_obtained = CRED_UNINITIALISED; - cred->keytab_obtained = CRED_UNINITIALISED; - cred->server_gss_creds_obtained = CRED_UNINITIALISED; - - cred->ccache_threshold = CRED_UNINITIALISED; - cred->client_gss_creds_threshold = CRED_UNINITIALISED; - - cred->workstation = NULL; - cred->username = NULL; - cred->password = NULL; - cred->old_password = NULL; - cred->domain = NULL; - cred->realm = NULL; - cred->principal = NULL; - cred->salt_principal = NULL; - cred->impersonate_principal = NULL; - cred->self_service = NULL; - cred->target_service = NULL; - - cred->bind_dn = NULL; - - cred->nt_hash = NULL; - - cred->lm_response.data = NULL; - cred->lm_response.length = 0; - cred->nt_response.data = NULL; - cred->nt_response.length = 0; - - cred->ccache = NULL; - cred->client_gss_creds = NULL; - cred->keytab = NULL; - cred->server_gss_creds = NULL; - - cred->workstation_cb = NULL; - cred->password_cb = NULL; - cred->username_cb = NULL; - cred->domain_cb = NULL; - cred->realm_cb = NULL; - cred->principal_cb = NULL; - - cred->priv_data = NULL; - - cred->netlogon_creds = NULL; - cred->secure_channel_type = SEC_CHAN_NULL; - - cred->kvno = 0; - - cred->password_last_changed_time = 0; - - cred->smb_krb5_context = NULL; - - cred->machine_account_pending = false; - cred->machine_account_pending_lp_ctx = NULL; - - cred->machine_account = false; - - cred->tries = 3; - - cred->callback_running = false; - - cli_credentials_set_kerberos_state(cred, CRED_AUTO_USE_KERBEROS); - cli_credentials_set_gensec_features(cred, 0); - cli_credentials_set_krb_forwardable(cred, CRED_AUTO_KRB_FORWARDABLE); - - return cred; -} - -/** - * Create a new anonymous credential - * @param mem_ctx TALLOC_CTX parent for credentials structure - */ -_PUBLIC_ struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx) -{ - struct cli_credentials *anon_credentials; - - anon_credentials = cli_credentials_init(mem_ctx); - cli_credentials_set_anonymous(anon_credentials); - - return anon_credentials; -} - -_PUBLIC_ void cli_credentials_set_kerberos_state(struct cli_credentials *creds, - enum credentials_use_kerberos use_kerberos) -{ - creds->use_kerberos = use_kerberos; -} - -_PUBLIC_ void cli_credentials_set_krb_forwardable(struct cli_credentials *creds, - enum credentials_krb_forwardable krb_forwardable) -{ - creds->krb_forwardable = krb_forwardable; -} - -_PUBLIC_ enum credentials_use_kerberos cli_credentials_get_kerberos_state(struct cli_credentials *creds) -{ - return creds->use_kerberos; -} - -_PUBLIC_ enum credentials_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds) -{ - return creds->krb_forwardable; -} - -_PUBLIC_ void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features) -{ - creds->gensec_features = gensec_features; -} - -_PUBLIC_ uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds) -{ - return creds->gensec_features; -} - - -/** - * Obtain the username for this credentials context. - * @param cred credentials context - * @retval The username set on this context. - * @note Return value will never be NULL except by programmer error. - */ -_PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - if (cred->username_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->username = cred->username_cb(cred); - cred->callback_running = false; - cred->username_obtained = CRED_SPECIFIED; - cli_credentials_invalidate_ccache(cred, cred->username_obtained); - } - - return cred->username; -} - -_PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, - const char *val, enum credentials_obtained obtained) -{ - if (obtained >= cred->username_obtained) { - cred->username = talloc_strdup(cred, val); - cred->username_obtained = obtained; - cli_credentials_invalidate_ccache(cred, cred->username_obtained); - return true; - } - - return false; -} - -bool cli_credentials_set_username_callback(struct cli_credentials *cred, - const char *(*username_cb) (struct cli_credentials *)) -{ - if (cred->username_obtained < CRED_CALLBACK) { - cred->username_cb = username_cb; - cred->username_obtained = CRED_CALLBACK; - return true; - } - - return false; -} - -_PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, - const char *bind_dn) -{ - cred->bind_dn = talloc_strdup(cred, bind_dn); - return true; -} - -/** - * Obtain the BIND DN for this credentials context. - * @param cred credentials context - * @retval The username set on this context. - * @note Return value will be NULL if not specified explictly - */ -_PUBLIC_ const char *cli_credentials_get_bind_dn(struct cli_credentials *cred) -{ - return cred->bind_dn; -} - - -/** - * Obtain the client principal for this credentials context. - * @param cred credentials context - * @retval The username set on this context. - * @note Return value will never be NULL except by programmer error. - */ -const char *cli_credentials_get_principal_and_obtained(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, enum credentials_obtained *obtained) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - if (cred->principal_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->principal = cred->principal_cb(cred); - cred->callback_running = false; - cred->principal_obtained = CRED_SPECIFIED; - cli_credentials_invalidate_ccache(cred, cred->principal_obtained); - } - - if (cred->principal_obtained < cred->username_obtained - || cred->principal_obtained < MAX(cred->domain_obtained, cred->realm_obtained)) { - if (cred->domain_obtained > cred->realm_obtained) { - *obtained = MIN(cred->domain_obtained, cred->username_obtained); - return talloc_asprintf(mem_ctx, "%s@%s", - cli_credentials_get_username(cred), - cli_credentials_get_domain(cred)); - } else { - *obtained = MIN(cred->domain_obtained, cred->username_obtained); - return talloc_asprintf(mem_ctx, "%s@%s", - cli_credentials_get_username(cred), - cli_credentials_get_realm(cred)); - } - } - *obtained = cred->principal_obtained; - return talloc_reference(mem_ctx, cred->principal); -} - -/** - * Obtain the client principal for this credentials context. - * @param cred credentials context - * @retval The username set on this context. - * @note Return value will never be NULL except by programmer error. - */ -_PUBLIC_ const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx) -{ - enum credentials_obtained obtained; - return cli_credentials_get_principal_and_obtained(cred, mem_ctx, &obtained); -} - -bool cli_credentials_set_principal(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - if (obtained >= cred->principal_obtained) { - cred->principal = talloc_strdup(cred, val); - cred->principal_obtained = obtained; - cli_credentials_invalidate_ccache(cred, cred->principal_obtained); - return true; - } - - return false; -} - -/* Set a callback to get the principal. This could be a popup dialog, - * a terminal prompt or similar. */ -bool cli_credentials_set_principal_callback(struct cli_credentials *cred, - const char *(*principal_cb) (struct cli_credentials *)) -{ - if (cred->principal_obtained < CRED_CALLBACK) { - cred->principal_cb = principal_cb; - cred->principal_obtained = CRED_CALLBACK; - return true; - } - - return false; -} - -/* Some of our tools are 'anonymous by default'. This is a single - * function to determine if authentication has been explicitly - * requested */ - -_PUBLIC_ bool cli_credentials_authentication_requested(struct cli_credentials *cred) -{ - if (cred->bind_dn) { - return true; - } - - if (cli_credentials_is_anonymous(cred)){ - return false; - } - - if (cred->principal_obtained >= CRED_SPECIFIED) { - return true; - } - if (cred->username_obtained >= CRED_SPECIFIED) { - return true; - } - - if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { - return true; - } - - return false; -} - -/** - * Obtain the password for this credentials context. - * @param cred credentials context - * @retval If set, the cleartext password, otherwise NULL - */ -_PUBLIC_ const char *cli_credentials_get_password(struct cli_credentials *cred) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - if (cred->password_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->password = cred->password_cb(cred); - cred->callback_running = false; - cred->password_obtained = CRED_CALLBACK_RESULT; - cli_credentials_invalidate_ccache(cred, cred->password_obtained); - } - - return cred->password; -} - -/* Set a password on the credentials context, including an indication - * of 'how' the password was obtained */ - -_PUBLIC_ bool cli_credentials_set_password(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - if (obtained >= cred->password_obtained) { - cred->password = talloc_strdup(cred, val); - cred->password_obtained = obtained; - cli_credentials_invalidate_ccache(cred, cred->password_obtained); - - cred->nt_hash = NULL; - cred->lm_response = data_blob(NULL, 0); - cred->nt_response = data_blob(NULL, 0); - return true; - } - - return false; -} - -_PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred, - const char *(*password_cb) (struct cli_credentials *)) -{ - if (cred->password_obtained < CRED_CALLBACK) { - cred->password_cb = password_cb; - cred->password_obtained = CRED_CALLBACK; - cli_credentials_invalidate_ccache(cred, cred->password_obtained); - return true; - } - - return false; -} - -/** - * Obtain the 'old' password for this credentials context (used for join accounts). - * @param cred credentials context - * @retval If set, the cleartext password, otherwise NULL - */ -const char *cli_credentials_get_old_password(struct cli_credentials *cred) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - return cred->old_password; -} - -bool cli_credentials_set_old_password(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - cred->old_password = talloc_strdup(cred, val); - return true; -} - -/** - * Obtain the password, in the form MD4(unicode(password)) for this credentials context. - * - * Sometimes we only have this much of the password, while the rest of - * the time this call avoids calling E_md4hash themselves. - * - * @param cred credentials context - * @retval If set, the cleartext password, otherwise NULL - */ -_PUBLIC_ const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, - TALLOC_CTX *mem_ctx) -{ - const char *password = cli_credentials_get_password(cred); - - if (password) { - struct samr_Password *nt_hash = talloc(mem_ctx, struct samr_Password); - if (!nt_hash) { - return NULL; - } - - E_md4hash(password, nt_hash->hash); - - return nt_hash; - } else { - return cred->nt_hash; - } -} - -/** - * Obtain the 'short' or 'NetBIOS' domain for this credentials context. - * @param cred credentials context - * @retval The domain set on this context. - * @note Return value will never be NULL except by programmer error. - */ -_PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - if (cred->domain_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->domain = cred->domain_cb(cred); - cred->callback_running = false; - cred->domain_obtained = CRED_SPECIFIED; - cli_credentials_invalidate_ccache(cred, cred->domain_obtained); - } - - return cred->domain; -} - - -_PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - if (obtained >= cred->domain_obtained) { - /* it is important that the domain be in upper case, - * particularly for the sensitive NTLMv2 - * calculations */ - cred->domain = strupper_talloc(cred, val); - cred->domain_obtained = obtained; - cli_credentials_invalidate_ccache(cred, cred->domain_obtained); - return true; - } - - return false; -} - -bool cli_credentials_set_domain_callback(struct cli_credentials *cred, - const char *(*domain_cb) (struct cli_credentials *)) -{ - if (cred->domain_obtained < CRED_CALLBACK) { - cred->domain_cb = domain_cb; - cred->domain_obtained = CRED_CALLBACK; - return true; - } - - return false; -} - -/** - * Obtain the Kerberos realm for this credentials context. - * @param cred credentials context - * @retval The realm set on this context. - * @note Return value will never be NULL except by programmer error. - */ -_PUBLIC_ const char *cli_credentials_get_realm(struct cli_credentials *cred) -{ - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - if (cred->realm_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->realm = cred->realm_cb(cred); - cred->callback_running = false; - cred->realm_obtained = CRED_SPECIFIED; - cli_credentials_invalidate_ccache(cred, cred->realm_obtained); - } - - return cred->realm; -} - -/** - * Set the realm for this credentials context, and force it to - * uppercase for the sainity of our local kerberos libraries - */ -_PUBLIC_ bool cli_credentials_set_realm(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - if (obtained >= cred->realm_obtained) { - cred->realm = strupper_talloc(cred, val); - cred->realm_obtained = obtained; - cli_credentials_invalidate_ccache(cred, cred->realm_obtained); - return true; - } - - return false; -} - -bool cli_credentials_set_realm_callback(struct cli_credentials *cred, - const char *(*realm_cb) (struct cli_credentials *)) -{ - if (cred->realm_obtained < CRED_CALLBACK) { - cred->realm_cb = realm_cb; - cred->realm_obtained = CRED_CALLBACK; - return true; - } - - return false; -} - -/** - * Obtain the 'short' or 'NetBIOS' workstation name for this credentials context. - * - * @param cred credentials context - * @retval The workstation name set on this context. - * @note Return value will never be NULL except by programmer error. - */ -_PUBLIC_ const char *cli_credentials_get_workstation(struct cli_credentials *cred) -{ - if (cred->workstation_obtained == CRED_CALLBACK && - !cred->callback_running) { - cred->callback_running = true; - cred->workstation = cred->workstation_cb(cred); - cred->callback_running = false; - cred->workstation_obtained = CRED_SPECIFIED; - } - - return cred->workstation; -} - -_PUBLIC_ bool cli_credentials_set_workstation(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained) -{ - if (obtained >= cred->workstation_obtained) { - cred->workstation = talloc_strdup(cred, val); - cred->workstation_obtained = obtained; - return true; - } - - return false; -} - -bool cli_credentials_set_workstation_callback(struct cli_credentials *cred, - const char *(*workstation_cb) (struct cli_credentials *)) -{ - if (cred->workstation_obtained < CRED_CALLBACK) { - cred->workstation_cb = workstation_cb; - cred->workstation_obtained = CRED_CALLBACK; - return true; - } - - return false; -} - -/** - * Given a string, typically obtained from a -U argument, parse it into domain, username, realm and password fields - * - * The format accepted is [domain\\]user[%password] or user[@realm][%password] - * - * @param credentials Credentials structure on which to set the password - * @param data the string containing the username, password etc - * @param obtained This enum describes how 'specified' this password is - */ - -_PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained) -{ - char *uname, *p; - - if (strcmp("%",data) == 0) { - cli_credentials_set_anonymous(credentials); - return; - } - - uname = talloc_strdup(credentials, data); - if ((p = strchr_m(uname,'%'))) { - *p = 0; - cli_credentials_set_password(credentials, p+1, obtained); - } - - if ((p = strchr_m(uname,'@'))) { - cli_credentials_set_principal(credentials, uname, obtained); - *p = 0; - cli_credentials_set_realm(credentials, p+1, obtained); - return; - } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) { - *p = 0; - cli_credentials_set_domain(credentials, uname, obtained); - uname = p+1; - } - cli_credentials_set_username(credentials, uname, obtained); -} - -/** - * Given a a credentials structure, print it as a string - * - * The format output is [domain\\]user[%password] or user[@realm][%password] - * - * @param credentials Credentials structure on which to set the password - * @param mem_ctx The memory context to place the result on - */ - -_PUBLIC_ const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx) -{ - const char *bind_dn = cli_credentials_get_bind_dn(credentials); - const char *domain; - const char *username; - const char *name; - - if (bind_dn) { - name = talloc_reference(mem_ctx, bind_dn); - } else { - cli_credentials_get_ntlm_username_domain(credentials, mem_ctx, &username, &domain); - if (domain && domain[0]) { - name = talloc_asprintf(mem_ctx, "%s\\%s", - domain, username); - } else { - name = talloc_asprintf(mem_ctx, "%s", - username); - } - } - return name; -} - -/** - * Specifies default values for domain, workstation and realm - * from the smb.conf configuration file - * - * @param cred Credentials structure to fill in - */ -_PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, - struct loadparm_context *lp_ctx) -{ - cli_credentials_set_username(cred, "", CRED_UNINITIALISED); - cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED); - cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_UNINITIALISED); - cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_UNINITIALISED); -} - -/** - * Guess defaults for credentials from environment variables, - * and from the configuration file - * - * @param cred Credentials structure to fill in - */ -_PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred, - struct loadparm_context *lp_ctx) -{ - char *p; - const char *error_string; - - if (lp_ctx != NULL) { - cli_credentials_set_conf(cred, lp_ctx); - } - - if (getenv("LOGNAME")) { - cli_credentials_set_username(cred, getenv("LOGNAME"), CRED_GUESS_ENV); - } - - if (getenv("USER")) { - cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV); - if ((p = strchr_m(getenv("USER"),'%'))) { - memset(p,0,strlen(cred->password)); - } - } - - if (getenv("PASSWD")) { - cli_credentials_set_password(cred, getenv("PASSWD"), CRED_GUESS_ENV); - } - - if (getenv("PASSWD_FD")) { - cli_credentials_parse_password_fd(cred, atoi(getenv("PASSWD_FD")), - CRED_GUESS_FILE); - } - - p = getenv("PASSWD_FILE"); - if (p && p[0]) { - cli_credentials_parse_password_file(cred, p, CRED_GUESS_FILE); - } - - if (cli_credentials_get_kerberos_state(cred) != CRED_DONT_USE_KERBEROS) { - cli_credentials_set_ccache(cred, lp_ctx, NULL, CRED_GUESS_FILE, - &error_string); - } -} - -/** - * Attach NETLOGON credentials for use with SCHANNEL - */ - -_PUBLIC_ void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, - struct netlogon_creds_CredentialState *netlogon_creds) -{ - cred->netlogon_creds = talloc_reference(cred, netlogon_creds); -} - -/** - * Return attached NETLOGON credentials - */ - -struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred) -{ - return cred->netlogon_creds; -} - -/** - * Set NETLOGON secure channel type - */ - -_PUBLIC_ void cli_credentials_set_secure_channel_type(struct cli_credentials *cred, - enum netr_SchannelType secure_channel_type) -{ - cred->secure_channel_type = secure_channel_type; -} - -/** - * Return NETLOGON secure chanel type - */ - -_PUBLIC_ time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred) -{ - return cred->password_last_changed_time; -} - -/** - * Set NETLOGON secure channel type - */ - -_PUBLIC_ void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred, - time_t last_changed_time) -{ - cred->password_last_changed_time = last_changed_time; -} - -/** - * Return NETLOGON secure chanel type - */ - -_PUBLIC_ enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred) -{ - return cred->secure_channel_type; -} - -/** - * Fill in a credentials structure as the anonymous user - */ -_PUBLIC_ void cli_credentials_set_anonymous(struct cli_credentials *cred) -{ - cli_credentials_set_username(cred, "", CRED_SPECIFIED); - cli_credentials_set_domain(cred, "", CRED_SPECIFIED); - cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); - cli_credentials_set_realm(cred, NULL, CRED_SPECIFIED); - cli_credentials_set_workstation(cred, "", CRED_UNINITIALISED); -} - -/** - * Describe a credentials context as anonymous or authenticated - * @retval true if anonymous, false if a username is specified - */ - -_PUBLIC_ bool cli_credentials_is_anonymous(struct cli_credentials *cred) -{ - const char *username; - - /* if bind dn is set it's not anonymous */ - if (cred->bind_dn) { - return false; - } - - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, - cred->machine_account_pending_lp_ctx); - } - - username = cli_credentials_get_username(cred); - - /* Yes, it is deliberate that we die if we have a NULL pointer - * here - anonymous is "", not NULL, which is 'never specified, - * never guessed', ie programmer bug */ - if (!username[0]) { - return true; - } - - return false; -} - -/** - * Mark the current password for a credentials struct as wrong. This will - * cause the password to be prompted again (if a callback is set). - * - * This will decrement the number of times the password can be tried. - * - * @retval whether the credentials struct is finished - */ -_PUBLIC_ bool cli_credentials_wrong_password(struct cli_credentials *cred) -{ - if (cred->password_obtained != CRED_CALLBACK_RESULT) { - return false; - } - - cred->password_obtained = CRED_CALLBACK; - - cred->tries--; - - return (cred->tries > 0); -} - -_PUBLIC_ void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, - const char **username, - const char **domain) -{ - if (cred->principal_obtained > cred->username_obtained) { - *domain = talloc_strdup(mem_ctx, ""); - *username = cli_credentials_get_principal(cred, mem_ctx); - } else { - *domain = cli_credentials_get_domain(cred); - *username = cli_credentials_get_username(cred); - } -} - -/** - * Read a named file, and parse it for username, domain, realm and password - * - * @param credentials Credentials structure on which to set the password - * @param file a named file to read the details from - * @param obtained This enum describes how 'specified' this password is - */ - -_PUBLIC_ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained) -{ - uint16_t len = 0; - char *ptr, *val, *param; - char **lines; - int i, numlines; - - lines = file_lines_load(file, &numlines, 0, NULL); - - if (lines == NULL) - { - /* fail if we can't open the credentials file */ - d_printf("ERROR: Unable to open credentials file!\n"); - return false; - } - - for (i = 0; i < numlines; i++) { - len = strlen(lines[i]); - - if (len == 0) - continue; - - /* break up the line into parameter & value. - * will need to eat a little whitespace possibly */ - param = lines[i]; - if (!(ptr = strchr_m (lines[i], '='))) - continue; - - val = ptr+1; - *ptr = '\0'; - - /* eat leading white space */ - while ((*val!='\0') && ((*val==' ') || (*val=='\t'))) - val++; - - if (strwicmp("password", param) == 0) { - cli_credentials_set_password(cred, val, obtained); - } else if (strwicmp("username", param) == 0) { - cli_credentials_set_username(cred, val, obtained); - } else if (strwicmp("domain", param) == 0) { - cli_credentials_set_domain(cred, val, obtained); - } else if (strwicmp("realm", param) == 0) { - cli_credentials_set_realm(cred, val, obtained); - } - memset(lines[i], 0, len); - } - - talloc_free(lines); - - return true; -} - -/** - * Read a named file, and parse it for a password - * - * @param credentials Credentials structure on which to set the password - * @param file a named file to read the password from - * @param obtained This enum describes how 'specified' this password is - */ - -_PUBLIC_ bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained) -{ - int fd = open(file, O_RDONLY, 0); - bool ret; - - if (fd < 0) { - fprintf(stderr, "Error opening password file %s: %s\n", - file, strerror(errno)); - return false; - } - - ret = cli_credentials_parse_password_fd(credentials, fd, obtained); - - close(fd); - - return ret; -} - - -/** - * Read a file descriptor, and parse it for a password (eg from a file or stdin) - * - * @param credentials Credentials structure on which to set the password - * @param fd open file descriptor to read the password from - * @param obtained This enum describes how 'specified' this password is - */ - -_PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credentials, - int fd, enum credentials_obtained obtained) -{ - char *p; - char pass[128]; - - for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */ - p && p - pass < sizeof(pass);) { - switch (read(fd, p, 1)) { - case 1: - if (*p != '\n' && *p != '\0') { - *++p = '\0'; /* advance p, and null-terminate pass */ - break; - } - /* fall through */ - case 0: - if (p - pass) { - *p = '\0'; /* null-terminate it, just in case... */ - p = NULL; /* then force the loop condition to become false */ - break; - } else { - fprintf(stderr, "Error reading password from file descriptor %d: %s\n", fd, "empty password\n"); - return false; - } - - default: - fprintf(stderr, "Error reading password from file descriptor %d: %s\n", - fd, strerror(errno)); - return false; - } - } - - cli_credentials_set_password(credentials, pass, obtained); - return true; -} - - diff --git a/source4/auth/credentials/credentials.h b/source4/auth/credentials/credentials.h deleted file mode 100644 index f8fa2f864b..0000000000 --- a/source4/auth/credentials/credentials.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - samba -- Unix SMB/CIFS implementation. - - Client credentials structure - - Copyright (C) Jelmer Vernooij 2004-2006 - Copyright (C) Andrew Bartlett 2005 - - 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 . -*/ -#ifndef __CREDENTIALS_H__ -#define __CREDENTIALS_H__ - -#include "../lib/util/data_blob.h" -#include "librpc/gen_ndr/misc.h" - -struct ccache_container; -struct tevent_context; - -/* In order of priority */ -enum credentials_obtained { - CRED_UNINITIALISED = 0, /* We don't even have a guess yet */ - CRED_CALLBACK, /* Callback should be used to obtain value */ - CRED_GUESS_ENV, /* Current value should be used, which was guessed */ - CRED_GUESS_FILE, /* A guess from a file (or file pointed at in env variable) */ - CRED_CALLBACK_RESULT, /* Value was obtained from a callback */ - CRED_SPECIFIED /* Was explicitly specified on the command-line */ -}; - -enum credentials_use_kerberos { - CRED_AUTO_USE_KERBEROS = 0, /* Default, we try kerberos if available */ - CRED_DONT_USE_KERBEROS, /* Sometimes trying kerberos just does 'bad things', so don't */ - CRED_MUST_USE_KERBEROS /* Sometimes administrators are parinoid, so always do kerberos */ -}; - -enum credentials_krb_forwardable { - CRED_AUTO_KRB_FORWARDABLE = 0, /* Default, follow library defaults */ - CRED_NO_KRB_FORWARDABLE, /* not forwardable */ - CRED_FORCE_KRB_FORWARDABLE /* forwardable */ -}; - -#define CLI_CRED_NTLM2 0x01 -#define CLI_CRED_NTLMv2_AUTH 0x02 -#define CLI_CRED_LANMAN_AUTH 0x04 -#define CLI_CRED_NTLM_AUTH 0x08 -#define CLI_CRED_CLEAR_AUTH 0x10 /* TODO: Push cleartext auth with this flag */ - -struct cli_credentials { - enum credentials_obtained workstation_obtained; - enum credentials_obtained username_obtained; - enum credentials_obtained password_obtained; - enum credentials_obtained domain_obtained; - enum credentials_obtained realm_obtained; - enum credentials_obtained ccache_obtained; - enum credentials_obtained client_gss_creds_obtained; - enum credentials_obtained principal_obtained; - enum credentials_obtained keytab_obtained; - enum credentials_obtained server_gss_creds_obtained; - - /* Threshold values (essentially a MAX() over a number of the - * above) for the ccache and GSS credentials, to ensure we - * regenerate/pick correctly */ - - enum credentials_obtained ccache_threshold; - enum credentials_obtained client_gss_creds_threshold; - - const char *workstation; - const char *username; - const char *password; - const char *old_password; - const char *domain; - const char *realm; - const char *principal; - char *salt_principal; - char *impersonate_principal; - char *self_service; - char *target_service; - - const char *bind_dn; - - /* Allows authentication from a keytab or similar */ - struct samr_Password *nt_hash; - - /* Allows NTLM pass-though authentication */ - DATA_BLOB lm_response; - DATA_BLOB nt_response; - - struct ccache_container *ccache; - struct gssapi_creds_container *client_gss_creds; - struct keytab_container *keytab; - struct gssapi_creds_container *server_gss_creds; - - const char *(*workstation_cb) (struct cli_credentials *); - const char *(*password_cb) (struct cli_credentials *); - const char *(*username_cb) (struct cli_credentials *); - const char *(*domain_cb) (struct cli_credentials *); - const char *(*realm_cb) (struct cli_credentials *); - const char *(*principal_cb) (struct cli_credentials *); - - /* Private handle for the callback routines to use */ - void *priv_data; - - struct netlogon_creds_CredentialState *netlogon_creds; - enum netr_SchannelType secure_channel_type; - int kvno; - time_t password_last_changed_time; - - struct smb_krb5_context *smb_krb5_context; - - /* We are flagged to get machine account details from the - * secrets.ldb when we are asked for a username or password */ - bool machine_account_pending; - struct loadparm_context *machine_account_pending_lp_ctx; - - /* Is this a machine account? */ - bool machine_account; - - /* Should we be trying to use kerberos? */ - enum credentials_use_kerberos use_kerberos; - - /* Should we get a forwardable ticket? */ - enum credentials_krb_forwardable krb_forwardable; - - /* gensec features which should be used for connections */ - uint32_t gensec_features; - - /* Number of retries left before bailing out */ - int tries; - - /* Whether any callback is currently running */ - bool callback_running; -}; - -struct ldb_context; -struct ldb_message; -struct loadparm_context; -struct ccache_container; - -struct gssapi_creds_container; - -const char *cli_credentials_get_workstation(struct cli_credentials *cred); -bool cli_credentials_set_workstation(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained); -bool cli_credentials_is_anonymous(struct cli_credentials *cred); -struct cli_credentials *cli_credentials_init(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); -void cli_credentials_get_ntlm_username_domain(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, - const char **username, - const char **domain); -NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, - int *flags, - DATA_BLOB challenge, DATA_BLOB target_info, - DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, - 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); -int cli_credentials_get_krb5_context(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct smb_krb5_context **smb_krb5_context); -int cli_credentials_get_ccache(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - struct ccache_container **ccc, - const char **error_string); -int cli_credentials_get_named_ccache(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - char *ccache_name, - struct ccache_container **ccc, const char **error_string); -int cli_credentials_get_keytab(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct keytab_container **_ktc); -const char *cli_credentials_get_domain(struct cli_credentials *cred); -struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred); -void cli_credentials_set_machine_account_pending(struct cli_credentials *cred, - struct loadparm_context *lp_ctx); -void cli_credentials_set_conf(struct cli_credentials *cred, - struct loadparm_context *lp_ctx); -const char *cli_credentials_get_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx); -int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct gssapi_creds_container **_gcc); -int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - struct gssapi_creds_container **_gcc, - const char **error_string); -void cli_credentials_set_kerberos_state(struct cli_credentials *creds, - enum credentials_use_kerberos use_kerberos); -void cli_credentials_set_krb_forwardable(struct cli_credentials *creds, - enum credentials_krb_forwardable krb_forwardable); -bool cli_credentials_set_domain(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained); -bool cli_credentials_set_domain_callback(struct cli_credentials *cred, - const char *(*domain_cb) (struct cli_credentials *)); -bool cli_credentials_set_username(struct cli_credentials *cred, - const char *val, enum credentials_obtained obtained); -bool cli_credentials_set_username_callback(struct cli_credentials *cred, - const char *(*username_cb) (struct cli_credentials *)); -bool cli_credentials_set_principal(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained); -bool cli_credentials_set_principal_callback(struct cli_credentials *cred, - const char *(*principal_cb) (struct cli_credentials *)); -bool cli_credentials_set_password(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained); -struct cli_credentials *cli_credentials_init_anon(TALLOC_CTX *mem_ctx); -void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained); -const struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, - TALLOC_CTX *mem_ctx); -bool cli_credentials_set_realm(struct cli_credentials *cred, - const char *val, - enum credentials_obtained obtained); -void cli_credentials_set_secure_channel_type(struct cli_credentials *cred, - enum netr_SchannelType secure_channel_type); -void cli_credentials_set_password_last_changed_time(struct cli_credentials *cred, - time_t last_change_time); -void cli_credentials_set_netlogon_creds(struct cli_credentials *cred, - struct netlogon_creds_CredentialState *netlogon_creds); -NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, - struct smb_krb5_context *smb_krb5_context); -NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *serviceprincipal); -NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred, - struct loadparm_context *lp_ctx); -bool cli_credentials_authentication_requested(struct cli_credentials *cred); -void cli_credentials_guess(struct cli_credentials *cred, - struct loadparm_context *lp_ctx); -bool cli_credentials_set_bind_dn(struct cli_credentials *cred, - const char *bind_dn); -const char *cli_credentials_get_bind_dn(struct cli_credentials *cred); -bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, enum credentials_obtained obtained); -const char *cli_credentials_get_unparsed_name(struct cli_credentials *credentials, TALLOC_CTX *mem_ctx); -bool cli_credentials_set_password_callback(struct cli_credentials *cred, - const char *(*password_cb) (struct cli_credentials *)); -enum netr_SchannelType cli_credentials_get_secure_channel_type(struct cli_credentials *cred); -time_t cli_credentials_get_password_last_changed_time(struct cli_credentials *cred); -void cli_credentials_set_kvno(struct cli_credentials *cred, - int kvno); -bool cli_credentials_set_nt_hash(struct cli_credentials *cred, - const struct samr_Password *nt_hash, - enum credentials_obtained obtained); -bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, - const DATA_BLOB *lm_response, - const DATA_BLOB *nt_response, - enum credentials_obtained obtained); -int cli_credentials_set_keytab_name(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *keytab_name, - enum credentials_obtained obtained); -void cli_credentials_set_gensec_features(struct cli_credentials *creds, uint32_t gensec_features); -uint32_t cli_credentials_get_gensec_features(struct cli_credentials *creds); -int cli_credentials_set_ccache(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *name, - enum credentials_obtained obtained, - const char **error_string); -bool cli_credentials_parse_password_file(struct cli_credentials *credentials, const char *file, enum credentials_obtained obtained); -bool cli_credentials_parse_password_fd(struct cli_credentials *credentials, - int fd, enum credentials_obtained obtained); -void cli_credentials_invalidate_ccache(struct cli_credentials *cred, - enum credentials_obtained obtained); -void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal); -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); -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_krb_forwardable cli_credentials_get_krb_forwardable(struct cli_credentials *creds); -NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct ldb_context *ldb, - const char *base, - const char *filter, - char **error_string); - int cli_credentials_get_kvno(struct cli_credentials *cred); - - -#endif /* __CREDENTIALS_H__ */ diff --git a/source4/auth/credentials/credentials_krb5.c b/source4/auth/credentials/credentials_krb5.c deleted file mode 100644 index 7130e4164d..0000000000 --- a/source4/auth/credentials/credentials_krb5.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Handle user credentials (as regards krb5) - - Copyright (C) Jelmer Vernooij 2005 - Copyright (C) Tim Potter 2001 - Copyright (C) Andrew Bartlett 2005 - - 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 . -*/ - -#include "includes.h" -#include "system/kerberos.h" -#include "auth/kerberos/kerberos.h" -#include "auth/credentials/credentials.h" -#include "auth/credentials/credentials_proto.h" -#include "auth/credentials/credentials_krb5.h" -#include "auth/kerberos/kerberos_credentials.h" -#include "auth/kerberos/kerberos_util.h" -#include "param/param.h" - -_PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct smb_krb5_context **smb_krb5_context) -{ - int ret; - if (cred->smb_krb5_context) { - *smb_krb5_context = cred->smb_krb5_context; - return 0; - } - - ret = smb_krb5_init_context(cred, NULL, lp_ctx, - &cred->smb_krb5_context); - if (ret) { - cred->smb_krb5_context = NULL; - return ret; - } - *smb_krb5_context = cred->smb_krb5_context; - return 0; -} - -/* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(), - * otherwise we may still have references to the old smb_krb5_context in a credential cache etc - */ -_PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred, - struct smb_krb5_context *smb_krb5_context) -{ - if (smb_krb5_context == NULL) { - talloc_unlink(cred, cred->smb_krb5_context); - cred->smb_krb5_context = NULL; - return NT_STATUS_OK; - } - - if (!talloc_reference(cred, smb_krb5_context)) { - return NT_STATUS_NO_MEMORY; - } - cred->smb_krb5_context = smb_krb5_context; - return NT_STATUS_OK; -} - -static int cli_credentials_set_from_ccache(struct cli_credentials *cred, - struct ccache_container *ccache, - enum credentials_obtained obtained, - const char **error_string) -{ - - krb5_principal princ; - krb5_error_code ret; - char *name; - - if (cred->ccache_obtained > obtained) { - return 0; - } - - ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context, - ccache->ccache, &princ); - - if (ret) { - (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n", - smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, - ret, cred)); - return ret; - } - - ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name); - if (ret) { - (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n", - smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context, - ret, cred)); - return ret; - } - - cli_credentials_set_principal(cred, name, obtained); - - free(name); - - krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ); - - /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */ - cred->ccache_obtained = obtained; - - return 0; -} - -/* Free a memory ccache */ -static int free_mccache(struct ccache_container *ccc) -{ - krb5_cc_destroy(ccc->smb_krb5_context->krb5_context, ccc->ccache); - - return 0; -} - -/* Free a disk-based ccache */ -static int free_dccache(struct ccache_container *ccc) { - krb5_cc_close(ccc->smb_krb5_context->krb5_context, ccc->ccache); - - return 0; -} - -_PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *name, - enum credentials_obtained obtained, - const char **error_string) -{ - krb5_error_code ret; - krb5_principal princ; - struct ccache_container *ccc; - if (cred->ccache_obtained > obtained) { - return 0; - } - - ccc = talloc(cred, struct ccache_container); - if (!ccc) { - (*error_string) = error_message(ENOMEM); - return ENOMEM; - } - - ret = cli_credentials_get_krb5_context(cred, lp_ctx, - &ccc->smb_krb5_context); - if (ret) { - (*error_string) = error_message(ret); - talloc_free(ccc); - return ret; - } - if (!talloc_reference(ccc, ccc->smb_krb5_context)) { - talloc_free(ccc); - (*error_string) = error_message(ENOMEM); - return ENOMEM; - } - - if (name) { - ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache); - if (ret) { - (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n", - name, - smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context, - ret, ccc)); - talloc_free(ccc); - return ret; - } - } else { - ret = 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, - ret, ccc)); - talloc_free(ccc); - return ret; - } - } - - talloc_set_destructor(ccc, free_dccache); - - ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ); - - if (ret == 0) { - krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ); - ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string); - - if (ret) { - (*error_string) = error_message(ret); - return ret; - } - - cred->ccache = ccc; - cred->ccache_obtained = obtained; - talloc_steal(cred, ccc); - - cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); - return 0; - } - return 0; -} - - -static int cli_credentials_new_ccache(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - char *ccache_name, - struct ccache_container **_ccc, - const char **error_string) -{ - bool must_free_cc_name = false; - krb5_error_code ret; - struct ccache_container *ccc = talloc(cred, struct ccache_container); - if (!ccc) { - return ENOMEM; - } - - ret = cli_credentials_get_krb5_context(cred, lp_ctx, - &ccc->smb_krb5_context); - if (ret) { - talloc_free(ccc); - (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s", - error_message(ret)); - return ret; - } - if (!talloc_reference(ccc, ccc->smb_krb5_context)) { - talloc_free(ccc); - (*error_string) = strerror(ENOMEM); - return ENOMEM; - } - - 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; - } - } - - ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name, - &ccc->ccache); - 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; - } - - if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) { - talloc_set_destructor(ccc, free_mccache); - } else { - talloc_set_destructor(ccc, free_dccache); - } - - if (must_free_cc_name) { - talloc_free(ccache_name); - } - - *_ccc = ccc; - - return 0; -} - -_PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - char *ccache_name, - struct ccache_container **ccc, - const char **error_string) -{ - krb5_error_code ret; - enum credentials_obtained obtained; - - if (cred->machine_account_pending) { - cli_credentials_set_machine_account(cred, lp_ctx); - } - - if (cred->ccache_obtained >= cred->ccache_threshold && - cred->ccache_obtained > CRED_UNINITIALISED) { - time_t lifetime; - bool expired = false; - ret = krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context, - cred->ccache->ccache, &lifetime); - if (ret == KRB5_CC_END) { - /* If we have a particular ccache set, without - * an initial ticket, then assume there is a - * good reason */ - } else if (ret == 0) { - if (lifetime == 0) { - DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n", - cli_credentials_get_principal(cred, cred))); - expired = true; - } else if (lifetime < 300) { - DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n", - cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); - expired = true; - } - } else { - (*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n", - smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context, - ret, cred)); - return ret; - } - - DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n", - cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); - - if (!expired) { - *ccc = cred->ccache; - return 0; - } - } - if (cli_credentials_is_anonymous(cred)) { - (*error_string) = "Cannot get anonymous kerberos credentials"; - return EINVAL; - } - - ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string); - if (ret) { - return ret; - } - - ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string); - if (ret) { - return ret; - } - - ret = cli_credentials_set_from_ccache(cred, *ccc, - obtained, error_string); - - cred->ccache = *ccc; - cred->ccache_obtained = cred->principal_obtained; - if (ret) { - return ret; - } - cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained); - return 0; -} - -_PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - struct ccache_container **ccc, - const char **error_string) -{ - return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string); -} - -/* 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) -{ - if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { - talloc_unlink(cred, cred->client_gss_creds); - cred->client_gss_creds = NULL; - } - cred->client_gss_creds_obtained = CRED_UNINITIALISED; -} - -void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, - enum credentials_obtained obtained) -{ - /* If the caller just changed the username/password etc, then - * any cached credentials are now invalid */ - if (obtained >= cred->client_gss_creds_obtained) { - if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) { - talloc_unlink(cred, cred->client_gss_creds); - cred->client_gss_creds = NULL; - } - cred->client_gss_creds_obtained = CRED_UNINITIALISED; - } - /* Now that we know that the data is 'this specified', then - * don't allow something less 'known' to be returned as a - * ccache. Ie, if the username is on the command line, we - * don't want to later guess to use a file-based ccache */ - if (obtained > cred->client_gss_creds_threshold) { - cred->client_gss_creds_threshold = obtained; - } -} - -/* We have good reason to think this CCACHE is invalid. Blow it away */ -static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred) -{ - if (cred->ccache_obtained > CRED_UNINITIALISED) { - talloc_unlink(cred, cred->ccache); - cred->ccache = NULL; - } - cred->ccache_obtained = CRED_UNINITIALISED; - - cli_credentials_unconditionally_invalidate_client_gss_creds(cred); -} - -_PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred, - enum credentials_obtained obtained) -{ - /* If the caller just changed the username/password etc, then - * any cached credentials are now invalid */ - if (obtained >= cred->ccache_obtained) { - if (cred->ccache_obtained > CRED_UNINITIALISED) { - talloc_unlink(cred, cred->ccache); - cred->ccache = NULL; - } - cred->ccache_obtained = CRED_UNINITIALISED; - } - /* Now that we know that the data is 'this specified', then - * don't allow something less 'known' to be returned as a - * ccache. i.e, if the username is on the command line, we - * don't want to later guess to use a file-based ccache */ - if (obtained > cred->ccache_threshold) { - cred->ccache_threshold = obtained; - } - - cli_credentials_invalidate_client_gss_creds(cred, - obtained); -} - -static int free_gssapi_creds(struct gssapi_creds_container *gcc) -{ - OM_uint32 min_stat, maj_stat; - maj_stat = gss_release_cred(&min_stat, &gcc->creds); - return 0; -} - -_PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred, - struct tevent_context *event_ctx, - struct loadparm_context *lp_ctx, - struct gssapi_creds_container **_gcc, - const char **error_string) -{ - int ret = 0; - OM_uint32 maj_stat, min_stat; - struct gssapi_creds_container *gcc; - struct ccache_container *ccache; - gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; - krb5_enctype *etypes = NULL; - - if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold && - cred->client_gss_creds_obtained > CRED_UNINITIALISED) { - bool expired = false; - OM_uint32 lifetime = 0; - gss_cred_usage_t usage = 0; - maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds, - NULL, &lifetime, &usage, NULL); - if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) { - DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred))); - expired = true; - } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) { - DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime)); - expired = true; - } else if (maj_stat != GSS_S_COMPLETE) { - *error_string = talloc_asprintf(cred, "inquiry of credential lifefime via GSSAPI gss_inquire_cred failed: %s\n", - gssapi_error_string(cred, maj_stat, min_stat, NULL)); - return EINVAL; - } - if (expired) { - cli_credentials_unconditionally_invalidate_client_gss_creds(cred); - } else { - DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n", - cli_credentials_get_principal(cred, cred), (unsigned int)lifetime)); - - *_gcc = cred->client_gss_creds; - return 0; - } - } - - ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, - &ccache, error_string); - if (ret) { - if (cli_credentials_get_kerberos_state(cred) == CRED_MUST_USE_KERBEROS) { - DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", error_message(ret))); - } else { - DEBUG(4, ("Failed to get kerberos credentials: %s\n", error_message(ret))); - } - return ret; - } - - gcc = talloc(cred, struct gssapi_creds_container); - if (!gcc) { - (*error_string) = error_message(ENOMEM); - return ENOMEM; - } - - maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, - &gcc->creds); - if ((maj_stat == GSS_S_FAILURE) && (min_stat == (OM_uint32)KRB5_CC_END || min_stat == (OM_uint32) KRB5_CC_NOTFOUND)) { - /* This CCACHE is no good. Ensure we don't use it again */ - cli_credentials_unconditionally_invalidate_ccache(cred); - - /* Now try again to get a ccache */ - ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx, - &ccache, error_string); - if (ret) { - DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret))); - return ret; - } - - maj_stat = gss_krb5_import_cred(&min_stat, ccache->ccache, NULL, NULL, - &gcc->creds); - - } - - if (maj_stat) { - talloc_free(gcc); - if (min_stat) { - ret = min_stat; - } else { - ret = EINVAL; - } - (*error_string) = talloc_asprintf(cred, "gss_krb5_import_cred failed: %s", error_message(ret)); - return ret; - } - - /* - * transfer the enctypes from the smb_krb5_context to the gssapi layer - * - * We use 'our' smb_krb5_context to do the AS-REQ and it is possible - * to configure the enctypes via the krb5.conf. - * - * And the gss_init_sec_context() creates it's own krb5_context and - * the TGS-REQ had all enctypes in it and only the ones configured - * and used for the AS-REQ, so it wasn't possible to disable the usage - * of AES keys. - */ - min_stat = krb5_get_default_in_tkt_etypes(ccache->smb_krb5_context->krb5_context, - KRB5_PDU_NONE, - &etypes); - if (min_stat == 0) { - OM_uint32 num_ktypes; - - for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++); - - maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds, - num_ktypes, - (int32_t *) etypes); - krb5_xfree (etypes); - if (maj_stat) { - talloc_free(gcc); - if (min_stat) { - ret = min_stat; - } else { - ret = EINVAL; - } - (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret)); - return ret; - } - } - - /* don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG */ - maj_stat = gss_set_cred_option(&min_stat, &gcc->creds, - GSS_KRB5_CRED_NO_CI_FLAGS_X, - &empty_buffer); - if (maj_stat) { - talloc_free(gcc); - if (min_stat) { - ret = min_stat; - } else { - ret = EINVAL; - } - (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret)); - return ret; - } - - cred->client_gss_creds_obtained = cred->ccache_obtained; - talloc_set_destructor(gcc, free_gssapi_creds); - cred->client_gss_creds = gcc; - *_gcc = gcc; - return 0; -} - -/** - Set a gssapi cred_id_t into the credentials system. (Client case) - - This grabs the credentials both 'intact' and getting the krb5 - ccache out of it. This routine can be generalised in future for - the case where we deal with GSSAPI mechs other than krb5. - - On sucess, the caller must not free gssapi_cred, as it now belongs - to the credentials system. -*/ - - int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - gss_cred_id_t gssapi_cred, - enum credentials_obtained obtained, - const char **error_string) -{ - int ret; - OM_uint32 maj_stat, min_stat; - struct ccache_container *ccc; - struct gssapi_creds_container *gcc; - if (cred->client_gss_creds_obtained > obtained) { - return 0; - } - - gcc = talloc(cred, struct gssapi_creds_container); - if (!gcc) { - (*error_string) = error_message(ENOMEM); - return ENOMEM; - } - - ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string); - if (ret != 0) { - return ret; - } - - maj_stat = gss_krb5_copy_ccache(&min_stat, - gssapi_cred, ccc->ccache); - if (maj_stat) { - if (min_stat) { - ret = min_stat; - } else { - ret = EINVAL; - } - if (ret) { - (*error_string) = error_message(ENOMEM); - } - } - - if (ret == 0) { - ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string); - } - cred->ccache = ccc; - cred->ccache_obtained = obtained; - if (ret == 0) { - gcc->creds = gssapi_cred; - talloc_set_destructor(gcc, free_gssapi_creds); - - /* set the clinet_gss_creds_obtained here, as it just - got set to UNINITIALISED by the calls above */ - cred->client_gss_creds_obtained = obtained; - cred->client_gss_creds = gcc; - } - return ret; -} - -/* Get the keytab (actually, a container containing the krb5_keytab) - * attached to this context. If this hasn't been done or set before, - * it will be generated from the password. - */ -_PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct keytab_container **_ktc) -{ - krb5_error_code ret; - struct keytab_container *ktc; - struct smb_krb5_context *smb_krb5_context; - TALLOC_CTX *mem_ctx; - - if (cred->keytab_obtained >= (MAX(cred->principal_obtained, - cred->username_obtained))) { - *_ktc = cred->keytab; - return 0; - } - - if (cli_credentials_is_anonymous(cred)) { - return EINVAL; - } - - ret = cli_credentials_get_krb5_context(cred, lp_ctx, - &smb_krb5_context); - if (ret) { - return ret; - } - - mem_ctx = talloc_new(cred); - if (!mem_ctx) { - return ENOMEM; - } - - ret = smb_krb5_create_memory_keytab(mem_ctx, cred, - smb_krb5_context, &ktc); - if (ret) { - talloc_free(mem_ctx); - return ret; - } - - cred->keytab_obtained = (MAX(cred->principal_obtained, - cred->username_obtained)); - - talloc_steal(cred, ktc); - cred->keytab = ktc; - *_ktc = cred->keytab; - talloc_free(mem_ctx); - return ret; -} - -/* Given the name of a keytab (presumably in the format - * FILE:/etc/krb5.keytab), open it and attach it */ - -_PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *keytab_name, - enum credentials_obtained obtained) -{ - krb5_error_code ret; - struct keytab_container *ktc; - struct smb_krb5_context *smb_krb5_context; - TALLOC_CTX *mem_ctx; - - if (cred->keytab_obtained >= obtained) { - return 0; - } - - ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context); - if (ret) { - return ret; - } - - mem_ctx = talloc_new(cred); - if (!mem_ctx) { - return ENOMEM; - } - - ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context, - keytab_name, &ktc); - if (ret) { - return ret; - } - - cred->keytab_obtained = obtained; - - talloc_steal(cred, ktc); - cred->keytab = ktc; - talloc_free(mem_ctx); - - return ret; -} - -/* Get server gss credentials (in gsskrb5, this means the keytab) */ - -_PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct gssapi_creds_container **_gcc) -{ - int ret = 0; - OM_uint32 maj_stat, min_stat; - struct gssapi_creds_container *gcc; - struct keytab_container *ktc; - struct smb_krb5_context *smb_krb5_context; - TALLOC_CTX *mem_ctx; - krb5_principal princ; - const char *error_string; - enum credentials_obtained obtained; - - mem_ctx = talloc_new(cred); - if (!mem_ctx) { - return ENOMEM; - } - - ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context); - if (ret) { - return ret; - } - - ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string); - if (ret) { - DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n", - error_string)); - talloc_free(mem_ctx); - return ret; - } - - if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) { - talloc_free(mem_ctx); - *_gcc = cred->server_gss_creds; - return 0; - } - - ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc); - if (ret) { - DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret))); - return ret; - } - - gcc = talloc(cred, struct gssapi_creds_container); - if (!gcc) { - talloc_free(mem_ctx); - return ENOMEM; - } - - /* This creates a GSSAPI cred_id_t with the principal and keytab set */ - maj_stat = gss_krb5_import_cred(&min_stat, NULL, princ, ktc->keytab, - &gcc->creds); - if (maj_stat) { - if (min_stat) { - ret = min_stat; - } else { - ret = EINVAL; - } - } - if (ret == 0) { - cred->server_gss_creds_obtained = cred->keytab_obtained; - talloc_set_destructor(gcc, free_gssapi_creds); - cred->server_gss_creds = gcc; - *_gcc = gcc; - } - talloc_free(mem_ctx); - return ret; -} - -/** - * Set Kerberos KVNO - */ - -_PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred, - int kvno) -{ - cred->kvno = kvno; -} - -/** - * Return Kerberos KVNO - */ - -_PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred) -{ - return cred->kvno; -} - - -const char *cli_credentials_get_salt_principal(struct cli_credentials *cred) -{ - return cred->salt_principal; -} - -_PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal) -{ - talloc_free(cred->salt_principal); - cred->salt_principal = talloc_strdup(cred, principal); -} - -/* The 'impersonate_principal' is used to allow one Kerberos principal - * (and it's associated keytab etc) to impersonate another. The - * ability to do this is controlled by the KDC, but it is generally - * permitted to impersonate anyone to yourself. This allows any - * member of the domain to get the groups of a user. This is also - * known as S4U2Self */ - -_PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred) -{ - return cred->impersonate_principal; -} - -/* - * The 'self_service' is the service principal that - * represents the same object (by its objectSid) - * as the client principal (typically our machine account). - * When trying to impersonate 'impersonate_principal' with - * S4U2Self. - */ -_PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred) -{ - return cred->self_service; -} - -_PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred, - const char *principal, - const char *self_service) -{ - talloc_free(cred->impersonate_principal); - cred->impersonate_principal = talloc_strdup(cred, principal); - talloc_free(cred->self_service); - cred->self_service = talloc_strdup(cred, self_service); - cli_credentials_set_kerberos_state(cred, CRED_MUST_USE_KERBEROS); -} - -/* - * when impersonating for S4U2proxy we need to set the target principal. - * Similarly, we may only be authorized to do general impersonation to - * some particular services. - * - * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT - * - * NULL means that tickets will be obtained for the krbtgt service. -*/ - -const char *cli_credentials_get_target_service(struct cli_credentials *cred) -{ - return cred->target_service; -} - -_PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service) -{ - talloc_free(cred->target_service); - cred->target_service = talloc_strdup(cred, target_service); -} - diff --git a/source4/auth/credentials/credentials_krb5.h b/source4/auth/credentials/credentials_krb5.h deleted file mode 100644 index 36bf03d5eb..0000000000 --- a/source4/auth/credentials/credentials_krb5.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - samba -- Unix SMB/CIFS implementation. - - Client credentials structure - - Copyright (C) Jelmer Vernooij 2004-2006 - Copyright (C) Andrew Bartlett 2005 - - 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 . -*/ - -#ifndef __CREDENTIALS_KRB5_H__ -#define __CREDENTIALS_KRB5_H__ - -#include -#include -#include - -struct gssapi_creds_container { - gss_cred_id_t creds; -}; - -/* Manually prototyped here to avoid needing gss headers in most callers */ -int cli_credentials_set_client_gss_creds(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - gss_cred_id_t gssapi_cred, - enum credentials_obtained obtained, - const char **error_string); - -/* Manually prototyped here to avoid needing krb5 headers in most callers */ -krb5_error_code principal_from_credentials(TALLOC_CTX *parent_ctx, - struct cli_credentials *credentials, - struct smb_krb5_context *smb_krb5_context, - krb5_principal *princ, - enum credentials_obtained *obtained, - const char **error_string); -krb5_error_code impersonate_principal_from_credentials(TALLOC_CTX *parent_ctx, - struct cli_credentials *credentials, - struct smb_krb5_context *smb_krb5_context, - krb5_principal *princ, - const char **error_string); - -void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred, - enum credentials_obtained obtained); - -#endif /* __CREDENTIALS_KRB5_H__ */ diff --git a/source4/auth/credentials/credentials_ntlm.c b/source4/auth/credentials/credentials_ntlm.c deleted file mode 100644 index 7f4af4f08c..0000000000 --- a/source4/auth/credentials/credentials_ntlm.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - User credentials handling - - Copyright (C) Andrew Tridgell 2001 - Copyright (C) Andrew Bartlett 2001-2005 - Copyright (C) Stefan Metzmacher 2005 - - 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 . -*/ - -#include "includes.h" -#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ -#include "../lib/crypto/crypto.h" -#include "libcli/auth/libcli_auth.h" -#include "auth/credentials/credentials.h" - -_PUBLIC_ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_CTX *mem_ctx, - int *flags, - DATA_BLOB challenge, DATA_BLOB target_info, - DATA_BLOB *_lm_response, DATA_BLOB *_nt_response, - DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key) -{ - const char *user, *domain; - DATA_BLOB lm_response, nt_response; - DATA_BLOB lm_session_key, session_key; - const struct samr_Password *nt_hash; - lm_session_key = data_blob(NULL, 0); - - /* We may already have an NTLM response we prepared earlier. - * This is used for NTLM pass-though authentication */ - if (cred->nt_response.data || cred->lm_response.data) { - *_nt_response = cred->nt_response; - *_lm_response = cred->lm_response; - - if (!cred->lm_response.data) { - *flags = *flags & ~CLI_CRED_LANMAN_AUTH; - } - *_lm_session_key = data_blob(NULL, 0); - *_session_key = data_blob(NULL, 0); - return NT_STATUS_OK; - } - - nt_hash = cli_credentials_get_nt_hash(cred, mem_ctx); - - cli_credentials_get_ntlm_username_domain(cred, mem_ctx, &user, &domain); - - /* If we are sending a username@realm login (see function - * above), then we will not send LM, it will not be - * accepted */ - if (cred->principal_obtained > cred->username_obtained) { - *flags = *flags & ~CLI_CRED_LANMAN_AUTH; - } - - /* Likewise if we are a machine account (avoid protocol downgrade attacks) */ - if (cred->machine_account) { - *flags = *flags & ~CLI_CRED_LANMAN_AUTH; - } - - if (cred->use_kerberos == CRED_MUST_USE_KERBEROS) { - return NT_STATUS_ACCESS_DENIED; - } - - if (!nt_hash) { - static const uint8_t zeros[16]; - /* do nothing - blobs are zero length */ - - /* session key is all zeros */ - session_key = data_blob_talloc(mem_ctx, zeros, 16); - lm_session_key = data_blob_talloc(mem_ctx, zeros, 16); - - lm_response = data_blob(NULL, 0); - nt_response = data_blob(NULL, 0); - - /* not doing NTLM2 without a password */ - *flags &= ~CLI_CRED_NTLM2; - } else if (*flags & CLI_CRED_NTLMv2_AUTH) { - - if (!target_info.length) { - /* be lazy, match win2k - we can't do NTLMv2 without it */ - DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - /* TODO: if the remote server is standalone, then we should replace 'domain' - with the server name as supplied above */ - - if (!SMBNTLMv2encrypt_hash(mem_ctx, - user, - domain, - nt_hash->hash, &challenge, - &target_info, - &lm_response, &nt_response, - NULL, &session_key)) { - return NT_STATUS_NO_MEMORY; - } - - /* LM Key is incompatible... */ - *flags &= ~CLI_CRED_LANMAN_AUTH; - } else if (*flags & CLI_CRED_NTLM2) { - struct MD5Context md5_session_nonce_ctx; - uint8_t session_nonce[16]; - uint8_t session_nonce_hash[16]; - uint8_t user_session_key[16]; - - lm_response = data_blob_talloc(mem_ctx, NULL, 24); - generate_random_buffer(lm_response.data, 8); - memset(lm_response.data+8, 0, 16); - - memcpy(session_nonce, challenge.data, 8); - memcpy(&session_nonce[8], lm_response.data, 8); - - MD5Init(&md5_session_nonce_ctx); - MD5Update(&md5_session_nonce_ctx, challenge.data, 8); - MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); - MD5Final(session_nonce_hash, &md5_session_nonce_ctx); - - DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); - DEBUG(5, ("challenge is: \n")); - dump_data(5, session_nonce_hash, 8); - - nt_response = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(nt_hash->hash, - session_nonce_hash, - nt_response.data); - - session_key = data_blob_talloc(mem_ctx, NULL, 16); - - SMBsesskeygen_ntv1(nt_hash->hash, user_session_key); - hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); - dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); - - /* LM Key is incompatible... */ - *flags &= ~CLI_CRED_LANMAN_AUTH; - } else { - uint8_t lm_hash[16]; - nt_response = data_blob_talloc(mem_ctx, NULL, 24); - SMBOWFencrypt(nt_hash->hash, challenge.data, - nt_response.data); - - session_key = data_blob_talloc(mem_ctx, NULL, 16); - SMBsesskeygen_ntv1(nt_hash->hash, session_key.data); - dump_data_pw("NT session key:\n", session_key.data, session_key.length); - - /* lanman auth is insecure, it may be disabled. - We may also not have a password */ - if (*flags & CLI_CRED_LANMAN_AUTH) { - const char *password; - password = cli_credentials_get_password(cred); - if (!password) { - lm_response = nt_response; - } else { - lm_response = data_blob_talloc(mem_ctx, NULL, 24); - if (!SMBencrypt(password,challenge.data, - lm_response.data)) { - /* If the LM password was too long (and therefore the LM hash being - of the first 14 chars only), don't send it. - - We don't have any better options but to send the NT response - */ - data_blob_free(&lm_response); - lm_response = nt_response; - /* LM Key is incompatible with 'long' passwords */ - *flags &= ~CLI_CRED_LANMAN_AUTH; - } else { - E_deshash(password, lm_hash); - lm_session_key = data_blob_talloc(mem_ctx, NULL, 16); - memcpy(lm_session_key.data, lm_hash, 8); - memset(&lm_session_key.data[8], '\0', 8); - - if (!(*flags & CLI_CRED_NTLM_AUTH)) { - session_key = lm_session_key; - } - } - } - } else { - const char *password; - - /* LM Key is incompatible... */ - lm_response = nt_response; - *flags &= ~CLI_CRED_LANMAN_AUTH; - - password = cli_credentials_get_password(cred); - if (password) { - E_deshash(password, lm_hash); - lm_session_key = data_blob_talloc(mem_ctx, NULL, 16); - memcpy(lm_session_key.data, lm_hash, 8); - memset(&lm_session_key.data[8], '\0', 8); - } - } - } - if (_lm_response) { - *_lm_response = lm_response; - } - if (_nt_response) { - *_nt_response = nt_response; - } - if (_lm_session_key) { - *_lm_session_key = lm_session_key; - } - if (_session_key) { - *_session_key = session_key; - } - return NT_STATUS_OK; -} - -_PUBLIC_ bool cli_credentials_set_nt_hash(struct cli_credentials *cred, - const struct samr_Password *nt_hash, - enum credentials_obtained obtained) -{ - if (obtained >= cred->password_obtained) { - cli_credentials_set_password(cred, NULL, obtained); - if (nt_hash) { - cred->nt_hash = talloc(cred, struct samr_Password); - *cred->nt_hash = *nt_hash; - } else { - cred->nt_hash = NULL; - } - return true; - } - - return false; -} - -_PUBLIC_ bool cli_credentials_set_ntlm_response(struct cli_credentials *cred, - const DATA_BLOB *lm_response, - const DATA_BLOB *nt_response, - enum credentials_obtained obtained) -{ - if (obtained >= cred->password_obtained) { - cli_credentials_set_password(cred, NULL, obtained); - if (nt_response) { - cred->nt_response = data_blob_talloc(cred, nt_response->data, nt_response->length); - talloc_steal(cred, cred->nt_response.data); - } - if (nt_response) { - cred->lm_response = data_blob_talloc(cred, lm_response->data, lm_response->length); - } - return true; - } - - return false; -} - diff --git a/source4/auth/credentials/credentials_secrets.c b/source4/auth/credentials/credentials_secrets.c deleted file mode 100644 index d86032a564..0000000000 --- a/source4/auth/credentials/credentials_secrets.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - User credentials handling (as regards on-disk files) - - Copyright (C) Jelmer Vernooij 2005 - Copyright (C) Tim Potter 2001 - Copyright (C) Andrew Bartlett 2005 - - 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 . -*/ - -#include "includes.h" -#include "lib/events/events.h" -#include -#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ -#include "param/secrets.h" -#include "system/filesys.h" -#include "auth/credentials/credentials.h" -#include "auth/credentials/credentials_proto.h" -#include "auth/credentials/credentials_krb5.h" -#include "auth/kerberos/kerberos_util.h" -#include "param/param.h" -#include "lib/events/events.h" -#include "dsdb/samdb/samdb.h" - -/** - * Fill in credentials for the machine trust account, from the secrets database. - * - * @param cred Credentials structure to fill in - * @retval NTSTATUS error detailing any failure - */ -_PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - struct ldb_context *ldb, - const char *base, - const char *filter, - char **error_string) -{ - TALLOC_CTX *mem_ctx; - - int ldb_ret; - struct ldb_message *msg; - - const char *machine_account; - const char *password; - const char *old_password; - const char *domain; - const char *realm; - enum netr_SchannelType sct; - const char *salt_principal; - char *keytab; - const struct ldb_val *whenChanged; - - /* ok, we are going to get it now, don't recurse back here */ - cred->machine_account_pending = false; - - /* some other parts of the system will key off this */ - cred->machine_account = true; - - mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password"); - - if (!ldb) { - /* Local secrets are stored in secrets.ldb */ - ldb = secrets_db_connect(mem_ctx, lp_ctx); - if (!ldb) { - /* set anonymous as the fallback, if the machine account won't work */ - cli_credentials_set_anonymous(cred); - *error_string = talloc_strdup(cred, "Could not open secrets.ldb"); - talloc_free(mem_ctx); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - } - - ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg, - ldb_dn_new(mem_ctx, ldb, base), - LDB_SCOPE_SUBTREE, - NULL, 0, "%s", filter); - - if (ldb_ret != LDB_SUCCESS) { - *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s\n", - filter, base ? base : "", - ldb_strerror(ldb_ret), ldb_errstring(ldb)); - /* set anonymous as the fallback, if the machine account won't work */ - cli_credentials_set_anonymous(cred); - talloc_free(mem_ctx); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } - - password = ldb_msg_find_attr_as_string(msg, "secret", NULL); - old_password = ldb_msg_find_attr_as_string(msg, "priorSecret", NULL); - - machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL); - - if (!machine_account) { - machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL); - - if (!machine_account) { - const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL); - if (!ldap_bind_dn) { - *error_string = talloc_asprintf(cred, - "Could not find 'samAccountName', " - "'servicePrincipalName' or " - "'ldapBindDn' in secrets record: %s", - ldb_dn_get_linearized(msg->dn)); - /* set anonymous as the fallback, if the machine account won't work */ - cli_credentials_set_anonymous(cred); - talloc_free(mem_ctx); - return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; - } else { - /* store bind dn in credentials */ - cli_credentials_set_bind_dn(cred, ldap_bind_dn); - } - } - } - - salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL); - cli_credentials_set_salt_principal(cred, salt_principal); - - sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0); - if (sct) { - cli_credentials_set_secure_channel_type(cred, sct); - } - - if (!password) { - const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd"); - struct samr_Password hash; - ZERO_STRUCT(hash); - if (nt_password_hash) { - memcpy(hash.hash, nt_password_hash->data, - MIN(nt_password_hash->length, sizeof(hash.hash))); - - cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); - } else { - cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); - } - } else { - cli_credentials_set_password(cred, password, CRED_SPECIFIED); - } - - - domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL); - if (domain) { - cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); - } - - realm = ldb_msg_find_attr_as_string(msg, "realm", NULL); - if (realm) { - cli_credentials_set_realm(cred, realm, CRED_SPECIFIED); - } - - if (machine_account) { - cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); - } - - cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0)); - - whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged"); - if (whenChanged) { - time_t lct; - if (ldb_val_to_time(whenChanged, &lct) == LDB_SUCCESS) { - cli_credentials_set_password_last_changed_time(cred, lct); - } - } - - /* If there was an external keytab specified by reference in - * the LDB, then use this. Otherwise we will make one up - * (chewing CPU time) from the password */ - keytab = keytab_name_from_msg(cred, ldb, msg); - if (keytab) { - cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED); - talloc_free(keytab); - } - talloc_free(mem_ctx); - - return NT_STATUS_OK; -} - -/** - * Fill in credentials for the machine trust account, from the secrets database. - * - * @param cred Credentials structure to fill in - * @retval NTSTATUS error detailing any failure - */ -_PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred, - struct loadparm_context *lp_ctx) -{ - NTSTATUS status; - char *filter; - char *error_string; - /* Bleh, nasty recursion issues: We are setting a machine - * account here, so we don't want the 'pending' flag around - * any more */ - cred->machine_account_pending = false; - filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER, - cli_credentials_get_domain(cred)); - status = cli_credentials_set_secrets(cred, lp_ctx, NULL, - SECRETS_PRIMARY_DOMAIN_DN, - filter, &error_string); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not find machine account in secrets database: %s: %s\n", nt_errstr(status), error_string)); - talloc_free(error_string); - } - return status; -} - -/** - * Fill in credentials for the machine trust account, from the secrets database. - * - * @param cred Credentials structure to fill in - * @retval NTSTATUS error detailing any failure - */ -NTSTATUS cli_credentials_set_krbtgt(struct cli_credentials *cred, - struct loadparm_context *lp_ctx) -{ - NTSTATUS status; - char *filter; - char *error_string; - /* Bleh, nasty recursion issues: We are setting a machine - * account here, so we don't want the 'pending' flag around - * any more */ - cred->machine_account_pending = false; - filter = talloc_asprintf(cred, SECRETS_KRBTGT_SEARCH, - cli_credentials_get_realm(cred), - cli_credentials_get_domain(cred)); - status = cli_credentials_set_secrets(cred, lp_ctx, NULL, - SECRETS_PRINCIPALS_DN, - filter, &error_string); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not find krbtgt (master Kerberos) account in secrets database: %s: %s\n", nt_errstr(status), error_string)); - talloc_free(error_string); - } - return status; -} - -/** - * Fill in credentials for a particular prinicpal, from the secrets database. - * - * @param cred Credentials structure to fill in - * @retval NTSTATUS error detailing any failure - */ -_PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred, - struct loadparm_context *lp_ctx, - const char *serviceprincipal) -{ - NTSTATUS status; - char *filter; - char *error_string; - /* Bleh, nasty recursion issues: We are setting a machine - * account here, so we don't want the 'pending' flag around - * any more */ - cred->machine_account_pending = false; - filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH, - cli_credentials_get_realm(cred), - cli_credentials_get_domain(cred), - serviceprincipal); - status = cli_credentials_set_secrets(cred, lp_ctx, NULL, - SECRETS_PRINCIPALS_DN, filter, - &error_string); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Could not find %s principal in secrets database: %s: %s\n", serviceprincipal, nt_errstr(status), error_string)); - } - return status; -} - -/** - * Ask that when required, the credentials system will be filled with - * machine trust account, from the secrets database. - * - * @param cred Credentials structure to fill in - * @note This function is used to call the above function after, rather - * than during, popt processing. - * - */ -_PUBLIC_ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred, - struct loadparm_context *lp_ctx) -{ - cred->machine_account_pending = true; - cred->machine_account_pending_lp_ctx = lp_ctx; -} - - diff --git a/source4/auth/credentials/pycredentials.c b/source4/auth/credentials/pycredentials.c deleted file mode 100644 index 5d21721490..0000000000 --- a/source4/auth/credentials/pycredentials.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Copyright (C) Jelmer Vernooij 2007 - - 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 . -*/ - -#include -#include "includes.h" -#include "pycredentials.h" -#include "param/param.h" -#include "lib/cmdline/credentials.h" -#include "librpc/gen_ndr/samr.h" /* for struct samr_Password */ -#include "libcli/util/pyerrors.h" -#include "param/pyparam.h" -#include - -void initcredentials(void); - -static PyObject *PyString_FromStringOrNULL(const char *str) -{ - if (str == NULL) - Py_RETURN_NONE; - return PyString_FromString(str); -} - -static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -{ - pytalloc_Object *ret = (pytalloc_Object *)type->tp_alloc(type, 0); - if (ret == NULL) { - PyErr_NoMemory(); - return NULL; - } - ret->talloc_ctx = talloc_new(NULL); - if (ret->talloc_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - ret->ptr = cli_credentials_init(ret->talloc_ctx); - return (PyObject *)ret; -} - -static PyObject *py_creds_get_username(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_username(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_username(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - return PyBool_FromLong(cli_credentials_set_username(PyCredentials_AsCliCredentials(self), newval, obt)); -} - -static PyObject *py_creds_get_password(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_password(PyCredentials_AsCliCredentials(self))); -} - - -static PyObject *py_creds_set_password(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - return PyBool_FromLong(cli_credentials_set_password(PyCredentials_AsCliCredentials(self), newval, obt)); -} - -static PyObject *py_creds_get_domain(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_domain(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_domain(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - return PyBool_FromLong(cli_credentials_set_domain(PyCredentials_AsCliCredentials(self), newval, obt)); -} - -static PyObject *py_creds_get_realm(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_realm(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_realm(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - return PyBool_FromLong(cli_credentials_set_realm(PyCredentials_AsCliCredentials(self), newval, obt)); -} - -static PyObject *py_creds_get_bind_dn(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_bind_dn(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_bind_dn(pytalloc_Object *self, PyObject *args) -{ - char *newval; - if (!PyArg_ParseTuple(args, "s", &newval)) - return NULL; - - return PyBool_FromLong(cli_credentials_set_bind_dn(PyCredentials_AsCliCredentials(self), newval)); -} - -static PyObject *py_creds_get_workstation(pytalloc_Object *self) -{ - return PyString_FromStringOrNULL(cli_credentials_get_workstation(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_workstation(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - return PyBool_FromLong(cli_credentials_set_workstation(PyCredentials_AsCliCredentials(self), newval, obt)); -} - -static PyObject *py_creds_is_anonymous(pytalloc_Object *self) -{ - return PyBool_FromLong(cli_credentials_is_anonymous(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_anonymous(pytalloc_Object *self) -{ - cli_credentials_set_anonymous(PyCredentials_AsCliCredentials(self)); - Py_RETURN_NONE; -} - -static PyObject *py_creds_authentication_requested(pytalloc_Object *self) -{ - return PyBool_FromLong(cli_credentials_authentication_requested(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_wrong_password(pytalloc_Object *self) -{ - return PyBool_FromLong(cli_credentials_wrong_password(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_set_cmdline_callbacks(pytalloc_Object *self) -{ - return PyBool_FromLong(cli_credentials_set_cmdline_callbacks(PyCredentials_AsCliCredentials(self))); -} - -static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args) -{ - char *newval; - enum credentials_obtained obt = CRED_SPECIFIED; - int _obt = obt; - - if (!PyArg_ParseTuple(args, "s|i", &newval, &_obt)) { - return NULL; - } - obt = _obt; - - cli_credentials_parse_string(PyCredentials_AsCliCredentials(self), newval, obt); - Py_RETURN_NONE; -} - -static PyObject *py_creds_get_nt_hash(pytalloc_Object *self) -{ - const struct samr_Password *ntpw = cli_credentials_get_nt_hash(PyCredentials_AsCliCredentials(self), self->ptr); - - return PyString_FromStringAndSize(discard_const_p(char, ntpw->hash), 16); -} - -static PyObject *py_creds_set_kerberos_state(pytalloc_Object *self, PyObject *args) -{ - int state; - if (!PyArg_ParseTuple(args, "i", &state)) - return NULL; - - cli_credentials_set_kerberos_state(PyCredentials_AsCliCredentials(self), state); - Py_RETURN_NONE; -} - -static PyObject *py_creds_set_krb_forwardable(pytalloc_Object *self, PyObject *args) -{ - int state; - if (!PyArg_ParseTuple(args, "i", &state)) - return NULL; - - cli_credentials_set_krb_forwardable(PyCredentials_AsCliCredentials(self), state); - Py_RETURN_NONE; -} - -static PyObject *py_creds_guess(pytalloc_Object *self, PyObject *args) -{ - PyObject *py_lp_ctx = Py_None; - struct loadparm_context *lp_ctx; - TALLOC_CTX *mem_ctx; - struct cli_credentials *creds; - - creds = PyCredentials_AsCliCredentials(self); - - if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx)) - return NULL; - - mem_ctx = talloc_new(NULL); - if (mem_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - - lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); - if (lp_ctx == NULL) { - talloc_free(mem_ctx); - return NULL; - } - - cli_credentials_guess(creds, lp_ctx); - - talloc_free(mem_ctx); - - Py_RETURN_NONE; -} - -static PyObject *py_creds_set_machine_account(pytalloc_Object *self, PyObject *args) -{ - PyObject *py_lp_ctx = Py_None; - struct loadparm_context *lp_ctx; - NTSTATUS status; - struct cli_credentials *creds; - TALLOC_CTX *mem_ctx; - - creds = PyCredentials_AsCliCredentials(self); - - if (!PyArg_ParseTuple(args, "|O", &py_lp_ctx)) - return NULL; - - mem_ctx = talloc_new(NULL); - if (mem_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - - lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); - if (lp_ctx == NULL) { - talloc_free(mem_ctx); - return NULL; - } - - status = cli_credentials_set_machine_account(creds, lp_ctx); - talloc_free(mem_ctx); - - PyErr_NTSTATUS_IS_ERR_RAISE(status); - - Py_RETURN_NONE; -} - -static PyObject *PyCredentialCacheContainer_from_ccache_container(struct ccache_container *ccc) -{ - PyCredentialCacheContainerObject *py_ret; - - if (ccc == NULL) { - Py_RETURN_NONE; - } - - py_ret = (PyCredentialCacheContainerObject *)PyCredentialCacheContainer.tp_alloc(&PyCredentialCacheContainer, 0); - if (py_ret == NULL) { - PyErr_NoMemory(); - return NULL; - } - py_ret->mem_ctx = talloc_new(NULL); - py_ret->ccc = talloc_reference(py_ret->mem_ctx, ccc); - return (PyObject *)py_ret; -} - - -static PyObject *py_creds_get_named_ccache(pytalloc_Object *self, PyObject *args) -{ - PyObject *py_lp_ctx = Py_None; - char *ccache_name; - struct loadparm_context *lp_ctx; - struct ccache_container *ccc; - struct tevent_context *event_ctx; - int ret; - const char *error_string; - struct cli_credentials *creds; - TALLOC_CTX *mem_ctx; - - creds = PyCredentials_AsCliCredentials(self); - - if (!PyArg_ParseTuple(args, "|Os", &py_lp_ctx, &ccache_name)) - return NULL; - - mem_ctx = talloc_new(NULL); - if (mem_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - - lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); - if (lp_ctx == NULL) { - talloc_free(mem_ctx); - return NULL; - } - - event_ctx = tevent_context_init(mem_ctx); - - ret = cli_credentials_get_named_ccache(creds, event_ctx, lp_ctx, - ccache_name, &ccc, &error_string); - talloc_unlink(mem_ctx, lp_ctx); - if (ret == 0) { - talloc_steal(ccc, event_ctx); - talloc_free(mem_ctx); - return PyCredentialCacheContainer_from_ccache_container(ccc); - } - - PyErr_SetString(PyExc_RuntimeError, error_string?error_string:"NULL"); - - talloc_free(mem_ctx); - return NULL; -} - -static PyObject *py_creds_set_gensec_features(pytalloc_Object *self, PyObject *args) -{ - unsigned int gensec_features; - - if (!PyArg_ParseTuple(args, "I", &gensec_features)) - return NULL; - - cli_credentials_set_gensec_features(PyCredentials_AsCliCredentials(self), gensec_features); - - Py_RETURN_NONE; -} - -static PyObject *py_creds_get_gensec_features(pytalloc_Object *self, PyObject *args) -{ - unsigned int gensec_features; - - gensec_features = cli_credentials_get_gensec_features(PyCredentials_AsCliCredentials(self)); - return PyInt_FromLong(gensec_features); -} - - -static PyMethodDef py_creds_methods[] = { - { "get_username", (PyCFunction)py_creds_get_username, METH_NOARGS, - "S.get_username() -> username\nObtain username." }, - { "set_username", (PyCFunction)py_creds_set_username, METH_VARARGS, - "S.set_username(name, obtained=CRED_SPECIFIED) -> None\n" - "Change username." }, - { "get_password", (PyCFunction)py_creds_get_password, METH_NOARGS, - "S.get_password() -> password\n" - "Obtain password." }, - { "set_password", (PyCFunction)py_creds_set_password, METH_VARARGS, - "S.set_password(password, obtained=CRED_SPECIFIED) -> None\n" - "Change password." }, - { "get_domain", (PyCFunction)py_creds_get_domain, METH_NOARGS, - "S.get_domain() -> domain\n" - "Obtain domain name." }, - { "set_domain", (PyCFunction)py_creds_set_domain, METH_VARARGS, - "S.set_domain(domain, obtained=CRED_SPECIFIED) -> None\n" - "Change domain name." }, - { "get_realm", (PyCFunction)py_creds_get_realm, METH_NOARGS, - "S.get_realm() -> realm\n" - "Obtain realm name." }, - { "set_realm", (PyCFunction)py_creds_set_realm, METH_VARARGS, - "S.set_realm(realm, obtained=CRED_SPECIFIED) -> None\n" - "Change realm name." }, - { "get_bind_dn", (PyCFunction)py_creds_get_bind_dn, METH_NOARGS, - "S.get_bind_dn() -> bind dn\n" - "Obtain bind DN." }, - { "set_bind_dn", (PyCFunction)py_creds_set_bind_dn, METH_VARARGS, - "S.set_bind_dn(bind_dn) -> None\n" - "Change bind DN." }, - { "is_anonymous", (PyCFunction)py_creds_is_anonymous, METH_NOARGS, - NULL }, - { "set_anonymous", (PyCFunction)py_creds_set_anonymous, METH_NOARGS, - "S.set_anonymous() -> None\n" - "Use anonymous credentials." }, - { "get_workstation", (PyCFunction)py_creds_get_workstation, METH_NOARGS, - NULL }, - { "set_workstation", (PyCFunction)py_creds_set_workstation, METH_VARARGS, - NULL }, - { "authentication_requested", (PyCFunction)py_creds_authentication_requested, METH_NOARGS, - NULL }, - { "wrong_password", (PyCFunction)py_creds_wrong_password, METH_NOARGS, - "S.wrong_password() -> bool\n" - "Indicate the returned password was incorrect." }, - { "set_cmdline_callbacks", (PyCFunction)py_creds_set_cmdline_callbacks, METH_NOARGS, - "S.set_cmdline_callbacks() -> bool\n" - "Use command-line to obtain credentials not explicitly set." }, - { "parse_string", (PyCFunction)py_creds_parse_string, METH_VARARGS, - "S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n" - "Parse credentials string." }, - { "get_nt_hash", (PyCFunction)py_creds_get_nt_hash, METH_NOARGS, - NULL }, - { "set_kerberos_state", (PyCFunction)py_creds_set_kerberos_state, METH_VARARGS, - NULL }, - { "set_krb_forwardable", (PyCFunction)py_creds_set_krb_forwardable, METH_VARARGS, - NULL }, - { "guess", (PyCFunction)py_creds_guess, METH_VARARGS, NULL }, - { "set_machine_account", (PyCFunction)py_creds_set_machine_account, METH_VARARGS, NULL }, - { "get_named_ccache", (PyCFunction)py_creds_get_named_ccache, METH_VARARGS, NULL }, - { "set_gensec_features", (PyCFunction)py_creds_set_gensec_features, METH_VARARGS, NULL }, - { "get_gensec_features", (PyCFunction)py_creds_get_gensec_features, METH_NOARGS, NULL }, - { NULL } -}; - -PyTypeObject PyCredentials = { - .tp_name = "credentials.Credentials", - .tp_basicsize = sizeof(pytalloc_Object), - .tp_new = py_creds_new, - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_methods = py_creds_methods, -}; - - -PyTypeObject PyCredentialCacheContainer = { - .tp_name = "credentials.CredentialCacheContainer", - .tp_basicsize = sizeof(pytalloc_Object), - .tp_flags = Py_TPFLAGS_DEFAULT, -}; - -void initcredentials(void) -{ - PyObject *m; - PyTypeObject *talloc_type = pytalloc_GetObjectType(); - if (talloc_type == NULL) - return; - - PyCredentials.tp_base = PyCredentialCacheContainer.tp_base = talloc_type; - - if (PyType_Ready(&PyCredentials) < 0) - return; - - if (PyType_Ready(&PyCredentialCacheContainer) < 0) - return; - - m = Py_InitModule3("credentials", NULL, "Credentials management."); - if (m == NULL) - return; - - PyModule_AddObject(m, "AUTO_USE_KERBEROS", PyInt_FromLong(CRED_AUTO_USE_KERBEROS)); - PyModule_AddObject(m, "DONT_USE_KERBEROS", PyInt_FromLong(CRED_DONT_USE_KERBEROS)); - PyModule_AddObject(m, "MUST_USE_KERBEROS", PyInt_FromLong(CRED_MUST_USE_KERBEROS)); - - PyModule_AddObject(m, "AUTO_KRB_FORWARDABLE", PyInt_FromLong(CRED_AUTO_KRB_FORWARDABLE)); - PyModule_AddObject(m, "NO_KRB_FORWARDABLE", PyInt_FromLong(CRED_NO_KRB_FORWARDABLE)); - PyModule_AddObject(m, "FORCE_KRB_FORWARDABLE", PyInt_FromLong(CRED_FORCE_KRB_FORWARDABLE)); - - Py_INCREF(&PyCredentials); - PyModule_AddObject(m, "Credentials", (PyObject *)&PyCredentials); - Py_INCREF(&PyCredentialCacheContainer); - PyModule_AddObject(m, "CredentialCacheContainer", (PyObject *)&PyCredentialCacheContainer); -} diff --git a/source4/auth/credentials/pycredentials.h b/source4/auth/credentials/pycredentials.h deleted file mode 100644 index 3a110fb09a..0000000000 --- a/source4/auth/credentials/pycredentials.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Jelmer Vernooij 2008 - - 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 . -*/ -#ifndef _PYCREDENTIALS_H_ -#define _PYCREDENTIALS_H_ - -#include "auth/credentials/credentials.h" -#include - -extern PyTypeObject PyCredentials; -extern PyTypeObject PyCredentialCacheContainer; -typedef struct { - PyObject_HEAD - TALLOC_CTX *mem_ctx; - struct ccache_container *ccc; -} PyCredentialCacheContainerObject; -#define PyCredentials_Check(py_obj) PyObject_TypeCheck(py_obj, &PyCredentials) -#define PyCredentials_AsCliCredentials(py_obj) pytalloc_get_type(py_obj, struct cli_credentials) -#define cli_credentials_from_py_object(py_obj) (py_obj == Py_None)?cli_credentials_init_anon(NULL):PyCredentials_AsCliCredentials(py_obj) - -#endif /* _PYCREDENTIALS_H_ */ diff --git a/source4/auth/credentials/samba-credentials.pc.in b/source4/auth/credentials/samba-credentials.pc.in deleted file mode 100644 index 9a0db509ee..0000000000 --- a/source4/auth/credentials/samba-credentials.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -modulesdir=${prefix}/modules/gensec - -Name: samba-credentials -Description: Credentials management -Version: @PACKAGE_VERSION@ -Libs: @LIB_RPATH@ -L${libdir} -lsamba-credentials -Cflags: -I${includedir} -DHAVE_IMMEDIATE_STRUCTURES=1 diff --git a/source4/auth/credentials/tests/bind.py b/source4/auth/credentials/tests/bind.py deleted file mode 100755 index 1529a475c7..0000000000 --- a/source4/auth/credentials/tests/bind.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# This is unit with tests for LDAP access checks - -import optparse -import sys -import base64 -import re -import os -import copy -import time - -sys.path.insert(0, "bin/python") -import samba -samba.ensure_external_module("testtools", "testtools") -samba.ensure_external_module("subunit", "subunit/python") - -import samba.getopt as options - -from ldb import ( - SCOPE_BASE, SCOPE_SUBTREE, LdbError, ERR_NO_SUCH_OBJECT) -from samba.dcerpc import security - -from samba.auth import system_session -from samba import gensec -from samba.samdb import SamDB -from samba.credentials import Credentials -import samba.tests -from samba.tests import delete_force -from subunit.run import SubunitTestRunner -import unittest - -parser = optparse.OptionParser("ldap [options] ") -sambaopts = options.SambaOptions(parser) -parser.add_option_group(sambaopts) - -# use command line creds if available -credopts = options.CredentialsOptions(parser) -parser.add_option_group(credopts) -opts, args = parser.parse_args() - -if len(args) < 1: - parser.print_usage() - sys.exit(1) - -host = args[0] -lp = sambaopts.get_loadparm() -creds = credopts.get_credentials(lp) -creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL) -creds_machine = copy.deepcopy(creds) -creds_user1 = copy.deepcopy(creds) -creds_user2 = copy.deepcopy(creds) -creds_user3 = copy.deepcopy(creds) - -class BindTests(samba.tests.TestCase): - - info_dc = None - - def setUp(self): - super(BindTests, self).setUp() - # fetch rootDSEs - if self.info_dc is None: - res = ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) - self.assertEquals(len(res), 1) - BindTests.info_dc = res[0] - # cache some of RootDSE props - self.schema_dn = self.info_dc["schemaNamingContext"][0] - self.domain_dn = self.info_dc["defaultNamingContext"][0] - self.config_dn = self.info_dc["configurationNamingContext"][0] - self.computer_dn = "CN=centos53,CN=Computers,%s" % self.domain_dn - self.password = "P@ssw0rd" - self.username = "BindTestUser_" + time.strftime("%s", time.gmtime()) - - def tearDown(self): - super(BindTests, self).tearDown() - - def test_computer_account_bind(self): - # create a computer acocount for the test - delete_force(ldb, self.computer_dn) - ldb.add_ldif(""" -dn: """ + self.computer_dn + """ -cn: CENTOS53 -displayName: CENTOS53$ -name: CENTOS53 -sAMAccountName: CENTOS53$ -countryCode: 0 -objectClass: computer -objectClass: organizationalPerson -objectClass: person -objectClass: top -objectClass: user -codePage: 0 -userAccountControl: 4096 -dNSHostName: centos53.alabala.test -operatingSystemVersion: 5.2 (3790) -operatingSystem: Windows Server 2003 -""") - ldb.modify_ldif(""" -dn: """ + self.computer_dn + """ -changetype: modify -replace: unicodePwd -unicodePwd:: """ + base64.b64encode("\"P@ssw0rd\"".encode('utf-16-le')) + """ -""") - - # do a simple bind and search with the machine account - creds_machine.set_bind_dn(self.computer_dn) - creds_machine.set_password(self.password) - print "BindTest with: " + creds_machine.get_bind_dn() - ldb_machine = samba.tests.connect_samdb(host, credentials=creds_machine, - lp=lp, ldap_only=True) - res = ldb_machine.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) - - def test_user_account_bind(self): - # create user - ldb.newuser(username=self.username, password=self.password) - ldb_res = ldb.search(base=self.domain_dn, - scope=SCOPE_SUBTREE, - expression="(samAccountName=%s)" % self.username) - self.assertEquals(len(ldb_res), 1) - user_dn = ldb_res[0]["dn"] - - # do a simple bind and search with the user account in format user@realm - creds_user1.set_bind_dn(self.username + "@" + creds.get_realm()) - creds_user1.set_password(self.password) - print "BindTest with: " + creds_user1.get_bind_dn() - ldb_user1 = samba.tests.connect_samdb(host, credentials=creds_user1, - lp=lp, ldap_only=True) - res = ldb_user1.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) - - # do a simple bind and search with the user account in format domain\user - creds_user2.set_bind_dn(creds.get_domain() + "\\" + self.username) - creds_user2.set_password(self.password) - print "BindTest with: " + creds_user2.get_bind_dn() - ldb_user2 = samba.tests.connect_samdb(host, credentials=creds_user2, - lp=lp, ldap_only=True) - res = ldb_user2.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) - - # do a simple bind and search with the user account DN - creds_user3.set_bind_dn(str(user_dn)) - creds_user3.set_password(self.password) - print "BindTest with: " + creds_user3.get_bind_dn() - ldb_user3 = samba.tests.connect_samdb(host, credentials=creds_user3, - lp=lp, ldap_only=True) - res = ldb_user3.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"]) - - -ldb = samba.tests.connect_samdb(host, credentials=creds, lp=lp, ldap_only=True) - -runner = SubunitTestRunner() -rc = 0 -if not runner.run(unittest.makeSuite(BindTests)).wasSuccessful(): - rc = 1 - -sys.exit(rc) diff --git a/source4/auth/credentials/tests/simple.c b/source4/auth/credentials/tests/simple.c deleted file mode 100644 index 6c722750d6..0000000000 --- a/source4/auth/credentials/tests/simple.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Samba utility functions - Copyright (C) Jelmer Vernooij 2007 - - 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 . -*/ - -#include "includes.h" -#include "auth/credentials/credentials.h" -#include "torture/torture.h" - -static bool test_init(struct torture_context *tctx) -{ - struct cli_credentials *creds = cli_credentials_init(tctx); - - cli_credentials_set_domain(creds, "bla", CRED_SPECIFIED); - - torture_assert_str_equal(tctx, "BLA", cli_credentials_get_domain(creds), - "domain"); - - cli_credentials_set_username(creds, "someuser", CRED_SPECIFIED); - - torture_assert_str_equal(tctx, "someuser", - cli_credentials_get_username(creds), - "username"); - - cli_credentials_set_password(creds, "p4ssw0rd", CRED_SPECIFIED); - - torture_assert_str_equal(tctx, "p4ssw0rd", - cli_credentials_get_password(creds), - "password"); - - return true; -} - -static bool test_init_anonymous(struct torture_context *tctx) -{ - struct cli_credentials *creds = cli_credentials_init_anon(tctx); - - torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), - "", "domain"); - - torture_assert_str_equal(tctx, cli_credentials_get_username(creds), - "", "username"); - - torture_assert(tctx, cli_credentials_get_password(creds) == NULL, - "password"); - - return true; -} - -static bool test_parse_string(struct torture_context *tctx) -{ - struct cli_credentials *creds = cli_credentials_init_anon(tctx); - - /* anonymous */ - cli_credentials_parse_string(creds, "%", CRED_SPECIFIED); - - torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), - "", "domain"); - - torture_assert_str_equal(tctx, cli_credentials_get_username(creds), - "", "username"); - - torture_assert(tctx, cli_credentials_get_password(creds) == NULL, - "password"); - - /* username + password */ - cli_credentials_parse_string(creds, "somebody%secret", - CRED_SPECIFIED); - - torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), - "", "domain"); - - torture_assert_str_equal(tctx, cli_credentials_get_username(creds), - "somebody", "username"); - - torture_assert_str_equal(tctx, cli_credentials_get_password(creds), - "secret", "password"); - - /* principal */ - cli_credentials_parse_string(creds, "prin@styx", - CRED_SPECIFIED); - - torture_assert_str_equal(tctx, cli_credentials_get_realm(creds), - "STYX", "realm"); - - torture_assert_str_equal(tctx, - cli_credentials_get_principal(creds, tctx), - "prin@styx", "principal"); - - return true; -} - -struct torture_suite *torture_local_credentials(TALLOC_CTX *mem_ctx) -{ - struct torture_suite *suite = torture_suite_create(mem_ctx, "credentials"); - - torture_suite_add_simple_test(suite, "init", test_init); - torture_suite_add_simple_test(suite, "init anonymous", - test_init_anonymous); - torture_suite_add_simple_test(suite, "parse_string", - test_parse_string); - - return suite; -} - diff --git a/source4/auth/credentials/wscript_build b/source4/auth/credentials/wscript_build deleted file mode 100644 index 2c46b43b21..0000000000 --- a/source4/auth/credentials/wscript_build +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -bld.SAMBA_LIBRARY('samba-credentials', - source='credentials.c', - autoproto='credentials_proto.h', - public_headers='credentials.h', - pc_files='samba-credentials.pc', - deps='LIBCRYPTO errors events LIBCLI_AUTH security CREDENTIALS_SECRETS CREDENTIALS_KRB5', - vnum='0.0.1' - ) - -bld.SAMBA_SUBSYSTEM('CREDENTIALS_KRB5', - source='credentials_krb5.c', - deps='KERBEROS_UTIL gssapi samba-credentials', - public_deps='com_err authkrb5', - ) - -bld.SAMBA_SUBSYSTEM('CREDENTIALS_SECRETS', - source='credentials_secrets.c', - deps='CREDENTIALS_KRB5 CREDENTIALS_NTLM ldb samdb-common', - ) - -bld.SAMBA_SUBSYSTEM('CREDENTIALS_NTLM', - source='credentials_ntlm.c', - deps='samba-credentials') - -bld.SAMBA_PYTHON('pycredentials', - source='pycredentials.c', - public_deps='samba-credentials cmdline-credentials pytalloc-util pyparam_util CREDENTIALS_KRB5 CREDENTIALS_SECRETS', - realname='samba/credentials.so' - ) - diff --git a/source4/auth/gensec/gensec_start.c b/source4/auth/gensec/gensec_start.c index d400685a49..3150cced97 100644 --- a/source4/auth/gensec/gensec_start.c +++ b/source4/auth/gensec/gensec_start.c @@ -928,8 +928,12 @@ _PUBLIC_ NTSTATUS gensec_init(void) { static bool initialized = false; #define _MODULE_PROTO(init) extern NTSTATUS init(void); +#if _SAMBA_BUILD_ == 4 STATIC_gensec_MODULES_PROTO; init_module_fn static_init[] = { STATIC_gensec_MODULES }; +#else + init_module_fn *static_init = NULL; +#endif init_module_fn *shared_init; if (initialized) return NT_STATUS_OK; diff --git a/source4/auth/wscript_build b/source4/auth/wscript_build index 079857dbb7..ebee49b89c 100644 --- a/source4/auth/wscript_build +++ b/source4/auth/wscript_build @@ -4,7 +4,6 @@ bld.RECURSE('gensec') bld.RECURSE('kerberos') bld.RECURSE('ntlmssp') bld.RECURSE('ntlm') -bld.RECURSE('credentials') bld.SAMBA_SUBSYSTEM('auth_session', source='session.c', diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index ce747cee9e..7dae7a2e76 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -455,7 +455,7 @@ plantestsuite("samba4.blackbox.setpassword.py", "none", ["PYTHON=%s" % python, o plantestsuite("samba4.blackbox.newuser.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_newuser.sh"), '$PREFIX/provision']) plantestsuite("samba4.blackbox.group.py", "none", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_group.sh"), '$PREFIX/provision']) plantestsuite("samba4.blackbox.spn.py(dc:local)", "dc:local", ["PYTHON=%s" % python, os.path.join(samba4srcdir, "setup/tests/blackbox_spn.sh"), '$PREFIX/dc']) -plantestsuite("samba4.ldap.bind(dc)", "dc", [python, os.path.join(samba4srcdir, "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"']) +plantestsuite("samba4.ldap.bind(dc)", "dc", [python, os.path.join(srcdir(), "auth/credentials/tests/bind.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"']) # DRS python tests plansambapythontestsuite("samba4.blackbox.samba-tool.drs(vampire_dc)", "vampire_dc", os.path.join(samba4srcdir, 'scripting/python'), "samba.tests.blackbox.samba_tool_drs", environ={'DC1': '$DC_SERVER', 'DC2': '$VAMPIRE_DC_SERVER'}, extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD']) diff --git a/source4/torture/local/wscript_build b/source4/torture/local/wscript_build index 0c269d7310..c5d897a123 100644 --- a/source4/torture/local/wscript_build +++ b/source4/torture/local/wscript_build @@ -13,7 +13,7 @@ TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c ../../../lib/util/charset/tests/convert_string.c ../../libcli/security/tests/sddl.c ../../../lib/tdr/testsuite.c ../../../lib/tevent/testsuite.c ../../param/tests/share.c - ../../param/tests/loadparm.c ../../auth/credentials/tests/simple.c local.c + ../../param/tests/loadparm.c ../../../auth/credentials/tests/simple.c local.c dbspeed.c torture.c ../ldb/ldb.c ../../dsdb/common/tests/dsdb_dn.c ../../dsdb/schema/tests/schema_syntax.c ../../../lib/util/tests/anonymous_shared.c''' -- cgit