From 6104e2b46d103bd58a253c35a8f416a3367bf0b8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 Jan 2016 12:19:48 +0100 Subject: [PATCH] Add possibility to change other user's password --- auth/credentials/credentials.c | 171 +++++++++++++++++++++++++++++--- auth/credentials/credentials.h | 25 ++++- auth/credentials/credentials_internal.h | 7 ++ auth/credentials/credentials_secrets.c | 18 ++-- auth/credentials/pycredentials.c | 97 +++++++++++++++++- auth/credentials/tests/simple.c | 6 +- python/samba/getopt.py | 8 ++ python/samba/netcmd/user.py | 12 +++ source4/lib/cmdline/popt_credentials.c | 2 +- source4/libnet/libnet_passwd.c | 6 +- source4/libnet/libnet_rpc.c | 27 ++--- source4/torture/gentest.c | 3 +- source4/torture/locktest.c | 3 +- source4/torture/rpc/forest_trust.c | 2 +- source4/torture/rpc/schannel.c | 4 +- source4/utils/ntlm_auth.c | 2 +- 16 files changed, 340 insertions(+), 53 deletions(-) diff --git a/auth/credentials/credentials.c b/auth/credentials/credentials.c index 3b7d42a..e9fbc0f 100644 --- a/auth/credentials/credentials.c +++ b/auth/credentials/credentials.c @@ -43,6 +43,7 @@ _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) cred->workstation_obtained = CRED_UNINITIALISED; cred->username_obtained = CRED_UNINITIALISED; + cred->user_to_connect_obtained = CRED_UNINITIALISED; cred->password_obtained = CRED_UNINITIALISED; cred->domain_obtained = CRED_UNINITIALISED; cred->realm_obtained = CRED_UNINITIALISED; @@ -51,15 +52,19 @@ _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) cred->principal_obtained = CRED_UNINITIALISED; cred->keytab_obtained = CRED_UNINITIALISED; cred->server_gss_creds_obtained = CRED_UNINITIALISED; + cred->user_to_connect_domain_obtained = CRED_UNINITIALISED; cred->ccache_threshold = CRED_UNINITIALISED; cred->client_gss_creds_threshold = CRED_UNINITIALISED; cred->workstation = NULL; cred->username = NULL; + cred->user_to_connect = NULL; + cred->password_to_connect = NULL; cred->password = NULL; cred->old_password = NULL; cred->domain = NULL; + cred->user_to_connect_domain = NULL; cred->realm = NULL; cred->principal = NULL; cred->salt_principal = NULL; @@ -85,6 +90,8 @@ _PUBLIC_ struct cli_credentials *cli_credentials_init(TALLOC_CTX *mem_ctx) cred->workstation_cb = NULL; cred->password_cb = NULL; cred->username_cb = NULL; + cred->user_to_connect_cb = NULL; + cred->user_to_connect_domain_cb = NULL; cred->domain_cb = NULL; cred->realm_cb = NULL; cred->principal_cb = NULL; @@ -218,9 +225,9 @@ _PUBLIC_ const char *cli_credentials_get_username(struct cli_credentials *cred) if (cred->username_obtained == CRED_CALLBACK && !cred->callback_running) { - cred->callback_running = true; + cred->callback_running = true; cred->username = cred->username_cb(cred); - cred->callback_running = false; + cred->callback_running = false; if (cred->username_obtained == CRED_CALLBACK) { cred->username_obtained = CRED_CALLBACK_RESULT; cli_credentials_invalidate_ccache(cred, cred->username_obtained); @@ -243,6 +250,40 @@ _PUBLIC_ bool cli_credentials_set_username(struct cli_credentials *cred, return false; } +_PUBLIC_ const char *cli_credentials_get_user_to_connect(struct cli_credentials *cred) +{ + if (cred->machine_account_pending) { + cli_credentials_set_machine_account(cred, + cred->machine_account_pending_lp_ctx); + } + + if (cred->user_to_connect_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->user_to_connect = cred->user_to_connect_cb(cred); + cred->callback_running = false; + if (cred->user_to_connect_obtained == CRED_CALLBACK) { + cred->user_to_connect_obtained = CRED_CALLBACK_RESULT; + cli_credentials_invalidate_ccache(cred, cred->user_to_connect_obtained); + } + } + + return cred->user_to_connect; +} + +_PUBLIC_ bool cli_credentials_set_user_to_connect(struct cli_credentials *cred, + const char *val, enum credentials_obtained obtained) +{ + if (obtained >= cred->user_to_connect_obtained) { + cred->user_to_connect = talloc_strdup(cred, val); + cred->user_to_connect_obtained = obtained; + cli_credentials_invalidate_ccache(cred, cred->user_to_connect_obtained); + return true; + } + + return false; +} + _PUBLIC_ bool cli_credentials_set_username_callback(struct cli_credentials *cred, const char *(*username_cb) (struct cli_credentials *)) { @@ -255,6 +296,18 @@ _PUBLIC_ bool cli_credentials_set_username_callback(struct cli_credentials *cred return false; } +_PUBLIC_ bool cli_credentials_set_user_to_connect_callback(struct cli_credentials *cred, + const char *(*username_cb) (struct cli_credentials *)) +{ + if (cred->user_to_connect_obtained < CRED_CALLBACK) { + cred->user_to_connect_cb = username_cb; + cred->user_to_connect_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + _PUBLIC_ bool cli_credentials_set_bind_dn(struct cli_credentials *cred, const char *bind_dn) { @@ -458,6 +511,21 @@ _PUBLIC_ bool cli_credentials_set_password_callback(struct cli_credentials *cred return false; } +_PUBLIC_ const char *cli_credentials_get_password_to_connect(struct cli_credentials *cred) +{ + return cred->password_to_connect; +} + +_PUBLIC_ bool cli_credentials_set_password_to_connect(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + (void)val; + (void)obtained; + cred->password_to_connect = talloc_strdup(cred, val); + return true; +} + /** * Obtain the 'old' password for this credentials context (used for join accounts). * @param cred credentials context @@ -566,6 +634,53 @@ _PUBLIC_ struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_creden return NULL; } +_PUBLIC_ const char *cli_credentials_get_user_to_connect_domain(struct cli_credentials *cred) +{ + if (cred->user_to_connect_domain_obtained == CRED_CALLBACK && + !cred->callback_running) { + cred->callback_running = true; + cred->user_to_connect_domain = cred->user_to_connect_domain_cb(cred); + cred->callback_running = false; + if (cred->user_to_connect_domain_obtained == CRED_CALLBACK) { + cred->user_to_connect_domain_obtained = CRED_CALLBACK_RESULT; + } + } + return cred->user_to_connect_domain; +} + +_PUBLIC_ bool cli_credentials_set_user_to_connect_domain(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained) +{ + if (obtained >= cred->user_to_connect_domain_obtained) { + /* it is important that the domain be in upper case, + * particularly for the sensitive NTLMv2 + * calculations */ + cred->user_to_connect_domain = strupper_talloc(cred, val); + cred->user_to_connect_domain_obtained = obtained; + /* setting domain does not mean we have to invalidate ccache + * because domain in not used for Kerberos operations. + * If ccache invalidation is required, one will anyway specify + * a password to kinit, and that will force invalidation of the ccache + */ + return true; + } + + return false; +} + +bool cli_credentials_set_user_to_connect_domain_callback(struct cli_credentials *cred, + const char *(*domain_cb) (struct cli_credentials *)) +{ + if (cred->user_to_connect_domain_obtained < CRED_CALLBACK) { + cred->user_to_connect_domain_cb = domain_cb; + cred->user_to_connect_domain_obtained = CRED_CALLBACK; + return true; + } + + return false; +} + /** * Obtain the 'short' or 'NetBIOS' domain for this credentials context. * @param cred credentials context @@ -579,11 +694,11 @@ _PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred) cred->machine_account_pending_lp_ctx); } - if (cred->domain_obtained == CRED_CALLBACK && + if (cred->domain_obtained == CRED_CALLBACK && !cred->callback_running) { - cred->callback_running = true; + cred->callback_running = true; cred->domain = cred->domain_cb(cred); - cred->callback_running = false; + cred->callback_running = false; if (cred->domain_obtained == CRED_CALLBACK) { cred->domain_obtained = CRED_CALLBACK_RESULT; cli_credentials_invalidate_ccache(cred, cred->domain_obtained); @@ -593,7 +708,6 @@ _PUBLIC_ const char *cli_credentials_get_domain(struct cli_credentials *cred) return cred->domain; } - _PUBLIC_ bool cli_credentials_set_domain(struct cli_credentials *cred, const char *val, enum credentials_obtained obtained) @@ -739,9 +853,11 @@ bool cli_credentials_set_workstation_callback(struct cli_credentials *cred, * @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 + * @param user_to_connect This boolean indicates whether we're setting the user_to_connect or not */ -_PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, enum credentials_obtained obtained) +_PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, + enum credentials_obtained obtained, bool user_to_connect) { char *uname, *p; @@ -753,7 +869,10 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, uname = talloc_strdup(credentials, data); if ((p = strchr_m(uname,'%'))) { *p = 0; - cli_credentials_set_password(credentials, p+1, obtained); + if (!user_to_connect) + cli_credentials_set_password(credentials, p+1, obtained); + else + cli_credentials_set_password_to_connect(credentials, p+1, obtained); } if ((p = strchr_m(uname,'@'))) { @@ -763,10 +882,18 @@ _PUBLIC_ void cli_credentials_parse_string(struct cli_credentials *credentials, return; } else if ((p = strchr_m(uname,'\\')) || (p = strchr_m(uname, '/'))) { *p = 0; - cli_credentials_set_domain(credentials, uname, obtained); + if (!user_to_connect) { + cli_credentials_set_domain(credentials, uname, obtained); + } else { + cli_credentials_set_user_to_connect_domain(credentials, uname, obtained); + } uname = p+1; } - cli_credentials_set_username(credentials, uname, obtained); + if (!user_to_connect) + cli_credentials_set_username(credentials, uname, obtained); + else { + cli_credentials_set_user_to_connect(credentials, uname, obtained); + } } /** @@ -812,8 +939,10 @@ _PUBLIC_ void cli_credentials_set_conf(struct cli_credentials *cred, cli_credentials_set_username(cred, "", CRED_UNINITIALISED); if (lpcfg_parm_is_cmdline(lp_ctx, "workgroup")) { cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_SPECIFIED); + cli_credentials_set_user_to_connect_domain(cred, lpcfg_workgroup(lp_ctx), CRED_SPECIFIED); } else { cli_credentials_set_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED); + cli_credentials_set_user_to_connect_domain(cred, lpcfg_workgroup(lp_ctx), CRED_UNINITIALISED); } if (lpcfg_parm_is_cmdline(lp_ctx, "netbios name")) { cli_credentials_set_workstation(cred, lpcfg_netbios_name(lp_ctx), CRED_SPECIFIED); @@ -842,13 +971,13 @@ _PUBLIC_ void cli_credentials_guess(struct cli_credentials *cred, 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); + cli_credentials_parse_string(cred, getenv("USER"), CRED_GUESS_ENV, false); if ((p = strchr_m(getenv("USER"),'%'))) { memset(p,0,strlen(cred->password)); } @@ -942,6 +1071,7 @@ _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_user_to_connect_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); @@ -1156,4 +1286,21 @@ _PUBLIC_ bool cli_credentials_parse_password_fd(struct cli_credentials *credenti return true; } +_PUBLIC_ void switch_values(struct cli_credentials *credentials, char **values) { + if (credentials->user_to_connect != NULL) { + values[0] = credentials->username; + credentials->username = credentials->user_to_connect; + values[1] = credentials->password; + credentials->username = credentials->password_to_connect; + values[2] = credentials->domain; + credentials->domain = credentials->user_to_connect_domain; + } +} +_PUBLIC_ void switch_back_values(struct cli_credentials *credentials, char **values) { + if (credentials->user_to_connect != NULL) { + credentials->username = values[0]; + credentials->password = values[1]; + credentials->domain = values[2]; + } +} diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h index fdedd63..401fec2 100644 --- a/auth/credentials/credentials.h +++ b/auth/credentials/credentials.h @@ -42,7 +42,7 @@ struct db_context; 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_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 */ @@ -75,6 +75,7 @@ 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); +const char *cli_credentials_get_password_to_connect(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); @@ -85,6 +86,7 @@ NTSTATUS cli_credentials_get_ntlm_response(struct cli_credentials *cred, TALLOC_ DATA_BLOB *_lm_session_key, DATA_BLOB *_session_key); const char *cli_credentials_get_realm(struct cli_credentials *cred); const char *cli_credentials_get_username(struct cli_credentials *cred); +const char *cli_credentials_get_user_to_connect(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); @@ -104,6 +106,7 @@ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred, int cli_credentials_get_keytab(struct cli_credentials *cred, struct loadparm_context *lp_ctx, struct keytab_container **_ktc); +const char *cli_credentials_get_user_to_connect_domain(struct cli_credentials *cred); 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, @@ -125,6 +128,11 @@ 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_user_to_connect_domain(struct cli_credentials *cred, + const char *val, + enum credentials_obtained obtained); +bool cli_credentials_set_user_to_connect_domain_callback(struct cli_credentials *cred, + const char *(*domain_cb) (struct cli_credentials *)); bool cli_credentials_set_domain(struct cli_credentials *cred, const char *val, enum credentials_obtained obtained); @@ -134,6 +142,10 @@ 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_user_to_connect(struct cli_credentials *cred, + const char *val, enum credentials_obtained obtained); +bool cli_credentials_set_user_to_connect_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); @@ -142,8 +154,12 @@ bool cli_credentials_set_principal_callback(struct cli_credentials *cred, bool cli_credentials_set_password(struct cli_credentials *cred, const char *val, enum credentials_obtained obtained); +bool cli_credentials_set_password_to_connect(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); +void cli_credentials_parse_string(struct cli_credentials *credentials, const char *data, + enum credentials_obtained obtained, bool user_to_connect); struct samr_Password *cli_credentials_get_nt_hash(struct cli_credentials *cred, TALLOC_CTX *mem_ctx); struct samr_Password *cli_credentials_get_old_nt_hash(struct cli_credentials *cred, @@ -189,6 +205,8 @@ bool cli_credentials_parse_file(struct cli_credentials *cred, const char *file, 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 *)); +bool cli_credentials_set_password_to_connect_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, @@ -291,4 +309,7 @@ struct cli_credentials *cli_credentials_shallow_copy(TALLOC_CTX *mem_ctx, */ struct netlogon_creds_CredentialState *cli_credentials_get_netlogon_creds(struct cli_credentials *cred); +void switch_values(struct cli_credentials *credentials, char **values); +void switch_back_values(struct cli_credentials *credentials, char **values); + #endif /* __CREDENTIALS_H__ */ diff --git a/auth/credentials/credentials_internal.h b/auth/credentials/credentials_internal.h index aa01ccc..f8833fb 100644 --- a/auth/credentials/credentials_internal.h +++ b/auth/credentials/credentials_internal.h @@ -28,8 +28,10 @@ struct cli_credentials { enum credentials_obtained workstation_obtained; enum credentials_obtained username_obtained; + enum credentials_obtained user_to_connect_obtained; enum credentials_obtained password_obtained; enum credentials_obtained domain_obtained; + enum credentials_obtained user_to_connect_domain_obtained; enum credentials_obtained realm_obtained; enum credentials_obtained ccache_obtained; enum credentials_obtained client_gss_creds_obtained; @@ -46,9 +48,12 @@ struct cli_credentials { const char *workstation; const char *username; + const char *user_to_connect; + const char *password_to_connect; const char *password; const char *old_password; const char *domain; + const char *user_to_connect_domain; const char *realm; const char *principal; char *salt_principal; @@ -74,7 +79,9 @@ struct cli_credentials { const char *(*workstation_cb) (struct cli_credentials *); const char *(*password_cb) (struct cli_credentials *); const char *(*username_cb) (struct cli_credentials *); + const char *(*user_to_connect_cb) (struct cli_credentials *); const char *(*domain_cb) (struct cli_credentials *); + const char *(*user_to_connect_domain_cb) (struct cli_credentials *); const char *(*realm_cb) (struct cli_credentials *); const char *(*principal_cb) (struct cli_credentials *); diff --git a/auth/credentials/credentials_secrets.c b/auth/credentials/credentials_secrets.c index 784e345..3406bfa 100644 --- a/auth/credentials/credentials_secrets.c +++ b/auth/credentials/credentials_secrets.c @@ -57,10 +57,10 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, char **error_string) { TALLOC_CTX *mem_ctx; - + int ldb_ret; struct ldb_message *msg; - + const char *machine_account; const char *password; const char *domain; @@ -116,19 +116,19 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, talloc_free(mem_ctx); return NT_STATUS_NOT_FOUND; } - + if (lct == secrets_tdb_last_change_time && secrets_tdb_password && strcmp(password, secrets_tdb_password) != 0) { talloc_free(mem_ctx); return NT_STATUS_NOT_FOUND; } - + cli_credentials_set_password_last_changed_time(cred, lct); - + 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) { @@ -153,7 +153,7 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, 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; @@ -161,7 +161,6 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, 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); @@ -170,7 +169,6 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, 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); @@ -196,7 +194,7 @@ static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred, talloc_free(keytab); } talloc_free(mem_ctx); - + return NT_STATUS_OK; } diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c index e32d9a9..f2dea2f 100644 --- a/auth/credentials/pycredentials.c +++ b/auth/credentials/pycredentials.c @@ -70,6 +70,25 @@ static PyObject *py_creds_set_username(pytalloc_Object *self, PyObject *args) return PyBool_FromLong(cli_credentials_set_username(PyCredentials_AsCliCredentials(self), newval, obt)); } +static PyObject *py_creds_get_user_to_connect(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_user_to_connect(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_user_to_connect(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_user_to_connect(PyCredentials_AsCliCredentials(self), newval, obt)); +} + static PyObject *py_creds_get_password(pytalloc_Object *self) { return PyString_FromStringOrNULL(cli_credentials_get_password(PyCredentials_AsCliCredentials(self))); @@ -90,6 +109,45 @@ static PyObject *py_creds_set_password(pytalloc_Object *self, PyObject *args) return PyBool_FromLong(cli_credentials_set_password(PyCredentials_AsCliCredentials(self), newval, obt)); } +static PyObject *py_creds_get_password_to_connect(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_password_to_connect(PyCredentials_AsCliCredentials(self))); +} + + +static PyObject *py_creds_set_password_to_connect(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_to_connect(PyCredentials_AsCliCredentials(self), newval, obt)); +} + +static PyObject *py_creds_get_user_to_connect_domain(pytalloc_Object *self) +{ + return PyString_FromStringOrNULL(cli_credentials_get_user_to_connect_domain(PyCredentials_AsCliCredentials(self))); +} + +static PyObject *py_creds_set_user_to_connect_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_user_to_connect_domain(PyCredentials_AsCliCredentials(self), newval, obt)); +} + static PyObject *py_creds_get_domain(pytalloc_Object *self) { return PyString_FromStringOrNULL(cli_credentials_get_domain(PyCredentials_AsCliCredentials(self))); @@ -184,10 +242,10 @@ static PyObject *py_creds_wrong_password(pytalloc_Object *self) static PyObject *py_creds_set_cmdline_callbacks(pytalloc_Object *self) { - return PyBool_FromLong(cli_credentials_set_cmdline_callbacks(PyCredentials_AsCliCredentials(self))); + return PyBool_FromLong(cli_credentials_set_cmdline_callbacks(PyCredentials_AsCliCredentials(self))); } -static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args) +PyObject *parse_string(pytalloc_Object *self, PyObject *args, bool user_to_connect) { char *newval; enum credentials_obtained obt = CRED_SPECIFIED; @@ -198,10 +256,20 @@ static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args) } obt = _obt; - cli_credentials_parse_string(PyCredentials_AsCliCredentials(self), newval, obt); + cli_credentials_parse_string(PyCredentials_AsCliCredentials(self), newval, obt, user_to_connect); Py_RETURN_NONE; } +static PyObject *py_creds_parse_string(pytalloc_Object *self, PyObject *args) +{ + return parse_string(self, args, false); +} + +static PyObject *py_creds_parse_string_to_connect(pytalloc_Object *self, PyObject *args) +{ + return parse_string(self, args, true); +} + 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); @@ -406,12 +474,30 @@ static PyMethodDef py_creds_methods[] = { { "set_username", (PyCFunction)py_creds_set_username, METH_VARARGS, "S.set_username(name, obtained=CRED_SPECIFIED) -> None\n" "Change username." }, + { "get_user_to_connect", (PyCFunction)py_creds_get_user_to_connect, METH_NOARGS, + "S.get_user_to_connect() -> username\n" + "Obtain user to connect." }, + { "set_user_to_connect", (PyCFunction)py_creds_set_user_to_connect, METH_VARARGS, + "S.set_user_to_connect(name, obtained=CRED_SPECIFIED) -> None\n" + "Change user to connect." }, { "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_password_to_connect", (PyCFunction)py_creds_get_password_to_connect, METH_NOARGS, + "S.get_password_to_connect() -> password\n" + "Obtain password to connect." }, + { "set_password_to_connect", (PyCFunction)py_creds_set_password_to_connect, METH_VARARGS, + "S.set_password_to_connect(password, obtained=CRED_SPECIFIED) -> None\n" + "Change password to connect." }, + { "get_user_to_connect_domain", (PyCFunction)py_creds_get_user_to_connect_domain, METH_NOARGS, + "S.get_user_to_connect_domain() -> domain\n" + "Obtain domain name." }, + { "set_user_to_connect_domain", (PyCFunction)py_creds_set_user_to_connect_domain, METH_VARARGS, + "S.set_user_to_connect_domain(domain, obtained=CRED_SPECIFIED) -> None\n" + "Change domain name." }, { "get_domain", (PyCFunction)py_creds_get_domain, METH_NOARGS, "S.get_domain() -> domain\n" "Obtain domain name." }, @@ -433,7 +519,7 @@ static PyMethodDef py_creds_methods[] = { { "is_anonymous", (PyCFunction)py_creds_is_anonymous, METH_NOARGS, NULL }, { "set_anonymous", (PyCFunction)py_creds_set_anonymous, METH_NOARGS, - "S.set_anonymous() -> None\n" + "S.set_anonymous() -> None\n" "Use anonymous credentials." }, { "get_workstation", (PyCFunction)py_creds_get_workstation, METH_NOARGS, NULL }, @@ -450,6 +536,9 @@ static PyMethodDef py_creds_methods[] = { { "parse_string", (PyCFunction)py_creds_parse_string, METH_VARARGS, "S.parse_string(text, obtained=CRED_SPECIFIED) -> None\n" "Parse credentials string." }, + { "parse_string_to_connect", (PyCFunction)py_creds_parse_string_to_connect, METH_VARARGS, + "S.parse_string_to_connect(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, diff --git a/auth/credentials/tests/simple.c b/auth/credentials/tests/simple.c index 90633ec..59767aa 100644 --- a/auth/credentials/tests/simple.c +++ b/auth/credentials/tests/simple.c @@ -67,7 +67,7 @@ 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); + cli_credentials_parse_string(creds, "%", CRED_SPECIFIED, false); torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), "", "domain"); @@ -80,7 +80,7 @@ static bool test_parse_string(struct torture_context *tctx) /* username + password */ cli_credentials_parse_string(creds, "somebody%secret", - CRED_SPECIFIED); + CRED_SPECIFIED, false); torture_assert_str_equal(tctx, cli_credentials_get_domain(creds), "", "domain"); @@ -93,7 +93,7 @@ static bool test_parse_string(struct torture_context *tctx) /* principal */ cli_credentials_parse_string(creds, "prin@styx", - CRED_SPECIFIED); + CRED_SPECIFIED, false); torture_assert_str_equal(tctx, cli_credentials_get_realm(creds), "STYX", "realm"); diff --git a/python/samba/getopt.py b/python/samba/getopt.py index 13139b2..1fbcdc8 100644 --- a/python/samba/getopt.py +++ b/python/samba/getopt.py @@ -144,6 +144,9 @@ def __init__(self, parser, special_name=None): self._add_option("-U", "--username", metavar="USERNAME", action="callback", type=str, help="Username", callback=self._parse_username) + self._add_option("-C", "--user_to_connect", metavar="USER_TO_CONNECT", + action="callback", type=str, + help="UserToConnect", callback=self._parse_user_to_connect) self._add_option("-W", "--workgroup", metavar="WORKGROUP", action="callback", type=str, help="Workgroup", callback=self._parse_workgroup) @@ -178,8 +181,13 @@ def _parse_username(self, option, opt_str, arg, parser): self.creds.parse_string(arg) self.machine_pass = False + def _parse_user_to_connect(self, option, opt_str, arg, parser): + self.creds.parse_string_to_connect(arg) + self.machine_pass = False + def _parse_workgroup(self, option, opt_str, arg, parser): self.creds.set_domain(arg) + self.creds.set_user_to_connect_domain(arg) def _set_password(self, option, opt_str, arg, parser): self.creds.set_password(arg) diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py index ec91a93..2167875 100644 --- a/python/samba/netcmd/user.py +++ b/python/samba/netcmd/user.py @@ -500,10 +500,22 @@ def run(self, credopts=None, sambaopts=None, versionopts=None, lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp) + connect_password = "" + + if len(creds.get_user_to_connect()) > 0: + connect_password = getpass("Password for [%s\\%s]: " % ( + creds.get_user_to_connect_domain(), + creds.get_user_to_connect()) + ) + creds.set_password_to_connect(connect_password) # get old password now, to get the password prompts in the right order old_password = creds.get_password() + if len(creds.get_user_to_connect()) < 1: + connect_password = old_password + import pdb; pdb.set_trace() + net = Net(creds, lp, server=credopts.ipaddress) password = newpassword diff --git a/source4/lib/cmdline/popt_credentials.c b/source4/lib/cmdline/popt_credentials.c index 59a724c..73bd04a 100644 --- a/source4/lib/cmdline/popt_credentials.c +++ b/source4/lib/cmdline/popt_credentials.c @@ -72,7 +72,7 @@ static void popt_common_credentials_callback(poptContext con, { char *lp; - cli_credentials_parse_string(cmdline_credentials, arg, CRED_SPECIFIED); + cli_credentials_parse_string(cmdline_credentials, arg, CRED_SPECIFIED, false); /* This breaks the abstraction, including the const above */ if ((lp=strchr_m(arg,'%'))) { lp[0]='\0'; diff --git a/source4/libnet/libnet_passwd.c b/source4/libnet/libnet_passwd.c index 77176bc..9bb9725 100644 --- a/source4/libnet/libnet_passwd.c +++ b/source4/libnet/libnet_passwd.c @@ -34,7 +34,7 @@ */ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r) { - NTSTATUS status; + NTSTATUS status; struct libnet_RpcConnect c; #if 0 struct policy_handle user_handle; @@ -58,7 +58,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT /* prepare connect to the SAMR pipe of the users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; - c.in.dcerpc_iface = &ndr_table_samr; + c.in.dcerpc_iface = &ndr_table_samr; c.in.dcerpc_flags = DCERPC_ANON_FALLBACK; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ @@ -85,7 +85,7 @@ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CT arcfour_crypt(lm_pass.data, old_nt_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); - encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); + encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); diff --git a/source4/libnet/libnet_rpc.c b/source4/libnet/libnet_rpc.c index a491a42..83a5c0e 100644 --- a/source4/libnet/libnet_rpc.c +++ b/source4/libnet/libnet_rpc.c @@ -54,7 +54,7 @@ static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context struct libnet_RpcConnect *r, void (*monitor)(struct monitor_msg*)) { - struct composite_context *c; + struct composite_context *c; struct rpc_connect_srv_state *s; struct dcerpc_binding *b; struct composite_context *pipe_connect_req; @@ -165,7 +165,7 @@ static void continue_pipe_connect(struct composite_context *ctx) s->monitor_fn(&msg); } - composite_done(c); + composite_done(c); } @@ -305,7 +305,7 @@ static void continue_lookup_dc(struct tevent_req *req) c = tevent_req_callback_data(req, struct composite_context); s = talloc_get_type_abort(c->private_data, struct rpc_connect_dc_state); - + /* receive result of domain controller lookup */ c->status = libnet_LookupDCs_recv(req, c, &s->f); if (!composite_is_ok(c)) return; @@ -327,13 +327,13 @@ static void continue_lookup_dc(struct tevent_req *req) } /* ok, pdc has been found so do attempt to rpc connect */ - s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS; + s->r2.level = LIBNET_RPC_CONNECT_SERVER_ADDRESS; /* this will cause yet another name resolution, but at least * we pass the right name down the stack now */ s->r2.in.name = talloc_strdup(s, s->connect_name); s->r2.in.address = talloc_steal(s, s->f.out.dcs[0].address); - s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface; + s->r2.in.dcerpc_iface = s->r.in.dcerpc_iface; s->r2.in.dcerpc_flags = s->r.in.dcerpc_flags; /* send rpc connect request to the server */ @@ -414,7 +414,7 @@ static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c, the original parent is well nigh impossible at this point in the code (yes, I tried). */ - r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe), + r->out.dcerpc_pipe = talloc_reparent(talloc_parent(s->r.out.dcerpc_pipe), mem_ctx, s->r.out.dcerpc_pipe); /* reference created pipe structure to long-term libnet_context @@ -516,7 +516,7 @@ static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_cont /* we need to query information on lsarpc interface first */ s->rpc_conn.in.dcerpc_iface = &ndr_table_lsarpc; - + /* request connection to the lsa pipe on the pdc */ conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn); if (composite_nomem(c, conn_req)) return c; @@ -565,7 +565,7 @@ static void continue_dci_rpc_connect(struct composite_context *ctx) /* prepare to open a policy handle on lsa pipe */ s->lsa_pipe = s->ctx->lsa.pipe; - + s->qos.len = 0; s->qos.impersonation_level = 2; s->qos.context_mode = 1; @@ -663,7 +663,7 @@ static void continue_lsa_policy(struct tevent_req *subreq) may result in failure) and query lsa info for domain name and sid. */ static void continue_lsa_query_info2(struct tevent_req *subreq) -{ +{ struct composite_context *c; struct rpc_connect_dci_state *s; @@ -672,7 +672,7 @@ static void continue_lsa_query_info2(struct tevent_req *subreq) c->status = dcerpc_lsa_QueryInfoPolicy2_r_recv(subreq, s); TALLOC_FREE(subreq); - + /* In case of error just null the realm and guid and proceed to the next step. After all, it doesn't have to be AD domain controller we talking to - NT-style PDC also counts */ @@ -854,7 +854,7 @@ static void continue_secondary_conn(struct composite_context *ctx) s->r.out.error_string = talloc_asprintf(c, "secondary connection failed: %s", nt_errstr(c->status)); - + composite_error(c, c->status); return; } @@ -1025,7 +1025,10 @@ NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r) { struct composite_context *c; - + const char **values = {NULL, NULL, NULL}; + + switch_values(ctx->cred, values); c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL); + switch_back_values(ctx->cred, values); return libnet_RpcConnect_recv(c, ctx, mem_ctx, r); } diff --git a/source4/torture/gentest.c b/source4/torture/gentest.c index 41b4aef..e85daed 100644 --- a/source4/torture/gentest.c +++ b/source4/torture/gentest.c @@ -3224,7 +3224,8 @@ int main(int argc, const char *argv[]) usage(pc); exit(1); } - cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), CRED_SPECIFIED); + cli_credentials_parse_string(servers[username_count].credentials, poptGetOptArg(pc), + CRED_SPECIFIED, false); username_count++; break; } diff --git a/source4/torture/locktest.c b/source4/torture/locktest.c index ac8d854..61c2dd4 100644 --- a/source4/torture/locktest.c +++ b/source4/torture/locktest.c @@ -605,7 +605,8 @@ int main(int argc, const char *argv[]) usage(pc); exit(1); } - cli_credentials_parse_string(servers[username_count], poptGetOptArg(pc), CRED_SPECIFIED); + cli_credentials_parse_string(servers[username_count], poptGetOptArg(pc), + CRED_SPECIFIED, false); username_count++; break; } diff --git a/source4/torture/rpc/forest_trust.c b/source4/torture/rpc/forest_trust.c index ccb19ed..fa1c68b 100644 --- a/source4/torture/rpc/forest_trust.c +++ b/source4/torture/rpc/forest_trust.c @@ -797,7 +797,7 @@ static bool testcase_ForestTrusts(struct torture_context *tctx, torture_assert(tctx, dom2_credentials != NULL, "cli_credentials_init()"); cli_credentials_parse_string(dom2_credentials, dom2_cred_string, - CRED_SPECIFIED); + CRED_SPECIFIED, false); cli_credentials_set_workstation(dom2_credentials, TEST_MACHINE_NAME, CRED_SPECIFIED); diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index a72dd31..40061ad 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -931,12 +931,12 @@ bool torture_rpc_schannel_bench1(struct torture_context *torture) s->user1_creds = cli_credentials_shallow_copy(s, cmdline_credentials); tmp = torture_setting_string(s->tctx, "extra_user1", NULL); if (tmp) { - cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED); + cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED, false); } s->user2_creds = cli_credentials_shallow_copy(s, cmdline_credentials); tmp = torture_setting_string(s->tctx, "extra_user2", NULL); if (tmp) { - cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED); + cli_credentials_parse_string(s->user1_creds, tmp, CRED_SPECIFIED, false); } s->join_ctx1 = torture_join_domain(s->tctx, talloc_asprintf(s, "%sb", TEST_MACHINE_NAME), diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c index f7c95eb..5eb1ea7 100644 --- a/source4/utils/ntlm_auth.c +++ b/source4/utils/ntlm_auth.c @@ -255,7 +255,7 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode, static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode, struct loadparm_context *lp_ctx, char *buf, int length, void **private1, - unsigned int mux_id, void **password) + unsigned int mux_id, void **password) { DATA_BLOB in; if (strlen(buf) < 2) {